// Warning: Some assembly references could not be resolved automatically. This might lead to incorrect decompilation of some parts,
// for ex. property getter/setter access. To get optimal decompilation results, please manually add the missing references to the list of loaded assemblies.

// C:\SteamLibrary\steamapps\common\Risk of Rain 2\Risk of Rain 2_Data\Managed\RoR2.dll
// RoR2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Global type: <Module>
// Architecture: AnyCPU (64-bit preferred)
// Runtime: v4.0.30319
// This assembly was compiled using the /deterministic option.
// Hash algorithm: SHA1

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using AK.Wwise;
using Assets.RoR2.Scripts.Platform;
using EntityStates;
using EntityStates.AI;
using EntityStates.AurelioniteHeart;
using EntityStates.Barrel;
using EntityStates.BrotherMonster;
using EntityStates.ChildMonster;
using EntityStates.Destructible;
using EntityStates.Drone;
using EntityStates.Engi.EngiBubbleShield;
using EntityStates.Engi.Mine;
using EntityStates.Engi.MineDeployer;
using EntityStates.EngiTurret;
using EntityStates.EngiTurret.EngiTurretWeapon;
using EntityStates.FalseSon;
using EntityStates.FalseSonBoss;
using EntityStates.GreaterWispMonster;
using EntityStates.GummyClone;
using EntityStates.Headstompers;
using EntityStates.Heretic;
using EntityStates.ImpBossMonster;
using EntityStates.InfiniteTowerSafeWard;
using EntityStates.Interactables.GoldBeacon;
using EntityStates.LaserTurbine;
using EntityStates.LightningStorm;
using EntityStates.Loader;
using EntityStates.LockedMage;
using EntityStates.Mage.Weapon;
using EntityStates.MagmaWorm;
using EntityStates.MajorConstruct.Stance;
using EntityStates.Merc;
using EntityStates.Missions.Arena.NullWard;
using EntityStates.Missions.Goldshores;
using EntityStates.Missions.Moon;
using EntityStates.MoonElevator;
using EntityStates.ParentMonster;
using EntityStates.Railgunner.Backpack;
using EntityStates.Railgunner.Reload;
using EntityStates.Railgunner.Scope;
using EntityStates.Railgunner.Weapon;
using EntityStates.RoboBallMini.Weapon;
using EntityStates.Scrapper;
using EntityStates.Seeker;
using EntityStates.ShrineHalcyonite;
using EntityStates.ShrineRebirth;
using EntityStates.Sniper.Scope;
using EntityStates.SurvivorPod;
using EntityStates.TimedChest;
using EntityStates.Toolbot;
using EntityStates.Treebot.UnlockInteractable;
using EntityStates.Treebot.Weapon;
using EntityStates.VagrantMonster;
using EntityStates.VoidJailer.Weapon;
using EntityStates.VoidRaidCrab;
using EntityStates.VoidRaidCrab.Joint;
using EntityStates.VoidRaidCrab.Leg;
using EntityStates.VoidSurvivor.CorruptMode;
using EntityStates.VoidSurvivor.Weapon;
using Epic.OnlineServices;
using Epic.OnlineServices.Achievements;
using Epic.OnlineServices.Auth;
using Epic.OnlineServices.Connect;
using Epic.OnlineServices.Ecom;
using Epic.OnlineServices.Friends;
using Epic.OnlineServices.Leaderboards;
using Epic.OnlineServices.Lobby;
using Epic.OnlineServices.Logging;
using Epic.OnlineServices.P2P;
using Epic.OnlineServices.Platform;
using Epic.OnlineServices.Stats;
using Epic.OnlineServices.UI;
using Epic.OnlineServices.UserInfo;
using Facepunch.Steamworks;
using Generics.Dynamics;
using Grumpy;
using Grumpy.Util;
using HG;
using HG.AssetManagement;
using HG.AsyncOperations;
using HG.BlendableTypes;
using HG.Collections.Generic;
using HG.Coroutines;
using HG.GeneralSerializer;
using HG.Reflection;
using HGsignup.Service;
using JetBrains.Annotations;
using KinematicCharacterController;
using Rewired;
using Rewired.Dev;
using Rewired.Integration.UnityUI;
using Rewired.UI;
using RoR2;
using RoR2.Achievements;
using RoR2.Artifacts;
using RoR2.Audio;
using RoR2.CameraModes;
using RoR2.CharacterAI;
using RoR2.CharacterSpeech;
using RoR2.ContentManagement;
using RoR2.ConVar;
using RoR2.DirectionalSearch;
using RoR2.EntitlementManagement;
using RoR2.EntityLogic;
using RoR2.ExpansionManagement;
using RoR2.Hologram;
using RoR2.HudOverlay;
using RoR2.Items;
using RoR2.Mecanim;
using RoR2.Modding;
using RoR2.Navigation;
using RoR2.Networking;
using RoR2.Orbs;
using RoR2.PostProcess;
using RoR2.PostProcessing;
using RoR2.Projectile;
using RoR2.RemoteGameBrowser;
using RoR2.Scripts.GameBehaviors.UI;
using RoR2.Scripts.Tutorial;
using RoR2.Scripts.Utility;
using RoR2.Skills;
using RoR2.Stats;
using RoR2.UI;
using RoR2.UI.LogBook;
using RoR2.UI.MainMenu;
using RoR2.VoidRaidCrab;
using RoR2.WwiseUtils;
using SimpleJSON;
using SteamAPIValidator;
using Tayx.Graphy;
using Tayx.Graphy.Utils;
using ThreeEyedGames;
using TMPro;
using UDPHelperSpace;
using Unity;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Networking;
using UnityEngine.Networking.Types;
using UnityEngine.Playables;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;
using UnityEngine.ResourceManagement;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using UnityEngine.Serialization;
using UnityEngine.UI;
using Zio;
using Zio.FileSystems;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: HG.Reflection.SearchableAttribute.OptIn]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
public class DevotedLemurianController : MonoBehaviour
{
	private CharacterMaster _lemurianMaster;

	private DevotionInventoryController _devotionInventoryController;

	private ItemIndex _devotionItem;

	private int _devotedEvolutionLevel;

	private float _leashDistSq = 160000f;

	private const float minTeleportDistance = 10f;

	private const float maxTeleportDistance = 40f;

	public int DevotedEvolutionLevel
	{
		get
		{
			return _devotedEvolutionLevel;
		}
		set
		{
			_devotedEvolutionLevel = value;
		}
	}

	public ItemIndex DevotionItem => _devotionItem;

	public CharacterBody LemurianBody => _lemurianMaster.GetBody();

	public RoR2.Inventory LemurianInventory => _lemurianMaster.inventory;

	private void Start()
	{
		StartCoroutine(TryTeleport());
	}

	private bool CheckIfNeedTeleport()
	{
		if (!LemurianBody.hasEffectiveAuthority)
		{
			return false;
		}
		CharacterMaster characterMaster = (_lemurianMaster ? _lemurianMaster.minionOwnership.ownerMaster : null);
		CharacterBody characterBody = (characterMaster ? characterMaster.GetBody() : null);
		if (!characterBody)
		{
			return false;
		}
		UnityEngine.Vector3 corePosition = characterBody.corePosition;
		UnityEngine.Vector3 corePosition2 = LemurianBody.corePosition;
		if ((((bool)LemurianBody.characterMotor && LemurianBody.characterMotor.walkSpeed > 0f) || LemurianBody.moveSpeed > 0f) && (corePosition2 - corePosition).sqrMagnitude > _leashDistSq)
		{
			return true;
		}
		return false;
	}

	private IEnumerator TryTeleport()
	{
		UnityEngine.Debug.Log("try teleport");
		while ((bool)_lemurianMaster)
		{
			while (!LemurianBody || !CheckIfNeedTeleport())
			{
				yield return new WaitForSeconds(1f);
			}
			CharacterMaster characterMaster = (_lemurianMaster ? _lemurianMaster.minionOwnership.ownerMaster : null);
			CharacterBody ownerBody = characterMaster.GetBody();
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			List<NodeGraph.NodeIndex> list = nodeGraph.FindNodesInRangeWithFlagConditions(ownerBody.transform.position, 3f, 20f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false);
			while (list.Count == 0)
			{
				UnityEngine.Debug.Log("no valid node to teleport");
				yield return new WaitForSeconds(1f);
				list = nodeGraph.FindNodesInRangeWithFlagConditions(ownerBody.transform.position, 3f, 20f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false);
			}
			while (list.Count > 0)
			{
				UnityEngine.Debug.Log("teleporting");
				int index = UnityEngine.Random.Range(0, list.Count);
				NodeGraph.NodeIndex nodeIndex = list[index];
				if (nodeGraph.GetNodePosition(nodeIndex, out var position))
				{
					TeleportHelper.TeleportBody(LemurianBody, position);
					GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(LemurianBody.gameObject);
					if ((bool)teleportEffectPrefab)
					{
						EffectManager.SimpleEffect(teleportEffectPrefab, position, UnityEngine.Quaternion.identity, transmit: true);
					}
					break;
				}
			}
			yield return new WaitForSeconds(1f);
		}
		UnityEngine.Debug.Log("finish try teleport");
	}

	public void InitializeDevotedLemurian(ItemIndex itemIndex, DevotionInventoryController devotionInventoryController)
	{
		_devotionItem = itemIndex;
		_devotionInventoryController = devotionInventoryController;
		_lemurianMaster = GetComponent<CharacterMaster>();
	}

	public void OnDevotedBodyDead()
	{
		if (_devotionInventoryController.HasItem(RoR2Content.Items.ExtraLife))
		{
			_devotionInventoryController.RemoveItem(RoR2Content.Items.ExtraLife.itemIndex);
		}
		else
		{
			_devotionInventoryController.RemoveItem(_devotionItem, _devotedEvolutionLevel + 1);
			_devotionInventoryController.DropScrapOnDeath(_devotionItem, LemurianBody);
		}
		_devotionInventoryController.UpdateAllMinions();
	}
}
public class activateGraphy : MonoBehaviour
{
	private void Start()
	{
		RoRGraphyControl.verifyInst(default(ConCommandArgs));
	}
}
public class DelusionPickerController : MonoBehaviour
{
	private void Start()
	{
	}

	private void Update()
	{
	}
}
public class UnseenHandIndicator : MonoBehaviour
{
	public UnityEngine.Color customColor = UnityEngine.Color.magenta;

	private Dictionary<Collider, Highlight> pairs = new Dictionary<Collider, Highlight>();

	private void OnTriggerEnter(Collider other)
	{
		AddIndictator(other);
	}

	private void OnTriggerExit(Collider other)
	{
		DelIndictator(other);
	}

	private void AddIndictator(Collider target)
	{
		if (pairs.ContainsKey(target))
		{
			return;
		}
		CharacterModel characterModel = target.GetComponent<ModelLocator>()?.modelTransform?.GetComponent<CharacterModel>();
		if (characterModel == null || characterModel.body.teamComponent.teamIndex != TeamIndex.Monster)
		{
			return;
		}
		CharacterModel.RendererInfo[] baseRendererInfos = characterModel.baseRendererInfos;
		for (int i = 0; i < baseRendererInfos.Length; i++)
		{
			CharacterModel.RendererInfo rendererInfo = baseRendererInfos[i];
			if (!rendererInfo.ignoreOverlays)
			{
				Highlight highlight = base.gameObject.AddComponent<Highlight>();
				highlight.CustomColor = customColor;
				highlight.highlightColor = Highlight.HighlightColor.custom;
				highlight.targetRenderer = rendererInfo.renderer;
				highlight.strength = 1f;
				highlight.isOn = true;
				pairs.Add(target, highlight);
				break;
			}
		}
	}

	private void DelIndictator(Collider target)
	{
		if (pairs.ContainsKey(target))
		{
			UnityEngine.Object.Destroy(pairs[target]);
			pairs.Remove(target);
		}
	}
}
public class FPSCounter : MonoBehaviour
{
	private TextMeshProUGUI unityText;

	private TextMeshProUGUI unityVarText;

	private TextMeshProUGUI cpuText;

	private TextMeshProUGUI gpuText;

	private TextMeshProUGUI memText;

	private static float[] unitySamples;

	private static float[] cpuSamples;

	private static float[] gpuSamples;

	public static int numSamples = 30;

	private static int sampleIndex = 0;

	private int frameSampleIndex;

	public GameObject rootObject;

	public float timingCaptureFrequency = 2f;

	private float captureTimer;

	private char[] tempArray = new char[64];

	private uint numTimings = 5u;

	private FrameTiming[] outTimings;

	private long prevAllocatedBytes;

	private static int waitTurn = 0;

	private static int waitIndex = 0;

	private static int maxWaitIndex = 5;

	public static float currentFPS = 30f;

	private void Start()
	{
		RoR2Application.onUpdate += UpdateFPSLimitVars;
		unitySamples = new float[numSamples];
		base.gameObject.SetActive(value: false);
	}

	private int PutValue(int value, char[] array, int startIndex, bool addPlusIfPositive = false, bool disableMinusIfNegative = false)
	{
		if (value >= 0)
		{
			if (addPlusIfPositive)
			{
				array[startIndex] = '+';
				startIndex++;
			}
		}
		else if (!disableMinusIfNegative)
		{
			value = -value;
			array[startIndex] = '-';
			startIndex++;
		}
		int num = 10;
		int num2 = 1;
		while (num <= value && num != 0)
		{
			num *= 10;
			num2++;
		}
		num /= 10;
		if (num == 0)
		{
			num = 1;
		}
		for (int i = 0; i < num2; i++)
		{
			int digit = GetDigit(value, num);
			num /= 10;
			array[startIndex + i] = (char)(digit + 48);
		}
		return startIndex + num2;
	}

	private int PutValue(int value, char[] array, int startIndex, int numDigits)
	{
		int num = 10;
		int num2 = 1;
		while (num <= value)
		{
			num *= 10;
			num2++;
		}
		num /= 10;
		if (num2 < numDigits)
		{
			for (int i = num2; i < numDigits; i++)
			{
				array[startIndex++] = '0';
			}
		}
		for (int j = 0; j < num2; j++)
		{
			int digit = GetDigit(value, num);
			num /= 10;
			array[startIndex + j] = (char)(digit + 48);
		}
		return startIndex + num2;
	}

	private int PutValue(double value, char[] array, int startIndex, int numDecimalPlaces = 0, bool addPlusIfPositive = false)
	{
		int value2 = (int)value;
		startIndex = PutValue(value2, array, startIndex, addPlusIfPositive);
		if (numDecimalPlaces == 0)
		{
			return startIndex;
		}
		array[startIndex++] = '.';
		double num = 10.0;
		for (int i = 1; i < numDecimalPlaces; i++)
		{
			num *= 10.0;
		}
		double num2 = Math.Abs(value);
		int value3 = (int)((num2 - Math.Floor(num2)) * num);
		startIndex = PutValue(value3, array, startIndex, numDecimalPlaces);
		return startIndex;
	}

	private int PutValue(float value, char[] array, int startIndex, int numDecimalPlaces = 0, bool addPlusIfPositive = false)
	{
		int value2 = (int)value;
		startIndex = PutValue(value2, array, startIndex, addPlusIfPositive);
		if (numDecimalPlaces == 0)
		{
			return startIndex;
		}
		array[startIndex++] = '.';
		float num = 10f;
		for (int i = 1; i < numDecimalPlaces; i++)
		{
			num *= 10f;
		}
		float num2 = Mathf.Abs(value);
		int value3 = (int)((num2 - Mathf.Floor(num2)) * num);
		startIndex = PutValue(value3, array, startIndex, numDecimalPlaces);
		return startIndex;
	}

	private int PutValue(string value, char[] array, int startIndex)
	{
		for (int i = 0; i < value.Length; i++)
		{
			array[startIndex + i] = value[i];
		}
		return startIndex + value.Length;
	}

	private int GetDigit(int value, int place)
	{
		if (place == 1)
		{
			return value % 10;
		}
		int num = place * 10;
		int num2 = value % num;
		int num3 = value % place;
		return (num2 - num3) / place;
	}

	public static int GetWaitIndex()
	{
		waitIndex++;
		if (waitIndex > maxWaitIndex)
		{
			waitIndex = 0;
		}
		return waitIndex;
	}

	public static bool CheckFPSQueue(ref int waitIndex)
	{
		if (waitIndex == 0)
		{
			waitIndex = GetWaitIndex();
		}
		if (currentFPS < 28f && waitIndex != waitTurn)
		{
			return false;
		}
		return true;
	}

	private static void UpdateFPSLimitVars()
	{
		waitTurn++;
		if (waitTurn > maxWaitIndex)
		{
			waitTurn = 0;
		}
		CalculateFramerate();
	}

	private static void CalculateFramerate()
	{
		unitySamples[sampleIndex++] = 1f / Time.unscaledDeltaTime;
		if (sampleIndex == numSamples)
		{
			sampleIndex = 0;
		}
		float num = 0f;
		for (int i = 0; i < numSamples; i++)
		{
			num += unitySamples[i];
		}
		num /= (float)numSamples;
		currentFPS = num;
	}

	private void Update()
	{
	}
}
public static class AkGameObjUtil
{
	public static void SetAkGameObjectStatic(GameObject gameObj, bool staticSetting)
	{
		if (gameObj.TryGetComponent<AkGameObj>(out var component))
		{
			component.isStaticAfterDelay = staticSetting;
		}
	}
}
public class ReadOnlyAttribute : PropertyAttribute
{
}
[Serializable]
public struct CubicBezier3
{
	public UnityEngine.Vector3 a;

	public UnityEngine.Vector3 b;

	public UnityEngine.Vector3 c;

	public UnityEngine.Vector3 d;

	public UnityEngine.Vector3 p0 => a;

	public UnityEngine.Vector3 p1 => d;

	public UnityEngine.Vector3 v0 => b - a;

	public UnityEngine.Vector3 v1 => c - d;

	public static CubicBezier3 FromVelocities(UnityEngine.Vector3 p0, UnityEngine.Vector3 v0, UnityEngine.Vector3 p1, UnityEngine.Vector3 v1)
	{
		CubicBezier3 result = default(CubicBezier3);
		result.a = p0;
		result.b = p0 + v0;
		result.c = p1 + v1;
		result.d = p1;
		return result;
	}

	public UnityEngine.Vector3 Evaluate(float t)
	{
		float num = t * t;
		float num2 = num * t;
		return a + 3f * t * (b - a) + 3f * num * (c - 2f * b + a) + num2 * (d - 3f * c + 3f * b - a);
	}

	public void ToVertices(UnityEngine.Vector3[] results)
	{
		ToVertices(results, 0, results.Length);
	}

	public void ToVertices(UnityEngine.Vector3[] results, int spanStart, int spanLength)
	{
		float num = 1f / (float)(spanLength - 1);
		for (int i = 0; i < spanLength; i++)
		{
			results[spanStart++] = Evaluate((float)i * num);
		}
	}

	public float ApproximateLength(int samples)
	{
		float num = 1f / (float)(samples - 1);
		float num2 = 0f;
		UnityEngine.Vector3 vector = p0;
		for (int i = 1; i < samples; i++)
		{
			UnityEngine.Vector3 vector2 = Evaluate((float)i * num);
			num2 += UnityEngine.Vector3.Distance(vector, vector2);
			vector = vector2;
		}
		return num2;
	}
}
public class ElectricEffect : MonoBehaviour
{
	public LineRenderer lightningLineRenderer;

	public List<Texture> lightningTextures = new List<Texture>();

	private Material lineRendererMat;

	private int counter;

	private int textureNum;

	public int interval = 3;

	public float lineWidth = 1f;

	private void Start()
	{
		lineRendererMat = lightningLineRenderer.material;
		lightningLineRenderer.startWidth = lineWidth;
		lightningLineRenderer.endWidth = lineWidth;
	}

	private void Update()
	{
		if (!(Time.timeScale > 0f))
		{
			return;
		}
		if (counter >= interval)
		{
			if (textureNum == lightningTextures.Count)
			{
				textureNum = 0;
			}
			lineRendererMat.SetTexture("_MainTex", lightningTextures[textureNum]);
			textureNum++;
			counter = 0;
		}
		counter++;
	}
}
public class FocusedConvergenceAnimator : MonoBehaviour
{
	public bool animateX;

	public bool animateY;

	public bool animateZ;

	private AnimationCurve animCurve;

	private float xScale;

	private float yScale;

	private float zScale;

	public float scaleTime = 4f;

	private float tempScaleTimer = 4f;

	public float rotateTime = 4f;

	private float tempRotateTimer = 4f;

	private float scaleMax = 1.2f;

	private float scaleMin = 0.8f;

	private bool isScaling;

	private float xRotate;

	private float xRotateTop;

	private float yRotate;

	private float yRotateTop;

	private float zRotate;

	private float zRotateTop;

	private void Start()
	{
		tempScaleTimer = 0f;
		tempRotateTimer = 0f;
		animCurve = AnimationCurve.EaseInOut(0f, scaleMin, 1f, scaleMax);
	}

	private void FixedUpdate()
	{
		if (isScaling)
		{
			tempScaleTimer += Time.deltaTime;
			if (tempScaleTimer <= scaleTime * 0.333f)
			{
				float t = tempScaleTimer / (scaleTime * 0.333f);
				xScale = Mathf.Lerp(1f, scaleMax, t);
				yScale = Mathf.Lerp(1f, scaleMax, t);
				zScale = Mathf.Lerp(1f, scaleMax, t);
			}
			if (tempScaleTimer > scaleTime * 0.333f && tempScaleTimer <= scaleTime * 0.666f)
			{
				float t = (tempScaleTimer - scaleTime * 0.333f) / (scaleTime * 0.333f);
				xScale = Mathf.Lerp(scaleMax, scaleMin, t);
				yScale = Mathf.Lerp(scaleMax, scaleMin, t);
				zScale = Mathf.Lerp(scaleMax, scaleMin, t);
			}
			if (tempScaleTimer > scaleTime * 0.666f)
			{
				float t = (tempScaleTimer - scaleTime * 0.666f) / (scaleTime * 0.333f);
				xScale = Mathf.Lerp(scaleMin, 1f, t);
				yScale = Mathf.Lerp(scaleMin, 1f, t);
				zScale = Mathf.Lerp(scaleMin, 1f, t);
			}
			if (tempScaleTimer >= scaleTime)
			{
				isScaling = false;
				tempRotateTimer = 0f;
				xRotateTop = UnityEngine.Random.Range(0f, 10f);
				yRotateTop = UnityEngine.Random.Range(0f, 10f);
				zRotateTop = UnityEngine.Random.Range(0f, 10f);
			}
			else
			{
				base.transform.localScale = new UnityEngine.Vector3(xScale, yScale, zScale);
			}
		}
		else
		{
			tempRotateTimer += Time.deltaTime;
			if (tempRotateTimer <= rotateTime * 0.5f)
			{
				float t2 = tempRotateTimer / (rotateTime * 0.5f);
				xRotate = Mathf.Lerp(0f, xRotateTop, t2);
				yRotate = Mathf.Lerp(0f, yRotateTop, t2);
				zRotate = Mathf.Lerp(0f, zRotateTop, t2);
			}
			else
			{
				float t2 = (tempRotateTimer - rotateTime * 0.5f) / (rotateTime * 0.5f);
				xRotate = Mathf.Lerp(xRotateTop, 0f, t2);
				yRotate = Mathf.Lerp(yRotateTop, 0f, t2);
				zRotate = Mathf.Lerp(zRotateTop, 0f, t2);
			}
			if (tempRotateTimer >= rotateTime)
			{
				isScaling = true;
				tempScaleTimer = 0f;
			}
			else
			{
				base.transform.Rotate(new UnityEngine.Vector3(xRotate, yRotate, zRotate));
			}
		}
	}
}
public class GrandparentEnergyFXController : MonoBehaviour
{
	public List<ParticleSystem> energyFXParticles = new List<ParticleSystem>();

	[HideInInspector]
	public GameObject portalObject;

	private bool isPortalSoundPlaying;

	private void Start()
	{
	}

	private void FixedUpdate()
	{
		if (!(portalObject != null))
		{
			return;
		}
		if (!isPortalSoundPlaying)
		{
			if (portalObject.transform.localScale == UnityEngine.Vector3.zero)
			{
				Util.PlaySound("Play_grandparent_portal_loop", portalObject);
				isPortalSoundPlaying = false;
			}
		}
		else if (portalObject.transform.localScale != UnityEngine.Vector3.zero)
		{
			Util.PlaySound("Stop_grandparent_portal_loop", portalObject);
			isPortalSoundPlaying = true;
		}
	}

	public void TurnOffFX()
	{
		for (int i = 0; i < energyFXParticles.Count; i++)
		{
			ParticleSystem.EmissionModule emission = energyFXParticles[i].emission;
			emission.enabled = false;
		}
		if (portalObject != null)
		{
			ParticleSystem componentInChildren = portalObject.GetComponentInChildren<ParticleSystem>();
			if (componentInChildren != null)
			{
				ParticleSystem.EmissionModule emission2 = componentInChildren.emission;
				emission2.enabled = false;
			}
		}
	}

	public void TurnOnFX()
	{
		for (int i = 0; i < energyFXParticles.Count; i++)
		{
			ParticleSystem.EmissionModule emission = energyFXParticles[i].emission;
			emission.enabled = true;
		}
		if (portalObject != null)
		{
			ParticleSystem componentInChildren = portalObject.GetComponentInChildren<ParticleSystem>();
			if (componentInChildren != null)
			{
				ParticleSystem.EmissionModule emission2 = componentInChildren.emission;
				emission2.enabled = true;
			}
		}
	}
}
public class MaulingRock : NetworkBehaviour
{
	private HealthComponent myHealthComponent;

	public GameObject deathEffect;

	public float blastRadius = 1f;

	public float damage = 10f;

	public float damageCoefficient = 1f;

	public float scaleVarianceLow = 0.8f;

	public float scaleVarianceHigh = 1.2f;

	public float verticalOffset;

	[SyncVar]
	private float scale;

	public float Networkscale
	{
		get
		{
			return scale;
		}
		[param: In]
		set
		{
			SetSyncVar(value, ref scale, 1u);
		}
	}

	public override void OnStartServer()
	{
		base.OnStartServer();
		Networkscale = UnityEngine.Random.Range(scaleVarianceLow, scaleVarianceHigh);
	}

	private void Start()
	{
		myHealthComponent = GetComponent<HealthComponent>();
		base.transform.localScale = new UnityEngine.Vector3(scale, scale, scale);
	}

	private void FixedUpdate()
	{
		if (NetworkServer.active && myHealthComponent != null && !myHealthComponent.alive)
		{
			if (deathEffect != null)
			{
				EffectManager.SpawnEffect(deathEffect, new EffectData
				{
					origin = base.transform.position,
					scale = blastRadius
				}, transmit: true);
			}
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}

	private void UNetVersion()
	{
	}

	public override bool OnSerialize(NetworkWriter writer, bool forceAll)
	{
		if (forceAll)
		{
			writer.Write(scale);
			return true;
		}
		bool flag = false;
		if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
		{
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
				flag = true;
			}
			writer.Write(scale);
		}
		if (!flag)
		{
			writer.WritePackedUInt32(base.syncVarDirtyBits);
		}
		return flag;
	}

	public override void OnDeserialize(NetworkReader reader, bool initialState)
	{
		if (initialState)
		{
			scale = reader.ReadSingle();
			return;
		}
		int num = (int)reader.ReadPackedUInt32();
		if (((uint)num & (true ? 1u : 0u)) != 0)
		{
			scale = reader.ReadSingle();
		}
	}

	public override void PreStartClient()
	{
	}
}
public delegate void EmptyDelegate();
public class MaulingRockZoneManager : MonoBehaviour
{
	public List<GameObject> maulingRockProjectilePrefabs = new List<GameObject>();

	public Transform startZonePoint1;

	public Transform startZonePoint2;

	public Transform endZonePoint1;

	public Transform endZonePoint2;

	public static float baseDuration = 60f;

	public float knockbackForce = 10000f;

	private UnityEngine.Vector3 vectorBetweenStartPoints = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 vectorBetweenEndPoints = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 MediumRockBump = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 LargeRockBump = UnityEngine.Vector3.zero;

	private int salvoMaximumCount = 10;

	private float timeBetweenSalvoShotsLow = 0.1f;

	private float timeBetweenSalvoShotsHigh = 1f;

	private float timeBetweenSalvosLow = 3f;

	private float timeBetweenSalvosHigh = 5f;

	private int salvoRockCount;

	private int currentSalvoCount;

	private void Awake()
	{
		if (!NetworkServer.active)
		{
			base.enabled = false;
		}
	}

	private void Start()
	{
		vectorBetweenStartPoints = startZonePoint2.position - startZonePoint1.position;
		vectorBetweenEndPoints = endZonePoint2.position - endZonePoint1.position;
		FireSalvo();
	}

	private void FireSalvo()
	{
		salvoRockCount = UnityEngine.Random.Range(0, salvoMaximumCount);
		currentSalvoCount = 0;
		FireRock();
	}

	private void FireRock()
	{
		GameObject gameObject = maulingRockProjectilePrefabs[UnityEngine.Random.Range(0, maulingRockProjectilePrefabs.Count)];
		UnityEngine.Vector3 vector = startZonePoint1.position + UnityEngine.Random.Range(0f, 1f) * vectorBetweenStartPoints;
		UnityEngine.Vector3 vector2 = endZonePoint1.position + UnityEngine.Random.Range(0f, 1f) * vectorBetweenEndPoints;
		MaulingRock component = gameObject.GetComponent<MaulingRock>();
		float num = UnityEngine.Random.Range(0f, 4f);
		num += component.verticalOffset;
		vector = new UnityEngine.Vector3(vector.x, vector.y + num, vector.z);
		num = UnityEngine.Random.Range(0f, 4f);
		num += component.verticalOffset;
		vector2 = new UnityEngine.Vector3(vector2.x, vector2.y + num, vector2.z);
		Ray ray = new Ray(vector, vector2 - vector);
		FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
		fireProjectileInfo.projectilePrefab = gameObject;
		fireProjectileInfo.position = ray.origin;
		fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction);
		fireProjectileInfo.owner = null;
		fireProjectileInfo.damage = component.damage * component.damageCoefficient;
		fireProjectileInfo.force = knockbackForce;
		fireProjectileInfo.crit = false;
		fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
		fireProjectileInfo.target = null;
		FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
		ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
		currentSalvoCount++;
		StartCoroutine(WaitToFireAnotherRock());
	}

	public IEnumerator WaitToFireAnotherSalvo()
	{
		float seconds = UnityEngine.Random.Range(timeBetweenSalvosLow, timeBetweenSalvosHigh);
		yield return new WaitForSeconds(seconds);
		FireSalvo();
	}

	public IEnumerator WaitToFireAnotherRock()
	{
		float seconds = UnityEngine.Random.Range(timeBetweenSalvoShotsLow, timeBetweenSalvoShotsHigh);
		if (currentSalvoCount >= salvoRockCount)
		{
			yield return null;
			StartCoroutine(WaitToFireAnotherSalvo());
		}
		else
		{
			yield return new WaitForSeconds(seconds);
			FireRock();
		}
	}
}
public class MoveCurve : MonoBehaviour
{
	public bool animateX;

	public bool animateY;

	public bool animateZ;

	public float curveScale = 1f;

	public AnimationCurve moveCurve;

	private float xValue;

	private float yValue;

	private float zValue;

	private void Start()
	{
	}

	private void Update()
	{
		if (animateX)
		{
			xValue = moveCurve.Evaluate(Time.time % (float)moveCurve.length) * curveScale;
		}
		else
		{
			xValue = base.transform.localPosition.x;
		}
		if (animateY)
		{
			yValue = moveCurve.Evaluate(Time.time % (float)moveCurve.length) * curveScale;
		}
		else
		{
			yValue = base.transform.localPosition.y;
		}
		if (animateZ)
		{
			zValue = moveCurve.Evaluate(Time.time % (float)moveCurve.length) * curveScale;
		}
		else
		{
			zValue = base.transform.localPosition.z;
		}
		base.transform.localPosition = new UnityEngine.Vector3(xValue, yValue, zValue);
	}
}
public class OnParticleEndEvent : MonoBehaviour
{
	public ParticleSystem particleSystemToTrack;

	public UnityEvent onEnd;

	private bool particleEnded;

	public void Update()
	{
		if ((bool)particleSystemToTrack && !particleSystemToTrack.IsAlive() && !particleEnded)
		{
			particleEnded = true;
			onEnd.Invoke();
		}
	}
}
public class ParentEnergyFXController : MonoBehaviour
{
	public List<ParticleSystem> energyFXParticles = new List<ParticleSystem>();

	public ParticleSystem loomingPresenceParticles;

	private void Start()
	{
	}

	private void FixedUpdate()
	{
	}

	public void TurnOffFX()
	{
		for (int i = 0; i < energyFXParticles.Count; i++)
		{
			ParticleSystem.EmissionModule emission = energyFXParticles[i].emission;
			emission.enabled = false;
		}
	}

	public void TurnOnFX()
	{
		for (int i = 0; i < energyFXParticles.Count; i++)
		{
			ParticleSystem.EmissionModule emission = energyFXParticles[i].emission;
			emission.enabled = true;
		}
	}

	public void SetLoomingPresenceParticles(bool setTo)
	{
		ParticleSystem.EmissionModule emission = loomingPresenceParticles.emission;
		emission.enabled = setTo;
	}
}
public class RJShroomBounce : MonoBehaviour
{
	private Animator shroomAnimator;

	public void Start()
	{
		shroomAnimator = GetComponent<Animator>();
	}

	public void Bounce()
	{
		shroomAnimator.Play("Bounce", 0);
	}
}
public class RootJungleFXController : MonoBehaviour
{
	public int minSystemsActive = 2;

	public int maxSystemsActive = 4;

	public float minActiveTime = 10f;

	public float maxActiveTime = 30f;

	private int numActive;

	private float timeActive;

	private float effectsTimer;

	private bool timeFX;

	public List<ParticleSystem> FXParticles = new List<ParticleSystem>();

	private void Start()
	{
		TurnOffFX(FXParticles.Count);
	}

	private void FixedUpdate()
	{
		if (timeFX)
		{
			effectsTimer -= Time.fixedDeltaTime;
			if (effectsTimer <= 0f)
			{
				timeFX = false;
				TurnOffFX(numActive);
			}
		}
	}

	public void SetupParticles()
	{
		numActive = UnityEngine.Random.Range(minSystemsActive, maxSystemsActive + 1);
		timeActive = UnityEngine.Random.Range(minActiveTime, maxActiveTime);
		effectsTimer = timeActive;
		FXParticles = Shuffle(FXParticles);
		TurnOnFX(numActive);
		timeFX = true;
	}

	public void TurnOffFX(int amount)
	{
		for (int i = 0; i < amount; i++)
		{
			ParticleSystem.EmissionModule emission = FXParticles[i].emission;
			emission.enabled = false;
		}
		SetupParticles();
	}

	public void TurnOnFX(int amount)
	{
		for (int i = 0; i < amount; i++)
		{
			ParticleSystem.EmissionModule emission = FXParticles[i].emission;
			emission.enabled = true;
		}
	}

	public static List<T> Shuffle<T>(List<T> list)
	{
		System.Random random = new System.Random();
		for (int i = 0; i < list.Count; i++)
		{
			int index = random.Next(0, i);
			T value = list[index];
			list[index] = list[i];
			list[i] = value;
		}
		return list;
	}
}
public class SetRandomRotation : MonoBehaviour
{
	public bool setRandomXRotation;

	public bool setRandomYRotation;

	public bool setRandomZRotation;

	private void Start()
	{
		UnityEngine.Vector3 localEulerAngles = base.transform.localEulerAngles;
		if (setRandomXRotation)
		{
			float x = UnityEngine.Random.Range(0f, 359f);
			localEulerAngles.x = x;
		}
		if (setRandomYRotation)
		{
			float y = UnityEngine.Random.Range(0f, 359f);
			localEulerAngles.y = y;
		}
		if (setRandomZRotation)
		{
			float z = UnityEngine.Random.Range(0f, 359f);
			localEulerAngles.z = z;
		}
		base.transform.localEulerAngles = localEulerAngles;
	}

	private void Update()
	{
	}
}
public class SetRandomScale : MonoBehaviour
{
	public float minimumScale;

	public float maximumScale;

	private void Start()
	{
		float num = UnityEngine.Random.Range(minimumScale, maximumScale);
		base.transform.localScale = UnityEngine.Vector3.one * num;
	}
}
public class Spinner : MonoBehaviour
{
	private float randRotationSpeed;

	private int randNumX;

	private int randNumY;

	private int randNumZ;

	private float randZeroOrOneX;

	private float randZeroOrOneY;

	private float randZeroOrOneZ;

	private bool shouldUpdate = true;

	private void Start()
	{
		if (!NetworkServer.active)
		{
			base.enabled = false;
			return;
		}
		if (base.gameObject.isStatic)
		{
			base.enabled = false;
			return;
		}
		UnityEngine.Random.Range(0f, 360f);
		UnityEngine.Random.Range(0f, 360f);
		UnityEngine.Random.Range(0f, 360f);
		UnityEngine.Random.Range(0f, 360f);
		base.gameObject.transform.rotation = UnityEngine.Random.rotationUniform;
		randRotationSpeed = UnityEngine.Random.Range(0.2f, 1f) / Time.deltaTime;
		randNumX = UnityEngine.Random.Range(0, 2);
		randNumY = UnityEngine.Random.Range(0, 2);
		randNumZ = UnityEngine.Random.Range(0, 2);
		randZeroOrOneX = randNumX;
		randZeroOrOneY = randNumY;
		randZeroOrOneZ = randNumZ;
		if (randZeroOrOneX == 0f && randZeroOrOneY == 0f && randZeroOrOneZ == 0f)
		{
			randZeroOrOneX = 1f;
			randZeroOrOneY = 1f;
			randZeroOrOneZ = 1f;
		}
	}

	private void OnBecameVisible()
	{
		shouldUpdate = true;
	}

	private void OnBecameInvisible()
	{
		shouldUpdate = false;
	}

	private void Update()
	{
		if (shouldUpdate)
		{
			base.gameObject.transform.Rotate(new UnityEngine.Vector3(randZeroOrOneX, randZeroOrOneY, randZeroOrOneZ), randRotationSpeed * Time.deltaTime);
		}
	}
}
public class JobCleaner : MonoBehaviour
{
	public static JobCleaner instance;

	public List<JobWrapper> jobsToClean;

	private void Awake()
	{
		if (instance == null)
		{
			instance = this;
		}
		jobsToClean = new List<JobWrapper>();
	}

	private void OnDestroy()
	{
		if (instance == this)
		{
			instance = null;
		}
		if (jobsToClean.Count <= 0)
		{
			return;
		}
		UnityEngine.Debug.LogError("JOBCLEANER HAS JOBS TO CLEAN BEFORE BEING DESTROYED");
		while (jobsToClean.Count > 0)
		{
			for (int num = jobsToClean.Count - 1; num >= 0; num--)
			{
				if (jobsToClean[num].handle.IsCompleted)
				{
					jobsToClean[num].handle.Complete();
					jobsToClean[num].Dispose();
					jobsToClean.RemoveAt(num);
				}
			}
		}
		UnityEngine.Debug.LogError("JOBCLEANER FINISHED CLEANING JOBS, CAN DIE HAPPY NOW");
	}

	private void LateUpdate()
	{
		if (jobsToClean.Count > 0)
		{
			int index = jobsToClean.Count - 1;
			if (jobsToClean[index].handle.IsCompleted)
			{
				jobsToClean[index].handle.Complete();
				jobsToClean[index].Dispose();
				jobsToClean.RemoveAt(index);
			}
		}
	}
}
public class JobWrapper
{
	public JobHandle handle;

	public bool jobScheduled;

	public bool isComplete
	{
		get
		{
			if (jobScheduled)
			{
				return handle.IsCompleted;
			}
			return true;
		}
	}

	public virtual void Dispose()
	{
		UnityEngine.Debug.LogError("Error: No overload for JobWrapper.Dispose()");
	}

	public virtual void Initialize(UnityEngine.Object data)
	{
		UnityEngine.Debug.LogError("Error: No overload for JobWrapper:Initialize()");
	}

	public virtual void Schedule()
	{
		JobHandle.ScheduleBatchedJobs();
		jobScheduled = true;
	}

	public void Complete()
	{
		handle.Complete();
		jobScheduled = false;
	}

	public bool SendToCleaner()
	{
		if (JobCleaner.instance != null)
		{
			JobCleaner.instance.jobsToClean.Add(this);
			return true;
		}
		return false;
	}
}
public class ConditionalLOD : MonoBehaviour
{
	public int PS4lod = -1;

	public int XBoxlod = -1;

	public int Switchlod = 1;

	public int SwitchHandHeldlod = 2;

	public int Defaultlod = -1;

	public int maxlod;

	private LODGroup lg;

	private void Start()
	{
	}

	private void OnEnable()
	{
		GetRenderers();
		int lODState = GetLODState();
		SetState(lODState);
	}

	public int GetLODPercentage(LOD[] lods, int i)
	{
		if (i == 0)
		{
			return 100;
		}
		return (int)(lods[i - 1].screenRelativeTransitionHeight * 100f + 0.5f);
	}

	private void ResetLOD()
	{
		GetRenderers();
	}

	private void GetRenderers()
	{
		lg = GetComponent<LODGroup>();
		LOD[] lODs = lg.GetLODs();
		int num = -1;
		for (int i = 0; i < lODs.Length; i++)
		{
			if (lODs[i].renderers != null && lODs[i].renderers.Length != 0)
			{
				num = i;
			}
		}
		maxlod = num;
	}

	public int GetLODState()
	{
		return Defaultlod;
	}

	private void SetState(int lodState)
	{
		LOD[] lODs = lg.GetLODs();
		if (lodState == -1)
		{
			lg.enabled = true;
			for (int i = 0; i < lODs.Length; i++)
			{
				Renderer[] renderers = lODs[i].renderers;
				for (int j = 0; j < renderers.Length; j++)
				{
					renderers[j].gameObject.SetActive(value: true);
				}
			}
			return;
		}
		for (int k = 0; k < lODs.Length; k++)
		{
			Renderer[] renderers = lODs[k].renderers;
			for (int j = 0; j < renderers.Length; j++)
			{
				renderers[j].gameObject.SetActive(value: false);
			}
		}
		lodState = Mathf.Min(lodState, maxlod);
		int num = maxlod - lodState + 1;
		if (num == 1 || !Application.isPlaying)
		{
			lg.enabled = false;
			Renderer[] renderers = lODs[lodState].renderers;
			for (int j = 0; j < renderers.Length; j++)
			{
				renderers[j].gameObject.SetActive(value: true);
			}
			return;
		}
		lg.enabled = true;
		int num2 = 0;
		LOD[] array = new LOD[num];
		for (int l = lodState; l < lODs.Length; l++)
		{
			Renderer[] renderers = lODs[l].renderers;
			for (int j = 0; j < renderers.Length; j++)
			{
				renderers[j].gameObject.SetActive(value: true);
			}
			array[num2] = lODs[l];
			if (l + 1 < lODs.Length)
			{
				array[num2].screenRelativeTransitionHeight = lODs[num2].screenRelativeTransitionHeight;
			}
			num2++;
		}
		lg.SetLODs(array);
	}
}
[DefaultExecutionOrder(-5)]
public class ConditionalObject : MonoBehaviour
{
	public bool enabledOnSwitch = true;

	public bool enabledOnXbox = true;

	public bool enabledOnPlaystation = true;

	public bool disableInProduction;

	public bool enabledOnSteam = true;

	public bool enabledOnEGS = true;

	public bool disableIfNoActiveRun;

	private void CheckConditions()
	{
		bool flag = false || enabledOnEGS || enabledOnSteam;
		base.gameObject.SetActive(flag && !disableInProduction);
	}

	private void Awake()
	{
		CheckConditions();
	}
}
public class EntityStateManager : ScriptableObject, ISerializationCallbackReceiver
{
	[Serializable]
	private class StateInfo
	{
		[Serializable]
		public class Field
		{
			public enum ValueType
			{
				Invalid,
				Int,
				Float,
				String,
				Object,
				Bool,
				AnimationCurve,
				Vector3
			}

			[NonSerialized]
			public StateInfo owner;

			[SerializeField]
			private string _fieldName;

			[SerializeField]
			private ValueType _valueType;

			[SerializeField]
			private int _intValue;

			[SerializeField]
			private float _floatValue;

			[SerializeField]
			private string _stringValue;

			[SerializeField]
			private UnityEngine.Object _objectValue;

			[SerializeField]
			private AnimationCurve _animationCurveValue;

			[SerializeField]
			private UnityEngine.Vector3 _vector3Value;

			public ValueType valueType => _valueType;

			public int intValue => _intValue;

			public bool boolValue => _intValue != 0;

			public float floatValue => _floatValue;

			public string stringValue => _stringValue;

			public UnityEngine.Object objectValue => _objectValue;

			public AnimationCurve animationCurveValue => _animationCurveValue;

			public UnityEngine.Vector3 vector3Value => _vector3Value;

			public object valueAsSystemObject
			{
				get
				{
					switch (_valueType)
					{
					case ValueType.Invalid:
						return null;
					case ValueType.Int:
						return intValue;
					case ValueType.Float:
						return floatValue;
					case ValueType.String:
						return stringValue;
					case ValueType.Object:
						if (!objectValue)
						{
							return null;
						}
						return objectValue;
					case ValueType.Bool:
						return boolValue;
					case ValueType.AnimationCurve:
						return animationCurveValue;
					case ValueType.Vector3:
						return vector3Value;
					default:
						return null;
					}
				}
			}

			public Field(string fieldName)
			{
				_fieldName = fieldName;
			}

			public void SetFieldInfo(FieldInfo fieldInfo)
			{
				_fieldName = fieldInfo.Name;
				ValueType valueType = ValueType.Invalid;
				Type fieldType = fieldInfo.FieldType;
				if (fieldType == typeof(int))
				{
					valueType = ValueType.Int;
				}
				else if (fieldType == typeof(float))
				{
					valueType = ValueType.Float;
				}
				else if (fieldType == typeof(string))
				{
					valueType = ValueType.String;
				}
				else if (typeof(UnityEngine.Object).IsAssignableFrom(fieldType))
				{
					valueType = ValueType.Object;
				}
				else if (fieldType == typeof(bool))
				{
					valueType = ValueType.Bool;
				}
				else if (fieldType == typeof(AnimationCurve))
				{
					valueType = ValueType.AnimationCurve;
				}
				else if (fieldType == typeof(UnityEngine.Vector3))
				{
					valueType = ValueType.Vector3;
				}
				if (_valueType != valueType)
				{
					ResetValues();
					_valueType = valueType;
				}
			}

			public bool MatchesFieldInfo(FieldInfo fieldInfo)
			{
				if (fieldInfo == null)
				{
					return false;
				}
				Type fieldType = fieldInfo.FieldType;
				switch (_valueType)
				{
				case ValueType.Invalid:
					return false;
				case ValueType.Int:
					return fieldType.IsAssignableFrom(typeof(int));
				case ValueType.Float:
					return fieldType.IsAssignableFrom(typeof(float));
				case ValueType.String:
					return fieldType.IsAssignableFrom(typeof(string));
				case ValueType.Object:
					if (!(_objectValue == null))
					{
						return fieldType.IsAssignableFrom(_objectValue.GetType());
					}
					return true;
				case ValueType.Bool:
					return fieldType.IsAssignableFrom(typeof(bool));
				case ValueType.AnimationCurve:
					return fieldType.IsAssignableFrom(typeof(AnimationCurve));
				case ValueType.Vector3:
					return fieldType.IsAssignableFrom(typeof(UnityEngine.Vector3));
				default:
					return false;
				}
			}

			public void Apply(FieldInfo fieldInfo, object instance)
			{
				fieldInfo.SetValue(instance, valueAsSystemObject);
			}

			public void ResetValues()
			{
				_intValue = 0;
				_floatValue = 0f;
				_stringValue = null;
				_objectValue = null;
				_animationCurveValue = null;
				_vector3Value = UnityEngine.Vector3.zero;
			}

			public void SetValue(int value)
			{
				ResetValues();
				_valueType = ValueType.Int;
				_intValue = value;
			}

			public void SetValue(float value)
			{
				ResetValues();
				_valueType = ValueType.Float;
				_floatValue = value;
			}

			public void SetValue(string value)
			{
				ResetValues();
				_valueType = ValueType.String;
				_stringValue = value;
			}

			public void SetValue(UnityEngine.Object value)
			{
				ResetValues();
				_valueType = ValueType.Object;
				_objectValue = value;
			}

			public void SetValue(bool value)
			{
				ResetValues();
				_valueType = ValueType.Bool;
				_intValue = (value ? 1 : 0);
			}

			public void SetValue(AnimationCurve value)
			{
				ResetValues();
				_valueType = ValueType.AnimationCurve;
				_animationCurveValue = value;
			}

			public void SetValue(UnityEngine.Vector3 value)
			{
				ResetValues();
				_valueType = ValueType.Vector3;
				_vector3Value = value;
			}

			public string GetFieldName()
			{
				return _fieldName;
			}

			public FieldInfo GetFieldInfo()
			{
				return owner?.serializedType.stateType?.GetField(_fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
			}
		}

		private struct FieldValuePair
		{
			public FieldInfo fieldInfo;

			public object value;
		}

		public SerializableEntityStateType serializedType;

		[FormerlySerializedAs("stateStaticFieldList")]
		[SerializeField]
		private List<Field> stateFieldList = new List<Field>();

		private const BindingFlags defaultInstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;

		private const BindingFlags defaultStaticBindingFlags = BindingFlags.Static | BindingFlags.Public;

		private static bool FieldHasSerializeAttribute(FieldInfo fieldInfo)
		{
			return CustomAttributeExtensions.GetCustomAttributes<SerializeField>(fieldInfo, inherit: true).Any();
		}

		private static bool FieldLacksNonSerializedAttribute(FieldInfo fieldInfo)
		{
			return !CustomAttributeExtensions.GetCustomAttributes<NonSerializedAttribute>(fieldInfo, inherit: true).Any();
		}

		public void SetStateType(Type stateType)
		{
			serializedType.stateType = stateType;
			stateType = serializedType.stateType;
			if (stateType == null)
			{
				return;
			}
			IEnumerable<FieldInfo> first = stateType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Where(FieldHasSerializeAttribute);
			IEnumerable<FieldInfo> second = (from fieldInfo in stateType.GetFields(BindingFlags.Static | BindingFlags.Public)
				where fieldInfo.DeclaringType == stateType
				select fieldInfo).Where(FieldLacksNonSerializedAttribute);
			List<FieldInfo> list = first.Concat(second).ToList();
			Dictionary<FieldInfo, Field> dictionary = new Dictionary<FieldInfo, Field>();
			foreach (FieldInfo fieldInfo2 in list)
			{
				Field field = stateFieldList.Find((Field item) => item.GetFieldName() == fieldInfo2.Name);
				if (field == null)
				{
					UnityEngine.Debug.LogFormat("Could not find field {0}.{1}. Initializing new field.", stateType.Name, fieldInfo2.Name);
					field = new Field(fieldInfo2.Name);
				}
				dictionary[fieldInfo2] = field;
			}
			stateFieldList.Clear();
			foreach (FieldInfo item in list)
			{
				Field field2 = dictionary[item];
				field2.owner = this;
				field2.SetFieldInfo(item);
				stateFieldList.Add(field2);
			}
		}

		public void RefreshStateType()
		{
			SetStateType(serializedType.stateType);
		}

		public void ApplyStatic()
		{
			Type stateType = serializedType.stateType;
			if (!(stateType != null))
			{
				return;
			}
			foreach (Field stateField in stateFieldList)
			{
				FieldInfo field = stateType.GetField(stateField.GetFieldName(), BindingFlags.Static | BindingFlags.Public);
				if (stateField.MatchesFieldInfo(field) && field.IsStatic)
				{
					stateField.Apply(field, null);
				}
			}
		}

		public Action<EntityState> GenerateInstanceFieldInitializerDelegate()
		{
			Type stateType = serializedType.stateType;
			if (stateType == null)
			{
				return null;
			}
			List<FieldValuePair> list = new List<FieldValuePair>();
			for (int i = 0; i < stateFieldList.Count; i++)
			{
				Field field = stateFieldList[i];
				FieldValuePair fieldValuePair = default(FieldValuePair);
				fieldValuePair.fieldInfo = stateType.GetField(field.GetFieldName(), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				fieldValuePair.value = field.valueAsSystemObject;
				FieldValuePair item = fieldValuePair;
				if (!(item.fieldInfo == null))
				{
					list.Add(item);
				}
			}
			FieldValuePair[] fieldValuePairs = list.ToArray();
			if (fieldValuePairs.Length == 0)
			{
				return null;
			}
			return delegate(EntityState entityState)
			{
				for (int j = 0; j < fieldValuePairs.Length; j++)
				{
					FieldValuePair fieldValuePair2 = fieldValuePairs[j];
					fieldValuePair2.fieldInfo.SetValue(entityState, fieldValuePair2.value);
				}
			};
		}

		public Field FindField(string fieldName)
		{
			return stateFieldList.Find((Field value) => value.GetFieldName() == fieldName);
		}

		public bool IsValid()
		{
			return serializedType.stateType != null;
		}

		public IList<Field> GetFields()
		{
			return stateFieldList.AsReadOnly();
		}
	}

	[SerializeField]
	private List<StateInfo> stateInfoList = new List<StateInfo>();

	[HideInInspector]
	[SerializeField]
	private string endMarker = "GIT_END";

	private static readonly Dictionary<Type, Action<EntityState>> instanceFieldInitializers = new Dictionary<Type, Action<EntityState>>();

	private StateInfo GetStateInfo(Type stateType)
	{
		if (stateType == null || !stateType.IsSubclassOf(typeof(EntityState)))
		{
			return null;
		}
		StateInfo stateInfo = stateInfoList.Find((StateInfo currentItem) => currentItem.serializedType.stateType == stateType);
		if (stateInfo == null)
		{
			stateInfo = new StateInfo();
			stateInfo.SetStateType(stateType);
			stateInfoList.Add(stateInfo);
		}
		return stateInfo;
	}

	private void ApplyStatic()
	{
		foreach (StateInfo stateInfo in stateInfoList)
		{
			stateInfo.ApplyStatic();
		}
	}

	public void Initialize()
	{
	}

	private static void SetEntityStateConfigurations(EntityStateConfiguration[] newEntityStateConfigurations)
	{
		EntityStateConfiguration[] array = ArrayUtils.Clone(newEntityStateConfigurations);
		Array.Sort(array, (EntityStateConfiguration a, EntityStateConfiguration b) => a.name.CompareTo(b.name));
		for (int i = 0; i < array.Length; i++)
		{
			array[i].ApplyStatic();
		}
		instanceFieldInitializers.Clear();
		foreach (EntityStateConfiguration entityStateConfiguration in array)
		{
			Action<object> action = entityStateConfiguration.BuildInstanceInitializer();
			if (action != null)
			{
				instanceFieldInitializers[(Type)entityStateConfiguration.targetType] = action;
			}
		}
	}

	void ISerializationCallbackReceiver.OnBeforeSerialize()
	{
		foreach (StateInfo stateInfo in stateInfoList)
		{
			stateInfo.RefreshStateType();
		}
		stateInfoList.RemoveAll((StateInfo stateInfo) => !stateInfo.IsValid());
	}

	void ISerializationCallbackReceiver.OnAfterDeserialize()
	{
		foreach (StateInfo stateInfo in stateInfoList)
		{
			stateInfo.RefreshStateType();
		}
	}

	private void GenerateInstanceFieldInitializers()
	{
		instanceFieldInitializers.Clear();
		foreach (StateInfo stateInfo in stateInfoList)
		{
			Type stateType = stateInfo.serializedType.stateType;
			if (!(stateType == null))
			{
				Action<EntityState> action = stateInfo.GenerateInstanceFieldInitializerDelegate();
				if (action != null)
				{
					instanceFieldInitializers.Add(stateType, action);
				}
			}
		}
	}

	public static void InitializeStateFields(EntityState entityState)
	{
		instanceFieldInitializers.TryGetValue(entityState.GetType(), out var value);
		value?.Invoke(entityState);
	}

	[ContextMenu("Migrate to individual assets")]
	public void MigrateToEntityStateTypes()
	{
		List<StateInfo> list = new List<StateInfo>();
		foreach (StateInfo stateInfo in stateInfoList)
		{
			if (MigrateToEntityStateType(stateInfo))
			{
				list.Add(stateInfo);
			}
		}
		foreach (StateInfo item in list)
		{
			_ = item;
		}
		foreach (Type item2 in from t in typeof(EntityState).Assembly.GetTypes()
			where typeof(EntityState).IsAssignableFrom(t)
			select t)
		{
			GetOrCreateEntityStateSerializer(item2);
		}
	}

	private EntityStateConfiguration GetOrCreateEntityStateSerializer(Type type)
	{
		return null;
	}

	private bool MigrateToEntityStateType(StateInfo stateInfo)
	{
		Type stateType = stateInfo.serializedType.stateType;
		if (stateType == null)
		{
			UnityEngine.Debug.LogWarningFormat("Could not migrate type named \"{0}\": Type could not be found.", typeof(SerializableEntityStateType).GetField("_typeName", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(stateInfo.serializedType));
			return false;
		}
		EntityStateConfiguration orCreateEntityStateSerializer = GetOrCreateEntityStateSerializer(stateType);
		foreach (StateInfo.Field field2 in stateInfo.GetFields())
		{
			string fieldName = field2.GetFieldName();
			FieldInfo field = stateType.GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			ref SerializedField orCreateField = ref orCreateEntityStateSerializer.serializedFieldsCollection.GetOrCreateField(fieldName);
			orCreateField.fieldName = fieldName;
			try
			{
				orCreateField.fieldValue.SetValue(field, field2.valueAsSystemObject);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}
		EditorUtil.SetDirty(orCreateEntityStateSerializer);
		return true;
	}
}
[Serializable]
[PostProcess(typeof(RampFogRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/RampFog", true)]
public sealed class RampFog : PostProcessEffectSettings
{
	[Range(0f, 1f)]
	[Tooltip("Fog intensity.")]
	public FloatParameter fogIntensity = new FloatParameter
	{
		value = 0.5f
	};

	[Range(0f, 20f)]
	[Tooltip("Fog Power")]
	public FloatParameter fogPower = new FloatParameter
	{
		value = 1f
	};

	[Range(-1f, 1f)]
	[Tooltip("The zero value for the fog depth remap.")]
	public FloatParameter fogZero = new FloatParameter
	{
		value = 0f
	};

	[Tooltip("The one value for the fog depth remap.")]
	[Range(-1f, 1f)]
	public FloatParameter fogOne = new FloatParameter
	{
		value = 1f
	};

	[Range(-100f, 100f)]
	[Tooltip("The world position value where the height fog begins.")]
	public FloatParameter fogHeightStart = new FloatParameter
	{
		value = 0f
	};

	[Range(-100f, 600f)]
	[Tooltip("The world position value where the height fog ends.")]
	public FloatParameter fogHeightEnd = new FloatParameter
	{
		value = 100f
	};

	[Range(0f, 5f)]
	[Tooltip("The overall strength of the height fog.")]
	public FloatParameter fogHeightIntensity = new FloatParameter
	{
		value = 0f
	};

	[Tooltip("Color of the fog at the beginning.")]
	public ColorParameter fogColorStart = new ColorParameter
	{
		value = UnityEngine.Color.white
	};

	[Tooltip("Color of the fog at the middle.")]
	public ColorParameter fogColorMid = new ColorParameter
	{
		value = UnityEngine.Color.white
	};

	[Tooltip("Color of the fog at the end.")]
	public ColorParameter fogColorEnd = new ColorParameter
	{
		value = UnityEngine.Color.white
	};

	[Tooltip("How much of the skybox will leak through?")]
	[Range(0f, 1f)]
	public FloatParameter skyboxStrength = new FloatParameter
	{
		value = 0f
	};
}
public sealed class RampFogRenderer : PostProcessEffectRenderer<RampFog>
{
	public override void Render(PostProcessRenderContext context)
	{
		PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/RampFog"));
		propertySheet.properties.SetFloat("_FogIntensity", base.settings.fogIntensity);
		propertySheet.properties.SetFloat("_FogPower", base.settings.fogPower);
		propertySheet.properties.SetFloat("_FogZero", base.settings.fogZero);
		propertySheet.properties.SetFloat("_FogOne", base.settings.fogOne);
		propertySheet.properties.SetFloat("_FogHeightStart", base.settings.fogHeightStart);
		propertySheet.properties.SetFloat("_FogHeightEnd", base.settings.fogHeightEnd);
		propertySheet.properties.SetFloat("_FogHeightIntensity", base.settings.fogHeightIntensity);
		propertySheet.properties.SetColor("_FogColorStart", base.settings.fogColorStart);
		propertySheet.properties.SetColor("_FogColorMid", base.settings.fogColorMid);
		propertySheet.properties.SetColor("_FogColorEnd", base.settings.fogColorEnd);
		propertySheet.properties.SetFloat("_SkyboxStrength", base.settings.skyboxStrength);
		context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0);
	}
}
[Serializable]
[PostProcess(typeof(SceneTintRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/SceneTint", true)]
public sealed class SceneTint : PostProcessEffectSettings
{
	[Range(0f, 1f)]
	[Tooltip("The intensity of the tint.")]
	public FloatParameter tintIntensity = new FloatParameter
	{
		value = 0.5f
	};
}
public sealed class SceneTintRenderer : PostProcessEffectRenderer<SceneTint>
{
	public override void Render(PostProcessRenderContext context)
	{
		PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/SceneTint"));
		propertySheet.properties.SetFloat("_TintIntensity", base.settings.tintIntensity);
		context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0);
	}
}
[Serializable]
[PostProcess(typeof(ScreenDamagePPRenderer), PostProcessEvent.BeforeStack, "PostProcess/ScreenDamage", true)]
public sealed class ScreenDamagePP : PostProcessEffectSettings
{
	[Tooltip("Screen tint color")]
	public ColorParameter VignetteTint = new ColorParameter
	{
		value = new UnityEngine.Color(0f, 0.5709429f, 0.5955881f)
	};

	[Tooltip("Distortion normal map")]
	public TextureParameter OffsetMap = new TextureParameter();

	[Tooltip("Distortion strength")]
	public FloatParameter DistortionStrength = new FloatParameter();

	[Tooltip("Desaturation strength")]
	public FloatParameter DesaturationStrength = new FloatParameter();

	[Tooltip("Tint strength")]
	public FloatParameter TintStrength = new FloatParameter();
}
public sealed class ScreenDamagePPRenderer : PostProcessEffectRenderer<ScreenDamagePP>
{
	private static readonly int NormalMap = Shader.PropertyToID("_NormalMap");

	private static readonly int Tint = Shader.PropertyToID("_Tint");

	private static readonly int DistortionStrength = Shader.PropertyToID("_DistortionStrength");

	private static readonly int DesaturationStrength = Shader.PropertyToID("_DesaturationStrength");

	private static readonly int TintStrength = Shader.PropertyToID("_TintStrength");

	private static readonly int CombinationType = Shader.PropertyToID("_CombinationType");

	private Shader shader;

	private static bool propsSet;

	private static bool usingTemporaryProps;

	private static int temporaryPropsSetExpirationFrameStamp;

	public static ColorParameter temporaryVignetteTint;

	public static TextureParameter temporaryOffsetMap;

	public static bool temporaryCombineAdditively;

	public static ScreenDamageCalculator temporaryPropsCalculator;

	private int temporaryPropsExpirationFrames = 2;

	public override void Init()
	{
		base.Init();
		shader = LegacyShaderAPI.Find("Shaders/PostProcess/HGScreenDamage");
		propsSet = false;
	}

	public static void ExtendTemporaryProps()
	{
		temporaryPropsSetExpirationFrameStamp++;
	}

	public static void SetTemporaryProps(ScreenDamageCalculator damageCalculator, ColorParameter tintColor, TextureParameter offsetMap, bool combineAdditively)
	{
		usingTemporaryProps = true;
		temporaryPropsCalculator = damageCalculator;
		temporaryVignetteTint = tintColor;
		temporaryOffsetMap = offsetMap;
		temporaryCombineAdditively = combineAdditively;
		temporaryPropsSetExpirationFrameStamp = int.MaxValue;
		propsSet = false;
	}

	public static void ClearTemporaryProps(ScreenDamageCalculator damageCalculator)
	{
		if (damageCalculator == temporaryPropsCalculator)
		{
			temporaryOffsetMap = null;
			temporaryVignetteTint = null;
			usingTemporaryProps = false;
			temporaryCombineAdditively = false;
			temporaryPropsSetExpirationFrameStamp = int.MaxValue;
			propsSet = false;
		}
	}

	private void HandlePropsSet(PropertySheet sheet, int frameCount)
	{
		propsSet = true;
		if (usingTemporaryProps && temporaryOffsetMap != null)
		{
			sheet.properties.SetTexture(NormalMap, temporaryOffsetMap);
		}
		else
		{
			sheet.properties.SetTexture(NormalMap, base.settings.OffsetMap);
		}
		if (usingTemporaryProps && temporaryVignetteTint != null)
		{
			sheet.properties.SetColor(Tint, temporaryVignetteTint);
		}
		else
		{
			sheet.properties.SetColor(Tint, base.settings.VignetteTint);
		}
		if (usingTemporaryProps && temporaryCombineAdditively)
		{
			sheet.properties.SetFloat(CombinationType, 1f);
		}
		else
		{
			sheet.properties.SetFloat(CombinationType, -1f);
		}
		if (usingTemporaryProps && (temporaryOffsetMap != null || temporaryVignetteTint != null))
		{
			temporaryPropsSetExpirationFrameStamp = frameCount + temporaryPropsExpirationFrames;
		}
		else
		{
			temporaryPropsSetExpirationFrameStamp = int.MaxValue;
		}
	}

	public override void Render(PostProcessRenderContext context)
	{
		PropertySheet propertySheet = context.propertySheets.Get(shader);
		int frameCount = Time.frameCount;
		if (usingTemporaryProps && propsSet && frameCount > temporaryPropsSetExpirationFrameStamp)
		{
			ClearTemporaryProps(temporaryPropsCalculator);
		}
		if (!propsSet)
		{
			HandlePropsSet(propertySheet, frameCount);
		}
		propertySheet.properties.SetFloat(DistortionStrength, base.settings.DistortionStrength);
		propertySheet.properties.SetFloat(DesaturationStrength, base.settings.DesaturationStrength);
		propertySheet.properties.SetFloat(TintStrength, base.settings.TintStrength);
		context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0);
	}
}
[Serializable]
[PostProcess(typeof(SobelOutlineRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/SobelOutline", true)]
public sealed class SobelOutline : PostProcessEffectSettings
{
	[Range(0f, 5f)]
	[Tooltip("The intensity of the outline.")]
	public FloatParameter outlineIntensity = new FloatParameter
	{
		value = 0.5f
	};

	[Range(0f, 10f)]
	[Tooltip("The falloff of the outline.")]
	public FloatParameter outlineScale = new FloatParameter
	{
		value = 1f
	};
}
public sealed class SobelOutlineRenderer : PostProcessEffectRenderer<SobelOutline>
{
	public override void Render(PostProcessRenderContext context)
	{
		PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/SobelOutline"));
		propertySheet.properties.SetFloat("_OutlineIntensity", base.settings.outlineIntensity);
		propertySheet.properties.SetFloat("_OutlineScale", base.settings.outlineScale);
		context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0);
	}
}
[Serializable]
[PostProcess(typeof(SobelRainRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/SobelRain", true)]
public sealed class SobelRain : PostProcessEffectSettings
{
	[Range(0f, 100f)]
	[Tooltip("The intensity of the rain.")]
	public FloatParameter rainIntensity = new FloatParameter
	{
		value = 0.5f
	};

	[Range(0f, 10f)]
	[Tooltip("The falloff of the outline. Higher values means it relies less on the sobel.")]
	public FloatParameter outlineScale = new FloatParameter
	{
		value = 1f
	};

	[Range(0f, 1f)]
	[Tooltip("The density of rain.")]
	public FloatParameter rainDensity = new FloatParameter
	{
		value = 1f
	};

	public TextureParameter rainTexture = new TextureParameter
	{
		value = null
	};

	public ColorParameter rainColor = new ColorParameter
	{
		value = UnityEngine.Color.white
	};
}
public sealed class SobelRainRenderer : PostProcessEffectRenderer<SobelRain>
{
	public override void Render(PostProcessRenderContext context)
	{
		PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcess/SobelRain"));
		propertySheet.properties.SetFloat("_RainIntensity", base.settings.rainIntensity);
		propertySheet.properties.SetFloat("_OutlineScale", base.settings.outlineScale);
		propertySheet.properties.SetFloat("_RainDensity", base.settings.rainDensity);
		propertySheet.properties.SetTexture("_RainTexture", base.settings.rainTexture);
		propertySheet.properties.SetColor("_RainColor", base.settings.rainColor);
		context.command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 0);
	}
}
public class DoXInYSecondsTracker
{
	private readonly float[] timestamps;

	private readonly float window;

	private int lastValidCount;

	private float newestTime => timestamps[0];

	private int requirement => timestamps.Length;

	public DoXInYSecondsTracker(int requirement, float window)
	{
		if (requirement < 1)
		{
			throw new ArgumentException("Argument must be greater than zero", "requirement");
		}
		timestamps = new float[requirement];
		Clear();
		this.window = window;
	}

	public void Clear()
	{
		for (int i = 0; i < timestamps.Length; i++)
		{
			timestamps[i] = float.NegativeInfinity;
		}
	}

	private int FindInsertionPosition(float t)
	{
		for (int i = 0; i < lastValidCount; i++)
		{
			if (timestamps[i] < t)
			{
				return i;
			}
		}
		return lastValidCount;
	}

	public bool Push(float t)
	{
		float num = t - window;
		if (t < newestTime)
		{
			lastValidCount = timestamps.Length;
		}
		int num2 = lastValidCount - 1;
		while (num2 >= 0 && !(num <= timestamps[num2]))
		{
			lastValidCount--;
			num2--;
		}
		int num3 = FindInsertionPosition(t);
		if (num3 < timestamps.Length)
		{
			lastValidCount++;
			ArrayUtils.ArrayInsertNoResize(timestamps, lastValidCount, num3, in t);
		}
		return lastValidCount == requirement;
	}
}
public class ChefController : NetworkBehaviour
{
	public delegate void YesChefEnded();

	[HideInInspector]
	public SkillStateOverrideData skillOverrides;

	private bool localCleaverFired;

	[SyncVar]
	public bool _cleaverAway;

	[SyncVar]
	public bool _recallCleaver;

	[NonSerialized]
	[SyncVar]
	public bool catchDirtied;

	[NonSerialized]
	public CleaverProjectile projectile;

	[NonSerialized]
	public CharacterBody characterBody;

	public Animator chefAnimator;

	internal float spreadBloom;

	public bool rolyPolyActive;

	private bool yesChefHeatActive;

	public YesChefEnded yesChefEndedDelegate;

	public bool blockOtherSkills;

	private bool cleaversAwayCached;

	public Transform handCleaverBone;

	public Transform[] cleaverStockBones;

	private UnityEngine.Vector3[] cleaverStockBones_DefaultLocalPosition;

	private float[] cleaverStockBones_AnimateInTimer01;

	private uint soundIDMoving;

	private uint soundIDServo;

	private float walkVolume_Target;

	private float walkVolume_Smoothed;

	private float servoStrain_Timer;

	private float servoStrain_VolumeSmoothed;

	private const float servoStrainFadeInDuration = 0.15f;

	private const float servoStrainFadeOutDuration = 0.5f;

	private Queue<FireProjectileInfo> cachedCleaverProjectileInfo = new Queue<FireProjectileInfo>();

	private Dictionary<ushort, CleaverProjectile> cleaverDictionary = new Dictionary<ushort, CleaverProjectile>();

	private static int kCmdCmdSetCleaverAway;

	private static int kCmdCmdSetRecallCleaver;

	public bool cleaverAway
	{
		get
		{
			if (!localCleaverFired)
			{
				return _cleaverAway;
			}
			return true;
		}
		set
		{
			if (base.hasAuthority)
			{
				Network_cleaverAway = value;
				CallCmdSetCleaverAway(value);
			}
		}
	}

	public bool recallCleaver
	{
		get
		{
			return _recallCleaver;
		}
		set
		{
			if (base.hasAuthority)
			{
				Network_recallCleaver = value;
				CallCmdSetRecallCleaver(value);
			}
		}
	}

	public bool Network_cleaverAway
	{
		get
		{
			return _cleaverAway;
		}
		[param: In]
		set
		{
			SetSyncVar(value, ref _cleaverAway, 1u);
		}
	}

	public bool Network_recallCleaver
	{
		get
		{
			return _recallCleaver;
		}
		[param: In]
		set
		{
			SetSyncVar(value, ref _recallCleaver, 2u);
		}
	}

	public bool NetworkcatchDirtied
	{
		get
		{
			return catchDirtied;
		}
		[param: In]
		set
		{
			SetSyncVar(value, ref catchDirtied, 4u);
		}
	}

	[Command]
	public void CmdSetCleaverAway(bool b)
	{
		Network_cleaverAway = b;
	}

	[Command]
	public void CmdSetRecallCleaver(bool b)
	{
		Network_recallCleaver = b;
	}

	private void Awake()
	{
		int num = cleaverStockBones.Length;
		cleaverStockBones_DefaultLocalPosition = new UnityEngine.Vector3[num];
		cleaverStockBones_AnimateInTimer01 = new float[num];
		for (int i = 0; i < num; i++)
		{
			cleaverStockBones_DefaultLocalPosition[i] = cleaverStockBones[i].localPosition;
		}
		soundIDMoving = Util.PlaySound("Play_chef_move_loop", base.gameObject);
		soundIDServo = Util.PlaySound("Play_chef_servo_loop", base.gameObject);
		if (characterBody == null)
		{
			characterBody = GetComponent<CharacterBody>();
		}
		chefAnimator = characterBody.modelLocator.modelTransform.GetComponent<Animator>();
	}

	private void Start()
	{
		CharacterBody obj = characterBody;
		obj.onJump = (CharacterBody.JumpDelegate)Delegate.Combine(obj.onJump, new CharacterBody.JumpDelegate(HandleJump));
	}

	private void OnDestroy()
	{
		CharacterBody obj = characterBody;
		obj.onJump = (CharacterBody.JumpDelegate)Delegate.Remove(obj.onJump, new CharacterBody.JumpDelegate(HandleJump));
	}

	public void SetYesChefHeatState(bool newYesChefHeatState)
	{
		yesChefHeatActive = newYesChefHeatState;
		if (!yesChefHeatActive)
		{
			yesChefEndedDelegate?.Invoke();
		}
	}

	private void HandleJump()
	{
		ActivateServoStrainSfxForDuration();
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public void ActivateServoStrainSfxForDuration(float duration = 0.5f)
	{
		servoStrain_Timer = Mathf.Max(servoStrain_Timer, duration);
	}

	public void CacheCleaverProjectileFireInfo(FireProjectileInfo fireProjectileInfo)
	{
		cachedCleaverProjectileInfo.Enqueue(fireProjectileInfo);
	}

	public bool TryRetrieveCachedProjectileFireInfo(out FireProjectileInfo fireProjectileInfo)
	{
		fireProjectileInfo = default(FireProjectileInfo);
		if (cachedCleaverProjectileInfo.Count < 0 || !base.hasAuthority)
		{
			return false;
		}
		fireProjectileInfo = cachedCleaverProjectileInfo.Dequeue();
		return true;
	}

	private void Update()
	{
		if ((bool)characterBody && !recallCleaver && cleaverAway)
		{
			characterBody.SetSpreadBloom(spreadBloom);
		}
		CharacterMotor characterMotor = characterBody.characterMotor;
		UnityEngine.Vector3 velocity = characterMotor.velocity;
		float sqrMagnitude = velocity.sqrMagnitude;
		bool isGrounded = characterMotor.isGrounded;
		bool @bool = chefAnimator.GetBool("isSprinting");
		UnityEngine.Vector3 vector = (characterBody.inputBank ? characterBody.inputBank.moveVector : UnityEngine.Vector3.zero);
		if (isGrounded && sqrMagnitude > Mathf.Epsilon)
		{
			if (rolyPolyActive)
			{
				walkVolume_Target = 1f;
			}
			else if (vector != UnityEngine.Vector3.zero)
			{
				if (@bool)
				{
					walkVolume_Target = 0.8f;
				}
				else
				{
					walkVolume_Target = 0.5f;
				}
			}
		}
		else
		{
			walkVolume_Target = Mathf.MoveTowards(walkVolume_Target, 0f, Time.deltaTime / (1f / 3f));
		}
		walkVolume_Smoothed = Mathf.MoveTowards(walkVolume_Smoothed, Mathf.Clamp01(walkVolume_Target), Time.deltaTime / (4f / 15f));
		AkSoundEngine.SetRTPCValueByPlayingID("charChefSpeed", walkVolume_Smoothed * 100f, soundIDMoving);
		if (servoStrain_Timer > 0f)
		{
			servoStrain_Timer -= Time.deltaTime;
		}
		if (servoStrain_Timer > 0f)
		{
			float maxDelta = Time.deltaTime / 0.15f;
			servoStrain_VolumeSmoothed = Mathf.MoveTowards(servoStrain_VolumeSmoothed, 1f, maxDelta);
		}
		else
		{
			float maxDelta2 = Time.deltaTime / 0.5f;
			servoStrain_VolumeSmoothed = Mathf.MoveTowards(servoStrain_VolumeSmoothed, 0f, maxDelta2);
		}
	}

	private void LateUpdate()
	{
		bool flag = cleaverDictionary.Count > 0;
		if (flag != cleaversAwayCached || flag)
		{
			cleaversAwayCached = flag;
			handCleaverBone.localScale = (flag ? UnityEngine.Vector3.zero : UnityEngine.Vector3.one);
		}
		if (!(characterBody != null) || !(characterBody.skillLocator != null) || !(characterBody.skillLocator.primary != null))
		{
			return;
		}
		int stock = characterBody.skillLocator.primary.stock;
		int num = cleaverStockBones.Length;
		float deltaTime = Time.deltaTime;
		float num2 = 8f;
		float num3 = -0.2f;
		for (int i = 0; i < num; i++)
		{
			bool num4 = i + 1 <= stock;
			float current = cleaverStockBones_AnimateInTimer01[i];
			current = ((!num4) ? 0f : Mathf.MoveTowards(current, 1f, deltaTime * num2));
			cleaverStockBones_AnimateInTimer01[i] = current;
			if (current != 1f)
			{
				current = 1f - current;
				current *= current;
				cleaverStockBones[i].localScale = UnityEngine.Vector3.one * (1f - current);
				cleaverStockBones[i].localPosition = cleaverStockBones_DefaultLocalPosition[i] + current * UnityEngine.Vector3.up * num3;
			}
		}
	}

	internal void AddLocalProjectileReference(ushort predictionId, CleaverProjectile cleaverProjectile)
	{
		if (!cleaverDictionary.ContainsKey(predictionId) || !cleaverProjectile.projectileController.isPrediction)
		{
			cleaverDictionary[predictionId] = cleaverProjectile;
		}
	}

	internal void RemoveLocalProjectileReference(ushort predictionId)
	{
		if (cleaverDictionary.ContainsKey(predictionId))
		{
			cleaverDictionary.Remove(predictionId);
		}
		if (cleaverDictionary.Count < 1)
		{
			localCleaverFired = false;
			cleaverAway = false;
			recallCleaver = false;
		}
	}

	public void TransferSkillOverrides(SkillStateOverrideData skillOverrideData)
	{
		if (skillOverrides != null)
		{
			if (skillOverrides == skillOverrideData)
			{
				return;
			}
			skillOverrides.ClearOverrides();
		}
		skillOverrides = skillOverrideData;
	}

	public void ClearSkillOverrides()
	{
		if (skillOverrides != null)
		{
			skillOverrides.ClearOverrides();
		}
		skillOverrides = null;
	}

	[Server]
	public void DestroyCleavers()
	{
		if (!NetworkServer.active)
		{
			UnityEngine.Debug.LogWarning("[Server] function 'System.Void ChefController::DestroyCleavers()' called on client");
			return;
		}
		foreach (CleaverProjectile value in cleaverDictionary.Values)
		{
			value.CallCmdDestroyAndCleanup();
		}
	}

	private void UNetVersion()
	{
	}

	protected static void InvokeCmdCmdSetCleaverAway(NetworkBehaviour obj, NetworkReader reader)
	{
		if (!NetworkServer.active)
		{
			UnityEngine.Debug.LogError("Command CmdSetCleaverAway called on client.");
		}
		else
		{
			((ChefController)obj).CmdSetCleaverAway(reader.ReadBoolean());
		}
	}

	protected static void InvokeCmdCmdSetRecallCleaver(NetworkBehaviour obj, NetworkReader reader)
	{
		if (!NetworkServer.active)
		{
			UnityEngine.Debug.LogError("Command CmdSetRecallCleaver called on client.");
		}
		else
		{
			((ChefController)obj).CmdSetRecallCleaver(reader.ReadBoolean());
		}
	}

	public void CallCmdSetCleaverAway(bool b)
	{
		if (!NetworkClient.active)
		{
			UnityEngine.Debug.LogError("Command function CmdSetCleaverAway called on server.");
			return;
		}
		if (base.isServer)
		{
			CmdSetCleaverAway(b);
			return;
		}
		NetworkWriter networkWriter = new NetworkWriter();
		networkWriter.Write((short)0);
		networkWriter.Write((short)5);
		networkWriter.WritePackedUInt32((uint)kCmdCmdSetCleaverAway);
		networkWriter.Write(GetComponent<NetworkIdentity>().netId);
		networkWriter.Write(b);
		SendCommandInternal(networkWriter, 0, "CmdSetCleaverAway");
	}

	public void CallCmdSetRecallCleaver(bool b)
	{
		if (!NetworkClient.active)
		{
			UnityEngine.Debug.LogError("Command function CmdSetRecallCleaver called on server.");
			return;
		}
		if (base.isServer)
		{
			CmdSetRecallCleaver(b);
			return;
		}
		NetworkWriter networkWriter = new NetworkWriter();
		networkWriter.Write((short)0);
		networkWriter.Write((short)5);
		networkWriter.WritePackedUInt32((uint)kCmdCmdSetRecallCleaver);
		networkWriter.Write(GetComponent<NetworkIdentity>().netId);
		networkWriter.Write(b);
		SendCommandInternal(networkWriter, 0, "CmdSetRecallCleaver");
	}

	static ChefController()
	{
		kCmdCmdSetCleaverAway = -1756854004;
		NetworkBehaviour.RegisterCommandDelegate(typeof(ChefController), kCmdCmdSetCleaverAway, InvokeCmdCmdSetCleaverAway);
		kCmdCmdSetRecallCleaver = 535604397;
		NetworkBehaviour.RegisterCommandDelegate(typeof(ChefController), kCmdCmdSetRecallCleaver, InvokeCmdCmdSetRecallCleaver);
		NetworkCRC.RegisterBehaviour("ChefController", 0);
	}

	public override bool OnSerialize(NetworkWriter writer, bool forceAll)
	{
		if (forceAll)
		{
			writer.Write(_cleaverAway);
			writer.Write(_recallCleaver);
			writer.Write(catchDirtied);
			return true;
		}
		bool flag = false;
		if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
		{
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
				flag = true;
			}
			writer.Write(_cleaverAway);
		}
		if ((base.syncVarDirtyBits & 2u) != 0)
		{
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
				flag = true;
			}
			writer.Write(_recallCleaver);
		}
		if ((base.syncVarDirtyBits & 4u) != 0)
		{
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
				flag = true;
			}
			writer.Write(catchDirtied);
		}
		if (!flag)
		{
			writer.WritePackedUInt32(base.syncVarDirtyBits);
		}
		return flag;
	}

	public override void OnDeserialize(NetworkReader reader, bool initialState)
	{
		if (initialState)
		{
			_cleaverAway = reader.ReadBoolean();
			_recallCleaver = reader.ReadBoolean();
			catchDirtied = reader.ReadBoolean();
			return;
		}
		int num = (int)reader.ReadPackedUInt32();
		if (((uint)num & (true ? 1u : 0u)) != 0)
		{
			_cleaverAway = reader.ReadBoolean();
		}
		if (((uint)num & 2u) != 0)
		{
			_recallCleaver = reader.ReadBoolean();
		}
		if (((uint)num & 4u) != 0)
		{
			catchDirtied = reader.ReadBoolean();
		}
	}

	public override void PreStartClient()
	{
	}
}
public class ChefFoodPickController : MonoBehaviour
{
	[SerializeField]
	public GameObject foodModel1;

	[SerializeField]
	public GameObject foodModel2;

	[SerializeField]
	public GameObject foodModel3;

	private void Start()
	{
		switch (UnityEngine.Random.Range(0, 2))
		{
		case 0:
			foodModel1.SetActive(value: true);
			break;
		case 1:
			foodModel2.SetActive(value: true);
			break;
		case 2:
			foodModel3.SetActive(value: true);
			break;
		}
	}
}
public class RolyPolyBoostedProjectileTimer : MonoBehaviour
{
	private ChefController chefController;

	private void OnEnable()
	{
		ProjectileController component = base.gameObject.GetComponent<ProjectileController>();
		if ((bool)component)
		{
			component.onInitialized += GetChefController;
		}
	}

	private void GetChefController(ProjectileController projectileController)
	{
		chefController = projectileController.owner.GetComponent<ChefController>();
	}

	private void Update()
	{
		if ((bool)chefController && !chefController.rolyPolyActive && Util.HasEffectiveAuthority(base.gameObject))
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}
}
public class YesChefHeatProjectileTimer : MonoBehaviour
{
	private ChefController chefController;

	private ProjectileController projectileController;

	private void OnEnable()
	{
		if (NetworkServer.active)
		{
			projectileController = base.gameObject.GetComponent<ProjectileController>();
			if ((bool)projectileController)
			{
				projectileController.onInitialized += GetChefController;
			}
		}
	}

	private void GetChefController(ProjectileController projectileController)
	{
		chefController = projectileController.owner.GetComponent<ChefController>();
		ChefController obj = chefController;
		obj.yesChefEndedDelegate = (ChefController.YesChefEnded)Delegate.Combine(obj.yesChefEndedDelegate, new ChefController.YesChefEnded(EndChefHeatProjectile));
	}

	private void EndChefHeatProjectile()
	{
		if (NetworkServer.active)
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}

	private void OnDestroy()
	{
		if ((bool)projectileController)
		{
			projectileController.onInitialized -= GetChefController;
		}
		if ((bool)chefController)
		{
			ChefController obj = chefController;
			obj.yesChefEndedDelegate = (ChefController.YesChefEnded)Delegate.Remove(obj.yesChefEndedDelegate, new ChefController.YesChefEnded(EndChefHeatProjectile));
		}
	}
}
public class PrimeDevastatorProjectileController : MonoBehaviour
{
	public ProjectileOwnerOrbiter orbiter;

	public float expansionSpeed = 1f;

	private float orbitExpansionTimer;

	private void Start()
	{
	}

	private void Update()
	{
		ProjectileOwnerOrbiter projectileOwnerOrbiter = orbiter;
		projectileOwnerOrbiter.Networkradius = projectileOwnerOrbiter.radius + Time.deltaTime * expansionSpeed;
	}
}
public class HereticInitialStateHelper : MonoBehaviour
{
	[SerializeField]
	private EntityStateMachine entityStateMachine;

	public void PrepareTransformation()
	{
		entityStateMachine.initialStateType = new SerializableEntityStateType(typeof(EntityStates.Heretic.SpawnState));
	}
}
public class ScorchlingController : MonoBehaviour
{
	public CharacterBody characterBody;

	public CharacterMotor characterMotor;

	private RigidbodyMotor rigidBodyMotor;

	public string burrowingSoundString;

	public Transform burrowFX;

	public float timeInAirToTele;

	public float timeInAirToShutOffDustTrail = 0.2f;

	private float inAirTimer;

	public GameObject breachEffectPrefab;

	public float breachEffectRadius = 5f;

	public float teleCooldown;

	private GameObject dustTrail;

	private GameObject baseDirt;

	private GameObject armatureObject;

	private GameObject meshObject;

	public bool isBurrowed = true;

	public bool isRecentlyBurrowed = true;

	public bool canTeleport = true;

	private bool dustTrailActive;

	private float teleportTimer;

	private float teleportCooldownDuration = 3f;

	private UnityEngine.Vector3 lastSafePosition;

	private GenericSkill breachSkill;

	private GenericSkill lavaBombSkill;

	private GenericSkill ensureBurrowSkill;

	private UnityEngine.Quaternion breachBaseDirtRotation;

	private int originalLayer;

	private float cachedYPosition;

	private void Start()
	{
		ChildLocator component = characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>();
		dustTrail = component.FindChild("BurrowLocation").gameObject;
		baseDirt = component.FindChild("BaseDirt").gameObject;
		armatureObject = component.FindChild("Armature").gameObject;
		meshObject = component.FindChild("Mesh").gameObject;
		dustTrailActive = dustTrail.activeInHierarchy;
		SkillLocator skillLocator = characterBody.skillLocator;
		breachSkill = skillLocator.GetSkill(SkillSlot.Primary);
		lavaBombSkill = skillLocator.GetSkill(SkillSlot.Secondary);
		ensureBurrowSkill = skillLocator.GetSkill(SkillSlot.Utility);
		rigidBodyMotor = GetComponent<RigidbodyMotor>();
		Burrow();
		teleportTimer = teleportCooldownDuration;
	}

	private void Update()
	{
		if (!isBurrowed)
		{
			return;
		}
		float deltaTime = Time.deltaTime;
		teleportTimer += deltaTime;
		if (!characterMotor.isGrounded)
		{
			if (characterBody.footPosition.y > cachedYPosition)
			{
				cachedYPosition = characterBody.footPosition.y;
				return;
			}
			inAirTimer += deltaTime;
			cachedYPosition = characterBody.footPosition.y;
			if (dustTrailActive && inAirTimer > timeInAirToShutOffDustTrail)
			{
				dustTrailActive = false;
				dustTrail.SetActive(value: false);
				EffectManager.SpawnEffect(breachEffectPrefab, new EffectData
				{
					origin = characterBody.footPosition,
					scale = breachEffectRadius
				}, transmit: true);
			}
			if (!(teleportTimer < teleportCooldownDuration) && canTeleport && inAirTimer > timeInAirToTele && NetworkServer.active)
			{
				UnityEngine.Vector3 bestTeleportPosition = GetBestTeleportPosition();
				TeleportHelper.TeleportBody(characterBody, bestTeleportPosition);
				inAirTimer = 0f;
				teleportTimer = 0f;
			}
		}
		else
		{
			inAirTimer = 0f;
			cachedYPosition = float.MaxValue;
			lastSafePosition = characterBody.footPosition;
			if (!dustTrailActive)
			{
				dustTrail.SetActive(value: true);
				dustTrailActive = true;
				EffectManager.SpawnEffect(breachEffectPrefab, new EffectData
				{
					origin = characterBody.footPosition,
					scale = breachEffectRadius
				}, transmit: true);
			}
		}
	}

	public void ResetTeleportTimer()
	{
		teleportTimer = 0f;
		inAirTimer = 0f;
	}

	public void SetTeleportPermission(bool b)
	{
		canTeleport = b;
		ResetTeleportTimer();
	}

	private UnityEngine.Vector3 GetBestTeleportPosition()
	{
		NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
		List<NodeGraph.NodeIndex> list = nodeGraph.FindNodesInRange(characterBody.corePosition, 3f, 16f, HullMask.Human);
		if (list.Count < 1)
		{
			return lastSafePosition;
		}
		nodeGraph.GetNodePosition(list[0], out var position);
		return position;
	}

	public void Burrow()
	{
		isRecentlyBurrowed = true;
		isBurrowed = true;
		SetTeleportPermission(b: true);
		if (NetworkServer.active)
		{
			breachSkill.stock = 1;
			lavaBombSkill.stock = 0;
			ensureBurrowSkill.stock = 5;
			characterMotor.walkSpeedPenaltyCoefficient = 1f;
			if (characterBody.GetBuffCount(RoR2Content.Buffs.HiddenInvincibility.buffIndex) < 1)
			{
				characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
		}
		originalLayer = base.gameObject.layer;
		base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(characterBody.teamComponent.teamIndex).intVal;
		characterMotor.Motor.RebuildCollidableLayers();
		if ((bool)baseDirt && (bool)dustTrail)
		{
			baseDirt.SetActive(value: false);
			dustTrail.SetActive(value: true);
			dustTrailActive = true;
			armatureObject.SetActive(value: false);
			meshObject.SetActive(value: false);
		}
	}

	public void LateUpdate()
	{
		if (!isBurrowed && (bool)baseDirt && NetworkServer.active && baseDirt.transform.rotation != breachBaseDirtRotation)
		{
			baseDirt.transform.rotation = breachBaseDirtRotation;
		}
	}

	public void Breach()
	{
		isBurrowed = false;
		SetTeleportPermission(b: false);
		if (NetworkServer.active)
		{
			characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			breachSkill.stock = 0;
			lavaBombSkill.stock = 1;
			ensureBurrowSkill.stock = 5;
			characterMotor.walkSpeedPenaltyCoefficient = 0f;
			if ((bool)characterBody)
			{
				characterBody.isSprinting = false;
			}
			if ((bool)rigidBodyMotor)
			{
				rigidBodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
			breachBaseDirtRotation = baseDirt.transform.rotation;
			breachBaseDirtRotation.eulerAngles = new UnityEngine.Vector3(breachBaseDirtRotation.eulerAngles.x, Mathf.Floor(breachBaseDirtRotation.eulerAngles.y), breachBaseDirtRotation.eulerAngles.z);
			baseDirt.transform.localEulerAngles = UnityEngine.Vector3.zero;
			baseDirt.transform.rotation = breachBaseDirtRotation;
		}
		base.gameObject.layer = originalLayer;
		characterMotor.Motor.RebuildCollidableLayers();
		if ((bool)baseDirt && (bool)dustTrail)
		{
			baseDirt.SetActive(value: true);
			dustTrail.SetActive(value: false);
			dustTrailActive = false;
			armatureObject.SetActive(value: true);
			meshObject.SetActive(value: true);
		}
	}
}
public class FirstSelectedObjectProvider : MonoBehaviour
{
	public GameObject firstSelectedObject;

	public GameObject[] fallBackFirstSelectedObjects;

	private GameObject lastSelected;

	public GameObject[] enforceCurrentSelectionIsInList;

	public bool takeAbsolutePriority;

	public static FirstSelectedObjectProvider priorityHolder;

	private void OnEnable()
	{
		if (takeAbsolutePriority)
		{
			priorityHolder = this;
		}
	}

	private void OnDisable()
	{
		if (takeAbsolutePriority && priorityHolder == this)
		{
			priorityHolder = null;
		}
	}

	private GameObject getInteractableFirstSelectedObject()
	{
		if ((bool)firstSelectedObject && firstSelectedObject.GetComponent<Selectable>().interactable && firstSelectedObject.activeInHierarchy)
		{
			return firstSelectedObject;
		}
		if (fallBackFirstSelectedObjects == null)
		{
			return null;
		}
		for (int i = 0; i < fallBackFirstSelectedObjects.Length; i++)
		{
			if (fallBackFirstSelectedObjects[i].GetComponent<Selectable>().interactable && fallBackFirstSelectedObjects[i].activeInHierarchy)
			{
				return fallBackFirstSelectedObjects[i];
			}
		}
		return null;
	}

	public void EnsureSelectedObject()
	{
		if (priorityHolder != null && priorityHolder != this)
		{
			return;
		}
		GameObject interactableFirstSelectedObject = getInteractableFirstSelectedObject();
		if (!(interactableFirstSelectedObject != null))
		{
			return;
		}
		MPEventSystemLocator component = interactableFirstSelectedObject.GetComponent<MPEventSystemLocator>();
		if (!component)
		{
			return;
		}
		MPEventSystem eventSystem = component.eventSystem;
		if (!eventSystem)
		{
			return;
		}
		GameObject currentSelectedGameObject = eventSystem.currentSelectedGameObject;
		if (currentSelectedGameObject == null)
		{
			if (lastSelected != null && lastSelected.GetComponent<Selectable>().interactable)
			{
				eventSystem.SetSelectedGameObject(lastSelected);
			}
			else
			{
				if (eventSystem.firstSelectedGameObject == null)
				{
					eventSystem.firstSelectedGameObject = interactableFirstSelectedObject;
				}
				eventSystem.SetSelectedGameObject(interactableFirstSelectedObject);
			}
		}
		else
		{
			Selectable component2 = currentSelectedGameObject.GetComponent<Selectable>();
			bool flag = true;
			if (enforceCurrentSelectionIsInList != null && enforceCurrentSelectionIsInList.Length != 0)
			{
				flag = false;
				GameObject[] array = enforceCurrentSelectionIsInList;
				for (int i = 0; i < array.Length; i++)
				{
					if (array[i] == currentSelectedGameObject)
					{
						flag = true;
					}
				}
			}
			if ((bool)component2 && (!component2.interactable || !component2.isActiveAndEnabled))
			{
				flag = false;
			}
			if (!flag && (bool)component2 && (!component2.interactable || !component2.isActiveAndEnabled))
			{
				eventSystem.SetSelectedGameObject(interactableFirstSelectedObject);
			}
		}
		if (component.eventSystem.currentSelectedGameObject != null)
		{
			lastSelected = component.eventSystem.currentSelectedGameObject;
		}
	}

	public void ForceSelectFirstInteractable()
	{
		GameObject interactableFirstSelectedObject = getInteractableFirstSelectedObject();
		if (!(interactableFirstSelectedObject != null))
		{
			return;
		}
		MPEventSystemLocator component = interactableFirstSelectedObject.GetComponent<MPEventSystemLocator>();
		if (!component)
		{
			return;
		}
		MPEventSystem eventSystem = component.eventSystem;
		if ((bool)eventSystem)
		{
			if (eventSystem.firstSelectedGameObject == null)
			{
				eventSystem.firstSelectedGameObject = interactableFirstSelectedObject;
			}
			eventSystem.SetSelectedGameObject(interactableFirstSelectedObject);
		}
		if (component.eventSystem.currentSelectedGameObject != null)
		{
			lastSelected = component.eventSystem.currentSelectedGameObject;
		}
	}

	public void ResetLastSelected()
	{
		lastSelected = null;
	}

	public void AddObject(GameObject obj, bool enforceCurrentSelection = false)
	{
		if (firstSelectedObject == null)
		{
			firstSelectedObject = obj;
		}
		else if (fallBackFirstSelectedObjects == null)
		{
			fallBackFirstSelectedObjects = new GameObject[1];
			fallBackFirstSelectedObjects[0] = obj;
		}
		else if (fallBackFirstSelectedObjects.Length >= 0)
		{
			List<GameObject> list = new List<GameObject>(fallBackFirstSelectedObjects);
			list.Add(obj);
			fallBackFirstSelectedObjects = list.ToArray();
		}
		if (enforceCurrentSelection)
		{
			if (enforceCurrentSelectionIsInList == null)
			{
				enforceCurrentSelectionIsInList = new GameObject[1];
				enforceCurrentSelectionIsInList[0] = obj;
			}
			else if (enforceCurrentSelectionIsInList.Length >= 0)
			{
				List<GameObject> list2 = new List<GameObject>(enforceCurrentSelectionIsInList);
				list2.Add(obj);
				enforceCurrentSelectionIsInList = list2.ToArray();
			}
		}
	}
}
public static class FlashWindow
{
	private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

	private struct FLASHWINFO
	{
		public uint cbSize;

		public IntPtr hwnd;

		public uint dwFlags;

		public uint uCount;

		public uint dwTimeout;
	}

	private static IntPtr myWindow;

	private static readonly IntPtr myProcessId = GetCurrentProcessId();

	public const uint FLASHW_STOP = 0u;

	public const uint FLASHW_CAPTION = 1u;

	public const uint FLASHW_TRAY = 2u;

	public const uint FLASHW_ALL = 3u;

	public const uint FLASHW_TIMER = 4u;

	public const uint FLASHW_TIMERNOFG = 12u;

	private static bool Win2000OrLater => Environment.OSVersion.Version.Major >= 5;

	[DllImport("user32.dll")]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool FlashWindowEx(ref FLASHWINFO pwfi);

	[DllImport("user32.dll")]
	private static extern IntPtr GetActiveWindow();

	[DllImport("user32.dll")]
	private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);

	[DllImport("user32.dll")]
	private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);

	[DllImport("kernel32.dll")]
	private static extern IntPtr GetCurrentProcessId();

	private static bool GetWindowEnum(IntPtr hWnd, IntPtr lParam)
	{
		GetWindowThreadProcessId(hWnd, out var lpdwProcessId);
		if (lpdwProcessId == myProcessId)
		{
			myWindow = hWnd;
			return false;
		}
		return true;
	}

	private static void UpdateCurrentWindow()
	{
		EnumWindows(GetWindowEnum, IntPtr.Zero);
	}

	private static bool IsCurrentWindowValid()
	{
		GetWindowThreadProcessId(myWindow, out var lpdwProcessId);
		if (lpdwProcessId != myProcessId)
		{
			myWindow = IntPtr.Zero;
		}
		return myWindow != IntPtr.Zero;
	}

	public static IntPtr GetWindowHandle()
	{
		if (!IsCurrentWindowValid())
		{
			UpdateCurrentWindow();
		}
		return myWindow;
	}

	public static bool Flash(IntPtr formHandle)
	{
		if (Win2000OrLater)
		{
			FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 15u, uint.MaxValue, 0u);
			return FlashWindowEx(ref pwfi);
		}
		return false;
	}

	private static FLASHWINFO Create_FLASHWINFO(IntPtr handle, uint flags, uint count, uint timeout)
	{
		FLASHWINFO fLASHWINFO = default(FLASHWINFO);
		fLASHWINFO.cbSize = System.Convert.ToUInt32(Marshal.SizeOf(fLASHWINFO));
		fLASHWINFO.hwnd = handle;
		fLASHWINFO.dwFlags = flags;
		fLASHWINFO.uCount = count;
		fLASHWINFO.dwTimeout = timeout;
		return fLASHWINFO;
	}

	public static bool Flash(IntPtr formHandle, uint count)
	{
		if (Win2000OrLater)
		{
			FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 3u, count, 0u);
			return FlashWindowEx(ref pwfi);
		}
		return false;
	}

	public static bool Flash()
	{
		return Flash(GetWindowHandle());
	}

	public static bool Start(IntPtr formHandle)
	{
		if (Win2000OrLater)
		{
			FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 3u, uint.MaxValue, 0u);
			return FlashWindowEx(ref pwfi);
		}
		return false;
	}

	public static bool Stop(IntPtr formHandle)
	{
		if (Win2000OrLater)
		{
			FLASHWINFO pwfi = Create_FLASHWINFO(formHandle, 0u, uint.MaxValue, 0u);
			return FlashWindowEx(ref pwfi);
		}
		return false;
	}

	[InitDuringStartup]
	private static void Init()
	{
		SceneManager.activeSceneChanged += delegate(Scene previousScene, Scene newScene)
		{
			if (newScene.name == "lobby")
			{
				Flash();
			}
		};
		NetworkManagerSystem.onClientConnectGlobal += delegate
		{
			Flash();
		};
	}
}
public class FPSQueue : MonoBehaviour
{
	public static float fpsThrottlingCutoff = 28f;

	public static float currentFPS = 30f;

	public static int numSamples = 30;

	private static int sampleIndex = 0;

	private static float[] unitySamples;

	private static int waitTurn = 0;

	private static int waitIndex = 0;

	private static int maxWaitIndex = 5;

	private void Start()
	{
		RoR2Application.onUpdate += UpdateFPSLimitVars;
		unitySamples = new float[numSamples];
	}

	public static int GetWaitIndex()
	{
		waitIndex++;
		if (waitIndex > maxWaitIndex)
		{
			waitIndex = 0;
		}
		return waitIndex;
	}

	public static bool CheckFPSQueue(ref int waitIndex)
	{
		if (waitIndex == 0)
		{
			waitIndex = GetWaitIndex();
		}
		if (currentFPS < fpsThrottlingCutoff && waitIndex != waitTurn)
		{
			return false;
		}
		return true;
	}

	private static void UpdateFPSLimitVars()
	{
		waitTurn++;
		if (waitTurn > maxWaitIndex)
		{
			waitTurn = 0;
		}
		CalculateFramerate();
	}

	private static void CalculateFramerate()
	{
		unitySamples[sampleIndex++] = 1f / Time.unscaledDeltaTime;
		if (sampleIndex == numSamples)
		{
			sampleIndex = 0;
		}
		float num = 0f;
		for (int i = 0; i < numSamples; i++)
		{
			num += unitySamples[i];
		}
		currentFPS = num / (float)numSamples;
	}
}
[ExecuteAlways]
public class BeamPointsFromTransforms : MonoBehaviour
{
	[Tooltip("Line Renderer to set the positions of.")]
	public LineRenderer target;

	[Tooltip("Transforms to use as the points for the line renderer.")]
	[SerializeField]
	private Transform[] pointTransforms = Array.Empty<Transform>();

	private void Start()
	{
		UpdateBeamPositions();
	}

	private void Update()
	{
		UpdateBeamPositions();
	}

	private void UpdateBeamPositions()
	{
		if (!target)
		{
			return;
		}
		int num = pointTransforms.Length;
		target.positionCount = num;
		for (int i = 0; i < num; i++)
		{
			Transform transform = pointTransforms[i];
			if ((bool)transform)
			{
				target.SetPosition(i, transform.position);
			}
		}
	}
}
public class BeginRapidlyActivatingAndDeactivating : MonoBehaviour
{
	public float blinkFrequency = 10f;

	public float delayBeforeBeginningBlinking = 30f;

	public GameObject blinkingRootObject;

	private float fixedAge;

	private float blinkAge;

	private void FixedUpdate()
	{
		fixedAge += Time.fixedDeltaTime;
		if (fixedAge >= delayBeforeBeginningBlinking)
		{
			blinkAge += Time.fixedDeltaTime;
			if (blinkAge >= 1f / blinkFrequency)
			{
				blinkAge -= 1f / blinkFrequency;
				blinkingRootObject.SetActive(!blinkingRootObject.activeSelf);
			}
		}
	}
}
[RequireComponent(typeof(LineRenderer))]
[ExecuteAlways]
public class BezierCurveLine : MonoBehaviour
{
	private UnityEngine.Vector3[] vertexList = Array.Empty<UnityEngine.Vector3>();

	private UnityEngine.Vector3 p0 = UnityEngine.Vector3.zero;

	public UnityEngine.Vector3 v0 = UnityEngine.Vector3.zero;

	public UnityEngine.Vector3 p1 = UnityEngine.Vector3.zero;

	public UnityEngine.Vector3 v1 = UnityEngine.Vector3.zero;

	public Transform endTransform;

	public bool animateBezierWind;

	public UnityEngine.Vector3 windMagnitude;

	public UnityEngine.Vector3 windFrequency;

	private UnityEngine.Vector3 windPhaseShift;

	private UnityEngine.Vector3 lastWind;

	private UnityEngine.Vector3 finalv0;

	private UnityEngine.Vector3 finalv1;

	private float windTime;

	public LineRenderer lineRenderer { get; private set; }

	private void Awake()
	{
		lineRenderer = GetComponent<LineRenderer>();
		windPhaseShift = UnityEngine.Random.insideUnitSphere * 360f;
		Array.Resize(ref vertexList, lineRenderer.positionCount + 1);
		UpdateBezier(0f);
	}

	public void OnEnable()
	{
		Array.Resize(ref vertexList, lineRenderer.positionCount + 1);
	}

	private void LateUpdate()
	{
		UpdateBezier(Time.deltaTime);
	}

	public void UpdateBezier(float deltaTime)
	{
		windTime += deltaTime;
		p0 = base.transform.position;
		if ((bool)endTransform)
		{
			p1 = endTransform.position;
		}
		if (animateBezierWind)
		{
			finalv0 = v0 + new UnityEngine.Vector3(Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.x) * windFrequency.x) * windMagnitude.x, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.y) * windFrequency.y) * windMagnitude.y, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.z) * windFrequency.z) * windMagnitude.z);
			finalv1 = v1 + new UnityEngine.Vector3(Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.x + p1.x) * windFrequency.x) * windMagnitude.x, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.y + p1.z) * windFrequency.y) * windMagnitude.y, Mathf.Sin(MathF.PI / 180f * (windTime * 360f + windPhaseShift.z + p1.y) * windFrequency.z) * windMagnitude.z);
		}
		else
		{
			finalv0 = v0;
			finalv1 = v1;
		}
		for (int i = 0; i < vertexList.Length; i++)
		{
			float t = (float)i / (float)(vertexList.Length - 2);
			vertexList[i] = EvaluateBezier(t);
		}
		lineRenderer.SetPositions(vertexList);
	}

	private UnityEngine.Vector3 EvaluateBezier(float t)
	{
		UnityEngine.Vector3 a = UnityEngine.Vector3.Lerp(p0, p0 + finalv0, t);
		UnityEngine.Vector3 b = UnityEngine.Vector3.Lerp(p1, p1 + finalv1, 1f - t);
		return UnityEngine.Vector3.Lerp(a, b, t);
	}
}
public class BlockObjectOnLoad : MonoBehaviour
{
	private void Start()
	{
		if (!RoR2Application.loadFinished)
		{
			base.gameObject.SetActive(value: false);
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate
			{
				base.gameObject.SetActive(value: true);
			});
		}
	}
}
public class BobObject : MonoBehaviour
{
	public float bobDelay;

	public UnityEngine.Vector3 bobDistance = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 initialPosition;

	private void Start()
	{
		if ((bool)base.transform.parent)
		{
			initialPosition = base.transform.localPosition;
		}
		else
		{
			initialPosition = base.transform.position;
		}
	}

	private void FixedUpdate()
	{
		if ((bool)Run.instance)
		{
			UnityEngine.Vector3 vector = initialPosition + bobDistance * Mathf.Sin(Run.instance.fixedTime - bobDelay);
			if ((bool)base.transform.parent)
			{
				base.transform.localPosition = vector;
			}
			else
			{
				base.transform.position = vector;
			}
		}
	}
}
[DisallowMultipleComponent]
public class ChildLocator : MonoBehaviour
{
	[Serializable]
	private struct NameTransformPair
	{
		public string name;

		public Transform transform;
	}

	[SerializeField]
	private NameTransformPair[] transformPairs = Array.Empty<NameTransformPair>();

	public int Count => transformPairs.Length;

	public int FindChildIndex(string childName)
	{
		for (int i = 0; i < transformPairs.Length; i++)
		{
			if (childName == transformPairs[i].name)
			{
				return i;
			}
		}
		return -1;
	}

	public int FindChildIndex(Transform childTransform)
	{
		for (int i = 0; i < transformPairs.Length; i++)
		{
			if ((object)childTransform == transformPairs[i].transform)
			{
				return i;
			}
		}
		return -1;
	}

	public string FindChildName(int childIndex)
	{
		if ((uint)childIndex < transformPairs.Length)
		{
			return transformPairs[childIndex].name;
		}
		return null;
	}

	public Transform FindChild(string childName)
	{
		return FindChild(FindChildIndex(childName));
	}

	public GameObject FindChildGameObject(int childIndex)
	{
		Transform transform = FindChild(childIndex);
		if (!transform)
		{
			return null;
		}
		return transform.gameObject;
	}

	public GameObject FindChildGameObject(string childName)
	{
		return FindChildGameObject(FindChildIndex(childName));
	}

	public Transform FindChild(int childIndex)
	{
		if ((uint)childIndex < transformPairs.Length)
		{
			return transformPairs[childIndex].transform;
		}
		return null;
	}

	public T FindChildComponent<T>(string childName)
	{
		return FindChildComponent<T>(FindChildIndex(childName));
	}

	public T FindChildComponent<T>(int childIndex)
	{
		Transform transform = FindChild(childIndex);
		if (!transform)
		{
			return default(T);
		}
		return transform.GetComponent<T>();
	}
}
public class DestroyOnKill : MonoBehaviour, IOnKilledServerReceiver
{
	public GameObject effectPrefab;

	public void OnKilledServer(DamageReport damageReport)
	{
		UnityEngine.Object.Instantiate(effectPrefab, base.transform.position, base.transform.rotation);
		UnityEngine.Object.Destroy(base.gameObject);
	}
}
public class DestroyOnParticleEnd : MonoBehaviour
{
	[SerializeField]
	[Tooltip("Set this if you want to specify which particle system is tracked. Otherwise it will automatically grab the first one it finds.")]
	private ParticleSystem trackedParticleSystem;

	private EffectManagerHelper efh;

	public void Start()
	{
		if (trackedParticleSystem == null)
		{
			trackedParticleSystem = GetComponentInChildren<ParticleSystem>();
		}
		if (!efh)
		{
			efh = GetComponent<EffectManagerHelper>();
		}
	}

	public void Update()
	{
		if ((bool)trackedParticleSystem && !trackedParticleSystem.IsAlive())
		{
			if ((bool)efh && efh.OwningPool != null)
			{
				efh.OwningPool.ReturnObject(efh);
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
}
[RequireComponent(typeof(AudioSource))]
public class DestroyOnSoundEnd : MonoBehaviour
{
	private AudioSource audioSource;

	private void Awake()
	{
		audioSource = GetComponent<AudioSource>();
	}

	private void Update()
	{
		if (!audioSource.isPlaying)
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}
}
public class DisableOnStart : MonoBehaviour
{
	private void Start()
	{
		base.gameObject.SetActive(value: false);
	}
}
[AddComponentMenu("Dynamic Bone/Dynamic Bone")]
public class DynamicBone : MonoBehaviour
{
	public enum UpdateMode
	{
		Normal,
		AnimatePhysics,
		UnscaledTime
	}

	public enum FreezeAxis
	{
		None,
		X,
		Y,
		Z
	}

	private class Particle
	{
		public Transform m_Transform;

		public int m_ParentIndex = -1;

		public float m_Damping;

		public float m_Elasticity;

		public float m_Stiffness;

		public float m_Inert;

		public float m_Radius;

		public float m_BoneLength;

		public UnityEngine.Vector3 m_Position = UnityEngine.Vector3.zero;

		public UnityEngine.Vector3 m_PrevPosition = UnityEngine.Vector3.zero;

		public UnityEngine.Vector3 m_EndOffset = UnityEngine.Vector3.zero;

		public UnityEngine.Vector3 m_InitLocalPosition = UnityEngine.Vector3.zero;

		public UnityEngine.Quaternion m_InitLocalRotation = UnityEngine.Quaternion.identity;
	}

	public Transform m_Root;

	public float m_UpdateRate = 60f;

	public UpdateMode m_UpdateMode;

	[Range(0f, 1f)]
	public float m_Damping = 0.1f;

	public AnimationCurve m_DampingDistrib;

	[Range(0f, 1f)]
	public float m_Elasticity = 0.1f;

	public AnimationCurve m_ElasticityDistrib;

	[Range(0f, 1f)]
	public float m_Stiffness = 0.1f;

	public AnimationCurve m_StiffnessDistrib;

	[Range(0f, 1f)]
	public float m_Inert;

	public AnimationCurve m_InertDistrib;

	public float m_Radius;

	public AnimationCurve m_RadiusDistrib;

	public float m_EndLength;

	public UnityEngine.Vector3 m_EndOffset = UnityEngine.Vector3.zero;

	public UnityEngine.Vector3 m_Gravity = UnityEngine.Vector3.zero;

	public UnityEngine.Vector3 m_Force = UnityEngine.Vector3.zero;

	public List<DynamicBoneCollider> m_Colliders;

	public List<Transform> m_Exclusions;

	public FreezeAxis m_FreezeAxis;

	public bool m_DistantDisable;

	public Transform m_ReferenceObject;

	public float m_DistanceToObject = 20f;

	[Tooltip("Check this if you want the bone to be dynamic even on low performance HW")]
	public bool neverOptimize;

	private UnityEngine.Vector3 m_LocalGravity = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 m_ObjectMove = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 m_ObjectPrevPosition = UnityEngine.Vector3.zero;

	private float m_BoneTotalLength;

	private float m_ObjectScale = 1f;

	private float m_Time;

	private float m_Weight = 1f;

	private bool m_DistantDisabled;

	private List<Particle> m_Particles = new List<Particle>();

	private void Start()
	{
		SetupParticles();
	}

	private void FixedUpdate()
	{
		if (m_UpdateMode == UpdateMode.AnimatePhysics)
		{
			PreUpdate();
		}
	}

	private void Update()
	{
		if (m_UpdateMode != UpdateMode.AnimatePhysics)
		{
			PreUpdate();
		}
	}

	private void LateUpdate()
	{
		if (m_DistantDisable)
		{
			CheckDistance();
		}
		if (m_Weight > 0f && (!m_DistantDisable || !m_DistantDisabled))
		{
			float deltaTime = Time.deltaTime;
			UpdateDynamicBones(deltaTime);
		}
	}

	private void PreUpdate()
	{
		if (m_Weight > 0f && (!m_DistantDisable || !m_DistantDisabled))
		{
			InitTransforms();
		}
	}

	private void CheckDistance()
	{
		Transform referenceObject = m_ReferenceObject;
		if (referenceObject == null && (bool)Camera.main)
		{
			referenceObject = Camera.main.transform;
		}
		if (!referenceObject)
		{
			return;
		}
		bool flag = (referenceObject.position - base.transform.position).sqrMagnitude > m_DistanceToObject * m_DistanceToObject;
		if (flag != m_DistantDisabled)
		{
			if (!flag)
			{
				ResetParticlesPosition();
			}
			m_DistantDisabled = flag;
		}
	}

	private void OnEnable()
	{
		ResetParticlesPosition();
	}

	private void OnDisable()
	{
		InitTransforms();
	}

	private void OnValidate()
	{
		m_UpdateRate = Mathf.Max(m_UpdateRate, 0f);
		m_Damping = Mathf.Clamp01(m_Damping);
		m_Elasticity = Mathf.Clamp01(m_Elasticity);
		m_Stiffness = Mathf.Clamp01(m_Stiffness);
		m_Inert = Mathf.Clamp01(m_Inert);
		m_Radius = Mathf.Max(m_Radius, 0f);
		if (Application.isEditor && Application.isPlaying)
		{
			InitTransforms();
			SetupParticles();
		}
	}

	private void OnDrawGizmosSelected()
	{
		if (!base.enabled || m_Root == null)
		{
			return;
		}
		if (Application.isEditor && !Application.isPlaying && base.transform.hasChanged)
		{
			InitTransforms();
			SetupParticles();
		}
		Gizmos.color = UnityEngine.Color.white;
		for (int i = 0; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			if (particle.m_ParentIndex >= 0)
			{
				Particle particle2 = m_Particles[particle.m_ParentIndex];
				Gizmos.DrawLine(particle.m_Position, particle2.m_Position);
			}
			if (particle.m_Radius > 0f)
			{
				Gizmos.DrawWireSphere(particle.m_Position, particle.m_Radius * m_ObjectScale);
			}
		}
	}

	public void SetWeight(float w)
	{
		if (m_Weight != w)
		{
			if (w == 0f)
			{
				InitTransforms();
			}
			else if (m_Weight == 0f)
			{
				ResetParticlesPosition();
			}
			m_Weight = w;
		}
	}

	public float GetWeight()
	{
		return m_Weight;
	}

	private void UpdateDynamicBones(float t)
	{
		if (m_Root == null)
		{
			return;
		}
		m_ObjectScale = Mathf.Abs(base.transform.lossyScale.x);
		m_ObjectMove = base.transform.position - m_ObjectPrevPosition;
		m_ObjectPrevPosition = base.transform.position;
		int num = 1;
		if (m_UpdateRate > 0f)
		{
			float num2 = 1f / m_UpdateRate;
			m_Time += t;
			num = 0;
			while (m_Time >= num2)
			{
				m_Time -= num2;
				if (++num >= 3)
				{
					m_Time = 0f;
					break;
				}
			}
		}
		if (num > 0)
		{
			for (int i = 0; i < num; i++)
			{
				UpdateParticles1();
				UpdateParticles2();
				m_ObjectMove = UnityEngine.Vector3.zero;
			}
		}
		else
		{
			SkipUpdateParticles();
		}
		ApplyParticlesToTransforms();
	}

	private void SetupParticles()
	{
		m_Particles.Clear();
		if (m_Root == null)
		{
			return;
		}
		m_LocalGravity = m_Root.InverseTransformDirection(m_Gravity);
		m_ObjectScale = Mathf.Abs(base.transform.lossyScale.x);
		m_ObjectPrevPosition = base.transform.position;
		m_ObjectMove = UnityEngine.Vector3.zero;
		m_BoneTotalLength = 0f;
		AppendParticles(m_Root, -1, 0f);
		for (int i = 0; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			particle.m_Damping = m_Damping;
			particle.m_Elasticity = m_Elasticity;
			particle.m_Stiffness = m_Stiffness;
			particle.m_Inert = m_Inert;
			particle.m_Radius = m_Radius;
			if (m_BoneTotalLength > 0f)
			{
				float time = particle.m_BoneLength / m_BoneTotalLength;
				if (m_DampingDistrib != null && m_DampingDistrib.keys.Length != 0)
				{
					particle.m_Damping *= m_DampingDistrib.Evaluate(time);
				}
				if (m_ElasticityDistrib != null && m_ElasticityDistrib.keys.Length != 0)
				{
					particle.m_Elasticity *= m_ElasticityDistrib.Evaluate(time);
				}
				if (m_StiffnessDistrib != null && m_StiffnessDistrib.keys.Length != 0)
				{
					particle.m_Stiffness *= m_StiffnessDistrib.Evaluate(time);
				}
				if (m_InertDistrib != null && m_InertDistrib.keys.Length != 0)
				{
					particle.m_Inert *= m_InertDistrib.Evaluate(time);
				}
				if (m_RadiusDistrib != null && m_RadiusDistrib.keys.Length != 0)
				{
					particle.m_Radius *= m_RadiusDistrib.Evaluate(time);
				}
			}
			particle.m_Damping = Mathf.Clamp01(particle.m_Damping);
			particle.m_Elasticity = Mathf.Clamp01(particle.m_Elasticity);
			particle.m_Stiffness = Mathf.Clamp01(particle.m_Stiffness);
			particle.m_Inert = Mathf.Clamp01(particle.m_Inert);
			particle.m_Radius = Mathf.Max(particle.m_Radius, 0f);
		}
	}

	private void AppendParticles(Transform b, int parentIndex, float boneLength)
	{
		Particle particle = new Particle();
		particle.m_Transform = b;
		particle.m_ParentIndex = parentIndex;
		if ((bool)b)
		{
			particle.m_Position = (particle.m_PrevPosition = b.position);
			particle.m_InitLocalPosition = b.localPosition;
			particle.m_InitLocalRotation = b.localRotation;
		}
		else
		{
			Transform transform = m_Particles[parentIndex].m_Transform;
			if (m_EndLength > 0f)
			{
				Transform parent = transform.parent;
				if ((bool)parent)
				{
					particle.m_EndOffset = transform.InverseTransformPoint(transform.position * 2f - parent.position) * m_EndLength;
				}
				else
				{
					particle.m_EndOffset = new UnityEngine.Vector3(m_EndLength, 0f, 0f);
				}
			}
			else
			{
				particle.m_EndOffset = transform.InverseTransformPoint(base.transform.TransformDirection(m_EndOffset) + transform.position);
			}
			particle.m_Position = (particle.m_PrevPosition = transform.TransformPoint(particle.m_EndOffset));
		}
		if (parentIndex >= 0)
		{
			boneLength += (m_Particles[parentIndex].m_Transform.position - particle.m_Position).magnitude;
			particle.m_BoneLength = boneLength;
			m_BoneTotalLength = Mathf.Max(m_BoneTotalLength, boneLength);
		}
		int count = m_Particles.Count;
		m_Particles.Add(particle);
		if (!b)
		{
			return;
		}
		for (int i = 0; i < b.childCount; i++)
		{
			bool flag = false;
			if (m_Exclusions != null)
			{
				for (int j = 0; j < m_Exclusions.Count; j++)
				{
					if (m_Exclusions[j] == b.GetChild(i))
					{
						flag = true;
						break;
					}
				}
			}
			if (!flag)
			{
				AppendParticles(b.GetChild(i), count, boneLength);
			}
		}
		if (b.childCount == 0 && (m_EndLength > 0f || m_EndOffset != UnityEngine.Vector3.zero))
		{
			AppendParticles(null, count, boneLength);
		}
	}

	private void InitTransforms()
	{
		for (int i = 0; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			if ((bool)particle.m_Transform)
			{
				particle.m_Transform.localPosition = particle.m_InitLocalPosition;
				particle.m_Transform.localRotation = particle.m_InitLocalRotation;
			}
		}
	}

	private void ResetParticlesPosition()
	{
		for (int i = 0; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			if ((bool)particle.m_Transform)
			{
				particle.m_Position = (particle.m_PrevPosition = particle.m_Transform.position);
				continue;
			}
			Transform transform = m_Particles[particle.m_ParentIndex].m_Transform;
			particle.m_Position = (particle.m_PrevPosition = transform.TransformPoint(particle.m_EndOffset));
		}
		m_ObjectPrevPosition = base.transform.position;
	}

	private void UpdateParticles1()
	{
		UnityEngine.Vector3 gravity = m_Gravity;
		UnityEngine.Vector3 normalized = m_Gravity.normalized;
		UnityEngine.Vector3 lhs = m_Root.TransformDirection(m_LocalGravity);
		UnityEngine.Vector3 vector = normalized * Mathf.Max(UnityEngine.Vector3.Dot(lhs, normalized), 0f);
		gravity -= vector;
		gravity = (gravity + m_Force) * m_ObjectScale;
		for (int i = 0; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			if (particle.m_ParentIndex >= 0)
			{
				UnityEngine.Vector3 vector2 = particle.m_Position - particle.m_PrevPosition;
				UnityEngine.Vector3 vector3 = m_ObjectMove * particle.m_Inert;
				particle.m_PrevPosition = particle.m_Position + vector3;
				particle.m_Position += vector2 * (1f - particle.m_Damping) + gravity + vector3;
			}
			else
			{
				particle.m_PrevPosition = particle.m_Position;
				particle.m_Position = particle.m_Transform.position;
			}
		}
	}

	private void UpdateParticles2()
	{
		UnityEngine.Plane plane = default(UnityEngine.Plane);
		for (int i = 1; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			Particle particle2 = m_Particles[particle.m_ParentIndex];
			if (!particle2.m_Transform)
			{
				continue;
			}
			float num = ((!particle.m_Transform) ? particle2.m_Transform.localToWorldMatrix.MultiplyVector(particle.m_EndOffset).magnitude : (particle2.m_Transform.position - particle.m_Transform.position).magnitude);
			float num2 = Mathf.Lerp(1f, particle.m_Stiffness, m_Weight);
			if (num2 > 0f || particle.m_Elasticity > 0f)
			{
				UnityEngine.Matrix4x4 localToWorldMatrix = particle2.m_Transform.localToWorldMatrix;
				localToWorldMatrix.SetColumn(3, particle2.m_Position);
				UnityEngine.Vector3 vector = ((!particle.m_Transform) ? localToWorldMatrix.MultiplyPoint3x4(particle.m_EndOffset) : localToWorldMatrix.MultiplyPoint3x4(particle.m_Transform.localPosition));
				UnityEngine.Vector3 vector2 = vector - particle.m_Position;
				particle.m_Position += vector2 * particle.m_Elasticity;
				if (num2 > 0f)
				{
					vector2 = vector - particle.m_Position;
					float magnitude = vector2.magnitude;
					float num3 = num * (1f - num2) * 2f;
					if (magnitude > num3)
					{
						particle.m_Position += vector2 * ((magnitude - num3) / magnitude);
					}
				}
			}
			if (m_Colliders != null)
			{
				float particleRadius = particle.m_Radius * m_ObjectScale;
				for (int j = 0; j < m_Colliders.Count; j++)
				{
					DynamicBoneCollider dynamicBoneCollider = m_Colliders[j];
					if ((bool)dynamicBoneCollider && dynamicBoneCollider.enabled)
					{
						dynamicBoneCollider.Collide(ref particle.m_Position, particleRadius);
					}
				}
			}
			if (m_FreezeAxis != 0)
			{
				switch (m_FreezeAxis)
				{
				case FreezeAxis.X:
					plane.SetNormalAndPosition(particle2.m_Transform.right, particle2.m_Position);
					break;
				case FreezeAxis.Y:
					plane.SetNormalAndPosition(particle2.m_Transform.up, particle2.m_Position);
					break;
				case FreezeAxis.Z:
					plane.SetNormalAndPosition(particle2.m_Transform.forward, particle2.m_Position);
					break;
				}
				particle.m_Position -= plane.normal * plane.GetDistanceToPoint(particle.m_Position);
			}
			UnityEngine.Vector3 vector3 = particle2.m_Position - particle.m_Position;
			float magnitude2 = vector3.magnitude;
			if (magnitude2 > 0f)
			{
				particle.m_Position += vector3 * ((magnitude2 - num) / magnitude2);
			}
		}
	}

	private void SkipUpdateParticles()
	{
		for (int i = 0; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			if (particle.m_ParentIndex >= 0)
			{
				particle.m_PrevPosition += m_ObjectMove;
				particle.m_Position += m_ObjectMove;
				Particle particle2 = m_Particles[particle.m_ParentIndex];
				if (!particle2.m_Transform)
				{
					continue;
				}
				float num = ((!particle.m_Transform) ? particle2.m_Transform.localToWorldMatrix.MultiplyVector(particle.m_EndOffset).magnitude : (particle2.m_Transform.position - particle.m_Transform.position).magnitude);
				float num2 = Mathf.Lerp(1f, particle.m_Stiffness, m_Weight);
				if (num2 > 0f)
				{
					UnityEngine.Matrix4x4 localToWorldMatrix = particle2.m_Transform.localToWorldMatrix;
					localToWorldMatrix.SetColumn(3, particle2.m_Position);
					UnityEngine.Vector3 vector = ((!particle.m_Transform) ? localToWorldMatrix.MultiplyPoint3x4(particle.m_EndOffset) : localToWorldMatrix.MultiplyPoint3x4(particle.m_Transform.localPosition));
					UnityEngine.Vector3 vector2 = vector - particle.m_Position;
					float magnitude = vector2.magnitude;
					float num3 = num * (1f - num2) * 2f;
					if (magnitude > num3)
					{
						particle.m_Position += vector2 * ((magnitude - num3) / magnitude);
					}
				}
				UnityEngine.Vector3 vector3 = particle2.m_Position - particle.m_Position;
				float magnitude2 = vector3.magnitude;
				if (magnitude2 > 0f)
				{
					particle.m_Position += vector3 * ((magnitude2 - num) / magnitude2);
				}
			}
			else if ((bool)particle.m_Transform)
			{
				particle.m_PrevPosition = particle.m_Position;
				particle.m_Position = particle.m_Transform.position;
			}
		}
	}

	private static UnityEngine.Vector3 MirrorVector(UnityEngine.Vector3 v, UnityEngine.Vector3 axis)
	{
		return v - axis * (UnityEngine.Vector3.Dot(v, axis) * 2f);
	}

	private void ApplyParticlesToTransforms()
	{
		for (int i = 1; i < m_Particles.Count; i++)
		{
			Particle particle = m_Particles[i];
			Particle particle2 = m_Particles[particle.m_ParentIndex];
			if (particle2.m_Transform.childCount <= 1)
			{
				UnityEngine.Vector3 direction = ((!particle.m_Transform) ? particle.m_EndOffset : particle.m_Transform.localPosition);
				UnityEngine.Vector3 toDirection = particle.m_Position - particle2.m_Position;
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.FromToRotation(particle2.m_Transform.TransformDirection(direction), toDirection);
				particle2.m_Transform.rotation = quaternion * particle2.m_Transform.rotation;
			}
			if ((bool)particle.m_Transform)
			{
				particle.m_Transform.position = particle.m_Position;
			}
		}
	}
}
[AddComponentMenu("Dynamic Bone/Dynamic Bone Collider")]
public class DynamicBoneCollider : MonoBehaviour
{
	public enum Direction
	{
		X,
		Y,
		Z
	}

	public enum Bound
	{
		Outside,
		Inside
	}

	public UnityEngine.Vector3 m_Center = UnityEngine.Vector3.zero;

	public float m_Radius = 0.5f;

	public float m_Height;

	public Direction m_Direction;

	public Bound m_Bound;

	private void OnValidate()
	{
		m_Radius = Mathf.Max(m_Radius, 0f);
		m_Height = Mathf.Max(m_Height, 0f);
	}

	public void Collide(ref UnityEngine.Vector3 particlePosition, float particleRadius)
	{
		float num = m_Radius * Mathf.Abs(base.transform.lossyScale.x);
		float num2 = m_Height * 0.5f - m_Radius;
		if (num2 <= 0f)
		{
			if (m_Bound == Bound.Outside)
			{
				OutsideSphere(ref particlePosition, particleRadius, base.transform.TransformPoint(m_Center), num);
			}
			else
			{
				InsideSphere(ref particlePosition, particleRadius, base.transform.TransformPoint(m_Center), num);
			}
			return;
		}
		UnityEngine.Vector3 center = m_Center;
		UnityEngine.Vector3 center2 = m_Center;
		switch (m_Direction)
		{
		case Direction.X:
			center.x -= num2;
			center2.x += num2;
			break;
		case Direction.Y:
			center.y -= num2;
			center2.y += num2;
			break;
		case Direction.Z:
			center.z -= num2;
			center2.z += num2;
			break;
		}
		if (m_Bound == Bound.Outside)
		{
			OutsideCapsule(ref particlePosition, particleRadius, base.transform.TransformPoint(center), base.transform.TransformPoint(center2), num);
		}
		else
		{
			InsideCapsule(ref particlePosition, particleRadius, base.transform.TransformPoint(center), base.transform.TransformPoint(center2), num);
		}
	}

	private static void OutsideSphere(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 sphereCenter, float sphereRadius)
	{
		float num = sphereRadius + particleRadius;
		float num2 = num * num;
		UnityEngine.Vector3 vector = particlePosition - sphereCenter;
		float sqrMagnitude = vector.sqrMagnitude;
		if (sqrMagnitude > 0f && sqrMagnitude < num2)
		{
			float num3 = Mathf.Sqrt(sqrMagnitude);
			particlePosition = sphereCenter + vector * (num / num3);
		}
	}

	private static void InsideSphere(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 sphereCenter, float sphereRadius)
	{
		float num = sphereRadius - particleRadius;
		float num2 = num * num;
		UnityEngine.Vector3 vector = particlePosition - sphereCenter;
		float sqrMagnitude = vector.sqrMagnitude;
		if (sqrMagnitude > num2)
		{
			float num3 = Mathf.Sqrt(sqrMagnitude);
			particlePosition = sphereCenter + vector * (num / num3);
		}
	}

	private static void OutsideCapsule(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 capsuleP0, UnityEngine.Vector3 capsuleP1, float capsuleRadius)
	{
		float num = capsuleRadius + particleRadius;
		float num2 = num * num;
		UnityEngine.Vector3 vector = capsuleP1 - capsuleP0;
		UnityEngine.Vector3 vector2 = particlePosition - capsuleP0;
		float num3 = UnityEngine.Vector3.Dot(vector2, vector);
		if (num3 <= 0f)
		{
			float sqrMagnitude = vector2.sqrMagnitude;
			if (sqrMagnitude > 0f && sqrMagnitude < num2)
			{
				float num4 = Mathf.Sqrt(sqrMagnitude);
				particlePosition = capsuleP0 + vector2 * (num / num4);
			}
			return;
		}
		float sqrMagnitude2 = vector.sqrMagnitude;
		if (num3 >= sqrMagnitude2)
		{
			vector2 = particlePosition - capsuleP1;
			float sqrMagnitude3 = vector2.sqrMagnitude;
			if (sqrMagnitude3 > 0f && sqrMagnitude3 < num2)
			{
				float num5 = Mathf.Sqrt(sqrMagnitude3);
				particlePosition = capsuleP1 + vector2 * (num / num5);
			}
		}
		else if (sqrMagnitude2 > 0f)
		{
			num3 /= sqrMagnitude2;
			vector2 -= vector * num3;
			float sqrMagnitude4 = vector2.sqrMagnitude;
			if (sqrMagnitude4 > 0f && sqrMagnitude4 < num2)
			{
				float num6 = Mathf.Sqrt(sqrMagnitude4);
				particlePosition += vector2 * ((num - num6) / num6);
			}
		}
	}

	private static void InsideCapsule(ref UnityEngine.Vector3 particlePosition, float particleRadius, UnityEngine.Vector3 capsuleP0, UnityEngine.Vector3 capsuleP1, float capsuleRadius)
	{
		float num = capsuleRadius - particleRadius;
		float num2 = num * num;
		UnityEngine.Vector3 vector = capsuleP1 - capsuleP0;
		UnityEngine.Vector3 vector2 = particlePosition - capsuleP0;
		float num3 = UnityEngine.Vector3.Dot(vector2, vector);
		if (num3 <= 0f)
		{
			float sqrMagnitude = vector2.sqrMagnitude;
			if (sqrMagnitude > num2)
			{
				float num4 = Mathf.Sqrt(sqrMagnitude);
				particlePosition = capsuleP0 + vector2 * (num / num4);
			}
			return;
		}
		float sqrMagnitude2 = vector.sqrMagnitude;
		if (num3 >= sqrMagnitude2)
		{
			vector2 = particlePosition - capsuleP1;
			float sqrMagnitude3 = vector2.sqrMagnitude;
			if (sqrMagnitude3 > num2)
			{
				float num5 = Mathf.Sqrt(sqrMagnitude3);
				particlePosition = capsuleP1 + vector2 * (num / num5);
			}
		}
		else if (sqrMagnitude2 > 0f)
		{
			num3 /= sqrMagnitude2;
			vector2 -= vector * num3;
			float sqrMagnitude4 = vector2.sqrMagnitude;
			if (sqrMagnitude4 > num2)
			{
				float num6 = Mathf.Sqrt(sqrMagnitude4);
				particlePosition += vector2 * ((num - num6) / num6);
			}
		}
	}

	private void OnDrawGizmosSelected()
	{
		if (!base.enabled)
		{
			return;
		}
		if (m_Bound == Bound.Outside)
		{
			Gizmos.color = UnityEngine.Color.yellow;
		}
		else
		{
			Gizmos.color = UnityEngine.Color.magenta;
		}
		float radius = m_Radius * Mathf.Abs(base.transform.lossyScale.x);
		float num = m_Height * 0.5f - m_Radius;
		if (num <= 0f)
		{
			Gizmos.DrawWireSphere(base.transform.TransformPoint(m_Center), radius);
			return;
		}
		UnityEngine.Vector3 center = m_Center;
		UnityEngine.Vector3 center2 = m_Center;
		switch (m_Direction)
		{
		case Direction.X:
			center.x -= num;
			center2.x += num;
			break;
		case Direction.Y:
			center.y -= num;
			center2.y += num;
			break;
		case Direction.Z:
			center.z -= num;
			center2.z += num;
			break;
		}
		Gizmos.DrawWireSphere(base.transform.TransformPoint(center), radius);
		Gizmos.DrawWireSphere(base.transform.TransformPoint(center2), radius);
	}
}
public class FloatPID : MonoBehaviour
{
	[Tooltip("PID Constants.")]
	public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f);

	public float gain = 1f;

	[Tooltip("The value we are currently at.")]
	[HideInInspector]
	public float inputFloat;

	[HideInInspector]
	[Tooltip("The value we want to be at.")]
	public float targetFloat;

	[Tooltip("Value output from PID controller; what we read.")]
	[HideInInspector]
	public float outputFloat;

	public float timeBetweenUpdates;

	private float timer;

	private float errorSum;

	private float deltaError;

	private float lastError;

	private float lastTimer;

	public bool automaticallyUpdate;

	private void Start()
	{
	}

	private void FixedUpdate()
	{
		timer += Time.fixedDeltaTime;
		if (automaticallyUpdate && timer > timeBetweenUpdates)
		{
			timer -= timeBetweenUpdates;
			outputFloat = UpdatePID();
		}
	}

	public float UpdatePID()
	{
		float num = timer - lastTimer;
		lastTimer = timer;
		float num2 = targetFloat - inputFloat;
		errorSum += num2 * num;
		deltaError = (num2 - lastError) / num;
		lastError = num2;
		return (num2 * PID.x + errorSum * PID.y + deltaError * PID.z) * gain;
	}
}
[RequireComponent(typeof(Animator))]
[ExecuteInEditMode]
public class ForcePose : MonoBehaviour
{
	[Tooltip("The animation clip to force.")]
	public AnimationClip clip;

	[Tooltip("The moment in the cycle to force.")]
	[Range(0f, 1f)]
	public float cycle;

	private void Start()
	{
	}

	private void Update()
	{
		if ((bool)clip)
		{
			clip.SampleAnimation(base.gameObject, cycle * clip.length);
		}
	}
}
[ExecuteInEditMode]
public class GlobalShaderTextures : MonoBehaviour
{
	public Texture warpRampTexture;

	public string warpRampShaderVariableName;

	public Texture eliteRampTexture;

	public string eliteRampShaderVariableName;

	public Texture snowMicrofacetTexture;

	public string snowMicrofacetNoiseVariableName;

	private void OnValidate()
	{
		Shader.SetGlobalTexture(warpRampShaderVariableName, warpRampTexture);
		Shader.SetGlobalTexture(eliteRampShaderVariableName, eliteRampTexture);
		Shader.SetGlobalTexture(snowMicrofacetNoiseVariableName, snowMicrofacetTexture);
	}

	private void Start()
	{
		Shader.SetGlobalTexture(warpRampShaderVariableName, warpRampTexture);
		Shader.SetGlobalTexture(eliteRampShaderVariableName, eliteRampTexture);
		Shader.SetGlobalTexture(snowMicrofacetNoiseVariableName, snowMicrofacetTexture);
	}
}
public class HoverOverHead : MonoBehaviour
{
	private Transform parentTransform;

	private Collider bodyCollider;

	public UnityEngine.Vector3 bonusOffset;

	private void Start()
	{
		Reset();
	}

	public void Reset()
	{
		if ((bool)base.transform)
		{
			parentTransform = base.transform.parent;
			bodyCollider = ((parentTransform == null) ? null : parentTransform.GetComponent<Collider>());
		}
	}

	private void Update()
	{
		if ((bool)parentTransform)
		{
			UnityEngine.Vector3 vector = parentTransform.position;
			if ((bool)bodyCollider)
			{
				vector = bodyCollider.bounds.center + new UnityEngine.Vector3(0f, bodyCollider.bounds.extents.y, 0f);
			}
			base.transform.position = vector + bonusOffset;
		}
	}
}
[RequireComponent(typeof(InterpolatedTransformUpdater))]
public class InterpolatedTransform : MonoBehaviour, ITeleportHandler, IEventSystemHandler
{
	private struct TransformData
	{
		public UnityEngine.Vector3 position;

		public UnityEngine.Quaternion rotation;

		public UnityEngine.Vector3 scale;

		public TransformData(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, UnityEngine.Vector3 scale)
		{
			this.position = position;
			this.rotation = rotation;
			this.scale = scale;
		}
	}

	private TransformData[] m_lastTransforms;

	private int m_newTransformIndex;

	private void OnEnable()
	{
		ForgetPreviousTransforms();
	}

	public void ForgetPreviousTransforms()
	{
		m_lastTransforms = new TransformData[2];
		TransformData transformData = new TransformData(base.transform.localPosition, base.transform.localRotation, base.transform.localScale);
		m_lastTransforms[0] = transformData;
		m_lastTransforms[1] = transformData;
		m_newTransformIndex = 0;
	}

	private void FixedUpdate()
	{
		TransformData transformData = m_lastTransforms[m_newTransformIndex];
		base.transform.localPosition = transformData.position;
		base.transform.localRotation = transformData.rotation;
		base.transform.localScale = transformData.scale;
	}

	public void LateFixedUpdate()
	{
		m_newTransformIndex = OldTransformIndex();
		m_lastTransforms[m_newTransformIndex] = new TransformData(base.transform.localPosition, base.transform.localRotation, base.transform.localScale);
	}

	private void Update()
	{
		TransformData transformData = m_lastTransforms[m_newTransformIndex];
		TransformData transformData2 = m_lastTransforms[OldTransformIndex()];
		base.transform.localPosition = UnityEngine.Vector3.Lerp(transformData2.position, transformData.position, InterpolationController.InterpolationFactor);
		base.transform.localRotation = UnityEngine.Quaternion.Slerp(transformData2.rotation, transformData.rotation, InterpolationController.InterpolationFactor);
		base.transform.localScale = UnityEngine.Vector3.Lerp(transformData2.scale, transformData.scale, InterpolationController.InterpolationFactor);
	}

	private int OldTransformIndex()
	{
		if (m_newTransformIndex != 0)
		{
			return 0;
		}
		return 1;
	}

	public void OnTeleport(UnityEngine.Vector3 oldPosition, UnityEngine.Vector3 newPosition)
	{
		ForgetPreviousTransforms();
	}
}
public class InterpolatedTransformUpdater : MonoBehaviour
{
	private InterpolatedTransform m_interpolatedTransform;

	private void Awake()
	{
		m_interpolatedTransform = GetComponent<InterpolatedTransform>();
	}

	private void FixedUpdate()
	{
		m_interpolatedTransform.LateFixedUpdate();
	}
}
public class InterpolationController : MonoBehaviour
{
	private float[] m_lastFixedUpdateTimes;

	private int m_newTimeIndex;

	private static float m_interpolationFactor;

	public static float InterpolationFactor => m_interpolationFactor;

	public void Start()
	{
		m_lastFixedUpdateTimes = new float[2];
		m_newTimeIndex = 0;
	}

	public void FixedUpdate()
	{
		m_newTimeIndex = OldTimeIndex();
		m_lastFixedUpdateTimes[m_newTimeIndex] = Time.fixedTime;
	}

	public void Update()
	{
		float num = m_lastFixedUpdateTimes[m_newTimeIndex];
		float num2 = m_lastFixedUpdateTimes[OldTimeIndex()];
		if (num != num2)
		{
			m_interpolationFactor = (Time.time - num) / (num - num2);
		}
		else
		{
			m_interpolationFactor = 1f;
		}
	}

	private int OldTimeIndex()
	{
		if (m_newTimeIndex != 0)
		{
			return 0;
		}
		return 1;
	}
}
public class LightIntensityCurve : MonoBehaviour
{
	public AnimationCurve curve;

	public float timeMax = 5f;

	private float time;

	private Light light;

	private float maxIntensity;

	[Tooltip("Loops the animation curve.")]
	public bool loop;

	[Tooltip("Starts in a random point in the animation curve.")]
	public bool randomStart;

	[Tooltip("Causes the lights to be negative, casting shadows instead.")]
	public bool enableNegativeLights;

	private void Awake()
	{
		if ((bool)light || TryGetComponent<Light>(out light))
		{
			maxIntensity = light.intensity;
		}
	}

	private void Start()
	{
		light.intensity = 0f;
		if (randomStart)
		{
			time = UnityEngine.Random.Range(0f, timeMax);
		}
		if (enableNegativeLights)
		{
			light.color = new UnityEngine.Color(0f - light.color.r, 0f - light.color.g, 0f - light.color.b);
		}
	}

	private void OnEnable()
	{
		time = 0f;
		if (!light)
		{
			light = GetComponent<Light>();
		}
		light.intensity = 0f;
		if (randomStart)
		{
			time = UnityEngine.Random.Range(0f, timeMax);
		}
		if (enableNegativeLights)
		{
			light.color = new UnityEngine.Color(0f - light.color.r, 0f - light.color.g, 0f - light.color.b);
		}
	}

	private void OnDisable()
	{
		if ((bool)light)
		{
			light.intensity = maxIntensity;
		}
	}

	private void Update()
	{
		time += Time.deltaTime;
		light.intensity = curve.Evaluate(time / timeMax) * maxIntensity;
		if (time >= timeMax && loop)
		{
			time = 0f;
		}
	}
}
[RequireComponent(typeof(LineRenderer))]
[ExecuteAlways]
public class LineBetweenTransforms : MonoBehaviour
{
	[SerializeField]
	[FormerlySerializedAs("transformNodes")]
	[Tooltip("The list of transforms whose positions will drive the vertex positions of the sibling LineRenderer component.")]
	private Transform[] _transformNodes = Array.Empty<Transform>();

	private LineRenderer lineRenderer;

	private UnityEngine.Vector3[] vertexList = Array.Empty<UnityEngine.Vector3>();

	public Transform[] transformNodes
	{
		get
		{
			return _transformNodes;
		}
		set
		{
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			_transformNodes = value;
			UpdateVertexBufferSize();
		}
	}

	private void PushPositionsToLineRenderer()
	{
		UnityEngine.Vector3[] array = vertexList;
		Transform[] array2 = transformNodes;
		for (int i = 0; i < array.Length; i++)
		{
			Transform transform = array2[i];
			if ((bool)transform)
			{
				array[i] = transform.position;
			}
		}
		lineRenderer.SetPositions(array);
	}

	private void UpdateVertexBufferSize()
	{
		Array.Resize(ref vertexList, transformNodes.Length);
	}

	private void Awake()
	{
		lineRenderer = GetComponent<LineRenderer>();
		UpdateVertexBufferSize();
	}

	private void LateUpdate()
	{
		PushPositionsToLineRenderer();
	}
}
public class LoadingScreenCanvas : MonoBehaviour
{
	public static LoadingScreenCanvas Instance;

	public SpriteAsNumberManager percentage;

	public GameObject background;

	public LoadingScreenCanvas()
	{
		Instance = this;
	}

	public void Awake()
	{
		UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
		RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnLoadComplete));
		SceneManager.sceneLoaded += OnSceneChange;
	}

	private void OnLoadComplete()
	{
		SceneManager.sceneLoaded -= OnSceneChange;
		Instance = null;
		UnityEngine.Object.Destroy(base.gameObject);
	}

	private void OnSceneChange(Scene a, LoadSceneMode b)
	{
		Instance.background.SetActive(a.name == "loadingbasic");
	}
}
public class LunarWispFXController : MonoBehaviour
{
	public List<ParticleSystem> FXParticles = new List<ParticleSystem>();

	private void Start()
	{
	}

	private void FixedUpdate()
	{
	}

	public void TurnOffFX()
	{
		for (int i = 0; i < FXParticles.Count; i++)
		{
			ParticleSystem.EmissionModule emission = FXParticles[i].emission;
			emission.enabled = false;
		}
	}

	public void TurnOnFX()
	{
		for (int i = 0; i < FXParticles.Count; i++)
		{
			ParticleSystem.EmissionModule emission = FXParticles[i].emission;
			emission.enabled = true;
		}
	}
}
[ExecuteAlways]
public class MaintainRotation : MonoBehaviour
{
	public UnityEngine.Vector3 eulerAngles;

	private void Start()
	{
	}

	private void LateUpdate()
	{
		base.transform.eulerAngles = eulerAngles;
	}
}
public class PauseTintController : MonoBehaviour
{
	private PostProcessVolume ppPauseVolume;

	private void Awake()
	{
		ppPauseVolume = GetComponent<PostProcessVolume>();
		ppPauseVolume.enabled = false;
	}

	private void OnEnable()
	{
		PauseManager.onPauseStartGlobal = (Action)Delegate.Combine(PauseManager.onPauseStartGlobal, new Action(OnPauseStart));
		PauseManager.onPauseEndGlobal = (Action)Delegate.Combine(PauseManager.onPauseEndGlobal, new Action(OnPauseEnd));
	}

	private void OnDisable()
	{
		PauseManager.onPauseStartGlobal = (Action)Delegate.Remove(PauseManager.onPauseStartGlobal, new Action(OnPauseStart));
		PauseManager.onPauseEndGlobal = (Action)Delegate.Remove(PauseManager.onPauseEndGlobal, new Action(OnPauseEnd));
	}

	private void OnPauseStart()
	{
		ppPauseVolume.enabled = true;
	}

	private void OnPauseEnd()
	{
		ppPauseVolume.enabled = false;
	}
}
public class PhysicsController : MonoBehaviour
{
	public UnityEngine.Vector3 centerOfMass = UnityEngine.Vector3.zero;

	private Rigidbody carRigidbody;

	public Transform cameraTransform;

	public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f);

	public bool turnOnInput;

	private UnityEngine.Vector3 errorSum = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 deltaError = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 lastError = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 desiredHeading;

	private void OnDrawGizmosSelected()
	{
		Gizmos.color = UnityEngine.Color.red;
		Gizmos.DrawSphere(base.transform.TransformPoint(centerOfMass), 0.5f);
	}

	private void Awake()
	{
		carRigidbody = GetComponent<Rigidbody>();
	}

	private void Update()
	{
	}

	private void FixedUpdate()
	{
		if (!turnOnInput || Input.GetAxis("Vertical") > 0f || Input.GetAxis("Vertical") > 0f)
		{
			desiredHeading = cameraTransform.forward;
			desiredHeading = UnityEngine.Vector3.Project(desiredHeading, base.transform.forward);
			desiredHeading = cameraTransform.forward - desiredHeading;
			UnityEngine.Debug.DrawRay(base.transform.position, desiredHeading * 15f, UnityEngine.Color.magenta);
		}
		UnityEngine.Vector3 vector = -base.transform.up;
		UnityEngine.Debug.DrawRay(base.transform.position, vector * 15f, UnityEngine.Color.blue);
		UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Cross(vector, desiredHeading);
		UnityEngine.Debug.DrawRay(base.transform.position, vector2 * 15f, UnityEngine.Color.red);
		vector2.x = 0f;
		vector2.z = 0f;
		errorSum += vector2 * Time.fixedDeltaTime;
		deltaError = (vector2 - lastError) / Time.fixedDeltaTime;
		lastError = vector2;
		carRigidbody.AddTorque(vector2 * PID.x + errorSum * PID.y + deltaError * PID.z, ForceMode.Acceleration);
	}
}
public class POISecretChest : MonoBehaviour
{
	public float influence = 5f;

	private void OnDrawGizmos()
	{
		Gizmos.matrix = base.transform.localToWorldMatrix;
		Gizmos.color = new UnityEngine.Color(0f, 1f, 1f, 0.03f);
		Gizmos.DrawCube(UnityEngine.Vector3.zero, base.transform.localScale / 2f);
		Gizmos.color = new UnityEngine.Color(0f, 1f, 1f, 0.1f);
		Gizmos.DrawWireCube(UnityEngine.Vector3.zero, base.transform.localScale / 2f);
	}
}
public class PositionFromParentRaycast : MonoBehaviour
{
	public float maxLength;

	public LayerMask mask;

	private void Update()
	{
		RaycastHit hitInfo = default(RaycastHit);
		if (Physics.Raycast(base.transform.parent.position, base.transform.parent.forward, out hitInfo, maxLength, mask))
		{
			base.transform.position = hitInfo.point;
		}
		else
		{
			base.transform.position = base.transform.parent.position + base.transform.parent.forward * maxLength;
		}
	}
}
[RequireComponent(typeof(Rigidbody))]
public class PhysicsImpactSpeedModifier : MonoBehaviour
{
	public float normalSpeedModifier;

	public float perpendicularSpeedModifier;

	private Rigidbody rigid;

	private void Awake()
	{
		rigid = GetComponent<Rigidbody>();
	}

	private void OnCollisionEnter(Collision collision)
	{
		UnityEngine.Vector3 normal = collision.contacts[0].normal;
		UnityEngine.Vector3 velocity = rigid.velocity;
		UnityEngine.Vector3 vector = UnityEngine.Vector3.Project(velocity, normal);
		UnityEngine.Vector3 vector2 = velocity - vector;
		vector *= normalSpeedModifier;
		vector2 *= perpendicularSpeedModifier;
		rigid.velocity = vector + vector2;
	}
}
public class ProjectileGhostTriggerOnStick : MonoBehaviour
{
	private UnityEngine.Vector3 lastPosition;

	private UnityEngine.Quaternion lastRotation;

	private bool begunMoving;

	private bool finishedMoving;

	[SerializeField]
	[Tooltip("If the object is rotating, will we consider that movement?")]
	private bool trackRotationAsMovement;

	[SerializeField]
	private UnityEvent OnStick;

	private void OnEnable()
	{
		begunMoving = false;
		finishedMoving = false;
		lastPosition = base.transform.position;
		lastRotation = base.transform.rotation;
	}

	private void Update()
	{
		UnityEngine.Vector3 position = base.transform.position;
		UnityEngine.Quaternion rotation = base.transform.rotation;
		if (!begunMoving && position != lastPosition && (!trackRotationAsMovement || (trackRotationAsMovement && rotation != lastRotation)))
		{
			begunMoving = true;
		}
		else if (begunMoving && !finishedMoving && position == lastPosition && (!trackRotationAsMovement || (trackRotationAsMovement && rotation == lastRotation)))
		{
			RunStuckMethod();
			finishedMoving = true;
		}
		lastPosition = position;
		lastRotation = rotation;
	}

	public void RunStuckMethod()
	{
		OnStick.Invoke();
	}
}
public class ProximityHighlight : MonoBehaviour
{
	public float highlightRadius = 50f;

	public float highlightScale = 0.6f;

	public float highlightUpdateInterval = 0.1f;

	private float _highlightUpdateTimer;

	private CharacterMaster _characterMaster;

	private CharacterBody _characterBody;

	private InteractionDriver _interactionDriver;

	private Collider[] _hitColliders = new Collider[64];

	private int _hits;

	private void Awake()
	{
		_characterMaster = GetComponent<CharacterMaster>();
		base.enabled = TutorialManager.isTutorialEnabled;
	}

	private void OnEnable()
	{
		OutlineHighlight.onPreRenderOutlineHighlight = (Action<OutlineHighlight>)Delegate.Combine(OutlineHighlight.onPreRenderOutlineHighlight, new Action<OutlineHighlight>(OnPreRenderOutlineHighlight));
	}

	private void OnDisable()
	{
		OutlineHighlight.onPreRenderOutlineHighlight = (Action<OutlineHighlight>)Delegate.Remove(OutlineHighlight.onPreRenderOutlineHighlight, new Action<OutlineHighlight>(OnPreRenderOutlineHighlight));
	}

	private void FixedUpdate()
	{
		if (!_characterMaster)
		{
			return;
		}
		_highlightUpdateTimer -= Time.fixedDeltaTime;
		if (!(_highlightUpdateTimer < 0f))
		{
			return;
		}
		_highlightUpdateTimer = highlightUpdateInterval;
		_characterBody = _characterMaster.GetBody();
		if ((bool)_characterBody)
		{
			_interactionDriver = _characterBody.GetComponent<InteractionDriver>();
			if ((bool)_interactionDriver)
			{
				Array.Clear(_hitColliders, 0, _hitColliders.Length);
				_hits = Physics.OverlapSphereNonAlloc(_characterBody.transform.position, highlightRadius, _hitColliders, LayerIndex.CommonMasks.interactable, QueryTriggerInteraction.Collide);
			}
		}
	}

	private void OnPreRenderOutlineHighlight(OutlineHighlight outlineHighlight)
	{
		for (int i = 0; i < _hits; i++)
		{
			if (!_hitColliders[i] || !_hitColliders[i].gameObject || !EntityLocator.HasEntityLocator(_hitColliders[i].gameObject, out var foundLocator))
			{
				continue;
			}
			GameObject entity = foundLocator.entity;
			if (_interactionDriver.currentInteractable == entity)
			{
				continue;
			}
			IInteractable component = entity.GetComponent<IInteractable>();
			if (component != null && ((MonoBehaviour)component).isActiveAndEnabled && (bool)_interactionDriver.interactor && component.GetInteractability(_interactionDriver.interactor) != 0 && component.ShouldProximityHighlight())
			{
				Highlight component2 = entity.GetComponent<Highlight>();
				if (!component2)
				{
					break;
				}
				UnityEngine.Color color = component2.GetColor() * component2.strength * highlightScale;
				outlineHighlight.highlightQueue.Enqueue(new OutlineHighlight.HighlightInfo
				{
					renderer = component2.targetRenderer,
					color = color
				});
			}
		}
	}
}
public class QuaternionPID : MonoBehaviour
{
	[Tooltip("Just a field for user naming. Doesn't do anything.")]
	[FormerlySerializedAs("name")]
	public string customName;

	[Tooltip("PID Constants.")]
	public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f);

	[Tooltip("The quaternion we are currently at.")]
	public UnityEngine.Quaternion inputQuat = UnityEngine.Quaternion.identity;

	[Tooltip("The quaternion we want to be at.")]
	public UnityEngine.Quaternion targetQuat = UnityEngine.Quaternion.identity;

	[Tooltip("Vector output from PID controller; what we read.")]
	[HideInInspector]
	public UnityEngine.Vector3 outputVector = UnityEngine.Vector3.zero;

	public float gain = 1f;

	private UnityEngine.Vector3 errorSum = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 deltaError = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 lastError = UnityEngine.Vector3.zero;

	private float lastUpdateTime;

	private void Start()
	{
		gain *= 60f * Time.fixedDeltaTime;
		lastUpdateTime = Time.time;
	}

	public UnityEngine.Vector3 UpdatePID()
	{
		float time = Time.time;
		float num = time - lastUpdateTime;
		lastUpdateTime = time;
		if (num != 0f)
		{
			UnityEngine.Quaternion quaternion = targetQuat * UnityEngine.Quaternion.Inverse(inputQuat);
			if (quaternion.w < 0f)
			{
				quaternion.x *= -1f;
				quaternion.y *= -1f;
				quaternion.z *= -1f;
				quaternion.w *= -1f;
			}
			UnityEngine.Vector3 vector = default(UnityEngine.Vector3);
			vector.x = quaternion.x;
			vector.y = quaternion.y;
			vector.z = quaternion.z;
			errorSum += vector * num;
			deltaError = (vector - lastError) / num;
			lastError = vector;
			outputVector = vector * PID.x + errorSum * PID.y + deltaError * PID.z;
			return outputVector * gain;
		}
		return UnityEngine.Vector3.zero;
	}
}
[ExecuteInEditMode]
public class RenderDepth : MonoBehaviour
{
	private void OnEnable()
	{
		GetComponent<Camera>().depthTextureMode = DepthTextureMode.DepthNormals;
	}
}
public class RenderInFrontOfParticles : MonoBehaviour
{
	public int renderOrder;

	private Renderer rend;

	private void Start()
	{
		rend = GetComponent<Renderer>();
		rend.material.renderQueue = renderOrder;
	}

	private void Update()
	{
	}
}
[RequireComponent(typeof(Animator))]
public class RootMotionAccumulator : MonoBehaviour
{
	private Animator animator;

	[NonSerialized]
	public UnityEngine.Vector3 accumulatedRootMotion;

	public UnityEngine.Quaternion accumulatedRootRotation;

	public bool accumulateRotation;

	public UnityEngine.Vector3 ExtractRootMotion()
	{
		UnityEngine.Vector3 result = accumulatedRootMotion;
		accumulatedRootMotion = UnityEngine.Vector3.zero;
		return result;
	}

	public UnityEngine.Quaternion ExtractRootRotation()
	{
		UnityEngine.Quaternion result = accumulatedRootRotation;
		accumulatedRootRotation = UnityEngine.Quaternion.identity;
		return result;
	}

	private void Awake()
	{
		animator = GetComponent<Animator>();
		accumulatedRootRotation = UnityEngine.Quaternion.identity;
	}

	private void OnAnimatorMove()
	{
		accumulatedRootMotion += animator.deltaPosition;
		if (accumulateRotation)
		{
			accumulatedRootRotation *= animator.deltaRotation;
		}
	}
}
public class RotateItem : MonoBehaviour
{
	public float spinSpeed = 30f;

	public float bobHeight = 0.3f;

	public UnityEngine.Vector3 offsetVector = UnityEngine.Vector3.zero;

	private float counter;

	private UnityEngine.Vector3 initialPosition;

	private void Start()
	{
		initialPosition = base.transform.position;
	}

	private void Update()
	{
		counter += Time.deltaTime;
		base.transform.Rotate(new UnityEngine.Vector3(0f, spinSpeed * Time.deltaTime, 0f), Space.World);
		if ((bool)base.transform.parent)
		{
			base.transform.localPosition = offsetVector + new UnityEngine.Vector3(0f, 0f, Mathf.Sin(counter) * bobHeight);
		}
		else
		{
			base.transform.position = initialPosition + new UnityEngine.Vector3(0f, Mathf.Sin(counter) * bobHeight, 0f);
		}
	}
}
public class RotateObject : MonoBehaviour
{
	public UnityEngine.Vector3 rotationSpeed;

	private void Start()
	{
	}

	private void Update()
	{
		base.transform.Rotate(rotationSpeed * Time.deltaTime);
	}
}
public class ScaledCamera : MonoBehaviour
{
	public float scale = 1f;

	private bool foundCamera;

	private UnityEngine.Vector3 offset;

	private void Start()
	{
	}

	private void LateUpdate()
	{
		Camera main = Camera.main;
		if (main != null)
		{
			if (!foundCamera)
			{
				foundCamera = true;
				offset = main.transform.position - base.transform.position;
			}
			base.transform.eulerAngles = main.transform.eulerAngles;
			base.transform.position = main.transform.position / scale - offset;
		}
	}
}
public class ScaleLineRenderer : MonoBehaviour
{
	private LineRenderer line;

	public float scaleSize = 1f;

	public UnityEngine.Vector3[] positions;

	private void Start()
	{
		line = GetComponent<LineRenderer>();
		SetScale();
	}

	private void Update()
	{
	}

	private void SetScale()
	{
		line.SetPosition(0, positions[0]);
		line.SetPosition(1, positions[1]);
		line.material.SetTextureScale("_MainTex", new UnityEngine.Vector2(UnityEngine.Vector3.Distance(positions[0], positions[1]) * scaleSize, 1f));
	}
}
public class ScaleProjector : MonoBehaviour
{
	private Projector projector;

	private void Start()
	{
		projector = GetComponent<Projector>();
	}

	private void Update()
	{
		if ((bool)projector)
		{
			projector.orthographicSize = base.transform.lossyScale.x;
		}
	}
}
[RequireComponent(typeof(Rigidbody))]
public class SetAngularVelocity : MonoBehaviour
{
	public UnityEngine.Vector3 angularVelocity;

	private Rigidbody rigidBody;

	private void Start()
	{
		rigidBody = GetComponent<Rigidbody>();
	}

	private void FixedUpdate()
	{
		rigidBody.maxAngularVelocity = angularVelocity.magnitude;
		rigidBody.angularVelocity = base.transform.TransformVector(angularVelocity);
	}
}
public class ShrinePlaceTotem : MonoBehaviour
{
	public int totemCount = 5;

	public GameObject totem;

	[Tooltip("Distance from which to form totem ring")]
	public float totemRadius = 2f;

	[Tooltip("Height from which to calculate totem placements.")]
	public float height = 10f;

	[Tooltip("Distance to raycast for totems")]
	public float raycastDistance = 20f;

	[Tooltip("Random bending of totems")]
	public float bendAmount = 15f;

	[Tooltip("Allowed difference from straight up (1) to straight down (-1)")]
	public float dotLimit = 0.8f;

	private void Awake()
	{
		int num = 0;
		for (int i = 0; i < totemCount * 2; i++)
		{
			float num2 = ((i >= totemCount) ? ((float)i * 1f * (360f / (float)totemCount)) : (((float)i + 0.5f) * (360f / (float)totemCount)));
			Physics.Raycast(base.transform.position + new UnityEngine.Vector3(0f, height, 0f), new UnityEngine.Vector3(Mathf.Cos(num2 * (MathF.PI / 180f)) * totemRadius, 0f - height, Mathf.Sin(num2 * (MathF.PI / 180f)) * totemRadius), out var hitInfo, raycastDistance);
			if (hitInfo.collider != null && UnityEngine.Vector3.Dot(hitInfo.normal, UnityEngine.Vector3.up) > dotLimit)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(totem, hitInfo.point, UnityEngine.Quaternion.identity);
				gameObject.transform.parent = base.transform;
				gameObject.transform.rotation = UnityEngine.Quaternion.FromToRotation(gameObject.transform.up, hitInfo.normal);
				gameObject.transform.eulerAngles += new UnityEngine.Vector3(UnityEngine.Random.Range(0f - bendAmount, bendAmount), UnityEngine.Random.Range(0f - bendAmount, bendAmount), UnityEngine.Random.Range(0f - bendAmount, bendAmount));
				gameObject.transform.position -= new UnityEngine.Vector3(0f, UnityEngine.Random.Range(0.1f, 0.2f), 0f);
				num++;
			}
			if (num == totemCount)
			{
				break;
			}
		}
	}

	private void Update()
	{
	}
}
public class SpeechBubbleController : MonoBehaviour
{
	[Serializable]
	public struct SpeechCategory
	{
		public string refName;

		public float chanceToTrigger;

		public SpeechInfo[] speechInfos;

		public WeightedSelection<SpeechInfo> speechSelection;
	}

	[Serializable]
	public struct SpeechInfo
	{
		public string nameToken;

		public float weight;
	}

	[Header("Cached Components")]
	public Transform idealBubbleTransform;

	public CharacterBody characterBody;

	public SfxLocator sfxLocator;

	[Header("Speech Info")]
	public string formatStringToken;

	public float minimumDurationBetweenSpeech;

	public bool removeRepeats;

	[SerializeField]
	public SpeechCategory[] speechCategories;

	[Header("Events")]
	public UnityEvent onBodyDamageDealt;

	public UnityEvent onStart;

	public UnityEvent onBodyKill;

	public UnityEvent onBodyDeath;

	private GameObject speechBubbleInstance;

	private float lastSpeechStopwatch;

	private void Start()
	{
		Initialize();
		lastSpeechStopwatch = minimumDurationBetweenSpeech;
		onStart?.Invoke();
	}

	private void OnEnable()
	{
		GlobalEventManager.onServerDamageDealt += OnServerDamageDealt;
		GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
	}

	private void OnDisable()
	{
		GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt;
		GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
	}

	private void FixedUpdate()
	{
		lastSpeechStopwatch += Time.fixedDeltaTime;
	}

	private void OnCharacterDeathGlobal(DamageReport damageReport)
	{
		if ((object)damageReport.victimBody == characterBody)
		{
			onBodyDeath?.Invoke();
		}
		else if ((object)damageReport.attackerBody == characterBody)
		{
			onBodyKill?.Invoke();
		}
	}

	private void OnServerDamageDealt(DamageReport damageReport)
	{
		if ((object)damageReport.attackerBody == characterBody)
		{
			onBodyDamageDealt?.Invoke();
		}
	}

	private void Initialize()
	{
		for (int i = 0; i < speechCategories.Length; i++)
		{
			WeightedSelection<SpeechInfo> weightedSelection = new WeightedSelection<SpeechInfo>();
			for (int j = 0; j < speechCategories[i].speechInfos.Length; j++)
			{
				SpeechInfo value = speechCategories[i].speechInfos[j];
				weightedSelection.AddChoice(value, value.weight);
			}
			speechCategories[i].speechSelection = weightedSelection;
		}
	}

	private void SubmitSpeech(string token)
	{
		lastSpeechStopwatch = 0f;
		Chat.SendBroadcastChat(new Chat.NpcChatMessage
		{
			baseToken = token,
			formatStringToken = formatStringToken,
			sender = base.gameObject,
			sound = sfxLocator.barkSound
		});
	}

	public void TriggerSpeech(string refName)
	{
		if (lastSpeechStopwatch < minimumDurationBetweenSpeech)
		{
			return;
		}
		for (int i = 0; i < speechCategories.Length; i++)
		{
			if (speechCategories[i].refName == refName)
			{
				if (speechCategories[i].speechSelection.Count <= 0)
				{
					Initialize();
				}
				int num = speechCategories[i].speechSelection.EvaluateToChoiceIndex(UnityEngine.Random.value);
				SpeechInfo value = speechCategories[i].speechSelection.GetChoice(num).value;
				if (removeRepeats)
				{
					SpeechCategory speechCategory = speechCategories[i];
					speechCategory.speechSelection.RemoveChoice(num);
					speechCategories[i] = speechCategory;
				}
				if (UnityEngine.Random.value < speechCategories[i].chanceToTrigger)
				{
					SubmitSpeech(value.nameToken);
				}
			}
		}
	}
}
public class TracerBehavior : MonoBehaviour
{
	public float speed = 1f;

	public UnityEngine.Vector3[] positions;

	private UnityEngine.Vector3 direction;

	private void Start()
	{
		direction = UnityEngine.Vector3.Normalize(positions[1] - positions[0]);
	}

	private void Update()
	{
		if (UnityEngine.Vector3.Distance(base.transform.position, positions[1]) > speed * Time.deltaTime)
		{
			base.transform.position += direction * speed * Time.deltaTime;
		}
	}
}
[RequireComponent(typeof(HGButton))]
public class AlternateButtonEvents : MonoBehaviour
{
	public UnityEvent onAlternateClick;

	public UnityEvent onTertiaryClick;

	public void InvokeAltClick()
	{
		if (onAlternateClick != null)
		{
			onAlternateClick.Invoke();
		}
	}

	public void InvokeTertiaryClick()
	{
		if (onTertiaryClick != null)
		{
			onTertiaryClick.Invoke();
		}
	}
}
public static class AutomatedBuildVersion
{
	public const string buildVersionString = "290";
}
[RequireComponent(typeof(MPEventSystemLocator))]
public class DevCheatMenu : MonoBehaviour
{
	public TextMeshProUGUI enemyName;

	public TextMeshProUGUI teamText;

	public TextMeshProUGUI affixText;

	public TextMeshProUGUI spawnEnemyText;

	public TextMeshProUGUI toggleSpawningText;

	public TextMeshProUGUI miscCommandLabel;

	public TMP_Dropdown masterNameDropdown;

	public TMP_Dropdown enemiesAmountDropdown;

	public TMP_Dropdown itemsNamesDropdown;

	public TMP_Dropdown itemsAmountDropdown;

	public TMP_Dropdown stageListDropdown;

	private string enemyMasterName;

	private string teamIndex;

	private string equipmentIndex;

	private string enemyMasterNameTeamIndexEquipmentIndex;

	private bool spawnEnemyArgsDirty;

	private readonly StringBuilder miscCommand = new StringBuilder();

	private NetworkUser localUser;

	private MPEventSystem eventSystem;

	private bool isUpper;

	private void Awake()
	{
		Close();
	}

	private void SetMonsterTabText()
	{
		spawnEnemyText.SetText(enemyMasterNameTeamIndexEquipmentIndex);
		enemyName.SetText(enemyMasterName);
		teamText.SetText(teamIndex);
		affixText.SetText(equipmentIndex);
		toggleSpawningText.SetText(CombatDirector.cvDirectorCombatDisable.value ? "Spawning DISABLED" : "Spawning ENABLED");
	}

	private void InitializeMasterDropdown()
	{
		masterNameDropdown.options = MasterCatalog.allMasters.Select((CharacterMaster master) => new TMP_Dropdown.OptionData(master.gameObject.name)).ToList();
	}

	private void InitializeStageListDropdown()
	{
		stageListDropdown.options = SceneCatalog.allSceneDefs.Select((SceneDef scene) => new TMP_Dropdown.OptionData(scene.baseSceneName)).ToList();
	}

	public void EnableSpawning()
	{
	}

	public void DisableSpawning()
	{
	}

	public void SpawnEnemy()
	{
		if (!CombatDirector.cvDirectorCombatDisable.value && !string.IsNullOrEmpty(enemyMasterName))
		{
			if (spawnEnemyArgsDirty)
			{
				enemyMasterNameTeamIndexEquipmentIndex = string.Join(" ", "create_master", enemyMasterName, teamIndex, equipmentIndex);
				spawnEnemyArgsDirty = false;
			}
			int num = int.Parse(enemiesAmountDropdown.options[Mathf.Min(enemiesAmountDropdown.options.Count - 1, enemiesAmountDropdown.value)].text);
			for (int i = 0; i < num; i++)
			{
				RoR2.Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], enemyMasterNameTeamIndexEquipmentIndex, recordSubmit: true);
				spawnEnemyText.SetText(enemyMasterNameTeamIndexEquipmentIndex);
			}
		}
	}

	public void SetEnemyMasterName()
	{
		string text = masterNameDropdown.options[Mathf.Min(masterNameDropdown.options.Count - 1, masterNameDropdown.value)].text;
		if (string.IsNullOrEmpty(text) || enemyMasterName == text || MasterCatalog.FindMasterIndex(text) == MasterCatalog.MasterIndex.none)
		{
			UnityEngine.Debug.LogWarning("Invalid newEnemyMaster: " + text);
			return;
		}
		enemyMasterName = text;
		spawnEnemyArgsDirty = true;
		enemyName.SetText(enemyMasterName);
	}

	public void SetSceneTravelName()
	{
		string text = stageListDropdown.options[Mathf.Min(stageListDropdown.options.Count - 1, stageListDropdown.value)].text;
		if (!string.IsNullOrEmpty(text))
		{
			RoR2.Console.instance.SubmitCmd(null, "set_scene " + text);
		}
	}

	public void SetTeamIndex(string newTeamIndex)
	{
		if (string.IsNullOrEmpty(newTeamIndex) || teamIndex == newTeamIndex || !Enum.TryParse<TeamIndex>(newTeamIndex, ignoreCase: true, out var _))
		{
			UnityEngine.Debug.LogWarning("Invalid newTeamIndex: " + newTeamIndex);
			return;
		}
		teamIndex = newTeamIndex;
		spawnEnemyArgsDirty = true;
		teamText.SetText(teamIndex);
	}

	public void SetCurrentEquipment(string newEquipment)
	{
		if (string.IsNullOrEmpty(newEquipment) || equipmentIndex == newEquipment || EquipmentCatalog.FindEquipmentIndex(newEquipment) == EquipmentIndex.None)
		{
			UnityEngine.Debug.LogWarning("Invalid newEquipment: " + newEquipment);
			return;
		}
		equipmentIndex = newEquipment;
		spawnEnemyArgsDirty = true;
		affixText.SetText(equipmentIndex);
	}

	public void SetUppercase()
	{
		isUpper = true;
	}

	public void SetLowercase()
	{
		isUpper = false;
	}

	public void BackspaceMiscCommand()
	{
		miscCommand.Remove(miscCommand.Length - 1, 1);
		miscCommandLabel.SetText(miscCommand);
	}

	public void AppendMiscCommand(string stringToAdd)
	{
		miscCommand.Append(isUpper ? stringToAdd.ToUpper() : stringToAdd.ToLower());
		miscCommandLabel.SetText(miscCommand);
	}

	public void SubmitMiscCommand()
	{
		string text = miscCommand.ToString();
		if (string.IsNullOrEmpty(text))
		{
			string text2 = "Invalid command sequence: " + text + ". Enter a valid command sequence before submitting a command.";
			UnityEngine.Debug.LogWarning(text2);
			miscCommandLabel.SetText(text2);
			return;
		}
		if (localUser == null && NetworkUser.readOnlyLocalPlayersList != null && NetworkUser.readOnlyLocalPlayersList.Count > 0)
		{
			localUser = NetworkUser.readOnlyLocalPlayersList[0];
		}
		RoR2.Console.instance.SubmitCmd(localUser, text, recordSubmit: true);
	}

	public void ClearMiscCommand()
	{
		miscCommand.Clear();
		miscCommandLabel.SetText(miscCommand);
	}

	public void AttemptAlternateClick()
	{
		if ((bool)eventSystem.currentSelectedButton)
		{
			AlternateButtonEvents component = eventSystem.currentSelectedButton.GetComponent<AlternateButtonEvents>();
			if ((bool)component)
			{
				component.InvokeAltClick();
			}
		}
	}

	public void AttemptTertiaryClick()
	{
		if ((bool)eventSystem.currentSelectedButton)
		{
			AlternateButtonEvents component = eventSystem.currentSelectedButton.GetComponent<AlternateButtonEvents>();
			if ((bool)component)
			{
				component.InvokeTertiaryClick();
			}
		}
	}

	private void InitializeItemsDropdown()
	{
		itemsNamesDropdown.options = ContentManager._itemDefs.Select((ItemDef itemDef) => new TMP_Dropdown.OptionData(itemDef.name)).ToList();
	}

	public void GiveItem()
	{
		string text = itemsNamesDropdown.options[Mathf.Min(itemsNamesDropdown.options.Count - 1, itemsNamesDropdown.value)].text;
		int num = int.Parse(itemsAmountDropdown.options[Mathf.Min(itemsAmountDropdown.options.Count - 1, itemsAmountDropdown.value)].text);
		RoR2.Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], $"give_item {text} {num}", recordSubmit: true);
	}

	[ConCommand(commandName = "enemies_are_gods", flags = ConVarFlags.None, helpText = "EnemiesAreGods")]
	private static void EnemiesAreGods(ConCommandArgs args)
	{
		foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(TeamIndex.Monster))
		{
			HealthComponent component = teamMember.GetComponent<HealthComponent>();
			component.godMode = !component.godMode;
		}
	}

	public void StartLog()
	{
	}

	public void StopLog()
	{
	}

	public void Close()
	{
		UnityEngine.Object.Destroy(base.gameObject);
	}
}
public class EclipseDifficultyMedalDisplay : MonoBehaviour
{
	[SerializeField]
	private int eclipseLevel;

	[SerializeField]
	private UnityEngine.UI.Image iconImage;

	[SerializeField]
	private Sprite unearnedSprite;

	[SerializeField]
	private Sprite incompleteSprite;

	[SerializeField]
	private Sprite completeSprite;

	private void OnEnable()
	{
		UserProfile.onSurvivorPreferenceChangedGlobal += OnSurvivorPreferenceChangedGlobal;
		Refresh();
	}

	private void OnDisable()
	{
		UserProfile.onSurvivorPreferenceChangedGlobal -= OnSurvivorPreferenceChangedGlobal;
	}

	private void OnSurvivorPreferenceChangedGlobal(UserProfile userProfile)
	{
		Refresh();
	}

	private void Refresh()
	{
		LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
		SurvivorDef survivorDef = firstLocalUser?.userProfile.GetSurvivorPreference();
		if (!survivorDef)
		{
			return;
		}
		int localUserSurvivorCompletedEclipseLevel = EclipseRun.GetLocalUserSurvivorCompletedEclipseLevel(firstLocalUser, survivorDef);
		if (eclipseLevel <= localUserSurvivorCompletedEclipseLevel)
		{
			bool flag = true;
			foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs)
			{
				if (ShouldDisplaySurvivor(orderedSurvivorDef, firstLocalUser))
				{
					localUserSurvivorCompletedEclipseLevel = EclipseRun.GetLocalUserSurvivorCompletedEclipseLevel(firstLocalUser, orderedSurvivorDef);
					if (localUserSurvivorCompletedEclipseLevel < eclipseLevel)
					{
						flag = false;
						break;
					}
				}
			}
			if (flag)
			{
				iconImage.sprite = completeSprite;
			}
			else
			{
				iconImage.sprite = incompleteSprite;
			}
		}
		else
		{
			iconImage.sprite = unearnedSprite;
		}
	}

	private bool ShouldDisplaySurvivor(SurvivorDef survivorDef, LocalUser localUser)
	{
		if ((bool)survivorDef && !survivorDef.hidden)
		{
			return survivorDef.CheckUserHasRequiredEntitlement(localUser);
		}
		return false;
	}
}
public class FriendSessionBrowserController : MonoBehaviour
{
	public SessionButtonController SessionButtonPrefab;

	public Transform SessionButtonContainer;

	public RectTransform InProgressSpinner;

	public TextMeshProUGUI SearchStateText;

	public MPButton RefreshButton;

	public MPButton BackButton;

	private List<SessionButtonController> sessionButtons;
}
public class GenericInspectInfoProvider : MonoBehaviour, IInspectInfoProvider, IHasInspectHintOverride
{
	public InspectDef InspectInfo;

	[Tooltip("Set this to a non-empty token to override the default Inspect hint on the HUD.")]
	public string inspectHintOverrideToken;

	public bool CanBeInspected()
	{
		return true;
	}

	public InspectInfo GetInfo()
	{
		return InspectInfo;
	}

	public bool GetInspectHintOverride(out string hintOverride)
	{
		if (inspectHintOverrideToken.Length > 0)
		{
			hintOverride = Language.GetString(inspectHintOverrideToken);
			return true;
		}
		hintOverride = null;
		return false;
	}
}
public class InviteButton : MonoBehaviour
{
	public void OnInviteButtonPressed()
	{
		PlatformSystems.lobbyManager.OpenInviteOverlay();
	}
}
public class SessionButtonController : MonoBehaviour
{
	public HGButton Button;

	public HGTextMeshProUGUI Text;

	public void AddListener(UnityAction call)
	{
		Button.onClick.AddListener(call);
	}

	public void SetText(int currentParticipationNumber, int maxParticipationNumber, string hostName)
	{
		Text.text = currentParticipationNumber + "/" + maxParticipationNumber + " " + hostName;
	}
}
public class SocialUserIconBehavior
{
	protected enum SourceType
	{
		Local,
		Network
	}

	protected RawImage rawImageComponent;

	protected Texture2D generatedTexture;

	protected RoR2.PlatformID userID;

	protected SourceType sourceType;

	protected GameObject gameObject;

	protected MonoBehaviour monoBehaviour;

	protected UserManager.AvatarSize avatarSize;

	protected Texture defaultTexture => LegacyResourcesAPI.Load<Texture>("Textures/UI/texDefaultSocialUserIcon");

	public void Awake(GameObject go, MonoBehaviour mb)
	{
		gameObject = go;
		monoBehaviour = mb;
		OnAwakeBehavior();
	}

	public void OnEnable(GameObject go, MonoBehaviour mb)
	{
		gameObject = go;
		monoBehaviour = mb;
		OnEnableBehavior();
	}

	public void OnDestroy()
	{
		OnDestroyBehavior();
		gameObject = null;
		monoBehaviour = null;
	}

	protected virtual void OnAwakeBehavior()
	{
		rawImageComponent = gameObject.GetComponent<RawImage>();
		rawImageComponent.texture = defaultTexture;
		if (!UserManager.P_UseSocialIcon.value)
		{
			gameObject.SetActive(value: false);
		}
	}

	protected virtual void OnEnableBehavior()
	{
	}

	protected virtual void OnDestroyBehavior()
	{
	}

	public virtual void Refresh(bool shouldForceRefresh = false)
	{
		if (PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon))
		{
			PlatformSystems.userManager.GetAvatar(userID, gameObject, generatedTexture, avatarSize, HandleNewTexture);
			if (!generatedTexture && rawImageComponent != null)
			{
				rawImageComponent.texture = defaultTexture;
			}
		}
	}

	public virtual void SetFromMaster(CharacterMaster master)
	{
		if (!PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon))
		{
			return;
		}
		if ((bool)master)
		{
			PlayerCharacterMasterController component = master.GetComponent<PlayerCharacterMasterController>();
			if ((bool)component)
			{
				NetworkUser networkUser = component.networkUser;
				RefreshWithUser(new RoR2.PlatformID(networkUser.id.value));
				return;
			}
		}
		userID = default(RoR2.PlatformID);
		sourceType = SourceType.Local;
		Refresh();
	}

	public virtual void RefreshWithUser(RoR2.PlatformID newUserID)
	{
		if (PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon) && (sourceType != SourceType.Network || !newUserID.Equals(userID)))
		{
			sourceType = SourceType.Network;
			userID = newUserID;
			Refresh();
		}
	}

	protected virtual void HandleNewTexture(Texture2D tex)
	{
		if ((bool)tex)
		{
			generatedTexture = tex;
			if (rawImageComponent != null)
			{
				rawImageComponent.texture = tex;
			}
		}
	}
}
public class SocialUserIconBehaviorConsoles : SocialUserIconBehavior
{
	private bool UserIconIsLoad;

	private bool loadAvatarIsDone;

	private Texture2D pointerOfTexture;

	private HGButton button;

	private bool blockToClick;

	private WaitForSeconds waiteSecond = new WaitForSeconds(0.3f);

	private UnityEngine.UI.Image outline;

	public override void Refresh(bool shouldForceRefresh = false)
	{
		if (!(!PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon) | (UserIconIsLoad && !shouldForceRefresh)))
		{
			PlatformSystems.userManager.GetAvatar(userID, gameObject, generatedTexture, avatarSize, HandleNewTexture);
			UserIconIsLoad = true;
			loadAvatarIsDone = false;
			if ((bool)gameObject && gameObject.activeInHierarchy)
			{
				monoBehaviour.StartCoroutine(UserIconTextureChangeCoroutine());
			}
			if (!generatedTexture && rawImageComponent != null)
			{
				rawImageComponent.texture = base.defaultTexture;
			}
		}
	}

	public override void RefreshWithUser(RoR2.PlatformID newUserID)
	{
		if (PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.UserIcon) && (sourceType != SourceType.Network || !newUserID.Equals(userID)))
		{
			sourceType = SourceType.Network;
			UserIconIsLoad = false;
			userID = newUserID;
			InitButtonToClickeble();
			Refresh();
		}
	}

	protected override void HandleNewTexture(Texture2D tex)
	{
		if (tex == null || rawImageComponent == null)
		{
			UserIconIsLoad = false;
			if (this != null && (bool)gameObject)
			{
				monoBehaviour.StopCoroutine(UserIconTextureChangeCoroutine());
			}
		}
		else
		{
			pointerOfTexture = tex;
			generatedTexture = pointerOfTexture;
			rawImageComponent.texture = pointerOfTexture;
			loadAvatarIsDone = true;
		}
	}

	protected override void OnAwakeBehavior()
	{
		rawImageComponent = gameObject.GetComponent<RawImage>();
		rawImageComponent.texture = base.defaultTexture;
		rawImageComponent.rectTransform.sizeDelta = new UnityEngine.Vector2(32f, 32f);
		if (PreGameController.instance != null)
		{
			UserIconIsLoad = false;
		}
		if (!UserManager.P_UseSocialIcon.value)
		{
			gameObject.SetActive(value: false);
		}
	}

	protected override void OnEnableBehavior()
	{
		if (UserIconIsLoad)
		{
			monoBehaviour.StartCoroutine(UserIconTextureChangeCoroutine());
		}
		if (userID != default(RoR2.PlatformID))
		{
			InitButtonToClickeble();
		}
	}

	private void InitButtonToClickeble()
	{
		if (!(button != null) && !(gameObject == null))
		{
			button = gameObject.AddComponent<HGButton>();
			button.onClick.RemoveAllListeners();
			button.onClick.AddListener(OnClickToSocialUserIcon);
			outline = gameObject.transform.GetComponentInChildren<UnityEngine.UI.Image>();
			if (outline != null)
			{
				outline.rectTransform.offsetMax = new UnityEngine.Vector2(2f, 2f);
				outline.rectTransform.offsetMin = new UnityEngine.Vector2(-2f, -2f);
				button.onSelect = new UnityEvent();
				button.onSelect.AddListener(Selected);
				button.onDeselect = new UnityEvent();
				button.onDeselect.AddListener(Deselected);
			}
		}
	}

	private void Selected()
	{
		outline.enabled = true;
	}

	private void Deselected()
	{
		outline.enabled = false;
	}

	private void OnClickToSocialUserIcon()
	{
		if (!blockToClick)
		{
			blockToClick = true;
		}
	}

	private void UnblockToCkick()
	{
		if (!monoBehaviour.isActiveAndEnabled)
		{
			blockToClick = false;
		}
		else
		{
			monoBehaviour.StartCoroutine(ButtonUpAcrivityCoroutine());
		}
	}

	private IEnumerator ButtonUpAcrivityCoroutine()
	{
		yield return waiteSecond;
		blockToClick = false;
	}

	private IEnumerator UserIconTextureChangeCoroutine()
	{
		while (!loadAvatarIsDone)
		{
			yield return null;
		}
		generatedTexture = pointerOfTexture;
		rawImageComponent.texture = pointerOfTexture;
	}
}
public class VectorPID : MonoBehaviour
{
	[Tooltip("Just a field for user naming. Doesn't do anything.")]
	[FormerlySerializedAs("name")]
	public string customName;

	[Tooltip("PID Constants.")]
	public UnityEngine.Vector3 PID = new UnityEngine.Vector3(1f, 0f, 0f);

	[Tooltip("The vector we are currently at.")]
	[HideInInspector]
	public UnityEngine.Vector3 inputVector = UnityEngine.Vector3.zero;

	[HideInInspector]
	[Tooltip("The vector we want to be at.")]
	public UnityEngine.Vector3 targetVector = UnityEngine.Vector3.zero;

	[Tooltip("Vector output from PID controller; what we read.")]
	[HideInInspector]
	public UnityEngine.Vector3 outputVector = UnityEngine.Vector3.zero;

	[Tooltip("This is an euler angle, so we need to wrap correctly")]
	public bool isAngle;

	public float gain = 1f;

	private UnityEngine.Vector3 errorSum = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 deltaError = UnityEngine.Vector3.zero;

	private UnityEngine.Vector3 lastError = UnityEngine.Vector3.zero;

	private float lastTimer;

	private float timer;

	private void Start()
	{
	}

	private void FixedUpdate()
	{
		timer += Time.fixedDeltaTime;
	}

	public UnityEngine.Vector3 UpdatePID()
	{
		float num = timer - lastTimer;
		lastTimer = timer;
		if (num != 0f)
		{
			UnityEngine.Vector3 vector;
			if (isAngle)
			{
				vector = UnityEngine.Vector3.zero;
				vector.x = Mathf.DeltaAngle(inputVector.x, targetVector.x);
				vector.y = Mathf.DeltaAngle(inputVector.y, targetVector.y);
				vector.z = Mathf.DeltaAngle(inputVector.z, targetVector.z);
			}
			else
			{
				vector = targetVector - inputVector;
			}
			errorSum += vector * num;
			deltaError = (vector - lastError) / num;
			lastError = vector;
			outputVector = vector * PID.x + errorSum * PID.y + deltaError * PID.z;
			return outputVector * gain;
		}
		return UnityEngine.Vector3.zero;
	}
}
public class Visualizer : MonoBehaviour
{
	public float yscale;

	public GameObject particleObject;

	public float yvalue;

	private UnityEngine.Vector3 initialPos;

	private void Start()
	{
		initialPos = particleObject.transform.localPosition;
	}

	private void Update()
	{
		particleObject.transform.localPosition = initialPos + new UnityEngine.Vector3(0f, yvalue / yscale, 0f);
	}
}
public class Wind : MonoBehaviour
{
	private Renderer rend;

	private MaterialPropertyBlock props;

	public UnityEngine.Vector4 windVector;

	public float MainWindAmplitude = 1f;

	public float MainWindSpeed = 3f;

	private float time;

	private void Start()
	{
		rend = GetComponent<Renderer>();
		props = new MaterialPropertyBlock();
		SetWind(props, windVector);
	}

	private void Update()
	{
		time += Time.deltaTime;
		windVector.x = (0.5f + 0.5f * Mathf.Sin(MainWindSpeed * time * (MathF.PI / 180f))) * MainWindAmplitude;
		SetWind(props, windVector);
	}

	private void SetWind(MaterialPropertyBlock block, UnityEngine.Vector4 input)
	{
		rend.GetPropertyBlock(block);
		block.Clear();
		block.SetVector("_Wind", input);
		rend.SetPropertyBlock(block);
	}
}
[Obsolete("HGArrayUtilities is deprecated. Use HG.ArrayUtils instead.")]
public static class HGArrayUtilities
{
	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void ArrayInsertNoResize<T>(T[] array, int arraySize, int position, ref T value)
	{
		ArrayUtils.ArrayInsertNoResize(array, arraySize, position, in value);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void ArrayInsert<T>(ref T[] array, ref int arraySize, int position, ref T value)
	{
		ArrayUtils.ArrayInsert(ref array, ref arraySize, position, in value);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void ArrayInsert<T>(ref T[] array, int position, ref T value)
	{
		ArrayUtils.ArrayInsert(ref array, position, in value);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void ArrayAppend<T>(ref T[] array, ref int arraySize, ref T value)
	{
		ArrayUtils.ArrayAppend(ref array, ref arraySize, in value);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void ArrayAppend<T>(ref T[] array, ref T value)
	{
		ArrayUtils.ArrayAppend(ref array, in value);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void ArrayRemoveAt<T>(ref T[] array, ref int arraySize, int position, int count = 1)
	{
		ArrayUtils.ArrayRemoveAt(array, ref arraySize, position, count);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void ArrayRemoveAtAndResize<T>(ref T[] array, int position, int count = 1)
	{
		ArrayUtils.ArrayRemoveAtAndResize(ref array, position, count);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static T GetSafe<T>([NotNull] T[] array, int index)
	{
		return ArrayUtils.GetSafe(array, index);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static T GetSafe<T>([NotNull] T[] array, int index, T defaultValue)
	{
		return ArrayUtils.GetSafe(array, index, in defaultValue);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void SetAll<T>(T[] array, in T value)
	{
		ArrayUtils.SetAll(array, in value);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void EnsureCapacity<T>(ref T[] array, int capacity)
	{
		ArrayUtils.EnsureCapacity(ref array, capacity);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void Swap<T>(T[] array, int a, int b)
	{
		ArrayUtils.Swap(array, a, b);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void Clear<T>(T[] array, ref int count)
	{
		ArrayUtils.Clear(array, ref count);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool SequenceEquals<T>(T[] a, T[] b) where T : IEquatable<T>
	{
		return ArrayUtils.SequenceEquals(a, b);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static T[] Clone<T>(T[] src)
	{
		return ArrayUtils.Clone(src);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool IsInBounds<T>(T[] array, int index)
	{
		return ArrayUtils.IsInBounds(array, index);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool IsInBounds<T>(T[] array, uint index)
	{
		return ArrayUtils.IsInBounds(array, index);
	}
}
public static class HGMath
{
	[Obsolete("Use HG.Vector3Utils.AverageFast or .AveragePrecise instead.", false)]
	public static UnityEngine.Vector3 Average<T>(T entries) where T : ICollection<UnityEngine.Vector3>
	{
		int count = entries.Count;
		float num = 1f / (float)count;
		UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
		foreach (UnityEngine.Vector3 item in entries)
		{
			zero += num * item;
		}
		return zero;
	}

	[Obsolete("Use HG.Vector3Utils.Average instead.", false)]
	public static UnityEngine.Vector3 Average(in UnityEngine.Vector3 a, in UnityEngine.Vector3 b)
	{
		return Vector3Utils.Average(in a, in b);
	}

	[Obsolete("Use HG.Vector3Utils.Average instead.", false)]
	public static UnityEngine.Vector3 Average(in UnityEngine.Vector3 a, in UnityEngine.Vector3 b, in UnityEngine.Vector3 c)
	{
		return Vector3Utils.Average(in a, in b, in c);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static int IntDivCeil(int a, int b)
	{
		return (a - 1) / b + 1;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static uint UintSafeSubtract(uint a, uint b)
	{
		if (b <= a)
		{
			return a - b;
		}
		return 0u;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static uint UintSafeAdd(uint a, uint b)
	{
		uint num = a + b;
		uint num2 = ((a > b) ? a : b);
		if (num >= num2)
		{
			return num;
		}
		return uint.MaxValue;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static byte ByteSafeSubtract(byte a, byte b)
	{
		if (b <= a)
		{
			return (byte)(a - b);
		}
		return 0;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static byte ByteSafeAdd(byte a, byte b)
	{
		byte b2 = (byte)(a + b);
		byte b3 = ((a > b) ? a : b);
		if (b2 >= b3)
		{
			return b2;
		}
		return byte.MaxValue;
	}

	public static UnityEngine.Vector3 Remap(UnityEngine.Vector3 value, UnityEngine.Vector3 inMin, UnityEngine.Vector3 inMax, UnityEngine.Vector3 outMin, UnityEngine.Vector3 outMax)
	{
		return new UnityEngine.Vector3(outMin.x + (value.x - inMin.x) / (inMax.x - inMin.x) * (outMax.x - outMin.x), outMin.y + (value.y - inMin.y) / (inMax.y - inMin.y) * (outMax.y - outMin.y), outMin.z + (value.z - inMin.z) / (inMax.z - inMin.z) * (outMax.z - outMin.z));
	}

	public static UnityEngine.Vector3 Remap(UnityEngine.Vector3 value, float inMin, float inMax, float outMin, float outMax)
	{
		return new UnityEngine.Vector3(outMin + (value.x - inMin) / (inMax - inMin) * (outMax - outMin), outMin + (value.y - inMin) / (inMax - inMin) * (outMax - outMin), outMin + (value.z - inMin) / (inMax - inMin) * (outMax - outMin));
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	private static float Clamp(float value, float min, float max)
	{
		if (!(value > min))
		{
			return min;
		}
		if (!(value < max))
		{
			return max;
		}
		return value;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static int Clamp(int value, int min, int max)
	{
		if (value <= min)
		{
			return min;
		}
		if (value >= max)
		{
			return max;
		}
		return value;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static uint Clamp(uint value, uint min, uint max)
	{
		if (value <= min)
		{
			return min;
		}
		if (value >= max)
		{
			return max;
		}
		return value;
	}

	public static UnityEngine.Vector3 Clamp(UnityEngine.Vector3 value, UnityEngine.Vector3 min, UnityEngine.Vector3 max)
	{
		return new UnityEngine.Vector3(Clamp(value.x, min.x, max.x), Clamp(value.y, min.y, max.y), Clamp(value.z, min.z, max.z));
	}

	public static UnityEngine.Vector3 Clamp(UnityEngine.Vector3 value, float min, float max)
	{
		return new UnityEngine.Vector3(Clamp(value.x, min, max), Clamp(value.y, min, max), Clamp(value.z, min, max));
	}

	public static bool IsVectorNaN(UnityEngine.Vector3 value)
	{
		if (!float.IsNaN(value.x) && !float.IsNaN(value.y))
		{
			return float.IsNaN(value.z);
		}
		return true;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool IsVectorValid(ref UnityEngine.Vector3 vector3)
	{
		float f = vector3.x + vector3.y + vector3.z;
		if (!float.IsInfinity(f))
		{
			return !float.IsNaN(f);
		}
		return false;
	}

	public static bool Overshoots(UnityEngine.Vector3 startPosition, UnityEngine.Vector3 endPosition, UnityEngine.Vector3 targetPosition)
	{
		UnityEngine.Vector3 lhs = endPosition - startPosition;
		UnityEngine.Vector3 rhs = targetPosition - endPosition;
		return UnityEngine.Vector3.Dot(lhs, rhs) <= 0f;
	}

	public static float TriangleArea(in UnityEngine.Vector3 a, in UnityEngine.Vector3 b, in UnityEngine.Vector3 c)
	{
		return 0.5f * UnityEngine.Vector3.Cross(b - a, c - a).magnitude;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static float CircleRadiusToArea(float radius)
	{
		return MathF.PI * (radius * radius);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static float CircleAreaToRadius(float area)
	{
		return Mathf.Sqrt(area * (1f / MathF.PI));
	}
}
public static class HGUnitConversions
{
	public static readonly double milesToKilometers = 1.609344;

	public static readonly double kilometersToMeters = 1000.0;

	public static readonly double milesToMeters = milesToKilometers * kilometersToMeters;

	public static readonly double hoursToMinutes = 60.0;

	public static readonly double minutesToSeconds = 60.0;

	public static readonly double hoursToSeconds = hoursToMinutes * minutesToSeconds;
}
public static class HGXml
{
	public delegate void Serializer<T>(XElement element, T contents);

	public delegate bool Deserializer<T>(XElement element, ref T contents);

	public class SerializationRules<T>
	{
		public Serializer<T> serializer;

		public Deserializer<T> deserializer;

		public static SerializationRules<T> defaultRules;

		static SerializationRules()
		{
			if (typeof(T).IsEnum)
			{
				RegisterEnum();
			}
		}

		private static void RegisterEnum()
		{
			Type typeFromHandle = typeof(T);
			Dictionary<string, T> nameToValue = new Dictionary<string, T>();
			string[] names = Enum.GetNames(typeFromHandle);
			for (int i = 0; i < names.Length; i++)
			{
				string text = names[i];
				Enum.Parse(typeFromHandle, names[i]);
				nameToValue[text] = (T)Enum.Parse(typeFromHandle, text);
			}
			Dictionary<T, string> valueToName = new Dictionary<T, string>();
			Array values = Enum.GetValues(typeFromHandle);
			for (int j = 0; j < values.Length; j++)
			{
				object value = values.GetValue(j);
				valueToName[(T)value] = Enum.GetName(typeFromHandle, value);
			}
			defaultRules = new SerializationRules<T>
			{
				serializer = Serializer,
				deserializer = Deserializer
			};
			bool Deserializer(XElement element, ref T contents)
			{
				if (nameToValue.TryGetValue(element.Value, out var value2))
				{
					contents = value2;
					return true;
				}
				try
				{
					contents = (T)Enum.Parse(typeof(T), element.Value);
					return true;
				}
				catch (Exception)
				{
				}
				return false;
			}
			void Serializer(XElement element, T contents)
			{
				if (valueToName.TryGetValue(contents, out var value3))
				{
					element.Value = value3;
				}
				else
				{
					element.Value = contents.ToString();
				}
			}
		}
	}

	public static void Register<T>(Serializer<T> serializer, Deserializer<T> deserializer)
	{
		SerializationRules<T>.defaultRules = new SerializationRules<T>
		{
			serializer = serializer,
			deserializer = deserializer
		};
	}

	[NotNull]
	public static XElement ToXml<T>(string name, T value)
	{
		return ToXml(name, value, SerializationRules<T>.defaultRules);
	}

	[NotNull]
	public static XElement ToXml<T>(string name, T value, SerializationRules<T> rules)
	{
		XElement xElement = new XElement(name);
		rules.serializer(xElement, value);
		return xElement;
	}

	public static bool FromXml<T>([NotNull] XElement element, ref T value)
	{
		return FromXml(element, ref value, SerializationRules<T>.defaultRules);
	}

	public static bool FromXml<T>([NotNull] XElement element, ref T value, SerializationRules<T> rules)
	{
		if (rules == null)
		{
			UnityEngine.Debug.LogFormat("Serialization rules not defined for type <{0}>", typeof(T).Name);
			return false;
		}
		return rules.deserializer(element, ref value);
	}

	public static bool FromXml<T>([NotNull] XElement element, [NotNull] Action<T> setter)
	{
		return FromXml(element, setter, SerializationRules<T>.defaultRules);
	}

	public static bool FromXml<T>([NotNull] XElement element, [NotNull] Action<T> setter, [NotNull] SerializationRules<T> rules)
	{
		T value = default(T);
		if (FromXml(element, ref value, rules))
		{
			setter(value);
			return true;
		}
		return false;
	}

	static HGXml()
	{
		Register(delegate(XElement element, int contents)
		{
			element.Value = TextSerialization.ToStringInvariant(contents);
		}, delegate(XElement element, ref int contents)
		{
			if (TextSerialization.TryParseInvariant(element.Value, out int result8))
			{
				contents = result8;
				return true;
			}
			return false;
		});
		Register(delegate(XElement element, uint contents)
		{
			element.Value = TextSerialization.ToStringInvariant(contents);
		}, delegate(XElement element, ref uint contents)
		{
			if (TextSerialization.TryParseInvariant(element.Value, out uint result7))
			{
				contents = result7;
				return true;
			}
			return false;
		});
		Register(delegate(XElement element, ulong contents)
		{
			element.Value = TextSerialization.ToStringInvariant(contents);
		}, delegate(XElement element, ref ulong contents)
		{
			if (TextSerialization.TryParseInvariant(element.Value, out ulong result6))
			{
				contents = result6;
				return true;
			}
			return false;
		});
		Register(delegate(XElement element, bool contents)
		{
			element.Value = (contents ? "1" : "0");
		}, delegate(XElement element, ref bool contents)
		{
			if (TextSerialization.TryParseInvariant(element.Value, out int result5))
			{
				contents = result5 != 0;
				return true;
			}
			return false;
		});
		Register(delegate(XElement element, float contents)
		{
			element.Value = TextSerialization.ToStringInvariant(contents);
		}, delegate(XElement element, ref float contents)
		{
			if (TextSerialization.TryParseInvariant(element.Value, out float result4))
			{
				contents = result4;
				return true;
			}
			return false;
		});
		Register(delegate(XElement element, double contents)
		{
			element.Value = TextSerialization.ToStringInvariant(contents);
		}, delegate(XElement element, ref double contents)
		{
			if (TextSerialization.TryParseInvariant(element.Value, out double result3))
			{
				contents = result3;
				return true;
			}
			return false;
		});
		Register(delegate(XElement element, string contents)
		{
			element.Value = contents;
		}, delegate(XElement element, ref string contents)
		{
			contents = element.Value;
			return true;
		});
		Register(delegate(XElement element, Guid contents)
		{
			element.Value = contents.ToString();
		}, delegate(XElement element, ref Guid contents)
		{
			if (Guid.TryParse(element.Value, out var result2))
			{
				contents = result2;
				return true;
			}
			return false;
		});
		Register(delegate(XElement element, DateTime contents)
		{
			element.Value = TextSerialization.ToStringInvariant(contents.ToBinary());
		}, delegate(XElement element, ref DateTime contents)
		{
			if (TextSerialization.TryParseInvariant(element.Value, out long result))
			{
				try
				{
					contents = DateTime.FromBinary(result);
					return true;
				}
				catch (ArgumentException)
				{
				}
			}
			return false;
		});
	}

	public static void Deserialize<T>(this XElement element, ref T dest)
	{
		FromXml(element, ref dest);
	}

	public static void Deserialize<T>(this XElement element, ref T dest, SerializationRules<T> rules)
	{
		FromXml(element, ref dest, rules);
	}

	public static void UsedOnlyForAOTCodeGeneration()
	{
		throw new InvalidOperationException("This method is used for AOT code generation only. Do not call it at runtime.");
	}
}
public class HideIfSurvivorLocked : MonoBehaviour
{
	[Tooltip("Survivor Def(s) that must be unlocked in order to show this component's gameObject. (ANY)")]
	public SurvivorDef[] requiredSurvivors;

	[Tooltip("Indicator to show that none of the designated survivors are unlocked.")]
	public GameObject lockedIndicator;

	private void Awake()
	{
		EntitlementManager.onEntitlementsUpdated += Reset;
		Reset();
	}

	private void OnDestroy()
	{
		EntitlementManager.onEntitlementsUpdated -= Reset;
	}

	private void Reset()
	{
		if (requiredSurvivors.Length != 0)
		{
			if (requiredSurvivors.Any((SurvivorDef survivorDef) => SurvivorCatalog.SurvivorIsUnlockedOnThisClient(survivorDef.survivorIndex) && survivorDef.CheckLocalUserHasRequiredEntitlement()))
			{
				base.gameObject.SetActive(value: true);
				SetLockIndicator(value: false);
			}
			else
			{
				base.gameObject.SetActive(value: false);
				SetLockIndicator(value: true);
			}
		}
		else
		{
			UnityEngine.Debug.LogWarning("No designated requiredSurvivors or lockedIndicator on HideIfSurvivorLocked. Consider updating or removing this component on gameObject:" + base.gameObject.name + ".");
		}
	}

	private void SetLockIndicator(bool value)
	{
		if (lockedIndicator != null)
		{
			lockedIndicator.SetActive(value);
		}
	}
}
public class ItemIndexStorage : MonoBehaviour
{
	public bool isEquipment;

	public ItemIndex itemIndex;

	public EquipmentIndex equipmentIndex;
}
public readonly struct KeyValueSplitter
{
	private interface IStringWrapper
	{
		int Length { get; }

		string SubString(int startIndex, int length);
	}

	private struct StringWrapper : IStringWrapper
	{
		private readonly string src;

		public int Length => src.Length;

		public StringWrapper([NotNull] string str)
		{
			src = str;
		}

		public override string ToString()
		{
			return src;
		}

		public string SubString(int startIndex, int length)
		{
			return src.Substring(startIndex, length);
		}
	}

	private struct StringBuilderWrapper : IStringWrapper
	{
		private readonly StringBuilder src;

		public int Length => src.Length;

		public StringBuilderWrapper([NotNull] StringBuilder src)
		{
			this.src = src;
		}

		public override string ToString()
		{
			return src.ToString();
		}

		public string SubString(int startIndex, int length)
		{
			return src.ToString(startIndex, length);
		}
	}

	public readonly string baseKey;

	private readonly int maxKeyLength;

	private readonly int maxValueLength;

	private readonly List<string> currentSubKeys;

	private readonly Action<string, string> keyValueSetter;

	public KeyValueSplitter([NotNull] string baseKey, int maxKeyLength, int maxValueLength, [NotNull] Action<string, string> keyValueSetter)
	{
		this.baseKey = baseKey;
		this.maxKeyLength = maxKeyLength;
		this.maxValueLength = maxValueLength;
		this.keyValueSetter = keyValueSetter;
		currentSubKeys = new List<string>();
	}

	public void SetValue([NotNull] StringBuilder stringBuilder)
	{
		SetValueInternal(new StringBuilderWrapper(stringBuilder));
	}

	public void SetValue([NotNull] string value)
	{
		SetValueInternal(new StringWrapper(value));
	}

	private void SetValueInternal<T>(T value) where T : IStringWrapper
	{
		int length = value.Length;
		List<KeyValuePair<string, string>> list = CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.RentCollection();
		if (length <= maxValueLength)
		{
			list.Add(new KeyValuePair<string, string>(baseKey, value.ToString()));
		}
		else
		{
			int num = length;
			int num2 = 0;
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			do
			{
				int length2 = Math.Min(num, maxValueLength);
				string key = stringBuilder.Clear().Append(baseKey).Append("[")
					.AppendInt(num2++)
					.Append("]")
					.ToString();
				string value2 = value.SubString(value.Length - num, length2);
				list.Add(new KeyValuePair<string, string>(key, value2));
				num -= maxValueLength;
			}
			while (num > 0);
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}
		for (int i = 0; i < currentSubKeys.Count; i++)
		{
			string text = currentSubKeys[i];
			bool flag = false;
			for (int j = 0; j < list.Count; j++)
			{
				if (list[j].Key.Equals(text, StringComparison.Ordinal))
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				keyValueSetter(text, null);
			}
		}
		currentSubKeys.Clear();
		for (int k = 0; k < list.Count; k++)
		{
			currentSubKeys.Add(list[k].Key);
		}
		for (int l = 0; l < list.Count; l++)
		{
			KeyValuePair<string, string> keyValuePair = list[l];
			keyValueSetter(keyValuePair.Key, keyValuePair.Value);
		}
		CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.ReturnCollection(list);
	}
}
public struct KeyValueUnsplitter
{
	public readonly string baseKey;

	public KeyValueUnsplitter(string baseKey)
	{
		this.baseKey = baseKey;
	}

	public string GetValue(IEnumerable<KeyValuePair<string, string>> keyValues)
	{
		List<KeyValuePair<int, string>> list = CollectionPool<KeyValuePair<int, string>, List<KeyValuePair<int, string>>>.RentCollection();
		foreach (KeyValuePair<string, string> keyValue in keyValues)
		{
			if (keyValue.Key.EndsWith("]", StringComparison.Ordinal))
			{
				int num = keyValue.Key.LastIndexOf("[", StringComparison.Ordinal);
				string value = keyValue.Key.Substring(0, num);
				if (baseKey.Equals(value, StringComparison.Ordinal) && int.TryParse(keyValue.Key.Substring(num + 1), out var result))
				{
					list.Add(new KeyValuePair<int, string>(result, keyValue.Value));
				}
			}
			else if (baseKey.Equals(keyValue.Key, StringComparison.Ordinal))
			{
				return keyValue.Value;
			}
		}
		list.Sort((KeyValuePair<int, string> a, KeyValuePair<int, string> b) => a.Key.CompareTo(b.Key));
		string result2 = string.Concat(list);
		CollectionPool<KeyValuePair<int, string>, List<KeyValuePair<int, string>>>.ReturnCollection(list);
		return result2;
	}
}
public static class LoadHelper
{
	private static Dictionary<string, AsyncOperationHandle<SceneInstance>> currentSceneLoads = new Dictionary<string, AsyncOperationHandle<SceneInstance>>();

	public static AsyncOperationHandle StartLoadSceneAdditiveAsync(string _sceneGuid)
	{
		AsyncOperationHandle<SceneInstance> asyncOperationHandle = Addressables.LoadSceneAsync(_sceneGuid, LoadSceneMode.Additive, activateOnLoad: false);
		if (!currentSceneLoads.ContainsKey(_sceneGuid))
		{
			currentSceneLoads[_sceneGuid] = asyncOperationHandle;
		}
		return asyncOperationHandle;
	}

	public static IEnumerator LoadSceneAdditivelyAsync(string _sceneGuid)
	{
		AsyncOperationHandle<SceneInstance> handler;
		if (!currentSceneLoads.ContainsKey(_sceneGuid))
		{
			handler = Addressables.LoadSceneAsync(_sceneGuid, LoadSceneMode.Additive, activateOnLoad: false);
			yield return handler;
		}
		else
		{
			handler = currentSceneLoads[_sceneGuid];
			currentSceneLoads.Remove(_sceneGuid);
			yield return handler;
		}
		Scene oldScene = SceneManager.GetActiveScene();
		SceneInstance newScene = handler.Result;
		yield return newScene.ActivateAsync();
		SceneManager.SetActiveScene(newScene.Scene);
		SceneManager.UnloadSceneAsync(oldScene);
	}
}
public static class FastDebug
{
	[Conditional("YEET")]
	public static void Log(object message, UnityEngine.Object context)
	{
		UnityEngine.Debug.Log(message, context);
	}

	[Conditional("YEET")]
	public static void Log(object message)
	{
		UnityEngine.Debug.Log(message);
	}

	[Conditional("YEET")]
	public static void LogFormat(string message, params object[] args)
	{
		UnityEngine.Debug.LogFormat(message, args);
	}

	[Conditional("YEET")]
	public static void LogFormat(UnityEngine.Object context, string message, params object[] args)
	{
		UnityEngine.Debug.LogFormat(context, message, args);
	}

	[Conditional("YEET")]
	public static void LogWarning(object message, UnityEngine.Object context)
	{
		UnityEngine.Debug.LogWarning(message, context);
	}

	[Conditional("YEET")]
	public static void LogWarning(object message)
	{
		UnityEngine.Debug.LogWarning(message);
	}

	[Conditional("YEET")]
	public static void LogWarningFormat(string message, params object[] args)
	{
		UnityEngine.Debug.LogWarningFormat(message, args);
	}

	[Conditional("YEET")]
	public static void LogWarningFormat(UnityEngine.Object context, string message, params object[] args)
	{
		UnityEngine.Debug.LogWarningFormat(context, message, args);
	}

	[Conditional("YEET")]
	public static void LogError(object message, UnityEngine.Object context)
	{
		UnityEngine.Debug.LogError(message, context);
	}

	[Conditional("YEET")]
	public static void LogError(object message)
	{
		UnityEngine.Debug.LogError(message);
	}

	[Conditional("YEET")]
	public static void LogErrorFormat(string message, params object[] args)
	{
		UnityEngine.Debug.LogErrorFormat(message, args);
	}

	[Conditional("YEET")]
	public static void LogErrorFormat(UnityEngine.Object context, string message, params object[] args)
	{
		UnityEngine.Debug.LogErrorFormat(context, message, args);
	}

	[Conditional("YEET")]
	public static void LogAssertion(object message, UnityEngine.Object context)
	{
	}

	[Conditional("YEET")]
	public static void LogAssertion(object message)
	{
	}

	[Conditional("YEET")]
	public static void LogAssertionFormat(string message, params object[] args)
	{
	}

	[Conditional("YEET")]
	public static void LogAssertion(UnityEngine.Object context, string message, params object[] args)
	{
	}

	[Conditional("YEET")]
	public static void LogException(Exception e, UnityEngine.Object context)
	{
		UnityEngine.Debug.LogException(e, context);
	}

	[Conditional("YEET")]
	public static void LogException(Exception e)
	{
		UnityEngine.Debug.LogException(e);
	}

	public static void LogChat(object message)
	{
		Chat.AddMessage(message.ToString());
	}
}
public struct MemoizedToString<TInput, TToString> where TInput : IEquatable<TInput> where TToString : struct, IToStringImplementation<TInput>
{
	private TInput lastInput;

	private string lastOutput;

	private TToString implementation;

	private static readonly MemoizedToString<TInput, TToString> defaultValue;

	public string GetString(in TInput input)
	{
		if (!input.Equals(lastInput))
		{
			lastInput = input;
			lastOutput = implementation.DoToString(in lastInput);
		}
		return lastOutput;
	}

	public static MemoizedToString<TInput, TToString> GetNew()
	{
		return defaultValue;
	}

	static MemoizedToString()
	{
		TInput input = default(TInput);
		TToString val = default(TToString);
		defaultValue = new MemoizedToString<TInput, TToString>
		{
			lastInput = input,
			lastOutput = val.DoToString(in input),
			implementation = val
		};
	}
}
public struct NetworkLerpedAngle
{
	private const float interpDuration = 0.05f;

	private const float invInterpDuration = 20f;

	public float authoritativeValue;

	private float interpStartValue;

	private float interpStartTime;

	public float GetCurrentValue(bool hasAuthority)
	{
		if (hasAuthority)
		{
			return authoritativeValue;
		}
		float t = Mathf.Clamp01((Time.time - interpStartTime) * 20f);
		return Mathf.LerpAngle(interpStartValue, authoritativeValue, t);
	}

	public void SetAuthoritativeValue(float newValue, bool hasAuthority)
	{
		interpStartValue = GetCurrentValue(hasAuthority);
		interpStartTime = Time.time;
		authoritativeValue = newValue;
	}
}
public struct NetworkLerpedAngleNew
{
	private struct InterpPoint
	{
		public float time;

		public float value;
	}

	private const float interpDelay = 0.1f;

	private InterpPoint lowInterpPoint;

	private InterpPoint highInterpPoint;

	private InterpPoint newestInterpPoint;

	private float inverseLowHighTimespan;

	public void SetValueImmediate(float value)
	{
		newestInterpPoint.time = Time.time;
		newestInterpPoint.value = value;
		highInterpPoint = newestInterpPoint;
		lowInterpPoint = newestInterpPoint;
		inverseLowHighTimespan = 0f;
	}

	public float GetCurrentValue(bool hasAuthority)
	{
		if (hasAuthority)
		{
			return newestInterpPoint.value;
		}
		float num = Time.time - 0.1f;
		if (num > highInterpPoint.time)
		{
			lowInterpPoint = highInterpPoint;
			highInterpPoint = newestInterpPoint;
			float num2 = highInterpPoint.time - lowInterpPoint.time;
			inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2));
		}
		float t = Mathf.Clamp01((num - lowInterpPoint.time) * inverseLowHighTimespan);
		return Mathf.LerpAngle(lowInterpPoint.value, highInterpPoint.value, t);
	}

	public float GetAuthoritativeValue()
	{
		return newestInterpPoint.value;
	}

	public void PushValue(float value)
	{
		if (newestInterpPoint.value != value)
		{
			newestInterpPoint.time = Time.time;
			newestInterpPoint.value = value;
		}
	}
}
public struct NetworkLerpedFloat
{
	private struct InterpPoint
	{
		public float time;

		public float value;
	}

	private const float interpDelay = 0.1f;

	private InterpPoint lowInterpPoint;

	private InterpPoint highInterpPoint;

	private InterpPoint newestInterpPoint;

	private float inverseLowHighTimespan;

	public void SetValueImmediate(float value)
	{
		newestInterpPoint.time = Time.time;
		newestInterpPoint.value = value;
		highInterpPoint = newestInterpPoint;
		lowInterpPoint = newestInterpPoint;
		inverseLowHighTimespan = 0f;
	}

	public float GetCurrentValue(bool hasAuthority)
	{
		if (hasAuthority)
		{
			return newestInterpPoint.value;
		}
		float num = Time.time - 0.1f;
		if (num > highInterpPoint.time)
		{
			lowInterpPoint = highInterpPoint;
			highInterpPoint = newestInterpPoint;
			float num2 = highInterpPoint.time - lowInterpPoint.time;
			inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2));
		}
		float t = (num - lowInterpPoint.time) * inverseLowHighTimespan;
		return Mathf.Lerp(lowInterpPoint.value, highInterpPoint.value, t);
	}

	public float GetAuthoritativeValue()
	{
		return newestInterpPoint.value;
	}

	public void PushValue(float value)
	{
		if (newestInterpPoint.value != value)
		{
			newestInterpPoint.time = Time.time;
			newestInterpPoint.value = value;
		}
	}
}
public struct NetworkLerpedVector3
{
	private struct InterpPoint
	{
		public float time;

		public UnityEngine.Vector3 value;
	}

	public float interpDelay;

	private InterpPoint lowInterpPoint;

	private InterpPoint highInterpPoint;

	private InterpPoint newestInterpPoint;

	private float inverseLowHighTimespan;

	public void SetValueImmediate(UnityEngine.Vector3 value)
	{
		newestInterpPoint.time = Time.time;
		newestInterpPoint.value = value;
		highInterpPoint = newestInterpPoint;
		lowInterpPoint = newestInterpPoint;
		inverseLowHighTimespan = 0f;
	}

	public UnityEngine.Vector3 GetCurrentValue(bool hasAuthority)
	{
		if (hasAuthority)
		{
			return newestInterpPoint.value;
		}
		float num = Time.time - interpDelay;
		if (num > highInterpPoint.time)
		{
			lowInterpPoint = highInterpPoint;
			highInterpPoint = newestInterpPoint;
			float num2 = highInterpPoint.time - lowInterpPoint.time;
			inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2));
		}
		float t = (num - lowInterpPoint.time) * inverseLowHighTimespan;
		return UnityEngine.Vector3.Lerp(lowInterpPoint.value, highInterpPoint.value, t);
	}

	public UnityEngine.Vector3 GetAuthoritativeValue()
	{
		return newestInterpPoint.value;
	}

	public void PushValue(UnityEngine.Vector3 value)
	{
		if (newestInterpPoint.value != value)
		{
			newestInterpPoint.time = Time.time;
			newestInterpPoint.value = value;
		}
	}
}
public struct NetworkLerpedQuaternion
{
	private struct InterpPoint
	{
		public float time;

		public UnityEngine.Quaternion value;
	}

	private const float interpDelay = 0.1f;

	private InterpPoint lowInterpPoint;

	private InterpPoint highInterpPoint;

	private InterpPoint newestInterpPoint;

	private float inverseLowHighTimespan;

	public void SetValueImmediate(UnityEngine.Quaternion value)
	{
		newestInterpPoint.time = Time.time;
		newestInterpPoint.value = value;
		highInterpPoint = newestInterpPoint;
		lowInterpPoint = newestInterpPoint;
		inverseLowHighTimespan = 0f;
	}

	public UnityEngine.Quaternion GetCurrentValue(bool hasAuthority)
	{
		if (hasAuthority)
		{
			return newestInterpPoint.value;
		}
		float num = Time.time - 0.1f;
		if (num > highInterpPoint.time)
		{
			lowInterpPoint = highInterpPoint;
			highInterpPoint = newestInterpPoint;
			float num2 = highInterpPoint.time - lowInterpPoint.time;
			inverseLowHighTimespan = ((num2 == 0f) ? 0f : (1f / num2));
		}
		float t = (num - lowInterpPoint.time) * inverseLowHighTimespan;
		return UnityEngine.Quaternion.Slerp(lowInterpPoint.value, highInterpPoint.value, t);
	}

	public UnityEngine.Quaternion GetAuthoritativeValue()
	{
		return newestInterpPoint.value;
	}

	public void PushValue(UnityEngine.Quaternion value)
	{
		if (newestInterpPoint.value != value)
		{
			newestInterpPoint.time = Time.time;
			newestInterpPoint.value = value;
		}
	}
}
public class NetworkManagerConfiguration : MonoBehaviour
{
	public new bool DontDestroyOnLoad = true;

	public bool RunInBackground = true;

	public LogFilter.FilterLevel LogLevel = LogFilter.FilterLevel.Info;

	public string OfflineScene;

	public string OnlineScene;

	public GameObject PlayerPrefab;

	public bool AutoCreatePlayer = true;

	public PlayerSpawnMethod PlayerSpawnMethod;

	public List<GameObject> SpawnPrefabs = new List<GameObject>();

	public bool CustomConfig;

	public int MaxConnections = 4;

	public List<QosType> QosChannels = new List<QosType>();
}
[RequireComponent(typeof(Light))]
public class EnableCustomRenderTextureOnLight : MonoBehaviour
{
	private Light targetLight;

	private bool targetLightHasCustomRenderTexture;

	private CustomRenderTexture targetLightCookie;

	private void Awake()
	{
		targetLight = GetComponent<Light>();
		InitRenderTexture();
	}

	private void Start()
	{
		SetUpdateMode(CustomRenderTextureUpdateMode.Realtime);
	}

	private void InitRenderTexture()
	{
		if (!(targetLight == null) && !(targetLight.cookie == null) && targetLight.cookie is CustomRenderTexture)
		{
			targetLightHasCustomRenderTexture = true;
			targetLightCookie = targetLight.cookie as CustomRenderTexture;
		}
	}

	private void SetUpdateMode(CustomRenderTextureUpdateMode mode)
	{
		if (targetLightHasCustomRenderTexture)
		{
			targetLightCookie.updateMode = mode;
		}
	}

	private void OnEnable()
	{
		SetUpdateMode(CustomRenderTextureUpdateMode.Realtime);
	}

	private void OnDisable()
	{
		SetUpdateMode(CustomRenderTextureUpdateMode.OnDemand);
	}

	private void OnDestroy()
	{
		SetUpdateMode(CustomRenderTextureUpdateMode.OnDemand);
	}
}
public static class GlobalPrefabFunctions
{
	private static bool doSave = true;

	private static Transform FindRecursive(Transform t, string name)
	{
		if (t.name == name)
		{
			return t;
		}
		for (int i = 0; i < t.childCount; i++)
		{
			Transform child = t.GetChild(i);
			child = FindRecursive(child, name);
			if (child != null)
			{
				return child;
			}
		}
		return null;
	}
}
public class NearestPlayerCheckerSingleton : MonoBehaviour
{
	public bool debugPrintInfo;

	public static NearestPlayerCheckerSingleton instance;
}
public class OnEnableRestartChildParticleSystems : MonoBehaviour
{
	[SerializeField]
	private List<ParticleSystem> particleSystemList = new List<ParticleSystem>();

	private void OnEnable()
	{
		if (particleSystemList == null || particleSystemList.Count <= 0)
		{
			return;
		}
		foreach (ParticleSystem particleSystem in particleSystemList)
		{
			if (!particleSystem.isPlaying)
			{
				particleSystem.Play();
			}
		}
	}

	private void OnDisable()
	{
		if (particleSystemList == null || particleSystemList.Count <= 0)
		{
			return;
		}
		foreach (ParticleSystem particleSystem in particleSystemList)
		{
			particleSystem.Stop();
			particleSystem.Clear();
		}
	}
}
public class OrbEffectSingleton : MonoBehaviour
{
	public static OrbEffectSingleton instance;

	public static OrbEffect[] orbEffectArray;

	public static int numPnts;

	private void Awake()
	{
		if (instance != null)
		{
			UnityEngine.Object.DestroyImmediate(this);
			return;
		}
		instance = this;
		orbEffectArray = new OrbEffect[50];
	}

	public static void RegisterInstance(OrbEffect newOrbEffect)
	{
		if (orbEffectArray == null || orbEffectArray.Length == numPnts)
		{
			OrbEffect[] array = new OrbEffect[(int)((float)(numPnts + 1) * 1.5f)];
			orbEffectArray.CopyTo(array, 0);
			orbEffectArray = array;
		}
		newOrbEffect.singletonArrayIndex = numPnts;
		orbEffectArray[numPnts] = newOrbEffect;
		numPnts++;
	}

	public static void UnregisterInstance(OrbEffect orbToDisable)
	{
		int singletonArrayIndex = orbToDisable.singletonArrayIndex;
		if (singletonArrayIndex != numPnts - 1)
		{
			orbEffectArray[singletonArrayIndex] = orbEffectArray[numPnts - 1];
			orbEffectArray[singletonArrayIndex].singletonArrayIndex = singletonArrayIndex;
		}
		orbToDisable.singletonArrayIndex = -1;
		numPnts--;
	}

	public void Update()
	{
		for (int i = 0; i < numPnts; i++)
		{
			orbEffectArray[i].UpdateOrb(Time.deltaTime);
		}
	}
}
public class SceneReduction : MonoBehaviour
{
	public enum ReductionSeverity
	{
		LOW,
		MEDIUM,
		HIGH
	}

	public static ReductionSeverity TargetReduction;

	public ReductionSeverity reductionSeverity;
}
public class Particle_SetMinSize : MonoBehaviour
{
	public float minimumPixelCoverage = 2f;

	public float defaultMinimumParticleSize;

	[SerializeField]
	private bool _isEnabled = true;

	private void Start()
	{
		UpdateMinSize();
	}

	public void SetEnabled(bool isEnabled)
	{
		_isEnabled = isEnabled;
		UpdateMinSize();
	}

	private void UpdateMinSize()
	{
		GetComponent<ParticleSystemRenderer>().minParticleSize = (_isEnabled ? (minimumPixelCoverage / (float)Screen.width) : defaultMinimumParticleSize);
	}
}
public class EOSTogglePopup : MonoBehaviour
{
	public string titleText = "EOS_TOGGLE_POPUP_TITLE";

	public string messageText = "EOS_TOGGLE_POPUP_MESSAGE";

	public string closeNowButtonText = "EOS_TOGGLE_CLOSE_NOW";

	public string closeLaterButtonText = "EOS_TOGGLE_CLOSE_LATER";

	public void emitMessage()
	{
		SimpleDialogBox dialogBox = SimpleDialogBox.Create();
		Action deactiveCrossplayAndRestartFunction = delegate
		{
			if ((bool)dialogBox)
			{
				RoR2.Console.instance.SubmitCmd(null, "quit");
			}
		};
		dialogBox.AddActionButton(delegate
		{
			deactiveCrossplayAndRestartFunction();
		}, closeNowButtonText, true);
		dialogBox.AddCancelButton(closeLaterButtonText);
		dialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
		{
			token = titleText,
			formatParams = Array.Empty<object>()
		};
		dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
		{
			token = messageText,
			formatParams = Array.Empty<object>()
		};
	}
}
public class GamecoreLeaderboards : MonoBehaviour
{
}
public class GamecoreNameDisplay : MonoBehaviour
{
	public HGTextMeshProUGUI Text;

	public GameObject Parent;

	private void Awake()
	{
		Parent.SetActive(value: false);
	}
}
public class GamecoreSwitchUser : MonoBehaviour
{
	public void OnButtonClick()
	{
	}
}
public class PS4Timer
{
}
public class SonyNpRanking
{
}
public class PlatformVoiceChatManager
{
	public static VoiceChatManager Get()
	{
		return null;
	}
}
public static class UDPHelper
{
	public static UDPSender Sender;

	public static UDPReceive Receiver;

	public static UDPTest Test;

	private static UDPSenderUpdate uDPSender;

	static UDPHelper()
	{
		Sender = new UDPSender();
		Receiver = new UDPReceive();
		Test = new UDPTest();
		GameObject gameObject = new GameObject("UDPHelperSender");
		gameObject.AddComponent<UDPSenderUpdate>();
		uDPSender = gameObject.GetComponent<UDPSenderUpdate>();
	}
}
public class UDPSenderUpdate : MonoBehaviour
{
	private void Awake()
	{
		UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
	}

	private void Start()
	{
	}

	private void Update()
	{
	}

	private IEnumerator EndlessSending()
	{
		yield return new WaitForEndOfFrame();
	}
}
public class UDPTest
{
	private byte counter = 1;

	public void AddByte(ref byte[] bytes, ref int numBytes, ref bool shouldAddToQueue, int channelId)
	{
		if (numBytes == 1 && bytes[0] == 0)
		{
			return;
		}
		if (bytes.Length <= numBytes)
		{
			byte[] array = new byte[numBytes + 1];
			for (int i = 0; i < bytes.Length; i++)
			{
				array[i] = bytes[i];
			}
			bytes = array;
		}
		shouldAddToQueue = TryAdd(ref bytes, ref numBytes, channelId);
	}

	private bool TryAdd(ref byte[] data, ref int numbytes, int channelId)
	{
		if (true)
		{
			data[numbytes] = GetCounter();
		}
		else
		{
			data[numbytes] = 0;
		}
		numbytes++;
		return true;
	}

	private byte GetCounter()
	{
		return 7;
	}
}
public class StadiaGameEventManager
{
}
public class VoiceChatManagerStadia : MonoBehaviour
{
}
public class PinnedKey
{
}
[Serializable]
internal class ApplicationDataStruct
{
	public uint quickPlayCutoffTime;

	public string hostName = "";

	public int Serialize(byte[] destinationBuf)
	{
		int offset = 0;
		EncodeUint(quickPlayCutoffTime, ref offset, ref destinationBuf);
		EncodeString(hostName, ref offset, ref destinationBuf);
		return offset;
	}

	private void EncodeUint(uint u, ref int offset, ref byte[] destinationBuf)
	{
		BitConverter.GetBytes(u).CopyTo(destinationBuf, offset);
		offset += 4;
	}

	private void EncodeString(string s, ref int offset, ref byte[] destinationBuf)
	{
		byte[] bytes = Encoding.ASCII.GetBytes(s);
		byte[] bytes2 = BitConverter.GetBytes(bytes.Length);
		bytes2.CopyTo(destinationBuf, offset);
		offset += bytes2.Length;
		bytes.CopyTo(destinationBuf, offset);
		offset += bytes.Length;
	}

	public void Deserialize(byte[] buffer, uint dataSize)
	{
		int offset = 0;
		quickPlayCutoffTime = DecodeUint(ref offset, buffer);
		hostName = DecodeString(ref offset, buffer);
	}

	private uint DecodeUint(ref int offset, byte[] buffer)
	{
		uint result = BitConverter.ToUInt32(buffer, offset);
		offset += 4;
		return result;
	}

	private string DecodeString(ref int offset, byte[] buffer)
	{
		string result = null;
		int num = BitConverter.ToInt32(buffer, offset);
		offset += 4;
		if (num > 0)
		{
			result = Encoding.ASCII.GetString(buffer, offset, num);
			offset += num;
		}
		return result;
	}
}
public class PiaMatchmaker : MonoBehaviour
{
}
public class PiaNetworkTransport : INetworkTransport
{
	public bool IsStarted => NetworkTransport.IsStarted;

	public int AddHost(HostTopology topology, int port, string ip)
	{
		UnityEngine.Debug.LogFormat($"PiaNetworkTransport::AddHost: topology: {0}, port: {1}, ip: {2}", topology.ToString(), port, ip);
		return NetworkTransport.AddHost(topology, 7777, "localhost");
	}

	public int AddHostWithSimulator(HostTopology topology, int minTimeout, int maxTimeout, int port)
	{
		return NetworkTransport.AddHostWithSimulator(topology, minTimeout, maxTimeout, port);
	}

	public int AddWebsocketHost(HostTopology topology, int port, string ip)
	{
		return NetworkTransport.AddWebsocketHost(topology, port, ip);
	}

	public int Connect(int hostId, string address, int port, int specialConnectionId, out byte error)
	{
		return NetworkTransport.Connect(hostId, address, port, specialConnectionId, out error);
	}

	public void ConnectAsNetworkHost(int hostId, string address, int port, NetworkID network, SourceID source, NodeID node, out byte error)
	{
		NetworkTransport.ConnectAsNetworkHost(hostId, address, port, network, source, node, out error);
	}

	public int ConnectEndPoint(int hostId, EndPoint endPoint, int specialConnectionId, out byte error)
	{
		return NetworkTransport.ConnectEndPoint(hostId, endPoint, specialConnectionId, out error);
	}

	public int ConnectToNetworkPeer(int hostId, string address, int port, int specialConnectionId, int relaySlotId, NetworkID network, SourceID source, NodeID node, out byte error)
	{
		return NetworkTransport.ConnectToNetworkPeer(hostId, address, port, specialConnectionId, relaySlotId, network, source, node, out error);
	}

	public int ConnectWithSimulator(int hostId, string address, int port, int specialConnectionId, out byte error, ConnectionSimulatorConfig conf)
	{
		return NetworkTransport.ConnectWithSimulator(hostId, address, port, specialConnectionId, out error, conf);
	}

	public bool Disconnect(int hostId, int connectionId, out byte error)
	{
		return NetworkTransport.Disconnect(hostId, connectionId, out error);
	}

	public bool DoesEndPointUsePlatformProtocols(EndPoint endPoint)
	{
		return true;
	}

	public void GetBroadcastConnectionInfo(int hostId, out string address, out int port, out byte error)
	{
		NetworkTransport.GetBroadcastConnectionInfo(hostId, out address, out port, out error);
	}

	public void GetBroadcastConnectionMessage(int hostId, byte[] buffer, int bufferSize, out int receivedSize, out byte error)
	{
		NetworkTransport.GetBroadcastConnectionMessage(hostId, buffer, bufferSize, out receivedSize, out error);
	}

	public void GetConnectionInfo(int hostId, int connectionId, out string address, out int port, out NetworkID network, out NodeID dstNode, out byte error)
	{
		NetworkTransport.GetConnectionInfo(hostId, connectionId, out address, out port, out network, out dstNode, out error);
	}

	public int GetCurrentRTT(int hostId, int connectionId, out byte error)
	{
		return NetworkTransport.GetCurrentRTT(hostId, connectionId, out error);
	}

	public void Init()
	{
		NetworkTransport.Init();
	}

	public void Init(GlobalConfig config)
	{
		NetworkTransport.Init(config);
	}

	public NetworkEventType Receive(out int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error)
	{
		return NetworkTransport.Receive(out hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
	}

	public NetworkEventType ReceiveFromHost(int hostId, out int connectionId, out int channelId, byte[] buffer, int bufferSize, out int receivedSize, out byte error)
	{
		return NetworkTransport.ReceiveFromHost(hostId, out connectionId, out channelId, buffer, bufferSize, out receivedSize, out error);
	}

	public NetworkEventType ReceiveRelayEventFromHost(int hostId, out byte error)
	{
		return NetworkTransport.ReceiveRelayEventFromHost(hostId, out error);
	}

	public bool RemoveHost(int hostId)
	{
		return NetworkTransport.RemoveHost(hostId);
	}

	public bool Send(int hostId, int connectionId, int channelId, byte[] buffer, int size, out byte error)
	{
		return NetworkTransport.Send(hostId, connectionId, channelId, buffer, size, out error);
	}

	public void SetBroadcastCredentials(int hostId, int key, int version, int subversion, out byte error)
	{
		NetworkTransport.SetBroadcastCredentials(hostId, key, version, subversion, out error);
	}

	public void SetPacketStat(int direction, int packetStatId, int numMsgs, int numBytes)
	{
		NetworkTransport.SetPacketStat(direction, packetStatId, numMsgs, numBytes);
	}

	public void Shutdown()
	{
		NetworkTransport.Shutdown();
	}

	public bool StartBroadcastDiscovery(int hostId, int broadcastPort, int key, int version, int subversion, byte[] buffer, int size, int timeout, out byte error)
	{
		return NetworkTransport.StartBroadcastDiscovery(hostId, broadcastPort, key, version, subversion, buffer, size, timeout, out error);
	}

	public void StopBroadcastDiscovery()
	{
		NetworkTransport.StopBroadcastDiscovery();
	}
}
public class RewiredControllerSupport : MonoBehaviour
{
}
public static class ProcessorAffinity
{
}
public static class RendererSetMaterialsExtension
{
	private static Material[][] sharedMaterialArrays;

	private static void InitSharedMaterialsArrays(int maxMaterials)
	{
		sharedMaterialArrays = new Material[maxMaterials + 1][];
		if (maxMaterials > 0)
		{
			sharedMaterialArrays[0] = Array.Empty<Material>();
			for (int i = 1; i < sharedMaterialArrays.Length; i++)
			{
				sharedMaterialArrays[i] = new Material[i];
			}
		}
	}

	static RendererSetMaterialsExtension()
	{
		InitSharedMaterialsArrays(16);
	}

	public static void SetSharedMaterials(this Renderer renderer, Material[] sharedMaterials, int count)
	{
		if (sharedMaterialArrays.Length < count)
		{
			InitSharedMaterialsArrays(count);
		}
		Material[] array = sharedMaterialArrays[count];
		Array.Copy(sharedMaterials, array, count);
		renderer.sharedMaterials = array;
		Array.Clear(array, 0, count);
	}

	public static void SetSharedMaterials(this Renderer renderer, List<Material> sharedMaterials)
	{
		int count = sharedMaterials.Count;
		if (sharedMaterialArrays.Length < count)
		{
			InitSharedMaterialsArrays(count);
		}
		Material[] array = sharedMaterialArrays[count];
		sharedMaterials.CopyTo(array, 0);
		renderer.sharedMaterials = array;
		Array.Clear(array, 0, count);
	}

	public static void SetMaterials(this Renderer renderer, Material[] materials, int count)
	{
		if (sharedMaterialArrays.Length < count)
		{
			InitSharedMaterialsArrays(count);
		}
		Material[] array = sharedMaterialArrays[count];
		Array.Copy(materials, array, count);
		renderer.materials = array;
		Array.Clear(array, 0, count);
	}

	public static void SetMaterials(this Renderer renderer, List<Material> materials)
	{
		int count = materials.Count;
		if (sharedMaterialArrays.Length < count)
		{
			InitSharedMaterialsArrays(count);
		}
		Material[] array = sharedMaterialArrays[count];
		materials.CopyTo(array, 0);
		renderer.materials = array;
		Array.Clear(array, 0, count);
	}
}
public class RendererVisiblity : MonoBehaviour
{
	public enum DistanceClass
	{
		Near,
		Far,
		VeryFar
	}

	public CharacterModel parentModel;

	public DistanceClass approxDistance;

	public bool isVisible;

	[HideInInspector]
	public Animator animatorToUpdateOnceWhenVisible;

	private float visualUpdateTimer;

	public bool shouldUpdateVisuals = true;

	public void CalcDistanceClass(float distanceSq)
	{
		if (distanceSq < 2500f)
		{
			approxDistance = DistanceClass.Near;
		}
		else if (distanceSq < 10000f)
		{
			approxDistance = DistanceClass.Far;
		}
		else
		{
			approxDistance = DistanceClass.VeryFar;
		}
		if (!isVisible)
		{
			visualUpdateTimer -= Time.deltaTime;
			if (visualUpdateTimer < 0f)
			{
				visualUpdateTimer = 0.2f;
				shouldUpdateVisuals = true;
			}
			else
			{
				shouldUpdateVisuals = false;
			}
			return;
		}
		switch (approxDistance)
		{
		case DistanceClass.Near:
			shouldUpdateVisuals = true;
			break;
		case DistanceClass.Far:
			visualUpdateTimer -= Time.deltaTime;
			if (visualUpdateTimer < 0f)
			{
				visualUpdateTimer = 1f / 15f;
				shouldUpdateVisuals = true;
			}
			else
			{
				shouldUpdateVisuals = false;
			}
			break;
		case DistanceClass.VeryFar:
			visualUpdateTimer -= Time.deltaTime;
			if (visualUpdateTimer < 0f)
			{
				visualUpdateTimer = 2f / 15f;
				shouldUpdateVisuals = true;
			}
			else
			{
				shouldUpdateVisuals = false;
			}
			break;
		}
	}

	private void OnBecameVisible()
	{
		parentModel.SetVisible(visible: true);
		isVisible = true;
		if ((bool)animatorToUpdateOnceWhenVisible)
		{
			animatorToUpdateOnceWhenVisible.Update(0f);
			animatorToUpdateOnceWhenVisible = null;
		}
	}

	private void OnBecameInvisible()
	{
		parentModel.SetVisible(visible: false);
		isVisible = false;
	}
}
[Serializable]
public struct RenderSettingsState
{
	public float haloStrength;

	public int defaultReflectionResolution;

	public DefaultReflectionMode defaultReflectionMode;

	public int reflectionBounces;

	public float reflectionIntensity;

	public Texture customReflection;

	public SphericalHarmonicsL2 ambientProbe;

	public Light sun;

	public Material skybox;

	public UnityEngine.Color subtractiveShadowColor;

	public float flareStrength;

	[ColorUsage(false, true)]
	public UnityEngine.Color ambientLight;

	[ColorUsage(false, true)]
	public UnityEngine.Color ambientGroundColor;

	[ColorUsage(false, true)]
	public UnityEngine.Color ambientEquatorColor;

	[ColorUsage(false, true)]
	public UnityEngine.Color ambientSkyColor;

	public AmbientMode ambientMode;

	public float fogDensity;

	[ColorUsage(true, false)]
	public UnityEngine.Color fogColor;

	public FogMode fogMode;

	public float fogEndDistance;

	public float fogStartDistance;

	public bool fog;

	public float ambientIntensity;

	public float flareFadeSpeed;

	public static RenderSettingsState FromCurrent()
	{
		RenderSettingsState result = default(RenderSettingsState);
		result.haloStrength = RenderSettings.haloStrength;
		result.defaultReflectionResolution = RenderSettings.defaultReflectionResolution;
		result.defaultReflectionMode = RenderSettings.defaultReflectionMode;
		result.reflectionBounces = RenderSettings.reflectionBounces;
		result.reflectionIntensity = RenderSettings.reflectionIntensity;
		result.customReflection = RenderSettings.customReflection;
		result.ambientProbe = RenderSettings.ambientProbe;
		result.sun = RenderSettings.sun;
		result.skybox = RenderSettings.skybox;
		result.subtractiveShadowColor = RenderSettings.subtractiveShadowColor;
		result.flareStrength = RenderSettings.flareStrength;
		result.ambientLight = RenderSettings.ambientLight;
		result.ambientGroundColor = RenderSettings.ambientGroundColor;
		result.ambientEquatorColor = RenderSettings.ambientEquatorColor;
		result.ambientSkyColor = RenderSettings.ambientSkyColor;
		result.ambientMode = RenderSettings.ambientMode;
		result.fogDensity = RenderSettings.fogDensity;
		result.fogColor = RenderSettings.fogColor;
		result.fogMode = RenderSettings.fogMode;
		result.fogEndDistance = RenderSettings.fogEndDistance;
		result.fogStartDistance = RenderSettings.fogStartDistance;
		result.fog = RenderSettings.fog;
		result.ambientIntensity = RenderSettings.ambientIntensity;
		result.flareFadeSpeed = RenderSettings.flareFadeSpeed;
		return result;
	}

	public void Apply()
	{
		RenderSettings.haloStrength = haloStrength;
		RenderSettings.defaultReflectionResolution = defaultReflectionResolution;
		RenderSettings.defaultReflectionMode = defaultReflectionMode;
		RenderSettings.reflectionBounces = reflectionBounces;
		RenderSettings.reflectionIntensity = reflectionIntensity;
		RenderSettings.customReflection = customReflection;
		RenderSettings.ambientProbe = ambientProbe;
		RenderSettings.sun = sun;
		RenderSettings.skybox = skybox;
		RenderSettings.subtractiveShadowColor = subtractiveShadowColor;
		RenderSettings.flareStrength = flareStrength;
		RenderSettings.ambientLight = ambientLight;
		RenderSettings.ambientGroundColor = ambientGroundColor;
		RenderSettings.ambientEquatorColor = ambientEquatorColor;
		RenderSettings.ambientSkyColor = ambientSkyColor;
		RenderSettings.ambientMode = ambientMode;
		RenderSettings.fogDensity = fogDensity;
		RenderSettings.fogColor = fogColor;
		RenderSettings.fogMode = fogMode;
		RenderSettings.fogEndDistance = fogEndDistance;
		RenderSettings.fogStartDistance = fogStartDistance;
		RenderSettings.fog = fog;
		RenderSettings.ambientIntensity = ambientIntensity;
		RenderSettings.flareFadeSpeed = flareFadeSpeed;
	}
}
public struct ResourceAvailability
{
	public bool available { get; private set; }

	private event Action onAvailable;

	public void MakeAvailable()
	{
		if (!available)
		{
			available = true;
			this.onAvailable?.Invoke();
			this.onAvailable = null;
		}
	}

	public void CallWhenAvailable([NotNull] Action callback)
	{
		if (available)
		{
			callback();
		}
		else
		{
			onAvailable += callback;
		}
	}
}
[Serializable]
public class SceneField
{
	[SerializeField]
	private UnityEngine.Object sceneAsset;

	[SerializeField]
	private string sceneName = "";

	public string SceneName => sceneName;

	public SceneField(string sceneName)
	{
		this.sceneName = sceneName;
	}

	public static implicit operator string(SceneField sceneField)
	{
		return sceneField.sceneName;
	}

	public static implicit operator bool(SceneField sceneField)
	{
		return !string.IsNullOrEmpty(sceneField.sceneName);
	}
}
[Serializable]
public class SerializableBitArray
{
	[SerializeField]
	protected readonly byte[] bytes;

	[SerializeField]
	public readonly int length;

	private const int bitMask = 7;

	public int byteCount => bytes.Length;

	public bool this[int index]
	{
		get
		{
			int num = index >> 3;
			int num2 = index & 7;
			return (bytes[num] & (1 << num2)) != 0;
		}
		set
		{
			int num = index >> 3;
			int num2 = index & 7;
			int num3 = bytes[num];
			bytes[num] = (byte)(value ? (num3 | (1 << num2)) : (num3 & ~(1 << num2)));
		}
	}

	public SerializableBitArray(int length)
	{
		bytes = new byte[length + 7 >> 3];
		this.length = length;
	}

	public SerializableBitArray(SerializableBitArray src)
	{
		if (src.bytes != null)
		{
			bytes = new byte[src.bytes.Length];
			src.bytes.CopyTo(bytes, 0);
		}
		length = src.length;
	}

	public byte[] GetBytes()
	{
		byte[] array = new byte[bytes.Length];
		GetBytes(array);
		return array;
	}

	public void GetBytes([NotNull] byte[] dest)
	{
		Buffer.BlockCopy(bytes, 0, dest, 0, bytes.Length);
	}
}
public class SetAkGameObjToStaticAfterDelay : MonoBehaviour
{
	[Tooltip("Delay until setting this AkGameObj script as 'static' (not updating")]
	[SerializeField]
	private float timeUntilSetToStatic = -1f;

	public static float defaultValueForDelayUntilSetToStatic = 10f;

	private void Awake()
	{
		if (timeUntilSetToStatic == -1f)
		{
			timeUntilSetToStatic = defaultValueForDelayUntilSetToStatic;
		}
		else
		{
			timeUntilSetToStatic = Mathf.Abs(timeUntilSetToStatic);
		}
		StartCoroutine(SetAkGameObjToStatic());
	}

	private IEnumerator SetAkGameObjToStatic()
	{
		yield return new WaitForSeconds(timeUntilSetToStatic);
		AkGameObjUtil.SetAkGameObjectStatic(base.gameObject, this);
		UnityEngine.Object.Destroy(this);
	}
}
public class ShowThumbnailAttribute : PropertyAttribute
{
}
public static class SingletonHelper
{
	public static void Assign<T>(ref T field, T instance) where T : UnityEngine.Object
	{
		if (!field)
		{
			field = instance;
			return;
		}
		UnityEngine.Debug.LogErrorFormat(instance, "Duplicate instance of singleton class {0}. Only one should exist at a time.", typeof(T).Name);
	}

	public static void Unassign<T>(ref T field, T instance) where T : UnityEngine.Object
	{
		if (field == instance)
		{
			field = null;
		}
	}

	public static T Assign<T>(T existingInstance, T instance) where T : UnityEngine.Object
	{
		if (!existingInstance)
		{
			return instance;
		}
		UnityEngine.Debug.LogErrorFormat(instance, "Duplicate instance of singleton class {0}. Only one should exist at a time.", typeof(T).Name);
		return existingInstance;
	}

	public static T Unassign<T>(T existingInstance, T instance) where T : UnityEngine.Object
	{
		if (instance == existingInstance)
		{
			return null;
		}
		return existingInstance;
	}
}
public static class StringBuilderExtensions
{
	private const uint maxDigitsInUint = 10u;

	private const uint maxDigitsInUlong = 20u;

	private static readonly char[] hexLookup = new char[16]
	{
		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
		'A', 'B', 'C', 'D', 'E', 'F'
	};

	public static StringBuilder AppendInt(this StringBuilder stringBuilder, int value, uint minDigits = 1u, uint maxDigits = uint.MaxValue)
	{
		return AppendSignedInternal(stringBuilder, value, 10u, minDigits, maxDigits);
	}

	public static StringBuilder AppendUint(this StringBuilder stringBuilder, uint value, uint minDigits = 1u, uint maxDigits = uint.MaxValue)
	{
		return AppendUnsignedInternal(stringBuilder, value, 10u, minDigits, maxDigits);
	}

	public static StringBuilder AppendLong(this StringBuilder stringBuilder, long value, uint minDigits = 1u, uint maxDigits = uint.MaxValue)
	{
		return AppendSignedInternal(stringBuilder, value, 20u, minDigits, maxDigits);
	}

	public static StringBuilder AppendUlong(this StringBuilder stringBuilder, ulong value, uint minDigits = 1u, uint maxDigits = uint.MaxValue)
	{
		return AppendUnsignedInternal(stringBuilder, value, 20u, minDigits, maxDigits);
	}

	private static StringBuilder AppendUnsignedInternal(StringBuilder stringBuilder, ulong value, uint maxDigitsForType, uint minDigits = 1u, uint maxDigits = uint.MaxValue)
	{
		if (maxDigits < minDigits)
		{
			throw new ArgumentException("minDigits cannot be greater than maxDigits.");
		}
		uint num = 0u;
		uint num2 = ((maxDigitsForType < maxDigits) ? maxDigitsForType : maxDigits);
		ulong num3 = 1uL;
		while (num3 <= value && num < num2)
		{
			num3 *= 10;
			num++;
		}
		uint num4 = ((minDigits < num) ? num : minDigits);
		if (num4 != 0)
		{
			int length = stringBuilder.Length;
			stringBuilder.Append('0', (int)num4);
			ulong num5 = 0uL;
			ulong num6 = (uint)(length + (int)num4 - 1);
			ulong num7 = value;
			while (num5 < num)
			{
				ulong num8 = num7 / 10;
				byte b = (byte)(num7 - num8 * 10);
				char value2 = (char)(48 + b);
				stringBuilder[(int)num6] = value2;
				num7 = num8;
				num5++;
				num6--;
			}
		}
		return stringBuilder;
	}

	private static StringBuilder AppendSignedInternal(StringBuilder stringBuilder, long value, uint maxDigitsForType, uint minDigits = 1u, uint maxDigits = uint.MaxValue)
	{
		if (maxDigits < minDigits)
		{
			throw new ArgumentException("minDigits cannot be greater than maxDigits.");
		}
		if (value < 0)
		{
			stringBuilder.Append('-');
			value = -value;
		}
		return AppendUnsignedInternal(stringBuilder, (uint)value, maxDigitsForType, minDigits, maxDigits);
	}

	private static void GetByteHexChars(byte byteValue, out char char1, out char char2)
	{
		char1 = hexLookup[(byteValue >> 4) & 0xF];
		char2 = hexLookup[byteValue & 0xF];
	}

	public static StringBuilder AppendByteHexValue(this StringBuilder stringBuilder, byte value)
	{
		GetByteHexChars(value, out var @char, out var char2);
		return stringBuilder.Append(@char).Append(char2);
	}

	public static StringBuilder AppendColor32RGBHexValues(this StringBuilder stringBuilder, Color32 color)
	{
		int num = stringBuilder.Length + 6;
		if (stringBuilder.Capacity < num)
		{
			stringBuilder.Capacity = num;
		}
		GetByteHexChars(color.r, out var @char, out var char2);
		GetByteHexChars(color.g, out var char3, out var char4);
		GetByteHexChars(color.b, out var char5, out var char6);
		return stringBuilder.Append(@char).Append(char2).Append(char3)
			.Append(char4)
			.Append(char5)
			.Append(char6);
	}

	public static StringBuilder JoinEnumerator<TElement, TEnumerator>(this StringBuilder stringBuilder, [NotNull] string separator, TEnumerator enumerator) where TEnumerator : IEnumerator<TElement>
	{
		if (enumerator.MoveNext())
		{
			stringBuilder.Append(enumerator.Current);
			while (enumerator.MoveNext())
			{
				stringBuilder.Append(separator);
				stringBuilder.Append(enumerator.Current);
			}
		}
		return stringBuilder;
	}

	public static string Take(this StringBuilder stringBuilder)
	{
		string result = stringBuilder.ToString();
		stringBuilder.Clear();
		return result;
	}
}
[Obsolete("Use HG.StringBuilderPool instead.", false)]
public static class StringBuilderPool
{
	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	[NotNull]
	[Obsolete("Use HG.StringBuilderPool instead.", false)]
	public static StringBuilder RentStringBuilder()
	{
		return HG.StringBuilderPool.RentStringBuilder();
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	[Obsolete("Use HG.StringBuilderPool instead.", false)]
	[CanBeNull]
	public static StringBuilder ReturnStringBuilder([NotNull] StringBuilder stringBuilder)
	{
		return HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
	}
}
public static class TextSerialization
{
	private static readonly CultureInfo invariantCulture = CultureInfo.InvariantCulture;

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static int ParseIntInvariant(string s)
	{
		return int.Parse(s, NumberStyles.Integer, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static uint ParseUintInvariant(string s)
	{
		return uint.Parse(s, NumberStyles.Integer, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static long ParseLongInvariant(string s)
	{
		return long.Parse(s, NumberStyles.Integer, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static ulong ParseUlongInvariant(string s)
	{
		return ulong.Parse(s, NumberStyles.Integer, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static short ParseShortInvariant(string s)
	{
		return short.Parse(s, NumberStyles.Integer, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static ushort ParseUshortInvariant(string s)
	{
		return ushort.Parse(s, NumberStyles.Integer, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static float ParseFloatInvariant(string s)
	{
		return float.Parse(s, NumberStyles.Float, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static double ParseDoubleInvariant(string s)
	{
		return double.Parse(s, NumberStyles.Float, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static decimal ParseDecimalInvariant(string s)
	{
		return decimal.Parse(s, NumberStyles.Float, invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out int result)
	{
		return int.TryParse(s, NumberStyles.Integer, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out uint result)
	{
		return uint.TryParse(s, NumberStyles.Integer, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out long result)
	{
		return long.TryParse(s, NumberStyles.Integer, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out ulong result)
	{
		return ulong.TryParse(s, NumberStyles.Integer, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out short result)
	{
		return short.TryParse(s, NumberStyles.Integer, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out ushort result)
	{
		return ushort.TryParse(s, NumberStyles.Integer, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out float result)
	{
		return float.TryParse(s, NumberStyles.Float, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out double result)
	{
		return double.TryParse(s, NumberStyles.Float, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static bool TryParseInvariant(string s, out decimal result)
	{
		return decimal.TryParse(s, NumberStyles.Float, invariantCulture, out result);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(int value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(uint value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(long value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(ulong value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(short value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(ushort value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(float value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(double value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringInvariant(decimal value)
	{
		return value.ToString(invariantCulture);
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(int value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(uint value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(long value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(ulong value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(short value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(ushort value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(float value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(double value)
	{
		return value.ToString("N0");
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static string ToStringNumeric(decimal value)
	{
		return value.ToString("N0");
	}
}
public interface IToStringImplementation<T>
{
	string DoToString(in T input);
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct ToStringDefault<T> : IToStringImplementation<T>
{
	public string DoToString(in T input)
	{
		return input.ToString();
	}

	string IToStringImplementation<T>.DoToString(in T input)
	{
		return DoToString(in input);
	}
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct ToStringImplementationInvariant : IToStringImplementation<int>, IToStringImplementation<uint>, IToStringImplementation<long>, IToStringImplementation<ulong>, IToStringImplementation<short>, IToStringImplementation<ushort>, IToStringImplementation<float>, IToStringImplementation<double>
{
	public string DoToString(in int input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in uint input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in long input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in ulong input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in short input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in ushort input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in float input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in double input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	public string DoToString(in decimal input)
	{
		return TextSerialization.ToStringInvariant(input);
	}

	string IToStringImplementation<int>.DoToString(in int input)
	{
		return DoToString(in input);
	}

	string IToStringImplementation<uint>.DoToString(in uint input)
	{
		return DoToString(in input);
	}

	string IToStringImplementation<long>.DoToString(in long input)
	{
		return DoToString(in input);
	}

	string IToStringImplementation<ulong>.DoToString(in ulong input)
	{
		return DoToString(in input);
	}

	string IToStringImplementation<short>.DoToString(in short input)
	{
		return DoToString(in input);
	}

	string IToStringImplementation<ushort>.DoToString(in ushort input)
	{
		return DoToString(in input);
	}

	string IToStringImplementation<float>.DoToString(in float input)
	{
		return DoToString(in input);
	}

	string IToStringImplementation<double>.DoToString(in double input)
	{
		return DoToString(in input);
	}
}
public class ToggleAction : IDisposable
{
	private readonly Action activationAction;

	private readonly Action deactivationAction;

	public bool active { get; private set; }

	public ToggleAction(Action activationAction, Action deactivationAction)
	{
		active = false;
		this.activationAction = activationAction;
		this.deactivationAction = deactivationAction;
	}

	public void SetActive(bool newActive)
	{
		if (active != newActive)
		{
			active = newActive;
			if (active)
			{
				activationAction?.Invoke();
			}
			else
			{
				deactivationAction?.Invoke();
			}
		}
	}

	public void Dispose()
	{
		SetActive(newActive: false);
	}
}
public static class QuickStopwatch
{
	private static string m_name;

	private static Stopwatch m_stopwatch = new Stopwatch();

	private static long m_lapTime = 0L;

	private static int m_lap = 0;

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void Begin(string name)
	{
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void End()
	{
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	public static void Lap(string addText = "")
	{
	}
}
public class Utility_DebugScreamer : MonoBehaviour
{
	[SerializeField]
	private bool screamOnFixedTime;

	[SerializeField]
	private bool screamOnUpdate;

	[SerializeField]
	private UnityEngine.Color _screamColor = new UnityEngine.Color(49f / 51f, 36f / 85f, 0.007843138f);

	private string colorHex;

	private float timeBorn;

	private float fixedTimeBorn;

	private float timeDisabled;

	private float fixedTimeDisabled;

	private string _goName;

	private void Awake()
	{
		timeBorn = Time.time;
		fixedTimeBorn = Time.fixedTime;
		_goName = base.gameObject.name;
		colorHex = "#" + ColorUtility.ToHtmlStringRGB(_screamColor);
	}

	private void FixedUpdate()
	{
		_ = screamOnFixedTime;
	}

	private void Update()
	{
		_ = screamOnUpdate;
	}

	private void OnDisable()
	{
		timeDisabled = Time.time;
		fixedTimeDisabled = Time.fixedTime;
		string text = _goName + " Screamer: <color = " + colorHex + " > DISABLED</color> ";
		if (screamOnFixedTime)
		{
			text = text + " (FixedTime of Disable: " + fixedTimeDisabled + " / " + (fixedTimeDisabled - fixedTimeBorn) + "s alive)";
		}
		if (screamOnUpdate)
		{
			text = text + " (Time of Disable: " + timeDisabled + " / " + (timeDisabled - timeBorn) + "s alive)";
		}
	}

	private void OnDestroy()
	{
		float time = Time.time;
		float fixedTime = Time.fixedTime;
		string text = _goName + " Screamer: <color = " + colorHex + " > DISABLED</color> ";
		if (screamOnFixedTime)
		{
			text = text + " (FixedTime of Destroy: " + fixedTime + " / " + (fixedTime - fixedTimeBorn) + "s alive)";
		}
		if (screamOnUpdate)
		{
			text = text + " (Time of Destroy: " + time + " / " + (time - timeBorn) + "s alive)";
		}
	}
}
public class Utility_Event_MemoryDebugging : MonoBehaviour
{
	[Flags]
	public enum EventFlags
	{
		None = 0,
		FixedUpdate = 2,
		EarlyUpdate = 4,
		Update = 8,
		LateUpdate = 0x10,
		Render = 0x20
	}

	public enum MemoryType
	{
		MonoUsed,
		TotalAllocated,
		FragmentationInfo
	}

	public const int arraySize = 10000;

	private static bool staticRecordData;

	private static EventFlags staticEventsToTrack;

	private static MemoryType staticMemoryTrackType;

	private static int index = 0;

	private static int lastRecordedRenderIndex = -1;

	private static long[] monoUsedEarlyUpdate = new long[10000];

	private static long[] monoUsedUpdate = new long[10000];

	private static long[] monoUsedLateUpdate = new long[10000];

	private static long[] monoUsedFixedUpdate = new long[10000];

	private static long[] monoUsedRender = new long[10000];

	public EventFlags EventsToTrack;

	private EventFlags prevEventsToTrack;

	[Header("Should we record this info")]
	public bool RecordData;

	private bool prevRecordData;

	[Header("What type of memory should we be tracking?")]
	public MemoryType memoryTrackType;

	private MemoryType prevMemoryTrackType;

	[Header("In case you need to print it again")]
	public bool DumpDebugDataToConsole;

	[Header("The most memory gained so far")]
	public long mostMemoryIncrease = long.MinValue;

	public EventFlags mostMemoryIncreaseEvent;

	[Header("For viewing only - editing does nothing")]
	[Space(20f)]
	public string Index;

	public bool IncreasingBetweenUpdate;

	public bool IncreasingBetweenEarlyUpdate;

	public bool IncreasingBetweenLateUpdate;

	public bool IncreasingBetweenFixedUpdate;

	private long previousLong;

	private long temporaryLong;

	private long previousLongInThisArray;

	protected bool amIPreDefaultTime;

	private NativeArray<int> fragmentationInfo;

	private void FixedUpdate()
	{
		if (DumpDebugDataToConsole && index > 0)
		{
			PrintAllDataRecorded();
			DumpDebugDataToConsole = false;
		}
		if (ShouldWeRecordAnything() && AreWeTrackingThisEvent(EventFlags.FixedUpdate | EventFlags.Render))
		{
			RecordCurrentMemory(ref monoUsedFixedUpdate, ref IncreasingBetweenFixedUpdate, EventFlags.FixedUpdate);
		}
	}

	private void EarlyUpdate()
	{
		if (ShouldWeRecordAnything() && AreWeTrackingThisEvent(EventFlags.EarlyUpdate))
		{
			RecordCurrentMemory(ref monoUsedEarlyUpdate, ref IncreasingBetweenEarlyUpdate, EventFlags.EarlyUpdate);
		}
	}

	private void Update()
	{
		if (ShouldWeRecordAnything() && AreWeTrackingThisEvent(EventFlags.Update))
		{
			RecordCurrentMemory(ref monoUsedUpdate, ref IncreasingBetweenUpdate, EventFlags.Update);
		}
	}

	private void LateUpdate()
	{
		if (ShouldWeRecordAnything() && (AreWeTrackingThisEvent(EventFlags.LateUpdate) || AreWeTrackingThisEvent(EventFlags.Render)))
		{
			RecordCurrentMemory(ref monoUsedLateUpdate, ref IncreasingBetweenLateUpdate, EventFlags.LateUpdate);
			TryIncrementIndex();
		}
	}

	private bool AreWeTrackingThisEvent(EventFlags eventFlag)
	{
		if (EventsToTrack != prevEventsToTrack)
		{
			staticEventsToTrack = EventsToTrack;
			prevEventsToTrack = EventsToTrack;
		}
		if (EventsToTrack != staticEventsToTrack)
		{
			EventsToTrack = staticEventsToTrack;
			prevEventsToTrack = staticEventsToTrack;
		}
		return staticEventsToTrack.HasFlag(eventFlag);
	}

	private bool ShouldWeRecordAnything()
	{
		if (prevMemoryTrackType != memoryTrackType)
		{
			prevMemoryTrackType = memoryTrackType;
			staticMemoryTrackType = memoryTrackType;
			if (staticRecordData)
			{
				ResetAllData();
			}
		}
		if (prevRecordData != RecordData)
		{
			prevRecordData = RecordData;
			staticRecordData = RecordData;
			if (!RecordData)
			{
				PrintAllDataRecorded();
			}
			else
			{
				ResetAllData();
			}
		}
		if (staticRecordData != RecordData)
		{
			RecordData = staticRecordData;
			prevRecordData = staticRecordData;
		}
		return staticRecordData;
	}

	private void TryIncrementIndex()
	{
		float num = index / 10000;
		Index = (float)(int)(num * 100f) / 100f + "% Complete";
		if (!amIPreDefaultTime)
		{
			if (index < 9998)
			{
				index++;
			}
			else if (staticRecordData)
			{
				staticRecordData = false;
				PrintAllDataRecorded();
			}
		}
	}

	private long GetMemoryValue()
	{
		return staticMemoryTrackType switch
		{
			MemoryType.TotalAllocated => Profiler.GetTotalAllocatedMemoryLong(), 
			MemoryType.FragmentationInfo => Profiler.GetTotalFragmentationInfo(fragmentationInfo), 
			_ => Profiler.GetMonoUsedSizeLong(), 
		};
	}

	private void RecordCurrentMemory(ref long[] _array, ref bool increasing, EventFlags _event)
	{
		temporaryLong = GetMemoryValue();
		if (staticEventsToTrack.HasFlag(EventFlags.Render))
		{
			if (!amIPreDefaultTime && _event == EventFlags.LateUpdate)
			{
				monoUsedRender[index] = temporaryLong;
			}
			else if (amIPreDefaultTime && _event == EventFlags.FixedUpdate && lastRecordedRenderIndex != index)
			{
				monoUsedRender[index] = temporaryLong - monoUsedRender[index];
				lastRecordedRenderIndex = index;
			}
		}
		if (!amIPreDefaultTime)
		{
			temporaryLong -= _array[index];
			RecordMostMemoryGain(temporaryLong - previousLong, _event);
			previousLong = temporaryLong;
			increasing = temporaryLong > 0;
		}
		_array[index] = temporaryLong;
	}

	private void TryRecordRenderMemoryGain()
	{
		if (amIPreDefaultTime && index >= 1 && index != lastRecordedRenderIndex)
		{
			lastRecordedRenderIndex = index;
			monoUsedRender[index] = monoUsedFixedUpdate[index] - monoUsedLateUpdate[index - 1];
		}
	}

	private void RecordMostMemoryGain(long amount, EventFlags _event)
	{
		if (mostMemoryIncrease < amount)
		{
			mostMemoryIncrease = amount;
			mostMemoryIncreaseEvent = _event;
		}
	}

	private void ResetAllData()
	{
		index = 0;
		monoUsedEarlyUpdate = new long[10000];
		monoUsedUpdate = new long[10000];
		monoUsedLateUpdate = new long[10000];
		monoUsedFixedUpdate = new long[10000];
		monoUsedRender = new long[10000];
	}

	private void PrintAllDataRecorded()
	{
		StringBuilder sb2 = new StringBuilder();
		sb2.Append($"<color=green>Memory Debugging Data results</color> -  Tracked Memory:  {staticMemoryTrackType}");
		sb2.Append($"\r\nMost Memory in a single step: {mostMemoryIncrease} ({mostMemoryIncreaseEvent})");
		long averageMemoryChangePerStep;
		long totalMemoryChange;
		if (staticEventsToTrack.HasFlag(EventFlags.FixedUpdate))
		{
			CalculateDataFromArray(ref sb2, EventFlags.FixedUpdate, ref monoUsedFixedUpdate);
		}
		if (staticEventsToTrack.HasFlag(EventFlags.EarlyUpdate))
		{
			CalculateDataFromArray(ref sb2, EventFlags.EarlyUpdate, ref monoUsedEarlyUpdate);
		}
		if (staticEventsToTrack.HasFlag(EventFlags.Update))
		{
			CalculateDataFromArray(ref sb2, EventFlags.Update, ref monoUsedUpdate);
		}
		if (staticEventsToTrack.HasFlag(EventFlags.LateUpdate))
		{
			CalculateDataFromArray(ref sb2, EventFlags.LateUpdate, ref monoUsedLateUpdate);
		}
		if (staticEventsToTrack.HasFlag(EventFlags.Render))
		{
			CalculateDataFromArray(ref sb2, EventFlags.Render, ref monoUsedRender);
		}
		totalMemoryChange = 0L;
		void CalculateDataFromArray(ref StringBuilder sb, EventFlags _event, ref long[] _array)
		{
			averageMemoryChangePerStep = 0L;
			totalMemoryChange = 0L;
			for (int i = 0; i < index; i++)
			{
				long num = _array[i];
				if (i != 0)
				{
					totalMemoryChange += num;
				}
			}
			averageMemoryChangePerStep = totalMemoryChange / Mathf.Max(index, 1);
			sb.Append($"\r\n\r\n<bold>{_event}</bold>: Avg change per step {FormatLongAsText(averageMemoryChangePerStep)}. | Total Memory changed: {FormatLongAsText(totalMemoryChange)}");
		}
		static string FormatLongAsText(long value)
		{
			if (value > 1000000000)
			{
				return $"<color=red>{(float)value / 1E+09f}GB </color> {value}";
			}
			if (value > 1000000)
			{
				return $"<color=orange>{(float)value / 1000000f}MB </color> {value}";
			}
			return $"{(float)value / 1000f}KB ({value})";
		}
	}
}
public class Utility_Event_MemoryDebugging_PostDefault : Utility_Event_MemoryDebugging
{
}
public class Utility_Event_MemoryDebugging_PreDefault : Utility_Event_MemoryDebugging
{
	private void Awake()
	{
		amIPreDefaultTime = true;
	}
}
public class Utility_ScreamPositionDiff : MonoBehaviour
{
	private UnityEngine.Vector3 _prevPosition;

	private void OnEnable()
	{
		_prevPosition = base.transform.position;
	}

	private void FixedUpdate()
	{
		UnityEngine.Vector3 position = base.transform.position;
		if (!NetworkServer.active && _prevPosition != position)
		{
			_prevPosition = position;
		}
	}
}
[Serializable]
public struct Wave
{
	public float amplitude;

	public float frequency;

	[FormerlySerializedAs("phase")]
	public float cycleOffset;

	public float period
	{
		get
		{
			return 1f / frequency;
		}
		set
		{
			frequency = 1f / value;
		}
	}

	public float Evaluate(float t)
	{
		return Mathf.Sin(MathF.PI * 2f * (frequency * t + cycleOffset)) * amplitude;
	}
}
public class WeightedSelection<T>
{
	[Serializable]
	public struct ChoiceInfo
	{
		public T value;

		public float weight;
	}

	[SerializeField]
	[HideInInspector]
	public ChoiceInfo[] choices;

	[HideInInspector]
	[SerializeField]
	private int _count;

	[SerializeField]
	[HideInInspector]
	private float totalWeight;

	private const int minCapacity = 8;

	public int Count
	{
		get
		{
			return _count;
		}
		private set
		{
			_count = value;
		}
	}

	public int Capacity
	{
		get
		{
			return choices.Length;
		}
		set
		{
			if (value < 8 || value < Count)
			{
				throw new ArgumentOutOfRangeException("value");
			}
			ChoiceInfo[] sourceArray = choices;
			choices = new ChoiceInfo[value];
			Array.Copy(sourceArray, choices, Count);
		}
	}

	public WeightedSelection(int capacity = 8)
	{
		choices = new ChoiceInfo[capacity];
	}

	public void AddChoice(T value, float weight)
	{
		AddChoice(new ChoiceInfo
		{
			value = value,
			weight = weight
		});
	}

	public void AddChoice(ChoiceInfo choice)
	{
		if (Count == Capacity)
		{
			Capacity *= 2;
		}
		choices[Count++] = choice;
		totalWeight += choice.weight;
	}

	public void RemoveChoice(int choiceIndex)
	{
		if (choiceIndex < 0 || Count <= choiceIndex)
		{
			throw new ArgumentOutOfRangeException("choiceIndex");
		}
		int i = choiceIndex;
		for (int num = Count - 1; i < num; i++)
		{
			choices[i] = choices[i + 1];
		}
		choices[--Count] = default(ChoiceInfo);
		RecalculateTotalWeight();
	}

	public void ModifyChoiceWeight(int choiceIndex, float newWeight)
	{
		choices[choiceIndex].weight = newWeight;
		RecalculateTotalWeight();
	}

	public void Clear()
	{
		for (int i = 0; i < Count; i++)
		{
			choices[i] = default(ChoiceInfo);
		}
		Count = 0;
		totalWeight = 0f;
	}

	private void RecalculateTotalWeight()
	{
		totalWeight = 0f;
		for (int i = 0; i < Count; i++)
		{
			totalWeight += choices[i].weight;
		}
	}

	public T Evaluate(float normalizedIndex)
	{
		int num = EvaluateToChoiceIndex(normalizedIndex);
		return choices[num].value;
	}

	public int EvaluateToChoiceIndex(float normalizedIndex)
	{
		return EvaluateToChoiceIndex(normalizedIndex, null);
	}

	public int EvaluateToChoiceIndex(float normalizedIndex, int[] ignoreIndices)
	{
		if (Count == 0)
		{
			throw new InvalidOperationException("Cannot call Evaluate without available choices.");
		}
		float num = totalWeight;
		if (ignoreIndices != null)
		{
			foreach (int num2 in ignoreIndices)
			{
				num -= choices[num2].weight;
			}
		}
		float num3 = normalizedIndex * num;
		float num4 = 0f;
		for (int j = 0; j < Count; j++)
		{
			if (ignoreIndices == null || Array.IndexOf(ignoreIndices, j) == -1)
			{
				num4 += choices[j].weight;
				if (num3 < num4)
				{
					return j;
				}
			}
		}
		return Count - 1;
	}

	public ChoiceInfo GetChoice(int i)
	{
		return choices[i];
	}
}
namespace SteamAPIValidator
{
	internal static class WinCrypt
	{
		public struct BLOB
		{
			public int cbData;

			public IntPtr pbData;
		}

		public struct CRYPT_ALGORITHM_IDENTIFIER
		{
			public string pszObjId;

			private BLOB Parameters;
		}

		public struct CERT_ID
		{
			public int dwIdChoice;

			public BLOB IssuerSerialNumberOrKeyIdOrHashId;
		}

		public struct SIGNER_SUBJECT_INFO
		{
			public uint cbSize;

			public IntPtr pdwIndex;

			public uint dwSubjectChoice;

			public SubjectChoiceUnion Union1;
		}

		[StructLayout(LayoutKind.Explicit)]
		public struct SubjectChoiceUnion
		{
			[FieldOffset(0)]
			public IntPtr pSignerFileInfo;

			[FieldOffset(0)]
			public IntPtr pSignerBlobInfo;
		}

		public struct CERT_NAME_BLOB
		{
			public uint cbData;

			[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
			public byte[] pbData;
		}

		public struct CRYPT_INTEGER_BLOB
		{
			public uint cbData;

			public IntPtr pbData;
		}

		public struct CRYPT_ATTR_BLOB
		{
			public uint cbData;

			[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
			public byte[] pbData;
		}

		public struct CRYPT_ATTRIBUTE
		{
			[MarshalAs(UnmanagedType.LPStr)]
			public string pszObjId;

			public uint cValue;

			[MarshalAs(UnmanagedType.LPStruct)]
			public CRYPT_ATTR_BLOB rgValue;
		}

		public struct CMSG_SIGNER_INFO
		{
			public int dwVersion;

			private CERT_NAME_BLOB Issuer;

			private CRYPT_INTEGER_BLOB SerialNumber;

			private CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;

			private CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;

			private BLOB EncryptedHash;

			private CRYPT_ATTRIBUTE[] AuthAttrs;

			private CRYPT_ATTRIBUTE[] UnauthAttrs;
		}

		public const int CRYPT_ASN_ENCODING = 1;

		public const int CRYPT_NDR_ENCODING = 2;

		public const int X509_ASN_ENCODING = 1;

		public const int X509_NDR_ENCODING = 2;

		public const int PKCS_7_ASN_ENCODING = 65536;

		public const int PKCS_7_NDR_ENCODING = 131072;

		public static UIntPtr PKCS7_SIGNER_INFO = new UIntPtr(500u);

		public static UIntPtr CMS_SIGNER_INFO = new UIntPtr(501u);

		public static string szOID_RSA_signingTime = "1.2.840.113549.1.9.5";

		public static string szOID_RSA_counterSign = "1.2.840.113549.1.9.6";

		public const int CMSG_TYPE_PARAM = 1;

		public const int CMSG_CONTENT_PARAM = 2;

		public const int CMSG_BARE_CONTENT_PARAM = 3;

		public const int CMSG_INNER_CONTENT_TYPE_PARAM = 4;

		public const int CMSG_SIGNER_COUNT_PARAM = 5;

		public const int CMSG_SIGNER_INFO_PARAM = 6;

		public const int CMSG_SIGNER_CERT_INFO_PARAM = 7;

		public const int CMSG_SIGNER_HASH_ALGORITHM_PARAM = 8;

		public const int CMSG_SIGNER_AUTH_ATTR_PARAM = 9;

		public const int CMSG_SIGNER_UNAUTH_ATTR_PARAM = 10;

		public const int CMSG_CERT_COUNT_PARAM = 11;

		public const int CMSG_CERT_PARAM = 12;

		public const int CMSG_CRL_COUNT_PARAM = 13;

		public const int CMSG_CRL_PARAM = 14;

		public const int CMSG_ENVELOPE_ALGORITHM_PARAM = 15;

		public const int CMSG_RECIPIENT_COUNT_PARAM = 17;

		public const int CMSG_RECIPIENT_INDEX_PARAM = 18;

		public const int CMSG_RECIPIENT_INFO_PARAM = 19;

		public const int CMSG_HASH_ALGORITHM_PARAM = 20;

		public const int CMSG_HASH_DATA_PARAM = 21;

		public const int CMSG_COMPUTED_HASH_PARAM = 22;

		public const int CMSG_ENCRYPT_PARAM = 26;

		public const int CMSG_ENCRYPTED_DIGEST = 27;

		public const int CMSG_ENCODED_SIGNER = 28;

		public const int CMSG_ENCODED_MESSAGE = 29;

		public const int CMSG_VERSION_PARAM = 30;

		public const int CMSG_ATTR_CERT_COUNT_PARAM = 31;

		public const int CMSG_ATTR_CERT_PARAM = 32;

		public const int CMSG_CMS_RECIPIENT_COUNT_PARAM = 33;

		public const int CMSG_CMS_RECIPIENT_INDEX_PARAM = 34;

		public const int CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM = 35;

		public const int CMSG_CMS_RECIPIENT_INFO_PARAM = 36;

		public const int CMSG_UNPROTECTED_ATTR_PARAM = 37;

		public const int CMSG_SIGNER_CERT_ID_PARAM = 38;

		public const int CMSG_CMS_SIGNER_INFO_PARAM = 39;

		public const int CERT_QUERY_OBJECT_FILE = 1;

		public const int CERT_QUERY_OBJECT_BLOB = 2;

		public const int CERT_QUERY_CONTENT_CERT = 1;

		public const int CERT_QUERY_CONTENT_CTL = 2;

		public const int CERT_QUERY_CONTENT_CRL = 3;

		public const int CERT_QUERY_CONTENT_SERIALIZED_STORE = 4;

		public const int CERT_QUERY_CONTENT_SERIALIZED_CERT = 5;

		public const int CERT_QUERY_CONTENT_SERIALIZED_CTL = 6;

		public const int CERT_QUERY_CONTENT_SERIALIZED_CRL = 7;

		public const int CERT_QUERY_CONTENT_PKCS7_SIGNED = 8;

		public const int CERT_QUERY_CONTENT_PKCS7_UNSIGNED = 9;

		public const int CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED = 10;

		public const int CERT_QUERY_CONTENT_PKCS10 = 11;

		public const int CERT_QUERY_CONTENT_PFX = 12;

		public const int CERT_QUERY_CONTENT_CERT_PAIR = 13;

		public const int CERT_QUERY_CONTENT_FLAG_CERT = 2;

		public const int CERT_QUERY_CONTENT_FLAG_CTL = 4;

		public const int CERT_QUERY_CONTENT_FLAG_CRL = 8;

		public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE = 16;

		public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT = 32;

		public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL = 64;

		public const int CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL = 128;

		public const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED = 256;

		public const int CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED = 512;

		public const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = 1024;

		public const int CERT_QUERY_CONTENT_FLAG_PKCS10 = 2048;

		public const int CERT_QUERY_CONTENT_FLAG_PFX = 4096;

		public const int CERT_QUERY_CONTENT_FLAG_CERT_PAIR = 8192;

		public const int CERT_QUERY_CONTENT_FLAG_ALL = 16382;

		public const int CERT_QUERY_FORMAT_BINARY = 1;

		public const int CERT_QUERY_FORMAT_BASE64_ENCODED = 2;

		public const int CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3;

		public const int CERT_QUERY_FORMAT_FLAG_BINARY = 2;

		public const int CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = 4;

		public const int CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = 8;

		public const int CERT_QUERY_FORMAT_FLAG_ALL = 14;

		[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool CryptQueryObject(int dwObjectType, IntPtr pvObject, int dwExpectedContentTypeFlags, int dwExpectedFormatTypeFlags, int dwFlags, out int pdwMsgAndCertEncodingType, out int pdwContentType, out int pdwFormatType, ref IntPtr phCertStore, ref IntPtr phMsg, ref IntPtr ppvContext);

		[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool CryptMsgGetParam(IntPtr hCryptMsg, int dwParamType, int dwIndex, IntPtr pvData, ref int pcbData);

		[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool CryptMsgGetParam(IntPtr hCryptMsg, int dwParamType, int dwIndex, [In][Out] byte[] vData, ref int pcbData);

		[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptDecodeObject(uint CertEncodingType, UIntPtr lpszStructType, byte[] pbEncoded, uint cbEncoded, uint flags, [In][Out] byte[] pvStructInfo, ref uint cbStructInfo);
	}
	public static class SteamApiValidator
	{
		private const int MAX_PATH_SIZE = 32767;

		[DllImport("kernel32.dll")]
		private static extern IntPtr LoadLibrary(string dllToLoad);

		[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
		private static extern IntPtr GetModuleHandle(string lpModuleName);

		[DllImport("kernel32.dll", SetLastError = true)]
		private static extern uint GetModuleFileName([In] IntPtr hModule, [Out] StringBuilder lpFilename, [In][MarshalAs(UnmanagedType.U4)] int nSize);

		public static bool IsValidSteamApiDll()
		{
			string text = (Environment.Is64BitProcess ? "steam_api64.dll" : "steam_api.dll");
			IntPtr intPtr = GetModuleHandle(text);
			if (intPtr == IntPtr.Zero)
			{
				intPtr = LoadLibrary(text);
			}
			if (intPtr == IntPtr.Zero)
			{
				return false;
			}
			if (intPtr != IntPtr.Zero)
			{
				StringBuilder stringBuilder = new StringBuilder(32767);
				if (GetModuleFileName(intPtr, stringBuilder, 32767) != 0)
				{
					return CheckIfValveSigned(stringBuilder.ToString());
				}
			}
			return false;
		}

		public static bool IsValidSteamClientDll()
		{
			IntPtr moduleHandle = GetModuleHandle(Environment.Is64BitProcess ? "steamclient64.dll" : "steamclient.dll");
			if (moduleHandle != IntPtr.Zero)
			{
				StringBuilder stringBuilder = new StringBuilder(32767);
				if (GetModuleFileName(moduleHandle, stringBuilder, 32767) != 0)
				{
					return CheckIfValveSigned(stringBuilder.ToString());
				}
			}
			return false;
		}

		private static bool CheckIfValveSigned(string filePath)
		{
			try
			{
				IntPtr phCertStore = IntPtr.Zero;
				IntPtr phMsg = IntPtr.Zero;
				IntPtr ppvContext = IntPtr.Zero;
				if (!WinCrypt.CryptQueryObject(1, Marshal.StringToHGlobalUni(filePath), 16382, 14, 0, out var _, out var pdwContentType, out var _, ref phCertStore, ref phMsg, ref ppvContext))
				{
					return false;
				}
				return pdwContentType == 10;
			}
			catch
			{
				return false;
			}
		}
	}
}
namespace RewiredConsts
{
	public static class Action
	{
		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Move Horizontal")]
		public const int MoveHorizontal = 0;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Move Vertical")]
		public const int MoveVertical = 1;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Horizontal Mouse")]
		public const int AimHorizontalMouse = 2;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Vertical Mouse")]
		public const int AimVerticalMouse = 3;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Horizontal Stick")]
		public const int AimHorizontalStick = 16;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Aim Vertical Stick")]
		public const int AimVerticalStick = 17;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Jump")]
		public const int Jump = 4;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Sprint")]
		public const int Sprint = 18;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Interact")]
		public const int Interact = 5;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Activate Equipment")]
		public const int Equipment = 6;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Primary Skill")]
		public const int PrimarySkill = 7;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Secondary Skill")]
		public const int SecondarySkill = 8;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Utility Skill")]
		public const int UtilitySkill = 9;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Special Skill")]
		public const int SpecialSkill = 10;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Start")]
		public const int Start = 11;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Info")]
		public const int Info = 19;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UIHorizontal")]
		public const int UIHorizontal = 12;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UIVertical")]
		public const int UIVertical = 13;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmit")]
		public const int UISubmit = 14;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UICancel")]
		public const int UICancel = 15;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UI Left Mouse Button")]
		public const int UILMB = 20;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UI Right Mouse Button")]
		public const int UIRMB = 21;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UI Middle Mouse Button")]
		public const int UIMMB = 22;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UICursorX")]
		public const int UICursorX = 23;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UICursorY")]
		public const int UICursorY = 24;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UIScrollWheel")]
		public const int UIScrollWheel = 26;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Pause")]
		public const int Pause = 25;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "Ping")]
		public const int Ping = 28;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UITabLeft")]
		public const int UITabLeft = 29;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UITabRight")]
		public const int UITabRight = 30;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmitAlt")]
		public const int UISubmitAlt = 31;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuLeft")]
		public const int UISubmenuLeft = 32;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuRight")]
		public const int UISubmenuRight = 33;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuUp")]
		public const int UISubmenuUp = 34;

		[ActionIdFieldInfo(categoryName = "Default", friendlyName = "UISubmenuDown")]
		public const int UISubmenuDown = 35;
	}
	public static class Category
	{
		public const int Default = 0;

		public const int UI = 2;
	}
	public static class Layout
	{
		public static class Joystick
		{
			public const int Default = 0;

			public const int Default_JP = 1;
		}

		public static class Keyboard
		{
			public const int Default = 0;
		}

		public static class Mouse
		{
			public const int Default = 0;
		}

		public static class CustomController
		{
			public const int Default = 0;
		}
	}
	public static class Player
	{
		[PlayerIdFieldInfo(friendlyName = "System")]
		public const int System = 9999999;

		[PlayerIdFieldInfo(friendlyName = "PlayerMain")]
		public const int PlayerMain = 0;

		[PlayerIdFieldInfo(friendlyName = "Player1")]
		public const int Player1 = 1;

		[PlayerIdFieldInfo(friendlyName = "Player2")]
		public const int Player2 = 2;

		[PlayerIdFieldInfo(friendlyName = "Player3")]
		public const int Player3 = 3;

		[PlayerIdFieldInfo(friendlyName = "Player4")]
		public const int Player4 = 4;

		[PlayerIdFieldInfo(friendlyName = "Player5")]
		public const int Player5 = 5;
	}
	public static class CustomController
	{
	}
}
namespace UDPHelperSpace
{
	public class UDPData
	{
		public byte packageNumber = 2;

		public byte[] data;

		public int numBytes;

		public int channelId;

		public byte error;

		public UDPData()
		{
		}

		public UDPData(byte packageNumber, byte[] data, int numBytes, int channelId, byte error)
		{
			this.packageNumber = packageNumber;
			this.packageNumber = data[0];
			this.data = data;
			this.numBytes = numBytes;
			this.channelId = channelId;
			this.error = error;
		}
	}
	public class UDPReceive
	{
		public int packageNumber;

		public List<UDPData> data = new List<UDPData>();

		public UDPReceiveWork Work = new UDPReceiveWork();

		public byte[] Receive(byte[] bytes, int length)
		{
			if (bytes == null || bytes.Length < 1 || (bytes.Length == 1 && bytes[0] == 0))
			{
				return bytes;
			}
			byte b = 0;
			byte ñonfirmationByte = 0;
			byte packetLoss = 0;
			byte temp = 0;
			byte[] array = Work.GetData(bytes, out b, out ñonfirmationByte, out packetLoss, out temp, length);
			string.Concat(string.Concat(string.Concat("_packageNumber: " + b + " ", "ñonfirmationByte: ", ñonfirmationByte.ToString(), " "), "packetLoss: ", packetLoss.ToString(), "\n"), "total bytes: ", bytes.Length.ToString(), "\n");
			if (packageNumber == 0)
			{
				packageNumber = b;
				ConfirmPackage(b);
				return array;
			}
			if (length == 4)
			{
				UDPHelper.Sender.RemoveFromQueue(array[2]);
				return null;
			}
			if (packageNumber == b)
			{
				ConfirmPackage(b);
				return null;
			}
			if (b == packageNumber + 1 || (b == 1 && packageNumber == 100))
			{
				packageNumber = b;
				ConfirmPackage(b);
			}
			return array;
		}

		public void ConfirmPackage(byte confirmPackageNumber)
		{
			byte[] arg = new byte[4] { 1, 0, 0, confirmPackageNumber };
			UDPHelper.Sender.SendCall?.Invoke(arg, 4, 0, 0);
		}
	}
	public class UDPReceiveWork
	{
		public byte[] GetData(byte[] bytes, out byte packageNumber, out byte ñonfirmationByte, out byte packetLoss, out byte temp2, int length)
		{
			byte[] array = new byte[bytes.Length];
			Array.Copy(bytes, array, bytes.Length);
			ñonfirmationByte = 0;
			packetLoss = 0;
			temp2 = 0;
			packageNumber = bytes[0];
			return RemoveDataReceive(array);
		}

		private byte[] RemoveDataReceive(byte[] bytes)
		{
			return RemoveBytes(bytes);
		}

		private byte[] RemoveBytes(byte[] bytes, int countRemove = 1)
		{
			return bytes = bytes.Skip(1).ToArray();
		}
	}
	public class UDPSender
	{
		public byte packageNumber = 1;

		public int maxListCount = 90;

		public List<UDPData> data = new List<UDPData>();

		public UDPSenderWork Work = new UDPSenderWork();

		public Action<byte[], int, int, byte> SendCall;

		public void Send(byte[] bytes, int numBytes, int channelId, byte error)
		{
			data.Add(new UDPData(packageNumber, bytes, numBytes, channelId, error));
		}

		public byte[] Send(byte[] bytes, ref int numBytes)
		{
			if (bytes == null || bytes.Length < 1 || (bytes.Length == 1 && bytes[0] == 0))
			{
				return bytes;
			}
			byte[] result = Work.AddDataSend(bytes, packageNumber);
			numBytes++;
			packageNumber++;
			if (packageNumber > 100)
			{
				packageNumber = 1;
			}
			return result;
		}

		public byte[] SendReturne(byte[] bytes, int numBytes, int channelId, byte error)
		{
			if (bytes == null || bytes.Length < 1 || (bytes.Length == 1 && bytes[0] == 0))
			{
				return bytes;
			}
			return new UDPData(packageNumber, bytes, numBytes, channelId, error).data;
		}

		public void SendAction()
		{
			if (data.Count > 0)
			{
				UDPData uDPData = data[data.Count - 1];
				byte[] arg = uDPData.data;
				UDPHelper.Sender.SendCall?.Invoke(arg, uDPData.numBytes, uDPData.channelId, uDPData.error);
			}
		}

		public void RemoveFromQueue(byte _packageNumber)
		{
			data = data.Where((UDPData x) => x.packageNumber != _packageNumber).ToList();
		}
	}
	public class UDPSenderWork
	{
		public byte[] AddDataSend(byte[] bytes, int packageNumber)
		{
			if (bytes == null || bytes.Length < 4)
			{
				return bytes;
			}
			bytes = AddByteToArray(bytes, packageNumber);
			return bytes;
		}

		private byte[] AddByteToArray(byte[] bArray, int newByte)
		{
			return AddByteToArray(bArray, (byte)newByte);
		}

		public byte[] AddByteToArray(byte[] bArray, byte newByte)
		{
			byte[] array = new byte[bArray.Length + 1];
			bArray.CopyTo(array, 1);
			array[0] = newByte;
			return array;
		}
	}
}
namespace Assets.RoR2.Scripts.Platform
{
	[CreateAssetMenu(menuName = "RoR2/ActivityData")]
	public class ActivityData : ScriptableObject
	{
		[SerializeField]
		private List<BaseActivity> activities;

		public BaseActivity LookupActivityByID(string activityID)
		{
			foreach (BaseActivity activity in activities)
			{
				if (activity.ActivityID == activityID)
				{
					return activity;
				}
			}
			return null;
		}

		public List<BaseActivity> CompareActivityCriteria(BaseActivitySelector activitySelector)
		{
			List<BaseActivity> list = new List<BaseActivity>();
			foreach (BaseActivity activity in activities)
			{
				if (activitySelector.IsCompatibleWith(activity))
				{
					list.Add(activity);
				}
			}
			return list;
		}
	}
	public class BaseActivitySelector
	{
		public BaseActivity.ActivityGameType activityGameType = BaseActivity.ActivityGameType.Any;

		public BaseActivity.ActivityGameMode activityGameMode = BaseActivity.ActivityGameMode.Any;

		public BaseActivity.ActivitySurvivor activitySurvivor = BaseActivity.ActivitySurvivor.Any;

		public string activityAchievementID = "";

		public bool IsCompatibleWith(BaseActivity activity)
		{
			if ((activity.GameType == BaseActivity.ActivityGameType.Any || activityGameType == BaseActivity.ActivityGameType.Any || activity.GameType == activityGameType) && (activity.GameMode == BaseActivity.ActivityGameMode.Any || activityGameMode == BaseActivity.ActivityGameMode.Any || activity.GameMode == activityGameMode) && (activity.Survivor == BaseActivity.ActivitySurvivor.Any || activitySurvivor == BaseActivity.ActivitySurvivor.Any || activity.Survivor == activitySurvivor))
			{
				if (activity.AchievementID.Length != 0 && activityAchievementID.Length != 0)
				{
					return activity.AchievementID.CompareTo(activityAchievementID) == 0;
				}
				return true;
			}
			return false;
		}
	}
	public class ActivityManager
	{
		protected ActivityData LoadedActivityData;

		protected Dictionary<string, BaseActivity> InProgressActivities = new Dictionary<string, BaseActivity>();

		protected Dictionary<string, BaseActivity> AvailableActivities = new Dictionary<string, BaseActivity>();

		protected BaseActivity ActivityToProcess;

		public bool IsInitialized { get; private set; }

		public BaseActivity.ActivityGameMode CurrentGameMode
		{
			get
			{
				GameModeIndex gameModeIndex = GameModeIndex.Invalid;
				if (null != PreGameController.instance)
				{
					gameModeIndex = PreGameController.instance.gameModeIndex;
				}
				if (null != Run.instance)
				{
					gameModeIndex = Run.instance.gameModeIndex;
				}
				if (GameModeIndex.Invalid != gameModeIndex)
				{
					if (gameModeIndex == GameModeCatalog.FindGameModeIndex("ClassicRun"))
					{
						return BaseActivity.ActivityGameMode.ClassicRun;
					}
					if (gameModeIndex == GameModeCatalog.FindGameModeIndex("EclipseRun"))
					{
						return BaseActivity.ActivityGameMode.Eclipse;
					}
					if (gameModeIndex == GameModeCatalog.FindGameModeIndex("InfiniteTowerRun"))
					{
						return BaseActivity.ActivityGameMode.InfiniteTower;
					}
					if (gameModeIndex == GameModeCatalog.FindGameModeIndex("WeeklyRun"))
					{
						return BaseActivity.ActivityGameMode.WeeklyRun;
					}
				}
				UnityEngine.Debug.LogError("ActivityManager::CurrentGameMode property unable to determine GameMode.");
				return BaseActivity.ActivityGameMode.Any;
			}
		}

		public BaseActivity.ActivityGameType CurrentGameType
		{
			get
			{
				ReadOnlyCollection<NetworkUser> readOnlyLocalPlayersList = NetworkUser.readOnlyLocalPlayersList;
				if (readOnlyLocalPlayersList != null)
				{
					if (readOnlyLocalPlayersList.Count == 1)
					{
						return BaseActivity.ActivityGameType.SinglePlayer;
					}
					if (readOnlyLocalPlayersList.Count > 1)
					{
						return BaseActivity.ActivityGameType.MultiPlayer;
					}
				}
				UnityEngine.Debug.LogError("ActivityManager::CurrentGameType property unable to determine GameType.");
				return BaseActivity.ActivityGameType.Any;
			}
		}

		public BaseActivity.ActivitySurvivor CurrentSurvivor
		{
			get
			{
				UserProfile userProfile = LocalUserManager.GetFirstLocalUser()?.userProfile;
				if (userProfile != null)
				{
					SurvivorDef survivorDef = userProfile?.GetSurvivorPreference();
					if (null != survivorDef)
					{
						BaseActivity.ActivitySurvivor result = BaseActivity.ActivitySurvivor.Any;
						if (Enum.TryParse<BaseActivity.ActivitySurvivor>(survivorDef.cachedName, out result))
						{
							return result;
						}
					}
				}
				UnityEngine.Debug.LogError("ActivityManager::CurrentSurvivor property unable to determine survivor.");
				return BaseActivity.ActivitySurvivor.Any;
			}
		}

		private bool ValidCurrentSelectorExists
		{
			get
			{
				if ((null != PreGameController.instance || null != Run.instance) && LocalUserManager.GetFirstLocalUser()?.userProfile != null)
				{
					if (NetworkUser.readOnlyLocalPlayersList != null)
					{
						return NetworkUser.readOnlyLocalPlayersList.Count >= 0;
					}
					return false;
				}
				return false;
			}
		}

		public BaseActivitySelector CurrentActivitySelector
		{
			get
			{
				if (ValidCurrentSelectorExists)
				{
					return new BaseActivitySelector
					{
						activitySurvivor = CurrentSurvivor,
						activityGameMode = CurrentGameMode,
						activityGameType = CurrentGameType
					};
				}
				return null;
			}
		}

		public virtual void Initialize()
		{
			MainMenuController.OnPreMainMenuInitialized -= OnPreMainMenuInitializedCallback;
			MainMenuController.OnPreMainMenuInitialized += OnPreMainMenuInitializedCallback;
			LocalUserManager.onUserSignIn -= OnLocalUserSignIn;
			LocalUserManager.onUserSignIn += OnLocalUserSignIn;
			BaseUserEntitlementTracker<LocalUser>.OnAllUserEntitlementsUpdated = (Action)Delegate.Remove(BaseUserEntitlementTracker<LocalUser>.OnAllUserEntitlementsUpdated, new Action(OnEntitlementsChangedCallback));
			BaseUserEntitlementTracker<LocalUser>.OnAllUserEntitlementsUpdated = (Action)Delegate.Combine(BaseUserEntitlementTracker<LocalUser>.OnAllUserEntitlementsUpdated, new Action(OnEntitlementsChangedCallback));
			Run.onRunStartGlobal += OnRunStartGlobal;
			Run.onClientGameOverGlobal += OnClientGameOverGlobal;
		}

		protected virtual void OnPreMainMenuReInitializedCallback()
		{
			AbandonInProgressActivities();
		}

		protected virtual void OnLocalUserSignIn(LocalUser localUser)
		{
			if (localUser.userProfile != null && localUser.userProfile == LocalUserManager.GetFirstLocalUser().userProfile)
			{
				RebuildActivityAvailabilityForUser(localUser);
				IsInitialized = true;
			}
		}

		protected virtual void AbandonInProgressActivities()
		{
			BaseActivitySelector activitySelector = new BaseActivitySelector();
			PlatformSystems.activityManager.TryToAbandonActivity(activitySelector);
		}

		protected virtual void OnClientGameOverGlobal(Run run, RunReport runReport)
		{
			if (runReport.gameEnding == RoR2Content.GameEndings.StandardLoss)
			{
				if (ValidCurrentSelectorExists)
				{
					PlatformSystems.activityManager.TryToFailActivity(PlatformSystems.activityManager.CurrentActivitySelector);
				}
				else
				{
					UnityEngine.Debug.LogError("ActivityManager::OnClientGameOverGlobal - missing context to fail activities activities on Game Over.");
				}
			}
		}

		protected virtual void OnRunStartGlobal(Run run)
		{
			if (ValidCurrentSelectorExists)
			{
				TryToStartActivity(CurrentActivitySelector);
			}
			else
			{
				UnityEngine.Debug.LogError("ActivityManager::OnRunStartGlobal - missing context to start activities on Run start.");
			}
		}

		protected virtual void OnPreMainMenuInitializedCallback()
		{
			MainMenuController.OnPreMainMenuInitialized -= OnPreMainMenuInitializedCallback;
			AsyncOperationHandle<ActivityData> handle = Addressables.LoadAssetAsync<ActivityData>("RoR2/Base/Common/ActivityData.asset");
			ActivityData loadedActivityData = handle.WaitForCompletion();
			LoadedActivityData = loadedActivityData;
			Addressables.Release(handle);
			if (GameIntentReceiver.GameIntentAdapter.hasPendingGameIntent)
			{
				CreateStartupActivity();
			}
			GameIntentReceiver.GameIntentAdapter.OnGameIntentReceivedEvent -= GameIntentReceiverListener;
			GameIntentReceiver.GameIntentAdapter.OnGameIntentReceivedEvent += GameIntentReceiverListener;
			if (ActivityToProcess != null)
			{
				RoR2Application.instance.StartCoroutine(ProcessGameActivity());
				GameIntentReceiver.GameIntentAdapter.ClearPendingGameIntent();
			}
			MainMenuController.OnPreMainMenuInitialized += OnPreMainMenuReInitializedCallback;
		}

		protected virtual void CreateStartupActivity()
		{
		}

		public virtual void GameIntentReceiverListener(GameIntentAdapter.EventResponse eventResponseObject)
		{
			eventResponseObject.EventHasBeenHandled(eventHandled: false);
		}

		public virtual void TryToStartActivity(BaseActivitySelector activitySelector)
		{
		}

		public virtual void TryToCompleteActivity(BaseActivitySelector activitySelector, bool markUnavailableOnComplete = true, bool applyAsDelta = true)
		{
		}

		public virtual void TryToAbandonActivity(BaseActivitySelector activitySelector)
		{
		}

		public virtual void TryToFailActivity(BaseActivitySelector activitySelector)
		{
		}

		public virtual void TryToSetActivityAvailability(BaseActivitySelector activitySelector, bool newAvailability, bool applyAsDelta = true, bool sendImmediate = true)
		{
		}

		public virtual void FlushAvailabilityUpdates(bool applyAsDelta)
		{
		}

		public virtual bool ShouldSkipGameIntentHandler(BaseActivity activity)
		{
			return CurrentActivitySelector?.IsCompatibleWith(activity) ?? false;
		}

		public virtual bool IsActivityAvailable(BaseActivity baseActivity)
		{
			return AvailableActivities.ContainsKey(baseActivity.ActivityID);
		}

		protected IEnumerator ProcessGameActivity()
		{
			if (!IsInitialized)
			{
				yield return new WaitForEndOfFrame();
			}
			BaseActivity gameActivity = LoadedActivityData.LookupActivityByID(ActivityToProcess.ActivityID);
			if (gameActivity == null)
			{
				UnityEngine.Debug.LogError("ActivityManager::ProcessGameActivity() was unable to find data for a Game Activity!");
				yield break;
			}
			if (!IsActivityAvailable(gameActivity))
			{
				UnityEngine.Debug.LogError("ActivityManager::ProcessGameActivity() user attempted to launch an unavailable activity!");
				yield break;
			}
			if (!RoR2Application.IsMainScene)
			{
				if (ShouldSkipGameIntentHandler(gameActivity))
				{
					yield break;
				}
				global::RoR2.Console.instance.SubmitCmd(null, "transition_command \"disconnect\";");
				yield return new WaitForSeconds(1f);
				global::RoR2.Console.instance.SubmitCmd(null, "transition_command \"set_scene title\";");
				while (!RoR2Application.IsMainScene)
				{
					yield return new WaitForEndOfFrame();
				}
			}
			while (!RoR2Application.IsMainMenuInitialized)
			{
				yield return new WaitForEndOfFrame();
			}
			string gameModeStr;
			if (gameActivity.GameMode == BaseActivity.ActivityGameMode.ClassicRun || gameActivity.GameMode == BaseActivity.ActivityGameMode.Any)
			{
				gameModeStr = "ClassicRun";
			}
			else if (gameActivity.GameMode == BaseActivity.ActivityGameMode.WeeklyRun)
			{
				gameModeStr = "WeeklyRun";
			}
			else if (gameActivity.GameMode == BaseActivity.ActivityGameMode.Eclipse)
			{
				gameModeStr = "EclipseRun";
			}
			else if (gameActivity.GameMode == BaseActivity.ActivityGameMode.InfiniteTower)
			{
				gameModeStr = "InfiniteTowerRun";
			}
			else
			{
				UnityEngine.Debug.LogError("ActivityManager::ProcessGameActivity() - Trying to transition to gamemode with unhandled BaseActivity.ActivityGameMode. Transitioning to Classic Run...");
				gameModeStr = "ClassicRun";
			}
			while (TransitionCommand.requestPending)
			{
				yield return new WaitForEndOfFrame();
			}
			global::RoR2.Console.instance.SubmitCmd(null, "transition_command \"gamemode " + gameModeStr + "; host 0;\"");
			string text = gameActivity.Survivor.ToString();
			if (string.Compare("Any", text) != 0)
			{
				SurvivorIndex survivorIndex = SurvivorCatalog.FindSurvivorIndex(text);
				UserProfile userProfile = LocalUserManager.GetFirstLocalUser()?.userProfile;
				if (userProfile.HasSurvivorUnlocked(survivorIndex))
				{
					SurvivorDef survivorDef = SurvivorCatalog.GetSurvivorDef(survivorIndex);
					userProfile.SetSurvivorPreference(survivorDef);
				}
			}
			yield return new WaitForSeconds(2f);
			RoR2Application.SetMapsEnabled(enabled: true);
		}

		public void RebuildActivityAvailabilityForUser(LocalUser localUser)
		{
			if (LoadedActivityData == null)
			{
				return;
			}
			UserProfile userProfile = localUser.userProfile;
			BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
			List<BaseActivity> list = LoadedActivityData.CompareActivityCriteria(baseActivitySelector);
			foreach (BaseActivity item in list)
			{
				if (item.AchievementID.Length == 0)
				{
					continue;
				}
				baseActivitySelector.activityAchievementID = item.AchievementID;
				bool flag = userProfile.CanSeeAchievement(item.AchievementID);
				bool flag2 = userProfile.HasAchievement(item.AchievementID);
				if (item.RequiredEntitlementID.Length > 0)
				{
					if (EntitlementCatalog.FindEntitlementIndex(item.RequiredEntitlementID) == EntitlementIndex.None)
					{
						UnityEngine.Debug.LogError("ActivityManager::RebuildAvailabilityForUser - Activity requires entitlement (" + item.RequiredEntitlementID + ") that is not defined in the EntitlementCatalog. (probably a typo)");
					}
					else
					{
						EntitlementDef entitlementDef = EntitlementCatalog.GetEntitlementDef(EntitlementCatalog.FindEntitlementIndex(item.RequiredEntitlementID));
						if (!EntitlementManager.localUserEntitlementTracker.UserHasEntitlement(localUser, entitlementDef))
						{
							flag = false;
						}
					}
				}
				TryToSetActivityAvailability(baseActivitySelector, flag && !flag2, applyAsDelta: false, sendImmediate: false);
			}
			if (list.Count > 0)
			{
				FlushAvailabilityUpdates(applyAsDelta: false);
			}
		}

		private void OnEntitlementsChangedCallback()
		{
			RebuildActivityAvailabilityForUser(LocalUserManager.GetFirstLocalUser());
		}
	}
	[Serializable]
	public class BaseActivity
	{
		public enum ActivityGameType : uint
		{
			SinglePlayer,
			MultiPlayer,
			Any
		}

		public enum ActivityGameMode : uint
		{
			ClassicRun,
			Eclipse,
			InfiniteTower,
			WeeklyRun,
			Any
		}

		public enum ActivitySurvivor : uint
		{
			Bandit2,
			Captain,
			Commando,
			Croco,
			Engi,
			Heretic,
			Huntress,
			Loader,
			Mage,
			Merc,
			Toolbot,
			Treebot,
			Railgunner,
			Any
		}

		[SerializeField]
		protected ActivityGameType _gameType;

		[SerializeField]
		protected ActivityGameMode _gameMode;

		[SerializeField]
		protected ActivitySurvivor _survivor;

		[SerializeField]
		protected string _activityID;

		[SerializeField]
		protected string _achievementID;

		[SerializeField]
		protected string _requiredEntitlementID;

		public ActivityGameType GameType => _gameType;

		public ActivityGameMode GameMode => _gameMode;

		public ActivitySurvivor Survivor => _survivor;

		public string ActivityID => _activityID;

		public string AchievementID => _achievementID;

		public string RequiredEntitlementID => _requiredEntitlementID;

		public virtual void StartActivity()
		{
			UnityEngine.Debug.LogError("BaseActivity::StartActivity() invoked!");
		}

		public virtual void CompleteActivity()
		{
			UnityEngine.Debug.LogError("BaseActivity::CompleteActivity() invoked!");
		}

		public virtual void AbandonActivity()
		{
			UnityEngine.Debug.LogError("BaseActivity::AbandonActivity() invoked!");
		}

		public virtual void FailActivity()
		{
			UnityEngine.Debug.LogError("BaseActivity::FailActivity() invoked!");
		}
	}
	public class GameIntentAdapter
	{
		public class EventResponse : EventArgs
		{
			public bool wasEventHandledByAnySystem { get; private set; }

			public void EventHasBeenHandled(bool eventHandled)
			{
				wasEventHandledByAnySystem |= eventHandled;
			}
		}

		public virtual bool hasPendingGameIntent => false;

		public event Action<EventResponse> OnGameIntentReceivedEvent;

		public virtual void Initialize()
		{
		}

		public virtual void ClearPendingGameIntent()
		{
		}

		protected void FireGameIntentReceived()
		{
			EventResponse eventResponse = new EventResponse();
			this.OnGameIntentReceivedEvent?.Invoke(eventResponse);
			if (eventResponse.wasEventHandledByAnySystem)
			{
				ClearPendingGameIntent();
			}
		}
	}
	public static class GameIntentReceiver
	{
		public static GameIntentAdapter GameIntentAdapter { get; private set; } = new GameIntentAdapter();


		public static void Initialize()
		{
			GameIntentAdapter.Initialize();
		}
	}
}
namespace Assets.RoR2.Scripts.Platform.PS5
{
	public class OnScreenLog : MonoBehaviour
	{
	}
}
namespace Optimization
{
	public static class WanderCulling
	{
		public const float wanderTimeBeforeCull = 15f;

		public const float wanderResetTime = 7.5f;

		public const float minLifeTime = 20f;

		public const float wanderPlayerCheckRadius = 75f;

		public const int minEnemyCountBeforeCull = 10;

		public const int importanceThreshold = 3;
	}
}
namespace UnityEngine.Rendering.PostProcessing
{
	[Serializable]
	[PostProcess(typeof(HopooSSRRenderer), PostProcessEvent.BeforeTransparent, "PostProcess/Hopoo SSR", true)]
	public sealed class HopooSSR : PostProcessEffectSettings
	{
		[Tooltip("Choose a quality preset, or use \"Custom\" to fine tune it. Don't use a preset higher than \"Medium\" if you care about performances on consoles.")]
		public ScreenSpaceReflectionPresetParameter preset = new ScreenSpaceReflectionPresetParameter
		{
			value = ScreenSpaceReflectionPreset.Medium
		};

		[Tooltip("Maximum iteration count.")]
		[Range(0f, 256f)]
		public IntParameter maximumIterationCount = new IntParameter
		{
			value = 16
		};

		[Tooltip("Changes the size of the SSR buffer. Downsample it to maximize performances or supersample it to get slow but higher quality results.")]
		public ScreenSpaceReflectionResolutionParameter resolution = new ScreenSpaceReflectionResolutionParameter
		{
			value = ScreenSpaceReflectionResolution.Downsampled
		};

		[Tooltip("Ray thickness. Lower values are more expensive but allow the effect to detect smaller details.")]
		[Range(1f, 64f)]
		public FloatParameter thickness = new FloatParameter
		{
			value = 8f
		};

		[Tooltip("Maximum distance to traverse after which it will stop drawing reflections.")]
		public FloatParameter maximumMarchDistance = new FloatParameter
		{
			value = 100f
		};

		[Range(0f, 1f)]
		[Tooltip("Fades reflections close to the near planes.")]
		public FloatParameter distanceFade = new FloatParameter
		{
			value = 0.5f
		};

		[Range(0f, 1f)]
		[Tooltip("Fades reflections close to the screen edges.")]
		public FloatParameter vignette = new FloatParameter
		{
			value = 0.5f
		};

		public override bool IsEnabledAndSupported(PostProcessRenderContext context)
		{
			if ((bool)enabled && context.camera.actualRenderingPath == RenderingPath.DeferredShading && SystemInfo.supportsMotionVectors && SystemInfo.supportsComputeShaders && SystemInfo.copyTextureSupport > CopyTextureSupport.None && (bool)context.resources.shaders.screenSpaceReflections && context.resources.shaders.screenSpaceReflections.isSupported)
			{
				return context.resources.computeShaders.gaussianDownsample;
			}
			return false;
		}
	}
	public sealed class HopooSSRRenderer : PostProcessEffectRenderer<HopooSSR>
	{
		private class QualityPreset
		{
			public int maximumIterationCount;

			public float thickness;

			public ScreenSpaceReflectionResolution downsampling;
		}

		private enum Pass
		{
			Test,
			Resolve,
			Reproject,
			Composite
		}

		private RenderTexture m_Resolve;

		private RenderTexture m_History;

		private int[] m_MipIDs;

		private readonly QualityPreset[] m_Presets = new QualityPreset[7]
		{
			new QualityPreset
			{
				maximumIterationCount = 10,
				thickness = 32f,
				downsampling = ScreenSpaceReflectionResolution.Downsampled
			},
			new QualityPreset
			{
				maximumIterationCount = 16,
				thickness = 32f,
				downsampling = ScreenSpaceReflectionResolution.Downsampled
			},
			new QualityPreset
			{
				maximumIterationCount = 32,
				thickness = 16f,
				downsampling = ScreenSpaceReflectionResolution.Downsampled
			},
			new QualityPreset
			{
				maximumIterationCount = 48,
				thickness = 8f,
				downsampling = ScreenSpaceReflectionResolution.Downsampled
			},
			new QualityPreset
			{
				maximumIterationCount = 16,
				thickness = 32f,
				downsampling = ScreenSpaceReflectionResolution.FullSize
			},
			new QualityPreset
			{
				maximumIterationCount = 48,
				thickness = 16f,
				downsampling = ScreenSpaceReflectionResolution.FullSize
			},
			new QualityPreset
			{
				maximumIterationCount = 128,
				thickness = 12f,
				downsampling = ScreenSpaceReflectionResolution.Supersampled
			}
		};

		public override DepthTextureMode GetCameraFlags()
		{
			return DepthTextureMode.Depth | DepthTextureMode.MotionVectors;
		}

		internal void CheckRT(ref RenderTexture rt, int width, int height, RenderTextureFormat format, FilterMode filterMode, bool useMipMap)
		{
			if (rt == null || !rt.IsCreated() || rt.width != width || rt.height != height || rt.format != format)
			{
				if (rt != null)
				{
					rt.Release();
				}
				rt = new RenderTexture(width, height, 0, format)
				{
					filterMode = filterMode,
					useMipMap = useMipMap,
					autoGenerateMips = false,
					hideFlags = HideFlags.HideAndDontSave
				};
				rt.Create();
			}
		}

		public override void Render(PostProcessRenderContext context)
		{
			CommandBuffer command = context.command;
			command.BeginSample("Screen-space Reflections");
			if (base.settings.preset.value != ScreenSpaceReflectionPreset.Custom)
			{
				int value = (int)base.settings.preset.value;
				base.settings.maximumIterationCount.value = m_Presets[value].maximumIterationCount;
				base.settings.thickness.value = m_Presets[value].thickness;
				base.settings.resolution.value = m_Presets[value].downsampling;
			}
			base.settings.maximumMarchDistance.value = Mathf.Max(0f, base.settings.maximumMarchDistance.value);
			int num = Mathf.ClosestPowerOfTwo(Mathf.Min(context.width, context.height));
			if (base.settings.resolution.value == ScreenSpaceReflectionResolution.Downsampled)
			{
				num >>= 1;
			}
			else if (base.settings.resolution.value == ScreenSpaceReflectionResolution.Supersampled)
			{
				num <<= 1;
			}
			int a = Mathf.FloorToInt(Mathf.Log(num, 2f) - 3f);
			a = Mathf.Min(a, 12);
			CheckRT(ref m_Resolve, num, num, context.sourceFormat, FilterMode.Trilinear, useMipMap: true);
			Texture2D texture2D = context.resources.blueNoise256[0];
			PropertySheet propertySheet = context.propertySheets.Get(LegacyShaderAPI.Find("Hidden/PostProcessing/HopooSSR"));
			propertySheet.properties.SetTexture(Shader.PropertyToID("_Noise"), texture2D);
			Matrix4x4 value2 = default(Matrix4x4);
			value2.SetRow(0, new Vector4((float)num * 0.5f, 0f, 0f, (float)num * 0.5f));
			value2.SetRow(1, new Vector4(0f, (float)num * 0.5f, 0f, (float)num * 0.5f));
			value2.SetRow(2, new Vector4(0f, 0f, 1f, 0f));
			value2.SetRow(3, new Vector4(0f, 0f, 0f, 1f));
			Matrix4x4 gPUProjectionMatrix = GL.GetGPUProjectionMatrix(context.camera.projectionMatrix, renderIntoTexture: false);
			value2 *= gPUProjectionMatrix;
			propertySheet.properties.SetMatrix(Shader.PropertyToID("_ViewMatrix"), context.camera.worldToCameraMatrix);
			propertySheet.properties.SetMatrix(Shader.PropertyToID("_InverseViewMatrix"), context.camera.worldToCameraMatrix.inverse);
			propertySheet.properties.SetMatrix(Shader.PropertyToID("_InverseProjectionMatrix"), gPUProjectionMatrix.inverse);
			propertySheet.properties.SetMatrix(Shader.PropertyToID("_ScreenSpaceProjectionMatrix"), value2);
			propertySheet.properties.SetVector(Shader.PropertyToID("_Params"), new Vector4(base.settings.vignette.value, base.settings.distanceFade.value, base.settings.maximumMarchDistance.value, a));
			propertySheet.properties.SetVector(Shader.PropertyToID("_Params2"), new Vector4((float)context.width / (float)context.height, (float)num / (float)texture2D.width, base.settings.thickness.value, base.settings.maximumIterationCount.value));
			command.GetTemporaryRT(Shader.PropertyToID("_Test"), num, num, 0, FilterMode.Point, context.sourceFormat);
			command.BlitFullscreenTriangle(context.source, Shader.PropertyToID("_Test"), propertySheet, 0);
			if (context.isSceneView)
			{
				command.BlitFullscreenTriangle(context.source, m_Resolve, propertySheet, 1);
			}
			else
			{
				CheckRT(ref m_History, num, num, context.sourceFormat, FilterMode.Bilinear, useMipMap: false);
				if (m_ResetHistory)
				{
					context.command.BlitFullscreenTriangle(context.source, m_History);
					m_ResetHistory = false;
				}
				command.GetTemporaryRT(Shader.PropertyToID("_SSRResolveTemp"), num, num, 0, FilterMode.Bilinear, context.sourceFormat);
				command.BlitFullscreenTriangle(context.source, Shader.PropertyToID("_SSRResolveTemp"), propertySheet, 1);
				propertySheet.properties.SetTexture(Shader.PropertyToID("_History"), m_History);
				command.BlitFullscreenTriangle(Shader.PropertyToID("_SSRResolveTemp"), m_Resolve, propertySheet, 2);
				command.CopyTexture(m_Resolve, 0, 0, m_History, 0, 0);
				command.ReleaseTemporaryRT(Shader.PropertyToID("_SSRResolveTemp"));
			}
			command.ReleaseTemporaryRT(Shader.PropertyToID("_Test"));
			if (m_MipIDs == null || m_MipIDs.Length == 0)
			{
				m_MipIDs = new int[12];
				for (int i = 0; i < 12; i++)
				{
					m_MipIDs[i] = Shader.PropertyToID("_SSRGaussianMip" + i);
				}
			}
			ComputeShader gaussianDownsample = context.resources.computeShaders.gaussianDownsample;
			int kernelIndex = gaussianDownsample.FindKernel("KMain");
			RenderTargetIdentifier rt = new RenderTargetIdentifier(m_Resolve);
			for (int j = 0; j < a; j++)
			{
				num >>= 1;
				command.GetTemporaryRT(m_MipIDs[j], num, num, 0, FilterMode.Bilinear, context.sourceFormat, RenderTextureReadWrite.Default, 1, enableRandomWrite: true);
				command.SetComputeTextureParam(gaussianDownsample, kernelIndex, "_Source", rt);
				command.SetComputeTextureParam(gaussianDownsample, kernelIndex, "_Result", m_MipIDs[j]);
				command.SetComputeVectorParam(gaussianDownsample, "_Size", new Vector4(num, num, 1f / (float)num, 1f / (float)num));
				command.DispatchCompute(gaussianDownsample, kernelIndex, num / 8, num / 8, 1);
				command.CopyTexture(m_MipIDs[j], 0, 0, m_Resolve, 0, j + 1);
				rt = m_MipIDs[j];
			}
			for (int k = 0; k < a; k++)
			{
				command.ReleaseTemporaryRT(m_MipIDs[k]);
			}
			propertySheet.properties.SetTexture(Shader.PropertyToID("_Resolve"), m_Resolve);
			command.BlitFullscreenTriangle(context.source, context.destination, propertySheet, 3);
			command.EndSample("Screen-space Reflections");
		}

		public override void Release()
		{
			RuntimeUtilities.Destroy(m_Resolve);
			RuntimeUtilities.Destroy(m_History);
			m_Resolve = null;
			m_History = null;
		}
	}
}
namespace EntityStates
{
	public abstract class AimThrowableBase : BaseSkillState
	{
		private struct CalculateArcPointsJob : IJobParallelFor, IDisposable
		{
			[ReadOnly]
			private UnityEngine.Vector3 origin;

			[ReadOnly]
			private UnityEngine.Vector3 velocity;

			[ReadOnly]
			private float indexMultiplier;

			[ReadOnly]
			private float gravity;

			[WriteOnly]
			public NativeArray<UnityEngine.Vector3> outputPositions;

			public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 velocity, float totalTravelTime, int positionCount, float gravity)
			{
				this.origin = origin;
				this.velocity = velocity;
				if (outputPositions.Length != positionCount)
				{
					if (outputPositions.IsCreated)
					{
						outputPositions.Dispose();
					}
					outputPositions = new NativeArray<UnityEngine.Vector3>(positionCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
				}
				indexMultiplier = totalTravelTime / (float)(positionCount - 1);
				this.gravity = gravity;
			}

			public void Dispose()
			{
				if (outputPositions.IsCreated)
				{
					outputPositions.Dispose();
				}
			}

			public void Execute(int index)
			{
				float t = (float)index * indexMultiplier;
				outputPositions[index] = Trajectory.CalculatePositionAtTime(origin, velocity, t, gravity);
			}
		}

		protected struct TrajectoryInfo
		{
			public Ray finalRay;

			public UnityEngine.Vector3 hitPoint;

			public UnityEngine.Vector3 hitNormal;

			public float travelTime;

			public float speedOverride;
		}

		[SerializeField]
		public float maxDistance;

		[SerializeField]
		public float rayRadius;

		[SerializeField]
		public GameObject arcVisualizerPrefab;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject endpointVisualizerPrefab;

		[SerializeField]
		public float endpointVisualizerRadiusScale;

		[SerializeField]
		public bool setFuse;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float baseMinimumDuration;

		protected LineRenderer arcVisualizerLineRenderer;

		protected Transform endpointVisualizerTransform;

		protected float projectileBaseSpeed;

		protected float detonationRadius;

		protected float minimumDuration;

		protected bool useGravity;

		private CalculateArcPointsJob calculateArcPointsJob;

		private JobHandle calculateArcPointsJobHandle;

		private UnityEngine.Vector3[] pointsBuffer = Array.Empty<UnityEngine.Vector3>();

		private Action completeArcPointsVisualizerJobMethod;

		protected TrajectoryInfo currentTrajectoryInfo;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)arcVisualizerPrefab)
			{
				arcVisualizerLineRenderer = UnityEngine.Object.Instantiate(arcVisualizerPrefab, base.transform.position, UnityEngine.Quaternion.identity).GetComponent<LineRenderer>();
				calculateArcPointsJob = default(CalculateArcPointsJob);
				completeArcPointsVisualizerJobMethod = CompleteArcVisualizerJob;
				RoR2Application.onLateUpdate += completeArcPointsVisualizerJobMethod;
			}
			if ((bool)endpointVisualizerPrefab)
			{
				endpointVisualizerTransform = UnityEngine.Object.Instantiate(endpointVisualizerPrefab, base.transform.position, UnityEngine.Quaternion.identity).transform;
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.hideCrosshair = true;
			}
			ProjectileSimple component = projectilePrefab.GetComponent<ProjectileSimple>();
			if ((bool)component)
			{
				projectileBaseSpeed = component.velocity;
			}
			Rigidbody component2 = projectilePrefab.GetComponent<Rigidbody>();
			if ((bool)component2)
			{
				useGravity = component2.useGravity;
			}
			minimumDuration = baseMinimumDuration / attackSpeedStat;
			ProjectileImpactExplosion component3 = projectilePrefab.GetComponent<ProjectileImpactExplosion>();
			if ((bool)component3)
			{
				detonationRadius = component3.blastRadius;
				if ((bool)endpointVisualizerTransform)
				{
					endpointVisualizerTransform.localScale = new UnityEngine.Vector3(detonationRadius, detonationRadius, detonationRadius);
				}
			}
			UpdateVisualizers(currentTrajectoryInfo);
			SceneCamera.onSceneCameraPreRender += OnPreRenderSceneCam;
		}

		public override void OnExit()
		{
			SceneCamera.onSceneCameraPreRender -= OnPreRenderSceneCam;
			if (!outer.destroying)
			{
				if (base.isAuthority)
				{
					FireProjectile();
				}
				OnProjectileFiredLocal();
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.hideCrosshair = false;
			}
			calculateArcPointsJobHandle.Complete();
			if ((bool)arcVisualizerLineRenderer)
			{
				EntityState.Destroy(arcVisualizerLineRenderer.gameObject);
				arcVisualizerLineRenderer = null;
			}
			if (completeArcPointsVisualizerJobMethod != null)
			{
				RoR2Application.onLateUpdate -= completeArcPointsVisualizerJobMethod;
				completeArcPointsVisualizerJobMethod = null;
			}
			calculateArcPointsJob.Dispose();
			pointsBuffer = Array.Empty<UnityEngine.Vector3>();
			if ((bool)endpointVisualizerTransform)
			{
				EntityState.Destroy(endpointVisualizerTransform.gameObject);
				endpointVisualizerTransform = null;
			}
			base.OnExit();
		}

		protected virtual bool KeyIsDown()
		{
			return IsKeyDownAuthority();
		}

		protected virtual void OnProjectileFiredLocal()
		{
		}

		protected virtual void FireProjectile()
		{
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.crit = RollCrit();
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.position = currentTrajectoryInfo.finalRay.origin;
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(currentTrajectoryInfo.finalRay.direction, UnityEngine.Vector3.up);
			fireProjectileInfo.speedOverride = currentTrajectoryInfo.speedOverride;
			fireProjectileInfo.damage = damageCoefficient * damageStat;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			if (setFuse)
			{
				fireProjectileInfo2.fuseOverride = currentTrajectoryInfo.travelTime;
			}
			ModifyProjectile(ref fireProjectileInfo2);
			ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
		}

		protected virtual void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo)
		{
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && !KeyIsDown() && base.fixedAge >= minimumDuration)
			{
				UpdateTrajectoryInfo(out currentTrajectoryInfo);
				EntityState entityState = PickNextState();
				if (entityState != null)
				{
					outer.SetNextState(entityState);
				}
				else
				{
					outer.SetNextStateToMain();
				}
			}
		}

		protected virtual EntityState PickNextState()
		{
			return null;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public override void Update()
		{
			base.Update();
			UpdateTrajectoryInfo(out currentTrajectoryInfo);
			UpdateVisualizers(currentTrajectoryInfo);
		}

		protected virtual void UpdateTrajectoryInfo(out TrajectoryInfo dest)
		{
			dest = default(TrajectoryInfo);
			Ray aimRay = GetAimRay();
			RaycastHit hitInfo = default(RaycastHit);
			bool flag = false;
			if (rayRadius > 0f && Util.CharacterSpherecast(base.gameObject, aimRay, rayRadius, out hitInfo, maxDistance, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.UseGlobal) && (bool)hitInfo.collider.GetComponent<HurtBox>())
			{
				flag = true;
			}
			if (!flag)
			{
				flag = Util.CharacterRaycast(base.gameObject, aimRay, out hitInfo, maxDistance, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.UseGlobal);
			}
			if (flag)
			{
				dest.hitPoint = hitInfo.point;
				dest.hitNormal = hitInfo.normal;
			}
			else
			{
				dest.hitPoint = aimRay.GetPoint(maxDistance);
				dest.hitNormal = -aimRay.direction;
			}
			UnityEngine.Vector3 vector = dest.hitPoint - aimRay.origin;
			if (useGravity)
			{
				float num = projectileBaseSpeed;
				UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z);
				float magnitude = vector2.magnitude;
				float y = Trajectory.CalculateInitialYSpeed(magnitude / num, vector.y);
				UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude * num, y, vector2.y / magnitude * num);
				dest.speedOverride = vector3.magnitude;
				dest.finalRay = new Ray(aimRay.origin, vector3 / dest.speedOverride);
				dest.travelTime = Trajectory.CalculateGroundTravelTime(num, magnitude);
			}
			else
			{
				dest.speedOverride = projectileBaseSpeed;
				dest.finalRay = aimRay;
				dest.travelTime = projectileBaseSpeed / vector.magnitude;
			}
		}

		private void CompleteArcVisualizerJob()
		{
			calculateArcPointsJobHandle.Complete();
			if ((bool)arcVisualizerLineRenderer)
			{
				Array.Resize(ref pointsBuffer, calculateArcPointsJob.outputPositions.Length);
				calculateArcPointsJob.outputPositions.CopyTo(pointsBuffer);
				arcVisualizerLineRenderer.SetPositions(pointsBuffer);
			}
		}

		private void UpdateVisualizers(TrajectoryInfo trajectoryInfo)
		{
			if ((bool)arcVisualizerLineRenderer && calculateArcPointsJobHandle.IsCompleted)
			{
				calculateArcPointsJob.SetParameters(trajectoryInfo.finalRay.origin, trajectoryInfo.finalRay.direction * trajectoryInfo.speedOverride, trajectoryInfo.travelTime, arcVisualizerLineRenderer.positionCount, useGravity ? Physics.gravity.y : 0f);
				calculateArcPointsJobHandle = calculateArcPointsJob.Schedule(calculateArcPointsJob.outputPositions.Length, 32);
			}
			if ((bool)endpointVisualizerTransform)
			{
				endpointVisualizerTransform.SetPositionAndRotation(trajectoryInfo.hitPoint, Util.QuaternionSafeLookRotation(trajectoryInfo.hitNormal));
				if (!endpointVisualizerRadiusScale.Equals(0f))
				{
					endpointVisualizerTransform.localScale = new UnityEngine.Vector3(endpointVisualizerRadiusScale, endpointVisualizerRadiusScale, endpointVisualizerRadiusScale);
				}
			}
		}

		private void OnPreRenderSceneCam(SceneCamera sceneCam)
		{
			if ((bool)arcVisualizerLineRenderer)
			{
				arcVisualizerLineRenderer.renderingLayerMask = ((sceneCam.cameraRigController.target == base.gameObject) ? 1u : 0u);
			}
			if ((bool)endpointVisualizerTransform)
			{
				endpointVisualizerTransform.gameObject.layer = ((sceneCam.cameraRigController.target == base.gameObject) ? LayerIndex.defaultLayer.intVal : LayerIndex.noDraw.intVal);
			}
		}
	}
	public class BaseBodyAttachmentState : EntityState
	{
		protected NetworkedBodyAttachment bodyAttachment { get; private set; }

		protected CharacterBody attachedBody { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			bodyAttachment = GetComponent<NetworkedBodyAttachment>();
			attachedBody = (bodyAttachment ? bodyAttachment.attachedBody : null);
		}
	}
	public class BaseCharacterMain : BaseState
	{
		private RootMotionAccumulator rootMotionAccumulator;

		private UnityEngine.Vector3 previousPosition;

		protected CharacterAnimParamAvailability characterAnimParamAvailability;

		private CharacterAnimatorWalkParamCalculator animatorWalkParamCalculator;

		protected BodyAnimatorSmoothingParameters.SmoothingParameters smoothingParameters;

		protected bool useRootMotion;

		private bool wasGrounded;

		private float lastYSpeed;

		protected bool hasCharacterMotor;

		protected bool hasCharacterDirection;

		protected bool hasCharacterBody;

		protected bool hasRailMotor;

		protected bool hasCameraTargetParams;

		protected bool hasSkillLocator;

		protected bool hasModelAnimator;

		protected bool hasInputBank;

		protected bool hasRootMotionAccumulator;

		protected Animator modelAnimator { get; private set; }

		protected UnityEngine.Vector3 estimatedVelocity { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			rootMotionAccumulator = GetModelRootMotionAccumulator();
			if ((bool)rootMotionAccumulator)
			{
				rootMotionAccumulator.ExtractRootMotion();
			}
			GetBodyAnimatorSmoothingParameters(out smoothingParameters);
			previousPosition = base.transform.position;
			hasCharacterMotor = base.characterMotor;
			hasCharacterDirection = base.characterDirection;
			hasCharacterBody = base.characterBody;
			hasRailMotor = base.railMotor;
			hasCameraTargetParams = base.cameraTargetParams;
			hasSkillLocator = base.skillLocator;
			hasModelAnimator = modelAnimator;
			hasInputBank = base.inputBank;
			hasRootMotionAccumulator = rootMotionAccumulator;
			if ((bool)modelAnimator)
			{
				characterAnimParamAvailability = CharacterAnimParamAvailability.FromAnimator(modelAnimator);
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				if (characterAnimParamAvailability.isGrounded)
				{
					wasGrounded = base.isGrounded;
					modelAnimator.SetBool(AnimationParameters.isGrounded, wasGrounded);
				}
				if (base.isGrounded || !hasCharacterMotor)
				{
					modelAnimator.CrossFadeInFixedTime("Idle", 0.1f, layerIndex);
				}
				else
				{
					modelAnimator.CrossFadeInFixedTime("AscendDescend", 0.1f, layerIndex);
				}
				modelAnimator.Update(0f);
			}
		}

		public override void OnExit()
		{
			if ((bool)rootMotionAccumulator)
			{
				rootMotionAccumulator.ExtractRootMotion();
			}
			if ((bool)modelAnimator)
			{
				if (characterAnimParamAvailability.isMoving)
				{
					modelAnimator.SetBool(AnimationParameters.isMoving, value: false);
				}
				if (characterAnimParamAvailability.turnAngle)
				{
					modelAnimator.SetFloat(AnimationParameters.turnAngle, 0f);
				}
			}
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			if (!(Time.deltaTime <= 0f))
			{
				UpdateEstimatedVelocity();
				useRootMotion = ((bool)base.characterBody && base.characterBody.rootMotionInMainState && base.isGrounded) || (bool)base.railMotor;
				UpdateAnimationParameters();
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void UpdateEstimatedVelocity()
		{
			UnityEngine.Vector3 vector;
			if (hasCharacterMotor)
			{
				vector = base.characterMotor.velocity;
			}
			else if (base.rigidbodyMotor != null && base.rigidbody != null)
			{
				vector = base.rigidbody.velocity;
			}
			else
			{
				UnityEngine.Vector3 position = base.transform.position;
				vector = (position - previousPosition) / Time.deltaTime;
				previousPosition = position;
			}
			estimatedVelocity = (estimatedVelocity + vector + vector) * (1f / 3f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (hasCharacterMotor)
			{
				float num = estimatedVelocity.y - lastYSpeed;
				if (base.isGrounded && !wasGrounded && hasModelAnimator)
				{
					int layerIndex = modelAnimator.GetLayerIndex("Impact");
					if (layerIndex >= 0)
					{
						modelAnimator.SetLayerWeight(layerIndex, Mathf.Clamp01(Mathf.Max(0.3f, num / 5f, modelAnimator.GetLayerWeight(layerIndex))));
						modelAnimator.PlayInFixedTime("LightImpact", layerIndex, 0f);
					}
				}
				wasGrounded = base.isGrounded;
				lastYSpeed = estimatedVelocity.y;
			}
			if (!hasRootMotionAccumulator)
			{
				return;
			}
			UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion();
			if (useRootMotion && vector != UnityEngine.Vector3.zero && base.isAuthority)
			{
				if ((bool)base.characterMotor)
				{
					base.characterMotor.rootMotion += vector;
				}
				if ((bool)base.railMotor)
				{
					base.railMotor.rootMotion += vector;
				}
			}
		}

		protected virtual void UpdateAnimationParameters()
		{
			if (hasRailMotor || !hasModelAnimator)
			{
				return;
			}
			float deltaTime = GetDeltaTime();
			UnityEngine.Vector3 vector = (base.inputBank ? base.inputBank.moveVector : UnityEngine.Vector3.zero);
			bool value = vector != UnityEngine.Vector3.zero && base.characterBody.moveSpeed > Mathf.Epsilon;
			animatorWalkParamCalculator.Update(vector, base.characterDirection ? base.characterDirection.animatorForward : base.transform.forward, in smoothingParameters, deltaTime);
			if (useRootMotion)
			{
				if (characterAnimParamAvailability.mainRootPlaybackRate)
				{
					float num = 1f;
					if ((bool)base.modelLocator && (bool)base.modelLocator.modelTransform)
					{
						num = base.modelLocator.modelTransform.localScale.x;
					}
					float value2 = base.characterBody.moveSpeed / (base.characterBody.mainRootSpeed * num);
					modelAnimator.SetFloat(AnimationParameters.mainRootPlaybackRate, value2);
				}
			}
			else if (characterAnimParamAvailability.walkSpeed)
			{
				modelAnimator.SetFloat(AnimationParameters.walkSpeed, base.characterBody.moveSpeed);
			}
			if (characterAnimParamAvailability.isGrounded)
			{
				modelAnimator.SetBool(AnimationParameters.isGrounded, base.isGrounded);
			}
			if (characterAnimParamAvailability.isMoving)
			{
				modelAnimator.SetBool(AnimationParameters.isMoving, value);
			}
			if (characterAnimParamAvailability.turnAngle)
			{
				modelAnimator.SetFloat(AnimationParameters.turnAngle, animatorWalkParamCalculator.remainingTurnAngle, smoothingParameters.turnAngleSmoothDamp, deltaTime);
			}
			if (characterAnimParamAvailability.isSprinting)
			{
				modelAnimator.SetBool(AnimationParameters.isSprinting, base.characterBody.isSprinting);
			}
			if (characterAnimParamAvailability.forwardSpeed)
			{
				modelAnimator.SetFloat(AnimationParameters.forwardSpeed, animatorWalkParamCalculator.animatorWalkSpeed.x, smoothingParameters.forwardSpeedSmoothDamp, Time.deltaTime);
			}
			if (characterAnimParamAvailability.rightSpeed)
			{
				modelAnimator.SetFloat(AnimationParameters.rightSpeed, animatorWalkParamCalculator.animatorWalkSpeed.y, smoothingParameters.rightSpeedSmoothDamp, Time.deltaTime);
			}
			if (characterAnimParamAvailability.upSpeed)
			{
				modelAnimator.SetFloat(AnimationParameters.upSpeed, estimatedVelocity.y, 0.1f, Time.deltaTime);
			}
		}
	}
	public class BaseSkillState : BaseState, ISkillState
	{
		public GenericSkill activatorSkillSlot { get; set; }

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			this.Serialize(base.skillLocator, writer);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			this.Deserialize(base.skillLocator, reader);
		}

		public bool IsKeyDownAuthority()
		{
			return this.IsKeyDownAuthority(base.skillLocator, base.inputBank);
		}
	}
	public class BaseState : EntityState
	{
		protected struct HitStopCachedState
		{
			public UnityEngine.Vector3 characterVelocity;

			public string playbackName;

			public float playbackRate;
		}

		protected float attackSpeedStat = 1f;

		protected float damageStat;

		protected float critStat;

		protected float moveSpeedStat;

		private const float defaultAimDuration = 2f;

		protected bool isGrounded
		{
			get
			{
				if ((bool)base.characterMotor)
				{
					return base.characterMotor.isGrounded;
				}
				return false;
			}
		}

		public override void Reset()
		{
			base.Reset();
			attackSpeedStat = 1f;
			damageStat = 0f;
			critStat = 0f;
			moveSpeedStat = 0f;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterBody)
			{
				attackSpeedStat = base.characterBody.attackSpeed;
				damageStat = base.characterBody.damage;
				critStat = base.characterBody.crit;
				moveSpeedStat = base.characterBody.moveSpeed;
			}
		}

		protected Ray GetAimRay()
		{
			if ((bool)base.inputBank)
			{
				return new Ray(base.inputBank.aimOrigin, base.inputBank.aimDirection);
			}
			return new Ray(base.transform.position, base.transform.forward);
		}

		protected void AddRecoil(float verticalMin, float verticalMax, float horizontalMin, float horizontalMax)
		{
			base.cameraTargetParams.AddRecoil(verticalMin, verticalMax, horizontalMin, horizontalMax);
		}

		public OverlapAttack InitMeleeOverlap(float damageCoefficient, GameObject hitEffectPrefab, Transform modelTransform, string hitboxGroupName)
		{
			OverlapAttack overlapAttack = new OverlapAttack();
			overlapAttack.attacker = base.gameObject;
			overlapAttack.inflictor = base.gameObject;
			overlapAttack.teamIndex = TeamComponent.GetObjectTeam(overlapAttack.attacker);
			overlapAttack.damage = damageCoefficient * damageStat;
			overlapAttack.hitEffectPrefab = hitEffectPrefab;
			overlapAttack.isCrit = RollCrit();
			if ((bool)modelTransform)
			{
				overlapAttack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == hitboxGroupName);
			}
			return overlapAttack;
		}

		public bool FireMeleeOverlap(OverlapAttack attack, Animator animator, string mecanimHitboxActiveParameter, float forceMagnitude, bool calculateForceVector = true)
		{
			bool result = false;
			if ((bool)animator && animator.GetFloat(mecanimHitboxActiveParameter) > 0.1f)
			{
				if (calculateForceVector)
				{
					attack.forceVector = base.transform.forward * forceMagnitude;
				}
				result = attack.Fire();
			}
			return result;
		}

		public bool FireMeleeOverlap(OverlapAttack attack, Animator animator, int mecanimHitboxActiveParameterHash, float forceMagnitude, bool calculateForceVector = true)
		{
			bool result = false;
			if ((bool)animator && animator.GetFloat(mecanimHitboxActiveParameterHash) > 0.1f)
			{
				if (calculateForceVector)
				{
					attack.forceVector = base.transform.forward * forceMagnitude;
				}
				result = attack.Fire();
			}
			return result;
		}

		public void SmallHop(CharacterMotor characterMotor, float smallHopVelocity)
		{
			if ((bool)characterMotor)
			{
				characterMotor.Motor.ForceUnground();
				characterMotor.velocity = new UnityEngine.Vector3(characterMotor.velocity.x, Mathf.Max(characterMotor.velocity.y, smallHopVelocity), characterMotor.velocity.z);
			}
		}

		protected HitStopCachedState CreateHitStopCachedState(CharacterMotor characterMotor, Animator animator, string playbackRateAnimationParameter)
		{
			HitStopCachedState result = default(HitStopCachedState);
			result.characterVelocity = new UnityEngine.Vector3(characterMotor.velocity.x, Mathf.Max(0f, characterMotor.velocity.y), characterMotor.velocity.z);
			result.playbackName = playbackRateAnimationParameter;
			result.playbackRate = animator.GetFloat(result.playbackName);
			return result;
		}

		protected void ConsumeHitStopCachedState(HitStopCachedState hitStopCachedState, CharacterMotor characterMotor, Animator animator)
		{
			characterMotor.velocity = hitStopCachedState.characterVelocity;
			animator.SetFloat(hitStopCachedState.playbackName, hitStopCachedState.playbackRate);
		}

		protected void StartAimMode(float duration = 2f, bool snap = false)
		{
			StartAimMode(GetAimRay(), duration, snap);
		}

		protected void StartAimMode(Ray aimRay, float duration = 2f, bool snap = false)
		{
			if ((bool)base.characterDirection && aimRay.direction != UnityEngine.Vector3.zero)
			{
				if (snap)
				{
					base.characterDirection.forward = aimRay.direction;
				}
				else
				{
					base.characterDirection.moveVector = aimRay.direction;
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
			if (!base.modelLocator)
			{
				return;
			}
			Transform modelTransform = base.modelLocator.modelTransform;
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component && snap)
				{
					component.AimImmediate();
				}
			}
		}

		protected bool RollCrit()
		{
			if ((bool)base.characterBody && (bool)base.characterBody.master)
			{
				return Util.CheckRoll(critStat, base.characterBody.master);
			}
			return false;
		}

		protected Transform FindModelChild(string childName)
		{
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				return modelChildLocator.FindChild(childName);
			}
			return null;
		}

		protected T FindModelChildComponent<T>(string childName)
		{
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				return modelChildLocator.FindChildComponent<T>(childName);
			}
			return default(T);
		}

		protected GameObject FindModelChildGameObject(string childName)
		{
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				return modelChildLocator.FindChildGameObject(childName);
			}
			return null;
		}

		public TeamIndex GetTeam()
		{
			return TeamComponent.GetObjectTeam(base.gameObject);
		}

		public bool HasBuff(BuffIndex buffType)
		{
			if ((bool)base.characterBody)
			{
				return base.characterBody.HasBuff(buffType);
			}
			return false;
		}

		public bool HasBuff(BuffDef buffType)
		{
			if ((bool)base.characterBody)
			{
				return base.characterBody.HasBuff(buffType);
			}
			return false;
		}

		public int GetBuffCount(BuffIndex buffType)
		{
			if (!base.characterBody)
			{
				return 0;
			}
			return base.characterBody.GetBuffCount(buffType);
		}

		public int GetBuffCount(BuffDef buffType)
		{
			if (!base.characterBody)
			{
				return 0;
			}
			return base.characterBody.GetBuffCount(buffType);
		}

		protected void AttemptToStartSprint()
		{
			if ((bool)base.inputBank)
			{
				base.inputBank.sprint.down = true;
			}
		}

		protected HitBoxGroup FindHitBoxGroup(string groupName)
		{
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return null;
			}
			HitBoxGroup result = null;
			List<HitBoxGroup> gameObjectComponents = GetComponentsCache<HitBoxGroup>.GetGameObjectComponents(modelTransform.gameObject);
			int i = 0;
			for (int count = gameObjectComponents.Count; i < count; i++)
			{
				if (gameObjectComponents[i].groupName == groupName)
				{
					result = gameObjectComponents[i];
					break;
				}
			}
			GetComponentsCache<HitBoxGroup>.ReturnBuffer(gameObjectComponents);
			return result;
		}
	}
	public class BasicMeleeAttack : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public string hitBoxGroupName;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float pushAwayForce;

		[SerializeField]
		public UnityEngine.Vector3 forceVector;

		[SerializeField]
		public float hitPauseDuration;

		[SerializeField]
		public GameObject swingEffectPrefab;

		[SerializeField]
		public string swingEffectMuzzleString;

		[SerializeField]
		public string mecanimHitboxActiveParameter;

		[SerializeField]
		public float shorthopVelocityFromHit;

		[SerializeField]
		public string beginStateSoundString;

		[SerializeField]
		public string beginSwingSoundString;

		[SerializeField]
		public NetworkSoundEventDef impactSound;

		[SerializeField]
		public bool forceForwardVelocity;

		[SerializeField]
		public AnimationCurve forwardVelocityCurve;

		[SerializeField]
		public bool scaleHitPauseDurationAndVelocityWithAttackSpeed;

		[SerializeField]
		public bool ignoreAttackSpeed;

		protected float duration;

		protected HitBoxGroup hitBoxGroup;

		protected Animator animator;

		private OverlapAttack overlapAttack;

		protected bool authorityHitThisFixedUpdate;

		protected float hitPauseTimer;

		protected UnityEngine.Vector3 storedHitPauseVelocity;

		private Run.FixedTimeStamp meleeAttackStartTime = Run.FixedTimeStamp.positiveInfinity;

		private GameObject swingEffectInstance;

		private int meleeAttackTicks;

		protected List<HurtBox> hitResults = new List<HurtBox>();

		private bool forceFire;

		protected EffectManagerHelper _emh_swingEffectInstance;

		protected bool authorityInHitPause => hitPauseTimer > 0f;

		private bool meleeAttackHasBegun => meleeAttackStartTime.hasPassed;

		protected bool authorityHasFiredAtAll => meleeAttackTicks > 0;

		protected bool isCritAuthority { get; private set; }

		protected virtual bool allowExitFire => true;

		public virtual string GetHitBoxGroupName()
		{
			return hitBoxGroupName;
		}

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			hitBoxGroup = null;
			animator = null;
			if (overlapAttack != null)
			{
				overlapAttack.Reset();
			}
			authorityHitThisFixedUpdate = false;
			hitPauseTimer = 0f;
			storedHitPauseVelocity = UnityEngine.Vector3.zero;
			meleeAttackStartTime = Run.FixedTimeStamp.positiveInfinity;
			swingEffectInstance = null;
			meleeAttackTicks = 0;
			forceFire = false;
			_emh_swingEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = CalcDuration();
			if (duration <= Time.fixedDeltaTime * 2f)
			{
				forceFire = true;
			}
			StartAimMode();
			Util.PlaySound(beginStateSoundString, base.gameObject);
			animator = GetModelAnimator();
			if (base.isAuthority)
			{
				isCritAuthority = RollCrit();
				hitBoxGroup = FindHitBoxGroup(GetHitBoxGroupName());
				if ((bool)hitBoxGroup)
				{
					overlapAttack = new OverlapAttack
					{
						attacker = base.gameObject,
						damage = damageCoefficient * damageStat,
						damageColorIndex = DamageColorIndex.Default,
						damageType = DamageType.Generic,
						forceVector = forceVector,
						hitBoxGroup = hitBoxGroup,
						hitEffectPrefab = hitEffectPrefab,
						impactSound = (impactSound?.index ?? NetworkSoundEventIndex.Invalid),
						inflictor = base.gameObject,
						isCrit = isCritAuthority,
						procChainMask = default(ProcChainMask),
						pushAwayForce = pushAwayForce,
						procCoefficient = procCoefficient,
						teamIndex = GetTeam()
					};
				}
			}
			PlayAnimation();
		}

		protected virtual float CalcDuration()
		{
			if (ignoreAttackSpeed)
			{
				return baseDuration;
			}
			return baseDuration / attackSpeedStat;
		}

		protected virtual void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (string.IsNullOrEmpty(mecanimHitboxActiveParameter))
			{
				BeginMeleeAttackEffect();
			}
			else if (animator.GetFloat(mecanimHitboxActiveParameter) > 0.5f)
			{
				BeginMeleeAttackEffect();
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		protected void AuthorityTriggerHitPause()
		{
			if ((bool)base.characterMotor)
			{
				storedHitPauseVelocity += base.characterMotor.velocity;
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			if ((bool)animator)
			{
				animator.speed = 0f;
			}
			if ((bool)swingEffectInstance)
			{
				ScaleParticleSystemDuration component = swingEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = 20f;
				}
			}
			hitPauseTimer = (scaleHitPauseDurationAndVelocityWithAttackSpeed ? (hitPauseDuration / attackSpeedStat) : hitPauseDuration);
		}

		protected virtual void BeginMeleeAttackEffect()
		{
			if (meleeAttackStartTime != Run.FixedTimeStamp.positiveInfinity)
			{
				return;
			}
			meleeAttackStartTime = Run.FixedTimeStamp.now;
			Util.PlaySound(beginSwingSoundString, base.gameObject);
			if (!swingEffectPrefab)
			{
				return;
			}
			Transform transform = FindModelChild(swingEffectMuzzleString);
			if ((bool)transform)
			{
				if (!EffectManager.ShouldUsePooledEffect(swingEffectPrefab))
				{
					swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, transform);
				}
				else
				{
					_emh_swingEffectInstance = EffectManager.GetAndActivatePooledEffect(swingEffectPrefab, transform, inResetLocal: true);
					swingEffectInstance = _emh_swingEffectInstance.gameObject;
				}
				ScaleParticleSystemDuration component = swingEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = component.initialDuration;
				}
			}
		}

		protected virtual void AuthorityExitHitPause()
		{
			hitPauseTimer = 0f;
			storedHitPauseVelocity.y = Mathf.Max(storedHitPauseVelocity.y, scaleHitPauseDurationAndVelocityWithAttackSpeed ? (shorthopVelocityFromHit / Mathf.Sqrt(attackSpeedStat)) : shorthopVelocityFromHit);
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = storedHitPauseVelocity;
			}
			storedHitPauseVelocity = UnityEngine.Vector3.zero;
			if ((bool)animator)
			{
				animator.speed = 1f;
			}
			if ((bool)swingEffectInstance)
			{
				ScaleParticleSystemDuration component = swingEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = component.initialDuration;
				}
			}
		}

		protected virtual void PlayAnimation()
		{
		}

		protected virtual void OnMeleeHitAuthority()
		{
		}

		private void AuthorityFireAttack()
		{
			AuthorityModifyOverlapAttack(overlapAttack);
			hitResults.Clear();
			authorityHitThisFixedUpdate = overlapAttack.Fire(hitResults);
			meleeAttackTicks++;
			if (authorityHitThisFixedUpdate)
			{
				AuthorityTriggerHitPause();
				OnMeleeHitAuthority();
			}
		}

		protected virtual void AuthorityFixedUpdate()
		{
			if (authorityInHitPause)
			{
				hitPauseTimer -= GetDeltaTime();
				if ((bool)base.characterMotor)
				{
					base.characterMotor.velocity = UnityEngine.Vector3.zero;
				}
				base.fixedAge -= GetDeltaTime();
				if (!authorityInHitPause)
				{
					AuthorityExitHitPause();
				}
			}
			else if (forceForwardVelocity && (bool)base.characterMotor && (bool)base.characterDirection)
			{
				UnityEngine.Vector3 vector = base.characterDirection.forward * forwardVelocityCurve.Evaluate(base.fixedAge / duration);
				_ = base.characterMotor.velocity;
				base.characterMotor.AddDisplacement(new UnityEngine.Vector3(vector.x, 0f, vector.z));
			}
			authorityHitThisFixedUpdate = false;
			if (overlapAttack != null && (string.IsNullOrEmpty(mecanimHitboxActiveParameter) || animator.GetFloat(mecanimHitboxActiveParameter) > 0.5f || forceFire))
			{
				AuthorityFireAttack();
			}
			if (duration <= base.fixedAge)
			{
				AuthorityOnFinish();
			}
		}

		public override void OnExit()
		{
			if (base.isAuthority)
			{
				if (!outer.destroying && !authorityHasFiredAtAll && allowExitFire)
				{
					BeginMeleeAttackEffect();
					AuthorityFireAttack();
				}
				if (authorityInHitPause)
				{
					AuthorityExitHitPause();
				}
			}
			if (_emh_swingEffectInstance != null && _emh_swingEffectInstance.OwningPool != null)
			{
				_emh_swingEffectInstance.OwningPool.ReturnObject(_emh_swingEffectInstance);
			}
			else if ((bool)swingEffectInstance)
			{
				EntityState.Destroy(swingEffectInstance);
			}
			swingEffectInstance = null;
			_emh_swingEffectInstance = null;
			if ((bool)animator)
			{
				animator.speed = 1f;
			}
			base.OnExit();
		}

		protected virtual void AuthorityOnFinish()
		{
			outer.SetNextStateToMain();
		}
	}
	public class BigCharacterMain : GenericCharacterMain
	{
		public override void ProcessJump()
		{
			if (base.characterMotor.jumpCount > base.characterBody.baseJumpCount)
			{
				base.ProcessJump();
			}
			else if (jumpInputReceived && base.characterMotor.isGrounded)
			{
				outer.SetNextState(new AnimatedJump());
			}
		}
	}
	public class AnimatedJump : BaseState
	{
		private float duration;

		private bool hasInputJump;

		public override void OnEnter()
		{
			base.OnEnter();
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				modelAnimator.CrossFadeInFixedTime("AnimatedJump", 0.25f);
				modelAnimator.Update(0f);
				duration = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length;
				AimAnimator component = modelAnimator.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = true;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration / 2f && base.isAuthority && !hasInputJump)
			{
				hasInputJump = true;
				base.characterMotor.moveDirection = base.inputBank.moveVector;
				GenericCharacterMain.ApplyJumpVelocity(base.characterMotor, base.characterBody, 1f, 1f);
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class CloakTest : BaseState
	{
		private float duration = 3f;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.Cloak);
				base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed);
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak);
				base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class EmotePoint : BaseState
	{
		public static float duration = 0.5f;

		private static int EmotePointStateHash = Animator.StringToHash("EmotePoint");

		private static int EmotePointplaybackRateParamHash = Animator.StringToHash("EmotePoint.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Gesture");
				modelAnimator.SetFloat(EmotePointplaybackRateParamHash, 1f);
				modelAnimator.PlayInFixedTime(EmotePointStateHash, layerIndex, 0f);
				modelAnimator.Update(0f);
				modelAnimator.SetFloat(EmotePointplaybackRateParamHash, attackSpeedStat);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public enum InterruptPriority
	{
		Any,
		Skill,
		PrioritySkill,
		Pain,
		Stun,
		Frozen,
		Vehicle,
		Death
	}
	public class EntityState
	{
		public EntityStateMachine outer;

		protected float age { get; set; }

		protected float fixedAge { get; set; }

		protected GameObject gameObject => outer.gameObject;

		protected bool isLocalPlayer
		{
			get
			{
				if ((bool)outer.networker)
				{
					return outer.networker.isLocalPlayer;
				}
				return false;
			}
		}

		protected bool localPlayerAuthority
		{
			get
			{
				if ((bool)outer.networker)
				{
					return outer.networker.localPlayerAuthority;
				}
				return false;
			}
		}

		protected bool isAuthority => Util.HasEffectiveAuthority(outer.networkIdentity);

		protected Transform transform => outer.commonComponents.transform;

		protected CharacterBody characterBody => outer.commonComponents.characterBody;

		protected CharacterMotor characterMotor => outer.commonComponents.characterMotor;

		protected CharacterDirection characterDirection => outer.commonComponents.characterDirection;

		protected Rigidbody rigidbody => outer.commonComponents.rigidbody;

		protected RigidbodyMotor rigidbodyMotor => outer.commonComponents.rigidbodyMotor;

		protected RigidbodyDirection rigidbodyDirection => outer.commonComponents.rigidbodyDirection;

		protected RailMotor railMotor => outer.commonComponents.railMotor;

		protected ModelLocator modelLocator => outer.commonComponents.modelLocator;

		protected InputBankTest inputBank => outer.commonComponents.inputBank;

		protected TeamComponent teamComponent => outer.commonComponents.teamComponent;

		protected HealthComponent healthComponent => outer.commonComponents.healthComponent;

		protected SkillLocator skillLocator => outer.commonComponents.skillLocator;

		protected CharacterEmoteDefinitions characterEmoteDefinitions => outer.commonComponents.characterEmoteDefinitions;

		protected CameraTargetParams cameraTargetParams => outer.commonComponents.cameraTargetParams;

		protected SfxLocator sfxLocator => outer.commonComponents.sfxLocator;

		protected BodyAnimatorSmoothingParameters bodyAnimatorSmoothingParameters => outer.commonComponents.bodyAnimatorSmoothingParameters;

		protected ProjectileController projectileController => outer.commonComponents.projectileController;

		public void ClearEntityStateMachine()
		{
			outer = null;
		}

		public EntityState()
		{
			EntityStateCatalog.InitializeStateFields(this);
		}

		public virtual void OnEnter()
		{
		}

		public virtual void OnExit()
		{
		}

		public virtual void ModifyNextState(EntityState nextState)
		{
		}

		public virtual void Update()
		{
			age += Time.deltaTime;
		}

		public virtual void FixedUpdate()
		{
			fixedAge += GetDeltaTime();
		}

		protected float GetDeltaTime()
		{
			return Time.fixedDeltaTime;
		}

		public virtual void OnSerialize(NetworkWriter writer)
		{
		}

		public virtual void OnDeserialize(NetworkReader reader)
		{
		}

		public virtual InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}

		public virtual void Reset()
		{
			ClearEntityStateMachine();
			age = 0f;
			fixedAge = 0f;
		}

		public void SetAIUpdateFrequency(bool alwaysUpdate)
		{
			if ((bool)characterBody && (bool)characterBody.master)
			{
				characterBody.master.SetAIUpdateFrequency(alwaysUpdate);
			}
		}

		protected static void Destroy(UnityEngine.Object obj)
		{
			UnityEngine.Object.Destroy(obj);
		}

		protected T GetComponent<T>() where T : Component
		{
			return outer.GetComponent<T>();
		}

		protected Component GetComponent(Type type)
		{
			return outer.GetComponent(type);
		}

		protected Component GetComponent(string type)
		{
			return outer.GetComponent(type);
		}

		protected Transform GetModelBaseTransform()
		{
			if (!modelLocator)
			{
				return null;
			}
			return modelLocator.modelBaseTransform;
		}

		protected Transform GetModelTransform()
		{
			if (!modelLocator)
			{
				return null;
			}
			return modelLocator.modelTransform;
		}

		protected AimAnimator GetAimAnimator()
		{
			if ((bool)modelLocator && (bool)modelLocator.modelTransform)
			{
				return modelLocator.modelTransform.GetComponent<AimAnimator>();
			}
			return null;
		}

		protected Animator GetModelAnimator()
		{
			if ((bool)modelLocator && (bool)modelLocator.modelTransform)
			{
				return modelLocator.modelTransform.GetComponent<Animator>();
			}
			return null;
		}

		protected ChildLocator GetModelChildLocator()
		{
			if ((bool)modelLocator && (bool)modelLocator.modelTransform)
			{
				return modelLocator.modelTransform.GetComponent<ChildLocator>();
			}
			return null;
		}

		protected RootMotionAccumulator GetModelRootMotionAccumulator()
		{
			if ((bool)modelLocator && (bool)modelLocator.modelTransform)
			{
				return modelLocator.modelTransform.GetComponent<RootMotionAccumulator>();
			}
			return null;
		}

		protected void PlayAnimation(string layerName, string animationStateName, string playbackRateParam, float duration, float transition = 0f)
		{
			if (duration <= 0f)
			{
				UnityEngine.Debug.LogWarningFormat("EntityState.PlayAnimation: Zero duration is not allowed. type={0}", GetType().Name);
				return;
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayAnimationOnAnimator(modelAnimator, layerName, animationStateName, playbackRateParam, duration, transition);
			}
		}

		protected void PlayAnimation(string layerName, int animationStateHash, int playbackRateParamHash, float duration)
		{
			if (duration <= 0f)
			{
				UnityEngine.Debug.LogWarningFormat("EntityState.PlayAnimation: Zero duration is not allowed. type={0}", GetType().Name);
				return;
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex(layerName);
				if (layerIndex >= 0)
				{
					PlayAnimationOnAnimator(modelAnimator, layerIndex, animationStateHash, playbackRateParamHash, duration);
				}
			}
		}

		protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, string animationStateName, string playbackRateParam, float duration, float transition = 0f)
		{
			modelAnimator.speed = 1f;
			modelAnimator.Update(0f);
			int layerIndex = modelAnimator.GetLayerIndex(layerName);
			if (layerIndex >= 0)
			{
				if (!string.IsNullOrEmpty(playbackRateParam))
				{
					modelAnimator.SetFloat(playbackRateParam, 1f);
				}
				if (transition > 0f)
				{
					modelAnimator.CrossFadeInFixedTime(animationStateName, transition, layerIndex);
				}
				else
				{
					modelAnimator.PlayInFixedTime(animationStateName, layerIndex, 0f);
				}
				modelAnimator.Update(0f);
				float length = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length;
				if (!string.IsNullOrEmpty(playbackRateParam))
				{
					modelAnimator.SetFloat(playbackRateParam, length / duration);
				}
			}
		}

		protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, int animationStateHash, int playbackRateParamHash, float duration)
		{
			int layerIndex = modelAnimator.GetLayerIndex(layerName);
			if (layerIndex >= 0)
			{
				PlayAnimationOnAnimator(modelAnimator, layerIndex, animationStateHash, playbackRateParamHash, duration);
			}
		}

		protected static void PlayAnimationOnAnimator(Animator modelAnimator, int layerIndex, int animationStateHash, int playbackRateParamHash, float duration)
		{
			modelAnimator.speed = 1f;
			modelAnimator.Update(0f);
			if (layerIndex >= 0)
			{
				modelAnimator.SetFloat(playbackRateParamHash, 1f);
				modelAnimator.PlayInFixedTime(animationStateHash, layerIndex, 0f);
				modelAnimator.Update(0f);
				float length = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length;
				modelAnimator.SetFloat(playbackRateParamHash, length / duration);
			}
		}

		protected void PlayCrossfade(string layerName, string animationStateName, string playbackRateParam, float duration, float crossfadeDuration)
		{
			if (duration <= 0f)
			{
				UnityEngine.Debug.LogWarningFormat("EntityState.PlayCrossfade: Zero duration is not allowed. type={0}", GetType().Name);
				return;
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.speed = 1f;
				modelAnimator.Update(0f);
				int layerIndex = modelAnimator.GetLayerIndex(layerName);
				modelAnimator.SetFloat(playbackRateParam, 1f);
				modelAnimator.CrossFadeInFixedTime(animationStateName, crossfadeDuration, layerIndex);
				modelAnimator.Update(0f);
				float length = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length;
				modelAnimator.SetFloat(playbackRateParam, length / duration);
			}
		}

		protected void PlayCrossfade(string layerName, int animationStateNameHash, int playbackRateParamHash, float duration, float crossfadeDuration)
		{
			if (duration <= 0f)
			{
				UnityEngine.Debug.LogWarningFormat("EntityState.PlayCrossfade: Zero duration is not allowed. type={0}", GetType().Name);
				return;
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.speed = 1f;
				modelAnimator.Update(0f);
				int layerIndex = modelAnimator.GetLayerIndex(layerName);
				modelAnimator.SetFloat(playbackRateParamHash, 1f);
				modelAnimator.CrossFadeInFixedTime(animationStateNameHash, crossfadeDuration, layerIndex);
				modelAnimator.Update(0f);
				float length = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length;
				modelAnimator.SetFloat(playbackRateParamHash, length / duration);
			}
		}

		protected void PlayCrossfade(string layerName, string animationStateName, float crossfadeDuration)
		{
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.speed = 1f;
				modelAnimator.Update(0f);
				int layerIndex = modelAnimator.GetLayerIndex(layerName);
				modelAnimator.CrossFadeInFixedTime(animationStateName, crossfadeDuration, layerIndex);
			}
		}

		protected void PlayCrossfade(string layerName, int animationStateHash, float crossfadeDuration)
		{
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.speed = 1f;
				modelAnimator.Update(0f);
				int layerIndex = modelAnimator.GetLayerIndex(layerName);
				modelAnimator.CrossFadeInFixedTime(animationStateHash, crossfadeDuration, layerIndex);
			}
		}

		public virtual void PlayAnimation(string layerName, string animationStateName)
		{
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayAnimationOnAnimator(modelAnimator, layerName, animationStateName);
			}
		}

		public virtual void PlayAnimation(string layerName, int animationStateHash)
		{
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayAnimationOnAnimator(modelAnimator, layerName, animationStateHash);
			}
		}

		public virtual void SetPingable(bool value)
		{
			if ((bool)outer && (bool)outer.networkIdentity)
			{
				outer.networkIdentity.isPingable = value;
			}
		}

		protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, string animationStateName)
		{
			int layerIndex = modelAnimator.GetLayerIndex(layerName);
			modelAnimator.speed = 1f;
			modelAnimator.Update(0f);
			modelAnimator.PlayInFixedTime(animationStateName, layerIndex, 0f);
		}

		protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, int animationStateHash)
		{
			int layerIndex = modelAnimator.GetLayerIndex(layerName);
			modelAnimator.speed = 1f;
			modelAnimator.Update(0f);
			modelAnimator.PlayInFixedTime(animationStateHash, layerIndex, 0f);
		}

		protected void GetBodyAnimatorSmoothingParameters(out BodyAnimatorSmoothingParameters.SmoothingParameters smoothingParameters)
		{
			if ((bool)bodyAnimatorSmoothingParameters)
			{
				smoothingParameters = bodyAnimatorSmoothingParameters.smoothingParameters;
			}
			else
			{
				smoothingParameters = BodyAnimatorSmoothingParameters.defaultParameters;
			}
		}
	}
	[Serializable]
	public struct SerializableEntityStateType
	{
		private Type _stateType;

		[SerializeField]
		private string _typeName;

		public string typeName
		{
			get
			{
				return _typeName;
			}
			private set
			{
				stateType = Type.GetType(value);
			}
		}

		public Type stateType
		{
			get
			{
				if (_stateType == null)
				{
					CacheStateType();
					return _stateType;
				}
				return _stateType;
			}
			set
			{
				_typeName = ((value != null && value.IsSubclassOf(typeof(EntityState))) ? value.AssemblyQualifiedName : "");
			}
		}

		public SerializableEntityStateType(string typeName)
		{
			_typeName = "";
			_stateType = null;
			this.typeName = typeName;
		}

		public SerializableEntityStateType(Type stateType)
		{
			_typeName = "";
			_stateType = null;
			this.stateType = stateType;
		}

		private void CacheStateType()
		{
			if (_typeName != null)
			{
				Type type = Type.GetType(_typeName);
				_stateType = ((type != null && type.IsSubclassOf(typeof(EntityState))) ? type : null);
			}
		}
	}
	public interface ISkillOverrideHandoff
	{
		void TransferSkillOverride(SkillStateOverrideData skillOverrideData);
	}
	public class SkillStateOverrideData
	{
		private object source;

		public bool duplicateStock;

		public bool overrideFullReloadOnAssign;

		public bool simulateRestockForOverridenSkills = true;

		private static GenericSkill.SkillOverridePriority priority = GenericSkill.SkillOverridePriority.Contextual;

		private float overrideTimestamp;

		public SkillDef primarySkillOverride;

		public SkillDef secondarySkillOverride;

		public SkillDef utilitySkillOverride;

		public SkillDef specialSkillOverride;

		private GenericSkill primarySkillOriginal;

		private GenericSkill secondarySkillOriginal;

		private GenericSkill utilitySkillOriginal;

		private GenericSkill specialSkillOriginal;

		public int previousPrimaryStock = -1;

		public int previousSecondaryStock = -1;

		public int previousUtilityStock = -1;

		public int previousSpecialStock = -1;

		public bool hasAuthority { get; private set; }

		public SkillStateOverrideData(CharacterBody sourceBody)
		{
			source = sourceBody;
			hasAuthority = Util.HasEffectiveAuthority(sourceBody.gameObject);
			duplicateStock = false;
		}

		public SkillStateOverrideData(CharacterBody sourceBody, bool _duplicateStock)
		{
			source = sourceBody;
			hasAuthority = Util.HasEffectiveAuthority(sourceBody.gameObject);
			duplicateStock = _duplicateStock;
		}

		public void OverrideSkills(SkillLocator skillLocator)
		{
			if (hasAuthority && !(skillLocator == null))
			{
				overrideTimestamp = Time.time;
				InternalOverride(skillLocator.primary, ref primarySkillOverride, ref primarySkillOriginal, ref previousPrimaryStock);
				InternalOverride(skillLocator.secondary, ref secondarySkillOverride, ref secondarySkillOriginal, ref previousSecondaryStock);
				InternalOverride(skillLocator.utility, ref utilitySkillOverride, ref utilitySkillOriginal, ref previousUtilityStock);
				InternalOverride(skillLocator.special, ref specialSkillOverride, ref specialSkillOriginal, ref previousSpecialStock);
			}
		}

		private void InternalOverride(GenericSkill existingSkillToOverride, ref SkillDef overridingSkill, ref GenericSkill originalSkill, ref int previousStockAmount)
		{
			if (!(overridingSkill == null) && !(existingSkillToOverride == null) && !(existingSkillToOverride == originalSkill) && !existingSkillToOverride.HasSkillOverrideOfPriority(priority))
			{
				int stock = existingSkillToOverride.stock;
				previousStockAmount = -1;
				originalSkill = existingSkillToOverride;
				originalSkill.SetSkillOverride(source, overridingSkill, priority);
				if (duplicateStock)
				{
					originalSkill.stock = stock;
				}
			}
		}

		public void ClearOverrides()
		{
			if (hasAuthority && source != null)
			{
				InternalClearOverride(ref primarySkillOriginal, ref primarySkillOverride, ref previousPrimaryStock);
				InternalClearOverride(ref secondarySkillOriginal, ref secondarySkillOverride, ref previousSecondaryStock);
				InternalClearOverride(ref utilitySkillOriginal, ref utilitySkillOverride, ref previousUtilityStock);
				InternalClearOverride(ref specialSkillOriginal, ref specialSkillOverride, ref previousSpecialStock);
			}
			void InternalClearOverride(ref GenericSkill overriddenSkill, ref SkillDef skillDef, ref int previousStockAmount)
			{
				if (!(overriddenSkill == null) && !(skillDef == null) && overriddenSkill.HasSkillOverrideOfPriority(priority))
				{
					int baseStock = overriddenSkill.GetBaseStock();
					int stock = overriddenSkill.stock;
					float rechargeStopwatch = overriddenSkill.rechargeStopwatch;
					overriddenSkill.UnsetSkillOverride(source, skillDef, priority);
					if (overrideFullReloadOnAssign && overriddenSkill.skillDef.fullRestockOnAssign)
					{
						overriddenSkill.stock = baseStock;
					}
					if (simulateRestockForOverridenSkills)
					{
						overriddenSkill.RechargeBaseSkill(Time.time - overrideTimestamp);
					}
					previousStockAmount = -1;
					if (duplicateStock)
					{
						overriddenSkill.baseStock = stock;
						overriddenSkill.baseRechargeStopwatch = rechargeStopwatch;
					}
				}
			}
		}

		public void StepRestock()
		{
			float time2 = Time.time;
			if (!(time2 <= overrideTimestamp))
			{
				InternalRestock(time2, ref primarySkillOriginal);
				InternalRestock(time2, ref secondarySkillOriginal);
				InternalRestock(time2, ref utilitySkillOriginal);
				InternalRestock(time2, ref specialSkillOriginal);
				overrideTimestamp = time2;
			}
			void InternalRestock(float time, ref GenericSkill overridenSkill)
			{
				if (!(overridenSkill == null))
				{
					overridenSkill.RechargeBaseSkill(time - overrideTimestamp);
				}
			}
		}
	}
	public class FlyState : BaseState
	{
		private Animator modelAnimator;

		private bool skill1InputReceived;

		private bool skill2InputReceived;

		private bool skill3InputReceived;

		private bool skill4InputReceived;

		private static int IdleStateHash = Animator.StringToHash("Idle");

		private bool hasPivotPitchLayer;

		private bool hasPivotYawLayer;

		private bool hasPivotRollLayer;

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

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

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

		private static readonly int flyRate = Animator.StringToHash("fly.rate");

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			PlayAnimation("Body", IdleStateHash);
			if ((bool)modelAnimator)
			{
				hasPivotPitchLayer = modelAnimator.GetLayerIndex("PivotPitch") != -1;
				hasPivotYawLayer = modelAnimator.GetLayerIndex("PivotYaw") != -1;
				hasPivotRollLayer = modelAnimator.GetLayerIndex("PivotRoll") != -1;
			}
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.rigidbodyDirection)
			{
				UnityEngine.Quaternion rotation = base.transform.rotation;
				UnityEngine.Quaternion quaternion = Util.QuaternionSafeLookRotation(base.rigidbodyDirection.aimDirection);
				UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.Inverse(rotation) * quaternion;
				if ((bool)modelAnimator)
				{
					float deltaTime = GetDeltaTime();
					if (hasPivotPitchLayer)
					{
						modelAnimator.SetFloat(pivotPitchCycle, Mathf.Clamp01(Util.Remap(quaternion2.x * Mathf.Sign(quaternion2.w), -1f, 1f, 0f, 1f)), 1f, deltaTime);
					}
					if (hasPivotYawLayer)
					{
						modelAnimator.SetFloat(pivotYawCycle, Mathf.Clamp01(Util.Remap(quaternion2.y * Mathf.Sign(quaternion2.w), -1f, 1f, 0f, 1f)), 1f, deltaTime);
					}
					if (hasPivotRollLayer)
					{
						modelAnimator.SetFloat(pivotRollCycle, Mathf.Clamp01(Util.Remap(quaternion2.z * Mathf.Sign(quaternion2.w), -1f, 1f, 0f, 1f)), 1f, deltaTime);
					}
				}
			}
			PerformInputs();
		}

		protected virtual bool CanExecuteSkill(GenericSkill skillSlot)
		{
			return true;
		}

		protected virtual void PerformInputs()
		{
			if (!base.isAuthority)
			{
				return;
			}
			if ((bool)base.inputBank)
			{
				if ((bool)base.rigidbodyMotor)
				{
					base.rigidbodyMotor.moveVector = base.inputBank.moveVector * base.characterBody.moveSpeed;
					if ((bool)modelAnimator)
					{
						modelAnimator.SetFloat(flyRate, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity));
					}
				}
				if ((bool)base.rigidbodyDirection)
				{
					base.rigidbodyDirection.aimDirection = GetAimRay().direction;
				}
				skill1InputReceived = base.inputBank.skill1.down;
				skill2InputReceived = base.inputBank.skill2.down;
				skill3InputReceived = base.inputBank.skill3.down;
				skill4InputReceived = base.inputBank.skill4.down;
			}
			if ((bool)base.skillLocator)
			{
				if (skill1InputReceived && (bool)base.skillLocator.primary && CanExecuteSkill(base.skillLocator.primary))
				{
					base.skillLocator.primary.ExecuteIfReady();
				}
				if (skill2InputReceived && (bool)base.skillLocator.secondary && CanExecuteSkill(base.skillLocator.secondary))
				{
					base.skillLocator.secondary.ExecuteIfReady();
				}
				if (skill3InputReceived && (bool)base.skillLocator.utility && CanExecuteSkill(base.skillLocator.utility))
				{
					base.skillLocator.utility.ExecuteIfReady();
				}
				if (skill4InputReceived && (bool)base.skillLocator.special && CanExecuteSkill(base.skillLocator.special))
				{
					base.skillLocator.special.ExecuteIfReady();
				}
			}
		}
	}
	public class FrozenState : BaseState
	{
		private float duration;

		private Animator modelAnimator;

		private TemporaryOverlayInstance temporaryOverlay;

		public float freezeDuration = 0.35f;

		public static GameObject frozenEffectPrefab;

		public static GameObject executeEffectPrefab;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				CharacterModel component = modelTransform.GetComponent<CharacterModel>();
				if ((bool)component)
				{
					temporaryOverlay = TemporaryOverlayManager.AddOverlay(base.gameObject);
					temporaryOverlay.duration = freezeDuration;
					temporaryOverlay.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matIsFrozen");
					temporaryOverlay.AddToCharacterModel(component);
				}
			}
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.enabled = false;
				duration = freezeDuration;
				EffectManager.SpawnEffect(frozenEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = (base.characterBody ? base.characterBody.radius : 1f)
				}, transmit: false);
			}
			if ((bool)base.rigidbody && !base.rigidbody.isKinematic)
			{
				base.rigidbody.velocity = UnityEngine.Vector3.zero;
				if ((bool)base.rigidbodyMotor)
				{
					base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
				}
			}
			base.healthComponent.isInFrozenState = true;
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
		}

		public override void OnExit()
		{
			if ((bool)modelAnimator)
			{
				modelAnimator.enabled = true;
			}
			if (temporaryOverlay != null)
			{
				temporaryOverlay.Destroy();
				temporaryOverlay = null;
			}
			EffectManager.SpawnEffect(frozenEffectPrefab, new EffectData
			{
				origin = base.characterBody.corePosition,
				scale = (base.characterBody ? base.characterBody.radius : 1f)
			}, transmit: false);
			base.healthComponent.isInFrozenState = false;
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public abstract class GenericBulletBaseState : BaseState
	{
		[SerializeField]
		public float baseDuration = 0.1f;

		[SerializeField]
		public int bulletCount = 1;

		[SerializeField]
		public float maxDistance = 50f;

		[SerializeField]
		public float bulletRadius;

		[SerializeField]
		public bool useSmartCollision;

		[SerializeField]
		public float damageCoefficient = 0.1f;

		[SerializeField]
		public float procCoefficient = 1f;

		[SerializeField]
		public float force = 100f;

		[SerializeField]
		public float minSpread;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public float spreadPitchScale = 0.5f;

		[SerializeField]
		public float spreadYawScale = 1f;

		[SerializeField]
		public float spreadBloomValue = 0.2f;

		[SerializeField]
		public float recoilAmplitudeY;

		[SerializeField]
		public float recoilAmplitudeX;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string fireSoundString;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public GameObject tracerEffectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		protected float duration;

		protected Transform muzzleTransform;

		protected BulletAttack GenerateBulletAttack(Ray aimRay)
		{
			float num = 0f;
			if ((bool)base.characterBody)
			{
				num = base.characterBody.spreadBloomAngle;
			}
			return new BulletAttack
			{
				aimVector = aimRay.direction,
				origin = aimRay.origin,
				owner = base.gameObject,
				weapon = null,
				bulletCount = (uint)bulletCount,
				damage = damageStat * damageCoefficient,
				damageColorIndex = DamageColorIndex.Default,
				damageType = DamageType.Generic,
				falloffModel = BulletAttack.FalloffModel.Buckshot,
				force = force,
				HitEffectNormal = false,
				procChainMask = default(ProcChainMask),
				procCoefficient = procCoefficient,
				maxDistance = maxDistance,
				radius = bulletRadius,
				isCrit = RollCrit(),
				muzzleName = muzzleName,
				minSpread = minSpread,
				maxSpread = maxSpread + num,
				hitEffectPrefab = hitEffectPrefab,
				smartCollision = useSmartCollision,
				sniper = false,
				spreadPitchScale = spreadPitchScale,
				spreadYawScale = spreadYawScale,
				tracerEffectPrefab = tracerEffectPrefab
			};
		}

		protected virtual void PlayFireAnimation()
		{
		}

		protected virtual void DoFireEffects()
		{
			Util.PlaySound(fireSoundString, base.gameObject);
			if ((bool)muzzleTransform)
			{
				EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			}
		}

		protected virtual void ModifyBullet(BulletAttack bulletAttack)
		{
		}

		protected virtual void FireBullet(Ray aimRay)
		{
			StartAimMode(aimRay, 3f);
			DoFireEffects();
			PlayFireAnimation();
			AddRecoil(-1f * recoilAmplitudeY, -1.5f * recoilAmplitudeY, -1f * recoilAmplitudeX, 1f * recoilAmplitudeX);
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = GenerateBulletAttack(aimRay);
				ModifyBullet(bulletAttack);
				bulletAttack.Fire();
				OnFireBulletAuthority(aimRay);
			}
		}

		protected virtual void OnFireBulletAuthority(Ray aimRay)
		{
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			muzzleTransform = FindModelChild(muzzleName);
			FireBullet(GetAimRay());
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(InstantiateNextState());
			}
		}

		protected virtual EntityState InstantiateNextState()
		{
			return EntityStateCatalog.InstantiateState(ref outer.mainStateType);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class GenericCharacterDeath : BaseState
	{
		private static readonly float bodyPreservationDuration = 1f;

		private static readonly float hardCutoffDuration = 10f;

		private static readonly float maxFallDuration = 4f;

		private static readonly float minTimeToKeepBodyForNetworkMessages = 0.5f;

		public static GameObject voidDeathEffect;

		private float restStopwatch;

		private float fallingStopwatch;

		private bool bodyMarkedForDestructionServer;

		private CameraTargetParams.AimRequest aimRequest;

		protected Transform cachedModelTransform { get; private set; }

		protected bool isBrittle { get; private set; }

		protected bool isVoidDeath { get; private set; }

		protected bool isPlayerDeath { get; private set; }

		protected virtual bool shouldAutoDestroy => true;

		protected virtual float GetDeathAnimationCrossFadeDuration()
		{
			return 0.1f;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			bodyMarkedForDestructionServer = false;
			cachedModelTransform = (base.modelLocator ? base.modelLocator.modelTransform : null);
			isBrittle = (bool)base.characterBody && base.characterBody.isGlass;
			isVoidDeath = (bool)base.healthComponent && (ulong)(base.healthComponent.killingDamageType & DamageType.VoidDeath) != 0;
			isPlayerDeath = (bool)base.characterBody.master && base.characterBody.master.GetComponent<PlayerCharacterMasterController>() != null;
			if (isVoidDeath)
			{
				if ((bool)base.characterBody && base.isAuthority)
				{
					EffectManager.SpawnEffect(voidDeathEffect, new EffectData
					{
						origin = base.characterBody.corePosition,
						scale = base.characterBody.bestFitRadius
					}, transmit: true);
				}
				if ((bool)cachedModelTransform)
				{
					EntityState.Destroy(cachedModelTransform.gameObject);
					cachedModelTransform = null;
				}
			}
			if (isPlayerDeath && (bool)base.characterBody)
			{
				UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/TemporaryVisualEffects/PlayerDeathEffect"), base.characterBody.corePosition, UnityEngine.Quaternion.identity).GetComponent<LocalCameraEffect>().targetCharacter = base.characterBody.gameObject;
			}
			if ((bool)cachedModelTransform)
			{
				if (isBrittle)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(cachedModelTransform.gameObject);
					temporaryOverlayInstance.duration = 0.5f;
					temporaryOverlayInstance.destroyObjectOnEnd = true;
					temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matShatteredGlass");
					temporaryOverlayInstance.destroyEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/BrittleDeath");
					temporaryOverlayInstance.destroyEffectChildString = "Chest";
					temporaryOverlayInstance.inspectorCharacterModel = cachedModelTransform.gameObject.GetComponent<CharacterModel>();
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
					temporaryOverlayInstance.animateShaderAlpha = true;
					temporaryOverlayInstance.transmit = false;
				}
				if ((bool)base.cameraTargetParams)
				{
					ChildLocator component = cachedModelTransform.GetComponent<ChildLocator>();
					if ((bool)component)
					{
						Transform transform = component.FindChild("Chest");
						if ((bool)transform)
						{
							base.cameraTargetParams.cameraPivotTransform = transform;
							aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
							base.cameraTargetParams.dontRaycastToPivot = true;
						}
					}
				}
			}
			if (!isVoidDeath)
			{
				PlayDeathSound();
				PlayDeathAnimation();
				CreateDeathEffects();
			}
		}

		protected virtual void PlayDeathSound()
		{
			if ((bool)base.sfxLocator && base.sfxLocator.deathSound != "")
			{
				Util.PlaySound(base.sfxLocator.deathSound, base.gameObject);
			}
		}

		protected virtual void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.CrossFadeInFixedTime("Death", crossfadeDuration);
			}
		}

		protected virtual void CreateDeathEffects()
		{
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!NetworkServer.active)
			{
				return;
			}
			bool flag = false;
			bool flag2 = true;
			if ((bool)base.characterMotor)
			{
				flag = base.characterMotor.isGrounded;
				flag2 = base.characterMotor.atRest;
			}
			else if ((bool)base.rigidbodyMotor)
			{
				flag = false;
				flag2 = false;
			}
			float deltaTime = GetDeltaTime();
			fallingStopwatch = (flag ? 0f : (fallingStopwatch + deltaTime));
			restStopwatch = ((!flag2) ? 0f : (restStopwatch + deltaTime));
			if (!(base.fixedAge >= minTimeToKeepBodyForNetworkMessages))
			{
				return;
			}
			if (!bodyMarkedForDestructionServer)
			{
				if ((restStopwatch >= bodyPreservationDuration || fallingStopwatch >= maxFallDuration || base.fixedAge > hardCutoffDuration) && shouldAutoDestroy)
				{
					DestroyBodyAsapServer();
				}
			}
			else
			{
				OnPreDestroyBodyServer();
				EntityState.Destroy(base.gameObject);
			}
		}

		protected void DestroyBodyAsapServer()
		{
			bodyMarkedForDestructionServer = true;
		}

		protected virtual void OnPreDestroyBodyServer()
		{
		}

		protected void DestroyModel()
		{
			if ((bool)cachedModelTransform)
			{
				EntityState.Destroy(cachedModelTransform.gameObject);
				cachedModelTransform = null;
			}
		}

		public override void OnExit()
		{
			aimRequest?.Dispose();
			if (shouldAutoDestroy && fallingStopwatch >= maxFallDuration)
			{
				DestroyModel();
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class GenericCharacterMain : BaseCharacterMain
	{
		public delegate void MovementHitDelegate(ref CharacterMotor.MovementHitInfo movementHitInfo);

		private AimAnimator aimAnimator;

		protected bool jumpInputReceived;

		protected bool sprintInputReceived;

		private UnityEngine.Vector3 moveVector = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 aimDirection = UnityEngine.Vector3.forward;

		private int emoteRequest = -1;

		private bool hasAimAnimator;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				aimAnimator = modelTransform.GetComponent<AimAnimator>();
				if ((bool)aimAnimator)
				{
					aimAnimator.enabled = true;
				}
			}
			hasAimAnimator = aimAnimator;
		}

		public override void OnExit()
		{
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = false;
				}
			}
			if (base.isAuthority)
			{
				if ((bool)base.characterMotor)
				{
					base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
				}
				if ((bool)base.railMotor)
				{
					base.railMotor.inputMoveVector = UnityEngine.Vector3.zero;
				}
			}
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			GatherInputs();
			HandleMovements();
			PerformInputs();
		}

		public virtual void HandleMovements()
		{
			if (useRootMotion)
			{
				if (hasCharacterMotor)
				{
					base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
				}
				if (hasRailMotor)
				{
					base.railMotor.inputMoveVector = moveVector;
				}
			}
			else
			{
				if (hasCharacterMotor)
				{
					base.characterMotor.moveDirection = moveVector;
				}
				if (hasRailMotor)
				{
					base.railMotor.inputMoveVector = moveVector;
				}
			}
			_ = base.isGrounded;
			if (!hasRailMotor && hasCharacterDirection && hasCharacterBody)
			{
				if (hasAimAnimator && aimAnimator.aimType == AimAnimator.AimType.Smart)
				{
					UnityEngine.Vector3 vector = ((moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : moveVector);
					float num = UnityEngine.Vector3.Angle(aimDirection, vector);
					float num2 = Mathf.Max(aimAnimator.pitchRangeMax + aimAnimator.pitchGiveupRange, aimAnimator.yawRangeMax + aimAnimator.yawGiveupRange);
					base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim && num > num2) ? aimDirection : vector);
				}
				else
				{
					base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim) ? aimDirection : moveVector);
				}
			}
			if (!base.isAuthority)
			{
				return;
			}
			ProcessJump();
			if (hasCharacterBody)
			{
				bool isSprinting = sprintInputReceived;
				if (moveVector.magnitude <= 0.5f)
				{
					isSprinting = false;
				}
				base.characterBody.isSprinting = isSprinting;
			}
		}

		public static void ApplyJumpVelocity(CharacterMotor characterMotor, CharacterBody characterBody, float horizontalBonus, float verticalBonus, bool vault = false)
		{
			UnityEngine.Vector3 moveDirection = characterMotor.moveDirection;
			if (vault)
			{
				characterMotor.velocity = moveDirection;
			}
			else
			{
				moveDirection.y = 0f;
				float magnitude = moveDirection.magnitude;
				if (magnitude > 0f)
				{
					moveDirection /= magnitude;
				}
				UnityEngine.Vector3 velocity = moveDirection * characterBody.moveSpeed * horizontalBonus;
				velocity.y = characterBody.jumpPower * verticalBonus;
				characterMotor.velocity = velocity;
			}
			characterMotor.Motor.ForceUnground();
		}

		public virtual void ProcessJump()
		{
			if (!hasCharacterMotor)
			{
				return;
			}
			bool flag = false;
			bool flag2 = false;
			if (!jumpInputReceived || !base.characterBody || base.characterMotor.jumpCount >= base.characterBody.maxJumpCount)
			{
				return;
			}
			int itemCount = base.characterBody.inventory.GetItemCount(RoR2Content.Items.JumpBoost);
			float horizontalBonus = 1f;
			float verticalBonus = 1f;
			if (base.characterMotor.jumpCount >= base.characterBody.baseJumpCount)
			{
				flag = true;
				horizontalBonus = 1.5f;
				verticalBonus = 1.5f;
			}
			else if ((float)itemCount > 0f && base.characterBody.isSprinting)
			{
				float num = base.characterBody.acceleration * base.characterMotor.airControl;
				if (base.characterBody.moveSpeed > 0f && num > 0f)
				{
					flag2 = true;
					float num2 = Mathf.Sqrt(10f * (float)itemCount / num);
					float num3 = base.characterBody.moveSpeed / num;
					horizontalBonus = (num2 + num3) / num3;
				}
			}
			ApplyJumpVelocity(base.characterMotor, base.characterBody, horizontalBonus, verticalBonus);
			if (hasModelAnimator)
			{
				int layerIndex = base.modelAnimator.GetLayerIndex("Body");
				if (layerIndex >= 0)
				{
					if (base.characterMotor.jumpCount == 0 || base.characterBody.baseJumpCount == 1)
					{
						base.modelAnimator.CrossFadeInFixedTime("Jump", smoothingParameters.intoJumpTransitionTime, layerIndex);
					}
					else
					{
						base.modelAnimator.CrossFadeInFixedTime("BonusJump", smoothingParameters.intoJumpTransitionTime, layerIndex);
					}
				}
			}
			if (flag)
			{
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/FeatherEffect"), new EffectData
				{
					origin = base.characterBody.footPosition
				}, transmit: true);
			}
			else if (base.characterMotor.jumpCount > 0)
			{
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/CharacterLandImpact"), new EffectData
				{
					origin = base.characterBody.footPosition,
					scale = base.characterBody.radius
				}, transmit: true);
			}
			if (flag2)
			{
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/BoostJumpEffect"), new EffectData
				{
					origin = base.characterBody.footPosition,
					rotation = Util.QuaternionSafeLookRotation(base.characterMotor.velocity)
				}, transmit: true);
			}
			base.characterMotor.jumpCount++;
			base.characterBody.onJump?.Invoke();
		}

		protected virtual bool CanExecuteSkill(GenericSkill skillSlot)
		{
			return true;
		}

		protected void PerformInputs()
		{
			if (base.isAuthority)
			{
				if (hasSkillLocator)
				{
					HandleSkill(base.skillLocator.primary, ref base.inputBank.skill1);
					HandleSkill(base.skillLocator.secondary, ref base.inputBank.skill2);
					HandleSkill(base.skillLocator.utility, ref base.inputBank.skill3);
					HandleSkill(base.skillLocator.special, ref base.inputBank.skill4);
				}
				jumpInputReceived = false;
				sprintInputReceived = false;
			}
			void HandleSkill(GenericSkill skillSlot, ref InputBankTest.ButtonState buttonState)
			{
				if (buttonState.down && (bool)skillSlot && (!skillSlot.mustKeyPress || !buttonState.hasPressBeenClaimed) && CanExecuteSkill(skillSlot) && skillSlot.ExecuteIfReady())
				{
					buttonState.hasPressBeenClaimed = true;
				}
			}
		}

		protected void GatherInputs()
		{
			if (hasInputBank)
			{
				moveVector = base.inputBank.moveVector;
				aimDirection = base.inputBank.aimDirection;
				emoteRequest = base.inputBank.emoteRequest;
				base.inputBank.emoteRequest = -1;
				jumpInputReceived |= base.inputBank.jump.justPressed;
				jumpInputReceived &= !base.inputBank.jump.hasPressBeenClaimed;
				sprintInputReceived |= base.inputBank.sprint.down;
			}
		}
	}
	public class GenericCharacterPod : BaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.enabled = false;
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = true;
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.enabled = true;
			}
			base.OnExit();
		}
	}
	public abstract class GenericCharacterSpawnState : BaseState
	{
		[SerializeField]
		public float duration = 2f;

		[SerializeField]
		public string spawnSoundString;

		private static int Spawn1StateHash = Animator.StringToHash("Spawn1");

		private static int Spawn1ParamHash = Animator.StringToHash("Spawn1.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", Spawn1StateHash, Spawn1ParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class GenericCharacterVehicleSeated : BaseState
	{
		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Vehicle;
		}
	}
	public class GenericProjectileBaseState : BaseState
	{
		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public float minSpread;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float recoilAmplitude = 1f;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float projectilePitchBonus;

		[SerializeField]
		public float baseDelayBeforeFiringProjectile;

		[SerializeField]
		public string targetMuzzle;

		[SerializeField]
		public float bloom;

		protected float stopwatch;

		protected float duration;

		protected float delayBeforeFiringProjectile;

		protected bool firedProjectile;

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			delayBeforeFiringProjectile = baseDelayBeforeFiringProjectile / attackSpeedStat;
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
			PlayAnimation(duration);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected virtual void PlayAnimation(float duration)
		{
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= delayBeforeFiringProjectile && !firedProjectile)
			{
				firedProjectile = true;
				FireProjectile();
				DoFireEffects();
			}
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		protected virtual void FireProjectile()
		{
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				aimRay = ModifyProjectileAimRay(aimRay);
				aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, 0f, projectilePitchBonus);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		protected virtual Ray ModifyProjectileAimRay(Ray aimRay)
		{
			return aimRay;
		}

		protected virtual void DoFireEffects()
		{
			Util.PlaySound(attackSoundString, base.gameObject);
			AddRecoil(-2f * recoilAmplitude, -3f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			base.characterBody.AddSpreadBloom(bloom);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class GenericReload : BaseState
	{
		[SerializeField]
		public string enterSoundString;

		protected float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.skillLocator && (bool)base.skillLocator.primary)
			{
				duration = base.skillLocator.primary.CalculateFinalRechargeInterval();
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public class GhostUtilitySkillState : GenericCharacterMain
	{
		public static float baseDuration;

		public static GameObject coreVfxPrefab;

		public static GameObject footVfxPrefab;

		public static GameObject entryEffectPrefab;

		public static GameObject exitEffectPrefab;

		public static float moveSpeedCoefficient;

		public static float healFractionPerTick;

		public static float healFrequency;

		private HurtBoxGroup hurtBoxGroup;

		private CharacterModel characterModel;

		private GameObject coreVfxInstance;

		private GameObject footVfxInstance;

		private float healTimer;

		private float duration;

		private ICharacterGravityParameterProvider characterGravityParameterProvider;

		private ICharacterFlightParameterProvider characterFlightParameterProvider;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string playbackRateParam;

		private EffectManagerHelper _emh_coreVfxInstance;

		private EffectManagerHelper _emh_footVfxInstance;

		public override void Reset()
		{
			base.Reset();
			hurtBoxGroup = null;
			characterModel = null;
			coreVfxInstance = null;
			footVfxInstance = null;
			healTimer = 0f;
			duration = 0f;
			_emh_coreVfxInstance = null;
			_emh_footVfxInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			characterGravityParameterProvider = base.gameObject.GetComponent<ICharacterGravityParameterProvider>();
			characterFlightParameterProvider = base.gameObject.GetComponent<ICharacterFlightParameterProvider>();
			if ((bool)base.characterBody)
			{
				if ((bool)base.characterBody.inventory)
				{
					duration *= base.characterBody.inventory.GetItemCount(RoR2Content.Items.LunarUtilityReplacement);
				}
				hurtBoxGroup = base.characterBody.hurtBoxGroup;
				if ((bool)hurtBoxGroup)
				{
					HurtBoxGroup obj = hurtBoxGroup;
					int hurtBoxesDeactivatorCounter = obj.hurtBoxesDeactivatorCounter + 1;
					obj.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
				if ((bool)coreVfxPrefab)
				{
					if (!EffectManager.ShouldUsePooledEffect(coreVfxPrefab))
					{
						coreVfxInstance = UnityEngine.Object.Instantiate(coreVfxPrefab);
					}
					else
					{
						_emh_coreVfxInstance = EffectManager.GetAndActivatePooledEffect(coreVfxPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
						coreVfxInstance = _emh_coreVfxInstance.gameObject;
					}
				}
				if ((bool)footVfxPrefab)
				{
					if (!EffectManager.ShouldUsePooledEffect(footVfxPrefab))
					{
						footVfxInstance = UnityEngine.Object.Instantiate(footVfxPrefab);
					}
					else
					{
						_emh_footVfxInstance = EffectManager.GetAndActivatePooledEffect(footVfxPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
						footVfxInstance = _emh_footVfxInstance.gameObject;
					}
				}
				UpdateVfxPositions();
				if ((bool)entryEffectPrefab)
				{
					Ray aimRay = GetAimRay();
					EffectManager.SimpleEffect(entryEffectPrefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction), transmit: false);
				}
			}
			characterModel = GetModelTransform()?.GetComponent<CharacterModel>();
			if ((bool)base.modelAnimator)
			{
				base.modelAnimator.enabled = false;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = moveSpeedCoefficient;
			}
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount++;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount++;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			EntityStateMachine[] components = base.gameObject.GetComponents<EntityStateMachine>();
			foreach (EntityStateMachine entityStateMachine in components)
			{
				if (entityStateMachine.customName == "Weapon")
				{
					entityStateMachine.SetNextStateToMain();
				}
			}
		}

		private void UpdateVfxPositions()
		{
			if ((bool)base.characterBody)
			{
				if ((bool)coreVfxInstance)
				{
					coreVfxInstance.transform.position = base.characterBody.corePosition;
				}
				if ((bool)footVfxInstance)
				{
					footVfxInstance.transform.position = base.characterBody.footPosition;
				}
			}
		}

		protected override bool CanExecuteSkill(GenericSkill skillSlot)
		{
			return false;
		}

		public override void Update()
		{
			base.Update();
			UpdateVfxPositions();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			healTimer -= GetDeltaTime();
			if (healTimer <= 0f)
			{
				if (NetworkServer.active)
				{
					base.healthComponent.HealFraction(healFractionPerTick, default(ProcChainMask));
				}
				healTimer = 1f / healFrequency;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)exitEffectPrefab && !outer.destroying)
			{
				Ray aimRay = GetAimRay();
				EffectManager.SimpleEffect(exitEffectPrefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction), transmit: false);
			}
			if (_emh_coreVfxInstance != null && _emh_coreVfxInstance.OwningPool != null)
			{
				_emh_coreVfxInstance.OwningPool.ReturnObject(_emh_coreVfxInstance);
			}
			else if (coreVfxInstance != null)
			{
				EntityState.Destroy(coreVfxInstance);
			}
			coreVfxInstance = null;
			_emh_coreVfxInstance = null;
			if (_emh_footVfxInstance != null && _emh_footVfxInstance.OwningPool != null)
			{
				_emh_footVfxInstance.OwningPool.ReturnObject(_emh_footVfxInstance);
			}
			else if (footVfxInstance != null)
			{
				EntityState.Destroy(footVfxInstance);
			}
			footVfxInstance = null;
			_emh_footVfxInstance = null;
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			if ((bool)hurtBoxGroup)
			{
				HurtBoxGroup obj = hurtBoxGroup;
				int hurtBoxesDeactivatorCounter = obj.hurtBoxesDeactivatorCounter - 1;
				obj.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.modelAnimator)
			{
				base.modelAnimator.enabled = true;
			}
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount--;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount--;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			}
			base.OnExit();
		}
	}
	public class HoverState : BaseState
	{
		private Animator modelAnimator;

		private bool skill1InputReceived;

		private bool skill2InputReceived;

		private bool skill3InputReceived;

		private bool skill4InputReceived;

		private static int IdleStateHash = Animator.StringToHash("Idle");

		private static int flyrateParamHash = Animator.StringToHash("fly.rate");

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			PlayAnimation("Body", IdleStateHash);
		}

		public override void Update()
		{
			base.Update();
			if ((bool)base.inputBank)
			{
				skill1InputReceived = base.inputBank.skill1.down;
				skill2InputReceived = base.inputBank.skill2.down;
				skill3InputReceived = base.inputBank.skill3.down;
				skill4InputReceived = base.inputBank.skill4.down;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			if ((bool)base.inputBank)
			{
				if ((bool)base.rigidbodyMotor)
				{
					base.rigidbodyMotor.moveVector = base.inputBank.moveVector * base.characterBody.moveSpeed;
					if ((bool)modelAnimator)
					{
						modelAnimator.SetFloat(flyrateParamHash, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity));
					}
				}
				if ((bool)base.rigidbodyDirection)
				{
					base.rigidbodyDirection.aimDirection = GetAimRay().direction;
				}
			}
			if ((bool)base.skillLocator)
			{
				if ((bool)base.skillLocator.primary && skill1InputReceived)
				{
					base.skillLocator.primary.ExecuteIfReady();
				}
				if ((bool)base.skillLocator.secondary && skill2InputReceived)
				{
					base.skillLocator.secondary.ExecuteIfReady();
				}
				if ((bool)base.skillLocator.utility && skill3InputReceived)
				{
					base.skillLocator.utility.ExecuteIfReady();
				}
				if ((bool)base.skillLocator.special && skill4InputReceived)
				{
					base.skillLocator.special.ExecuteIfReady();
				}
			}
		}
	}
	public class HurtState : BaseState
	{
		private float stopwatch;

		private float duration = 0.35f;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				modelAnimator.CrossFadeInFixedTime((UnityEngine.Random.Range(0, 2) == 0) ? "Hurt1" : "Hurt2", 0.1f);
				modelAnimator.Update(0f);
				duration = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length;
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.isSprinting = false;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class HurtStateFlyer : BaseState
	{
		private float stopwatch;

		private float duration = 0.35f;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.sfxLocator && base.sfxLocator.deathSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				modelAnimator.CrossFadeInFixedTime((UnityEngine.Random.Range(0, 2) == 0) ? "Hurt1" : "Hurt2", 0.1f);
				modelAnimator.Update(0f);
				duration = modelAnimator.GetNextAnimatorStateInfo(layerIndex).length;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class Idle : EntityState
	{
	}
	public class IdleSkillOverrideHandoff : EntityState, ISkillOverrideHandoff
	{
		public static float skillOverrideTimeout = 0.05f;

		private bool shouldProcess;

		private SkillStateOverrideData skillOverrideData;

		public void TransferSkillOverride(SkillStateOverrideData skillOverrideData)
		{
			this.skillOverrideData = skillOverrideData;
			shouldProcess = this.skillOverrideData != null;
		}

		public override void Update()
		{
			if (shouldProcess)
			{
				base.Update();
				skillOverrideData.StepRestock();
				if (base.age > skillOverrideTimeout)
				{
					skillOverrideData.ClearOverrides();
					skillOverrideData = null;
					shouldProcess = false;
				}
			}
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (skillOverrideData != null && nextState is ISkillOverrideHandoff skillOverrideHandoff)
			{
				skillOverrideHandoff.TransferSkillOverride(skillOverrideData);
				skillOverrideData = null;
				shouldProcess = false;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (shouldProcess)
			{
				skillOverrideData?.ClearOverrides();
			}
		}
	}
	public interface ISkillState
	{
		GenericSkill activatorSkillSlot { get; set; }
	}
	public static class SkillStateMethods
	{
		public static void Serialize(this ISkillState skillState, SkillLocator skillLocator, NetworkWriter writer)
		{
			int num = -1;
			if ((object)skillLocator != null)
			{
				num = skillLocator.GetSkillSlotIndex(skillState.activatorSkillSlot);
			}
			writer.Write((sbyte)num);
		}

		public static void Deserialize(this ISkillState skillState, SkillLocator skillLocator, NetworkReader reader)
		{
			int index = reader.ReadSByte();
			if ((object)skillLocator != null)
			{
				skillState.activatorSkillSlot = skillLocator.GetSkillAtIndex(index);
			}
		}

		public static bool IsKeyDownAuthority(this ISkillState skillState, SkillLocator skillLocator, InputBankTest inputBank)
		{
			GenericSkill activatorSkillSlot = skillState.activatorSkillSlot;
			if ((object)skillLocator == null || (object)activatorSkillSlot == null || (object)inputBank == null)
			{
				return false;
			}
			return skillLocator.FindSkillSlot(activatorSkillSlot) switch
			{
				SkillSlot.None => false, 
				SkillSlot.Primary => inputBank.skill1.down, 
				SkillSlot.Secondary => inputBank.skill2.down, 
				SkillSlot.Utility => inputBank.skill3.down, 
				SkillSlot.Special => inputBank.skill4.down, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}
	}
	public class LockSkill : BaseState
	{
		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class MageCalibrate : BaseState
	{
		public MageElement element;

		public MageCalibrationController calibrationController;

		private bool shouldApply;

		public override void OnEnter()
		{
			calibrationController = GetComponent<MageCalibrationController>();
			shouldApply = NetworkServer.active;
			base.OnEnter();
		}

		public override void OnExit()
		{
			ApplyElement();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			outer.SetNextStateToMain();
		}

		private void ApplyElement()
		{
			if (shouldApply && (bool)calibrationController)
			{
				shouldApply = false;
				calibrationController.SetElement(element);
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			writer.Write((byte)element);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			element = (MageElement)reader.ReadByte();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class BaseMelee : BaseState
	{
		protected RootMotionAccumulator rootMotionAccumulator;

		public RootMotionAccumulator InitMeleeRootMotion()
		{
			rootMotionAccumulator = GetModelRootMotionAccumulator();
			if ((bool)rootMotionAccumulator)
			{
				rootMotionAccumulator.ExtractRootMotion();
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.forward = base.inputBank.aimDirection;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
			}
			return rootMotionAccumulator;
		}

		public void UpdateMeleeRootMotion(float scale)
		{
			if ((bool)rootMotionAccumulator)
			{
				UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion();
				if ((bool)base.characterMotor)
				{
					base.characterMotor.rootMotion = vector * scale;
				}
			}
		}
	}
	public class SleepState : EntityState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				modelAnimator.Play("Sleep", layerIndex, 0f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public class SpawnTeleporterState : BaseState
	{
		private float duration = 4f;

		public static string soundString;

		public static float initialDelay;

		private bool hasTeleported;

		private Animator modelAnimator;

		private PrintController printController;

		private CharacterModel characterModel;

		private CameraTargetParams.AimRequest aimRequest;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			if ((bool)modelAnimator)
			{
				GameObject gameObject = modelAnimator.gameObject;
				characterModel = gameObject.GetComponent<CharacterModel>();
				characterModel.invisibilityCount++;
			}
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (!hasTeleported)
			{
				characterModel.invisibilityCount--;
			}
			aimRequest?.Dispose();
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 3f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= initialDelay && !hasTeleported)
			{
				hasTeleported = true;
				characterModel.invisibilityCount--;
				duration = initialDelay;
				TeleportOutController.AddTPOutEffect(characterModel, 1f, 0f, duration);
				GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(base.gameObject);
				if ((bool)teleportEffectPrefab)
				{
					EffectManager.SimpleEffect(teleportEffectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: false);
				}
				Util.PlaySound(soundString, base.gameObject);
			}
			if (base.fixedAge >= duration && hasTeleported && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class StunState : BaseState
	{
		private float duration;

		private GameObject stunVfxInstance;

		public float stunDuration = 0.35f;

		public static GameObject stunVfxPrefab;

		protected EffectManagerHelper _efhStunEffect;

		public float timeRemaining => Math.Max(duration - base.fixedAge, 0f);

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			stunVfxInstance = null;
			stunDuration = 0.35f;
			_efhStunEffect = null;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Stun;
		}

		public void ExtendStun(float durationDelta)
		{
			duration += durationDelta;
			PlayStunAnimation();
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			PlayStunAnimation();
			if ((bool)base.characterBody)
			{
				base.characterBody.isSprinting = false;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
		}

		private void PlayStunAnimation()
		{
			Animator modelAnimator = GetModelAnimator();
			if (!modelAnimator)
			{
				return;
			}
			int layerIndex = modelAnimator.GetLayerIndex("Body");
			modelAnimator.CrossFadeInFixedTime((UnityEngine.Random.Range(0, 2) == 0) ? "Hurt1" : "Hurt2", 0.1f);
			modelAnimator.Update(0f);
			AnimatorStateInfo nextAnimatorStateInfo = modelAnimator.GetNextAnimatorStateInfo(layerIndex);
			duration = Mathf.Max(duration, Mathf.Max(stunDuration, nextAnimatorStateInfo.length));
			if (stunDuration >= 0f)
			{
				if ((bool)stunVfxInstance)
				{
					ReleaseStunVFX();
				}
				if (!EffectManager.ShouldUsePooledEffect(stunVfxPrefab))
				{
					stunVfxInstance = UnityEngine.Object.Instantiate(stunVfxPrefab, base.transform);
				}
				else
				{
					_efhStunEffect = EffectManager.GetAndActivatePooledEffect(stunVfxPrefab, base.transform);
					stunVfxInstance = _efhStunEffect.gameObject;
				}
				ScaleParticleSystemDuration component = stunVfxInstance.GetComponent<ScaleParticleSystemDuration>();
				component.newDuration = duration;
				component.UpdateDuration();
			}
		}

		public override void OnExit()
		{
			ReleaseStunVFX();
			base.OnExit();
		}

		private void ReleaseStunVFX()
		{
			if (!stunVfxInstance)
			{
				return;
			}
			if (!EffectManager.UsePools)
			{
				EntityState.Destroy(stunVfxInstance);
			}
			else if (_efhStunEffect != null && _efhStunEffect.OwningPool != null)
			{
				if (!_efhStunEffect.OwningPool.IsObjectInPool(_efhStunEffect))
				{
					_efhStunEffect.OwningPool.ReturnObject(_efhStunEffect);
				}
			}
			else
			{
				if (_efhStunEffect != null)
				{
					UnityEngine.Debug.LogFormat("StunEffect has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID());
				}
				EntityState.Destroy(stunVfxInstance);
			}
			_efhStunEffect = null;
			stunVfxInstance = null;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class ShockState : BaseState
	{
		public static GameObject stunVfxPrefab;

		public float shockDuration = 1f;

		public static float shockInterval = 0.1f;

		public static float shockStrength = 1f;

		public static float healthFractionToForceExit = 0.1f;

		public static string enterSoundString;

		public static string exitSoundString;

		private float shockTimer;

		private Animator animator;

		private TemporaryOverlayInstance temporaryOverlay;

		private float healthFraction;

		private GameObject stunVfxInstance;

		private static int Hurt1StateHash = Animator.StringToHash("Hurt1");

		private static int Hurt2StateHash = Animator.StringToHash("Hurt2");

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Body", (UnityEngine.Random.Range(0, 2) == 0) ? Hurt1StateHash : Hurt2StateHash);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				CharacterModel component = modelTransform.GetComponent<CharacterModel>();
				if ((bool)component)
				{
					temporaryOverlay = TemporaryOverlayManager.AddOverlay(base.gameObject);
					temporaryOverlay.duration = shockDuration;
					temporaryOverlay.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matIsShocked");
					temporaryOverlay.AddToCharacterModel(component);
				}
			}
			stunVfxInstance = UnityEngine.Object.Instantiate(stunVfxPrefab, base.transform);
			stunVfxInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = shockDuration;
			if ((bool)base.characterBody.healthComponent)
			{
				healthFraction = base.characterBody.healthComponent.combinedHealthFraction;
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.isSprinting = false;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			shockTimer -= GetDeltaTime();
			float combinedHealthFraction = base.characterBody.healthComponent.combinedHealthFraction;
			if (shockTimer <= 0f)
			{
				shockTimer += shockInterval;
				PlayShockAnimation();
			}
			if (base.fixedAge > shockDuration || healthFraction - combinedHealthFraction > healthFractionToForceExit)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (temporaryOverlay != null)
			{
				temporaryOverlay.Destroy();
			}
			if ((bool)stunVfxInstance)
			{
				EntityState.Destroy(stunVfxInstance);
			}
			Util.PlaySound(exitSoundString, base.gameObject);
			base.OnExit();
		}

		private void PlayShockAnimation()
		{
			string layerName = "Flinch";
			int layerIndex = animator.GetLayerIndex(layerName);
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, shockStrength);
				animator.Play("FlinchStart", layerIndex);
			}
		}
	}
	public class TestState1 : EntityState
	{
		public override void OnEnter()
		{
			UnityEngine.Debug.LogFormat("{0} Entering TestState1.", base.gameObject);
		}

		public override void OnExit()
		{
			UnityEngine.Debug.LogFormat("{0} Exiting TestState1.", base.gameObject);
		}

		public override void FixedUpdate()
		{
			if (base.isAuthority && Input.GetButton("Fire1"))
			{
				outer.SetNextState(new TestState2());
			}
		}
	}
	public class TestState2 : EntityState
	{
		public override void OnEnter()
		{
			UnityEngine.Debug.LogFormat("{0} Entering TestState2.", base.gameObject);
		}

		public override void OnExit()
		{
			UnityEngine.Debug.LogFormat("{0} Exiting TestState2.", base.gameObject);
		}

		public override void FixedUpdate()
		{
			if (base.isAuthority && Input.GetButton("Fire2"))
			{
				outer.SetNextState(new TestState1());
			}
		}
	}
	public class PrepFlower2 : BaseState
	{
		public static float baseDuration;

		public static string enterSoundString;

		private float duration;

		private static int PrepFlowerStateHash = Animator.StringToHash("PrepFlower");

		private static int PrepFlowerParamHash = Animator.StringToHash("PrepFlower.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Gesture, Additive", PrepFlowerStateHash, PrepFlowerParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new FireFlower2());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireFlower2 : BaseState
	{
		public static GameObject projectilePrefab;

		public static float baseDuration;

		public static float damageCoefficient;

		public static float healthCostFraction;

		public static string enterSoundString;

		public static string muzzleName;

		public static GameObject muzzleFlashPrefab;

		private float duration;

		private static int FireFlowerStateHash = Animator.StringToHash("FireFlower");

		private static int FireFlowerParamHash = Animator.StringToHash("FireFlower.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Gesture, Additive", FireFlowerStateHash, FireFlowerParamHash, duration);
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.crit = RollCrit();
				fireProjectileInfo.damage = damageCoefficient * damageStat;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.position = aimRay.origin;
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction);
				fireProjectileInfo.useSpeedOverride = false;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
			if (NetworkServer.active && (bool)base.healthComponent)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction;
				damageInfo.position = base.characterBody.corePosition;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.damageColorIndex = DamageColorIndex.Default;
				damageInfo.crit = false;
				damageInfo.attacker = null;
				damageInfo.inflictor = null;
				damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor;
				damageInfo.procCoefficient = 0f;
				damageInfo.procChainMask = default(ProcChainMask);
				base.healthComponent.TakeDamage(damageInfo);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class Uninitialized : EntityState
	{
	}
}
namespace EntityStates.Wisp1Monster
{
	public class ChargeEmbers : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargeEffectPrefab;

		public static GameObject laserEffectPrefab;

		public static string attackString;

		private float duration;

		private float stopwatch;

		private uint soundID;

		private GameObject chargeEffectInstance;

		private GameObject laserEffectInstance;

		private LineRenderer laserEffectInstanceLineRenderer;

		private bool lineRendererNull;

		protected EffectManagerHelper _emh_chargeEffect;

		protected EffectManagerHelper _emh_laserEffect;

		private UnityEngine.Color startColor = UnityEngine.Color.white;

		private static int ChargeAttack1StateHash = Animator.StringToHash("ChargeAttack1");

		private static int ChargeAttack1ParamHash = Animator.StringToHash("ChargeAttack1.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffectInstance = null;
			laserEffectInstance = null;
			laserEffectInstanceLineRenderer = null;
			lineRendererNull = true;
			_emh_chargeEffect = null;
			_emh_laserEffect = null;
			startColor = UnityEngine.Color.white;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			SetAIUpdateFrequency(alwaysUpdate: true);
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			soundID = Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("Muzzle");
					if ((bool)transform)
					{
						if ((bool)chargeEffectPrefab)
						{
							if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
							{
								chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
							}
							else
							{
								_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
								chargeEffectInstance = _emh_chargeEffect.gameObject;
							}
							chargeEffectInstance.transform.parent = transform;
							ScaleParticleSystemDuration component2 = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
							if ((bool)component2)
							{
								component2.newDuration = duration;
							}
						}
						if ((bool)laserEffectPrefab)
						{
							if (!EffectManager.ShouldUsePooledEffect(laserEffectPrefab))
							{
								laserEffectInstance = UnityEngine.Object.Instantiate(laserEffectPrefab, transform.position, transform.rotation);
							}
							else
							{
								_emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserEffectPrefab, transform.position, transform.rotation);
								laserEffectInstance = _emh_laserEffect.gameObject;
							}
							laserEffectInstance.transform.parent = transform;
							laserEffectInstanceLineRenderer = laserEffectInstance.GetComponent<LineRenderer>();
							lineRendererNull = false;
						}
					}
				}
			}
			PlayAnimation("Body", ChargeAttack1StateHash, ChargeAttack1ParamHash, duration);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			SetAIUpdateFrequency(alwaysUpdate: false);
			AkSoundEngine.StopPlayingID(soundID);
			if ((bool)chargeEffectInstance)
			{
				if (!EffectManager.UsePools)
				{
					EntityState.Destroy(chargeEffectInstance);
				}
				else if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffectInstance);
				}
				chargeEffectInstance = null;
				_emh_chargeEffect = null;
			}
			if ((bool)laserEffectInstance)
			{
				if (!EffectManager.UsePools)
				{
					EntityState.Destroy(laserEffectInstance);
				}
				else if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null)
				{
					_emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect);
				}
				else
				{
					EntityState.Destroy(laserEffectInstance);
				}
				laserEffectInstance = null;
				_emh_laserEffect = null;
				lineRendererNull = true;
			}
		}

		public override void Update()
		{
			base.Update();
			if (!lineRendererNull)
			{
				if (!laserEffectInstanceLineRenderer)
				{
					lineRendererNull = true;
					return;
				}
				Ray aimRay = GetAimRay();
				float distance = 50f;
				UnityEngine.Vector3 origin = aimRay.origin;
				UnityEngine.Vector3 point = aimRay.GetPoint(distance);
				laserEffectInstanceLineRenderer.SetPosition(0, origin);
				laserEffectInstanceLineRenderer.SetPosition(1, point);
				startColor.a = stopwatch / duration;
				laserEffectInstanceLineRenderer.startColor = startColor;
				laserEffectInstanceLineRenderer.endColor = UnityEngine.Color.clear;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireEmbers());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialExplosion;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if (!EffectManager.ShouldUsePooledEffect(initialExplosion))
			{
				UnityEngine.Object.Instantiate(initialExplosion, base.transform.position, base.transform.rotation);
			}
			else
			{
				EffectManager.SpawnEffect(initialExplosion, new EffectData
				{
					origin = base.transform.position,
					rotation = base.transform.rotation
				}, transmit: false);
			}
			if (NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
	public class FireEmbers : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public static string attackString;

		private float duration;

		private static int FireAttack1StateHash = Animator.StringToHash("FireAttack1");

		private static int FireAttack1ParamHash = Animator.StringToHash("FireAttack1.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat);
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			PlayAnimation("Body", FireAttack1StateHash, FireAttack1ParamHash, duration);
			string muzzleName = "";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u);
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet;
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = 0.5f;
				bulletAttack.procCoefficient = 1f / (float)bulletCount;
				bulletAttack.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Vulture
{
	public class FallingDeath : GenericCharacterDeath
	{
		private Animator animator;

		private static int isGroundedParamHash = Animator.StringToHash("isGrounded");

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity.y = 0f;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)animator)
			{
				animator.SetBool(isGroundedParamHash, base.characterMotor.isGrounded);
				return;
			}
			animator = GetModelAnimator();
			if ((bool)animator)
			{
				int layerIndex = animator.GetLayerIndex("FlyOverride");
				animator.SetLayerWeight(layerIndex, 0f);
			}
		}
	}
	public class VultureModeState : BaseSkillState
	{
		[SerializeField]
		public float mecanimTransitionDuration;

		[SerializeField]
		public float flyOverrideMecanimLayerWeight;

		[SerializeField]
		public float movementSpeedMultiplier;

		[SerializeField]
		public string enterSoundString;

		protected Animator animator;

		protected int flyOverrideLayer;

		protected ICharacterGravityParameterProvider characterGravityParameterProvider;

		protected ICharacterFlightParameterProvider characterFlightParameterProvider;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			characterGravityParameterProvider = base.gameObject.GetComponent<ICharacterGravityParameterProvider>();
			characterFlightParameterProvider = base.gameObject.GetComponent<ICharacterFlightParameterProvider>();
			if ((bool)animator)
			{
				flyOverrideLayer = animator.GetLayerIndex("FlyOverride");
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = movementSpeedMultiplier;
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.normalizeToFloor = false;
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void Update()
		{
			base.Update();
			if ((bool)animator)
			{
				animator.SetLayerWeight(flyOverrideLayer, Util.Remap(Mathf.Clamp01(base.age / mecanimTransitionDuration), 0f, 1f, 1f - flyOverrideMecanimLayerWeight, flyOverrideMecanimLayerWeight));
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			}
			base.OnExit();
		}
	}
	public class Land : VultureModeState
	{
		public override void OnEnter()
		{
			base.OnEnter();
		}
	}
	public class Fly : VultureModeState
	{
		public static SkillDef landingSkill;

		public static float launchSpeed;

		public static GameObject jumpEffectPrefab;

		public static string jumpEffectMuzzleString;

		private static int JumpStateHash = Animator.StringToHash("Jump");

		public override void OnEnter()
		{
			base.OnEnter();
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount++;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount++;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity.y = launchSpeed;
				base.characterMotor.Motor.ForceUnground();
			}
			PlayAnimation("Body", JumpStateHash);
			if ((bool)base.activatorSkillSlot)
			{
				base.activatorSkillSlot.SetSkillOverride(this, landingSkill, GenericSkill.SkillOverridePriority.Contextual);
			}
			if ((bool)jumpEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(jumpEffectPrefab, base.gameObject, jumpEffectMuzzleString, transmit: false);
			}
		}

		public override void OnExit()
		{
			if ((bool)base.activatorSkillSlot)
			{
				base.activatorSkillSlot.UnsetSkillOverride(this, landingSkill, GenericSkill.SkillOverridePriority.Contextual);
			}
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount--;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount--;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.normalizeToFloor = true;
			}
			base.OnExit();
		}
	}
	public class FlyToLand : BaseSkillState
	{
		private float duration;

		private UnityEngine.Vector3 targetPosition;

		public static float speedMultiplier;

		private ICharacterGravityParameterProvider characterGravityParameterProvider;

		private ICharacterFlightParameterProvider characterFlightParameterProvider;

		public override void OnEnter()
		{
			base.OnEnter();
			characterGravityParameterProvider = base.gameObject.GetComponent<ICharacterGravityParameterProvider>();
			characterFlightParameterProvider = base.gameObject.GetComponent<ICharacterFlightParameterProvider>();
			UnityEngine.Vector3 footPosition = GetFootPosition();
			if (base.isAuthority)
			{
				bool flag = false;
				NodeGraph groundNodes = SceneInfo.instance.groundNodes;
				if ((bool)groundNodes)
				{
					NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNodeWithFlagConditions(base.transform.position, base.characterBody.hullClassification, NodeFlags.None, NodeFlags.None, preventOverhead: false);
					flag = nodeIndex != NodeGraph.NodeIndex.invalid && groundNodes.GetNodePosition(nodeIndex, out targetPosition);
				}
				if (!flag)
				{
					outer.SetNextState(new Fly
					{
						activatorSkillSlot = base.activatorSkillSlot
					});
					duration = 0f;
					targetPosition = footPosition;
					return;
				}
			}
			UnityEngine.Vector3 vector = targetPosition - footPosition;
			float num = moveSpeedStat * speedMultiplier;
			duration = vector.magnitude / num;
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount++;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount++;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
		}

		private UnityEngine.Vector3 GetFootPosition()
		{
			if ((bool)base.characterBody)
			{
				return base.characterBody.footPosition;
			}
			return base.transform.position;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			UnityEngine.Vector3 footPosition = GetFootPosition();
			base.characterMotor.moveDirection = (targetPosition - footPosition).normalized * speedMultiplier;
			if (base.isAuthority && (base.characterMotor.isGrounded || duration <= base.fixedAge))
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount--;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount--;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat("Flying", 0f);
			}
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(targetPosition);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			targetPosition = reader.ReadVector3();
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Vulture.Weapon
{
	public class ChargeWindblade : BaseSkillState
	{
		public static float baseDuration;

		public static string muzzleString;

		public static GameObject chargeEffectPrefab;

		public static string soundString;

		private float duration;

		private GameObject chargeEffectInstance;

		protected EffectManagerHelper _emh_chargeEffectInstance;

		private static int ChargeWindbladeStateHash = Animator.StringToHash("ChargeWindblade");

		private static int ChargeWindbladeParamHash = Animator.StringToHash("ChargeWindblade.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffectInstance = null;
			_emh_chargeEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", ChargeWindbladeStateHash, ChargeWindbladeParamHash, duration);
			Util.PlaySound(soundString, base.gameObject);
			base.characterBody.SetAimTimer(3f);
			Transform transform = FindModelChild(muzzleString);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				}
				else
				{
					_emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance = _emh_chargeEffectInstance.gameObject;
				}
				chargeEffectInstance.transform.parent = transform;
				ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new FireWindblade());
			}
		}

		public override void OnExit()
		{
			if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null)
			{
				_emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance);
			}
			else if (chargeEffectInstance != null)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
			chargeEffectInstance = null;
			_emh_chargeEffectInstance = null;
			base.OnExit();
		}
	}
	public class FireWindblade : BaseSkillState
	{
		public static float baseDuration;

		public static string muzzleString;

		public static GameObject muzzleEffectPrefab;

		public static GameObject projectilePrefab;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string soundString;

		private float duration;

		private static int FireWindbladeStateHash = Animator.StringToHash("FireWindblade");

		private static int FireWindbladeParamHash = Animator.StringToHash("FireWindblade.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", FireWindbladeStateHash, FireWindbladeParamHash, duration);
			Util.PlaySound(soundString, base.gameObject);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			Ray aimRay = GetAimRay();
			if (base.isAuthority)
			{
				UnityEngine.Quaternion quaternion = Util.QuaternionSafeLookRotation(aimRay.direction);
				UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 360f), aimRay.direction);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, quaternion2 * quaternion, base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.VoidSurvivorPod
{
	public class Descent : SurvivorPodBaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && duration < base.fixedAge)
			{
				TransitionIntoNextState();
			}
		}

		protected virtual void TransitionIntoNextState()
		{
			outer.SetNextState(new Landed());
		}
	}
	public class Landed : SurvivorPodBaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string effectMuzzle;

		[SerializeField]
		public GameObject openEffect;

		[SerializeField]
		public string particleChildName;

		private ParticleSystem[] particles;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			base.vehicleSeat.handleVehicleExitRequestServer.AddCallback(HandleVehicleExitRequest);
			ModelLocator component = GetComponent<ModelLocator>();
			if (!component || !component.modelTransform)
			{
				return;
			}
			ChildLocator component2 = component.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component2)
			{
				Transform transform = component2.FindChild(particleChildName);
				if ((bool)transform)
				{
					particles = transform.GetComponentsInChildren<ParticleSystem>();
					transform.gameObject.SetActive(value: true);
				}
			}
		}

		public override void FixedUpdate()
		{
			if (base.fixedAge > 0f)
			{
				base.survivorPodController.exitAllowed = true;
			}
			base.FixedUpdate();
		}

		private void HandleVehicleExitRequest(GameObject gameObject, ref bool? result)
		{
			base.survivorPodController.exitAllowed = false;
			outer.SetNextState(new Release());
			result = true;
		}

		public override void OnExit()
		{
			base.vehicleSeat.handleVehicleExitRequestServer.RemoveCallback(HandleVehicleExitRequest);
			base.survivorPodController.exitAllowed = false;
			EffectManager.SimpleMuzzleFlash(openEffect, base.gameObject, effectMuzzle, transmit: false);
			ParticleSystem[] array = particles;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Stop();
			}
		}
	}
	public class Release : SurvivorPodBaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public float exitForceAmount;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)base.survivorPodController && NetworkServer.active && (bool)base.vehicleSeat && (bool)base.vehicleSeat.currentPassengerBody)
			{
				CharacterBody currentPassengerBody = base.vehicleSeat.currentPassengerBody;
				base.vehicleSeat.EjectPassenger(currentPassengerBody.gameObject);
				HealthComponent component = currentPassengerBody.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.attacker = base.gameObject;
					damageInfo.force = UnityEngine.Vector3.up * exitForceAmount;
					damageInfo.position = currentPassengerBody.corePosition;
					component.TakeDamageForce(damageInfo, alwaysApply: true);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (!base.vehicleSeat || !base.vehicleSeat.currentPassengerBody))
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.VoidSurvivor
{
	public class CorruptionTransitionBase : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationGroundStateName;

		[SerializeField]
		public string animationAirStateName;

		[SerializeField]
		public string animationPlaybackParameterName;

		[SerializeField]
		public float animationCrossfadeDuration;

		[SerializeField]
		public string entrySound;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public GameObject completionEffectPrefab;

		[SerializeField]
		public string effectmuzzle;

		[SerializeField]
		public CharacterCameraParams cameraParams;

		[SerializeField]
		public float dampingCoefficient;

		protected VoidSurvivorController voidSurvivorController;

		private GameObject chargeEffectInstance;

		private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle;

		public override void OnEnter()
		{
			base.OnEnter();
			voidSurvivorController = GetComponent<VoidSurvivorController>();
			PlayCrossfade(animationLayerName, base.characterMotor.isGrounded ? animationGroundStateName : animationAirStateName, animationPlaybackParameterName, duration, animationCrossfadeDuration);
			Util.PlaySound(entrySound, base.gameObject);
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
			StartCameraParamsOverride(duration);
			Transform transform = FindModelChild(effectmuzzle);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeEffectInstance.transform.parent = transform;
				ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
			if (base.isAuthority && (bool)voidSurvivorController)
			{
				voidSurvivorController.weaponStateMachine.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			EndCameraParamsOverride(0f);
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
			if ((bool)chargeEffectInstance)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				base.characterMotor.velocity -= base.characterMotor.velocity * dampingCoefficient;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				OnFinishAuthority();
				outer.SetNextStateToMain();
			}
		}

		public virtual void OnFinishAuthority()
		{
			EffectManager.SimpleMuzzleFlash(completionEffectPrefab, base.gameObject, effectmuzzle, transmit: true);
		}

		protected void StartCameraParamsOverride(float transitionDuration)
		{
			if (!cameraParamsOverrideHandle.isValid)
			{
				cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest
				{
					cameraParamsData = cameraParams.data
				}, transitionDuration);
			}
		}

		protected void EndCameraParamsOverride(float transitionDuration)
		{
			if (cameraParamsOverrideHandle.isValid)
			{
				base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle, transitionDuration);
				cameraParamsOverrideHandle = default(CameraTargetParams.CameraParamsOverrideHandle);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class EnterCorruptionTransition : CorruptionTransitionBase
	{
		[SerializeField]
		public float lingeringInvincibilityDuration;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)voidSurvivorController && NetworkServer.active)
			{
				voidSurvivorController.AddCorruption(100f);
			}
		}

		public override void OnFinishAuthority()
		{
			base.OnFinishAuthority();
			if ((bool)voidSurvivorController)
			{
				voidSurvivorController.corruptionModeStateMachine.SetNextState(new EntityStates.VoidSurvivor.CorruptMode.CorruptMode());
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (NetworkServer.active)
			{
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, lingeringInvincibilityDuration);
			}
		}
	}
	public class ExitCorruptionTransition : CorruptionTransitionBase
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)voidSurvivorController && NetworkServer.active)
			{
				voidSurvivorController.AddCorruption(-100f);
			}
		}

		public override void OnFinishAuthority()
		{
			base.OnFinishAuthority();
			if ((bool)voidSurvivorController)
			{
				voidSurvivorController.corruptionModeStateMachine.SetNextState(new UncorruptedMode());
			}
		}
	}
	public class VoidBlinkBase : BaseState
	{
		public class VoidBlinkUp : VoidBlinkBase
		{
		}

		public class VoidBlinkDown : VoidBlinkBase
		{
		}

		private Transform modelTransform;

		[SerializeField]
		public GameObject blinkEffectPrefab;

		[SerializeField]
		public float duration = 0.3f;

		[SerializeField]
		public float speedCoefficient = 25f;

		[SerializeField]
		public string beginSoundString;

		[SerializeField]
		public string endSoundString;

		[SerializeField]
		public AnimationCurve forwardSpeed;

		[SerializeField]
		public AnimationCurve upSpeed;

		[SerializeField]
		public GameObject blinkVfxPrefab;

		[SerializeField]
		public float overlayDuration;

		[SerializeField]
		public Material overlayMaterial;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private UnityEngine.Vector3 forwardVector;

		private GameObject blinkVfxInstance;

		private uint soundID;

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterBody.bodyFlags |= CharacterBody.BodyFlags.OverheatImmune;
			soundID = Util.PlaySound(beginSoundString, base.gameObject);
			forwardVector = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized;
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if (NetworkServer.active)
			{
				Util.CleanseBody(base.characterBody, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: false, removeDots: true, removeStun: true, removeNearbyProjectiles: false);
			}
			blinkVfxInstance = UnityEngine.Object.Instantiate(blinkVfxPrefab);
			blinkVfxInstance.transform.SetParent(base.transform, worldPositionStays: false);
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
		}

		protected virtual UnityEngine.Vector3 GetBlinkVector()
		{
			return base.inputBank.aimDirection;
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(GetVelocity());
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkEffectPrefab, effectData, transmit: false);
		}

		private UnityEngine.Vector3 GetVelocity()
		{
			float time = base.fixedAge / duration;
			UnityEngine.Vector3 vector = forwardSpeed.Evaluate(time) * forwardVector;
			UnityEngine.Vector3 vector2 = upSpeed.Evaluate(time) * UnityEngine.Vector3.up;
			return (vector + vector2) * speedCoefficient * moveSpeedStat;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				if ((bool)base.characterMotor)
				{
					base.characterMotor.Motor.ForceUnground();
				}
				UnityEngine.Vector3 velocity = GetVelocity();
				base.characterMotor.velocity = velocity;
				if ((bool)blinkVfxInstance)
				{
					blinkVfxInstance.transform.forward = velocity;
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(soundID);
			if (!outer.destroying)
			{
				Util.PlaySound(endSoundString, base.gameObject);
				CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
			}
			if ((bool)blinkVfxInstance)
			{
				VfxKillBehavior.KillVfxObject(blinkVfxInstance);
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.OverheatImmune;
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance.duration = overlayDuration;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = overlayMaterial;
				temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.VoidSurvivor.Weapon
{
	public class ChargeMegaBlaster : BaseSkillState
	{
		[SerializeField]
		public float minimumDuration = 0.1f;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string chargeSoundString;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		private float duration;

		private uint soundID;

		private GameObject chargeEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			soundID = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat);
			PlayAnimation(animationLayerName, animationStateName);
			base.characterBody.SetAimTimer(duration + 1f);
			Transform transform = FindModelChild(muzzle);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeEffectInstance.transform.parent = transform;
				ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				ObjectScaleCurve component2 = chargeEffectInstance.GetComponent<ObjectScaleCurve>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
				if ((bool)component2)
				{
					component2.timeMax = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				if (base.fixedAge >= duration)
				{
					outer.SetNextState(new ReadyMegaBlaster
					{
						activatorSkillSlot = base.activatorSkillSlot
					});
				}
				else if (!IsKeyDownAuthority() && base.fixedAge > minimumDuration)
				{
					outer.SetNextState(new FireMegaBlasterSmall());
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeEffectInstance)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
			AkSoundEngine.StopPlayingID(soundID);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ReadyMegaBlaster : BaseSkillState
	{
		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string exitSoundString;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		private GameObject chargeEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName);
			Transform transform = FindModelChild(muzzle);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeEffectInstance.transform.parent = transform;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterBody.SetAimTimer(3f);
			if (base.isAuthority && !IsKeyDownAuthority())
			{
				outer.SetNextState(new FireMegaBlasterBig());
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(exitSoundString, base.gameObject);
			if ((bool)chargeEffectInstance)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireMegaBlasterSmall : FireMegaBlasterBase
	{
	}
	public class FireMegaBlasterBig : FireMegaBlasterBase
	{
	}
	public class FireMegaBlasterBase : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public float spread;

		[SerializeField]
		public float yawPerProjectile;

		[SerializeField]
		public float selfKnockbackForce;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			Ray aimRay = GetAimRay();
			duration = baseDuration / attackSpeedStat;
			StartAimMode(duration + 2f);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(attackSoundString, base.gameObject);
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(bloom);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				FireProjectiles();
			}
			base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction);
		}

		private void FireProjectiles()
		{
			Ray ray = GetAimRay();
			TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
			ray.direction = Util.ApplySpread(ray.direction, 0f, spread, 1f, 1f);
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.position = ray.origin;
			fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction);
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.damage = damageStat * damageCoefficient;
			fireProjectileInfo.force = force;
			fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
			ProjectileManager.instance.FireProjectile(fireProjectileInfo);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeCorruptHandBeam : BaseSkillState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			GetAimRay();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			base.characterBody.SetAimTimer(3f);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextState(new FireCorruptHandBeam
				{
					activatorSkillSlot = base.activatorSkillSlot
				});
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireCorruptHandBeam : BaseSkillState
	{
		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject beamVfxPrefab;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string exitSoundString;

		[SerializeField]
		public float tickRate;

		[SerializeField]
		public float damageCoefficientPerSecond;

		[SerializeField]
		public float procCoefficientPerSecond;

		[SerializeField]
		public float forcePerSecond;

		[SerializeField]
		public float maxDistance;

		[SerializeField]
		public float minDistance;

		[SerializeField]
		public float bulletRadius;

		[SerializeField]
		public float baseMinimumDuration = 2f;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float spreadBloomValue = 0.3f;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationEnterStateName;

		[SerializeField]
		public string animationExitStateName;

		private GameObject blinkVfxInstance;

		private float minimumDuration;

		private float fireCountdown;

		public override void OnEnter()
		{
			base.OnEnter();
			minimumDuration = baseMinimumDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationEnterStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			blinkVfxInstance = UnityEngine.Object.Instantiate(beamVfxPrefab);
			blinkVfxInstance.transform.SetParent(base.characterBody.aimOriginTransform, worldPositionStays: false);
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.Slow50);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireCountdown -= GetDeltaTime();
			if (fireCountdown <= 0f)
			{
				fireCountdown = 1f / tickRate / attackSpeedStat;
				FireBullet();
			}
			base.characterBody.SetAimTimer(3f);
			if ((bool)blinkVfxInstance)
			{
				UnityEngine.Vector3 point = GetAimRay().GetPoint(maxDistance);
				if (Util.CharacterRaycast(base.gameObject, GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal))
				{
					point = hitInfo.point;
				}
				blinkVfxInstance.transform.forward = point - blinkVfxInstance.transform.position;
			}
			if (((base.fixedAge >= minimumDuration && !IsKeyDownAuthority()) || base.characterBody.isSprinting) && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)blinkVfxInstance)
			{
				VfxKillBehavior.KillVfxObject(blinkVfxInstance);
			}
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.Slow50);
			}
			PlayAnimation(animationLayerName, animationExitStateName);
			Util.PlaySound(exitSoundString, base.gameObject);
			base.OnExit();
		}

		private void FireBullet()
		{
			Ray aimRay = GetAimRay();
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.muzzleName = muzzle;
				bulletAttack.maxDistance = Mathf.Lerp(minDistance, maxDistance, UnityEngine.Random.value);
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.radius = bulletRadius;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.smartCollision = false;
				bulletAttack.stopperMask = default(LayerMask);
				bulletAttack.hitMask = LayerIndex.entityPrecise.mask;
				bulletAttack.allowTrajectoryAimAssist = false;
				bulletAttack.damage = damageCoefficientPerSecond * damageStat / tickRate;
				bulletAttack.procCoefficient = procCoefficientPerSecond / tickRate;
				bulletAttack.force = forcePerSecond / tickRate;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.Fire();
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeCrabCannon : BaseSkillState
	{
		[SerializeField]
		public float baseDurationPerGrenade;

		[SerializeField]
		public float minimumDuration;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string chargeStockSoundString;

		[SerializeField]
		public string chargeLoopStartSoundString;

		[SerializeField]
		public string chargeLoopStopSoundString;

		[SerializeField]
		public float bloomPerGrenade;

		[SerializeField]
		public float corruptionPerGrenade;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		private VoidSurvivorController voidSurvivorController;

		private GameObject chargeEffectInstance;

		private int grenadeCount;

		private int lastGrenadeCount;

		private float durationPerGrenade;

		private float nextGrenadeStopwatch;

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		public override void OnEnter()
		{
			base.OnEnter();
			voidSurvivorController = GetComponent<VoidSurvivorController>();
			PlayAnimation(animationLayerName, animationStateName);
			durationPerGrenade = baseDurationPerGrenade / attackSpeedStat;
			Util.PlaySound(chargeLoopStartSoundString, base.gameObject);
			AddGrenade();
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild(muzzle);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeEffectInstance.transform.parent = transform;
				ScaleParticleSystemDuration component2 = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component2)
				{
					component2.newDuration = durationPerGrenade;
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			Util.PlaySound(chargeLoopStopSoundString, base.gameObject);
			PlayAnimation(animationLayerName, BufferEmptyStateHash);
			EntityState.Destroy(chargeEffectInstance);
		}

		private void AddGrenade()
		{
			grenadeCount++;
			if ((bool)voidSurvivorController && NetworkServer.active)
			{
				voidSurvivorController.AddCorruption(corruptionPerGrenade);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterBody.SetAimTimer(3f);
			nextGrenadeStopwatch += GetDeltaTime();
			if (nextGrenadeStopwatch > durationPerGrenade && base.activatorSkillSlot.stock > 0)
			{
				AddGrenade();
				nextGrenadeStopwatch -= durationPerGrenade;
				base.activatorSkillSlot.DeductStock(1);
			}
			float value = bloomPerGrenade * (float)lastGrenadeCount;
			base.characterBody.SetSpreadBloom(value);
			if (lastGrenadeCount < grenadeCount)
			{
				Util.PlaySound(chargeStockSoundString, base.gameObject);
			}
			if (!IsKeyDownAuthority() && base.fixedAge > minimumDuration / attackSpeedStat && base.isAuthority)
			{
				FireCrabCannon fireCrabCannon = new FireCrabCannon();
				fireCrabCannon.grenadeCountMax = grenadeCount;
				outer.SetNextState(fireCrabCannon);
			}
			else
			{
				lastGrenadeCount = grenadeCount;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireCrabCannon : BaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public int grenadeCountMax = 3;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public float fireDuration = 1f;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		private static float recoilAmplitude = 1f;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string perGrenadeSoundString;

		[SerializeField]
		public float spreadBloomValue = 0.3f;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			StartAimMode();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireProjectile()
		{
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(perGrenadeSoundString, base.gameObject);
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(spreadBloomValue);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, maxSpread, 1f, 1f);
				UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
				UnityEngine.Vector3.ProjectOnPlane(onUnitSphere, aimRay.direction);
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction, onUnitSphere);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			float num = fireDuration / attackSpeedStat / (float)grenadeCountMax;
			if (fireTimer <= 0f && grenadeCount < grenadeCountMax)
			{
				FireProjectile();
				fireTimer += num;
				grenadeCount++;
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ChargeCrushBase : BaseSkillState
	{
		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string chargeSoundString;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackParameterName;

		protected float duration;

		private uint soundID;

		private GameObject chargeEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			soundID = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration);
			base.characterBody.SetAimTimer(duration + 1f);
			Transform transform = FindModelChild(muzzle);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeEffectInstance.transform.parent = transform;
				ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				ObjectScaleCurve component2 = chargeEffectInstance.GetComponent<ObjectScaleCurve>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
				if ((bool)component2)
				{
					component2.timeMax = duration;
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeEffectInstance)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
			AkSoundEngine.StopPlayingID(soundID);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class CrushBase : BaseState
	{
		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public float selfHealFraction;

		[SerializeField]
		public float corruptionChange;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			GetAimRay();
			duration = baseDuration / attackSpeedStat;
			StartAimMode(duration + 2f);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(bloom);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (NetworkServer.active)
			{
				ProcChainMask procChainMask = default(ProcChainMask);
				procChainMask.AddProc(ProcType.VoidSurvivorCrush);
				if (selfHealFraction > 0f)
				{
					base.healthComponent.HealFraction(selfHealFraction, procChainMask);
				}
				else
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = (0f - base.healthComponent.fullCombinedHealth) * selfHealFraction;
					damageInfo.position = base.characterBody.corePosition;
					damageInfo.force = UnityEngine.Vector3.zero;
					damageInfo.damageColorIndex = DamageColorIndex.Default;
					damageInfo.crit = false;
					damageInfo.attacker = null;
					damageInfo.inflictor = null;
					damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor;
					damageInfo.procCoefficient = 0f;
					damageInfo.procChainMask = procChainMask;
					base.healthComponent.TakeDamage(damageInfo);
				}
				VoidSurvivorController component = GetComponent<VoidSurvivorController>();
				if ((bool)component)
				{
					component.AddCorruption(corruptionChange);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeCrushCorruption : ChargeCrushBase
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new CrushCorruption());
			}
		}
	}
	public class ChargeCrushHealth : ChargeCrushBase
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new CrushHealth());
			}
		}
	}
	public class CrushCorruption : CrushBase
	{
	}
	public class CrushHealth : CrushBase
	{
	}
	public class FireBlasterBase : BaseSkillState, SteppedSkillDef.IStepSetter
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float attackSoundPitchPerStep;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public float spread;

		[SerializeField]
		public int projectileCount;

		[SerializeField]
		public float yawPerProjectile;

		[SerializeField]
		public float offsetPerProjectile;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public int burstCount;

		[SerializeField]
		public bool canCharge;

		private float duration;

		private float interruptDuration;

		public int step;

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			step = i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			base.activatorSkillSlot = base.skillLocator.primary;
			GetAimRay();
			duration = baseDuration / attackSpeedStat;
			StartAimMode(duration + 2f);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, 1f + (float)step * attackSoundPitchPerStep);
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(bloom);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				FireProjectiles();
			}
		}

		private void FireProjectiles()
		{
			for (int i = 0; i < projectileCount; i++)
			{
				float num = (float)i - (float)(projectileCount - 1) / 2f;
				float bonusYaw = num * yawPerProjectile;
				float num2 = num * offsetPerProjectile;
				Ray aimRay = GetAimRay();
				aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, base.characterBody.spreadBloomAngle + spread, 1f, 1f, bonusYaw);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = aimRay.origin + UnityEngine.Vector3.Cross(aimRay.direction, UnityEngine.Vector3.up) * num2;
				fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(aimRay.direction);
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.force = force;
				fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				if (step >= burstCount && IsKeyDownAuthority() && canCharge)
				{
					outer.SetNextState(new ChargeMegaBlaster());
				}
				else
				{
					outer.SetNextState(new Idle());
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)step);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			step = reader.ReadByte();
		}
	}
	public class FireBlaster1 : FireBlasterBase
	{
	}
	public class FireBlaster2 : FireBlasterBase
	{
	}
	public class FireBlaster3 : FireBlasterBase
	{
	}
	public class FireBlaster4 : FireBlasterBase
	{
	}
	public class FireCorruptDisks : BaseSkillState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public float spread;

		[SerializeField]
		public int projectileCount;

		[SerializeField]
		public float yawPerProjectile;

		[SerializeField]
		public float offsetPerProjectile;

		[SerializeField]
		public float selfKnockbackForce;

		[SerializeField]
		public float bonusPitch;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			Ray aimRay = GetAimRay();
			duration = baseDuration / attackSpeedStat;
			StartAimMode(duration + 2f);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(attackSoundString, base.gameObject);
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(bloom);
			base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				FireProjectiles();
			}
		}

		private void FireProjectiles()
		{
			for (int i = 0; i < projectileCount; i++)
			{
				float num = (float)i - (float)(projectileCount - 1) / 2f;
				float bonusYaw = num * yawPerProjectile;
				float num2 = num * offsetPerProjectile;
				Ray aimRay = GetAimRay();
				aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, base.characterBody.spreadBloomAngle + spread, 1f, 1f, bonusYaw, bonusPitch);
				UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
				UnityEngine.Vector3.ProjectOnPlane(onUnitSphere, aimRay.direction);
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction, onUnitSphere);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = aimRay.origin + UnityEngine.Vector3.Cross(aimRay.direction, UnityEngine.Vector3.up) * num2;
				fireProjectileInfo.rotation = rotation;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.force = force;
				fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new Idle());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireRepulsion : BaseState
	{
		[SerializeField]
		public string sound;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public GameObject fireEffectPrefab;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float fieldOfView;

		[SerializeField]
		public float backupDistance;

		[SerializeField]
		public float maxKnockbackDistance;

		[SerializeField]
		public float idealDistanceToPlaceTargets;

		[SerializeField]
		public float liftVelocity;

		[SerializeField]
		public float animationCrossfadeDuration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackParameterName;

		[SerializeField]
		public float damageMultiplier;

		[SerializeField]
		public float maxProjectileReflectDistance;

		[SerializeField]
		public GameObject tracerEffectPrefab;

		[SerializeField]
		public float corruption;

		[SerializeField]
		public BuffDef buffDef;

		[SerializeField]
		public float buffDuration;

		public static AnimationCurve shoveSuitabilityCurve;

		private float duration;

		private Ray aimRay;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			aimRay = GetAimRay();
			PlayCrossfade(animationLayerName, animationStateName, animationPlaybackParameterName, duration, animationCrossfadeDuration);
			Util.PlaySound(sound, base.gameObject);
			UnityEngine.Vector3 origin = aimRay.origin;
			Transform transform = FindModelChild(muzzle);
			if ((bool)transform)
			{
				origin = transform.position;
			}
			EffectManager.SpawnEffect(fireEffectPrefab, new EffectData
			{
				origin = origin,
				rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction)
			}, transmit: false);
			aimRay.origin -= aimRay.direction * backupDistance;
			if (NetworkServer.active)
			{
				PushEnemies();
				ReflectProjectiles();
				VoidSurvivorController component = GetComponent<VoidSurvivorController>();
				if ((bool)component)
				{
					component.AddCorruption(corruption);
				}
			}
		}

		private void ReflectProjectiles()
		{
			UnityEngine.Vector3 vector = (base.characterBody ? base.characterBody.corePosition : UnityEngine.Vector3.zero);
			TeamIndex teamIndex = (base.characterBody ? base.characterBody.teamComponent.teamIndex : TeamIndex.None);
			float num = maxProjectileReflectDistance * maxProjectileReflectDistance;
			List<ProjectileController> instancesList = InstanceTracker.GetInstancesList<ProjectileController>();
			List<ProjectileController> list = new List<ProjectileController>();
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				ProjectileController projectileController = instancesList[i];
				if (projectileController.teamFilter.teamIndex != teamIndex && (projectileController.transform.position - vector).sqrMagnitude < num)
				{
					list.Add(projectileController);
				}
			}
			int j = 0;
			for (int count2 = list.Count; j < count2; j++)
			{
				ProjectileController projectileController2 = list[j];
				if (!projectileController2)
				{
					continue;
				}
				UnityEngine.Vector3 position = projectileController2.transform.position;
				UnityEngine.Vector3 start = vector;
				if ((bool)tracerEffectPrefab)
				{
					EffectData effectData = new EffectData
					{
						origin = position,
						start = start
					};
					EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
				}
				_ = projectileController2.owner;
				CharacterBody component = projectileController2.owner.GetComponent<CharacterBody>();
				projectileController2.IgnoreCollisionsWithOwner(shouldIgnore: false);
				projectileController2.Networkowner = base.gameObject;
				projectileController2.teamFilter.teamIndex = base.characterBody.teamComponent.teamIndex;
				ProjectileDamage component2 = projectileController2.GetComponent<ProjectileDamage>();
				if ((bool)component2)
				{
					component2.damage *= damageMultiplier;
				}
				Rigidbody component3 = projectileController2.GetComponent<Rigidbody>();
				if ((bool)component3)
				{
					UnityEngine.Vector3 vector2 = component3.velocity * -1f;
					if ((bool)component)
					{
						vector2 = component.corePosition - component3.transform.position;
					}
					component3.transform.forward = vector2;
					component3.velocity = UnityEngine.Vector3.RotateTowards(component3.velocity, vector2, float.PositiveInfinity, 0f);
				}
			}
		}

		private void PushEnemies()
		{
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.all;
			bullseyeSearch.maxAngleFilter = fieldOfView * 0.5f;
			bullseyeSearch.maxDistanceFilter = maxKnockbackDistance;
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.RefreshCandidates();
			bullseyeSearch.FilterOutGameObject(base.gameObject);
			IEnumerable<HurtBox> enumerable = bullseyeSearch.GetResults().Where(Util.IsValid).Distinct(default(HurtBox.EntityEqualityComparer));
			TeamIndex team = GetTeam();
			foreach (HurtBox item in enumerable)
			{
				if (FriendlyFireManager.ShouldSplashHitProceed(item.healthComponent, team))
				{
					CharacterBody body = item.healthComponent.body;
					AddDebuff(body);
					body.RecalculateStats();
					_ = body.acceleration;
				}
			}
		}

		protected virtual void AddDebuff(CharacterBody body)
		{
			body.AddTimedBuff(buffDef, buffDuration);
			body.healthComponent.GetComponent<SetStateOnHurt>()?.SetStun(-1f);
		}

		protected virtual float CalculateDamage()
		{
			return 0f;
		}

		protected virtual float CalculateProcCoefficient()
		{
			return 0f;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireTwinBlaster : BaseSkillState
	{
		[SerializeField]
		public GameObject projectile1Prefab;

		[SerializeField]
		public GameObject projectile2Prefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float attackSoundPitchPerStep;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public float spread;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private float duration;

		private float interruptDuration;

		public int step;

		public override void OnEnter()
		{
			base.OnEnter();
			base.activatorSkillSlot = base.skillLocator.primary;
			GetAimRay();
			duration = baseDuration / attackSpeedStat;
			StartAimMode(duration + 2f);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, 1f + (float)step * attackSoundPitchPerStep);
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(bloom);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				FireProjectiles();
			}
		}

		private void FireProjectiles()
		{
			Ray aimRay = GetAimRay();
			aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, base.characterBody.spreadBloomAngle * spread, 1f, 1f);
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.position = aimRay.origin;
			fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(aimRay.direction);
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.damage = damageStat * damageCoefficient;
			fireProjectileInfo.force = force;
			fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
			fireProjectileInfo.projectilePrefab = projectile1Prefab;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectile2Prefab;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeHandBeam : BaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			GetAimRay();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			base.characterBody.SetAimTimer(3f);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextState(new FireHandBeam());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireHandBeam : BaseState
	{
		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject tracerEffectPrefab;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float maxDistance;

		[SerializeField]
		public float force;

		[SerializeField]
		public int bulletCount;

		[SerializeField]
		public float bulletRadius;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float spreadBloomValue = 0.3f;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public float trajectoryAimAssistMultiplier = 0.75f;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude);
			StartAimMode(aimRay);
			Util.PlaySound(attackSoundString, base.gameObject);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.muzzleName = muzzle;
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = base.characterBody.spreadBloomAngle;
				bulletAttack.radius = bulletRadius;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.smartCollision = true;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.procCoefficient = 1f / (float)bulletCount;
				bulletAttack.force = force;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.damageType = DamageType.SlowOnHit;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier;
				bulletAttack.Fire();
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Suppress : BaseSkillState
	{
		[SerializeField]
		public float minimumDuration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public float maxSearchAngleFilter;

		[SerializeField]
		public float maxSearchDistance;

		[SerializeField]
		public float idealDistance;

		[SerializeField]
		public float springConstant;

		[SerializeField]
		public float springMaxLength;

		[SerializeField]
		public float damperConstant;

		[SerializeField]
		public float suppressedTargetForceRadius;

		[SerializeField]
		public GameObject suppressEffectPrefab;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public AnimationCurve forceSuitabilityCurve;

		[SerializeField]
		public float damageCoefficientPerSecond;

		[SerializeField]
		public float procCoefficientPerSecond;

		[SerializeField]
		public float corruptionPerSecond;

		[SerializeField]
		public float maxBreakDistance;

		[SerializeField]
		public float tickRate;

		[SerializeField]
		public bool applyForces;

		private GameObject suppressEffectInstance;

		private Transform idealFXTransform;

		private Transform targetFXTransform;

		private Transform muzzleTransform;

		private VoidSurvivorController voidSurvivorController;

		private CharacterBody targetBody;

		private float damageTickCountdown;

		public override void OnEnter()
		{
			base.OnEnter();
			targetBody = null;
			voidSurvivorController = GetComponent<VoidSurvivorController>();
			PlayAnimation(animationLayerName, animationStateName);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					muzzleTransform = component.FindChild(muzzle);
					if ((bool)muzzleTransform && (bool)suppressEffectPrefab)
					{
						suppressEffectInstance = UnityEngine.Object.Instantiate(suppressEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
						suppressEffectInstance.transform.parent = base.characterBody.transform;
						ChildLocator component2 = suppressEffectInstance.GetComponent<ChildLocator>();
						if ((bool)component2)
						{
							idealFXTransform = component2.FindChild("IdealFX");
							targetFXTransform = component2.FindChild("TargetFX");
						}
					}
				}
			}
			Ray aimRay = GetAimRay();
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam());
			bullseyeSearch.maxAngleFilter = maxSearchAngleFilter;
			bullseyeSearch.maxDistanceFilter = maxSearchDistance;
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.filterByLoS = true;
			bullseyeSearch.RefreshCandidates();
			bullseyeSearch.FilterOutGameObject(base.gameObject);
			HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
			if ((bool)hurtBox)
			{
				UnityEngine.Debug.LogFormat("Found target {0}", targetBody);
				targetBody = hurtBox.healthComponent.body;
			}
		}

		public override void OnExit()
		{
			if ((bool)suppressEffectInstance)
			{
				EntityState.Destroy(suppressEffectInstance);
			}
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			if ((bool)targetBody)
			{
				if ((bool)muzzleTransform)
				{
					suppressEffectInstance.transform.position = muzzleTransform.position;
				}
				if ((bool)idealFXTransform)
				{
					Ray aimRay = GetAimRay();
					_ = targetBody.corePosition;
					UnityEngine.Vector3 position = aimRay.origin + aimRay.direction * idealDistance;
					idealFXTransform.position = position;
				}
				if ((bool)targetFXTransform)
				{
					targetFXTransform.position = targetBody.corePosition;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterBody.SetAimTimer(3f);
			float deltaTime = GetDeltaTime();
			if (NetworkServer.active && (bool)targetBody)
			{
				Ray aimRay = GetAimRay();
				UnityEngine.Vector3 corePosition = targetBody.corePosition;
				UnityEngine.Vector3 vector = aimRay.origin + aimRay.direction * idealDistance;
				if (applyForces)
				{
					UnityEngine.Vector3 vector2 = vector - corePosition;
					float magnitude = vector2.magnitude;
					Mathf.Clamp01(magnitude / suppressedTargetForceRadius);
					UnityEngine.Vector3 velocity;
					float mass;
					bool flag;
					if ((bool)targetBody.characterMotor)
					{
						velocity = targetBody.characterMotor.velocity;
						mass = targetBody.characterMotor.mass;
						flag = !targetBody.characterMotor.isFlying;
					}
					else
					{
						Rigidbody obj = targetBody.rigidbody;
						velocity = obj.velocity;
						mass = obj.mass;
						flag = obj.useGravity;
					}
					UnityEngine.Vector3 vector3 = vector2.normalized * Mathf.Min(springMaxLength, magnitude) * springConstant * deltaTime;
					UnityEngine.Vector3 vector4 = -velocity * damperConstant * deltaTime;
					UnityEngine.Vector3 vector5 = (flag ? (Physics.gravity * deltaTime * mass) : UnityEngine.Vector3.zero);
					float num = forceSuitabilityCurve.Evaluate(mass);
					targetBody.healthComponent.TakeDamageForce((vector3 + vector4) * num - vector5, alwaysApply: true, disableAirControlUntilCollision: true);
				}
				damageTickCountdown -= deltaTime;
				if (damageTickCountdown <= 0f)
				{
					damageTickCountdown = 1f / tickRate;
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.attacker = base.gameObject;
					damageInfo.procCoefficient = procCoefficientPerSecond / tickRate;
					damageInfo.damage = damageCoefficientPerSecond * damageStat / tickRate;
					damageInfo.crit = RollCrit();
					targetBody.healthComponent.TakeDamage(damageInfo);
					voidSurvivorController.AddCorruption(corruptionPerSecond / tickRate);
				}
			}
			if (base.isAuthority && (!targetBody || !targetBody.healthComponent.alive))
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class EnterSwingMelee : BaseState, SteppedSkillDef.IStepSetter
	{
		public int step;

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			step = i;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)step);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			step = reader.ReadByte();
		}

		public override void OnEnter()
		{
			base.OnEnter();
			switch (step)
			{
			case 0:
				outer.SetNextState(new SwingMelee1());
				break;
			case 1:
				outer.SetNextState(new SwingMelee2());
				break;
			case 2:
				outer.SetNextState(new SwingMelee3());
				break;
			default:
				outer.SetNextState(new SwingMelee1());
				break;
			}
		}
	}
	public class SwingMeleeBase : BasicMeleeAttack
	{
		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParameter;

		protected override bool allowExitFire
		{
			get
			{
				if ((bool)base.characterBody)
				{
					return !base.characterBody.isSprinting;
				}
				return false;
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterDirection.forward = GetAimRay().direction;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
		}

		protected override void PlayAnimation()
		{
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParameter, duration);
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			base.characterBody.AddSpreadBloom(bloom);
		}

		protected override void BeginMeleeAttackEffect()
		{
			AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			base.BeginMeleeAttackEffect();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SwingMelee1 : SwingMeleeBase
	{
	}
	public class SwingMelee2 : SwingMeleeBase
	{
	}
	public class SwingMelee3 : SwingMeleeBase
	{
	}
}
namespace EntityStates.VoidSurvivor.Vent
{
	public class VentCorruption : GenericCharacterMain
	{
		[SerializeField]
		public float minimumDuration;

		[SerializeField]
		public float maximumDuration;

		[SerializeField]
		public string leftVentEffectChildLocatorEntry;

		[SerializeField]
		public string rightVentEffectChildLocatorEntry;

		[SerializeField]
		public string miniVentEffectChildLocatorEntry;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string exitSoundString;

		[SerializeField]
		public float animationCrossfadeDuration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string enterAnimationStateName;

		[SerializeField]
		public string exitAnimationStateName;

		[SerializeField]
		public float hoverVelocity;

		[SerializeField]
		public float hoverAcceleration;

		[SerializeField]
		public float healingPercentagePerSecond;

		[SerializeField]
		public float healingTickRate;

		[SerializeField]
		public float corruptionReductionPerSecond;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public float turnSpeed;

		private float healPerTick;

		private float healTickStopwatch;

		private float corruptionReductionPerTick;

		private UnityEngine.Vector3 liftVector = UnityEngine.Vector3.up;

		private VoidSurvivorController voidSurvivorController;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private float previousTurnSpeed;

		public override void OnEnter()
		{
			base.OnEnter();
			voidSurvivorController = GetComponent<VoidSurvivorController>();
			voidSurvivorController = GetComponent<VoidSurvivorController>();
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayCrossfade(animationLayerName, enterAnimationStateName, animationCrossfadeDuration);
			healPerTick = base.healthComponent.fullHealth * healingPercentagePerSecond / healingTickRate;
			corruptionReductionPerTick = corruptionReductionPerSecond / healingTickRate;
			FindModelChild(leftVentEffectChildLocatorEntry)?.gameObject.SetActive(value: true);
			FindModelChild(rightVentEffectChildLocatorEntry)?.gameObject.SetActive(value: true);
			FindModelChild(miniVentEffectChildLocatorEntry)?.gameObject.SetActive(value: true);
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			if ((bool)base.characterDirection)
			{
				previousTurnSpeed = base.characterDirection.turnSpeed;
				base.characterDirection.turnSpeed = turnSpeed;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterBody.SetAimTimer(1f);
			if (NetworkServer.active)
			{
				healTickStopwatch += GetDeltaTime();
				if (healTickStopwatch > 1f / healingTickRate)
				{
					healTickStopwatch -= 1f / healingTickRate;
					base.healthComponent.Heal(healPerTick, default(ProcChainMask));
					if ((bool)voidSurvivorController)
					{
						voidSurvivorController.AddCorruption(0f - corruptionReductionPerTick);
					}
				}
			}
			if (!base.isAuthority)
			{
				return;
			}
			if ((bool)base.characterMotor)
			{
				float y = base.characterMotor.velocity.y;
				if (y < hoverVelocity)
				{
					y = Mathf.MoveTowards(y, hoverVelocity, hoverAcceleration * GetDeltaTime());
					base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, y, base.characterMotor.velocity.z);
				}
			}
			if (base.fixedAge >= maximumDuration || (base.fixedAge >= minimumDuration && (bool)voidSurvivorController && voidSurvivorController.corruption <= voidSurvivorController.minimumCorruption))
			{
				outer.SetNextStateToMain();
			}
		}

		protected override bool CanExecuteSkill(GenericSkill skillSlot)
		{
			return false;
		}

		public override void OnExit()
		{
			if ((bool)base.characterDirection)
			{
				base.characterDirection.turnSpeed = previousTurnSpeed;
			}
			crosshairOverrideRequest?.Dispose();
			FindModelChild(leftVentEffectChildLocatorEntry)?.gameObject.SetActive(value: false);
			FindModelChild(rightVentEffectChildLocatorEntry)?.gameObject.SetActive(value: false);
			FindModelChild(miniVentEffectChildLocatorEntry)?.gameObject.SetActive(value: false);
			PlayCrossfade(animationLayerName, exitAnimationStateName, animationCrossfadeDuration);
			Util.PlaySound(exitSoundString, base.gameObject);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.VoidSurvivor.CorruptMode
{
	public class CorruptModeBase : BaseState
	{
		protected VoidSurvivorController voidSurvivorController;

		public override void OnEnter()
		{
			base.OnEnter();
			voidSurvivorController = GetComponent<VoidSurvivorController>();
		}
	}
	public class CorruptMode : CorruptModeBase
	{
		[SerializeField]
		public SkillDef primaryOverrideSkillDef;

		[SerializeField]
		public SkillDef secondaryOverrideSkillDef;

		[SerializeField]
		public SkillDef utilityOverrideSkillDef;

		[SerializeField]
		public SkillDef specialOverrideSkillDef;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority && (bool)base.skillLocator)
			{
				base.skillLocator.primary.SetSkillOverride(this, primaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
				base.skillLocator.secondary.SetSkillOverride(this, secondaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
				base.skillLocator.utility.SetSkillOverride(this, utilityOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
				base.skillLocator.special.SetSkillOverride(this, specialOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
			}
			if ((bool)voidSurvivorController && NetworkServer.active)
			{
				base.characterBody.AddBuff(voidSurvivorController.corruptedBuffDef);
			}
		}

		public override void OnExit()
		{
			if (base.isAuthority && (bool)base.skillLocator)
			{
				base.skillLocator.primary.UnsetSkillOverride(this, primaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
				base.skillLocator.secondary.UnsetSkillOverride(this, secondaryOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
				base.skillLocator.utility.UnsetSkillOverride(this, utilityOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
				base.skillLocator.special.UnsetSkillOverride(this, specialOverrideSkillDef, GenericSkill.SkillOverridePriority.Upgrade);
			}
			if ((bool)voidSurvivorController && NetworkServer.active)
			{
				base.characterBody.RemoveBuff(voidSurvivorController.corruptedBuffDef);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (bool)voidSurvivorController && voidSurvivorController.corruption <= voidSurvivorController.minimumCorruption && !voidSurvivorController.isPermanentlyCorrupted && (bool)voidSurvivorController.bodyStateMachine)
			{
				voidSurvivorController.bodyStateMachine.SetInterruptState(new ExitCorruptionTransition(), InterruptPriority.Skill);
			}
		}
	}
	public class UncorruptedMode : CorruptModeBase
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (bool)voidSurvivorController && voidSurvivorController.corruption >= voidSurvivorController.maxCorruption && (bool)voidSurvivorController.bodyStateMachine)
			{
				voidSurvivorController.bodyStateMachine.SetInterruptState(new EnterCorruptionTransition(), InterruptPriority.Skill);
			}
		}
	}
}
namespace EntityStates.VoidRaidCrab
{
	public class BaseWardWipeState : BaseState
	{
		[SerializeField]
		public GameObject safeWardDisappearEffectPrefab;

		protected List<GameObject> safeWards = new List<GameObject>();

		protected FogDamageController fogDamageController;

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (nextState is BaseWardWipeState baseWardWipeState)
			{
				baseWardWipeState.fogDamageController = fogDamageController;
				baseWardWipeState.safeWards = safeWards;
				return;
			}
			if ((bool)fogDamageController)
			{
				fogDamageController.enabled = false;
			}
			if (safeWards == null || !NetworkServer.active)
			{
				return;
			}
			foreach (GameObject safeWard in safeWards)
			{
				if ((bool)fogDamageController)
				{
					IZone component = safeWard.GetComponent<IZone>();
					fogDamageController.RemoveSafeZone(component);
				}
				if ((bool)safeWardDisappearEffectPrefab)
				{
					EffectData effectData = new EffectData();
					effectData.origin = safeWard.transform.position;
					EffectManager.SpawnEffect(safeWardDisappearEffectPrefab, effectData, transmit: true);
				}
				EntityState.Destroy(safeWard);
			}
		}
	}
	public class ChannelGauntlet : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public GameObject overlayPrefab;

		[SerializeField]
		public string overlayChildLocatorEntryName;

		[SerializeField]
		public string fillImageChildLocatorEntryName;

		private List<OverlayController> overlayControllers;

		private HashSet<UnityEngine.UI.Image> overlayFillImages;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Player);
			overlayControllers = new List<OverlayController>();
			overlayFillImages = new HashSet<UnityEngine.UI.Image>();
			foreach (TeamComponent item in teamMembers)
			{
				OverlayController overlayController = HudOverlayManager.AddOverlay(item.gameObject, new OverlayCreationParams
				{
					prefab = overlayPrefab,
					childLocatorEntry = overlayChildLocatorEntryName
				});
				overlayController.onInstanceAdded += OnOverlayInstanceAdded;
				overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
				overlayControllers.Add(overlayController);
			}
		}

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			if (!instance)
			{
				return;
			}
			ChildLocator component = instance.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				UnityEngine.UI.Image image = component.FindChildComponent<UnityEngine.UI.Image>(fillImageChildLocatorEntryName);
				if (image != null)
				{
					overlayFillImages.Add(image);
				}
			}
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			if (!instance)
			{
				return;
			}
			ChildLocator component = instance.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				UnityEngine.UI.Image image = component.FindChildComponent<UnityEngine.UI.Image>(overlayChildLocatorEntryName);
				if (image != null)
				{
					overlayFillImages.Remove(image);
				}
			}
		}

		public override void OnExit()
		{
			overlayFillImages.Clear();
			foreach (OverlayController overlayController in overlayControllers)
			{
				HudOverlayManager.RemoveOverlay(overlayController);
				overlayController.onInstanceAdded -= OnOverlayInstanceAdded;
				overlayController.onInstanceRemove -= OnOverlayInstanceRemoved;
			}
			overlayControllers.Clear();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (duration > 0f)
			{
				float fillAmount = base.fixedAge / duration;
				foreach (UnityEngine.UI.Image overlayFillImage in overlayFillImages)
				{
					overlayFillImage.fillAmount = fillAmount;
				}
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				_ = (bool)VoidRaidGauntletController.instance;
				outer.SetNextState(new CloseGauntlet());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class ChargeFinalStand : BaseWardWipeState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		private GameObject chargeEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator && (bool)chargeEffectPrefab)
			{
				Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform;
				if ((bool)transform)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
					ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = duration;
					}
				}
			}
			fogDamageController = GetComponent<FogDamageController>();
			fogDamageController.enabled = true;
			safeWards = new List<GameObject>();
			PhasedInventorySetter component2 = GetComponent<PhasedInventorySetter>();
			if ((bool)component2 && NetworkServer.active)
			{
				component2.AdvancePhase();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				FireFinalStand nextState = new FireFinalStand();
				outer.SetNextState(nextState);
			}
		}

		public override void OnExit()
		{
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class ChargeGauntlet : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public SkillDef skillDefToReplaceAtStocksEmpty;

		[SerializeField]
		public SkillDef nextSkillDef;

		private GameObject chargeEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator && (bool)chargeEffectPrefab)
			{
				Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform;
				if ((bool)transform)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
					ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = duration;
					}
				}
			}
			PhasedInventorySetter component2 = GetComponent<PhasedInventorySetter>();
			if ((bool)component2 && NetworkServer.active)
			{
				component2.AdvancePhase();
			}
			if ((bool)nextSkillDef)
			{
				GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty);
				if ((bool)genericSkill && genericSkill.stock == 0)
				{
					genericSkill.SetBaseSkill(nextSkillDef);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				_ = (bool)VoidRaidGauntletController.instance;
				outer.SetNextState(new ChannelGauntlet());
			}
		}

		public override void OnExit()
		{
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class ChargeWardWipe : BaseWardWipeState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public InteractableSpawnCard safeWardSpawnCard;

		[SerializeField]
		public AnimationCurve safeWardSpawnCurve;

		[SerializeField]
		public float minDistanceBetweenConsecutiveWards;

		[SerializeField]
		public float maxDistanceBetweenConsecutiveWards;

		[SerializeField]
		public float maxDistanceToInitialWard;

		private GameObject chargeEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator && (bool)chargeEffectPrefab)
			{
				Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform;
				if ((bool)transform)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
					ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = duration;
					}
				}
			}
			fogDamageController = GetComponent<FogDamageController>();
			fogDamageController.enabled = true;
			safeWards = new List<GameObject>();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)safeWardSpawnCard)
			{
				float time = base.fixedAge / duration;
				float f = safeWardSpawnCurve.Evaluate(time);
				DirectorPlacementRule directorPlacementRule = null;
				while ((float)safeWards.Count < Mathf.Floor(f))
				{
					if (directorPlacementRule == null)
					{
						directorPlacementRule = new DirectorPlacementRule
						{
							placementMode = DirectorPlacementRule.PlacementMode.Approximate,
							maxDistance = maxDistanceToInitialWard,
							minDistance = 0f,
							spawnOnTarget = base.gameObject.transform,
							preventOverhead = true
						};
					}
					if (safeWards.Count > 0)
					{
						directorPlacementRule.maxDistance = maxDistanceBetweenConsecutiveWards;
						directorPlacementRule.minDistance = minDistanceBetweenConsecutiveWards;
						directorPlacementRule.spawnOnTarget = safeWards[safeWards.Count - 1].transform;
						directorPlacementRule.placementMode = DirectorPlacementRule.PlacementMode.Approximate;
					}
					GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(safeWardSpawnCard, directorPlacementRule, Run.instance.stageRng));
					if ((bool)gameObject)
					{
						NetworkServer.Spawn(gameObject);
						if ((bool)fogDamageController)
						{
							IZone component = gameObject.GetComponent<IZone>();
							fogDamageController.AddSafeZone(component);
						}
						safeWards.Add(gameObject);
					}
					else
					{
						UnityEngine.Debug.LogError("Unable to spawn safe ward instance.  Are there any ground nodes?");
					}
				}
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				FireWardWipe nextState = new FireWardWipe();
				outer.SetNextState(nextState);
			}
		}

		public override void OnExit()
		{
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class CloseGauntlet : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class Collapse : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new ReEmerge());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public GameObject initialEffectPrefab;

		[SerializeField]
		public string initialEffectMuzzle;

		[SerializeField]
		public GameObject explosionEffectPrefab;

		[SerializeField]
		public string explosionEffectMuzzle;

		[SerializeField]
		public UnityEngine.Vector3 ragdollForce;

		[SerializeField]
		public float explosionForce;

		[SerializeField]
		public bool addPrintController;

		[SerializeField]
		public float printDuration;

		[SerializeField]
		public float startingPrintBias;

		[SerializeField]
		public float maxPrintBias;

		private Transform modelTransform;

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration)
		{
			PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, crossfadeDuration);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)VoidRaidGauntletController.instance)
			{
				VoidRaidGauntletController.instance.SetCurrentDonutCombatDirectorEnabled(isEnabled: false);
			}
			modelTransform = GetModelTransform();
			Transform transform = FindModelChild("StandableSurface");
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: false);
			}
			if ((bool)explosionEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(initialEffectPrefab, base.gameObject, initialEffectMuzzle, transmit: false);
			}
			if (addPrintController)
			{
				PrintController printController = modelTransform.gameObject.AddComponent<PrintController>();
				printController.printTime = printDuration;
				printController.enabled = true;
				printController.startingPrintHeight = 99f;
				printController.maxPrintHeight = 99f;
				printController.startingPrintBias = startingPrintBias;
				printController.maxPrintBias = maxPrintBias;
				printController.disableWhenFinished = false;
				printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				if ((bool)explosionEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(explosionEffectPrefab, base.gameObject, explosionEffectMuzzle, transmit: true);
				}
				DestroyBodyAsapServer();
			}
		}

		public override void OnExit()
		{
			if ((bool)modelTransform)
			{
				RagdollController component = modelTransform.GetComponent<RagdollController>();
				Rigidbody component2 = GetComponent<Rigidbody>();
				if ((bool)component && (bool)component2)
				{
					component.BeginRagdoll(ragdollForce);
				}
				ExplodeRigidbodiesOnStart component3 = modelTransform.GetComponent<ExplodeRigidbodiesOnStart>();
				if ((bool)component3)
				{
					component3.force = explosionForce;
					component3.enabled = true;
				}
			}
		}
	}
	public class EscapeDeath : GenericCharacterDeath
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public bool addPrintController;

		[SerializeField]
		public float printDuration;

		[SerializeField]
		public float startingPrintHeight;

		[SerializeField]
		public float maxPrintHeight;

		[SerializeField]
		public string gauntletEntranceChildName;

		[SerializeField]
		public string enterSoundString;

		private UnityEngine.Vector3 gauntletEntrancePosition;

		private Transform gauntletEntranceTransform;

		private NetworkInstanceId netId;

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration)
		{
			PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, crossfadeDuration);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			netId = NetworkInstanceId.Invalid;
			if ((bool)base.characterBody && (bool)base.characterBody.master)
			{
				netId = base.characterBody.master.netId;
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			if (addPrintController)
			{
				Transform modelTransform = GetModelTransform();
				if ((bool)modelTransform)
				{
					PrintController printController = modelTransform.gameObject.AddComponent<PrintController>();
					printController.printTime = printDuration;
					printController.enabled = true;
					printController.startingPrintHeight = startingPrintHeight;
					printController.maxPrintHeight = maxPrintHeight;
					printController.startingPrintBias = 0f;
					printController.maxPrintBias = 0f;
					printController.disableWhenFinished = false;
					printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
				}
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				gauntletEntranceTransform = modelChildLocator.FindChild(gauntletEntranceChildName);
				RefreshGauntletEntrancePosition();
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active)
			{
				RefreshGauntletEntrancePosition();
				VoidRaidGauntletController.instance.TryOpenGauntlet(gauntletEntrancePosition, netId);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				RefreshGauntletEntrancePosition();
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		private void RefreshGauntletEntrancePosition()
		{
			if ((bool)gauntletEntranceTransform)
			{
				gauntletEntrancePosition = gauntletEntranceTransform.position;
			}
		}
	}
	public class FireFinalStand : BaseWardWipeState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public BuffDef requiredBuffToKill;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)muzzleFlashPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (!fogDamageController)
			{
				return;
			}
			if (NetworkServer.active)
			{
				foreach (CharacterBody affectedBody in fogDamageController.GetAffectedBodies())
				{
					if (!requiredBuffToKill || affectedBody.HasBuff(requiredBuffToKill))
					{
						affectedBody.healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath);
					}
				}
			}
			fogDamageController.enabled = false;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class FireWardWipe : BaseWardWipeState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public SkillDef skillDefToReplaceAtStocksEmpty;

		[SerializeField]
		public SkillDef nextSkillDef;

		[SerializeField]
		public BuffDef requiredBuffToKill;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)muzzleFlashPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if ((bool)nextSkillDef)
			{
				GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty);
				if ((bool)genericSkill && genericSkill.stock == 0)
				{
					genericSkill.SetBaseSkill(nextSkillDef);
				}
			}
			if (!fogDamageController)
			{
				return;
			}
			if (NetworkServer.active)
			{
				foreach (CharacterBody affectedBody in fogDamageController.GetAffectedBodies())
				{
					if (!requiredBuffToKill || affectedBody.HasBuff(requiredBuffToKill))
					{
						affectedBody.healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath);
					}
				}
			}
			fogDamageController.enabled = false;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class LegBreakStunState : BaseState
	{
		public static string animLayerName;

		public static string animStateName;

		public static string animPlaybackRateParamName;

		public static float baseDuration;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			PlayAnimation(animLayerName, animStateName, animPlaybackRateParamName, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class ReEmerge : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if (NetworkServer.active)
			{
				CentralLegController component = GetComponent<CentralLegController>();
				if ((bool)component)
				{
					component.RegenerateAllBrokenServer();
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class SpawnState : BaseState
	{
		[SerializeField]
		public float duration = 4f;

		[SerializeField]
		public string spawnSoundString;

		[SerializeField]
		public GameObject spawnEffectPrefab;

		[SerializeField]
		public string spawnMuzzleName;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public bool doLegs;

		[SerializeField]
		public CharacterSpawnCard jointSpawnCard;

		[SerializeField]
		public string leg1Name;

		[SerializeField]
		public string leg2Name;

		[SerializeField]
		public string leg3Name;

		[SerializeField]
		public string leg4Name;

		[SerializeField]
		public string leg5Name;

		[SerializeField]
		public string leg6Name;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnMuzzleName, transmit: false);
			}
			if (doLegs && NetworkServer.active)
			{
				ChildLocator modelChildLocator = GetModelChildLocator();
				if ((bool)jointSpawnCard && (bool)modelChildLocator)
				{
					DirectorPlacementRule placementRule = new DirectorPlacementRule
					{
						placementMode = DirectorPlacementRule.PlacementMode.Direct,
						spawnOnTarget = base.transform
					};
					SpawnJointBodyForLegServer(leg1Name, modelChildLocator, placementRule);
					SpawnJointBodyForLegServer(leg2Name, modelChildLocator, placementRule);
					SpawnJointBodyForLegServer(leg3Name, modelChildLocator, placementRule);
					SpawnJointBodyForLegServer(leg4Name, modelChildLocator, placementRule);
					SpawnJointBodyForLegServer(leg5Name, modelChildLocator, placementRule);
					SpawnJointBodyForLegServer(leg6Name, modelChildLocator, placementRule);
				}
			}
		}

		private void SpawnJointBodyForLegServer(string legName, ChildLocator childLocator, DirectorPlacementRule placementRule)
		{
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(jointSpawnCard, placementRule, Run.instance.stageRng);
			directorSpawnRequest.summonerBodyObject = base.gameObject;
			GameObject gameObject = DirectorCore.instance?.TrySpawnObject(directorSpawnRequest);
			Transform transform = childLocator.FindChild(legName);
			if (!gameObject || !transform)
			{
				return;
			}
			CharacterMaster component = gameObject.GetComponent<CharacterMaster>();
			if ((bool)component)
			{
				LegController component2 = transform.GetComponent<LegController>();
				if ((bool)component2)
				{
					component2.SetJointMaster(component, transform.GetComponent<ChildLocator>());
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class BaseSpinBeamAttackState : BaseState
	{
		[SerializeField]
		public string animLayerName;

		[SerializeField]
		public string animStateName;

		[SerializeField]
		public string animPlaybackRateParamName;

		[SerializeField]
		public float baseDuration;

		public static string headTransformNameInChildLocator;

		public static string muzzleTransformNameInChildLocator;

		public static string headYawParamName;

		[SerializeField]
		public AnimationCurve headForwardYCurve;

		private Transform headTransform;

		private Transform muzzleTransform;

		private bool hasHeadSpinOwnership;

		protected float duration { get; private set; }

		protected Animator modelAnimator { get; private set; }

		protected GameObject beamVfxInstance { get; private set; }

		protected float normalizedFixedAge => Mathf.Clamp01(base.fixedAge / duration);

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			headTransform = FindModelChild(headTransformNameInChildLocator);
			muzzleTransform = FindModelChild(muzzleTransformNameInChildLocator);
			duration = baseDuration;
			if (!string.IsNullOrEmpty(animLayerName) && !string.IsNullOrEmpty(animStateName))
			{
				if (!string.IsNullOrEmpty(animPlaybackRateParamName))
				{
					PlayAnimation(animLayerName, animStateName, animPlaybackRateParamName, duration);
				}
				else
				{
					PlayAnimation(animLayerName, animStateName);
				}
			}
			if ((bool)modelAnimator)
			{
				modelAnimator.GetComponent<AimAnimator>().enabled = true;
			}
			hasHeadSpinOwnership = true;
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (nextState is BaseSpinBeamAttackState baseSpinBeamAttackState)
			{
				baseSpinBeamAttackState.hasHeadSpinOwnership |= hasHeadSpinOwnership;
				hasHeadSpinOwnership = false;
			}
		}

		public override void OnExit()
		{
			if (hasHeadSpinOwnership)
			{
				SetHeadYawRevolutions(0f);
				hasHeadSpinOwnership = true;
			}
			DestroyBeamVFXInstance();
			base.OnExit();
		}

		protected void SetHeadYawRevolutions(float newRevolutions)
		{
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat(headYawParamName, (0.5f + newRevolutions) % 1f);
			}
		}

		protected Ray GetBeamRay()
		{
			_ = muzzleTransform.forward;
			UnityEngine.Vector3 forward = headTransform.forward;
			forward.y = headForwardYCurve.Evaluate(base.fixedAge / duration);
			forward.Normalize();
			return new Ray(muzzleTransform.position, forward);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		protected void CreateBeamVFXInstance(GameObject beamVfxPrefab)
		{
			if ((object)beamVfxInstance != null)
			{
				throw new InvalidOperationException();
			}
			beamVfxInstance = UnityEngine.Object.Instantiate(beamVfxPrefab);
			beamVfxInstance.transform.SetParent(headTransform, worldPositionStays: true);
			UpdateBeamTransforms();
			RoR2Application.onLateUpdate += UpdateBeamTransformsInLateUpdate;
		}

		protected void DestroyBeamVFXInstance()
		{
			if ((object)beamVfxInstance != null)
			{
				RoR2Application.onLateUpdate -= UpdateBeamTransformsInLateUpdate;
				VfxKillBehavior.KillVfxObject(beamVfxInstance);
				beamVfxInstance = null;
			}
		}

		private void UpdateBeamTransformsInLateUpdate()
		{
			try
			{
				UpdateBeamTransforms();
			}
			catch (Exception exception)
			{
				UnityEngine.Debug.LogException(exception);
			}
		}

		private void UpdateBeamTransforms()
		{
			Ray beamRay = GetBeamRay();
			beamVfxInstance.transform.SetPositionAndRotation(beamRay.origin, UnityEngine.Quaternion.LookRotation(beamRay.direction));
		}
	}
	public class SpinBeamEnter : BaseSpinBeamAttackState
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= base.duration && base.isAuthority)
			{
				outer.SetNextState(new SpinBeamWindUp());
			}
		}
	}
	public class SpinBeamWindUp : BaseSpinBeamAttackState
	{
		public static AnimationCurve revolutionsCurve;

		public static GameObject warningLaserPrefab;

		public static string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			CreateBeamVFXInstance(warningLaserPrefab);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= base.duration && base.isAuthority)
			{
				outer.SetNextState(new SpinBeamAttack());
			}
			SetHeadYawRevolutions(revolutionsCurve.Evaluate(base.normalizedFixedAge));
		}
	}
	public class SpinBeamWindDown : BaseSpinBeamAttackState
	{
		public static AnimationCurve revolutionsCurve;

		public static string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= base.duration && base.isAuthority)
			{
				outer.SetNextState(new SpinBeamExit());
			}
			SetHeadYawRevolutions(revolutionsCurve.Evaluate(base.normalizedFixedAge));
		}
	}
	public class SpinBeamExit : BaseSpinBeamAttackState
	{
		[SerializeField]
		public SkillDef skillDefToReplaceAtStocksEmpty;

		[SerializeField]
		public SkillDef nextSkillDef;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)nextSkillDef)
			{
				GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty);
				if ((bool)genericSkill && genericSkill.stock == 0)
				{
					genericSkill.SetBaseSkill(nextSkillDef);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= base.duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class SpinBeamAttack : BaseSpinBeamAttackState
	{
		public static AnimationCurve revolutionsCurve;

		public static GameObject beamVfxPrefab;

		public static float beamRadius = 16f;

		public static float beamMaxDistance = 400f;

		public static float beamDpsCoefficient = 1f;

		public static float beamTickFrequency = 4f;

		public static GameObject beamImpactEffectPrefab;

		public static LoopSoundDef loopSound;

		public static string enterSoundString;

		private float beamTickTimer;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		public override void OnEnter()
		{
			base.OnEnter();
			CreateBeamVFXInstance(beamVfxPrefab);
			loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void OnExit()
		{
			LoopSoundManager.StopSoundLoopLocal(loopPtr);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= base.duration && base.isAuthority)
			{
				outer.SetNextState(new SpinBeamWindDown());
			}
			if (base.isAuthority)
			{
				if (beamTickTimer <= 0f)
				{
					beamTickTimer += 1f / beamTickFrequency;
					FireBeamBulletAuthority();
				}
				beamTickTimer -= GetDeltaTime();
			}
			SetHeadYawRevolutions(revolutionsCurve.Evaluate(base.normalizedFixedAge));
		}

		private void FireBeamBulletAuthority()
		{
			Ray beamRay = GetBeamRay();
			BulletAttack bulletAttack = new BulletAttack();
			bulletAttack.muzzleName = BaseSpinBeamAttackState.muzzleTransformNameInChildLocator;
			bulletAttack.origin = beamRay.origin;
			bulletAttack.aimVector = beamRay.direction;
			bulletAttack.minSpread = 0f;
			bulletAttack.maxSpread = 0f;
			bulletAttack.maxDistance = 400f;
			bulletAttack.hitMask = LayerIndex.CommonMasks.bullet;
			bulletAttack.stopperMask = 0;
			bulletAttack.bulletCount = 1u;
			bulletAttack.radius = beamRadius;
			bulletAttack.smartCollision = false;
			bulletAttack.queryTriggerInteraction = QueryTriggerInteraction.Ignore;
			bulletAttack.procCoefficient = 1f;
			bulletAttack.procChainMask = default(ProcChainMask);
			bulletAttack.owner = base.gameObject;
			bulletAttack.weapon = base.gameObject;
			bulletAttack.damage = beamDpsCoefficient * damageStat / beamTickFrequency;
			bulletAttack.damageColorIndex = DamageColorIndex.Default;
			bulletAttack.damageType = DamageType.Generic;
			bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
			bulletAttack.force = 0f;
			bulletAttack.hitEffectPrefab = beamImpactEffectPrefab;
			bulletAttack.tracerEffectPrefab = null;
			bulletAttack.isCrit = false;
			bulletAttack.HitEffectNormal = false;
			bulletAttack.Fire();
		}
	}
	public class TurnState : GenericCharacterMain
	{
		[SerializeField]
		public float duration = 1f;

		[SerializeField]
		public float turnDegrees = 22.5f;

		[SerializeField]
		public int maxNumConsecutiveTurns;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string clockwiseAnimationStateName;

		[SerializeField]
		public string counterClockwiseAnimationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private CentralLegController centralLegController;

		private CentralLegController.SuppressBreaksRequest suppressBreaksRequest;

		private int turnCount = 1;

		private bool isClockwiseTurn;

		private bool canTurn;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				centralLegController = GetComponent<CentralLegController>();
				if ((bool)centralLegController)
				{
					suppressBreaksRequest = centralLegController.SuppressBreaks();
				}
				float dirToAimDegrees = GetDirToAimDegrees();
				if (dirToAimDegrees >= turnDegrees)
				{
					isClockwiseTurn = true;
					canTurn = true;
				}
				else if (dirToAimDegrees <= 0f - turnDegrees)
				{
					isClockwiseTurn = false;
					canTurn = true;
				}
			}
			if (canTurn)
			{
				if (isClockwiseTurn)
				{
					PlayAnimation(animationLayerName, clockwiseAnimationStateName, animationPlaybackRateParam, duration);
				}
				else
				{
					PlayAnimation(animationLayerName, counterClockwiseAnimationStateName, animationPlaybackRateParam, duration);
				}
			}
			else if (base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			suppressBreaksRequest?.Dispose();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				if (Mathf.Abs(GetDirToAimDegrees()) >= turnDegrees && (bool)centralLegController && !centralLegController.AreAnyBreaksPending() && turnCount < maxNumConsecutiveTurns)
				{
					TurnState turnState = new TurnState();
					turnState.turnCount = turnCount + 1;
					outer.SetNextState(turnState);
				}
				else
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public float GetDirToAimDegrees()
		{
			float num = 0f;
			if ((bool)base.inputBank && (bool)base.characterDirection)
			{
				UnityEngine.Vector3 rhs = base.inputBank.aimDirection;
				rhs.y = 0f;
				rhs.Normalize();
				UnityEngine.Vector3 forward = base.characterDirection.forward;
				forward.y = 0f;
				forward.Normalize();
				num = Mathf.Acos(UnityEngine.Vector3.Dot(forward, rhs)) * 57.29578f;
				if (UnityEngine.Vector3.Dot(UnityEngine.Vector3.Cross(forward, rhs), UnityEngine.Vector3.up) < 0f)
				{
					num *= -1f;
				}
			}
			return num;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(isClockwiseTurn);
			writer.Write(canTurn);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			isClockwiseTurn = reader.ReadBoolean();
			canTurn = reader.ReadBoolean();
		}
	}
	public abstract class BaseVacuumAttackState : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string animLayerName;

		[SerializeField]
		public string animStateName;

		[SerializeField]
		public string animPlaybackRateParamName;

		public static string vacuumOriginChildLocatorName;

		protected float duration { get; private set; }

		protected Transform vacuumOrigin { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if (!string.IsNullOrEmpty(animLayerName) && !string.IsNullOrEmpty(animStateName) && !string.IsNullOrEmpty(animPlaybackRateParamName))
			{
				PlayAnimation(animLayerName, animStateName, animPlaybackRateParamName, duration);
			}
			if (!string.IsNullOrEmpty(vacuumOriginChildLocatorName))
			{
				vacuumOrigin = FindModelChild(vacuumOriginChildLocatorName);
			}
			else
			{
				vacuumOrigin = base.transform;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				OnLifetimeExpiredAuthority();
			}
		}

		protected abstract void OnLifetimeExpiredAuthority();

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class VacuumEnter : BaseVacuumAttackState
	{
		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new VacuumWindUp());
		}
	}
	public class VacuumWindUp : BaseVacuumAttackState
	{
		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new VacuumAttack());
		}
	}
	public class VacuumAttack : BaseVacuumAttackState
	{
		public static AnimationCurve killRadiusCurve;

		public static AnimationCurve pullMagnitudeCurve;

		public static float losObstructionFactor = 0.5f;

		public static GameObject killSphereVfxPrefab;

		public static GameObject environmentVfxPrefab;

		public static LoopSoundDef loopSound;

		private CharacterLosTracker losTracker;

		private VFXHelper killSphereVfxHelper;

		private VFXHelper environmentVfxHelper;

		private SphereSearch killSearch;

		private float killRadius = 1f;

		private BodyIndex jointBodyIndex = BodyIndex.None;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		public override void OnEnter()
		{
			base.OnEnter();
			losTracker = new CharacterLosTracker();
			losTracker.enabled = true;
			killSphereVfxHelper = VFXHelper.Rent();
			killSphereVfxHelper.vfxPrefabReference = killSphereVfxPrefab;
			killSphereVfxHelper.followedTransform = base.vacuumOrigin;
			killSphereVfxHelper.useFollowedTransformScale = false;
			killSphereVfxHelper.enabled = true;
			UpdateKillSphereVfx();
			environmentVfxHelper = VFXHelper.Rent();
			environmentVfxHelper.vfxPrefabReference = environmentVfxPrefab;
			environmentVfxHelper.followedTransform = base.vacuumOrigin;
			environmentVfxHelper.useFollowedTransformScale = false;
			environmentVfxHelper.enabled = true;
			loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound);
			if (NetworkServer.active)
			{
				killSearch = new SphereSearch();
			}
			jointBodyIndex = BodyCatalog.FindBodyIndex("VoidRaidCrabJointBody");
		}

		public override void OnExit()
		{
			killSphereVfxHelper = VFXHelper.Return(killSphereVfxHelper);
			environmentVfxHelper = VFXHelper.Return(environmentVfxHelper);
			losTracker.enabled = false;
			losTracker.Dispose();
			losTracker = null;
			LoopSoundManager.StopSoundLoopLocal(loopPtr);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float time = Mathf.Clamp01(base.fixedAge / base.duration);
			killRadius = killRadiusCurve.Evaluate(time);
			UpdateKillSphereVfx();
			UnityEngine.Vector3 position = base.vacuumOrigin.position;
			losTracker.origin = position;
			losTracker.Step();
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			float num = pullMagnitudeCurve.Evaluate(time);
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CharacterBody characterBody = readOnlyInstancesList[i];
				if ((object)characterBody == base.characterBody)
				{
					continue;
				}
				bool flag = losTracker.CheckBodyHasLos(characterBody);
				if (characterBody.hasEffectiveAuthority)
				{
					IDisplacementReceiver component = characterBody.GetComponent<IDisplacementReceiver>();
					if (component != null)
					{
						float num2 = (flag ? 1f : losObstructionFactor);
						component.AddDisplacement((position - characterBody.transform.position).normalized * (num * num2 * GetDeltaTime()));
					}
				}
			}
			if (!NetworkServer.active)
			{
				return;
			}
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			List<HealthComponent> list2 = CollectionPool<HealthComponent, List<HealthComponent>>.RentCollection();
			try
			{
				killSearch.radius = killRadius;
				killSearch.origin = position;
				killSearch.mask = LayerIndex.entityPrecise.mask;
				killSearch.RefreshCandidates();
				killSearch.OrderCandidatesByDistance();
				killSearch.FilterCandidatesByDistinctHurtBoxEntities();
				killSearch.GetHurtBoxes(list);
				for (int j = 0; j < list.Count; j++)
				{
					HurtBox hurtBox = list[j];
					if ((bool)hurtBox.healthComponent)
					{
						list2.Add(hurtBox.healthComponent);
					}
				}
				for (int k = 0; k < list2.Count; k++)
				{
					HealthComponent healthComponent = list2[k];
					if ((object)base.healthComponent != healthComponent && healthComponent.body.bodyIndex != jointBodyIndex)
					{
						healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath);
					}
				}
			}
			finally
			{
				list2 = CollectionPool<HealthComponent, List<HealthComponent>>.ReturnCollection(list2);
				list = CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
			}
		}

		private void UpdateKillSphereVfx()
		{
			if ((bool)killSphereVfxHelper.vfxInstanceTransform)
			{
				killSphereVfxHelper.vfxInstanceTransform.localScale = UnityEngine.Vector3.one * killRadius;
			}
		}

		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new VacuumWindDown());
		}
	}
	public class VacuumWindDown : BaseVacuumAttackState
	{
		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new VacuumExit());
		}
	}
	public class VacuumExit : BaseVacuumAttackState
	{
		[SerializeField]
		public SkillDef skillDefToReplaceAtStocksEmpty;

		[SerializeField]
		public SkillDef nextSkillDef;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)nextSkillDef)
			{
				GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty);
				if ((bool)genericSkill && genericSkill.stock == 0)
				{
					genericSkill.SetBaseSkill(nextSkillDef);
				}
			}
		}

		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextStateToMain();
		}
	}
	public class WaitForLegsAvailable : BaseState
	{
		public EntityState nextState;

		private CentralLegController centralLegController;

		public override void OnEnter()
		{
			base.OnEnter();
			centralLegController = GetComponent<CentralLegController>();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && !centralLegController.AreLegsBlockingBodyAnimation())
			{
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return nextState.GetMinimumInterruptPriority();
		}
	}
}
namespace EntityStates.VoidRaidCrab.Weapon
{
	public abstract class BaseFireMultiBeam : BaseMultiBeamState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public GameObject tracerEffectPrefab;

		[SerializeField]
		public GameObject explosionEffectPrefab;

		[SerializeField]
		public float blastDamageCoefficient;

		[SerializeField]
		public float blastForceMagnitude;

		[SerializeField]
		public float blastRadius;

		[SerializeField]
		public UnityEngine.Vector3 blastBonusForce;

		[SerializeField]
		public string enterSoundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, BaseMultiBeamState.muzzleName, transmit: false);
			}
			Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
			if (!base.isAuthority)
			{
				return;
			}
			CalcBeamPath(out var beamRay, out var beamEndPos);
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.inflictor = base.gameObject;
			blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
			blastAttack.baseDamage = damageStat * blastDamageCoefficient;
			blastAttack.baseForce = blastForceMagnitude;
			blastAttack.position = beamEndPos;
			blastAttack.radius = blastRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot;
			blastAttack.bonusForce = blastBonusForce;
			blastAttack.damageType = DamageType.Generic;
			blastAttack.Fire();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					int childIndex = component.FindChildIndex(BaseMultiBeamState.muzzleName);
					if ((bool)tracerEffectPrefab)
					{
						EffectData effectData = new EffectData
						{
							origin = beamEndPos,
							start = beamRay.origin,
							scale = blastRadius
						};
						effectData.SetChildLocatorTransformReference(base.gameObject, childIndex);
						EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
						EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true);
					}
				}
			}
			OnFireBeam(beamRay.origin, beamEndPos);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				EntityState nextState = InstantiateNextState();
				outer.SetNextState(nextState);
			}
		}

		protected abstract EntityState InstantiateNextState();

		protected virtual void OnFireBeam(UnityEngine.Vector3 beamStart, UnityEngine.Vector3 beamEnd)
		{
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public abstract class BaseGravityBumpState : BaseState
	{
		[SerializeField]
		public float maxDistance;

		protected UnityEngine.Vector3 airborneForce;

		protected UnityEngine.Vector3 groundedForce;

		protected bool isLeft;

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(isLeft);
			writer.Write(groundedForce);
			writer.Write(airborneForce);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			isLeft = reader.ReadBoolean();
			groundedForce = reader.ReadVector3();
			airborneForce = reader.ReadVector3();
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (nextState is BaseGravityBumpState baseGravityBumpState)
			{
				baseGravityBumpState.groundedForce = groundedForce;
				baseGravityBumpState.airborneForce = airborneForce;
				baseGravityBumpState.isLeft = isLeft;
			}
		}

		protected IEnumerable<HurtBox> GetTargets()
		{
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.viewer = base.characterBody;
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(base.characterBody.teamComponent.teamIndex);
			bullseyeSearch.minDistanceFilter = 0f;
			bullseyeSearch.maxDistanceFilter = maxDistance;
			bullseyeSearch.searchOrigin = base.inputBank.aimOrigin;
			bullseyeSearch.searchDirection = base.inputBank.aimDirection;
			bullseyeSearch.maxAngleFilter = 360f;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.filterByDistinctEntity = true;
			bullseyeSearch.RefreshCandidates();
			return bullseyeSearch.GetResults();
		}
	}
	public abstract class BaseMultiBeamState : BaseState
	{
		public static float beamMaxDistance = 1000f;

		public static string muzzleName;

		protected Transform muzzleTransform { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
		}

		protected void CalcBeamPath(out Ray beamRay, out UnityEngine.Vector3 beamEndPos)
		{
			Ray aimRay = GetAimRay();
			float num = float.PositiveInfinity;
			RaycastHit[] array = Physics.RaycastAll(aimRay, beamMaxDistance, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.Ignore);
			Transform root = GetModelTransform().root;
			for (int i = 0; i < array.Length; i++)
			{
				ref RaycastHit reference = ref array[i];
				float distance = reference.distance;
				if (distance < num && (object)reference.collider.transform.root != root)
				{
					num = distance;
				}
			}
			num = Mathf.Min(num, beamMaxDistance);
			beamEndPos = aimRay.GetPoint(num);
			UnityEngine.Vector3 position = muzzleTransform.position;
			beamRay = new Ray(position, beamEndPos - position);
		}
	}
	public class ChargeGravityBump : BaseGravityBumpState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public bool isSoundScaledByAttackSpeed;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public float horizontalAirborneForce;

		[SerializeField]
		public float verticalAirborneForce;

		[SerializeField]
		public float horizontalGroundedForce;

		[SerializeField]
		public float verticalGroundedForce;

		[SerializeField]
		public GameObject forceIndicatorPrefab;

		private float duration;

		private GameObject chargeEffectInstance;

		private Dictionary<CharacterMotor, Transform> characterMotorsToIndicatorTransforms;

		private UnityEngine.Quaternion airborneForceOrientation;

		private UnityEngine.Quaternion groundedForceOrientation;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				isLeft = UnityEngine.Random.value > 0.5f;
				CharacterDirection component = GetComponent<CharacterDirection>();
				if ((bool)component)
				{
					UnityEngine.Vector3 vector = UnityEngine.Vector3.Cross(component.forward, UnityEngine.Vector3.up);
					if (!isLeft)
					{
						vector *= -1f;
					}
					airborneForce = UnityEngine.Vector3.up * -1f * verticalAirborneForce + vector * horizontalAirborneForce;
					groundedForce = UnityEngine.Vector3.up * verticalGroundedForce + vector * horizontalGroundedForce;
				}
			}
			airborneForceOrientation = Util.QuaternionSafeLookRotation(airborneForce);
			groundedForceOrientation = Util.QuaternionSafeLookRotation(groundedForce);
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator && (bool)chargeEffectPrefab)
			{
				Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform;
				if ((bool)transform)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
					ScaleParticleSystemDuration component2 = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component2)
					{
						component2.newDuration = duration;
					}
				}
			}
			if (!string.IsNullOrEmpty(enterSoundString))
			{
				if (isSoundScaledByAttackSpeed)
				{
					Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
				}
				else
				{
					Util.PlaySound(enterSoundString, base.gameObject);
				}
			}
			characterMotorsToIndicatorTransforms = new Dictionary<CharacterMotor, Transform>();
			AssignIndicators();
		}

		public override void OnExit()
		{
			CleanUpIndicators();
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			foreach (KeyValuePair<CharacterMotor, Transform> characterMotorsToIndicatorTransform in characterMotorsToIndicatorTransforms)
			{
				if (characterMotorsToIndicatorTransform.Key.isGrounded)
				{
					characterMotorsToIndicatorTransform.Value.rotation = groundedForceOrientation;
				}
				else
				{
					characterMotorsToIndicatorTransform.Value.rotation = airborneForceOrientation;
				}
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new FireGravityBump());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		private void AssignIndicators()
		{
			foreach (HurtBox target in GetTargets())
			{
				GameObject gameObject = target.healthComponent.gameObject;
				if ((bool)gameObject)
				{
					CharacterMotor component = gameObject.GetComponent<CharacterMotor>();
					if ((bool)component && !characterMotorsToIndicatorTransforms.ContainsKey(component))
					{
						GameObject gameObject2 = UnityEngine.Object.Instantiate(forceIndicatorPrefab, gameObject.transform);
						characterMotorsToIndicatorTransforms.Add(component, gameObject2.transform);
					}
				}
			}
		}

		private void CleanUpIndicators()
		{
			foreach (KeyValuePair<CharacterMotor, Transform> characterMotorsToIndicatorTransform in characterMotorsToIndicatorTransforms)
			{
				Transform value = characterMotorsToIndicatorTransform.Value;
				if ((bool)value)
				{
					EntityState.Destroy(value.gameObject);
				}
			}
			characterMotorsToIndicatorTransforms.Clear();
		}
	}
	public class ChargeMissiles : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public bool isSoundScaledByAttackSpeed;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private float duration;

		private GameObject chargeEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator && (bool)chargeEffectPrefab)
			{
				Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform;
				if ((bool)transform)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
				}
			}
			if (!string.IsNullOrEmpty(enterSoundString))
			{
				if (isSoundScaledByAttackSpeed)
				{
					Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
				}
				else
				{
					Util.PlaySound(enterSoundString, base.gameObject);
				}
			}
		}

		public override void OnExit()
		{
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new FireMissiles());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ChargeMultiBeam : BaseMultiBeamState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public GameObject warningLaserVfxPrefab;

		[SerializeField]
		public new string muzzleName;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public bool isSoundScaledByAttackSpeed;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private float duration;

		private GameObject chargeEffectInstance;

		private GameObject warningLaserVfxInstance;

		private RayAttackIndicator warningLaserVfxInstanceRayAttackIndicator;

		private bool warningLaserEnabled
		{
			get
			{
				return warningLaserVfxInstance;
			}
			set
			{
				if (value == warningLaserEnabled)
				{
					return;
				}
				if (value)
				{
					if ((bool)warningLaserVfxPrefab)
					{
						warningLaserVfxInstance = UnityEngine.Object.Instantiate(warningLaserVfxPrefab);
						warningLaserVfxInstanceRayAttackIndicator = warningLaserVfxInstance.GetComponent<RayAttackIndicator>();
						UpdateWarningLaser();
					}
				}
				else
				{
					EntityState.Destroy(warningLaserVfxInstance);
					warningLaserVfxInstance = null;
					warningLaserVfxInstanceRayAttackIndicator = null;
				}
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator && (bool)chargeEffectPrefab)
			{
				Transform transform = modelChildLocator.FindChild(muzzleName) ?? base.characterBody.coreTransform;
				if ((bool)transform)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
					ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = duration;
					}
				}
			}
			if (!string.IsNullOrEmpty(enterSoundString))
			{
				if (isSoundScaledByAttackSpeed)
				{
					Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
				}
				else
				{
					Util.PlaySound(enterSoundString, base.gameObject);
				}
			}
			warningLaserEnabled = true;
		}

		public override void OnExit()
		{
			warningLaserEnabled = false;
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new FireMultiBeamSmall());
			}
		}

		public override void Update()
		{
			base.Update();
			UpdateWarningLaser();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		private void UpdateWarningLaser()
		{
			if ((bool)warningLaserVfxInstanceRayAttackIndicator)
			{
				warningLaserVfxInstanceRayAttackIndicator.attackRange = BaseMultiBeamState.beamMaxDistance;
				CalcBeamPath(out var beamRay, out var _);
				warningLaserVfxInstanceRayAttackIndicator.attackRay = beamRay;
			}
		}
	}
	public class FireGravityBump : BaseGravityBumpState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public bool disableAirControlUntilCollision;

		[SerializeField]
		public GameObject airborneEffectPrefab;

		[SerializeField]
		public GameObject groundedEffectPrefab;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public bool isSoundScaledByAttackSpeed;

		[SerializeField]
		public string leftAnimationLayerName;

		[SerializeField]
		public string leftAnimationStateName;

		[SerializeField]
		public string leftAnimationPlaybackRateParam;

		[SerializeField]
		public string rightAnimationLayerName;

		[SerializeField]
		public string rightAnimationStateName;

		[SerializeField]
		public string rightAnimationPlaybackRateParam;

		[SerializeField]
		public SkillDef skillDefToReplaceAtStocksEmpty;

		[SerializeField]
		public SkillDef nextSkillDef;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if ((bool)nextSkillDef)
			{
				GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty);
				if ((bool)genericSkill && genericSkill.stock == 0)
				{
					genericSkill.SetBaseSkill(nextSkillDef);
				}
			}
			if (isLeft)
			{
				PlayAnimation(leftAnimationLayerName, leftAnimationStateName, leftAnimationPlaybackRateParam, duration);
			}
			else
			{
				PlayAnimation(rightAnimationLayerName, rightAnimationStateName, rightAnimationPlaybackRateParam, duration);
			}
			if ((bool)muzzleFlashPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (!NetworkServer.active)
			{
				return;
			}
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.viewer = base.characterBody;
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(base.characterBody.teamComponent.teamIndex);
			bullseyeSearch.minDistanceFilter = 0f;
			bullseyeSearch.maxDistanceFilter = maxDistance;
			bullseyeSearch.searchOrigin = base.inputBank.aimOrigin;
			bullseyeSearch.searchDirection = base.inputBank.aimDirection;
			bullseyeSearch.maxAngleFilter = 360f;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.filterByDistinctEntity = true;
			bullseyeSearch.RefreshCandidates();
			foreach (HurtBox result in bullseyeSearch.GetResults())
			{
				GameObject gameObject = result.healthComponent.gameObject;
				if (!gameObject)
				{
					continue;
				}
				CharacterMotor component = gameObject.GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					EffectData effectData = new EffectData
					{
						origin = gameObject.transform.position
					};
					GameObject effectPrefab;
					if (component.isGrounded)
					{
						component.ApplyForce(groundedForce, alwaysApply: true, disableAirControlUntilCollision);
						effectPrefab = groundedEffectPrefab;
						effectData.rotation = Util.QuaternionSafeLookRotation(groundedForce);
					}
					else
					{
						component.ApplyForce(airborneForce, alwaysApply: true, disableAirControlUntilCollision);
						effectPrefab = airborneEffectPrefab;
						effectData.rotation = Util.QuaternionSafeLookRotation(airborneForce);
					}
					EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireMissiles : BaseState
	{
		[SerializeField]
		public float baseInitialDelay;

		[SerializeField]
		public float baseDelayBetweenWaves;

		[SerializeField]
		public float baseEndDelay;

		[SerializeField]
		public int numWaves;

		[SerializeField]
		public int numMissilesPerWave;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public float minSpreadDegrees;

		[SerializeField]
		public float rangeSpreadDegrees;

		[SerializeField]
		public string fireWaveSoundString;

		[SerializeField]
		public bool isSoundScaledByAttackSpeed;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public SkillDef skillDefToReplaceAtStocksEmpty;

		[SerializeField]
		public SkillDef nextSkillDef;

		private float delayBetweenWaves;

		private float duration;

		private int numWavesFired;

		private float timeUntilNextWave;

		private Transform muzzleTransform;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)nextSkillDef)
			{
				GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty);
				if ((bool)genericSkill && genericSkill.stock == 0)
				{
					genericSkill.SetBaseSkill(nextSkillDef);
				}
			}
			float num = baseInitialDelay + Mathf.Max(0f, baseDelayBetweenWaves * (float)(numWaves - 1)) + baseEndDelay;
			duration = num / attackSpeedStat;
			timeUntilNextWave = baseInitialDelay / attackSpeedStat;
			delayBetweenWaves = baseDelayBetweenWaves / attackSpeedStat;
			muzzleTransform = FindModelChild(muzzleName);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			timeUntilNextWave -= GetDeltaTime();
			while (timeUntilNextWave < 0f && numWavesFired < numWaves)
			{
				PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
				timeUntilNextWave += delayBetweenWaves;
				numWavesFired++;
				EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
				if (base.isAuthority)
				{
					UnityEngine.Quaternion quaternion = Util.QuaternionSafeLookRotation(GetAimRay().direction);
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.projectilePrefab = projectilePrefab;
					fireProjectileInfo.position = muzzleTransform.position;
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.damage = damageStat * damageCoefficient;
					fireProjectileInfo.force = force;
					FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
					for (int i = 0; i < numMissilesPerWave; i++)
					{
						fireProjectileInfo2.rotation = quaternion * GetRandomRollPitch();
						fireProjectileInfo2.crit = Util.CheckRoll(critStat, base.characterBody.master);
						ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
					}
				}
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		protected UnityEngine.Quaternion GetRandomRollPitch()
		{
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.forward);
			UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(minSpreadDegrees + UnityEngine.Random.Range(0f, rangeSpreadDegrees), UnityEngine.Vector3.left);
			return quaternion * quaternion2;
		}
	}
	public class FireMultiBeamFinale : BaseFireMultiBeam
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float projectileVerticalSpawnOffset;

		[SerializeField]
		public float projectileDamageCoefficient;

		[SerializeField]
		public SkillDef skillDefToReplaceAtStocksEmpty;

		[SerializeField]
		public SkillDef nextSkillDef;

		protected override void OnFireBeam(UnityEngine.Vector3 beamStart, UnityEngine.Vector3 beamEnd)
		{
			if ((bool)nextSkillDef)
			{
				GenericSkill genericSkill = base.skillLocator.FindSkillByDef(skillDefToReplaceAtStocksEmpty);
				if ((bool)genericSkill && genericSkill.stock == 0)
				{
					genericSkill.SetBaseSkill(nextSkillDef);
				}
			}
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.position = beamEnd + UnityEngine.Vector3.up * projectileVerticalSpawnOffset;
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.damage = damageStat * projectileDamageCoefficient;
			fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
			ProjectileManager.instance.FireProjectile(fireProjectileInfo);
		}

		protected override EntityState InstantiateNextState()
		{
			return EntityStateCatalog.InstantiateState(ref outer.mainStateType);
		}
	}
	public class FireMultiBeamSmall : BaseFireMultiBeam
	{
		[SerializeField]
		public int numFireBeforeFinale;

		private int fireIndex;

		protected override EntityState InstantiateNextState()
		{
			if (fireIndex < numFireBeforeFinale - 1)
			{
				return new FireMultiBeamSmall
				{
					fireIndex = fireIndex + 1
				};
			}
			return new FireMultiBeamFinale();
		}
	}
}
namespace EntityStates.VoidRaidCrab.Leg
{
	public class BaseLegState : EntityState
	{
		protected LegController legController { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			legController = legController ?? GetComponent<LegController>();
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (nextState is BaseLegState baseLegState)
			{
				baseLegState.legController = legController;
			}
		}
	}
	public class Idle : BaseLegState
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.legController.mainBodyHasEffectiveAuthority && !base.legController.DoesJointExist())
			{
				outer.SetNextState(new JointBroken());
			}
		}
	}
	public abstract class BaseStompState : BaseLegState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string animName;

		public static GameObject warningIndicatorPrefab;

		public GameObject target;

		protected float duration;

		private bool lifetimeExpiredAuthority;

		private RayAttackIndicator warningIndicatorInstance;

		protected virtual bool shouldUseWarningIndicator => false;

		protected virtual bool shouldUpdateLegStompTargetPosition => false;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			string stompPlaybackRateParam = base.legController.stompPlaybackRateParam;
			if (!string.IsNullOrEmpty(stompPlaybackRateParam))
			{
				EntityState.PlayAnimationOnAnimator(base.legController.animator, base.legController.primaryLayerName, animName, stompPlaybackRateParam, duration);
			}
			else
			{
				EntityState.PlayAnimationOnAnimator(base.legController.animator, base.legController.primaryLayerName, animName);
				int layerIndex = base.legController.animator.GetLayerIndex(base.legController.primaryLayerName);
				duration = base.legController.animator.GetCurrentAnimatorStateInfo(layerIndex).length;
			}
			SetWarningIndicatorActive(shouldUseWarningIndicator);
		}

		public override void OnExit()
		{
			SetWarningIndicatorActive(newWarningIndicatorActive: false);
			base.OnExit();
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (nextState is BaseStompState baseStompState)
			{
				baseStompState.warningIndicatorInstance = warningIndicatorInstance;
				warningIndicatorInstance = null;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.legController.mainBody.hasEffectiveAuthority && base.fixedAge >= duration && !lifetimeExpiredAuthority)
			{
				lifetimeExpiredAuthority = true;
				OnLifetimeExpiredAuthority();
			}
			if (shouldUpdateLegStompTargetPosition && (bool)target)
			{
				base.legController.SetStompTargetWorldPosition(target.transform.position);
			}
			UpdateWarningIndicatorInstance();
		}

		protected abstract void OnLifetimeExpiredAuthority();

		protected void SetWarningIndicatorActive(bool newWarningIndicatorActive)
		{
			if ((bool)warningIndicatorInstance == newWarningIndicatorActive)
			{
				return;
			}
			if (newWarningIndicatorActive)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(warningIndicatorPrefab);
				warningIndicatorInstance = gameObject.GetComponent<RayAttackIndicator>();
				UpdateWarningIndicatorInstance();
				return;
			}
			if ((bool)warningIndicatorInstance)
			{
				EntityState.Destroy(warningIndicatorInstance.gameObject);
			}
			warningIndicatorInstance = null;
		}

		private void UpdateWarningIndicatorInstance()
		{
			if ((bool)warningIndicatorInstance)
			{
				UnityEngine.Vector3 position = base.legController.toeTipTransform.position;
				UnityEngine.Vector3 vector = (base.legController.mainBody ? base.legController.mainBody.transform.position : position);
				warningIndicatorInstance.attackRay = new Ray(position, UnityEngine.Vector3.down);
				warningIndicatorInstance.attackRange = position.y - vector.y;
				warningIndicatorInstance.attackRadius = Stomp.blastRadius;
				warningIndicatorInstance.layerMask = LayerIndex.world.mask;
			}
		}
	}
	public class PreStompLegRaise : BaseStompState
	{
		protected override bool shouldUseWarningIndicator => true;

		protected override bool shouldUpdateLegStompTargetPosition => true;

		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new PreStompFollowTarget
			{
				target = target
			});
		}
	}
	public class PreStompFollowTarget : BaseStompState
	{
		protected override bool shouldUseWarningIndicator => true;

		protected override bool shouldUpdateLegStompTargetPosition => true;

		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new PreStompPauseBeforeStomp
			{
				target = target
			});
		}
	}
	public class PreStompPauseBeforeStomp : BaseStompState
	{
		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new Stomp
			{
				target = target
			});
		}
	}
	public class Stomp : BaseStompState
	{
		public static float blastDamageCoefficient;

		public static float blastRadius;

		public static float blastForce;

		public static GameObject blastEffectPrefab;

		private UnityEngine.Vector3? previousToePosition;

		private bool hasDoneBlast;

		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextState(new PostStompReturnToBase
			{
				target = target
			});
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!hasDoneBlast && (bool)base.legController.mainBody && base.legController.mainBody.hasEffectiveAuthority)
			{
				TryStompCollisionAuthority();
			}
		}

		private void TryStompCollisionAuthority()
		{
			UnityEngine.Vector3 currentToePosition = base.legController.toeTipTransform.position;
			TryAttack();
			previousToePosition = currentToePosition;
			void TryAttack()
			{
				if (previousToePosition.HasValue)
				{
					UnityEngine.Vector3 value = previousToePosition.Value;
					if (!((currentToePosition - value).sqrMagnitude < 0.0025000002f) && Physics.Linecast(previousToePosition.Value, currentToePosition, out var hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						DoBlastAuthority(hitInfo.point);
						base.legController.DoToeConcussionBlastAuthority(hitInfo.point, useEffect: false);
						hasDoneBlast = true;
					}
				}
			}
		}

		private void DoBlastAuthority(UnityEngine.Vector3 blastOrigin)
		{
			CharacterBody mainBody = base.legController.mainBody;
			EffectData effectData = new EffectData();
			effectData.origin = blastOrigin;
			effectData.scale = blastRadius;
			effectData.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.up);
			EffectManager.SpawnEffect(blastEffectPrefab, effectData, transmit: true);
			BlastAttack obj = new BlastAttack
			{
				attacker = mainBody.gameObject
			};
			obj.inflictor = obj.attacker;
			obj.baseDamage = blastDamageCoefficient * mainBody.damage;
			obj.baseForce = blastForce;
			obj.position = blastOrigin;
			obj.radius = blastRadius;
			obj.falloffModel = BlastAttack.FalloffModel.SweetSpot;
			obj.teamIndex = mainBody.teamComponent.teamIndex;
			obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
			obj.damageType = DamageType.Generic;
			obj.crit = mainBody.RollCrit();
			obj.damageColorIndex = DamageColorIndex.Default;
			obj.impactEffect = EffectIndex.Invalid;
			obj.losType = BlastAttack.LoSType.None;
			obj.procChainMask = default(ProcChainMask);
			obj.procCoefficient = 1f;
			obj.Fire();
		}

		private void DoStompAttackAuthority(UnityEngine.Vector3 hitPosition)
		{
			CharacterBody mainBody = base.legController.mainBody;
			if ((bool)mainBody)
			{
				UnityEngine.Vector3 position = base.legController.footTranform.position;
				UnityEngine.Vector3 position2 = base.legController.toeTipTransform.position;
				RaycastHit hitInfo;
				UnityEngine.Vector3 vector = (Physics.Linecast(position, position2, out hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore) ? hitInfo.point : position2);
				EffectData effectData = new EffectData();
				effectData.origin = vector;
				effectData.scale = blastRadius;
				effectData.rotation = UnityEngine.Quaternion.LookRotation(-hitInfo.normal);
				EffectManager.SpawnEffect(blastEffectPrefab, effectData, transmit: true);
				BlastAttack obj = new BlastAttack
				{
					attacker = mainBody.gameObject
				};
				obj.inflictor = obj.attacker;
				obj.baseDamage = blastDamageCoefficient * mainBody.damage;
				obj.baseForce = blastForce;
				obj.position = vector;
				obj.radius = blastRadius;
				obj.falloffModel = BlastAttack.FalloffModel.Linear;
				obj.teamIndex = mainBody.teamComponent.teamIndex;
				obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
				obj.damageType = DamageType.Generic;
				obj.crit = mainBody.RollCrit();
				obj.damageColorIndex = DamageColorIndex.Default;
				obj.impactEffect = EffectIndex.Invalid;
				obj.losType = BlastAttack.LoSType.None;
				obj.procChainMask = default(ProcChainMask);
				obj.procCoefficient = 1f;
				obj.Fire();
			}
		}
	}
	public class PostStompReturnToBase : BaseStompState
	{
		protected override void OnLifetimeExpiredAuthority()
		{
			outer.SetNextStateToMain();
		}
	}
	public class JointBroken : BaseLegState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			base.legController.shouldRetract = true;
		}

		public override void OnExit()
		{
			base.OnExit();
			base.legController.shouldRetract = false;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.legController.mainBodyHasEffectiveAuthority && base.legController.DoesJointExist())
			{
				outer.SetNextState(new Idle());
			}
		}
	}
	public class Retract : BaseLegState
	{
	}
	public class Retracted : BaseLegState
	{
	}
	public class Restore : BaseLegState
	{
	}
}
namespace EntityStates.VoidRaidCrab.Joint
{
	public class DeathState : GenericCharacterDeath
	{
		[SerializeField]
		public string joint1Name;

		[SerializeField]
		public string joint2Name;

		[SerializeField]
		public string joint3Name;

		[SerializeField]
		public GameObject joint1EffectPrefab;

		[SerializeField]
		public GameObject joint2EffectPrefab;

		[SerializeField]
		public GameObject joint3EffectPrefab;

		private CharacterModel characterModel;

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleMuzzleFlash(joint1EffectPrefab, base.gameObject, joint1Name, transmit: false);
			EffectManager.SimpleMuzzleFlash(joint2EffectPrefab, base.gameObject, joint2Name, transmit: false);
			EffectManager.SimpleMuzzleFlash(joint3EffectPrefab, base.gameObject, joint3Name, transmit: false);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				characterModel = modelTransform.GetComponent<CharacterModel>();
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
		}

		public override void OnExit()
		{
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			base.OnExit();
		}
	}
	public class PreDeathState : BaseState
	{
		[SerializeField]
		public float minDuration;

		[SerializeField]
		public string joint1Name;

		[SerializeField]
		public string joint2Name;

		[SerializeField]
		public string joint3Name;

		[SerializeField]
		public GameObject jointEffectPrefab;

		public bool canProceed;

		private List<GameObject> jointEffects = new List<GameObject>();

		public override void OnEnter()
		{
			base.OnEnter();
			canProceed = false;
			jointEffects.Clear();
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				SpawnJointEffect(joint1Name, modelChildLocator);
				SpawnJointEffect(joint2Name, modelChildLocator);
				SpawnJointEffect(joint3Name, modelChildLocator);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			foreach (GameObject jointEffect in jointEffects)
			{
				UnityEngine.Object.Destroy(jointEffect);
			}
			jointEffects.Clear();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > minDuration && canProceed)
			{
				outer.SetNextState(new DeathState());
			}
		}

		private void SpawnJointEffect(string jointName, ChildLocator childLocator)
		{
			Transform transform = childLocator.FindChild(jointName);
			if ((bool)transform)
			{
				GameObject item = UnityEngine.Object.Instantiate(jointEffectPrefab, transform);
				jointEffects.Add(item);
			}
		}
	}
}
namespace EntityStates.VoidMegaCrab
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathBombProjectile;

		public static float duration;

		public static string muzzleName;

		private Transform muzzleTransform;

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int DeathStateHash = Animator.StringToHash("Death");

		private static int DeathParamHash = Animator.StringToHash("Death.playbackRate");

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayCrossfade("Body", DeathStateHash, DeathParamHash, duration, 0.1f);
			PlayAnimation("Left Gun Override (Arm)", EmptyStateHash);
			PlayAnimation("Right Gun Override (Arm)", EmptyStateHash);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
			if ((bool)muzzleTransform && base.isAuthority)
			{
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = deathBombProjectile;
				fireProjectileInfo.position = muzzleTransform.position;
				fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up);
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat;
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				DestroyModel();
				if (NetworkServer.active)
				{
					DestroyBodyAsapServer();
				}
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class SpawnState : BaseState
	{
		[SerializeField]
		public float duration = 4f;

		[SerializeField]
		public string spawnSoundString;

		[SerializeField]
		public GameObject spawnEffectPrefab;

		[SerializeField]
		public string spawnMuzzleName;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnMuzzleName, transmit: false);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				modelTransform.GetComponent<PrintController>().enabled = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.VoidMegaCrab.Weapon
{
	public class FireCrabCannonBase : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public int projectileCount = 3;

		[SerializeField]
		public float spread;

		[SerializeField]
		public float bonusPitch;

		[SerializeField]
		public float totalYawSpread = 5f;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float baseFireDuration = 0.2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		[SerializeField]
		public string attackSound;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string animationLayerName = "Gesture, Additive";

		[SerializeField]
		public string animationStateName = "FireCrabCannon";

		[SerializeField]
		public string animationPlaybackRateParam = "FireCrabCannon.playbackRate";

		private float duration;

		private float fireDuration;

		private int projectilesFired;

		private Transform muzzleTransform;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			fireDuration = baseFireDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			muzzleTransform = FindModelChild(muzzleName);
			if (!muzzleTransform)
			{
				muzzleTransform = base.characterBody.aimOriginTransform;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount);
			if (projectilesFired <= num && projectilesFired < projectileCount)
			{
				FireProjectile();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireProjectile()
		{
			Util.PlaySound(attackSound, base.gameObject);
			base.characterBody.SetAimTimer(3f);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				int num = Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f);
				float bonusYaw = 0f;
				if (projectileCount > 1)
				{
					bonusYaw = (float)num / (float)(projectileCount - 1) * totalYawSpread;
				}
				UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, spread, 1f, 1f, bonusYaw, bonusPitch);
				UnityEngine.Vector3 position = muzzleTransform.position;
				ProjectileManager.instance.FireProjectile(projectilePrefab, position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
			projectilesFired++;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireCrabBlackCannon : FireCrabCannonBase
	{
	}
	public class FireCrabWhiteCannon : FireCrabCannonBase
	{
	}
	public abstract class ChargeCrabCannonBase : BaseState
	{
		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public string soundName;

		[SerializeField]
		public string chargeMuzzleName;

		[SerializeField]
		public string animationLayerName = "Gesture, Additive";

		[SerializeField]
		public string animationStateName = "FireCrabCannon";

		[SerializeField]
		public string animationStateNamePreCharged = "FireCrabCannon";

		[SerializeField]
		public string animationPlaybackRateParam = "FireCrabCannon.playbackRate";

		[SerializeField]
		public float animationCrossfadeDuration = 0.2f;

		private GameObject chargeInstance;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex(animationLayerName);
				if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("Empty"))
				{
					PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, animationCrossfadeDuration);
				}
				else
				{
					PlayCrossfade(animationLayerName, animationStateNamePreCharged, animationPlaybackRateParam, duration, animationCrossfadeDuration);
				}
			}
			Util.PlaySound(soundName, base.gameObject);
			Transform transform = FindModelChild(chargeMuzzleName);
			if ((bool)chargeEffectPrefab && (bool)transform)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeInstance.transform.parent = transform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
			base.characterBody.SetAimTimer(duration + 2f);
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(GetNextState());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		protected abstract FireCrabCannonBase GetNextState();
	}
	public class ChargeCrabBlackCannon : ChargeCrabCannonBase
	{
		protected override FireCrabCannonBase GetNextState()
		{
			return new FireCrabBlackCannon();
		}
	}
	public class ChargeCrabWhiteCannon : ChargeCrabCannonBase
	{
		protected override FireCrabCannonBase GetNextState()
		{
			return new FireCrabWhiteCannon();
		}
	}
}
namespace EntityStates.VoidMegaCrab.BackWeapon
{
	public class FireVoidMissiles : BaseSkillState
	{
		public static float baseDuration;

		public static string leftMuzzleString;

		public static string rightMuzzleString;

		public static GameObject muzzleEffectPrefab;

		public static GameObject projectilePrefab;

		public static int totalMissileWaveCount;

		public static float baseDurationBetweenMissiles;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string enterSoundString;

		public static string animationLayerName = "Gesture, Additive";

		public static string animationStateName = "FireCrabCannon";

		public static string animationPlaybackRateParam = "FireCrabCannon.playbackRate";

		private float duration;

		private float durationBetweenMissiles;

		private float missileTimer;

		private int missileWaveCount;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			durationBetweenMissiles = baseDurationBetweenMissiles / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		private void FireMissile()
		{
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, leftMuzzleString, transmit: false);
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, rightMuzzleString, transmit: false);
			}
			if (base.isAuthority)
			{
				Transform transform = FindModelChild(leftMuzzleString);
				Transform transform2 = FindModelChild(rightMuzzleString);
				Ray ray = GetAimRay();
				if (transform != null)
				{
					ray = new Ray(transform.position, transform.forward);
				}
				ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
				if (transform2 != null)
				{
					ray = new Ray(transform2.position, transform2.forward);
				}
				ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			missileTimer -= GetDeltaTime();
			if (missileWaveCount < totalMissileWaveCount && missileTimer <= 0f)
			{
				missileWaveCount++;
				missileTimer += durationBetweenMissiles;
				FireMissile();
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.VoidJailer
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathBombProjectile;

		public static float duration;

		public static string muzzleName;

		private Transform muzzleTransform;

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayCrossfade("Body", "Death", "Death.playbackRate", duration, 0.1f);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
			if ((bool)muzzleTransform && base.isAuthority)
			{
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = deathBombProjectile;
				fireProjectileInfo.position = muzzleTransform.position;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(base.characterDirection.forward, UnityEngine.Vector3.up);
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat;
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				DestroyModel();
				if (NetworkServer.active)
				{
					DestroyBodyAsapServer();
				}
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
		public static GameObject spawnFXPrefab;

		public static string spawnFXTransformName;

		public override void OnEnter()
		{
			base.OnEnter();
			PlaySpawnFX();
		}

		private void PlaySpawnFX()
		{
			if (spawnFXPrefab != null && !string.IsNullOrEmpty(spawnFXTransformName))
			{
				EffectManager.SimpleMuzzleFlash(spawnFXPrefab, base.gameObject, spawnFXTransformName, transmit: false);
			}
		}
	}
	public class Capture : BaseState
	{
		public static string animationLayerName;

		public static string animationStateName;

		public static string animationPlaybackRateName;

		public static GameObject chargeVfxPrefab;

		[SerializeField]
		public float duration;

		public static GameObject tetherPrefab;

		public static GameObject captureRangeEffect;

		public static float effectScaleCoefficient;

		public static float effectScaleAddition;

		public static string muzzleName;

		public static string tetherOriginName;

		public static float maxTetherDistance;

		public static float tetherReelSpeed;

		public static float damagePerSecond;

		public static float damageTickFrequency;

		public static BuffDef tetherDebuff;

		public static float innerRange;

		public static BuffDef innerRangeDebuff;

		public static float innerRangeDebuffDuration;

		public static GameObject innerRangeDebuffEffect;

		public static bool singleDurationReset;

		public static string captureLoopSoundString;

		private Transform muzzleTransform;

		private List<JailerTetherController> tetherControllers = new List<JailerTetherController>();

		private uint soundID;

		private bool initialized;

		private bool shouldModifyTetherDuration = true;

		private GameObject rangeEffect;

		private GameObject _chargeVfxInstance;

		public override void OnEnter()
		{
			muzzleTransform = FindModelChild(muzzleName);
			if (NetworkServer.active)
			{
				InitializeTethers();
			}
			if (NetworkServer.active && base.isAuthority && tetherControllers.Count == 0)
			{
				outer.SetNextState(new ExitCapture());
				return;
			}
			base.OnEnter();
			duration /= attackSpeedStat;
			FireTethers();
		}

		private void InitializeTethers()
		{
			UnityEngine.Vector3 position = muzzleTransform.position;
			float breakDistanceSqr = maxTetherDistance * maxTetherDistance;
			tetherControllers = new List<JailerTetherController>();
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = position;
			bullseyeSearch.maxDistanceFilter = maxTetherDistance;
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(base.teamComponent.teamIndex);
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.filterByLoS = true;
			bullseyeSearch.searchDirection = UnityEngine.Vector3.up;
			bullseyeSearch.RefreshCandidates();
			bullseyeSearch.FilterOutGameObject(base.gameObject);
			List<HurtBox> list = bullseyeSearch.GetResults().ToList();
			for (int i = 0; i < list.Count; i++)
			{
				GameObject gameObject = list[i].healthComponent.gameObject;
				if ((bool)gameObject && !TargetIsTethered(gameObject.GetComponent<CharacterBody>()))
				{
					GameObject obj = UnityEngine.Object.Instantiate(tetherPrefab, position, UnityEngine.Quaternion.identity, muzzleTransform);
					JailerTetherController component = obj.GetComponent<JailerTetherController>();
					component.NetworkownerRoot = base.gameObject;
					component.Networkorigin = muzzleTransform.gameObject;
					component.NetworktargetRoot = gameObject;
					component.breakDistanceSqr = breakDistanceSqr;
					component.damageCoefficientPerTick = damagePerSecond / damageTickFrequency;
					component.tickInterval = 1f / damageTickFrequency;
					component.tickTimer = (float)i * 0.1f;
					component.NetworkreelSpeed = tetherReelSpeed;
					component.SetTetheredBuff(tetherDebuff);
					tetherControllers.Add(component);
					NetworkServer.Spawn(obj);
				}
			}
			initialized = true;
		}

		private static bool TargetIsTethered(CharacterBody characterBody)
		{
			if (characterBody != null)
			{
				return characterBody.HasBuff(tetherDebuff);
			}
			return false;
		}

		private void FireTethers()
		{
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration);
			soundID = Util.PlayAttackSpeedSound(captureLoopSoundString, base.gameObject, attackSpeedStat);
			if (!muzzleTransform)
			{
				return;
			}
			if ((bool)captureRangeEffect)
			{
				rangeEffect = UnityEngine.Object.Instantiate(captureRangeEffect, base.characterBody.transform);
				rangeEffect.transform.localScale = effectScaleCoefficient * (maxTetherDistance + effectScaleAddition) * UnityEngine.Vector3.one;
				ScaleParticleSystemDuration component = rangeEffect.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
			if ((bool)chargeVfxPrefab)
			{
				_chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, muzzleTransform.position, muzzleTransform.rotation, muzzleTransform);
				ScaleParticleSystemDuration component2 = _chargeVfxInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component2)
				{
					component2.newDuration = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (initialized)
			{
				UpdateTethers(base.gameObject.transform.position);
				if (tetherControllers.Count == 0 || base.fixedAge >= duration)
				{
					outer.SetNextState(new ExitCapture());
				}
			}
		}

		private void UpdateTethers(UnityEngine.Vector3 origin)
		{
			for (int num = tetherControllers.Count - 1; num >= 0; num--)
			{
				JailerTetherController jailerTetherController = tetherControllers[num];
				if (!jailerTetherController)
				{
					tetherControllers.RemoveAt(num);
				}
				else
				{
					CharacterBody targetBody = jailerTetherController.GetTargetBody();
					if (!(targetBody == null) && !targetBody.HasBuff(innerRangeDebuff) && UnityEngine.Vector3.Distance(origin, targetBody.transform.position) < innerRange)
					{
						float num2 = duration - base.fixedAge;
						targetBody.AddTimedBuff(innerRangeDebuff, innerRangeDebuffDuration);
						if (shouldModifyTetherDuration)
						{
							duration = ((num2 > innerRangeDebuffDuration) ? innerRangeDebuffDuration : (innerRangeDebuffDuration + base.fixedAge));
							PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, innerRangeDebuffDuration);
							shouldModifyTetherDuration = !singleDurationReset;
							if ((bool)_chargeVfxInstance)
							{
								ScaleParticleSystemDuration component = _chargeVfxInstance.GetComponent<ScaleParticleSystemDuration>();
								if ((bool)component)
								{
									component.newDuration = duration;
								}
							}
						}
						jailerTetherController.NetworkreelSpeed = 0f;
					}
				}
			}
		}

		public override void OnExit()
		{
			DestroyTethers();
			if ((bool)rangeEffect)
			{
				EntityState.Destroy(rangeEffect);
			}
			if ((bool)_chargeVfxInstance)
			{
				EntityState.Destroy(_chargeVfxInstance);
			}
			AkSoundEngine.StopPlayingID(soundID);
			base.OnExit();
		}

		private void DestroyTethers()
		{
			if (tetherControllers == null)
			{
				return;
			}
			for (int num = tetherControllers.Count - 1; num >= 0; num--)
			{
				if ((bool)tetherControllers[num])
				{
					EntityState.Destroy(tetherControllers[num].gameObject);
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class CaptureFire : BaseState
	{
		public static string animationLayerName;

		public static string animationStateName;

		public static string animationPlaybackRateName;

		public static float duration;

		public static string enterSoundString;

		public static float exitCrossfadeDuration;

		public static string crossfadeStateName;

		public override void OnEnter()
		{
			base.OnEnter();
			duration /= attackSpeedStat;
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				Capture nextState = new Capture();
				outer.SetNextState(nextState);
			}
		}

		public override void OnExit()
		{
			PlayCrossfade(animationLayerName, crossfadeStateName, animationPlaybackRateName, exitCrossfadeDuration, exitCrossfadeDuration);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.VoidJailer.Weapon
{
	public class Capture2 : BaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateName;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public float pullFieldOfView;

		[SerializeField]
		public float pullMinDistance;

		[SerializeField]
		public float pullMaxDistance;

		[SerializeField]
		public AnimationCurve pullSuitabilityCurve;

		[SerializeField]
		public GameObject pullTracerPrefab;

		[SerializeField]
		public float pullLiftVelocity;

		[SerializeField]
		public BuffDef debuffDef;

		[SerializeField]
		public float debuffDuration;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public string muzzleString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			Ray aimRay = GetAimRay();
			if (!NetworkServer.active)
			{
				return;
			}
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.all;
			bullseyeSearch.maxAngleFilter = pullFieldOfView * 0.5f;
			bullseyeSearch.maxDistanceFilter = pullMaxDistance;
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.filterByLoS = true;
			bullseyeSearch.RefreshCandidates();
			bullseyeSearch.FilterOutGameObject(base.gameObject);
			HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
			GetTeam();
			if (!hurtBox)
			{
				return;
			}
			UnityEngine.Vector3 vector = hurtBox.transform.position - aimRay.origin;
			float magnitude = vector.magnitude;
			UnityEngine.Vector3 vector2 = vector / magnitude;
			float num = 1f;
			CharacterBody body = hurtBox.healthComponent.body;
			if ((bool)body.characterMotor)
			{
				num = body.characterMotor.mass;
			}
			else if ((bool)hurtBox.healthComponent.GetComponent<Rigidbody>())
			{
				num = base.rigidbody.mass;
			}
			if ((bool)debuffDef)
			{
				body.AddTimedBuff(debuffDef, debuffDuration);
			}
			float num2 = pullSuitabilityCurve.Evaluate(num);
			UnityEngine.Vector3 vector3 = vector2;
			float num3 = Trajectory.CalculateInitialYSpeedForHeight(Mathf.Abs(pullMinDistance - magnitude)) * Mathf.Sign(pullMinDistance - magnitude);
			vector3 *= num3;
			vector3.y = pullLiftVelocity;
			DamageInfo damageInfo = new DamageInfo
			{
				attacker = base.gameObject,
				damage = damageStat * damageCoefficient,
				position = hurtBox.transform.position,
				procCoefficient = procCoefficient
			};
			hurtBox.healthComponent.TakeDamageForce(vector3 * (num * num2), alwaysApply: true, disableAirControlUntilCollision: true);
			hurtBox.healthComponent.TakeDamage(damageInfo);
			GlobalEventManager.instance.OnHitEnemy(damageInfo, hurtBox.healthComponent.gameObject);
			if ((bool)pullTracerPrefab)
			{
				UnityEngine.Vector3 position = hurtBox.transform.position;
				UnityEngine.Vector3 start = base.characterBody.corePosition;
				Transform transform = FindModelChild(muzzleString);
				if ((bool)transform)
				{
					start = transform.position;
				}
				EffectData effectData = new EffectData
				{
					origin = position,
					start = start
				};
				EffectManager.SpawnEffect(pullTracerPrefab, effectData, transmit: true);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new ExitCapture());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ChargeCapture : BaseState
	{
		public static string animationLayerName;

		public static string animationStateName;

		public static string animationPlaybackRateName;

		public static float duration;

		public static string enterSoundString;

		public static GameObject chargeEffectPrefab;

		public static GameObject attackIndicatorPrefab;

		public static string muzzleString;

		private float _crossFadeDuration;

		private uint soundID;

		private GameObject attackIndicatorInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			duration /= attackSpeedStat;
			_crossFadeDuration = duration * 0.25f;
			PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateName, duration, _crossFadeDuration);
			soundID = Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
			if ((bool)chargeEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(chargeEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if ((bool)attackIndicatorPrefab)
			{
				Transform coreTransform = base.characterBody.coreTransform;
				if ((bool)coreTransform)
				{
					attackIndicatorInstance = UnityEngine.Object.Instantiate(attackIndicatorPrefab, coreTransform);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new Capture2());
			}
		}

		public override void Update()
		{
			if ((bool)attackIndicatorInstance)
			{
				attackIndicatorInstance.transform.forward = GetAimRay().direction;
			}
			base.Update();
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(soundID);
			if ((bool)attackIndicatorInstance)
			{
				EntityState.Destroy(attackIndicatorInstance);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ChargeFire : BaseState
	{
		public static string attackSoundEffect;

		public static string animationLayerName;

		public static string animationStateName;

		public static string animationPlaybackRateName;

		public static float baseDuration;

		public static GameObject chargeVfxPrefab;

		private float _totalDuration;

		private float _crossFadeDuration;

		private float _chargingDuration;

		private GameObject _chargeVfxInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			_totalDuration = baseDuration / attackSpeedStat;
			_crossFadeDuration = _totalDuration * 0.25f;
			_chargingDuration = _totalDuration - _crossFadeDuration;
			Transform modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackSoundEffect, base.gameObject, attackSpeedStat);
			if (modelTransform != null)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("ClawMuzzle");
					if ((bool)transform && (bool)chargeVfxPrefab)
					{
						_chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform.position, transform.rotation, transform);
						ScaleParticleSystemDuration component2 = _chargeVfxInstance.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = _totalDuration;
						}
					}
				}
			}
			PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateName, _chargingDuration, _crossFadeDuration);
			base.characterBody.SetAimTimer(_totalDuration + 3f);
		}

		public override void Update()
		{
			base.Update();
			if ((bool)_chargeVfxInstance)
			{
				Ray aimRay = GetAimRay();
				_chargeVfxInstance.transform.forward = aimRay.direction;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= _totalDuration && base.isAuthority)
			{
				Fire nextState = new Fire();
				outer.SetNextState(nextState);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)_chargeVfxInstance)
			{
				EntityState.Destroy(_chargeVfxInstance);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ExitCapture : BaseState
	{
		public static string animationLayerName;

		public static string animationStateName;

		public static string animationPlaybackRateName;

		public static float duration;

		public static string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			duration /= attackSpeedStat;
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class Fire : GenericProjectileBaseState
	{
		public static string animationLayerName;

		public static string animationStateName;

		public static string animationPlaybackRateName;

		public static int totalProjectileCount;

		public static float maxRandomDistance;

		public static float basePriorityReductionDuration;

		private float priorityReductionDuration;

		private Transform muzzleTransform;

		public override void OnEnter()
		{
			muzzleTransform = FindModelChild("ClawMuzzle");
			base.OnEnter();
			base.characterBody.SetAimTimer(duration + 3f);
			for (int i = 1; i < totalProjectileCount; i++)
			{
				FireProjectile();
			}
			priorityReductionDuration = basePriorityReductionDuration / attackSpeedStat;
		}

		protected override Ray ModifyProjectileAimRay(Ray aimRay)
		{
			aimRay.origin += UnityEngine.Random.insideUnitSphere * maxRandomDistance;
			return aimRay;
		}

		protected override void PlayAnimation(float duration)
		{
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge > priorityReductionDuration))
			{
				return InterruptPriority.PrioritySkill;
			}
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.VoidInfestor
{
	public class Death : GenericCharacterDeath
	{
		public static float deathDelay;

		public static GameObject deathEffectPrefab;

		private bool hasDied;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > deathDelay && NetworkServer.active && !hasDied)
			{
				hasDied = true;
				EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true);
				DestroyBodyAsapServer();
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class Infest : BaseState
	{
		public static GameObject enterEffectPrefab;

		public static GameObject successfulInfestEffectPrefab;

		public static GameObject infestVfxPrefab;

		public static string enterSoundString;

		public static float searchMaxDistance;

		public static float searchMaxAngle;

		public static float velocityInitialSpeed;

		public static float velocityTurnRate;

		public static float infestDamageCoefficient;

		private Transform targetTransform;

		private GameObject infestVfxInstance;

		private OverlapAttack attack;

		private List<HurtBox> victimsStruck = new List<HurtBox>();

		private static int InfestStateHash = Animator.StringToHash("Infest");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", InfestStateHash);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)enterEffectPrefab)
			{
				EffectManager.SimpleImpactEffect(enterEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false);
			}
			if ((bool)infestVfxPrefab)
			{
				infestVfxInstance = UnityEngine.Object.Instantiate(infestVfxPrefab, base.transform.position, UnityEngine.Quaternion.identity);
				infestVfxInstance.transform.parent = base.transform;
			}
			HitBoxGroup hitBoxGroup = null;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Infest");
			}
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = GetTeam();
			attack.damage = infestDamageCoefficient * damageStat;
			attack.hitEffectPrefab = null;
			attack.hitBoxGroup = hitBoxGroup;
			attack.isCrit = RollCrit();
			attack.damageType = DamageType.Stun1s;
			attack.damageColorIndex = DamageColorIndex.Void;
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.viewer = base.characterBody;
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			bullseyeSearch.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex);
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.minDistanceFilter = 0f;
			bullseyeSearch.maxDistanceFilter = searchMaxDistance;
			bullseyeSearch.searchOrigin = base.inputBank.aimOrigin;
			bullseyeSearch.searchDirection = base.inputBank.aimDirection;
			bullseyeSearch.maxAngleFilter = searchMaxAngle;
			bullseyeSearch.filterByLoS = true;
			bullseyeSearch.RefreshCandidates();
			HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
			if ((bool)hurtBox)
			{
				targetTransform = hurtBox.transform;
				if ((bool)base.characterMotor)
				{
					UnityEngine.Vector3 position = targetTransform.position;
					float num = velocityInitialSpeed;
					UnityEngine.Vector3 vector = position - base.transform.position;
					UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z);
					float magnitude = vector2.magnitude;
					float y = Trajectory.CalculateInitialYSpeed(magnitude / num, vector.y);
					UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude * num, y, vector2.y / magnitude * num);
					base.characterMotor.velocity = vector3;
					base.characterMotor.disableAirControlUntilCollision = true;
					base.characterMotor.Motor.ForceUnground();
					base.characterDirection.forward = vector3;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)targetTransform && (bool)base.characterMotor)
			{
				UnityEngine.Vector3 target = targetTransform.position - base.transform.position;
				UnityEngine.Vector3 velocity = base.characterMotor.velocity;
				velocity = UnityEngine.Vector3.RotateTowards(velocity, target, velocityTurnRate * GetDeltaTime() * (MathF.PI / 180f), 0f);
				base.characterMotor.velocity = velocity;
				if (NetworkServer.active && attack.Fire(victimsStruck))
				{
					for (int i = 0; i < victimsStruck.Count; i++)
					{
						HealthComponent obj = victimsStruck[i].healthComponent;
						CharacterBody body = obj.body;
						CharacterMaster master = body.master;
						if (obj.alive && master != null && !body.isPlayerControlled && !body.bodyFlags.HasFlag(CharacterBody.BodyFlags.Mechanical))
						{
							master.teamIndex = TeamIndex.Void;
							body.teamComponent.teamIndex = TeamIndex.Void;
							body.inventory.SetEquipmentIndex(DLC1Content.Elites.Void.eliteEquipmentDef.equipmentIndex);
							BaseAI component = master.GetComponent<BaseAI>();
							if ((bool)component)
							{
								component.enemyAttention = 0f;
								component.ForceAcquireNearestEnemyIfNoCurrentEnemy();
							}
							base.healthComponent.Suicide();
							if ((bool)successfulInfestEffectPrefab)
							{
								EffectManager.SimpleImpactEffect(successfulInfestEffectPrefab, base.transform.position, UnityEngine.Vector3.up, transmit: false);
							}
							break;
						}
					}
				}
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterMotor.velocity;
			}
			if (base.isAuthority && (bool)base.characterMotor && base.characterMotor.isGrounded && base.fixedAge > 0.1f)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)infestVfxInstance)
			{
				EntityState.Destroy(infestVfxInstance);
			}
			base.OnExit();
		}
	}
	public class Spawn : BaseState
	{
		public static GameObject spawnEffectPrefab;

		public static float velocityStrength;

		public static float spread;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleImpactEffect(spawnEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false);
			}
			if ((bool)base.characterMotor)
			{
				UnityEngine.Vector3 vector = (UnityEngine.Vector3.up + UnityEngine.Random.onUnitSphere * spread) * velocityStrength;
				base.characterMotor.ApplyForce(vector, alwaysApply: true, disableAirControlUntilCollision: true);
				base.characterDirection.forward = vector;
			}
			PlayAnimation("Base", SpawnStateHash);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (bool)base.characterMotor && base.characterMotor.isGrounded && base.fixedAge > 0.1f)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.VoidCamp
{
	public class Deactivate : EntityState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string onEnterSoundString;

		[SerializeField]
		public string baseAnimationLayerName;

		[SerializeField]
		public string baseAnimationStateName;

		[SerializeField]
		public string deactivateChildName;

		[SerializeField]
		public string additiveAnimationLayerName;

		[SerializeField]
		public string additiveAnimationStateName;

		[SerializeField]
		public string completeObjectiveChatMessageToken;

		[SerializeField]
		public PickupDropTable rewardDropTable;

		[SerializeField]
		public GameObject rewardPickupPrefab;

		[SerializeField]
		public bool dropItem;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(additiveAnimationLayerName, additiveAnimationStateName);
			FogDamageController componentInChildren = outer.GetComponentInChildren<FogDamageController>();
			if ((bool)componentInChildren)
			{
				componentInChildren.enabled = false;
			}
			Util.PlaySound(onEnterSoundString, base.gameObject);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				modelChildLocator.FindChild("ActiveFX").gameObject.SetActive(value: false);
				modelChildLocator.FindChild("RangeFX").GetComponent<AnimateShaderAlpha>().enabled = true;
			}
			Chat.SendBroadcastChat(new Chat.SimpleChatMessage
			{
				baseToken = completeObjectiveChatMessageToken
			});
			if (!NetworkServer.active || !dropItem)
			{
				return;
			}
			Transform transform = modelChildLocator.FindChild("RewardSpawnTarget");
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (participatingPlayerCount > 0 && (bool)transform && (bool)rewardDropTable)
			{
				int num = participatingPlayerCount;
				float angle = 360f / (float)num;
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				UnityEngine.Vector3 position = transform.transform.position;
				PickupPickerController.Option[] pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(3, rewardDropTable, Run.instance.treasureRng);
				int num2 = 0;
				while (num2 < num)
				{
					GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo);
					pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(ItemTier.VoidTier2);
					pickupInfo.pickerOptions = pickerOptions;
					pickupInfo.rotation = UnityEngine.Quaternion.identity;
					pickupInfo.prefabOverride = rewardPickupPrefab;
					pickupInfo.position = position;
					PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector);
					num2++;
					vector = quaternion * vector;
				}
			}
		}

		public override void OnExit()
		{
			PlayAnimation(baseAnimationLayerName, baseAnimationStateName);
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				modelChildLocator.FindChildGameObject(deactivateChildName).gameObject.SetActive(value: false);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new EntityStates.Idle());
			}
		}
	}
	public class Idle : EntityState
	{
		private class VoidCampObjectiveTracker : ObjectivePanelController.ObjectiveTracker
		{
			protected override string GenerateString()
			{
				int count = TeamComponent.GetTeamMembers(TeamIndex.Void).Count;
				return string.Format(Language.GetString("OBJECTIVE_VOIDCAMP"), count);
			}

			protected override bool IsDirty()
			{
				return true;
			}
		}

		[SerializeField]
		public string baseAnimationLayerName;

		[SerializeField]
		public string baseAnimationStateName;

		[SerializeField]
		public string additiveAnimationLayerName;

		[SerializeField]
		public string additiveAnimationStateName;

		[SerializeField]
		public float clearCheckRate;

		[SerializeField]
		public float initialClearCheckDelay;

		[SerializeField]
		public LoopSoundDef loopSoundDef;

		[SerializeField]
		public int indicatorMaxTeamCountThreshold;

		[SerializeField]
		public GameObject indicatorPrefab;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		private bool hasEnabledIndicators;

		private HashSet<NetworkInstanceId> indicatedNetIds;

		private float countdown;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(baseAnimationLayerName, baseAnimationStateName);
			PlayAnimation(additiveAnimationLayerName, additiveAnimationStateName);
			loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef);
			countdown = initialClearCheckDelay;
			indicatedNetIds = new HashSet<NetworkInstanceId>();
			GetComponent<OutsideInteractableLocker>().enabled = true;
			ObjectivePanelController.collectObjectiveSources += OnCollectObjectiveSources;
		}

		private void OnCollectObjectiveSources(CharacterMaster master, List<ObjectivePanelController.ObjectiveSourceDescriptor> objectiveSourcesList)
		{
			objectiveSourcesList.Add(new ObjectivePanelController.ObjectiveSourceDescriptor
			{
				master = master,
				objectiveType = typeof(VoidCampObjectiveTracker),
				source = base.gameObject
			});
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			countdown -= GetDeltaTime();
			if (!(countdown < 0f))
			{
				return;
			}
			countdown = clearCheckRate;
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Void);
			int count = teamMembers.Count;
			if (count <= 0)
			{
				outer.SetNextState(new Deactivate());
			}
			else
			{
				if (!hasEnabledIndicators && count > indicatorMaxTeamCountThreshold)
				{
					return;
				}
				hasEnabledIndicators = true;
				foreach (TeamComponent item in teamMembers)
				{
					if ((bool)item && (bool)item.body && (bool)item.body.master)
					{
						RequestIndicatorForMaster(item.body.master);
					}
				}
			}
		}

		public override void OnExit()
		{
			LoopSoundManager.StopSoundLoopLocal(loopPtr);
			GetComponent<OutsideInteractableLocker>().enabled = false;
			ObjectivePanelController.collectObjectiveSources -= OnCollectObjectiveSources;
			base.OnExit();
		}

		protected void RequestIndicatorForMaster(CharacterMaster master)
		{
			if (indicatedNetIds.Contains(master.netId))
			{
				return;
			}
			GameObject bodyObject = master.GetBodyObject();
			if ((bool)bodyObject)
			{
				TeamComponent component = bodyObject.GetComponent<TeamComponent>();
				if ((bool)component)
				{
					indicatedNetIds.Add(master.netId);
					component.RequestDefaultIndicator(indicatorPrefab);
				}
			}
		}
	}
}
namespace EntityStates.VoidBarnacle
{
	public class DeathState : GenericCharacterDeath
	{
		public static string animationLayerName;

		public static string animationStateName;

		public static string animationPlaybackRateName;

		public static float duration;

		public static GameObject deathFXPrefab;

		public override void OnEnter()
		{
			base.OnEnter();
			if (deathFXPrefab != null)
			{
				EffectManager.SimpleEffect(deathFXPrefab, base.transform.position, base.transform.rotation, transmit: true);
			}
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class FindSurface : NoCastSpawn
	{
		public static int raycastCount;

		public static float maxRaycastLength;

		public static float raycastSphereYOffset;

		public static float raycastMinimumAngle;

		public static float raycastMaximumAngle;

		private const float _cRadianConversionCoeficcient = MathF.PI / 180f;

		public override void OnEnter()
		{
			base.OnEnter();
			RaycastHit hitInfo = default(RaycastHit);
			UnityEngine.Vector3 origin = new UnityEngine.Vector3(base.characterBody.corePosition.x, base.characterBody.corePosition.y + raycastSphereYOffset, base.characterBody.corePosition.z);
			if (!base.isAuthority)
			{
				return;
			}
			raycastMinimumAngle = Mathf.Clamp(raycastMinimumAngle, 0f, raycastMaximumAngle);
			raycastMaximumAngle = Mathf.Clamp(raycastMaximumAngle, raycastMinimumAngle, 90f);
			raycastCount = Mathf.Abs(raycastCount);
			float num = 360f / (float)raycastCount;
			for (int i = 0; i < raycastCount; i++)
			{
				float minInclusive = num * (float)i;
				float maxInclusive = num * (float)(i + 1) - 1f;
				float f = UnityEngine.Random.Range(minInclusive, maxInclusive) * (MathF.PI / 180f);
				float f2 = UnityEngine.Random.Range(raycastMinimumAngle, raycastMaximumAngle) * (MathF.PI / 180f);
				float x = Mathf.Cos(f);
				float y = Mathf.Sin(f2);
				float z = Mathf.Sin(f);
				UnityEngine.Vector3 direction = new UnityEngine.Vector3(x, y, z);
				if (Physics.Raycast(origin, direction, out hitInfo, maxRaycastLength, LayerIndex.world.mask))
				{
					base.transform.position = hitInfo.point;
					base.transform.up = hitInfo.normal;
					break;
				}
			}
		}
	}
	public class NoCastSpawn : BaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateName;

		[SerializeField]
		public float duration;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public GameObject spawnFXPrefab;

		[SerializeField]
		public string spawnFXTransformName;

		public override void OnEnter()
		{
			base.OnEnter();
			if (spawnFXPrefab != null)
			{
				EffectManager.SimpleMuzzleFlash(spawnFXPrefab, base.gameObject, spawnFXTransformName, transmit: false);
			}
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.VoidBarnacle.Weapon
{
	public class ChargeFire : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject chargeVfxPrefab;

		[SerializeField]
		public string attackSoundEffect;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateName;

		private float _chargingDuration;

		private float _totalDuration;

		private float _crossFadeDuration;

		private GameObject _chargeVfxInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			_totalDuration = baseDuration / attackSpeedStat;
			_crossFadeDuration = _totalDuration * 0.25f;
			_chargingDuration = _totalDuration - _crossFadeDuration;
			Transform modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackSoundEffect, base.gameObject, attackSpeedStat);
			if (modelTransform != null)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleMouth");
					if ((bool)transform && (bool)chargeVfxPrefab)
					{
						_chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform.position, transform.rotation, transform);
						ScaleParticleSystemDuration component2 = _chargeVfxInstance.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = _totalDuration;
						}
					}
				}
			}
			PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateName, _chargingDuration, _crossFadeDuration);
		}

		public override void Update()
		{
			base.Update();
			if ((bool)_chargeVfxInstance)
			{
				Ray aimRay = GetAimRay();
				_chargeVfxInstance.transform.forward = aimRay.direction;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= _totalDuration && base.isAuthority)
			{
				Fire nextState = new Fire();
				outer.SetNextState(nextState);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)_chargeVfxInstance)
			{
				EntityState.Destroy(_chargeVfxInstance);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Fire : GenericProjectileBaseState
	{
		[SerializeField]
		public int numberOfFireballs;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateName;

		private float _interFireballDuration;

		private float _animationDuration;

		private Transform muzzleTransform;

		public override void OnEnter()
		{
			duration = baseDuration / attackSpeedStat;
			_interFireballDuration = duration / (float)numberOfFireballs;
			_animationDuration = _interFireballDuration;
			muzzleTransform = FindModelChild(targetMuzzle);
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (stopwatch >= _animationDuration && numberOfFireballs > 0)
			{
				_animationDuration += _animationDuration;
				PlayAnimation(_animationDuration);
			}
		}

		protected override void PlayAnimation(float duration)
		{
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateName, _interFireballDuration);
		}

		protected override void FireProjectile()
		{
			base.FireProjectile();
			if (numberOfFireballs > 1)
			{
				firedProjectile = false;
				delayBeforeFiringProjectile += _interFireballDuration;
			}
			numberOfFireballs--;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Vermin
{
	public class SpawnState : GenericCharacterSpawnState
	{
	}
}
namespace EntityStates.Vermin.Weapon
{
	public class TongueLash : BasicMeleeAttack
	{
		protected override void PlayAnimation()
		{
			PlayCrossfade("Gesture, Additive", "TongueLash", "TongueLash.playbackRate", duration, 0.1f);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
		}
	}
}
namespace EntityStates.VagrantNovaItem
{
	public class BaseVagrantNovaItemState : BaseBodyAttachmentState
	{
		protected ParticleSystem chargeSparks;

		protected int GetItemStack()
		{
			if (!base.attachedBody || !base.attachedBody.inventory)
			{
				return 1;
			}
			return base.attachedBody.inventory.GetItemCount(RoR2Content.Items.NovaOnLowHealth);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			ChildLocator component = GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			chargeSparks = component.FindChild("ChargeSparks")?.GetComponent<ParticleSystem>();
			if ((bool)chargeSparks)
			{
				ParticleSystem.ShapeModule shape = chargeSparks.shape;
				SkinnedMeshRenderer skinnedMeshRenderer = FindAttachedBodyMainRenderer();
				if ((bool)skinnedMeshRenderer)
				{
					shape.skinnedMeshRenderer = FindAttachedBodyMainRenderer();
					ParticleSystem.MainModule main = chargeSparks.main;
					float x = skinnedMeshRenderer.transform.lossyScale.x;
					main.startSize = 0.5f / x;
				}
			}
		}

		protected void SetChargeSparkEmissionRateMultiplier(float multiplier)
		{
			if ((bool)chargeSparks)
			{
				ParticleSystem.EmissionModule emission = chargeSparks.emission;
				emission.rateOverTimeMultiplier = multiplier * 20f;
			}
		}

		private SkinnedMeshRenderer FindAttachedBodyMainRenderer()
		{
			if (!base.attachedBody)
			{
				return null;
			}
			CharacterModel.RendererInfo[] array = base.attachedBody.modelLocator?.modelTransform.GetComponent<CharacterModel>()?.baseRendererInfos;
			if (array == null)
			{
				return null;
			}
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].renderer is SkinnedMeshRenderer result)
				{
					return result;
				}
			}
			return null;
		}
	}
	public class RechargeState : BaseVagrantNovaItemState
	{
		public static float baseDuration = 30f;

		public static AnimationCurve particleEmissionCurve;

		private float rechargeDuration;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				int itemStack = GetItemStack();
				float num = baseDuration / (float)(itemStack + 1);
				float num2 = base.fixedAge / num;
				if (num2 >= 1f)
				{
					num2 = 1f;
					outer.SetNextState(new ReadyState());
				}
				SetChargeSparkEmissionRateMultiplier(particleEmissionCurve.Evaluate(num2));
			}
		}
	}
	public class ReadyState : BaseVagrantNovaItemState
	{
		private HealthComponent attachedHealthComponent;

		public override void OnEnter()
		{
			base.OnEnter();
			attachedHealthComponent = base.attachedBody?.healthComponent;
			SetChargeSparkEmissionRateMultiplier(1f);
			GlobalEventManager.onServerDamageDealt += OnDamaged;
		}

		public override void OnExit()
		{
			base.OnExit();
			GlobalEventManager.onServerDamageDealt -= OnDamaged;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && attachedHealthComponent.isHealthLow)
			{
				outer.SetNextState(new ChargeState());
			}
		}

		private void OnDamaged(DamageReport report)
		{
			if (report.hitLowHealth && (object)report?.victim?.body == base.attachedBody)
			{
				outer.SetNextState(new ChargeState());
			}
		}
	}
	public class ChargeState : BaseVagrantNovaItemState
	{
		public static float baseDuration = 3f;

		public static string chargeSound;

		private float duration;

		private GameObject chargeVfxInstance;

		private GameObject areaIndicatorVfxInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / (base.attachedBody ? base.attachedBody.attackSpeed : 1f);
			SetChargeSparkEmissionRateMultiplier(1f);
			if ((bool)base.attachedBody)
			{
				UnityEngine.Vector3 position = base.transform.position;
				UnityEngine.Quaternion rotation = base.transform.rotation;
				chargeVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.chargingEffectPrefab, position, rotation);
				chargeVfxInstance.transform.localScale = UnityEngine.Vector3.one * 0.25f;
				Util.PlaySound(chargeSound, base.gameObject);
				areaIndicatorVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.areaIndicatorPrefab, position, rotation);
				ObjectScaleCurve component = areaIndicatorVfxInstance.GetComponent<ObjectScaleCurve>();
				component.timeMax = duration;
				component.baseScale = UnityEngine.Vector3.one * DetonateState.blastRadius * 2f;
				areaIndicatorVfxInstance.GetComponent<AnimateShaderAlpha>().timeMax = duration;
			}
			RoR2Application.onLateUpdate += OnLateUpdate;
		}

		public override void OnExit()
		{
			RoR2Application.onLateUpdate -= OnLateUpdate;
			if ((object)chargeVfxInstance != null)
			{
				EntityState.Destroy(chargeVfxInstance);
				chargeVfxInstance = null;
			}
			if ((object)areaIndicatorVfxInstance != null)
			{
				EntityState.Destroy(areaIndicatorVfxInstance);
				areaIndicatorVfxInstance = null;
			}
			base.OnExit();
		}

		private void OnLateUpdate()
		{
			if ((bool)chargeVfxInstance)
			{
				chargeVfxInstance.transform.position = base.transform.position;
			}
			if ((bool)areaIndicatorVfxInstance)
			{
				areaIndicatorVfxInstance.transform.position = base.transform.position;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new DetonateState());
			}
		}
	}
	public class DetonateState : BaseVagrantNovaItemState
	{
		public static float blastRadius;

		public static float blastDamageCoefficient;

		public static float blastProcCoefficient;

		public static float blastForce;

		public static float baseDuration;

		public static string explosionSound;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			if (NetworkServer.active && (bool)base.attachedBody)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.attachedBody.gameObject;
				blastAttack.baseDamage = base.attachedBody.damage * blastDamageCoefficient;
				blastAttack.baseForce = blastForce;
				blastAttack.bonusForce = UnityEngine.Vector3.zero;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.crit = base.attachedBody.RollCrit();
				blastAttack.damageColorIndex = DamageColorIndex.Item;
				blastAttack.damageType = DamageType.Generic;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.inflictor = base.gameObject;
				blastAttack.position = base.attachedBody.corePosition;
				blastAttack.procChainMask = default(ProcChainMask);
				blastAttack.procCoefficient = blastProcCoefficient;
				blastAttack.radius = blastRadius;
				blastAttack.losType = BlastAttack.LoSType.NearestHit;
				blastAttack.teamIndex = base.attachedBody.teamComponent.teamIndex;
				blastAttack.Fire();
				EffectData effectData = new EffectData();
				effectData.origin = base.attachedBody.corePosition;
				effectData.SetHurtBoxReference(base.attachedBody.mainHurtBox);
				EffectManager.SpawnEffect(FireMegaNova.novaEffectPrefab, effectData, transmit: true);
			}
			SetChargeSparkEmissionRateMultiplier(0f);
			Util.PlaySound(explosionSound, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new RechargeState());
			}
		}
	}
}
namespace EntityStates.UrchinTurret
{
	public class DeathState : BaseState
	{
		public static GameObject initialExplosion;

		public static float effectScale;

		public static string deathString;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(deathString, base.gameObject);
			Transform transform = FindModelChild("Muzzle");
			if (base.isAuthority)
			{
				if ((bool)initialExplosion)
				{
					EffectManager.SpawnEffect(initialExplosion, new EffectData
					{
						origin = transform.position,
						scale = effectScale
					}, transmit: true);
				}
				EntityState.Destroy(base.gameObject);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
	}
}
namespace EntityStates.UrchinTurret.Weapon
{
	public class MinigunState : BaseState
	{
		public static string muzzleName;

		protected Transform muzzleTransform;

		protected ref InputBankTest.ButtonState skillButtonState => ref base.inputBank.skill1;

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			StartAimMode();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class MinigunSpinUp : MinigunState
	{
		public static float baseDuration;

		public static string sound;

		public static GameObject chargeEffectPrefab;

		private GameObject chargeInstance;

		private float duration;

		private EffectManagerHelper _emh_chargeInstance;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeInstance = null;
			_emh_chargeInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(sound, base.gameObject);
			PlayCrossfade("Gesture, Additive", "EnterShootLoop", 0.2f);
			if ((bool)muzzleTransform && (bool)chargeEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
				{
					chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
				}
				else
				{
					_emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
					chargeInstance = _emh_chargeInstance.gameObject;
				}
				chargeInstance.transform.parent = muzzleTransform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new MinigunFire());
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeInstance)
			{
				if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null)
				{
					_emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance);
				}
				else
				{
					EntityState.Destroy(chargeInstance);
				}
				_emh_chargeInstance = null;
				chargeInstance = null;
			}
		}
	}
	public class MinigunSpinDown : MinigunState
	{
		public static float baseDuration;

		public static string sound;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class MinigunFire : MinigunState
	{
		public static GameObject muzzleVfxPrefab;

		public static GameObject projectilePrefab;

		public static float baseFireInterval;

		public static float baseDamagePerSecondCoefficient;

		public static float bulletMinSpread;

		public static float bulletMaxSpread;

		public static string fireSound;

		public static string startSound;

		public static string endSound;

		private float fireTimer;

		private Transform muzzleVfxTransform;

		private float baseFireRate;

		private float baseBulletsPerSecond;

		private Run.FixedTimeStamp critEndTime;

		private Run.FixedTimeStamp lastCritCheck;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)muzzleTransform && (bool)muzzleVfxPrefab)
			{
				muzzleVfxTransform = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransform).transform;
			}
			baseFireRate = 1f / baseFireInterval;
			baseBulletsPerSecond = baseFireRate;
			critEndTime = Run.FixedTimeStamp.negativeInfinity;
			lastCritCheck = Run.FixedTimeStamp.negativeInfinity;
			Util.PlaySound(startSound, base.gameObject);
			PlayCrossfade("Gesture, Additive", "ShootLoop", 0.2f);
		}

		private void UpdateCrits()
		{
			if (lastCritCheck.timeSince >= 1f)
			{
				lastCritCheck = Run.FixedTimeStamp.now;
				if (RollCrit())
				{
					critEndTime = Run.FixedTimeStamp.now + 2f;
				}
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(endSound, base.gameObject);
			if ((bool)muzzleVfxTransform)
			{
				EntityState.Destroy(muzzleVfxTransform.gameObject);
				muzzleVfxTransform = null;
			}
			PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f);
			base.OnExit();
		}

		private void OnFireShared()
		{
			Util.PlaySound(fireSound, base.gameObject);
			if (base.isAuthority)
			{
				OnFireAuthority();
			}
		}

		private void OnFireAuthority()
		{
			UpdateCrits();
			bool crit = !critEndTime.hasPassed;
			float damage = baseDamagePerSecondCoefficient / baseBulletsPerSecond * damageStat;
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, bulletMinSpread, bulletMaxSpread, 1f, 1f);
			ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damage, 0f, crit);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			if (fireTimer <= 0f)
			{
				float num = baseFireInterval / attackSpeedStat;
				fireTimer += num;
				OnFireShared();
			}
			if (base.isAuthority && !base.skillButtonState.down)
			{
				outer.SetNextState(new MinigunSpinDown());
			}
		}
	}
}
namespace EntityStates.Pounder
{
	public class Spawn : BaseState
	{
		public static GameObject spawnPrefab;

		public static float baseDuration;

		public static string spawnSoundString;

		private float duration;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(spawnSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(spawnPrefab, base.gameObject, "Feet", transmit: false);
			PlayAnimation("Base", SpawnStateHash, SpawnParamHash, duration);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Pound : BaseState
	{
		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastForce;

		public static float blastFrequency;

		public static float duration;

		public static GameObject blastEffectPrefab;

		private ProjectileDamage projectileDamage;

		private float poundTimer;

		private static int PoundStateHash = Animator.StringToHash("Pound");

		public override void OnEnter()
		{
			base.OnEnter();
			projectileDamage = GetComponent<ProjectileDamage>();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			poundTimer -= GetDeltaTime();
			if (poundTimer <= 0f && (bool)base.projectileController.owner)
			{
				poundTimer += 1f / blastFrequency;
				if (NetworkServer.active)
				{
					BlastAttack blastAttack = new BlastAttack();
					blastAttack.attacker = base.projectileController.owner;
					blastAttack.baseDamage = projectileDamage.damage;
					blastAttack.baseForce = blastForce;
					blastAttack.crit = projectileDamage.crit;
					blastAttack.damageType = projectileDamage.damageType;
					blastAttack.falloffModel = BlastAttack.FalloffModel.None;
					blastAttack.position = base.transform.position;
					blastAttack.radius = blastRadius;
					blastAttack.teamIndex = base.projectileController.teamFilter.teamIndex;
					blastAttack.Fire();
					EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
					{
						origin = base.transform.position,
						scale = blastRadius
					}, transmit: true);
				}
				PlayAnimation("Base", PoundStateHash);
			}
			if (NetworkServer.active && base.fixedAge > duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
}
namespace EntityStates.Treebot
{
	public class BurrowDash : BaseCharacterMain
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public static AnimationCurve speedMultiplier;

		public static float chargeDamageCoefficient;

		public static GameObject impactEffectPrefab;

		public static GameObject burrowLoopEffectPrefab;

		public static float hitPauseDuration;

		public static float timeBeforeExitToPlayExitAnimation;

		public static string impactSoundString;

		public static string startSoundString;

		public static string endSoundString;

		public static float healPercent;

		public static bool resetDurationOnImpact;

		[SerializeField]
		public GameObject startEffectPrefab;

		[SerializeField]
		public GameObject endEffectPrefab;

		private float duration;

		private float hitPauseTimer;

		private UnityEngine.Vector3 idealDirection;

		private OverlapAttack attack;

		private ChildLocator childLocator;

		private bool inHitPause;

		private bool beginPlayingExitAnimation;

		private Transform modelTransform;

		private GameObject burrowLoopEffectInstance;

		private int originalLayer;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			if (base.isAuthority)
			{
				if ((bool)base.inputBank)
				{
					idealDirection = base.inputBank.aimDirection;
					idealDirection.y = 0f;
				}
				UpdateDirection();
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.normalizeToFloor = true;
			}
			if ((bool)startEffectPrefab && (bool)base.characterBody)
			{
				EffectManager.SpawnEffect(startEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition
				}, transmit: false);
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.forward = idealDirection;
			}
			Util.PlaySound(startSoundString, base.gameObject);
			PlayCrossfade("Body", "BurrowEnter", 0.1f);
			HitBoxGroup hitBoxGroup = null;
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "BurrowCharge");
				childLocator = modelTransform.GetComponent<ChildLocator>();
			}
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = chargeDamageCoefficient * damageStat;
			attack.hitEffectPrefab = impactEffectPrefab;
			attack.hitBoxGroup = hitBoxGroup;
			attack.damage = damageStat * chargeDamageCoefficient;
			attack.damageType = DamageType.Freeze2s;
			attack.procCoefficient = 1f;
			originalLayer = base.gameObject.layer;
			base.gameObject.layer = LayerIndex.debris.intVal;
			base.characterMotor.Motor.RebuildCollidableLayers();
			modelTransform.GetComponent<HurtBoxGroup>().hurtBoxesDeactivatorCounter++;
			base.characterBody.hideCrosshair = true;
			base.characterBody.isSprinting = true;
			if ((bool)childLocator)
			{
				Transform transform = childLocator.FindChild("BurrowCenter");
				if ((bool)transform && (bool)burrowLoopEffectPrefab)
				{
					burrowLoopEffectInstance = UnityEngine.Object.Instantiate(burrowLoopEffectPrefab, transform.position, transform.rotation);
					burrowLoopEffectInstance.transform.parent = transform;
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterBody && !outer.destroying && (bool)endEffectPrefab)
			{
				EffectManager.SpawnEffect(endEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition
				}, transmit: false);
			}
			Util.PlaySound(endSoundString, base.gameObject);
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			modelTransform.GetComponent<HurtBoxGroup>().hurtBoxesDeactivatorCounter--;
			base.characterBody.hideCrosshair = false;
			if ((bool)burrowLoopEffectInstance)
			{
				EntityState.Destroy(burrowLoopEffectInstance);
			}
			Animator animator = GetModelAnimator();
			int layerIndex = animator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, 2f);
				animator.PlayInFixedTime("LightImpact", layerIndex, 0f);
			}
			base.OnExit();
		}

		private void UpdateDirection()
		{
			if ((bool)base.inputBank)
			{
				UnityEngine.Vector2 vector = Util.Vector3XZToVector2XY(base.inputBank.moveVector);
				if (vector != UnityEngine.Vector2.zero)
				{
					vector.Normalize();
					idealDirection = new UnityEngine.Vector3(vector.x, 0f, vector.y).normalized;
				}
			}
		}

		protected override void UpdateAnimationParameters()
		{
		}

		private UnityEngine.Vector3 GetIdealVelocity()
		{
			return base.characterDirection.forward * base.characterBody.moveSpeed * speedMultiplier.Evaluate(base.fixedAge / duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
				return;
			}
			if (base.fixedAge >= duration - timeBeforeExitToPlayExitAnimation && !beginPlayingExitAnimation)
			{
				beginPlayingExitAnimation = true;
				PlayCrossfade("Body", "BurrowExit", 0.1f);
			}
			if (!base.isAuthority)
			{
				return;
			}
			UpdateDirection();
			if (!inHitPause)
			{
				if ((bool)base.characterDirection)
				{
					base.characterDirection.moveVector = idealDirection;
					if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision)
					{
						base.characterMotor.rootMotion += GetIdealVelocity() * GetDeltaTime();
					}
				}
				if (attack.Fire())
				{
					Util.PlaySound(impactSoundString, base.gameObject);
					inHitPause = true;
					hitPauseTimer = hitPauseDuration;
					if (healPercent > 0f)
					{
						base.healthComponent.HealFraction(healPercent, default(ProcChainMask));
						Util.PlaySound("Play_item_use_fruit", base.gameObject);
						EffectData effectData = new EffectData();
						effectData.origin = base.transform.position;
						effectData.SetNetworkedObjectReference(base.gameObject);
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/FruitHealEffect"), effectData, transmit: true);
					}
					if (resetDurationOnImpact)
					{
						base.fixedAge = 0f;
					}
					else
					{
						base.fixedAge -= hitPauseDuration;
					}
				}
			}
			else
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				hitPauseTimer -= GetDeltaTime();
				if (hitPauseTimer < 0f)
				{
					inHitPause = false;
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class Burrowed : GenericCharacterMain
	{
		public static float mortarCooldown;

		public static string primarySkillName;

		public static string altPrimarySkillName;

		public static string utilitySkillName;

		public static string altUtilitySkillName;

		public float duration;

		private ChildLocator childLocator;

		private CameraTargetParams.AimRequest aimRequest;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", "Burrowed", 0.1f);
			base.skillLocator.primary = base.skillLocator.FindSkill(altPrimarySkillName);
			base.skillLocator.utility = base.skillLocator.FindSkill(altUtilitySkillName);
			base.skillLocator.primary.stateMachine.mainStateType = new SerializableEntityStateType(typeof(AimMortar));
			base.skillLocator.primary.stateMachine.SetNextStateToMain();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
			}
			if ((bool)childLocator)
			{
				base.characterBody.aimOriginTransform = childLocator.FindChild("AimOriginMortar");
			}
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
		}

		public override void OnExit()
		{
			aimRequest?.Dispose();
			base.skillLocator.primary = base.skillLocator.FindSkill(primarySkillName);
			base.skillLocator.utility = base.skillLocator.FindSkill(utilitySkillName);
			base.skillLocator.primary.stateMachine.mainStateType = new SerializableEntityStateType(typeof(Idle));
			base.skillLocator.primary.stateMachine.SetNextStateToMain();
			if ((bool)childLocator)
			{
				base.characterBody.aimOriginTransform = childLocator.FindChild("AimOriginSyringe");
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class BurrowIn : BaseState
	{
		public static GameObject burrowPrefab;

		public static float baseDuration;

		public static string burrowInSoundString;

		private float stopwatch;

		private float duration;

		private Transform modelTransform;

		private ChildLocator childLocator;

		private CameraTargetParams.AimRequest aimRequest;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "BurrowIn", "BurrowIn.playbackRate", duration, 0.1f);
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			Util.PlaySound(burrowInSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false);
			if ((bool)base.characterBody)
			{
				base.characterBody.hideCrosshair = true;
			}
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
		}

		public override void OnExit()
		{
			aimRequest?.Dispose();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				Burrowed nextState = new Burrowed();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class BurrowOut : GenericCharacterMain
	{
		public static GameObject burrowPrefab;

		public static float baseDuration;

		public static string burrowOutSoundString;

		public static float jumpVelocity;

		private float stopwatch;

		private Transform modelTransform;

		private ChildLocator childLocator;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			Util.PlaySound(burrowOutSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false);
			base.characterMotor.velocity = new UnityEngine.Vector3(0f, jumpVelocity, 0f);
			base.characterMotor.Motor.ForceUnground();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class TreebotFireFruitSeed : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public string animationLayerName = "Gesture, Additive";

		[SerializeField]
		public string animationStateName = "FireFlower";

		[SerializeField]
		public string playbackRateParam = "FireFlower.playbackRate";

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration);
			if (base.isAuthority)
			{
				Ray ray = GetAimRay();
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.crit = RollCrit();
				fireProjectileInfo.damage = damageCoefficient * damageStat;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.position = ray.origin;
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(ray.direction);
				fireProjectileInfo.useSpeedOverride = false;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FlowerProjectileHover : DroneProjectileHover
	{
		public static float yankSpeed;

		public static AnimationCurve yankSuitabilityCurve;

		public static float healthFractionYieldPerHit;

		private GameObject owner;

		private ProcChainMask procChainMask;

		private float procCoefficient;

		private float damage;

		private DamageTypeCombo damageType;

		private bool crit;

		private TeamIndex teamIndex = TeamIndex.None;

		private float healPulseHealthFractionValue;

		public override void OnEnter()
		{
			base.OnEnter();
			ProjectileController component = GetComponent<ProjectileController>();
			if ((bool)component)
			{
				owner = component.owner;
				procChainMask = component.procChainMask;
				procCoefficient = component.procCoefficient;
				teamIndex = component.teamFilter.teamIndex;
			}
			ProjectileDamage component2 = GetComponent<ProjectileDamage>();
			if ((bool)component2)
			{
				damage = component2.damage;
				damageType = component2.damageType;
				crit = component2.crit;
			}
		}

		private void FirstPulse()
		{
			UnityEngine.Vector3 position = base.transform.position;
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = position;
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(teamIndex);
			bullseyeSearch.maxDistanceFilter = pulseRadius;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.filterByLoS = true;
			bullseyeSearch.filterByDistinctEntity = true;
			bullseyeSearch.RefreshCandidates();
			IEnumerable<HurtBox> results = bullseyeSearch.GetResults();
			int num = 0;
			foreach (HurtBox item in results)
			{
				num++;
				UnityEngine.Vector3 vector = item.transform.position - position;
				float magnitude = vector.magnitude;
				UnityEngine.Vector3 vector2 = vector / magnitude;
				Rigidbody component = item.healthComponent.GetComponent<Rigidbody>();
				float num2 = (component ? component.mass : 1f);
				float num3 = yankSuitabilityCurve.Evaluate(num2);
				UnityEngine.Vector3 force = vector2 * (num2 * num3 * (0f - yankSpeed));
				DamageInfo damageInfo = new DamageInfo
				{
					attacker = owner,
					inflictor = base.gameObject,
					crit = crit,
					damage = damage,
					damageColorIndex = DamageColorIndex.Default,
					damageType = damageType,
					force = force,
					position = item.transform.position,
					procChainMask = procChainMask,
					procCoefficient = procCoefficient
				};
				item.healthComponent.TakeDamage(damageInfo);
			}
			healPulseHealthFractionValue = (float)num * healthFractionYieldPerHit / (float)(pulseCount - 1);
		}

		private void HealPulse()
		{
			if ((bool)owner)
			{
				HealthComponent component = owner.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					component.HealFraction(healPulseHealthFractionValue, procChainMask);
				}
			}
		}

		protected override void Pulse()
		{
			if (pulses == 1)
			{
				FirstPulse();
			}
			else
			{
				HealPulse();
			}
		}
	}
	public class TreebotPrepFruitSeed : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string animationLayerName = "Gesture, Additive";

		[SerializeField]
		public string animationStateName = "PrepFlower";

		[SerializeField]
		public string playbackRateParam = "PrepFlower.playbackRate";

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new TreebotFireFruitSeed());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.Treebot.Weapon
{
	public class AimFlower : AimThrowableBase
	{
		public static float healthCostFraction;

		private bool keyDown = true;

		public override void Update()
		{
			base.Update();
			keyDown &= !base.inputBank.skill1.down;
		}

		protected override bool KeyIsDown()
		{
			return keyDown;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		protected override void FireProjectile()
		{
			if ((bool)base.healthComponent)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction;
				damageInfo.position = base.characterBody.corePosition;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.damageColorIndex = DamageColorIndex.Default;
				damageInfo.crit = false;
				damageInfo.attacker = null;
				damageInfo.inflictor = null;
				damageInfo.damageType = DamageType.NonLethal;
				damageInfo.procCoefficient = 0f;
				damageInfo.procChainMask = default(ProcChainMask);
				base.healthComponent.TakeDamage(damageInfo);
			}
			base.FireProjectile();
		}
	}
	public class AimMortar : AimThrowableBase
	{
		public static string enterSoundString;

		public static string exitSoundString;

		private static int StateHash = Animator.StringToHash("");

		private static int ParamHash = Animator.StringToHash(".playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Gesture, Additive", StateHash, ParamHash, minimumDuration);
		}

		public override void OnExit()
		{
			base.OnExit();
			outer.SetNextState(new FireMortar());
			if (!outer.destroying)
			{
				Util.PlaySound(exitSoundString, base.gameObject);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class AimMortar2 : AimThrowableBase
	{
		[SerializeField]
		public float healthCostFraction;

		public static string muzzleName;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public string fireSound;

		[SerializeField]
		public string enterSound;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Gesture, Additive", "PrepBomb", 0.1f);
			Util.PlaySound(enterSound, base.gameObject);
		}

		protected override void OnProjectileFiredLocal()
		{
			if (NetworkServer.active && (bool)base.healthComponent && healthCostFraction >= Mathf.Epsilon)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction;
				damageInfo.position = base.characterBody.corePosition;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.damageColorIndex = DamageColorIndex.Default;
				damageInfo.crit = false;
				damageInfo.attacker = null;
				damageInfo.inflictor = null;
				damageInfo.damageType = DamageType.NonLethal;
				damageInfo.procCoefficient = 0f;
				damageInfo.procChainMask = default(ProcChainMask);
				base.healthComponent.TakeDamage(damageInfo);
			}
			EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			Util.PlaySound(fireSound, base.gameObject);
			PlayCrossfade("Gesture, Additive", "FireBomb", 0.1f);
		}

		protected override bool KeyIsDown()
		{
			return base.inputBank.skill2.down;
		}

		protected override void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo)
		{
			base.ModifyProjectile(ref fireProjectileInfo);
			fireProjectileInfo.position = currentTrajectoryInfo.hitPoint;
			fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
			fireProjectileInfo.speedOverride = 0f;
		}
	}
	public class AimMortarRain : AimMortar2
	{
	}
	public class ChargeSonicBoom : BaseState
	{
		[SerializeField]
		public string sound;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		public static string muzzleName;

		public static float baseDuration;

		private float duration;

		private GameObject chargeEffect;

		private EffectManagerHelper _emh_chargeEffect;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffect = null;
			_emh_chargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(sound, base.gameObject);
			base.characterBody.SetAimTimer(3f);
			if (!chargeEffectPrefab)
			{
				return;
			}
			Transform transform = FindModelChild(muzzleName);
			if ((bool)transform)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
				{
					chargeEffect = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform);
				}
				else
				{
					_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform, inResetLocal: true);
					chargeEffect = _emh_chargeEffect.gameObject;
				}
				chargeEffect.transform.localPosition = UnityEngine.Vector3.zero;
				chargeEffect.transform.localRotation = UnityEngine.Quaternion.identity;
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeEffect)
			{
				if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffect);
				}
				chargeEffect = null;
				_emh_chargeEffect = null;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(GetNextState());
			}
		}

		protected virtual EntityState GetNextState()
		{
			return new FireSonicBoom();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ChargePlantSonicBoom : ChargeSonicBoom
	{
		protected override EntityState GetNextState()
		{
			return new FirePlantSonicBoom();
		}
	}
	public class CreatePounder : BaseState
	{
		public static float baseDuration;

		public static GameObject areaIndicatorPrefab;

		public static GameObject projectilePrefab;

		public static float damageCoefficient;

		public static GameObject muzzleflashEffect;

		public static GameObject goodCrosshairPrefab;

		public static GameObject badCrosshairPrefab;

		public static string prepSoundString;

		public static float maxDistance;

		public static string fireSoundString;

		public static float maxSlopeAngle;

		private float duration;

		private float stopwatch;

		private bool goodPlacement;

		private GameObject areaIndicatorInstance;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private EffectManagerHelper _emh_areaIndicatorInstance;

		private static int PrepWallStateHash = Animator.StringToHash("PrepWall");

		private static int PrepWallParamHash = Animator.StringToHash("PrepWall.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			stopwatch = 0f;
			goodPlacement = false;
			areaIndicatorInstance = null;
			_emh_areaIndicatorInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", PrepWallStateHash, PrepWallParamHash, duration);
			Util.PlaySound(prepSoundString, base.gameObject);
			if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab))
			{
				areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab);
			}
			else
			{
				_emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
				areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject;
			}
			UpdateAreaIndicator();
		}

		private void UpdateAreaIndicator()
		{
			bool flag = goodPlacement;
			goodPlacement = false;
			areaIndicatorInstance.SetActive(value: true);
			if ((bool)areaIndicatorInstance)
			{
				float num = maxDistance;
				float extraRaycastDistance = 0f;
				if (Physics.Raycast(CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance), out var hitInfo, num + extraRaycastDistance, LayerIndex.world.mask))
				{
					areaIndicatorInstance.transform.position = hitInfo.point;
					areaIndicatorInstance.transform.up = hitInfo.normal;
					goodPlacement = UnityEngine.Vector3.Angle(UnityEngine.Vector3.up, hitInfo.normal) < maxSlopeAngle;
				}
				if (flag != goodPlacement || crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest?.Dispose();
					GameObject crosshairPrefab = (goodPlacement ? goodCrosshairPrefab : badCrosshairPrefab);
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill);
				}
			}
			areaIndicatorInstance.SetActive(goodPlacement);
		}

		public override void Update()
		{
			base.Update();
			UpdateAreaIndicator();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && !base.inputBank.skill4.down && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (goodPlacement)
			{
				Util.PlaySound(fireSoundString, base.gameObject);
				if ((bool)areaIndicatorInstance && base.isAuthority)
				{
					bool crit = Util.CheckRoll(critStat, base.characterBody.master);
					ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position, UnityEngine.Quaternion.identity, base.gameObject, damageStat * damageCoefficient, 0f, crit);
				}
			}
			else
			{
				base.skillLocator.special.AddOneStock();
			}
			if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null)
			{
				_emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance);
			}
			else
			{
				EntityState.Destroy(areaIndicatorInstance.gameObject);
			}
			areaIndicatorInstance = null;
			_emh_areaIndicatorInstance = null;
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class FireMortar : BaseState
	{
		public static GameObject muzzleEffectPrefab;

		public static string fireSoundString;

		public static float baseDuration;

		private float duration;

		private static int FireBombStateHash = Animator.StringToHash("FireBomb");

		private static int FireBombParamHash = Animator.StringToHash("FireBomb.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", FireBombStateHash, FireBombParamHash, duration);
			Util.PlaySound(fireSoundString, base.gameObject);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "MuzzleNailgun", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireMortar2 : BaseState
	{
		public static float baseDuration;

		public static GameObject projectilePrefab;

		public static string fireSound;

		public static float maxDistance;

		public static float damageCoefficient;

		public static float force;

		public static string muzzleName;

		public static GameObject muzzleEffect;

		public static float healthCostFraction;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			EffectManager.SimpleMuzzleFlash(muzzleEffect, base.gameObject, muzzleName, transmit: false);
			Util.PlaySound(fireSound, base.gameObject);
			PlayCrossfade("Gesture, Additive", "FireBomb", 0.1f);
			if (base.isAuthority)
			{
				Fire();
			}
			if (NetworkServer.active && (bool)base.healthComponent)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction;
				damageInfo.position = base.characterBody.corePosition;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.damageColorIndex = DamageColorIndex.Default;
				damageInfo.crit = false;
				damageInfo.attacker = null;
				damageInfo.inflictor = null;
				damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor;
				damageInfo.procCoefficient = 0f;
				damageInfo.procChainMask = default(ProcChainMask);
				base.healthComponent.TakeDamage(damageInfo);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		private void Fire()
		{
			RaycastHit hitInfo;
			UnityEngine.Vector3 position = ((!base.inputBank.GetAimRaycast(maxDistance, out hitInfo)) ? base.inputBank.GetAimRay().GetPoint(maxDistance) : hitInfo.point);
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.position = position;
			fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.damage = damageCoefficient * damageStat;
			fireProjectileInfo.force = force;
			fireProjectileInfo.crit = RollCrit();
			fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
			fireProjectileInfo.target = null;
			fireProjectileInfo.speedOverride = 0f;
			fireProjectileInfo.fuseOverride = -1f;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireSonicBoom : BaseState
	{
		[SerializeField]
		public string sound;

		[SerializeField]
		public string muzzle;

		[SerializeField]
		public GameObject fireEffectPrefab;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float fieldOfView;

		[SerializeField]
		public float backupDistance;

		[SerializeField]
		public float maxDistance;

		[SerializeField]
		public float idealDistanceToPlaceTargets;

		[SerializeField]
		public float liftVelocity;

		[SerializeField]
		public float slowDuration;

		[SerializeField]
		public float groundKnockbackDistance;

		[SerializeField]
		public float airKnockbackDistance;

		public static AnimationCurve shoveSuitabilityCurve;

		private float duration;

		private static int FireSonicBoomStateHash = Animator.StringToHash("FireSonicBoom");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", FireSonicBoomStateHash);
			Util.PlaySound(sound, base.gameObject);
			Ray aimRay = GetAimRay();
			if (!string.IsNullOrEmpty(muzzle))
			{
				EffectManager.SimpleMuzzleFlash(fireEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			else
			{
				EffectManager.SpawnEffect(fireEffectPrefab, new EffectData
				{
					origin = aimRay.origin,
					rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction)
				}, transmit: false);
			}
			aimRay.origin -= aimRay.direction * backupDistance;
			if (NetworkServer.active)
			{
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.teamMaskFilter = TeamMask.all;
				bullseyeSearch.maxAngleFilter = fieldOfView * 0.5f;
				bullseyeSearch.maxDistanceFilter = maxDistance;
				bullseyeSearch.searchOrigin = aimRay.origin;
				bullseyeSearch.searchDirection = aimRay.direction;
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
				bullseyeSearch.filterByLoS = false;
				bullseyeSearch.RefreshCandidates();
				bullseyeSearch.FilterOutGameObject(base.gameObject);
				IEnumerable<HurtBox> enumerable = bullseyeSearch.GetResults().Where(Util.IsValid).Distinct(default(HurtBox.EntityEqualityComparer));
				TeamIndex team = GetTeam();
				foreach (HurtBox item in enumerable)
				{
					if (FriendlyFireManager.ShouldSplashHitProceed(item.healthComponent, team))
					{
						UnityEngine.Vector3 vector = item.transform.position - aimRay.origin;
						float magnitude = vector.magnitude;
						_ = new UnityEngine.Vector2(vector.x, vector.z).magnitude;
						UnityEngine.Vector3 vector2 = vector / magnitude;
						float num = 1f;
						CharacterBody body = item.healthComponent.body;
						if ((bool)body.characterMotor)
						{
							num = body.characterMotor.mass;
						}
						else if ((bool)item.healthComponent.GetComponent<Rigidbody>())
						{
							num = base.rigidbody.mass;
						}
						float num2 = shoveSuitabilityCurve.Evaluate(num);
						AddDebuff(body);
						body.RecalculateStats();
						float acceleration = body.acceleration;
						UnityEngine.Vector3 vector3 = vector2;
						float num3 = Trajectory.CalculateInitialYSpeedForHeight(Mathf.Abs(idealDistanceToPlaceTargets - magnitude), 0f - acceleration) * Mathf.Sign(idealDistanceToPlaceTargets - magnitude);
						vector3 *= num3;
						vector3.y = liftVelocity;
						DamageInfo damageInfo = new DamageInfo
						{
							attacker = base.gameObject,
							damage = CalculateDamage(),
							position = item.transform.position,
							procCoefficient = CalculateProcCoefficient()
						};
						item.healthComponent.TakeDamageForce(vector3 * (num * num2), alwaysApply: true, disableAirControlUntilCollision: true);
						item.healthComponent.TakeDamage(new DamageInfo
						{
							attacker = base.gameObject,
							damage = CalculateDamage(),
							position = item.transform.position,
							procCoefficient = CalculateProcCoefficient()
						});
						GlobalEventManager.instance.OnHitEnemy(damageInfo, item.healthComponent.gameObject);
					}
				}
			}
			if (base.isAuthority && (bool)base.characterBody && (bool)base.characterBody.characterMotor)
			{
				float height = (base.characterBody.characterMotor.isGrounded ? groundKnockbackDistance : airKnockbackDistance);
				float num4 = (base.characterBody.characterMotor ? base.characterBody.characterMotor.mass : 1f);
				float acceleration2 = base.characterBody.acceleration;
				float num5 = Trajectory.CalculateInitialYSpeedForHeight(height, 0f - acceleration2);
				base.characterBody.characterMotor.ApplyForce((0f - num5) * num4 * aimRay.direction);
			}
		}

		protected virtual void AddDebuff(CharacterBody body)
		{
			body.AddTimedBuff(RoR2Content.Buffs.Weak, slowDuration);
			body.healthComponent.GetComponent<SetStateOnHurt>()?.SetStun(-1f);
		}

		protected virtual float CalculateDamage()
		{
			return 0f;
		}

		protected virtual float CalculateProcCoefficient()
		{
			return 0f;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FirePlantSonicBoom : FireSonicBoom
	{
		public static float damageCoefficient;

		public static float procCoefficient;

		public static GameObject hitEffectPrefab;

		public static float healthFractionPerHit;

		public static float healthCostFraction;

		public static string impactSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active && (bool)base.healthComponent && healthCostFraction >= Mathf.Epsilon)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction;
				damageInfo.position = base.characterBody.corePosition;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.damageColorIndex = DamageColorIndex.Default;
				damageInfo.crit = false;
				damageInfo.attacker = null;
				damageInfo.inflictor = null;
				damageInfo.damageType = DamageType.NonLethal;
				damageInfo.procCoefficient = 0f;
				damageInfo.procChainMask = default(ProcChainMask);
				base.healthComponent.TakeDamage(damageInfo);
			}
		}

		protected override void AddDebuff(CharacterBody body)
		{
			body.healthComponent.GetComponent<SetStateOnHurt>()?.SetStun(-1f);
			if ((bool)hitEffectPrefab)
			{
				EffectManager.SpawnEffect(hitEffectPrefab, new EffectData
				{
					origin = body.corePosition
				}, transmit: true);
			}
			if ((bool)base.healthComponent)
			{
				HealOrb healOrb = new HealOrb();
				healOrb.origin = body.corePosition;
				healOrb.target = base.healthComponent.body.mainHurtBox;
				healOrb.healValue = healthFractionPerHit * base.healthComponent.fullHealth;
				healOrb.overrideDuration = UnityEngine.Random.Range(0.3f, 0.6f);
				OrbManager.instance.AddOrb(healOrb);
			}
			Util.PlaySound(impactSoundString, base.gameObject);
		}

		protected override float CalculateDamage()
		{
			return damageCoefficient * damageStat;
		}

		protected override float CalculateProcCoefficient()
		{
			return procCoefficient;
		}
	}
	public class FireSonicPull : FireSonicBoom
	{
	}
	public class FireSyringe : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject finalProjectilePrefab;

		public static GameObject muzzleflashEffectPrefab;

		public static int projectileCount = 3;

		public static float totalYawSpread = 5f;

		public static float baseDuration = 2f;

		public static float baseFireDuration = 0.2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string attackSound;

		public static string finalAttackSound;

		public static string muzzleName;

		private float duration;

		private float fireDuration;

		private int projectilesFired;

		private static int FireSyringeStateHash = Animator.StringToHash("FireSyringe");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			fireDuration = baseFireDuration / attackSpeedStat;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount);
			if (projectilesFired <= num && projectilesFired < projectileCount)
			{
				GameObject prefab = projectilePrefab;
				string soundString = attackSound;
				if (projectilesFired == projectileCount - 1)
				{
					prefab = finalProjectilePrefab;
					soundString = finalAttackSound;
				}
				PlayAnimation("Gesture, Additive", FireSyringeStateHash);
				Util.PlaySound(soundString, base.gameObject);
				base.characterBody.SetAimTimer(3f);
				if ((bool)muzzleflashEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleName, transmit: false);
				}
				if (base.isAuthority)
				{
					Ray ray = GetAimRay();
					TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
					float bonusYaw = (float)Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f) / (float)(projectileCount - 1) * totalYawSpread;
					UnityEngine.Vector3 forward = Util.ApplySpread(ray.direction, 0f, 0f, 1f, 1f, bonusYaw);
					ProjectileManager.instance.FireProjectile(prefab, ray.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
				}
				projectilesFired++;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Treebot.UnlockInteractable
{
	public class Unlock : BaseState
	{
		private static int ReviveParamHash = Animator.StringToHash("Revive");

		public static event Action<Interactor> onActivated;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				Unlock.onActivated?.Invoke(GetComponent<PurchaseInteraction>().lastActivator);
			}
			GetModelAnimator().SetBool(ReviveParamHash, value: true);
			GetModelTransform().GetComponent<RandomBlinkController>().enabled = true;
		}
	}
}
namespace EntityStates.Treebot.TreebotFlower
{
	public class SpawnState : BaseState
	{
		public static float duration;

		public static string enterSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Base", SpawnStateHash, SpawnParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new TreebotFlower2Projectile());
			}
		}
	}
	public class TreebotFlower2Projectile : BaseState
	{
		public static float yankIdealDistance;

		public static AnimationCurve yankSuitabilityCurve;

		public static float healthFractionYieldPerHit;

		public static float radius;

		public static float healPulseCount;

		public static float duration;

		public static float rootPulseCount;

		public static string enterSoundString;

		public static string exitSoundString;

		public static GameObject enterEffectPrefab;

		public static GameObject exitEffectPrefab;

		private List<CharacterBody> rootedBodies;

		private float healTimer;

		private float rootPulseTimer;

		private GameObject owner;

		private ProcChainMask procChainMask;

		private float procCoefficient;

		private TeamIndex teamIndex = TeamIndex.None;

		private float damage;

		private DamageTypeCombo damageType;

		private bool crit;

		private float healPulseHealthFractionValue;

		private static int SpawnToIdleStateHash = Animator.StringToHash("SpawnToIdle");

		public override void OnEnter()
		{
			base.OnEnter();
			ProjectileController component = GetComponent<ProjectileController>();
			if ((bool)component)
			{
				owner = component.owner;
				procChainMask = component.procChainMask;
				procCoefficient = component.procCoefficient;
				teamIndex = component.teamFilter.teamIndex;
			}
			ProjectileDamage component2 = GetComponent<ProjectileDamage>();
			if ((bool)component2)
			{
				damage = component2.damage;
				damageType = component2.damageType;
				crit = component2.crit;
			}
			if (NetworkServer.active)
			{
				rootedBodies = new List<CharacterBody>();
			}
			PlayAnimation("Base", SpawnToIdleStateHash);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)enterEffectPrefab)
			{
				EffectManager.SimpleEffect(enterEffectPrefab, base.transform.position, base.transform.rotation, transmit: false);
			}
			ChildLocator component3 = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component3)
			{
				Transform obj = component3.FindChild("AreaIndicator");
				obj.localScale = new UnityEngine.Vector3(radius, radius, radius);
				obj.gameObject.SetActive(value: true);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				float deltaTime = GetDeltaTime();
				rootPulseTimer -= deltaTime;
				healTimer -= deltaTime;
				if (rootPulseTimer <= 0f)
				{
					rootPulseTimer += duration / rootPulseCount;
					RootPulse();
				}
				if (healTimer <= 0f)
				{
					healTimer += duration / healPulseCount;
					HealPulse();
				}
				if (base.fixedAge >= duration)
				{
					EntityState.Destroy(base.gameObject);
				}
			}
		}

		private void RootPulse()
		{
			UnityEngine.Vector3 position = base.transform.position;
			HurtBox[] hurtBoxes = new SphereSearch
			{
				origin = position,
				radius = radius,
				mask = LayerIndex.entityPrecise.mask
			}.RefreshCandidates().FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamIndex)).OrderCandidatesByDistance()
				.FilterCandidatesByDistinctHurtBoxEntities()
				.GetHurtBoxes();
			foreach (HurtBox hurtBox in hurtBoxes)
			{
				CharacterBody body = hurtBox.healthComponent.body;
				if (!rootedBodies.Contains(body))
				{
					rootedBodies.Add(body);
					body.AddBuff(RoR2Content.Buffs.Entangle);
					body.RecalculateStats();
					UnityEngine.Vector3 vector = hurtBox.transform.position - position;
					float magnitude = vector.magnitude;
					UnityEngine.Vector3 vector2 = vector / magnitude;
					Rigidbody component = hurtBox.healthComponent.GetComponent<Rigidbody>();
					float num = (component ? component.mass : 1f);
					float num2 = magnitude - yankIdealDistance;
					float num3 = yankSuitabilityCurve.Evaluate(num);
					UnityEngine.Vector3 vector3 = (component ? component.velocity : UnityEngine.Vector3.zero);
					if (HGMath.IsVectorNaN(vector3))
					{
						vector3 = UnityEngine.Vector3.zero;
					}
					UnityEngine.Vector3 vector4 = -vector3;
					if (num2 > 0f)
					{
						vector4 = vector2 * (0f - Trajectory.CalculateInitialYSpeedForHeight(num2, 0f - body.acceleration));
					}
					UnityEngine.Vector3 force = vector4 * (num * num3);
					DamageInfo damageInfo = new DamageInfo
					{
						attacker = owner,
						inflictor = base.gameObject,
						crit = crit,
						damage = damage,
						damageColorIndex = DamageColorIndex.Default,
						damageType = damageType,
						force = force,
						position = hurtBox.transform.position,
						procChainMask = procChainMask,
						procCoefficient = procCoefficient
					};
					hurtBox.healthComponent.TakeDamage(damageInfo);
					HurtBox hurtBoxReference = hurtBox;
					HurtBoxGroup hurtBoxGroup = hurtBox.hurtBoxGroup;
					for (int j = 0; (float)j < Mathf.Min(4f, body.radius * 2f); j++)
					{
						EffectData effectData = new EffectData
						{
							scale = 1f,
							origin = position,
							genericFloat = Mathf.Max(0.2f, duration - base.fixedAge)
						};
						effectData.SetHurtBoxReference(hurtBoxReference);
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OrbEffects/EntangleOrbEffect"), effectData, transmit: true);
						hurtBoxReference = hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, hurtBoxGroup.hurtBoxes.Length)];
					}
				}
			}
		}

		public override void OnExit()
		{
			if (rootedBodies != null)
			{
				foreach (CharacterBody rootedBody in rootedBodies)
				{
					rootedBody.RemoveBuff(RoR2Content.Buffs.Entangle);
				}
				rootedBodies = null;
			}
			Util.PlaySound(exitSoundString, base.gameObject);
			if ((bool)exitEffectPrefab)
			{
				EffectManager.SimpleEffect(exitEffectPrefab, base.transform.position, base.transform.rotation, transmit: false);
			}
			base.OnExit();
		}

		private void HealPulse()
		{
			HealthComponent healthComponent = (owner ? owner.GetComponent<HealthComponent>() : null);
			if ((bool)healthComponent && rootedBodies.Count > 0)
			{
				float num = 1f / healPulseCount;
				HealOrb healOrb = new HealOrb();
				healOrb.origin = base.transform.position;
				healOrb.target = healthComponent.body.mainHurtBox;
				healOrb.healValue = num * healthFractionYieldPerHit * healthComponent.fullHealth * (float)rootedBodies.Count;
				healOrb.overrideDuration = 0.3f;
				OrbManager.instance.AddOrb(healOrb);
			}
		}
	}
}
namespace EntityStates.Toolbot
{
	public abstract class AimGrenade : AimThrowableBase
	{
		public override void OnEnter()
		{
			base.OnEnter();
			detonationRadius = 7f;
		}
	}
	public class AimStunDrone : AimGrenade
	{
		public static string enterSoundString;

		public static string exitSoundString;

		private static int PrepBombStateHash = Animator.StringToHash("PrepBomb");

		private static int PutAwayGunStateHash = Animator.StringToHash("PutAwayGun");

		private static int PrepBombParamHash = Animator.StringToHash("PrepBomb.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Gesture, Additive", PrepBombStateHash, PrepBombParamHash, minimumDuration);
			PlayAnimation("Stance, Override", PutAwayGunStateHash);
		}

		public override void OnExit()
		{
			base.OnExit();
			outer.SetNextState(new RecoverAimStunDrone());
			Util.PlaySound(exitSoundString, base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class RecoverAimStunDrone : BaseState
	{
		public static GameObject muzzleEffectPrefab;

		public static string fireSoundString;

		public static float baseDuration;

		private float duration;

		private static int FireBombStateHash = Animator.StringToHash("FireBomb");

		private static int FireBombParamHash = Animator.StringToHash("FireBomb.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", FireBombStateHash, FireBombParamHash, duration);
			Util.PlaySound(fireSoundString, base.gameObject);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "MuzzleNailgun", transmit: false);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			PlayCrossfade("Stance, Override", "Empty", 0.1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class AimHealDrone : AimGrenade
	{
	}
	public abstract class BaseToolbotPrimarySkillState : BaseSkillState, IToolbotPrimarySkillState, ISkillState
	{
		public Transform muzzleTransform { get; set; }

		public virtual string baseMuzzleName => "Muzzle";

		public bool isInDualWield { get; set; }

		public int currentHand { get; set; }

		public string muzzleName { get; set; }

		public SkillDef skillDef { get; set; }

		public override void OnEnter()
		{
			base.OnEnter();
			BaseToolbotPrimarySkillStateMethods.OnEnter(this, base.gameObject, base.skillLocator, GetModelChildLocator());
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public static class BaseToolbotPrimarySkillStateMethods
	{
		private static int DualWieldFireLStateHash = Animator.StringToHash("DualWieldFire, Left");

		private static int DualWieldFireRStateHash = Animator.StringToHash("DualWieldFire, Right");

		public static void OnEnter<T>(T state, GameObject gameObject, SkillLocator skillLocator, ChildLocator modelChildLocator) where T : BaseState, IToolbotPrimarySkillState
		{
			state.currentHand = 0;
			state.isInDualWield = EntityStateMachine.FindByCustomName(gameObject, "Body").state is ToolbotDualWield;
			state.muzzleName = state.baseMuzzleName;
			state.skillDef = state.activatorSkillSlot.skillDef;
			if (state.isInDualWield)
			{
				if ((object)state.activatorSkillSlot == skillLocator.primary)
				{
					state.currentHand = -1;
					state.muzzleName = "DualWieldMuzzleL";
				}
				else if ((object)state.activatorSkillSlot == skillLocator.secondary)
				{
					state.currentHand = 1;
					state.muzzleName = "DualWieldMuzzleR";
				}
			}
			if (state.muzzleName != null)
			{
				state.muzzleTransform = modelChildLocator.FindChild(state.muzzleName);
			}
		}

		public static void PlayGenericFireAnim<T>(T state, GameObject gameObject, SkillLocator skillLocator, float duration) where T : BaseState, IToolbotPrimarySkillState
		{
			state.currentHand = 0;
			if ((object)state.activatorSkillSlot == skillLocator.primary)
			{
				state.currentHand = -1;
			}
			else if ((object)state.activatorSkillSlot == skillLocator.secondary)
			{
				state.currentHand = 1;
			}
			switch (state.currentHand)
			{
			case -1:
				state.PlayAnimation("Gesture, Additive", DualWieldFireLStateHash);
				break;
			case 1:
				state.PlayAnimation("Gesture, Additive Bonus", DualWieldFireRStateHash);
				break;
			}
		}
	}
	public interface IToolbotPrimarySkillState : ISkillState
	{
		Transform muzzleTransform { get; set; }

		string muzzleName { get; set; }

		string baseMuzzleName { get; }

		bool isInDualWield { get; set; }

		int currentHand { get; set; }

		SkillDef skillDef { get; set; }
	}
	public class ChargeSpear : BaseToolbotPrimarySkillState
	{
		public static float baseMinChargeDuration;

		public static float baseChargeDuration;

		public static float perfectChargeWindow;

		public static GameObject chargeupVfxPrefab;

		public static GameObject holdChargeVfxPrefab;

		private float minChargeDuration;

		private float chargeDuration;

		private bool released;

		private GameObject chargeupVfxGameObject;

		private GameObject holdChargeVfxGameObject;

		private EffectManagerHelper _emh_chargeupVfx;

		private EffectManagerHelper _emh_holdChargeVfx;

		private static int ChargeSpearStateHash = Animator.StringToHash("ChargeSpear");

		private static int ChargeSpearParamHash = Animator.StringToHash("ChargeSpear.playbackRate");

		public override void Reset()
		{
			base.Reset();
			minChargeDuration = 0f;
			chargeDuration = 0f;
			released = false;
			chargeupVfxGameObject = null;
			holdChargeVfxGameObject = null;
			_emh_chargeupVfx = null;
			_emh_holdChargeVfx = null;
			released = false;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			minChargeDuration = baseMinChargeDuration / attackSpeedStat;
			chargeDuration = baseChargeDuration / attackSpeedStat;
			if (!base.isInDualWield)
			{
				PlayAnimation("Gesture, Additive", ChargeSpearStateHash, ChargeSpearParamHash, chargeDuration);
			}
			if ((bool)base.muzzleTransform)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeupVfxPrefab))
				{
					chargeupVfxGameObject = UnityEngine.Object.Instantiate(chargeupVfxPrefab, base.muzzleTransform);
				}
				else
				{
					_emh_chargeupVfx = EffectManager.GetAndActivatePooledEffect(chargeupVfxPrefab, base.muzzleTransform, inResetLocal: true);
					chargeupVfxGameObject = _emh_chargeupVfx.gameObject;
				}
				chargeupVfxGameObject.GetComponent<ScaleParticleSystemDuration>().newDuration = chargeDuration;
			}
		}

		protected void KillChargeEffect()
		{
			if (!chargeupVfxGameObject)
			{
				return;
			}
			if (!EffectManager.UsePools)
			{
				EntityState.Destroy(chargeupVfxGameObject);
			}
			else
			{
				if (_emh_chargeupVfx != null && _emh_chargeupVfx.OwningPool != null)
				{
					_emh_chargeupVfx.OwningPool.ReturnObject(_emh_chargeupVfx);
				}
				else
				{
					EntityState.Destroy(chargeupVfxGameObject);
				}
				_emh_chargeupVfx = null;
			}
			chargeupVfxGameObject = null;
		}

		public override void OnExit()
		{
			KillChargeEffect();
			if ((bool)holdChargeVfxGameObject)
			{
				if (!EffectManager.UsePools)
				{
					EntityState.Destroy(holdChargeVfxGameObject);
				}
				else
				{
					if (_emh_holdChargeVfx != null && _emh_holdChargeVfx.OwningPool != null)
					{
						_emh_holdChargeVfx.OwningPool.ReturnObject(_emh_holdChargeVfx);
					}
					else
					{
						EntityState.Destroy(holdChargeVfxGameObject);
					}
					_emh_holdChargeVfx = null;
				}
				holdChargeVfxGameObject = null;
			}
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			base.characterBody.SetSpreadBloom(base.age / chargeDuration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float num = base.fixedAge - chargeDuration;
			if (num >= 0f)
			{
				_ = perfectChargeWindow;
			}
			float charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			if (base.fixedAge >= chargeDuration)
			{
				KillChargeEffect();
				if (!holdChargeVfxGameObject && (bool)base.muzzleTransform)
				{
					if (!EffectManager.ShouldUsePooledEffect(holdChargeVfxPrefab))
					{
						holdChargeVfxGameObject = UnityEngine.Object.Instantiate(holdChargeVfxPrefab, base.muzzleTransform);
					}
					else
					{
						_emh_holdChargeVfx = EffectManager.GetAndActivatePooledEffect(holdChargeVfxPrefab, base.muzzleTransform, inResetLocal: true);
						holdChargeVfxGameObject = _emh_holdChargeVfx.gameObject;
					}
				}
			}
			if (base.isAuthority)
			{
				if (!released && !IsKeyDownAuthority())
				{
					released = true;
				}
				if (released && base.fixedAge >= minChargeDuration)
				{
					outer.SetNextState(new FireSpear
					{
						charge = charge,
						activatorSkillSlot = base.activatorSkillSlot
					});
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class CooldownSpear : BaseToolbotPrimarySkillState
	{
		public static float baseDuration;

		public static string enterSoundString;

		private float duration;

		private uint soundID;

		private static int CooldownSpearStateHash = Animator.StringToHash("CooldownSpear");

		private static int CooldownSpearParamHash = Animator.StringToHash("CooldownSpear.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if (!base.isInDualWield)
			{
				PlayAnimation("Gesture, Additive", CooldownSpearStateHash, CooldownSpearParamHash, duration);
			}
			soundID = Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(soundID);
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			base.characterBody.SetSpreadBloom(1f - base.age / duration, canOnlyIncreaseBloom: false);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireBuzzsaw : BaseToolbotPrimarySkillState
	{
		public static float damageCoefficientPerSecond;

		public static float procCoefficientPerSecond = 1f;

		public static string fireSoundString;

		public static string impactSoundString;

		public static string spinUpSoundString;

		public static string spinDownSoundString;

		public static float spreadBloomValue = 0.2f;

		public static float baseFireFrequency;

		public static GameObject spinEffectPrefab;

		public static GameObject spinImpactEffectPrefab;

		public static GameObject impactEffectPrefab;

		public static float selfForceMagnitude;

		private OverlapAttack attack;

		private float fireFrequency;

		private float fireAge;

		private GameObject spinEffectInstance;

		private GameObject spinImpactEffectInstance;

		private bool hitOverlapLastTick;

		protected EffectManagerHelper _emh_spinEffectInstance;

		protected EffectManagerHelper _emh_spinImpactEffectInstance;

		private static int SpinBuzzsawStateHash = Animator.StringToHash("SpinBuzzsaw");

		private static int EnterBuzzsawStateHash = Animator.StringToHash("EnterBuzzsaw");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int ExitBuzzsawStateHash = Animator.StringToHash("ExitBuzzsaw");

		private static int ImpactBuzzsawStateHash = Animator.StringToHash("ImpactBuzzsaw");

		public override string baseMuzzleName => "MuzzleBuzzsaw";

		public override void Reset()
		{
			base.Reset();
			if (attack != null)
			{
				attack.Reset();
			}
			fireFrequency = 0f;
			fireAge = 0f;
			spinEffectInstance = null;
			spinImpactEffectInstance = null;
			base.muzzleTransform = null;
			hitOverlapLastTick = false;
			_emh_spinEffectInstance = null;
			_emh_spinImpactEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			fireFrequency = baseFireFrequency * attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			Util.PlaySound(spinUpSoundString, base.gameObject);
			Util.PlaySound(fireSoundString, base.gameObject);
			if (!base.isInDualWield)
			{
				PlayAnimation("Gesture, Additive Gun", SpinBuzzsawStateHash);
				PlayAnimation("Gesture, Additive", EnterBuzzsawStateHash);
			}
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficientPerSecond * damageStat / baseFireFrequency;
			attack.procCoefficient = procCoefficientPerSecond / baseFireFrequency;
			if ((bool)impactEffectPrefab)
			{
				attack.hitEffectPrefab = impactEffectPrefab;
			}
			if ((bool)modelTransform)
			{
				string groupName = "Buzzsaw";
				if (base.isInDualWield)
				{
					if (base.currentHand == -1)
					{
						groupName = "BuzzsawL";
					}
					else if (base.currentHand == 1)
					{
						groupName = "BuzzsawR";
					}
				}
				attack.hitBoxGroup = HitBoxGroup.FindByGroupName(modelTransform.gameObject, groupName);
			}
			if ((bool)base.muzzleTransform)
			{
				if ((bool)spinEffectPrefab)
				{
					if (!EffectManager.ShouldUsePooledEffect(spinEffectPrefab))
					{
						spinEffectInstance = UnityEngine.Object.Instantiate(spinEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation);
					}
					else
					{
						_emh_spinEffectInstance = EffectManager.GetAndActivatePooledEffect(spinEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation);
						spinEffectInstance = _emh_spinEffectInstance.gameObject;
					}
					spinEffectInstance.transform.parent = base.muzzleTransform;
					spinEffectInstance.transform.localScale = UnityEngine.Vector3.one;
				}
				if ((bool)spinImpactEffectPrefab)
				{
					if (!EffectManager.ShouldUsePooledEffect(spinImpactEffectPrefab))
					{
						spinImpactEffectInstance = UnityEngine.Object.Instantiate(spinImpactEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation);
					}
					else
					{
						_emh_spinImpactEffectInstance = EffectManager.GetAndActivatePooledEffect(spinImpactEffectPrefab, base.muzzleTransform.position, base.muzzleTransform.rotation);
						spinImpactEffectInstance = _emh_spinImpactEffectInstance.gameObject;
					}
					spinImpactEffectInstance.transform.parent = base.muzzleTransform;
					spinImpactEffectInstance.transform.localScale = UnityEngine.Vector3.one;
					spinImpactEffectInstance.gameObject.SetActive(value: false);
				}
			}
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
		}

		public override void OnExit()
		{
			base.OnExit();
			Util.PlaySound(spinDownSoundString, base.gameObject);
			if (!base.isInDualWield)
			{
				PlayAnimation("Gesture, Additive Gun", EmptyStateHash);
				PlayAnimation("Gesture, Additive", ExitBuzzsawStateHash);
			}
			if ((bool)spinEffectInstance)
			{
				if (!EffectManager.UsePools)
				{
					EntityState.Destroy(spinEffectInstance);
				}
				else
				{
					if (_emh_spinEffectInstance != null && _emh_spinEffectInstance.OwningPool != null)
					{
						_emh_spinEffectInstance.OwningPool.ReturnObject(_emh_spinEffectInstance);
					}
					else
					{
						EntityState.Destroy(spinEffectInstance);
					}
					_emh_spinEffectInstance = null;
				}
			}
			if ((bool)spinImpactEffectInstance)
			{
				EntityState.Destroy(spinImpactEffectInstance);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireAge += GetDeltaTime();
			base.characterBody.SetAimTimer(2f);
			attackSpeedStat = base.characterBody.attackSpeed;
			fireFrequency = baseFireFrequency * attackSpeedStat;
			if (fireAge >= 1f / fireFrequency && base.isAuthority)
			{
				fireAge = 0f;
				attack.ResetIgnoredHealthComponents();
				attack.isCrit = base.characterBody.RollCrit();
				hitOverlapLastTick = attack.Fire();
				if (hitOverlapLastTick)
				{
					UnityEngine.Vector3 normalized = (attack.lastFireAverageHitPosition - GetAimRay().origin).normalized;
					if ((bool)base.characterMotor)
					{
						base.characterMotor.ApplyForce(normalized * selfForceMagnitude);
					}
					Util.PlaySound(impactSoundString, base.gameObject);
					if (!base.isInDualWield)
					{
						PlayAnimation("Gesture, Additive", ImpactBuzzsawStateHash);
					}
				}
				base.characterBody.AddSpreadBloom(spreadBloomValue);
				if (!IsKeyDownAuthority() || (object)base.skillDef != base.activatorSkillSlot.skillDef)
				{
					outer.SetNextStateToMain();
				}
			}
			spinImpactEffectInstance.gameObject.SetActive(hitOverlapLastTick);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireGrenadeLauncher : GenericProjectileBaseState, IToolbotPrimarySkillState, ISkillState
	{
		private static int FireGrenadeLauncherStateHash = Animator.StringToHash("FireGrenadeLauncher");

		private static int FireGrenadeLauncherParamHash = Animator.StringToHash("FireGrenadeLauncher.playbackRate");

		Transform IToolbotPrimarySkillState.muzzleTransform { get; set; }

		string IToolbotPrimarySkillState.baseMuzzleName => targetMuzzle;

		bool IToolbotPrimarySkillState.isInDualWield { get; set; }

		int IToolbotPrimarySkillState.currentHand { get; set; }

		string IToolbotPrimarySkillState.muzzleName { get; set; }

		public SkillDef skillDef { get; set; }

		public GenericSkill activatorSkillSlot { get; set; }

		public override void OnEnter()
		{
			BaseToolbotPrimarySkillStateMethods.OnEnter(this, base.gameObject, base.skillLocator, GetModelChildLocator());
			base.OnEnter();
		}

		protected override void PlayAnimation(float duration)
		{
			if (!((IToolbotPrimarySkillState)this).isInDualWield)
			{
				PlayAnimation("Gesture, Additive", FireGrenadeLauncherStateHash, FireGrenadeLauncherParamHash, duration);
			}
			else
			{
				BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, duration);
			}
		}

		protected override Ray ModifyProjectileAimRay(Ray projectileRay)
		{
			if (((IToolbotPrimarySkillState)this).isInDualWield)
			{
				Transform muzzleTransform = ((IToolbotPrimarySkillState)this).muzzleTransform;
				if ((bool)muzzleTransform)
				{
					projectileRay.origin = muzzleTransform.position;
				}
			}
			return projectileRay;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			this.Serialize(base.skillLocator, writer);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			this.Deserialize(base.skillLocator, reader);
		}
	}
	public class BaseNailgunState : BaseToolbotPrimarySkillState
	{
		public static float damageCoefficient = 0.1f;

		public static float procCoefficient = 1f;

		public static float force = 100f;

		public static float maxDistance = 50f;

		public new static string muzzleName;

		public static GameObject hitEffectPrefab;

		public static float spreadPitchScale = 0.5f;

		public static float spreadYawScale = 1f;

		public static GameObject tracerEffectPrefab;

		public static string fireSoundString;

		public static GameObject muzzleFlashPrefab;

		public static float spreadBloomValue = 0.2f;

		protected float duration;

		protected int fireNumber;

		private static int FireNailgunStateHash = Animator.StringToHash("FireNailgun");

		private static int isFiringNailgunStateHash = Animator.StringToHash("isFiringNailgun");

		private bool _animateNailgunFiring;

		public override string baseMuzzleName => muzzleName;

		protected bool animateNailgunFiring
		{
			get
			{
				return _animateNailgunFiring;
			}
			set
			{
				if (_animateNailgunFiring != value)
				{
					_animateNailgunFiring = value;
					GetModelAnimator().SetBool(isFiringNailgunStateHash, value);
				}
			}
		}

		protected virtual float GetBaseDuration()
		{
			return 0f;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			PullCurrentStats();
		}

		protected void PullCurrentStats()
		{
			attackSpeedStat = base.characterBody.attackSpeed;
			critStat = base.characterBody.crit;
			duration = GetBaseDuration() / attackSpeedStat;
		}

		protected void FireBullet(Ray aimRay, int bulletCount, float spreadPitchScale, float spreadYawScale)
		{
			fireNumber++;
			StartAimMode(aimRay, 3f);
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.bulletCount = (uint)bulletCount;
				bulletAttack.damage = damageStat * damageCoefficient;
				bulletAttack.damageColorIndex = DamageColorIndex.Default;
				bulletAttack.damageType = DamageType.Generic;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet;
				bulletAttack.force = force;
				bulletAttack.HitEffectNormal = false;
				bulletAttack.procChainMask = default(ProcChainMask);
				bulletAttack.procCoefficient = procCoefficient;
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.radius = 0f;
				bulletAttack.isCrit = RollCrit();
				bulletAttack.muzzleName = ((IToolbotPrimarySkillState)this).muzzleName;
				bulletAttack.minSpread = 0f;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.maxSpread = base.characterBody.spreadBloomAngle;
				bulletAttack.smartCollision = false;
				bulletAttack.sniper = false;
				bulletAttack.spreadPitchScale = spreadPitchScale * spreadPitchScale;
				bulletAttack.spreadYawScale = spreadYawScale * spreadYawScale;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.allowTrajectoryAimAssist = false;
				bulletAttack.Fire();
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.AddSpreadBloom(spreadBloomValue);
			}
			Util.PlaySound(fireSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			if (!base.isInDualWield)
			{
				PlayAnimation("Gesture, Additive", FireNailgunStateHash);
			}
			else
			{
				BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, 0.2f);
			}
		}
	}
	public class FireNailgun : BaseNailgunState
	{
		public static float baseRefireInterval;

		public static string spinUpSound;

		private float refireStopwatch;

		private uint loopSoundID;

		private BuffIndex skillsDisabledBuffIndex;

		protected override float GetBaseDuration()
		{
			return baseRefireInterval;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			loopSoundID = Util.PlaySound(spinUpSound, base.gameObject);
			base.animateNailgunFiring = true;
			refireStopwatch = duration;
			skillsDisabledBuffIndex = DLC2Content.Buffs.DisableAllSkills.buffIndex;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			refireStopwatch += GetDeltaTime();
			if (refireStopwatch >= duration)
			{
				PullCurrentStats();
				refireStopwatch -= duration;
				Ray ray = GetAimRay();
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, BaseNailgunState.maxDistance, base.gameObject);
				UnityEngine.Vector3 direction = ray.direction;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, direction);
				float num = Mathf.Sin((float)fireNumber * 0.5f);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(base.characterBody.spreadBloomAngle * num, axis) * direction;
				vector = UnityEngine.Quaternion.AngleAxis((float)fireNumber * -65.454544f, direction) * vector;
				ray.direction = vector;
				FireBullet(ray, 1, 0f, 0f);
			}
			if (base.isAuthority && (!IsKeyDownAuthority() || base.characterBody.isSprinting || base.characterBody.HasBuff(skillsDisabledBuffIndex)))
			{
				outer.SetNextState(new NailgunSpinDown
				{
					activatorSkillSlot = base.activatorSkillSlot
				});
			}
		}

		public override void OnExit()
		{
			base.animateNailgunFiring = false;
			AkSoundEngine.StopPlayingID(loopSoundID);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class NailgunSpinDown : BaseNailgunState
	{
		public static string spinDownSound;

		public static float baseDuration;

		protected override float GetBaseDuration()
		{
			return baseDuration;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlayAttackSpeedSound(spinDownSound, base.gameObject, attackSpeedStat);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new NailgunFinalBurst
				{
					activatorSkillSlot = base.activatorSkillSlot
				});
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class NailgunFinalBurst : BaseNailgunState
	{
		public static int finalBurstBulletCount = 8;

		public static float burstTimeCostCoefficient = 1.2f;

		public static string burstSound;

		public static float selfForce = 1000f;

		private static int FireGrenadeLauncherStateHash = Animator.StringToHash("FireGrenadeLauncher");

		private static int FireGrenadeLauncherParamHash = Animator.StringToHash("FireGrenadeLauncher.playbackRate");

		protected override float GetBaseDuration()
		{
			return (float)finalBurstBulletCount * FireNailgun.baseRefireInterval * burstTimeCostCoefficient;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetSpreadBloom(1f, canOnlyIncreaseBloom: false);
			}
			if (!base.characterBody.HasBuff(DLC2Content.Buffs.DisableAllSkills.buffIndex))
			{
				Ray ray = GetAimRay();
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, BaseNailgunState.maxDistance, base.gameObject);
				FireBullet(GetAimRay(), finalBurstBulletCount, BaseNailgunState.spreadPitchScale, BaseNailgunState.spreadYawScale);
				if (!base.isInDualWield)
				{
					PlayAnimation("Gesture, Additive", FireGrenadeLauncherStateHash, FireGrenadeLauncherParamHash, 0.45f / attackSpeedStat);
				}
				else
				{
					BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, 0.45f / attackSpeedStat);
				}
				Util.PlaySound(burstSound, base.gameObject);
				if (base.isAuthority)
				{
					float num = selfForce * (base.characterMotor.isGrounded ? 0.5f : 1f) * base.characterMotor.mass;
					base.characterMotor.ApplyForce(ray.direction * (0f - num));
				}
				Util.PlaySound(BaseNailgunState.fireSoundString, base.gameObject);
				Util.PlaySound(BaseNailgunState.fireSoundString, base.gameObject);
				Util.PlaySound(BaseNailgunState.fireSoundString, base.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireSpear : GenericBulletBaseState, IToolbotPrimarySkillState, ISkillState
	{
		public float charge;

		public static float recoilAmplitude;

		private static int FireSpearStateHash = Animator.StringToHash("FireSpear");

		private static int FireSpearParamHash = Animator.StringToHash("FireSpear.playbackRate");

		Transform IToolbotPrimarySkillState.muzzleTransform { get; set; }

		string IToolbotPrimarySkillState.baseMuzzleName => muzzleName;

		bool IToolbotPrimarySkillState.isInDualWield { get; set; }

		int IToolbotPrimarySkillState.currentHand { get; set; }

		string IToolbotPrimarySkillState.muzzleName { get; set; }

		public SkillDef skillDef { get; set; }

		public GenericSkill activatorSkillSlot { get; set; }

		public override void OnEnter()
		{
			BaseToolbotPrimarySkillStateMethods.OnEnter(this, base.gameObject, base.skillLocator, GetModelChildLocator());
			base.OnEnter();
		}

		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.stopperMask = LayerIndex.world.mask;
			bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
			bulletAttack.muzzleName = ((IToolbotPrimarySkillState)this).muzzleName;
		}

		protected override void FireBullet(Ray aimRay)
		{
			base.FireBullet(aimRay);
			base.characterBody.SetSpreadBloom(1f, canOnlyIncreaseBloom: false);
			AddRecoil(-0.6f * recoilAmplitude, -0.8f * recoilAmplitude, -0.1f * recoilAmplitude, 0.1f * recoilAmplitude);
			if (!((IToolbotPrimarySkillState)this).isInDualWield)
			{
				PlayAnimation("Gesture, Additive", FireSpearStateHash, FireSpearParamHash, duration);
			}
			else
			{
				BaseToolbotPrimarySkillStateMethods.PlayGenericFireAnim(this, base.gameObject, base.skillLocator, duration);
			}
		}

		public override void Update()
		{
			base.Update();
			base.characterBody.SetSpreadBloom(0.9f + base.age / duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new CooldownSpear
				{
					activatorSkillSlot = activatorSkillSlot
				});
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			this.Serialize(base.skillLocator, writer);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			this.Deserialize(base.skillLocator, reader);
		}
	}
	public class ToolbotDash : BaseCharacterMain
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float speedMultiplier;

		public static float chargeDamageCoefficient;

		public static float awayForceMagnitude;

		public static float upwardForceMagnitude;

		public static GameObject impactEffectPrefab;

		public static float hitPauseDuration;

		public static string impactSoundString;

		public static float recoilAmplitude;

		public static string startSoundString;

		public static string endSoundString;

		public static GameObject knockbackEffectPrefab;

		public static float knockbackDamageCoefficient;

		public static float massThresholdForKnockback;

		public static float knockbackForce;

		[SerializeField]
		public GameObject startEffectPrefab;

		[SerializeField]
		public GameObject endEffectPrefab;

		private uint soundID;

		private float duration;

		private float hitPauseTimer;

		private UnityEngine.Vector3 idealDirection;

		private OverlapAttack attack;

		private bool inHitPause;

		private List<HurtBox> victimsStruck = new List<HurtBox>();

		private static int BoxModeExitStateHash = Animator.StringToHash("BoxModeExit");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int aimWeightStateHash = Animator.StringToHash("aimWeight");

		private static int BoxModeImpactStateHash = Animator.StringToHash("BoxModeImpact");

		private static int BoxModeImpactParamHash = Animator.StringToHash("BoxModeImpact.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			if (base.isAuthority)
			{
				if ((bool)base.inputBank)
				{
					idealDirection = base.inputBank.aimDirection;
					idealDirection.y = 0f;
				}
				UpdateDirection();
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.normalizeToFloor = true;
			}
			if ((bool)startEffectPrefab && (bool)base.characterBody)
			{
				EffectManager.SpawnEffect(startEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition
				}, transmit: false);
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.forward = idealDirection;
			}
			soundID = Util.PlaySound(startSoundString, base.gameObject);
			PlayCrossfade("Body", "BoxModeEnter", 0.1f);
			PlayCrossfade("Stance, Override", "PutAwayGun", 0.1f);
			base.modelAnimator.SetFloat("aimWeight", 0f);
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost);
			}
			HitBoxGroup hitBoxGroup = null;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Charge");
			}
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = GetTeam();
			attack.damage = chargeDamageCoefficient * damageStat;
			attack.hitEffectPrefab = impactEffectPrefab;
			attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude;
			attack.pushAwayForce = awayForceMagnitude;
			attack.hitBoxGroup = hitBoxGroup;
			attack.isCrit = RollCrit();
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(soundID);
			Util.PlaySound(endSoundString, base.gameObject);
			if (!outer.destroying && (bool)base.characterBody)
			{
				if ((bool)endEffectPrefab)
				{
					EffectManager.SpawnEffect(endEffectPrefab, new EffectData
					{
						origin = base.characterBody.corePosition
					}, transmit: false);
				}
				PlayAnimation("Body", BoxModeExitStateHash);
				PlayCrossfade("Stance, Override", EmptyStateHash, 0.1f);
				base.characterBody.isSprinting = false;
				if (NetworkServer.active)
				{
					base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost);
				}
			}
			if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision)
			{
				base.characterMotor.velocity += GetIdealVelocity();
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.normalizeToFloor = false;
			}
			base.modelAnimator.SetFloat(aimWeightStateHash, 1f);
			base.OnExit();
		}

		private float GetDamageBoostFromSpeed()
		{
			return Mathf.Max(1f, base.characterBody.moveSpeed / base.characterBody.baseMoveSpeed);
		}

		private void UpdateDirection()
		{
			if ((bool)base.inputBank)
			{
				UnityEngine.Vector2 vector = Util.Vector3XZToVector2XY(base.inputBank.moveVector);
				if (vector != UnityEngine.Vector2.zero)
				{
					vector.Normalize();
					idealDirection = new UnityEngine.Vector3(vector.x, 0f, vector.y).normalized;
				}
			}
		}

		private UnityEngine.Vector3 GetIdealVelocity()
		{
			return base.characterDirection.forward * base.characterBody.moveSpeed * speedMultiplier;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
			else
			{
				if (!base.isAuthority)
				{
					return;
				}
				if ((bool)base.characterBody)
				{
					base.characterBody.isSprinting = true;
				}
				if ((bool)base.skillLocator.special && base.inputBank.skill4.down)
				{
					base.skillLocator.special.ExecuteIfReady();
				}
				UpdateDirection();
				if (!inHitPause)
				{
					if ((bool)base.characterDirection)
					{
						base.characterDirection.moveVector = idealDirection;
						if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision)
						{
							base.characterMotor.rootMotion += GetIdealVelocity() * GetDeltaTime();
						}
					}
					attack.damage = damageStat * (chargeDamageCoefficient * GetDamageBoostFromSpeed());
					if (!attack.Fire(victimsStruck))
					{
						return;
					}
					Util.PlaySound(impactSoundString, base.gameObject);
					inHitPause = true;
					hitPauseTimer = hitPauseDuration;
					AddRecoil(-0.5f * recoilAmplitude, -0.5f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude);
					PlayAnimation("Gesture, Additive", BoxModeImpactStateHash, BoxModeImpactParamHash, hitPauseDuration);
					for (int i = 0; i < victimsStruck.Count; i++)
					{
						float num = 0f;
						HurtBox hurtBox = victimsStruck[i];
						if (!hurtBox.healthComponent)
						{
							continue;
						}
						CharacterMotor component = hurtBox.healthComponent.GetComponent<CharacterMotor>();
						if ((bool)component)
						{
							num = component.mass;
						}
						else
						{
							Rigidbody component2 = hurtBox.healthComponent.GetComponent<Rigidbody>();
							if ((bool)component2)
							{
								num = component2.mass;
							}
						}
						if (num >= massThresholdForKnockback)
						{
							outer.SetNextState(new ToolbotDashImpact
							{
								victimHealthComponent = hurtBox.healthComponent,
								idealDirection = idealDirection,
								damageBoostFromSpeed = GetDamageBoostFromSpeed(),
								isCrit = attack.isCrit
							});
							break;
						}
					}
				}
				else
				{
					base.characterMotor.velocity = UnityEngine.Vector3.zero;
					hitPauseTimer -= GetDeltaTime();
					if (hitPauseTimer < 0f)
					{
						inHitPause = false;
					}
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class ToolbotDashImpact : BaseState
	{
		public HealthComponent victimHealthComponent;

		public UnityEngine.Vector3 idealDirection;

		public float damageBoostFromSpeed;

		public bool isCrit;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				if ((bool)victimHealthComponent)
				{
					DamageInfo damageInfo = new DamageInfo
					{
						attacker = base.gameObject,
						damage = damageStat * ToolbotDash.knockbackDamageCoefficient * damageBoostFromSpeed,
						crit = isCrit,
						procCoefficient = 1f,
						damageColorIndex = DamageColorIndex.Item,
						damageType = DamageType.Stun1s,
						position = base.characterBody.corePosition
					};
					victimHealthComponent.TakeDamage(damageInfo);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, victimHealthComponent.gameObject);
					GlobalEventManager.instance.OnHitAll(damageInfo, victimHealthComponent.gameObject);
				}
				base.healthComponent.TakeDamageForce(idealDirection * (0f - ToolbotDash.knockbackForce), alwaysApply: true);
			}
			if (base.isAuthority)
			{
				AddRecoil(-0.5f * ToolbotDash.recoilAmplitude * 3f, -0.5f * ToolbotDash.recoilAmplitude * 3f, -0.5f * ToolbotDash.recoilAmplitude * 8f, 0.5f * ToolbotDash.recoilAmplitude * 3f);
				EffectManager.SimpleImpactEffect(ToolbotDash.knockbackEffectPrefab, base.characterBody.corePosition, base.characterDirection.forward, transmit: true);
				outer.SetNextStateToMain();
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(victimHealthComponent ? victimHealthComponent.gameObject : null);
			writer.Write(idealDirection);
			writer.Write(damageBoostFromSpeed);
			writer.Write(isCrit);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			GameObject gameObject = reader.ReadGameObject();
			victimHealthComponent = (gameObject ? gameObject.GetComponent<HealthComponent>() : null);
			idealDirection = reader.ReadVector3();
			damageBoostFromSpeed = reader.ReadSingle();
			isCrit = reader.ReadBoolean();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class DroneProjectileInFlight : BaseState
	{
		private ProjectileImpactEventCaller impactEventCaller;

		private ProjectileSimple projectileSimple;

		private ProjectileFuse projectileFuse;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				impactEventCaller = GetComponent<ProjectileImpactEventCaller>();
				if ((bool)impactEventCaller)
				{
					impactEventCaller.impactEvent.AddListener(OnImpact);
				}
				projectileSimple = GetComponent<ProjectileSimple>();
				projectileFuse = GetComponent<ProjectileFuse>();
				if ((bool)projectileFuse)
				{
					projectileFuse.onFuse.AddListener(OnFuse);
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)impactEventCaller)
			{
				impactEventCaller.impactEvent.RemoveListener(OnImpact);
			}
			if ((bool)projectileFuse)
			{
				projectileFuse.onFuse.RemoveListener(OnFuse);
			}
			base.OnEnter();
		}

		private void OnImpact(ProjectileImpactInfo projectileImpactInfo)
		{
			Advance();
		}

		private void OnFuse()
		{
			Advance();
		}

		private void Advance()
		{
			if (NetworkServer.active)
			{
				if ((bool)projectileSimple)
				{
					projectileSimple.velocity = 0f;
					projectileSimple.enabled = false;
				}
				if ((bool)base.rigidbody)
				{
					base.rigidbody.velocity = new UnityEngine.Vector3(0f, Trajectory.CalculateInitialYSpeedForFlightDuration(DroneProjectilePrepHover.duration), 0f);
				}
			}
			if (base.isAuthority)
			{
				outer.SetNextState(new DroneProjectilePrepHover());
			}
		}
	}
	public class DroneProjectilePrepHover : BaseState
	{
		public static float duration;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.age >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class DroneProjectileHover : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public int pulseCount = 3;

		[SerializeField]
		public float pulseRadius = 7f;

		protected TeamFilter teamFilter;

		protected float interval;

		protected int pulses;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.rigidbody)
			{
				base.rigidbody.velocity = UnityEngine.Vector3.zero;
				base.rigidbody.useGravity = false;
			}
			if (NetworkServer.active && (bool)base.projectileController)
			{
				teamFilter = base.projectileController.teamFilter;
			}
			interval = duration / (float)(pulseCount + 1);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				if (base.age >= duration)
				{
					EntityState.Destroy(base.gameObject);
				}
				else if (base.age >= interval * (float)(pulses + 1))
				{
					pulses++;
					Pulse();
				}
			}
		}

		protected virtual void Pulse()
		{
		}
	}
	public class DroneProjectileHoverStun : DroneProjectileHover
	{
		protected override void Pulse()
		{
			BlastAttack blastAttack = new BlastAttack
			{
				baseDamage = 0f,
				baseForce = 0f,
				attacker = (base.projectileController ? base.projectileController.owner : null),
				inflictor = base.gameObject,
				bonusForce = UnityEngine.Vector3.zero,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				crit = false,
				damageColorIndex = DamageColorIndex.Default,
				damageType = DamageType.Stun1s,
				falloffModel = BlastAttack.FalloffModel.None,
				procChainMask = default(ProcChainMask),
				position = base.transform.position,
				procCoefficient = 0f,
				teamIndex = (base.projectileController ? base.projectileController.teamFilter.teamIndex : TeamIndex.None),
				radius = pulseRadius
			};
			blastAttack.Fire();
			EffectData effectData = new EffectData();
			effectData.origin = blastAttack.position;
			effectData.scale = blastAttack.radius;
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/ExplosionVFX"), effectData, transmit: true);
		}
	}
	public class DroneProjectileHoverHeal : DroneProjectileHover
	{
		public static float healPointsCoefficient;

		public static float healFraction;

		protected override void Pulse()
		{
			float num = 1f;
			ProjectileDamage component = GetComponent<ProjectileDamage>();
			if ((bool)component)
			{
				num = component.damage;
			}
			HealOccupants(pulseRadius, healPointsCoefficient * num, healFraction);
			EffectData effectData = new EffectData();
			effectData.origin = base.transform.position;
			effectData.scale = pulseRadius;
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/ExplosionVFX"), effectData, transmit: true);
		}

		private static HealthComponent SelectHealthComponent(Collider collider)
		{
			HurtBox component = collider.GetComponent<HurtBox>();
			if ((bool)component && (bool)component.healthComponent)
			{
				return component.healthComponent;
			}
			return null;
		}

		private void HealOccupants(float radius, float healPoints, float healFraction)
		{
			Collider[] colliders;
			int num = HGPhysics.OverlapSphere(out colliders, base.transform.position, radius, LayerIndex.entityPrecise.mask);
			TeamIndex teamIndex = (teamFilter ? teamFilter.teamIndex : TeamIndex.None);
			for (int i = 0; i < num; i++)
			{
				HurtBox component = colliders[i].GetComponent<HurtBox>();
				if (!component || !component.healthComponent)
				{
					continue;
				}
				HealthComponent healthComponent = component.healthComponent;
				if (healthComponent.body.teamComponent.teamIndex == teamIndex)
				{
					float num2 = healPoints + healthComponent.fullHealth * healFraction;
					if (num2 > 0f)
					{
						healthComponent.Heal(num2, default(ProcChainMask));
					}
				}
			}
			HGPhysics.ReturnResults(colliders);
		}
	}
	public abstract class ToolbotDualWieldBase : GenericCharacterMain, ISkillState
	{
		public static BuffDef penaltyBuff;

		public static BuffDef bonusBuff;

		public static SkillDef inertSkillDef;

		public static SkillDef cancelSkillDef;

		public static CharacterCameraParams cameraParams;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public bool applyPenaltyBuff = true;

		[SerializeField]
		public bool applyBonusBuff = true;

		[SerializeField]
		public bool applyCameraAimMode = true;

		private GenericSkill specialSlot;

		private bool allowPrimarySkills;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle;

		private static int isDualWieldingParamHash = Animator.StringToHash("isDualWielding");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static GenericSkill.StateMachineResolver offhandStateMachineResolverDelegate = OffhandStateMachineResolver;

		public GenericSkill activatorSkillSlot { get; set; }

		protected GenericSkill primary1Slot { get; private set; }

		protected GenericSkill primary2Slot { get; private set; }

		protected virtual bool shouldAllowPrimarySkills => false;

		public override void OnEnter()
		{
			base.OnEnter();
			allowPrimarySkills = shouldAllowPrimarySkills;
			if (NetworkServer.active && (bool)base.characterBody)
			{
				if ((bool)penaltyBuff && applyPenaltyBuff)
				{
					base.characterBody.AddBuff(penaltyBuff);
				}
				if ((bool)bonusBuff && applyBonusBuff)
				{
					base.characterBody.AddBuff(bonusBuff);
				}
			}
			if ((bool)base.skillLocator)
			{
				primary1Slot = base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary1");
				primary2Slot = base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary2");
				specialSlot = base.skillLocator.FindSkillByFamilyName("ToolbotBodySpecialFamily");
				if (!allowPrimarySkills)
				{
					if ((object)inertSkillDef != null)
					{
						if ((bool)base.skillLocator.primary)
						{
							base.skillLocator.primary.SetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual);
						}
						if ((bool)base.skillLocator.secondary)
						{
							base.skillLocator.secondary.SetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual);
						}
					}
				}
				else if ((bool)base.skillLocator.secondary && (bool)primary2Slot)
				{
					base.skillLocator.secondary.SetSkillOverride(this, primary2Slot.skillDef, GenericSkill.SkillOverridePriority.Contextual);
					base.skillLocator.secondary.customStateMachineResolver += offhandStateMachineResolverDelegate;
				}
				if ((bool)specialSlot && (object)cancelSkillDef != null)
				{
					specialSlot.SetSkillOverride(this, cancelSkillDef, GenericSkill.SkillOverridePriority.Contextual);
				}
			}
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			if ((bool)base.modelAnimator)
			{
				base.modelAnimator.SetBool(isDualWieldingParamHash, value: true);
			}
			if ((bool)base.cameraTargetParams && applyCameraAimMode)
			{
				cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest
				{
					cameraParamsData = cameraParams.data,
					priority = 1f
				});
			}
			StopSkills();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(1f);
				if (base.isAuthority && (base.characterBody.isSprinting || base.characterBody.HasBuff(DLC2Content.Buffs.DisableAllSkills.buffIndex)))
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)specialSlot && (object)cancelSkillDef != null)
			{
				specialSlot.UnsetSkillOverride(this, cancelSkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			if (!allowPrimarySkills)
			{
				if ((object)inertSkillDef != null)
				{
					if ((bool)base.skillLocator.secondary)
					{
						base.skillLocator.secondary.UnsetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual);
					}
					if ((bool)base.skillLocator.primary)
					{
						base.skillLocator.primary.UnsetSkillOverride(this, inertSkillDef, GenericSkill.SkillOverridePriority.Contextual);
					}
				}
			}
			else if ((bool)base.skillLocator.secondary && (bool)primary2Slot)
			{
				base.skillLocator.secondary.UnsetSkillOverride(this, primary2Slot.skillDef, GenericSkill.SkillOverridePriority.Contextual);
				base.skillLocator.secondary.customStateMachineResolver -= offhandStateMachineResolverDelegate;
			}
			if (NetworkServer.active && (bool)base.characterBody)
			{
				if ((bool)bonusBuff && applyBonusBuff)
				{
					base.characterBody.RemoveBuff(bonusBuff);
				}
				if ((bool)penaltyBuff && applyPenaltyBuff)
				{
					base.characterBody.RemoveBuff(penaltyBuff);
				}
			}
			crosshairOverrideRequest?.Dispose();
			if ((bool)base.modelAnimator)
			{
				base.modelAnimator.SetBool(isDualWieldingParamHash, value: false);
			}
			PlayAnimation("DualWield, Additive", EmptyStateHash);
			if ((bool)base.cameraTargetParams && cameraParamsOverrideHandle.isValid)
			{
				cameraParamsOverrideHandle = base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle);
			}
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			this.Serialize(base.skillLocator, writer);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			this.Deserialize(base.skillLocator, reader);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		private static void OffhandStateMachineResolver(GenericSkill genericSkill, SkillDef skillDef, ref EntityStateMachine targetStateMachine)
		{
			if (string.Equals(skillDef.activationStateMachineName, "Weapon", StringComparison.Ordinal))
			{
				targetStateMachine = EntityStateMachine.FindByCustomName(genericSkill.gameObject, "Weapon2");
			}
		}

		protected void StopSkills()
		{
			if (base.isAuthority)
			{
				EntityStateMachine.FindByCustomName(base.gameObject, "Weapon")?.SetNextStateToMain();
				EntityStateMachine.FindByCustomName(base.gameObject, "Weapon2")?.SetNextStateToMain();
			}
		}
	}
	public class ToolbotDualWield : ToolbotDualWieldBase
	{
		public static string animLayer;

		public static string animStateName;

		public static GameObject coverPrefab;

		public static GameObject coverEjectEffect;

		public static string enterSoundString;

		public static string exitSoundString;

		public static string startLoopSoundString;

		public static string stopLoopSoundString;

		private bool keyReleased;

		private GameObject coverLeftInstance;

		private GameObject coverRightInstance;

		private uint loopSoundID;

		protected override bool shouldAllowPrimarySkills => true;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animLayer, animStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			loopSoundID = Util.PlaySound(startLoopSoundString, base.gameObject);
			if ((bool)coverPrefab)
			{
				Transform transform = FindModelChild("LowerArmL");
				Transform transform2 = FindModelChild("LowerArmR");
				if ((bool)transform)
				{
					coverLeftInstance = UnityEngine.Object.Instantiate(coverPrefab, transform.position, transform.rotation, transform);
				}
				if ((bool)transform2)
				{
					coverRightInstance = UnityEngine.Object.Instantiate(coverPrefab, transform2.position, transform2.rotation, transform2);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				bool flag = this.IsKeyDownAuthority(base.skillLocator, base.inputBank);
				keyReleased |= !flag;
				if (keyReleased && flag)
				{
					outer.SetNextState(new ToolbotDualWieldEnd
					{
						activatorSkillSlot = base.activatorSkillSlot
					});
				}
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(exitSoundString, base.gameObject);
			Util.PlaySound(stopLoopSoundString, base.gameObject);
			AkSoundEngine.StopPlayingID(loopSoundID);
			if ((bool)coverLeftInstance)
			{
				EffectManager.SimpleMuzzleFlash(coverEjectEffect, base.gameObject, "LowerArmL", transmit: false);
				EntityState.Destroy(coverLeftInstance);
			}
			if ((bool)coverRightInstance)
			{
				EffectManager.SimpleMuzzleFlash(coverEjectEffect, base.gameObject, "LowerArmR", transmit: false);
				EntityState.Destroy(coverRightInstance);
			}
			base.OnExit();
		}
	}
	public class ToolbotDualWieldStart : ToolbotDualWieldBase
	{
		public static float baseDuration;

		public static string animLayer;

		public static string animStateName;

		public static string animPlaybackRateParam;

		public static string enterSfx;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animLayer, animStateName, animPlaybackRateParam, duration);
			Util.PlaySound(enterSfx, base.gameObject);
			if (base.isAuthority && (bool)base.characterMotor && !base.characterMotor.isGrounded)
			{
				base.characterMotor.disableAirControlUntilCollision = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new ToolbotDualWield
				{
					activatorSkillSlot = base.activatorSkillSlot
				});
			}
		}
	}
	public class ToolbotDualWieldEnd : ToolbotDualWieldBase
	{
		public static float baseDuration;

		public static string animLayer;

		public static string animStateName;

		public static string animPlaybackRateParam;

		public static string enterSfx;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animLayer, animStateName, animPlaybackRateParam, duration);
			Util.PlaySound(enterSfx, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public class ToolbotStanceBase : BaseState
	{
		protected enum WeaponStance
		{
			None = -1,
			Nailgun,
			Spear,
			Grenade,
			Buzzsaw
		}

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		public static GameObject emptyCrosshairPrefab;

		public static AnimationCurve emptyCrosshairSpreadCurve;

		protected RoR2.Inventory inventory;

		public Type swapStateType;

		protected void SetPrimarySkill()
		{
			base.skillLocator.primary = GetCurrentPrimarySkill();
		}

		protected void SetSecondarySkill(string skillName)
		{
			if ((bool)base.skillLocator)
			{
				base.skillLocator.secondary = base.skillLocator.FindSkill(skillName);
			}
		}

		protected string GetSkillSlotStance(GenericSkill skillSlot)
		{
			return (skillSlot.skillDef as ToolbotWeaponSkillDef)?.stanceName ?? string.Empty;
		}

		protected GenericSkill GetPrimarySkill1()
		{
			return base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary1");
		}

		protected GenericSkill GetPrimarySkill2()
		{
			return base.skillLocator.FindSkillByFamilyName("ToolbotBodyPrimary2");
		}

		protected virtual GenericSkill GetCurrentPrimarySkill()
		{
			return null;
		}

		protected void UpdateCrosshairParameters(ToolbotWeaponSkillDef weaponSkillDef)
		{
			GameObject crosshairPrefab = emptyCrosshairPrefab;
			AnimationCurve crosshairSpreadCurve = emptyCrosshairSpreadCurve;
			if ((bool)weaponSkillDef)
			{
				crosshairPrefab = weaponSkillDef.crosshairPrefab;
				crosshairSpreadCurve = weaponSkillDef.crosshairSpreadCurve;
			}
			crosshairOverrideRequest?.Dispose();
			crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill);
			base.characterBody.spreadBloomCurve = crosshairSpreadCurve;
		}

		protected void SetEquipmentSlot(byte i)
		{
			if ((bool)inventory)
			{
				inventory.SetActiveEquipmentSlot(i);
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			inventory = (base.characterBody ? base.characterBody.inventory : null);
			SetPrimarySkill();
			ToolbotWeaponSkillDef toolbotWeaponSkillDef = GetCurrentPrimarySkill()?.skillDef as ToolbotWeaponSkillDef;
			if ((bool)toolbotWeaponSkillDef)
			{
				SendWeaponStanceToAnimator(toolbotWeaponSkillDef);
				PlayCrossfade("Gesture, Additive", toolbotWeaponSkillDef.enterGestureAnimState, 0.2f);
			}
			UpdateCrosshairParameters(toolbotWeaponSkillDef);
		}

		public override void OnExit()
		{
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}

		protected void SendWeaponStanceToAnimator(ToolbotWeaponSkillDef weaponSkillDef)
		{
			if ((bool)weaponSkillDef)
			{
				GetModelAnimator().SetInteger("weaponStance", weaponSkillDef.animatorWeaponIndex);
			}
		}

		protected static WeaponStance GetSkillStance(GenericSkill skillSlot)
		{
			return (skillSlot?.skillDef as ToolbotWeaponSkillDef)?.stanceName switch
			{
				"Nailgun" => WeaponStance.Nailgun, 
				"Spear" => WeaponStance.Spear, 
				"Grenade" => WeaponStance.Grenade, 
				"Buzzsaw" => WeaponStance.Buzzsaw, 
				_ => WeaponStance.None, 
			};
		}
	}
	public class ToolbotStanceA : ToolbotStanceBase
	{
		public override void OnEnter()
		{
			base.OnEnter();
			swapStateType = typeof(ToolbotStanceB);
			if (NetworkServer.active)
			{
				SetEquipmentSlot(0);
			}
		}

		protected override GenericSkill GetCurrentPrimarySkill()
		{
			return GetPrimarySkill1();
		}
	}
	public class ToolbotStanceB : ToolbotStanceBase
	{
		public override void OnEnter()
		{
			base.OnEnter();
			swapStateType = typeof(ToolbotStanceA);
			if (NetworkServer.active)
			{
				SetEquipmentSlot(1);
			}
		}

		protected override GenericSkill GetCurrentPrimarySkill()
		{
			return GetPrimarySkill2();
		}
	}
	public class ToolbotStanceSwap : ToolbotStanceBase
	{
		[SerializeField]
		private float baseDuration = 0.5f;

		private Run.FixedTimeStamp endTime;

		public Type nextStanceState;

		public Type previousStanceState;

		public override void OnEnter()
		{
			base.OnEnter();
			float num = baseDuration / attackSpeedStat;
			endTime = Run.FixedTimeStamp.now + num;
			GenericSkill a = GetPrimarySkill1();
			GenericSkill b = GetPrimarySkill2();
			if (previousStanceState != typeof(ToolbotStanceA))
			{
				Util.Swap(ref a, ref b);
			}
			if ((bool)b && b.skillDef is ToolbotWeaponSkillDef toolbotWeaponSkillDef)
			{
				SendWeaponStanceToAnimator(toolbotWeaponSkillDef);
				Util.PlaySound(toolbotWeaponSkillDef.entrySound, base.gameObject);
			}
			if ((bool)a && a.skillDef is ToolbotWeaponSkillDef toolbotWeaponSkillDef2)
			{
				PlayAnimation("Stance, Additive", toolbotWeaponSkillDef2.exitAnimState, "StanceSwap.playbackRate", num * 0.5f);
				PlayAnimation("Gesture, Additive", toolbotWeaponSkillDef2.exitGestureAnimState);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && endTime.hasPassed)
			{
				outer.SetNextState(EntityStateCatalog.InstantiateState(nextStanceState));
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			EntityStateIndex stateIndex = EntityStateCatalog.GetStateIndex(previousStanceState);
			EntityStateIndex stateIndex2 = EntityStateCatalog.GetStateIndex(nextStanceState);
			writer.Write(stateIndex);
			writer.Write(stateIndex2);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			EntityStateIndex entityStateIndex = reader.ReadEntityStateIndex();
			EntityStateIndex entityStateIndex2 = reader.ReadEntityStateIndex();
			previousStanceState = EntityStateCatalog.GetStateType(entityStateIndex);
			nextStanceState = EntityStateCatalog.GetStateType(entityStateIndex2);
		}
	}
	public class StartToolbotStanceSwap : BaseState
	{
		private EntityStateMachine stanceStateMachine;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				stanceStateMachine = base.gameObject.GetComponents<EntityStateMachine>().FirstOrDefault((EntityStateMachine c) => c.customName == "Stance");
				if (stanceStateMachine?.state is ToolbotStanceBase toolbotStanceBase && toolbotStanceBase.swapStateType != null)
				{
					stanceStateMachine.SetNextState(new ToolbotStanceSwap
					{
						previousStanceState = toolbotStanceBase.GetType(),
						nextStanceState = toolbotStanceBase.swapStateType
					});
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			outer.SetNextStateToMain();
		}
	}
}
namespace EntityStates.TimedChest
{
	public class Opening : BaseState
	{
		public static float delayUntilUnlockAchievement;

		private bool hasGrantedAchievement;

		private static int OpeningStateHash = Animator.StringToHash("Opening");

		public static event Action onOpened;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", OpeningStateHash);
			TimedChestController component = GetComponent<TimedChestController>();
			if ((bool)component)
			{
				component.purchased = true;
			}
			if ((bool)base.sfxLocator)
			{
				Util.PlaySound(base.sfxLocator.openSound, base.gameObject);
			}
			SetPingable(value: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= delayUntilUnlockAchievement && !hasGrantedAchievement)
			{
				Opening.onOpened?.Invoke();
				hasGrantedAchievement = true;
				GenericPickupController componentInChildren = base.gameObject.GetComponentInChildren<GenericPickupController>();
				if ((bool)componentInChildren)
				{
					componentInChildren.enabled = true;
				}
			}
		}
	}
}
namespace EntityStates.TeleporterHealNovaController
{
	public class TeleporterHealNovaWindup : BaseState
	{
		public static GameObject chargeEffectPrefab;

		public static float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleEffect(chargeEffectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && duration <= base.fixedAge)
			{
				outer.SetNextState(new TeleporterHealNovaPulse());
			}
		}
	}
	public class TeleporterHealNovaPulse : BaseState
	{
		private class HealPulse
		{
			private readonly List<HealthComponent> healedTargets = new List<HealthComponent>();

			private readonly SphereSearch sphereSearch;

			private float rate;

			private float t;

			private float finalRadius;

			private float healFractionValue;

			private TeamMask teamMask;

			private readonly List<HurtBox> hurtBoxesList = new List<HurtBox>();

			public bool isFinished => t >= 1f;

			public HealPulse(UnityEngine.Vector3 origin, float finalRadius, float healFractionValue, float duration, TeamIndex teamIndex)
			{
				sphereSearch = new SphereSearch
				{
					mask = LayerIndex.entityPrecise.mask,
					origin = origin,
					queryTriggerInteraction = QueryTriggerInteraction.Collide,
					radius = 0f
				};
				this.finalRadius = finalRadius;
				this.healFractionValue = healFractionValue;
				rate = 1f / duration;
				teamMask = default(TeamMask);
				teamMask.AddTeam(teamIndex);
			}

			public void Update(float deltaTime)
			{
				t += rate * deltaTime;
				t = ((t > 1f) ? 1f : t);
				sphereSearch.radius = finalRadius * novaRadiusCurve.Evaluate(t);
				sphereSearch.RefreshCandidates().FilterCandidatesByHurtBoxTeam(teamMask).FilterCandidatesByDistinctHurtBoxEntities()
					.GetHurtBoxes(hurtBoxesList);
				int i = 0;
				for (int count = hurtBoxesList.Count; i < count; i++)
				{
					HealthComponent healthComponent = hurtBoxesList[i].healthComponent;
					if (!healedTargets.Contains(healthComponent))
					{
						healedTargets.Add(healthComponent);
						HealTarget(healthComponent);
					}
				}
				hurtBoxesList.Clear();
			}

			private void HealTarget(HealthComponent target)
			{
				target.HealFraction(healFractionValue, default(ProcChainMask));
				Util.PlaySound("Play_item_proc_TPhealingNova_hitPlayer", target.gameObject);
			}
		}

		public static AnimationCurve novaRadiusCurve;

		public static float duration;

		private Transform effectTransform;

		private HealPulse healPulse;

		private float radius;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.transform.parent)
			{
				HoldoutZoneController componentInParent = base.gameObject.GetComponentInParent<HoldoutZoneController>();
				if ((bool)componentInParent)
				{
					radius = componentInParent.currentRadius;
				}
			}
			TeamFilter component = GetComponent<TeamFilter>();
			TeamIndex teamIndex = (component ? component.teamIndex : TeamIndex.None);
			if (NetworkServer.active)
			{
				healPulse = new HealPulse(base.transform.position, radius, 0.5f, duration, teamIndex);
			}
			effectTransform = base.transform.Find("PulseEffect");
			if ((bool)effectTransform)
			{
				effectTransform.gameObject.SetActive(value: true);
			}
		}

		public override void OnExit()
		{
			if ((bool)effectTransform)
			{
				effectTransform.gameObject.SetActive(value: false);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				healPulse.Update(GetDeltaTime());
				if (duration < base.fixedAge)
				{
					EntityState.Destroy(outer.gameObject);
				}
			}
		}

		public override void Update()
		{
			if ((bool)effectTransform)
			{
				float num = radius * novaRadiusCurve.Evaluate(base.fixedAge / duration);
				effectTransform.localScale = new UnityEngine.Vector3(num, num, num);
			}
		}
	}
	public class TeleporterHealNovaGeneratorMain : BaseState
	{
		public static GameObject pulsePrefab;

		[SerializeField]
		public float minSecondsBetweenPulses;

		private HoldoutZoneController holdoutZone;

		private TeamIndex teamIndex;

		private float previousPulseFraction;

		private int pulseCount;

		private float secondsUntilPulseAvailable;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform parent = base.transform.parent;
			if ((bool)parent)
			{
				holdoutZone = parent.GetComponentInParent<HoldoutZoneController>();
				previousPulseFraction = GetCurrentTeleporterChargeFraction();
			}
			TeamFilter component = GetComponent<TeamFilter>();
			teamIndex = (component ? component.teamIndex : TeamIndex.None);
		}

		private float GetCurrentTeleporterChargeFraction()
		{
			return holdoutZone.charge;
		}

		public override void FixedUpdate()
		{
			if (!NetworkServer.active || !(GetDeltaTime() > 0f))
			{
				return;
			}
			if (!holdoutZone || holdoutZone.charge >= 1f)
			{
				EntityState.Destroy(outer.gameObject);
				return;
			}
			if (secondsUntilPulseAvailable > 0f)
			{
				secondsUntilPulseAvailable -= GetDeltaTime();
				return;
			}
			pulseCount = CalculatePulseCount(teamIndex);
			float num = CalculateNextPulseFraction(pulseCount, previousPulseFraction);
			float currentTeleporterChargeFraction = GetCurrentTeleporterChargeFraction();
			if (num < currentTeleporterChargeFraction)
			{
				Pulse();
				previousPulseFraction = num;
				secondsUntilPulseAvailable = minSecondsBetweenPulses;
			}
		}

		private static int CalculatePulseCount(TeamIndex teamIndex)
		{
			int num = 0;
			ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CharacterMaster characterMaster = readOnlyInstancesList[i];
				if (characterMaster.teamIndex == teamIndex)
				{
					num += characterMaster.inventory.GetItemCount(RoR2Content.Items.TPHealingNova);
				}
			}
			return num;
		}

		private static float CalculateNextPulseFraction(int pulseCount, float previousPulseFraction)
		{
			float num = 1f / (float)(pulseCount + 1);
			for (int i = 1; i <= pulseCount; i++)
			{
				float num2 = (float)i * num;
				if (!(num2 <= previousPulseFraction))
				{
					return num2;
				}
			}
			return 1f;
		}

		protected void Pulse()
		{
			GameObject obj = UnityEngine.Object.Instantiate(pulsePrefab, base.transform.position, base.transform.rotation, base.transform.parent);
			obj.GetComponent<TeamFilter>().teamIndex = teamIndex;
			NetworkServer.Spawn(obj);
		}
	}
}
namespace EntityStates.FalseSonMeteorPod
{
	public class Descent : EntityStates.SurvivorPod.Descent
	{
		public static GameObject effectPrefab;

		protected override void TransitionIntoNextState()
		{
			base.TransitionIntoNextState();
		}

		public override void OnExit()
		{
			VehicleSeat component = GetComponent<VehicleSeat>();
			if ((bool)component)
			{
				component.EjectPassenger();
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "Base", transmit: true);
			}
			if (NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.RoboCratePod
{
	public class Descent : EntityStates.SurvivorPod.Descent
	{
		public static GameObject effectPrefab;

		protected override void TransitionIntoNextState()
		{
			base.TransitionIntoNextState();
			EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "Base", transmit: true);
		}

		public override void OnExit()
		{
			VehicleSeat component = GetComponent<VehicleSeat>();
			if ((bool)component)
			{
				component.EjectPassenger();
			}
			if (NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.SurvivorPod
{
	public class Descent : SurvivorPodBaseState
	{
		public static float failsafeTimer = 30f;

		private ShakeEmitter shakeEmitter;

		private static int InitialSpawnStateHash = Animator.StringToHash("InitialSpawn");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", InitialSpawnStateHash);
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("Travel");
				if ((bool)transform)
				{
					shakeEmitter = transform.gameObject.AddComponent<ShakeEmitter>();
					shakeEmitter.wave = new Wave
					{
						amplitude = 1f,
						frequency = 180f,
						cycleOffset = 0f
					};
					shakeEmitter.duration = 10000f;
					shakeEmitter.radius = 400f;
					shakeEmitter.amplitudeTimeDecay = false;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		protected void AuthorityFixedUpdate()
		{
			if (base.fixedAge > failsafeTimer)
			{
				UnityEngine.Debug.LogError($"Descent timeout {failsafeTimer}...");
				TransitionIntoNextState();
				return;
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Base");
				if (layerIndex != -1 && modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("Idle"))
				{
					TransitionIntoNextState();
				}
			}
		}

		protected virtual void TransitionIntoNextState()
		{
			outer.SetNextState(new Landed());
		}

		public override void OnExit()
		{
			EntityState.Destroy(shakeEmitter);
			base.OnExit();
		}
	}
	public class Landed : SurvivorPodBaseState
	{
		private static int IdleStateHash = Animator.StringToHash("Idle");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", IdleStateHash);
			Util.PlaySound("Play_UI_podSteamLoop", base.gameObject);
			base.vehicleSeat.handleVehicleExitRequestServer.AddCallback(HandleVehicleExitRequest);
		}

		public override void FixedUpdate()
		{
			if (base.fixedAge > 0f)
			{
				base.survivorPodController.exitAllowed = true;
			}
			base.FixedUpdate();
		}

		private void HandleVehicleExitRequest(GameObject gameObject, ref bool? result)
		{
			base.survivorPodController.exitAllowed = false;
			outer.SetNextState(new PreRelease());
			result = true;
		}

		public override void OnExit()
		{
			base.vehicleSeat.handleVehicleExitRequestServer.RemoveCallback(HandleVehicleExitRequest);
			base.survivorPodController.exitAllowed = false;
			Util.PlaySound("Stop_UI_podSteamLoop", base.gameObject);
		}
	}
	public class PreRelease : SurvivorPodBaseState
	{
		private static int IdleToReleaseStateHash = Animator.StringToHash("IdleToRelease");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", IdleToReleaseStateHash);
			Util.PlaySound("Play_UI_podBlastDoorOpen", base.gameObject);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				modelTransform.GetComponent<ChildLocator>().FindChild("InitialExhaustFX").gameObject.SetActive(value: true);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Base");
				if (layerIndex != -1 && modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("IdleToReleaseFinished"))
				{
					outer.SetNextState(new Release());
				}
			}
		}
	}
	public class Release : SurvivorPodBaseState
	{
		public static float ejectionSpeed = 20f;

		private static int ReleaseStateHash = Animator.StringToHash("Release");

		public static event Action<Release, CharacterBody> onEnter;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", ReleaseStateHash);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				component.FindChild("Door").gameObject.SetActive(value: false);
				component.FindChild("ReleaseExhaustFX").gameObject.SetActive(value: true);
			}
			Release.onEnter?.Invoke(this, base.vehicleSeat?.currentPassengerBody);
			if ((bool)base.survivorPodController && NetworkServer.active && (bool)base.vehicleSeat && (bool)base.vehicleSeat.currentPassengerBody)
			{
				base.vehicleSeat.EjectPassenger(base.vehicleSeat.currentPassengerBody.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (!base.vehicleSeat || !base.vehicleSeat.currentPassengerBody))
			{
				outer.SetNextState(new ReleaseFinished());
			}
		}
	}
	public class ReleaseFinished : SurvivorPodBaseState
	{
		private static int ReleaseStateHash = Animator.StringToHash("Release");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", ReleaseStateHash);
		}
	}
	public abstract class SurvivorPodBaseState : EntityState
	{
		protected SurvivorPodController survivorPodController { get; private set; }

		protected VehicleSeat vehicleSeat { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			survivorPodController = GetComponent<SurvivorPodController>();
			vehicleSeat = survivorPodController?.vehicleSeat;
			if (!survivorPodController && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.SurvivorPod.BatteryPanel
{
	public class BaseBatteryPanelState : BaseState
	{
		protected struct PodInfo
		{
			public GameObject podObject;

			public Animator podAnimator;
		}

		protected PodInfo podInfo;

		public override void OnEnter()
		{
			base.OnEnter();
			SetPodObject(base.gameObject.GetComponentInParent<VehicleSeat>()?.gameObject);
		}

		private void SetPodObject(GameObject podObject)
		{
			podInfo = default(PodInfo);
			if (!podObject)
			{
				return;
			}
			podInfo.podObject = podObject;
			ModelLocator component = podObject.GetComponent<ModelLocator>();
			if ((bool)component)
			{
				Transform modelTransform = component.modelTransform;
				if ((bool)modelTransform)
				{
					podInfo.podAnimator = modelTransform.GetComponent<Animator>();
				}
			}
		}

		protected void PlayPodAnimation(string layerName, string animationStateName, string playbackRateParam, float duration)
		{
			if ((bool)podInfo.podAnimator)
			{
				EntityState.PlayAnimationOnAnimator(podInfo.podAnimator, layerName, animationStateName, playbackRateParam, duration);
			}
		}

		protected void PlayPodAnimation(string layerName, string animationStateName)
		{
			if ((bool)podInfo.podAnimator)
			{
				EntityState.PlayAnimationOnAnimator(podInfo.podAnimator, layerName, animationStateName);
			}
		}

		protected void EnablePickup()
		{
			ChildLocator component = podInfo.podAnimator.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("BatteryAttachmentPoint");
			if (!transform)
			{
				return;
			}
			Transform transform2 = transform.Find("QuestVolatileBatteryWorldPickup(Clone)");
			if ((bool)transform2)
			{
				GenericPickupController component2 = transform2.GetComponent<GenericPickupController>();
				if ((bool)component2)
				{
					component2.enabled = true;
				}
			}
		}
	}
	public class Opening : BaseBatteryPanelState
	{
		public static float duration;

		public static string openSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayPodAnimation("Additive", "OpenPanel", "OpenPanel.playbackRate", duration);
			Util.PlaySound(openSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new Opened());
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class Opened : BaseBatteryPanelState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			PlayPodAnimation("Additive", "OpenPanelFinished");
			EnablePickup();
		}
	}
}
namespace EntityStates.Emote
{
	public class SurpriseState : EntityState
	{
		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				modelAnimator.Play("EmoteSurprise", layerIndex, 0f);
				modelAnimator.Update(0f);
				duration = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Squid
{
	public class SquidDeathState : GenericCharacterDeath
	{
		private static int DeathStateHash = Animator.StringToHash("Death");

		public static float duration = 0f;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", DeathStateHash);
		}
	}
}
namespace EntityStates.Squid.SquidWeapon
{
	public class FireSpine : BaseState
	{
		public static GameObject hitEffectPrefab;

		public static GameObject muzzleflashEffectPrefab;

		public static float damageCoefficient;

		public static float baseDuration = 2f;

		public static float procCoefficient = 1f;

		public static float forceScalar = 1f;

		private bool hasFiredArrow;

		private ChildLocator childLocator;

		private BullseyeSearch enemyFinder;

		private const float maxVisionDistance = float.PositiveInfinity;

		public bool fullVision = true;

		private float duration;

		private static int FireGooStateHash = Animator.StringToHash("FireGoo");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			GetAimRay();
			PlayAnimation("Gesture", FireGooStateHash);
			if (base.isAuthority)
			{
				FireOrbArrow();
			}
		}

		private void FireOrbArrow()
		{
			if (hasFiredArrow || !NetworkServer.active)
			{
				return;
			}
			Ray aimRay = GetAimRay();
			enemyFinder = new BullseyeSearch();
			enemyFinder.viewer = base.characterBody;
			enemyFinder.maxDistanceFilter = float.PositiveInfinity;
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.sortMode = BullseyeSearch.SortMode.Distance;
			enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
			enemyFinder.minDistanceFilter = 0f;
			enemyFinder.maxAngleFilter = (fullVision ? 180f : 90f);
			enemyFinder.filterByLoS = true;
			if ((bool)base.teamComponent)
			{
				enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			enemyFinder.RefreshCandidates();
			HurtBox hurtBox = enemyFinder.GetResults().FirstOrDefault();
			if ((bool)hurtBox)
			{
				UnityEngine.Vector3 vector = hurtBox.transform.position - GetAimRay().origin;
				aimRay.origin = GetAimRay().origin;
				aimRay.direction = vector;
				base.inputBank.aimDirection = vector;
				StartAimMode(aimRay);
				hasFiredArrow = true;
				SquidOrb squidOrb = new SquidOrb();
				squidOrb.forceScalar = forceScalar;
				squidOrb.damageValue = base.characterBody.damage * damageCoefficient;
				squidOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master);
				squidOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				squidOrb.attacker = base.gameObject;
				squidOrb.procCoefficient = procCoefficient;
				HurtBox hurtBox2 = hurtBox;
				if ((bool)hurtBox2)
				{
					Transform transform = base.characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("Muzzle");
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "Muzzle", transmit: true);
					squidOrb.origin = transform.position;
					squidOrb.target = hurtBox2;
					OrbManager.instance.AddOrb(squidOrb);
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Squid.DeathState
{
	public class DeathState : BaseState
	{
		public static float baseDuration;

		private float duration;

		private static int DeathStateHash = Animator.StringToHash("Death");

		public override void OnEnter()
		{
			duration = baseDuration;
			base.OnEnter();
			PlayAnimation("Body", DeathStateHash);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying && (bool)base.gameObject)
			{
				EntityState.Destroy(base.gameObject);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.SpectatorSkills
{
	public class LockOn : BaseSkillState
	{
		private UnityEngine.Vector3 targetPoint;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.inputBank.GetAimRaycast(float.PositiveInfinity, out var hitInfo))
			{
				targetPoint = hitInfo.point;
			}
			else
			{
				outer.SetNextStateToMain();
			}
			RoR2Application.onUpdate += LookAtTarget;
			RoR2Application.onLateUpdate += LookAtTarget;
		}

		public override void OnExit()
		{
			RoR2Application.onLateUpdate -= LookAtTarget;
			RoR2Application.onUpdate -= LookAtTarget;
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			if (base.isAuthority && !IsKeyDownAuthority())
			{
				outer.SetNextStateToMain();
			}
		}

		private void LookAtTarget()
		{
			ReadOnlyCollection<CameraRigController> readOnlyInstancesList = CameraRigController.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				_ = readOnlyInstancesList[i].target == base.gameObject;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.Sniper.SniperWeapon
{
	public class FireRifle : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float minChargeDamageCoefficient;

		public static float maxChargeDamageCoefficient;

		public static float minChargeForce;

		public static float maxChargeForce;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public static string attackSoundString;

		public static float recoilAmplitude;

		public static float spreadBloomValue = 0.3f;

		public static float interruptInterval = 0.2f;

		private float duration;

		private bool inputReleased;

		private static int FireShotgunStateHash = Animator.StringToHash("FireShotgun");

		private static int FireShotgunParamHash = Animator.StringToHash("FireShotgun.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			float num = 0f;
			if ((bool)base.skillLocator)
			{
				GenericSkill secondary = base.skillLocator.secondary;
				if ((bool)secondary)
				{
					EntityStateMachine stateMachine = secondary.stateMachine;
					if ((bool)stateMachine && stateMachine.state is ScopeSniper scopeSniper)
					{
						num = scopeSniper.charge;
						scopeSniper.charge = 0f;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude);
			duration = baseDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			Util.PlaySound(attackSoundString, base.gameObject);
			PlayAnimation("Gesture", FireShotgunStateHash, FireShotgunParamHash, duration * 1.1f);
			string muzzleName = "MuzzleShotgun";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = base.characterBody.spreadBloomAngle;
				bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u);
				bulletAttack.procCoefficient = 1f / (float)bulletCount;
				bulletAttack.damage = Mathf.LerpUnclamped(minChargeDamageCoefficient, maxChargeDamageCoefficient, num) * damageStat / (float)bulletCount;
				bulletAttack.force = Mathf.LerpUnclamped(minChargeForce, maxChargeForce, num);
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				if (num == 1f)
				{
					bulletAttack.stopperMask = LayerIndex.world.mask;
				}
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = 0f;
				bulletAttack.sniper = true;
				bulletAttack.Fire();
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.inputBank)
			{
				inputReleased |= !base.inputBank.skill1.down;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (inputReleased && base.fixedAge >= interruptInterval / attackSpeedStat)
			{
				return InterruptPriority.Any;
			}
			return InterruptPriority.Skill;
		}
	}
	public class Reload : BaseState
	{
		public static float baseDuration = 1f;

		public static float reloadTimeFraction = 0.75f;

		public static string soundString = "";

		private float duration;

		private float reloadTime;

		private Animator modelAnimator;

		private bool reloaded;

		private EntityStateMachine scopeStateMachine;

		private static int PrepBarrageStateHash = Animator.StringToHash("PrepBarrage");

		private static int PrepBarrageParamHash = Animator.StringToHash("PrepBarrage.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			reloadTime = duration * reloadTimeFraction;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", PrepBarrageStateHash, PrepBarrageParamHash, duration);
			}
			if ((bool)base.skillLocator)
			{
				GenericSkill secondary = base.skillLocator.secondary;
				if ((bool)secondary)
				{
					scopeStateMachine = secondary.stateMachine;
				}
			}
			if (base.isAuthority && (bool)scopeStateMachine)
			{
				scopeStateMachine.SetNextState(new LockSkill());
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!reloaded && base.fixedAge >= reloadTime)
			{
				if ((bool)base.skillLocator)
				{
					GenericSkill primary = base.skillLocator.primary;
					if ((bool)primary)
					{
						primary.Reset();
						Util.PlaySound(soundString, base.gameObject);
					}
				}
				reloaded = true;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (base.isAuthority && (bool)scopeStateMachine)
			{
				scopeStateMachine.SetNextStateToMain();
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.Sniper.Scope
{
	public class ScopeSniper : BaseState
	{
		public static float baseChargeDuration = 4f;

		public static GameObject crosshairPrefab;

		public float charge;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private GameObject laserPointerObject;

		private CameraTargetParams.AimRequest aimRequest;

		public override void OnEnter()
		{
			base.OnEnter();
			charge = 0f;
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.Slow50);
			}
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.FirstPerson);
				base.cameraTargetParams.fovOverride = 20f;
			}
			if ((bool)crosshairPrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill);
			}
			laserPointerObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/LaserPointerBeamEnd"));
			laserPointerObject.GetComponent<LaserPointerController>().source = base.inputBank;
		}

		public override void OnExit()
		{
			EntityState.Destroy(laserPointerObject);
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.Slow50);
			}
			aimRequest?.Dispose();
			if ((bool)base.cameraTargetParams)
			{
				base.cameraTargetParams.fovOverride = -1f;
			}
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			charge = Mathf.Min(charge + attackSpeedStat / baseChargeDuration * GetDeltaTime(), 1f);
			if (base.isAuthority && (!base.inputBank || !base.inputBank.skill2.down))
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.SiphonItem
{
	public class BaseSiphonItemState : BaseBodyAttachmentState
	{
		private List<ParticleSystem> FXParticles = new List<ParticleSystem>();

		protected int GetItemStack()
		{
			if (!base.attachedBody || !base.attachedBody.inventory)
			{
				return 1;
			}
			return base.attachedBody.inventory.GetItemCount(RoR2Content.Items.SiphonOnLowHealth);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			FXParticles = base.gameObject.GetComponentsInChildren<ParticleSystem>().ToList();
		}

		public void TurnOffHealingFX()
		{
			for (int i = 0; i < FXParticles.Count; i++)
			{
				ParticleSystem.EmissionModule emission = FXParticles[i].emission;
				emission.enabled = false;
			}
		}

		public void TurnOnHealingFX()
		{
			for (int i = 0; i < FXParticles.Count; i++)
			{
				ParticleSystem.EmissionModule emission = FXParticles[i].emission;
				emission.enabled = true;
			}
		}
	}
	public class RechargeState : BaseSiphonItemState
	{
		public static float baseDuration = 30f;

		public static AnimationCurve particleEmissionCurve;

		private float rechargeDuration;

		public override void OnEnter()
		{
			base.OnEnter();
			TurnOffHealingFX();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				int itemStack = GetItemStack();
				float num = baseDuration / (float)(itemStack + 1);
				if (base.fixedAge / num >= 1f)
				{
					outer.SetNextState(new ReadyState());
				}
			}
		}
	}
	public class ReadyState : BaseSiphonItemState
	{
		public static float healthFractionThreshold = 0.5f;

		private HealthComponent attachedHealthComponent;

		public override void OnEnter()
		{
			base.OnEnter();
			attachedHealthComponent = base.attachedBody?.healthComponent;
			TurnOffHealingFX();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && attachedHealthComponent.combinedHealthFraction <= healthFractionThreshold)
			{
				outer.SetNextState(new ChargeState());
			}
		}
	}
	public class ChargeState : BaseSiphonItemState
	{
		public static float baseDuration = 3f;

		public static string chargeSound;

		private float duration;

		private GameObject chargeVfxInstance;

		private GameObject areaIndicatorVfxInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / (base.attachedBody ? base.attachedBody.attackSpeed : 1f);
			TurnOffHealingFX();
			if ((bool)base.attachedBody)
			{
				UnityEngine.Vector3 position = base.transform.position;
				UnityEngine.Quaternion rotation = base.transform.rotation;
				chargeVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.chargingEffectPrefab, position, rotation);
				chargeVfxInstance.transform.localScale = UnityEngine.Vector3.one * 0.25f;
				Util.PlaySound(chargeSound, base.gameObject);
				areaIndicatorVfxInstance = UnityEngine.Object.Instantiate(ChargeMegaNova.areaIndicatorPrefab, position, rotation);
				ObjectScaleCurve component = areaIndicatorVfxInstance.GetComponent<ObjectScaleCurve>();
				component.timeMax = duration;
				component.baseScale = UnityEngine.Vector3.one * DetonateState.baseSiphonRange * 2f;
				areaIndicatorVfxInstance.GetComponent<AnimateShaderAlpha>().timeMax = duration;
			}
			RoR2Application.onLateUpdate += OnLateUpdate;
		}

		public override void OnExit()
		{
			RoR2Application.onLateUpdate -= OnLateUpdate;
			if ((object)chargeVfxInstance != null)
			{
				EntityState.Destroy(chargeVfxInstance);
				chargeVfxInstance = null;
			}
			if ((object)areaIndicatorVfxInstance != null)
			{
				EntityState.Destroy(areaIndicatorVfxInstance);
				areaIndicatorVfxInstance = null;
			}
			base.OnExit();
		}

		private void OnLateUpdate()
		{
			if ((bool)chargeVfxInstance)
			{
				chargeVfxInstance.transform.position = base.transform.position;
			}
			if ((bool)areaIndicatorVfxInstance)
			{
				areaIndicatorVfxInstance.transform.position = base.transform.position;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new DetonateState());
			}
		}
	}
	public class DetonateState : BaseSiphonItemState
	{
		public static float baseSiphonRange = 50f;

		public static float baseDuration;

		public static float healPulseFraction = 0.5f;

		public static float healMultiplier = 2f;

		public static float damageFraction = 0.1f;

		public static GameObject burstEffectPrefab;

		public static string explosionSound;

		public static string siphonLoopSound;

		public static string retractSound;

		private float duration;

		private float gainedHealth;

		private float gainedHealthFraction;

		private float healTimer;

		private bool burstPlayed;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			GetItemStack();
			UnityEngine.Vector3 position = base.attachedBody.transform.position;
			SphereSearch obj = new SphereSearch
			{
				origin = position,
				radius = baseSiphonRange,
				mask = LayerIndex.entityPrecise.mask
			};
			float num = base.attachedBody.healthComponent.fullCombinedHealth * damageFraction;
			TeamMask mask = default(TeamMask);
			mask.AddTeam(base.attachedBody.teamComponent.teamIndex);
			HurtBox[] hurtBoxes = obj.RefreshCandidates().FilterCandidatesByHurtBoxTeam(mask).OrderCandidatesByDistance()
				.FilterCandidatesByDistinctHurtBoxEntities()
				.GetHurtBoxes();
			foreach (HurtBox hurtBox in hurtBoxes)
			{
				if (hurtBox.healthComponent != base.attachedBody.healthComponent)
				{
					if (!burstPlayed)
					{
						burstPlayed = true;
						Util.PlaySound(explosionSound, base.gameObject);
						Util.PlaySound(siphonLoopSound, base.gameObject);
						EffectData effectData = new EffectData
						{
							scale = 1f,
							origin = position
						};
						effectData.SetHurtBoxReference(base.attachedBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("Base").gameObject);
						EffectManager.SpawnEffect(burstEffectPrefab, effectData, transmit: false);
					}
					DamageInfo damageInfo = new DamageInfo
					{
						attacker = base.attachedBody.gameObject,
						inflictor = base.attachedBody.gameObject,
						crit = false,
						damage = num,
						damageColorIndex = DamageColorIndex.Default,
						damageType = DamageType.Generic,
						force = UnityEngine.Vector3.zero,
						position = hurtBox.transform.position
					};
					hurtBox.healthComponent.TakeDamage(damageInfo);
					HurtBox hurtBoxReference = hurtBox;
					HurtBoxGroup hurtBoxGroup = hurtBox.hurtBoxGroup;
					for (int j = 0; (float)j < Mathf.Min(4f, base.attachedBody.radius * 2f); j++)
					{
						EffectData effectData2 = new EffectData
						{
							scale = 1f,
							origin = position,
							genericFloat = 3f
						};
						effectData2.SetHurtBoxReference(hurtBoxReference);
						GameObject obj2 = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OrbEffects/SiphonOrbEffect");
						obj2.GetComponent<OrbEffect>().parentObjectTransform = base.attachedBody.mainHurtBox.transform;
						EffectManager.SpawnEffect(obj2, effectData2, transmit: true);
						hurtBoxReference = hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, hurtBoxGroup.hurtBoxes.Length)];
					}
					gainedHealth += num;
				}
			}
			gainedHealthFraction = gainedHealth * healPulseFraction;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			healTimer += GetDeltaTime();
			if (base.isAuthority && healTimer > duration * healPulseFraction && gainedHealth > 0f)
			{
				base.attachedBody.healthComponent.Heal(gainedHealthFraction, default(ProcChainMask));
				TurnOnHealingFX();
				healTimer = 0f;
				if (base.fixedAge >= duration)
				{
					Util.PlaySound(retractSound, base.gameObject);
					TurnOffHealingFX();
					outer.SetNextState(new RechargeState());
				}
			}
		}
	}
}
namespace EntityStates.ShrineRebirth
{
	public class ShrineRebirthEntityStates : EntityState
	{
		protected ShrineRebirthController _shrineController;

		protected PickupPickerController _pickupPickerController;

		protected PurchaseInteraction _pi;

		protected NetworkUIPromptController _netUIPromptController;

		public override void OnEnter()
		{
			base.OnEnter();
			_shrineController = base.gameObject.GetComponent<ShrineRebirthController>();
			if (_shrineController.isForTesting)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class RevealRebirthShriine : ShrineRebirthEntityStates
	{
		[SyncVar]
		private GameObject shrineModel;

		public override void OnEnter()
		{
			base.OnEnter();
			if (Run.instance.selectedDifficulty < DifficultyIndex.Eclipse1)
			{
				_shrineController.purchaseInteraction.SetAvailable(newAvailable: true);
				_shrineController.onShrineRevealObjectiveTextObject.SetActive(value: true);
				Transform transform = _shrineController.childLocator.FindChild("ShrineModel");
				if ((bool)transform)
				{
					shrineModel = transform.gameObject;
					if (!shrineModel.activeInHierarchy)
					{
						shrineModel.SetActive(value: true);
					}
				}
				return;
			}
			Transform transform2 = _shrineController.childLocator.FindChild("ShrineModel");
			shrineModel = transform2.gameObject;
			shrineModel.SetActive(value: false);
			GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(_shrineController.helminthPortalISC, new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Direct,
				position = _shrineController.portalObject.transform.position,
				spawnOnTarget = _shrineController.portalObject.transform
			}, Run.instance.stageRng));
			if ((bool)gameObject)
			{
				gameObject.transform.rotation = _shrineController.portalObject.transform.rotation;
			}
		}

		public override void OnExit()
		{
			_shrineController.onShrineRevealObjectiveTextObject.SetActive(value: false);
			base.OnExit();
		}
	}
	public class RebirthOrPortalChoice : ShrineRebirthEntityStates
	{
		public override void OnEnter()
		{
			base.OnEnter();
			_shrineController.onRebirthOrContinueTextObject.SetActive(value: true);
			_shrineController.CallRpcChangeInteractScript();
			GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(_shrineController.helminthPortalISC, new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Direct,
				position = _shrineController.portalObject.transform.position,
				spawnOnTarget = _shrineController.portalObject.transform
			}, Run.instance.stageRng));
			if ((bool)gameObject)
			{
				gameObject.transform.rotation = _shrineController.portalObject.transform.rotation;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			_shrineController.onRebirthOrContinueTextObject.SetActive(value: true);
		}
	}
	public class RebirthChoice : ShrineRebirthEntityStates
	{
		public float rebirthGameEndingTransition = 15f;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound("Play_obj_shrineColossus_locked_loop", base.gameObject);
			Transform transform = _shrineController.childLocator.FindChild("TriggeredVFXSpawnPoint");
			GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/RebirthOnRebirthVFX");
			EffectData effectData = new EffectData
			{
				origin = transform.position,
				genericFloat = 1.5f
			};
			effectData.SetNetworkedObjectReference(base.gameObject);
			int childIndex = _shrineController.childLocator.FindChildIndex("TriggeredVFXSpawnPoint");
			effectData.SetChildLocatorTransformReference(base.gameObject, childIndex);
			if (NetworkServer.active)
			{
				EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			_ = base.fixedAge;
			_ = rebirthGameEndingTransition;
		}
	}
	public class RebirthStormEnding : ShrineRebirthEntityStates
	{
		public override void OnEnter()
		{
			base.OnEnter();
		}
	}
}
namespace EntityStates.ShrineHalcyonite
{
	public class ShrineHalcyoniteBaseState : BaseState
	{
		protected HalcyoniteShrineInteractable parentShrineReference;

		protected GameObject crystalObject;

		protected ParticleSystem ps;

		protected GameObject shrineHalcyoniteBubble;

		protected GameObject shrineBase;

		private Xoroshiro128Plus rng;

		private GameObject modelBase;

		protected bool visualsDone;

		protected float timer;

		private int sliceHeightNameId;

		private Renderer shrineBaseRenderer;

		public override void OnEnter()
		{
			base.OnEnter();
			parentShrineReference = GetComponent<HalcyoniteShrineInteractable>();
			if ((bool)parentShrineReference)
			{
				shrineHalcyoniteBubble = parentShrineReference.shrineHalcyoniteBubble;
				crystalObject = parentShrineReference.crystalObject;
				crystalObject.GetComponent<Renderer>();
				shrineBase = parentShrineReference.shrineBaseObject;
			}
			shrineBaseRenderer = parentShrineReference.shrineGoldTop.GetComponent<Renderer>();
			shrineBaseRenderer.material.EnableKeyword("_SLICEHEIGHT");
			int propertyIndex = shrineBaseRenderer.material.shader.FindPropertyIndex("_SliceHeight");
			sliceHeightNameId = shrineBaseRenderer.material.shader.GetPropertyNameId(propertyIndex);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected void TierChange(float tierChangeVFXModifier)
		{
			Transform transform = parentShrineReference.modelChildLocator.FindChild("ModelBase");
			if ((bool)transform)
			{
				modelBase = transform.gameObject;
			}
			UnityEngine.Vector3 origin = modelBase.gameObject.transform.position + new UnityEngine.Vector3(0f, tierChangeVFXModifier, 0f);
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/HalcyonShrineTierReachVFX"), new EffectData
			{
				origin = origin
			}, transmit: false);
			Util.PlaySound("Play_obj_shrineHalcyonite_tierChange", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			parentShrineReference.shrineGoldTop.GetComponent<Renderer>().material.SetFloat(sliceHeightNameId, parentShrineReference.goldMaterialModifier);
		}

		protected void ModifyVisuals()
		{
			if (!NetworkServer.active || visualsDone || !parentShrineReference.isDraining)
			{
				return;
			}
			float num = 4.1f;
			float num2 = 3.5f;
			float num3 = 4f;
			float num4 = (float)parentShrineReference.goldDrainValue * num / (float)parentShrineReference.lowGoldCost;
			if (parentShrineReference.goldDrained < parentShrineReference.lowGoldCost || parentShrineReference.goldMaterialModifier < 1.9f)
			{
				HalcyoniteShrineInteractable halcyoniteShrineInteractable = parentShrineReference;
				halcyoniteShrineInteractable.NetworkgoldMaterialModifier = halcyoniteShrineInteractable.goldMaterialModifier + num4;
			}
			if ((parentShrineReference.goldDrained > parentShrineReference.lowGoldCost && parentShrineReference.goldDrained < parentShrineReference.midGoldCost) || (parentShrineReference.goldMaterialModifier < 6f && parentShrineReference.goldMaterialModifier >= 1.9f))
			{
				num4 = (float)parentShrineReference.goldDrainValue * num2 / (float)(parentShrineReference.midGoldCost - parentShrineReference.lowGoldCost);
				if (parentShrineReference.goldMaterialModifier >= 5f)
				{
					num4 = (float)parentShrineReference.goldDrainValue * num3 / (float)(parentShrineReference.maxGoldCost - parentShrineReference.midGoldCost);
				}
				HalcyoniteShrineInteractable halcyoniteShrineInteractable2 = parentShrineReference;
				halcyoniteShrineInteractable2.NetworkgoldMaterialModifier = halcyoniteShrineInteractable2.goldMaterialModifier + num4;
			}
			if ((parentShrineReference.goldDrained > parentShrineReference.midGoldCost && parentShrineReference.goldDrained < parentShrineReference.maxGoldCost) || parentShrineReference.goldMaterialModifier >= 6f)
			{
				num4 = (float)parentShrineReference.goldDrainValue * num3 / (float)(parentShrineReference.maxGoldCost - parentShrineReference.midGoldCost);
				HalcyoniteShrineInteractable halcyoniteShrineInteractable3 = parentShrineReference;
				halcyoniteShrineInteractable3.NetworkgoldMaterialModifier = halcyoniteShrineInteractable3.goldMaterialModifier + num4;
			}
			if (parentShrineReference.goldDrained >= parentShrineReference.maxGoldCost)
			{
				visualsDone = true;
			}
		}
	}
	public class ShrineHalcyoniteActivatedState : ShrineHalcyoniteBaseState
	{
		public float shrineAnimationDuration = 1f;

		public float shrineDelayAge;

		public UnityEngine.Vector3 shrineEndLocation = new UnityEngine.Vector3(0f, 0f, 0f);

		private float shrineMovementTimer;

		private GameObject modelBase;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform transform = parentShrineReference.modelChildLocator.FindChild("ModelBase");
			if ((bool)transform)
			{
				modelBase = transform.gameObject;
			}
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/HalcyonResurfaceVFX"), new EffectData
			{
				origin = base.gameObject.transform.position
			}, transmit: true);
			Util.PlaySound("Play_obj_shrineHalcyonite_activate", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			shrineMovementTimer -= Time.deltaTime;
			if (!(shrineMovementTimer <= 0f))
			{
				return;
			}
			if (modelBase.transform.localPosition != shrineEndLocation)
			{
				shrineMovementTimer += 0.05f;
				modelBase.transform.localPosition += new UnityEngine.Vector3(0f, 0.1f, 0f);
				if (modelBase.transform.localPosition == shrineEndLocation)
				{
					Util.PlaySound("Play_obj_shrineHalcyonite_activate_finish", base.gameObject);
				}
			}
			else
			{
				shrineDelayAge += Time.deltaTime;
				if (shrineDelayAge >= shrineAnimationDuration)
				{
					outer.SetNextState(new ShrineHalcyoniteNoQuality());
				}
			}
		}
	}
	public class ShrineHalcyoniteNoQuality : ShrineHalcyoniteBaseState
	{
		[SerializeField]
		public float tierChangeMonsterCreditReduction;

		public override void OnEnter()
		{
			base.OnEnter();
			parentShrineReference.TrackInteractions();
			shrineHalcyoniteBubble.SetActive(value: true);
			parentShrineReference.activationDirector.monsterCredit += parentShrineReference.monsterCredit - tierChangeMonsterCreditReduction;
			parentShrineReference.activationDirector.SpendAllCreditsOnMapSpawns(parentShrineReference.gameObject.transform);
			GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain += base.ModifyVisuals;
			Util.PlaySound("Play_obj_shrineHalcyonite_idle_loop", base.gameObject);
		}

		public override void OnExit()
		{
			base.OnExit();
			GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain -= base.ModifyVisuals;
		}
	}
	public class ShrineHalcyoniteLowQuality : ShrineHalcyoniteBaseState
	{
		[SerializeField]
		public float tierChangeMonsterCreditReduction;

		public override void OnEnter()
		{
			base.OnEnter();
			GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain += base.ModifyVisuals;
			TierChange(5f);
			parentShrineReference.activationDirector.monsterCredit += parentShrineReference.monsterCredit - tierChangeMonsterCreditReduction;
			parentShrineReference.activationDirector.SpendAllCreditsOnMapSpawns(parentShrineReference.gameObject.transform);
		}

		public override void OnExit()
		{
			base.OnExit();
			GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain -= base.ModifyVisuals;
		}
	}
	public class ShrineHalcyoniteMidQuality : ShrineHalcyoniteBaseState
	{
		[SerializeField]
		public float tierChangeMonsterCreditReduction;

		public override void OnEnter()
		{
			base.OnEnter();
			TierChange(8f);
			GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain += base.ModifyVisuals;
			parentShrineReference.activationDirector.monsterCredit += parentShrineReference.monsterCredit - tierChangeMonsterCreditReduction;
			parentShrineReference.activationDirector.SpendAllCreditsOnMapSpawns(parentShrineReference.gameObject.transform);
		}

		public override void OnExit()
		{
			base.OnExit();
			GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain -= base.ModifyVisuals;
		}
	}
	public class ShrineHalcyoniteMaxQuality : ShrineHalcyoniteBaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			parentShrineReference.shrineGoldTop.SetActive(value: true);
			parentShrineReference.DrainConditionMet();
		}
	}
	public class ShrineHalcyoniteFinished : ShrineHalcyoniteBaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (shrineHalcyoniteBubble.activeInHierarchy)
			{
				Util.PlaySound("Stop_obj_shrineHalcyonite_idle_loop", base.gameObject);
				shrineHalcyoniteBubble.SetActive(value: false);
			}
		}
	}
}
namespace EntityStates.Seeker
{
	public class InnerStrength : BaseState
	{
		public override void OnEnter()
		{
		}
	}
	public class Meditate : BaseWindUp
	{
		[SerializeField]
		public new GameObject scopeOverlayPrefab;

		private OverlayController overlayController;

		public override void OnEnter()
		{
			base.OnEnter();
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams
			{
				prefab = scopeOverlayPrefab,
				childLocatorEntry = "ScopeContainer"
			});
		}
	}
	public class BaseScopeState : BaseSkillState
	{
		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public GameObject scopeOverlayPrefab;

		[SerializeField]
		public CharacterCameraParams cameraParams;

		[SerializeField]
		public float cameraOverridePriority;

		public static string mecanimBoolName;

		private OverlayController overlayController;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle;

		public static bool inScope;

		public override void OnEnter()
		{
			base.OnEnter();
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams
			{
				prefab = scopeOverlayPrefab,
				childLocatorEntry = "ScopeContainer"
			});
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(mecanimBoolName, value: true);
			}
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			inScope = true;
		}

		public override void OnExit()
		{
			inScope = false;
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(mecanimBoolName, value: false);
			}
			RemoveOverlay(0f);
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}

		protected void SetScopeAlpha(float alpha)
		{
			if (overlayController != null)
			{
				overlayController.alpha = alpha;
			}
		}

		protected void RemoveOverlay(float transitionDuration)
		{
			if (overlayController != null)
			{
				HudOverlayManager.RemoveOverlay(overlayController);
				overlayController = null;
			}
		}

		protected void StartScopeParamsOverride(float transitionDuration)
		{
			if (!cameraParamsOverrideHandle.isValid)
			{
				cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest
				{
					cameraParamsData = cameraParams.data,
					priority = cameraOverridePriority
				}, transitionDuration);
			}
		}

		protected void EndScopeParamsOverride(float transitionDuration)
		{
			if (cameraParamsOverrideHandle.isValid)
			{
				base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle, transitionDuration);
				cameraParamsOverrideHandle = default(CameraTargetParams.CameraParamsOverrideHandle);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		protected virtual CharacterCameraParams GetCameraParams()
		{
			return cameraParams;
		}

		protected virtual float GetScopeEntryDuration()
		{
			return 0f;
		}
	}
	public class BaseWindUp : BaseScopeState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string enterSoundString;

		private float duration;

		public override void OnEnter()
		{
			duration = baseDuration;
			base.OnEnter();
			SetScopeAlpha(0f);
			StartScopeParamsOverride(duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void OnExit()
		{
			EndScopeParamsOverride(0f);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				BaseActive nextState = GetNextState();
				nextState.activatorSkillSlot = base.activatorSkillSlot;
				outer.SetNextState(nextState);
			}
		}

		public override void Update()
		{
			base.Update();
			SetScopeAlpha(Mathf.Clamp01(base.age / duration));
		}

		protected virtual BaseActive GetNextState()
		{
			return new BaseActive();
		}

		protected override float GetScopeEntryDuration()
		{
			return duration;
		}

		public override void ModifyNextState(EntityState nextState)
		{
		}
	}
	public class BaseWindDown : BaseScopeState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string enterSoundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			SetScopeAlpha(1f);
			RemoveOverlay(duration);
			StartScopeParamsOverride(0f);
			EndScopeParamsOverride(duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void Update()
		{
			base.Update();
			SetScopeAlpha(1f - Mathf.Clamp01(base.age / duration));
		}

		protected override CharacterCameraParams GetCameraParams()
		{
			return null;
		}
	}
	public class BaseActive : BaseScopeState
	{
		[SerializeField]
		public SkillDef primaryOverride;

		[SerializeField]
		public LoopSoundDef loopSound;

		private GenericSkill overriddenSkill;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		public override void OnEnter()
		{
			base.OnEnter();
			SetScopeAlpha(1f);
			StartScopeParamsOverride(0f);
			GenericSkill genericSkill = base.skillLocator?.primary;
			if ((bool)genericSkill)
			{
				TryOverrideSkill(genericSkill);
				genericSkill.onSkillChanged += TryOverrideSkill;
			}
			if (base.isAuthority)
			{
				loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound);
			}
		}

		public override void OnExit()
		{
			if (loopPtr.isValid)
			{
				LoopSoundManager.StopSoundLoopLocal(loopPtr);
			}
			GenericSkill genericSkill = base.skillLocator?.primary;
			if ((bool)genericSkill)
			{
				genericSkill.onSkillChanged -= TryOverrideSkill;
			}
			if ((bool)overriddenSkill)
			{
				overriddenSkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
			}
			EndScopeParamsOverride(0f);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (!IsKeyDownAuthority() || base.characterBody.isSprinting))
			{
				outer.SetNextState(GetNextState());
			}
		}

		private void TryOverrideSkill(GenericSkill skill)
		{
			if ((bool)skill && !overriddenSkill && !skill.HasSkillOverrideOfPriority(GenericSkill.SkillOverridePriority.Contextual))
			{
				overriddenSkill = skill;
				overriddenSkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
				overriddenSkill.stock = base.skillLocator.secondary.stock;
			}
		}

		protected virtual BaseWindDown GetNextState()
		{
			return new BaseWindDown();
		}
	}
	public class MeditationUI : BaseSkillState
	{
		[SerializeField]
		[Header("UI")]
		public GameObject scopeOverlayPrefab;

		[SerializeField]
		public float duration = 5f;

		[SerializeField]
		public float timePenalty = 1f;

		[SerializeField]
		public float failureCooldownPenalty = 5f;

		[SerializeField]
		public float animDuration;

		[SerializeField]
		public float smallHopVelocity;

		[SerializeField]
		public Sprite primaryIcon;

		[SerializeField]
		public Sprite secondaryIcon;

		[SerializeField]
		public Sprite utilityIcon;

		[SerializeField]
		public Sprite specialIcon;

		[SerializeField]
		public SeekerController seekerController;

		[SerializeField]
		public GameObject lotusPrefab;

		[SerializeField]
		public float wrapUpDuration;

		[SerializeField]
		public GameObject successEffectPrefab;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public string startSoundString;

		[SerializeField]
		public string stopSoundString;

		[SerializeField]
		public string timeoutSoundString;

		[SerializeField]
		public string successSoundString;

		[SerializeField]
		public string inputCorrectSoundString;

		[SerializeField]
		public string inputFailSoundString;

		[SerializeField]
		[Header("Healing Explosion")]
		public float healingExplosionAmount = 10f;

		[SerializeField]
		public float healingOverShield = 5f;

		[SerializeField]
		public float blastRadius = 5f;

		[SerializeField]
		public float damageCoefficient = 5f;

		[SerializeField]
		public float blastForce = 5f;

		[SerializeField]
		public UnityEngine.Vector3 blastBonusForce;

		[SerializeField]
		public float blastProcCoefficient = 5f;

		[SerializeField]
		public float percentPerGate = 0.75f;

		[SerializeField]
		public float overShieldPercent = 0.25f;

		[SerializeField]
		public float startingOverShieldPercentage = 0.33f;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private GameObject lotus;

		private OverlayController overlayController;

		private bool meditationSuccess;

		private ICharacterGravityParameterProvider characterGravityParameterProvider;

		private ChildLocator overlayInstanceChildLocator;

		private ChildLocator lotusChildLocator;

		private List<ImageFillController> fillUiList = new List<ImageFillController>();

		private CameraTargetParams.AimRequest aimRequest;

		private bool spawnedLotus;

		private bool failed;

		private bool meditationWrapUp;

		private bool wrapUpAnimationPlayed;

		private float wrapUpTimer;

		private float startingYaw;

		private EntityStateMachine bodyStateMachine;

		private float explosionHealingMod;

		private bool upReady = true;

		private bool downReady = true;

		private bool rightReady = true;

		private bool leftReady = true;

		private static string[] c = new string[5] { "ArrowInput1", "ArrowInput2", "ArrowInput3", "ArrowInput4", "ArrowInput5" };

		public override void OnEnter()
		{
			base.OnEnter();
			EntityStateMachine[] components = base.characterBody.gameObject.GetComponents<EntityStateMachine>();
			foreach (EntityStateMachine entityStateMachine in components)
			{
				if (entityStateMachine.customName == "Body")
				{
					bodyStateMachine = entityStateMachine;
				}
			}
			bodyStateMachine.SetNextState(new Idle());
			explosionHealingMod = base.characterBody.maxHealth;
			if (explosionHealingMod < base.characterBody.baseMaxHealth)
			{
				explosionHealingMod = base.characterBody.baseMaxHealth;
			}
			base.healthComponent.AddBarrierAuthority(explosionHealingMod * startingOverShieldPercentage);
			seekerController = base.characterBody.transform.GetComponent<SeekerController>();
			if (base.isAuthority)
			{
				seekerController.RandomizeMeditationInputs();
			}
			SmallHop(base.characterMotor, smallHopVelocity);
			if ((bool)base.characterMotor)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = 0f;
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.isSprinting = false;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
			PlayAnimation("FullBody, Override", "MeditationStart", "Meditation.playbackRate", animDuration);
			characterGravityParameterProvider = base.gameObject.GetComponent<ICharacterGravityParameterProvider>();
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount++;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams
			{
				prefab = scopeOverlayPrefab,
				childLocatorEntry = "CrosshairExtras"
			});
			overlayController.onInstanceAdded += OnOverlayInstanceAdded;
			overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
			crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			CameraTargetParams component = base.gameObject.GetComponent<CameraTargetParams>();
			if ((bool)component)
			{
				aimRequest = component.RequestAimType(CameraTargetParams.AimType.ZoomedOut);
			}
			startingYaw = base.characterDirection.yaw;
			Util.PlaySound(startSoundString, base.gameObject);
		}

		public override void Update()
		{
			if (seekerController.meditationUIDirty)
			{
				seekerController.meditationUIDirty = false;
				UpdateUIInputSequence();
			}
			base.characterDirection.yaw = startingYaw;
			base.characterDirection.moveVector = base.characterDirection.forward;
			base.Update();
			if (meditationWrapUp)
			{
				wrapUpTimer += Time.deltaTime;
				if (wrapUpTimer > wrapUpDuration)
				{
					outer.SetNextStateToMain();
				}
				if (!wrapUpAnimationPlayed)
				{
					wrapUpAnimationPlayed = true;
					if (meditationSuccess)
					{
						PlayAnimation("FullBody, Override", "MeditationSuccess", "Meditation.playbackRate", animDuration);
						Util.PlaySound(successSoundString, base.gameObject);
						lotus.GetComponentInChildren<Animator>().Play("MeditationSuccess");
						EffectManager.SpawnEffect(successEffectPrefab, new EffectData
						{
							origin = base.characterBody.corePosition
						}, transmit: true);
						if (base.isAuthority)
						{
							float num = 0f;
							float num2 = 0f;
							seekerController.IncrementChakraGate();
							if (base.characterBody.HasBuff(DLC2Content.Buffs.ChakraBuff))
							{
								num2 = base.characterBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff);
								num = num2 * percentPerGate;
							}
							seekerController.CallCmdTriggerHealPulse((healingExplosionAmount * num2 + 0.04f) * explosionHealingMod, base.characterBody.corePosition, blastRadius);
							BlastAttack blastAttack = new BlastAttack();
							blastAttack.attacker = base.characterBody.gameObject;
							blastAttack.baseDamage = (damageCoefficient + num) * base.characterBody.damage;
							blastAttack.baseForce = blastForce;
							blastAttack.bonusForce = blastBonusForce;
							blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
							blastAttack.crit = base.characterBody.RollCrit();
							blastAttack.damageColorIndex = DamageColorIndex.Item;
							blastAttack.inflictor = base.gameObject;
							blastAttack.position = base.characterBody.corePosition;
							blastAttack.procChainMask = default(ProcChainMask);
							blastAttack.procCoefficient = blastProcCoefficient;
							blastAttack.radius = blastRadius;
							blastAttack.falloffModel = BlastAttack.FalloffModel.None;
							blastAttack.teamIndex = base.teamComponent.teamIndex;
							blastAttack.Fire();
						}
					}
					else
					{
						PlayAnimation("FullBody, Override", "MeditationFail", "Meditation.playbackRate", animDuration);
						Util.PlaySound(timeoutSoundString, base.gameObject);
						lotus.GetComponentInChildren<Animator>().Play("MeditationFail");
						outer.SetNextStateToMain();
					}
				}
			}
			int num3 = -1;
			if (base.inputBank.rawMoveUp.justPressed)
			{
				num3 = 0;
			}
			if (base.inputBank.rawMoveDown.justPressed)
			{
				num3 = 1;
			}
			if (base.inputBank.rawMoveRight.justPressed)
			{
				num3 = 2;
			}
			if (base.inputBank.rawMoveLeft.justPressed)
			{
				num3 = 3;
			}
			if (seekerController.meditationInputStep > 4)
			{
				meditationSuccess = true;
				meditationWrapUp = true;
			}
			if (num3 == seekerController.GetNextMeditationStep())
			{
				if (!wrapUpAnimationPlayed && seekerController.meditationInputStep < 5)
				{
					Util.PlaySound(inputCorrectSoundString, base.gameObject);
					seekerController.meditationInputStep++;
				}
			}
			else if (num3 != -1)
			{
				Util.PlaySound(inputFailSoundString, base.gameObject);
				base.fixedAge += timePenalty;
			}
			if (base.fixedAge > 0.4f)
			{
				base.characterMotor.velocity = new UnityEngine.Vector3(0f, 0f, 0f);
				if (base.inputBank.skill4.justPressed)
				{
					meditationWrapUp = true;
				}
				Transform modelTransform = GetModelTransform();
				if ((bool)modelTransform && !spawnedLotus)
				{
					spawnedLotus = true;
					lotusChildLocator = modelTransform.GetComponent<ChildLocator>();
					lotus = UnityEngine.Object.Instantiate(lotusPrefab, lotusChildLocator.FindChild("Lotus"), worldPositionStays: false);
				}
			}
			if (base.fixedAge > duration)
			{
				failed = true;
				meditationWrapUp = true;
			}
			else
			{
				UpdateUI();
			}
		}

		private void SetupInputUIIcons()
		{
			for (int i = 0; i < 5; i++)
			{
				switch (seekerController.meditationStepAndSequence[i + 1])
				{
				case 0:
					overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = UnityEngine.Quaternion.Euler(0f, 0f, 0f);
					break;
				case 1:
					overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = UnityEngine.Quaternion.Euler(0f, 0f, -180f);
					break;
				case 2:
					overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = UnityEngine.Quaternion.Euler(0f, 0f, -90f);
					break;
				case 3:
					overlayInstanceChildLocator.FindChild(c[i]).GetComponent<RectTransform>().rotation = UnityEngine.Quaternion.Euler(0f, 0f, -270f);
					break;
				}
			}
			UpdateUIInputSequence();
		}

		private void UpdateUIInputSequence()
		{
			if (base.isAuthority)
			{
				Color32 color = new Color32(byte.MaxValue, 233, 124, byte.MaxValue);
				for (int i = 0; i < seekerController.meditationInputStep; i++)
				{
					overlayInstanceChildLocator.FindChild(c[i]).GetComponent<UnityEngine.UI.Image>().color = color;
				}
			}
		}

		private void UpdateUI()
		{
			foreach (ImageFillController fillUi in fillUiList)
			{
				fillUi.SetTValue(base.fixedAge / duration);
			}
		}

		public override void OnExit()
		{
			PlayAnimation("FullBody, Override", "Empty");
			Util.PlaySound(stopSoundString, base.gameObject);
			if (overlayController != null)
			{
				HudOverlayManager.RemoveOverlay(overlayController);
				overlayController = null;
			}
			aimRequest?.Dispose();
			crosshairOverrideRequest?.Dispose();
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount--;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			}
			if ((bool)lotus)
			{
				lotus.GetComponent<DestroyOnTimer>().duration = 0.01f;
			}
			if (failed)
			{
				base.skillLocator.special.temporaryCooldownPenalty += failureCooldownPenalty;
			}
			bodyStateMachine.SetNextStateToMain();
			base.OnExit();
		}

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			fillUiList.Add(instance.GetComponent<ImageFillController>());
			overlayInstanceChildLocator = instance.GetComponent<ChildLocator>();
			SetupInputUIIcons();
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			fillUiList.Remove(instance.GetComponent<ImageFillController>());
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SeekerInitialWeaponState : BaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			GenericSkill genericSkill = base.skillLocator.FindSkillByFamilyName("SeekerBodyPrimaryFamily");
			if (genericSkill == null)
			{
				outer.SetNextStateToMain();
				return;
			}
			SeekerWeaponSkillDef seekerWeaponSkillDef = genericSkill.skillDef as SeekerWeaponSkillDef;
			if (seekerWeaponSkillDef == null)
			{
				outer.SetNextStateToMain();
				return;
			}
			HandleCrosshair(seekerWeaponSkillDef);
			HandleTargetTracking(seekerWeaponSkillDef);
			outer.SetNextStateToMain();
		}

		private void HandleTargetTracking(SeekerWeaponSkillDef seekerWeapon)
		{
			HuntressTracker component = GetComponent<HuntressTracker>();
			if (!(component == null))
			{
				component.enabled = seekerWeapon.targetTrackingIndicator;
			}
		}

		private void HandleCrosshair(SeekerWeaponSkillDef seekerWeapon)
		{
			CrosshairUtils.RequestOverrideForBody(base.characterBody, seekerWeapon.crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
		}
	}
	public class Sojourn : BaseState
	{
		[SerializeField]
		public GameObject vehiclePrefab;

		public static float smallHopVelocity;

		public static UnityEngine.Color screenDamageColor;

		public static bool combineTintAdditively;

		public static float minimumDamageStrength;

		public static float maximumDamageStrength;

		public static float pulseDuration;

		private SeekerController seekerController;

		public float duration = 0.3f;

		private bool animFinished;

		private ScreenDamageCalculatorSojourn screenDamageCalculator;

		public override void OnEnter()
		{
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(DLC2Content.Buffs.SojournVehicle);
			}
			screenDamageCalculator = new ScreenDamageCalculatorSojourn();
			screenDamageCalculator.minimumDamage = minimumDamageStrength;
			screenDamageCalculator.maximumDamage = maximumDamageStrength;
			screenDamageCalculator.duration = pulseDuration;
			ScreenDamageData screenDamageData = screenDamageCalculator.screenDamageData;
			screenDamageData.IntendedTintColor = screenDamageColor;
			screenDamageData.combineAdditively = combineTintAdditively;
			base.characterBody.healthComponent.screenDamageCalculator = screenDamageCalculator;
			seekerController = base.characterBody.transform.GetComponent<SeekerController>();
			seekerController.doesExitVehicle = false;
			SmallHop(base.characterMotor, smallHopVelocity);
			PlayAnimation("Gesture, Override", "SojournEnterTransform");
			base.fixedAge = 0f;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration && !animFinished)
			{
				if (NetworkServer.active)
				{
					Ray aimRay = GetAimRay();
					GameObject gameObject = UnityEngine.Object.Instantiate(vehiclePrefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction));
					gameObject.GetComponent<SojournVehicle>().sojournState = this;
					gameObject.GetComponent<VehicleSeat>().AssignPassenger(base.gameObject);
					NetworkUser networkUser = base.characterBody?.master?.playerCharacterMasterController?.networkUser;
					if ((bool)networkUser)
					{
						NetworkServer.SpawnWithClientAuthority(gameObject, networkUser.gameObject);
					}
					else
					{
						NetworkServer.Spawn(gameObject);
					}
				}
				animFinished = true;
			}
			if (seekerController.doesExitVehicle)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Vehicle;
		}

		public override void OnExit()
		{
			PlayAnimation("Gesture, Override", "SojournExitTransformation");
			if (screenDamageCalculator != null)
			{
				screenDamageCalculator.End();
			}
			base.characterBody.healthComponent.screenDamageCalculator = null;
			if (!NetworkServer.active)
			{
				return;
			}
			base.characterBody.RemoveBuff(DLC2Content.Buffs.SojournVehicle);
			if (base.characterBody.HasBuff(DLC2Content.Buffs.SojournHealing))
			{
				float num = base.characterBody.GetBuffCount(DLC2Content.Buffs.SojournHealing);
				for (int i = 0; (float)i < num; i++)
				{
					base.characterBody.RemoveBuff(DLC2Content.Buffs.SojournHealing);
				}
			}
		}
	}
	public class SoulSearch : BaseState, SteppedSkillDef.IStepSetter
	{
		public enum Gauntlet
		{
			Left,
			Right
		}

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force = 20f;

		public static float attackSpeedAltAnimationThreshold;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float attackSoundPitch;

		public static float bloom;

		[SerializeField]
		public GameObject blastEffectPrefab;

		[SerializeField]
		public GameObject blastImpactEffectPrefab;

		[SerializeField]
		public float blastRadius;

		[SerializeField]
		public float blastDamageCoefficient;

		[SerializeField]
		public float blastForce;

		[SerializeField]
		public UnityEngine.Vector3 blastBonusForce;

		[SerializeField]
		public float blastProcCoefficient;

		private float duration;

		private bool hasFiredGauntlet;

		private string muzzleString;

		private Transform muzzleTransform;

		private Animator animator;

		private ChildLocator childLocator;

		private Gauntlet gauntlet;

		private HuntressTracker huntressTracker;

		public void SetStep(int i)
		{
			gauntlet = (Gauntlet)i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			huntressTracker = base.characterBody.GetComponent<HuntressTracker>();
			if (!huntressTracker.GetTrackingTarget())
			{
				outer.SetNextStateToMain();
				return;
			}
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch);
			base.characterBody.SetAimTimer(2f);
			animator = GetModelAnimator();
			if ((bool)animator)
			{
				childLocator = animator.GetComponent<ChildLocator>();
			}
			switch (gauntlet)
			{
			case Gauntlet.Left:
				muzzleString = "MuzzleLeft";
				PlayCrossfade("Gesture, Additive", "Cast1Left", "FireGauntlet.playbackRate", duration, 0.1f);
				PlayCrossfade("Gesture, Override", "Cast1Left", "FireGauntlet.playbackRate", duration, 0.1f);
				break;
			case Gauntlet.Right:
				muzzleString = "MuzzleRight";
				PlayCrossfade("Gesture, Additive", "Cast1Right", "FireGauntlet.playbackRate", duration, 0.1f);
				PlayCrossfade("Gesture, Override", "Cast1Right", "FireGauntlet.playbackRate", duration, 0.1f);
				break;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireGauntlet()
		{
			if (!hasFiredGauntlet)
			{
				base.characterBody.AddSpreadBloom(bloom);
				Ray aimRay = GetAimRay();
				if ((bool)childLocator)
				{
					muzzleTransform = childLocator.FindChild(muzzleString);
				}
				if ((bool)muzzleflashEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
				}
				if (projectilePrefab != null && base.isAuthority)
				{
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.projectilePrefab = projectilePrefab;
					fireProjectileInfo.position = muzzleTransform.position;
					fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(aimRay.direction);
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.damage = damageStat * damageCoefficient;
					FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
					ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration || hasFiredGauntlet)
			{
				if (!hasFiredGauntlet && (bool)huntressTracker.GetTrackingTarget())
				{
					FireGauntlet();
					hasFiredGauntlet = true;
				}
				if (base.isAuthority)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)gauntlet);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			gauntlet = (Gauntlet)reader.ReadByte();
		}
	}
	public class SoulSpiral : BaseState
	{
		public static string prepOrbSoundString;

		public static float duration;

		public static float dmgCoefficient;

		public static GameObject projectilePrefab;

		public static GameObject muzzleFXPrefab;

		public static string muzzleChildName;

		public static float projectileForce;

		public static float smallHopVelocity;

		public bool firedOrb;

		private EffectData effectData;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.modelLocator)
			{
				ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					int childIndex = component.FindChildIndex(muzzleChildName);
					effectData = new EffectData();
					effectData.SetChildLocatorTransformReference(base.characterBody.gameObject, childIndex);
				}
			}
			PlayAnimation("Gesture, Additive", "SoulSpiralStart", "PrepUnseenHand.playbackRate", duration);
			PlayAnimation("Gesture, Override", "SoulSpiralStart", "PrepUnseenHand.playbackRate", duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!firedOrb && base.fixedAge > duration && base.isAuthority)
			{
				FireSpiral();
				outer.SetNextStateToMain();
			}
		}

		private void FireSpiral()
		{
			firedOrb = true;
			Util.PlaySound(prepOrbSoundString, base.gameObject);
			effectData.origin = base.characterBody.corePosition;
			effectData.rotation = UnityEngine.Quaternion.identity;
			EffectManager.SpawnEffect(muzzleFXPrefab, effectData, transmit: false);
			if (base.isAuthority)
			{
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * dmgCoefficient;
				fireProjectileInfo.force = projectileForce;
				fireProjectileInfo.position = base.characterBody.corePosition;
				fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				FireProjectileInfo projectileInfo = fireProjectileInfo;
				base.characterBody.GetComponent<SeekerController>().FireSoulSpiral(projectileInfo);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (!firedOrb && !ObjectIsBeingDestroyed())
			{
				FireSpiral();
			}
			if ((bool)base.characterMotor && !base.isGrounded)
			{
				base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, Mathf.Max(base.characterMotor.velocity.y, smallHopVelocity), base.characterMotor.velocity.z);
			}
		}

		private bool ObjectIsBeingDestroyed()
		{
			GameObject gameObject = base.characterBody.gameObject;
			if (!(gameObject == null))
			{
				if (!gameObject.activeSelf)
				{
					return gameObject.activeInHierarchy;
				}
				return false;
			}
			return true;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public class SpiritPunch : BaseState, SteppedSkillDef.IStepSetter
	{
		public enum Gauntlet
		{
			Left,
			Right,
			Explode
		}

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject projectileFinisherPrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float dmgBuffIncrease = 0.2f;

		[SerializeField]
		public float comboDamageCoefficient;

		[SerializeField]
		public float force = 20f;

		public static float attackSpeedAltAnimationThreshold;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float paddingBetweenAttacks = 0.2f;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public string attackSoundStringAlt;

		[SerializeField]
		public float attackSoundPitch;

		[SerializeField]
		public float bloom;

		private float duration;

		private bool hasFiredGauntlet;

		private string muzzleString;

		private Transform muzzleTransform;

		private Animator animator;

		private ChildLocator childLocator;

		private Gauntlet gauntlet;

		private float extraDmgFromBuff;

		public static float recoilAmplitude;

		private string animationStateName;

		public static event Action<bool> onSpiritOrbFired;

		public void SetStep(int i)
		{
			gauntlet = (Gauntlet)i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			base.characterBody.SetAimTimer(2f);
			animator = GetModelAnimator();
			if ((bool)animator)
			{
				childLocator = animator.GetComponent<ChildLocator>();
			}
			switch (gauntlet)
			{
			case Gauntlet.Left:
				muzzleString = "MuzzleLeft";
				animationStateName = "Cast1Left";
				break;
			case Gauntlet.Right:
				muzzleString = "MuzzleRight";
				animationStateName = "Cast1Right";
				break;
			case Gauntlet.Explode:
				muzzleString = "MuzzleEnergyBomb";
				animationStateName = "SpiritPunchFinisher";
				extraDmgFromBuff = dmgBuffIncrease * (float)base.characterBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff);
				break;
			}
			bool @bool = animator.GetBool("isMoving");
			bool bool2 = animator.GetBool("isGrounded");
			if (!@bool && bool2)
			{
				PlayCrossfade("FullBody, Override", animationStateName, "FireGauntlet.playbackRate", duration, 0.025f);
				return;
			}
			PlayCrossfade("Gesture, Additive", animationStateName, "FireGauntlet.playbackRate", duration, 0.025f);
			PlayCrossfade("Gesture, Override", animationStateName, "FireGauntlet.playbackRate", duration, 0.025f);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireGauntlet()
		{
			if (!hasFiredGauntlet)
			{
				base.characterBody.AddSpreadBloom(bloom);
				Ray ray = GetAimRay();
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
				if ((bool)childLocator)
				{
					muzzleTransform = childLocator.FindChild(muzzleString);
				}
				if ((bool)muzzleflashEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
				}
				if (base.isAuthority)
				{
					float damage = damageStat * (damageCoefficient + extraDmgFromBuff);
					ProjectileManager.instance.FireProjectile(projectilePrefab, muzzleTransform.position, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damage, force, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, 70f + attackSpeedStat * 2f);
				}
				AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration - duration * 0.25f || hasFiredGauntlet)
			{
				if (gauntlet == Gauntlet.Explode && !hasFiredGauntlet)
				{
					Util.PlayAttackSpeedSound(attackSoundStringAlt, base.gameObject, attackSoundPitch);
					projectilePrefab = projectileFinisherPrefab;
					damageCoefficient = comboDamageCoefficient;
					FireGauntlet();
					SpiritPunch.onSpiritOrbFired?.Invoke(obj: true);
					_ = base.characterMotor.isGrounded;
					hasFiredGauntlet = true;
				}
				else if (!hasFiredGauntlet)
				{
					Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch);
					FireGauntlet();
					hasFiredGauntlet = true;
					SpiritPunch.onSpiritOrbFired?.Invoke(obj: false);
				}
				if (base.isAuthority && base.fixedAge >= duration + duration * paddingBetweenAttacks)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)gauntlet);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			gauntlet = (Gauntlet)reader.ReadByte();
		}
	}
	public class UnseenHand : BaseState
	{
		public static float baseDuration;

		public static GameObject areaIndicatorPrefab;

		public static GameObject projectilePrefab;

		public static GameObject muzzleflashEffect;

		public static GameObject goodCrosshairPrefab;

		public static GameObject badCrosshairPrefab;

		public static string prepFistSoundString;

		public static string endFistSoundString;

		public static string startTargetingLoopSoundString;

		public static string stopTargetingLoopSoundString;

		public static float maxDistance;

		public static string fireSoundString;

		public static float maxSlopeAngle;

		public static GameObject initialEffect;

		public static GameObject muzzleFlashEffect;

		public static GameObject fistProjectilePrefab;

		public static float fistDamageCoefficient;

		public static float fistForce;

		public static float fuseOverride;

		public static int abilityAimType;

		public static float cameraTransitionOutTime;

		public static float smallHopVelocity;

		private float duration;

		private float stopwatch;

		private bool goodPlacement;

		private GameObject areaIndicatorInstance;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		protected CameraTargetParams.AimRequest aimRequest;

		private bool cameraStarted;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			base.characterBody.SetAimTimer(duration + 2f);
			PlayAnimation("Gesture, Additive", "UnseenHandPrep", "PrepUnseenHand.playbackRate", duration);
			PlayAnimation("Gesture, Override", "UnseenHandPrep", "PrepUnseenHand.playbackRate", duration);
			Util.PlaySound(prepFistSoundString, base.gameObject);
			Util.PlaySound(startTargetingLoopSoundString, base.gameObject);
			areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab);
			UpdateAreaIndicator();
		}

		private void UpdateAreaIndicator()
		{
			bool flag = goodPlacement;
			goodPlacement = false;
			areaIndicatorInstance.SetActive(value: true);
			if ((bool)areaIndicatorInstance)
			{
				float num = maxDistance;
				float extraRaycastDistance = 0f;
				if (Physics.Raycast(CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance), out var hitInfo, num + extraRaycastDistance, LayerIndex.world.mask))
				{
					areaIndicatorInstance.transform.position = hitInfo.point;
					goodPlacement = UnityEngine.Vector3.Angle(UnityEngine.Vector3.up, hitInfo.normal) < maxSlopeAngle;
				}
				if (flag != goodPlacement || crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest?.Dispose();
					GameObject crosshairPrefab = (goodPlacement ? goodCrosshairPrefab : badCrosshairPrefab);
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill);
				}
			}
			areaIndicatorInstance.SetActive(goodPlacement);
		}

		public override void Update()
		{
			base.Update();
			UpdateAreaIndicator();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!cameraStarted && base.fixedAge > 0.1f)
			{
				if ((bool)base.cameraTargetParams)
				{
					aimRequest = base.cameraTargetParams.RequestAimType((CameraTargetParams.AimType)abilityAimType);
				}
				cameraStarted = true;
			}
			if (base.inputBank.skill2.down || !base.isAuthority)
			{
				return;
			}
			if (goodPlacement)
			{
				PlayAnimation("Gesture, Additive", "UnseenHandFinish");
				PlayAnimation("Gesture, Override", "UnseenHandFinish");
				Util.PlaySound(fireSoundString, base.gameObject);
				if ((bool)areaIndicatorInstance)
				{
					EffectManager.SpawnEffect(muzzleFlashEffect, new EffectData
					{
						origin = areaIndicatorInstance.transform.position
					}, transmit: true);
					if (base.isAuthority)
					{
						EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleLeft", transmit: true);
						EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleRight", transmit: true);
						UnityEngine.Vector3 forward = areaIndicatorInstance.transform.forward;
						forward.y = 0f;
						forward.Normalize();
						UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward);
						Util.CheckRoll(critStat, base.characterBody.master);
						FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
						fireProjectileInfo.projectilePrefab = fistProjectilePrefab;
						fireProjectileInfo.position = areaIndicatorInstance.transform.position;
						fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up);
						fireProjectileInfo.owner = base.gameObject;
						fireProjectileInfo.damage = damageStat * fistDamageCoefficient;
						fireProjectileInfo.damageTypeOverride = DamageType.Stun1s;
						fireProjectileInfo.force = fistForce;
						fireProjectileInfo.crit = base.characterBody.RollCrit();
						fireProjectileInfo.fuseOverride = fuseOverride;
						ProjectileManager.instance.FireProjectile(fireProjectileInfo);
					}
				}
			}
			else
			{
				base.skillLocator.secondary.AddOneStock();
				PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f);
				PlayCrossfade("Gesture, Override", "BufferEmpty", 0.2f);
			}
			outer.SetNextStateToMain();
		}

		public override void OnExit()
		{
			if (goodPlacement)
			{
				if (!base.isGrounded)
				{
					base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, smallHopVelocity);
				}
				if (base.characterBody.isServer)
				{
					CharacterBody obj = base.characterBody;
					if ((object)obj != null && obj.inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage) > 0)
					{
						base.characterBody.AddIncreasePrimaryDamageStack();
					}
				}
			}
			Util.PlaySound(endFistSoundString, base.gameObject);
			Util.PlaySound(stopTargetingLoopSoundString, base.gameObject);
			EntityState.Destroy(areaIndicatorInstance.gameObject);
			crosshairOverrideRequest?.Dispose();
			aimRequest?.Dispose();
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
}
namespace EntityStates.Scrapper
{
	public class ScrapperBaseState : BaseState
	{
		protected PickupPickerController pickupPickerController;

		protected ScrapperController scrapperController;

		protected virtual bool enableInteraction => true;

		public override void OnEnter()
		{
			base.OnEnter();
			pickupPickerController = GetComponent<PickupPickerController>();
			scrapperController = GetComponent<ScrapperController>();
			pickupPickerController.SetAvailable(enableInteraction);
		}
	}
	public class WaitToBeginScrapping : ScrapperBaseState
	{
		public static float duration;

		protected override bool enableInteraction => false;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new Scrapping());
			}
		}
	}
	public class Scrapping : ScrapperBaseState
	{
		public static string enterSoundString;

		public static string exitSoundString;

		public static float duration;

		private static int ScrappingStateHash = Animator.StringToHash("Scrapping");

		private static int ScrappingParamHash = Animator.StringToHash("Scrapping.playbackRate");

		protected override bool enableInteraction => false;

		public override void OnEnter()
		{
			base.OnEnter();
			FindModelChild("ScrappingEffect").gameObject.SetActive(value: true);
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Base", ScrappingStateHash, ScrappingParamHash, duration);
		}

		public override void OnExit()
		{
			FindModelChild("ScrappingEffect").gameObject.SetActive(value: false);
			Util.PlaySound(exitSoundString, base.gameObject);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new ScrappingToIdle());
			}
		}
	}
	public class ScrappingToIdle : ScrapperBaseState
	{
		public static string enterSoundString;

		public static string exitSoundString;

		public static float duration;

		public static float dropUpVelocityStrength;

		public static float dropForwardVelocityStrength;

		public static GameObject muzzleflashEffectPrefab;

		public static string muzzleString;

		private bool foundValidScrap;

		private static int ScrappingToIdleStateHash = Animator.StringToHash("ScrappingToIdle");

		private static int ScrappingParamHash = Animator.StringToHash("Scrapping.playbackRate");

		protected override bool enableInteraction => false;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation("Base", ScrappingToIdleStateHash, ScrappingParamHash, duration);
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if (NetworkServer.active)
			{
				foundValidScrap = false;
				PickupIndex none = PickupIndex.none;
				none = PickupCatalog.FindScrapIndexForItemTier(ItemCatalog.GetItemDef(scrapperController.lastScrappedItemIndex).tier);
				if (none != PickupIndex.none)
				{
					foundValidScrap = true;
					Transform transform = FindModelChild(muzzleString);
					PickupDropletController.CreatePickupDroplet(none, transform.position, UnityEngine.Vector3.up * dropUpVelocityStrength + transform.forward * dropForwardVelocityStrength);
					scrapperController.itemsEaten--;
				}
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(exitSoundString, base.gameObject);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (foundValidScrap && scrapperController.itemsEaten > 0 && base.fixedAge > duration / 2f)
			{
				outer.SetNextState(new ScrappingToIdle());
			}
			else if (base.fixedAge > duration)
			{
				outer.SetNextState(new Idle());
			}
		}
	}
	public class Idle : ScrapperBaseState
	{
		protected override bool enableInteraction => true;
	}
}
namespace EntityStates.Scorchling
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathExplosion;

		public static string deathSoundString;

		public static string stopBurrowLoopString;

		public static float animDuration = 1f;

		public static float cleanUpDuration = 0.3f;

		public static float printDuration;

		private bool burrowed;

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayAnimation("FullBody, Override", "Burrow", "Burrow.playbackRate", animDuration);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				PrintController printController = modelTransform.gameObject.AddComponent<PrintController>();
				printController.printTime = printDuration;
				printController.enabled = true;
				printController.startingPrintHeight = 99999f;
				printController.maxPrintHeight = 99999f;
				printController.startingPrintBias = 1f;
				printController.maxPrintBias = 3.5f;
				printController.animateFlowmapPower = true;
				printController.startingFlowmapPower = 1.14f;
				printController.maxFlowmapPower = 30f;
				printController.disableWhenFinished = false;
				printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
			}
			cleanUpDuration += animDuration;
			Util.PlaySound(deathSoundString, base.gameObject);
			Util.PlaySound(stopBurrowLoopString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!burrowed && base.fixedAge >= animDuration)
			{
				EffectManager.SpawnEffect(deathExplosion, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = 4f
				}, transmit: true);
				burrowed = true;
			}
			if (base.fixedAge >= cleanUpDuration)
			{
				DestroyModel();
				if (NetworkServer.active)
				{
					DestroyBodyAsapServer();
				}
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class ScorchlingBreach : BaseState
	{
		[SerializeField]
		[Header("Timing")]
		public float crackToBreachTime = 1f;

		[SerializeField]
		public float breachToBurrow = 5f;

		[SerializeField]
		public float burrowToEndOfTime = 1f;

		[SerializeField]
		public float animDuration = 1f;

		[Header("Explosion Attr")]
		[SerializeField]
		public float blastProcCoefficient;

		[SerializeField]
		public float blastDamageCoefficient;

		[SerializeField]
		public float blastForce;

		[SerializeField]
		public UnityEngine.Vector3 blastBonusForce;

		[SerializeField]
		public float knockbackForce;

		[Header("FX Objects")]
		[SerializeField]
		public GameObject crackEffectPrefab;

		[SerializeField]
		public float crackRadius = 1f;

		[SerializeField]
		public GameObject blastEffectPrefab;

		[SerializeField]
		public GameObject blastImpactEffectPrefab;

		[SerializeField]
		public float blastRadius = 1f;

		[SerializeField]
		public GameObject burrowEffectPrefab;

		[SerializeField]
		public float burrowRadius = 1f;

		[Header("Sound Strings")]
		[SerializeField]
		public string preBreachSoundString;

		[SerializeField]
		public string breachSoundString;

		[SerializeField]
		public string burrowSoundString;

		[SerializeField]
		public string burrowLoopSoundString;

		[SerializeField]
		public string burrowStopLoopSoundString;

		public bool proceedImmediatelyToLavaBomb;

		private bool breached;

		private bool burrowed;

		private bool amServer;

		private UnityEngine.Vector3 breachPosition;

		private ScorchlingController scorchlingController;

		private CharacterBody enemyCBody;

		public override void OnEnter()
		{
			base.OnEnter();
			amServer = NetworkServer.active;
			scorchlingController = base.characterBody.GetComponent<ScorchlingController>();
			Util.PlaySound(preBreachSoundString, base.gameObject);
			if (amServer)
			{
				enemyCBody = base.characterBody.master.GetComponent<BaseAI>().currentEnemy?.characterBody;
				if (proceedImmediatelyToLavaBomb)
				{
					breachToBurrow = 1f;
				}
				breachToBurrow += crackToBreachTime;
				burrowToEndOfTime += breachToBurrow;
				breachPosition = base.characterBody.footPosition;
				if (!proceedImmediatelyToLavaBomb && (bool)enemyCBody)
				{
					breachPosition = enemyCBody.footPosition;
				}
				if ((bool)base.characterMotor)
				{
					base.characterMotor.walkSpeedPenaltyCoefficient = 0f;
				}
				base.characterBody.SetAimTimer(breachToBurrow);
				TeleportHelper.TeleportBody(base.characterBody, breachPosition);
				EffectManager.SpawnEffect(crackEffectPrefab, new EffectData
				{
					origin = breachPosition,
					scale = crackRadius
				}, transmit: true);
				scorchlingController.SetTeleportPermission(b: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (amServer && base.fixedAge < crackToBreachTime && enemyCBody != null)
			{
				UnityEngine.Vector3 normalized = (enemyCBody.corePosition - base.characterBody.corePosition).normalized;
				base.characterBody.characterDirection.forward = normalized;
			}
			if (!breached && base.fixedAge > crackToBreachTime)
			{
				breached = true;
				scorchlingController.Breach();
				PlayAnimation("FullBody, Override", "Breach", "Breach.playbackRate", animDuration);
				Util.PlaySound(breachSoundString, base.gameObject);
				Util.PlaySound(burrowStopLoopSoundString, base.gameObject);
				if (amServer)
				{
					DetonateAuthority();
				}
			}
			if (base.fixedAge > burrowToEndOfTime)
			{
				DoExit();
			}
		}

		private void DoExit()
		{
			if (proceedImmediatelyToLavaBomb)
			{
				outer.SetNextState(new ScorchlingLavaBomb());
			}
			else
			{
				outer.SetNextStateToMain();
			}
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = breachPosition,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				damageType = DamageType.Stun1s,
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = breachPosition,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (proceedImmediatelyToLavaBomb)
			{
				return InterruptPriority.Frozen;
			}
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ScorchlingEnsureBurrow : BaseState
	{
		[SerializeField]
		public string burrowSoundString;

		[SerializeField]
		public string burrowLoopSoundString;

		[SerializeField]
		public string burrowStopLoopSoundString;

		[SerializeField]
		public GameObject burrowEffectPrefab;

		[SerializeField]
		public float burrowRadius = 1f;

		[SerializeField]
		public float animDurationBurrow = 1f;

		[SerializeField]
		public float burrowAnimationDuration = 1f;

		private ScorchlingController sController;

		private bool waitingForBurrow;

		public override void OnEnter()
		{
			base.OnEnter();
			sController = base.characterBody.GetComponent<ScorchlingController>();
			if (!sController.isBurrowed)
			{
				Util.PlaySound(burrowSoundString, base.gameObject);
				Util.PlaySound(burrowLoopSoundString, base.gameObject);
				EffectManager.SpawnEffect(burrowEffectPrefab, new EffectData
				{
					origin = base.characterBody.footPosition,
					scale = burrowRadius
				}, transmit: true);
				PlayAnimation("FullBody, Override", "Burrow", "Burrow.playbackRate", animDurationBurrow);
				if ((bool)base.characterMotor)
				{
					base.characterMotor.walkSpeedPenaltyCoefficient = 0f;
				}
				if ((bool)base.characterBody)
				{
					base.characterBody.isSprinting = false;
				}
				if ((bool)base.rigidbodyMotor)
				{
					base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
				}
				waitingForBurrow = true;
			}
		}

		public override void Update()
		{
			base.Update();
			HandleWaitForBurrow();
		}

		public override void OnExit()
		{
			base.OnExit();
			HandleWaitForBurrow();
		}

		private void HandleWaitForBurrow()
		{
			if (waitingForBurrow && base.age > burrowAnimationDuration)
			{
				sController.Burrow();
				waitingForBurrow = false;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (waitingForBurrow)
			{
				return InterruptPriority.Frozen;
			}
			return InterruptPriority.Skill;
		}
	}
	public class ScorchlingLavaBomb : BaseState
	{
		[SerializeField]
		[Header("Timing")]
		public float breachToSpitTime = 1f;

		[SerializeField]
		public float spitToLaunchTime = 0.3f;

		[SerializeField]
		public float spitToBurrowTime = 5f;

		[SerializeField]
		public float burrowToEndOfTime = 1f;

		[SerializeField]
		public float animDurationBreach = 1f;

		[SerializeField]
		public float animDurationSpit = 1f;

		[SerializeField]
		public float animDurationBurrow = 1f;

		[SerializeField]
		public float animDurationPostSpit = 0.75f;

		[SerializeField]
		public float percentageToFireProjectile = 0.75f;

		[SerializeField]
		[Header("FX Objects")]
		public GameObject burrowEffectPrefab;

		[SerializeField]
		public float burrowRadius = 1f;

		[Header("Sound Strings")]
		[SerializeField]
		public string breachSoundString;

		[SerializeField]
		public string spitSoundString;

		[SerializeField]
		public string burrowSoundString;

		[SerializeField]
		public string burrowLoopSoundString;

		[SerializeField]
		public string burrowStopLoopSoundString;

		[Header("Lava Bomb Projectile")]
		public static GameObject mortarProjectilePrefab;

		public static GameObject mortarMuzzleflashEffect;

		public static int mortarCount;

		public static string mortarMuzzleName;

		public static string mortarSoundString;

		public static float mortarDamageCoefficient;

		public static float timeToTarget = 3f;

		public static float projectileVelocity = 55f;

		public static float minimumDistance;

		private bool spitStarted;

		private bool firedProjectile;

		private bool earlyExit;

		private ScorchlingController sController;

		public override void OnEnter()
		{
			base.OnEnter();
			sController = base.characterBody.GetComponent<ScorchlingController>();
			animDurationBreach = (sController.isBurrowed ? animDurationBreach : 0f);
			spitToBurrowTime += animDurationBreach + animDurationSpit;
			burrowToEndOfTime += spitToBurrowTime;
			if (sController.isBurrowed)
			{
				earlyExit = true;
				if (Util.HasEffectiveAuthority(base.characterBody.networkIdentity))
				{
					outer.SetNextState(new ScorchlingBreach
					{
						proceedImmediatelyToLavaBomb = true,
						breachToBurrow = breachToSpitTime
					});
				}
			}
			else
			{
				base.characterBody.SetAimTimer(burrowToEndOfTime);
			}
		}

		public override void FixedUpdate()
		{
			if (earlyExit)
			{
				return;
			}
			base.FixedUpdate();
			if (!spitStarted && base.fixedAge > animDurationBreach)
			{
				spitStarted = true;
				PlayAnimation("FullBody, Override", "Spit", "Spit.playbackRate", animDurationSpit);
			}
			if (spitStarted && !firedProjectile && base.fixedAge > animDurationSpit * percentageToFireProjectile + animDurationBreach)
			{
				firedProjectile = true;
				Util.PlaySound(spitSoundString, base.gameObject);
				EffectManager.SimpleMuzzleFlash(mortarMuzzleflashEffect, base.gameObject, mortarMuzzleName, transmit: false);
				if (base.isAuthority)
				{
					Spit();
				}
			}
			if (firedProjectile && base.fixedAge > animDurationBreach + animDurationSpit + animDurationPostSpit)
			{
				outer.SetNextStateToMain();
			}
		}

		public void Spit()
		{
			Transform transform = base.characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("MuzzleFire");
			Ray ray = new Ray(transform.position, transform.forward);
			Ray ray2 = new Ray(ray.origin, UnityEngine.Vector3.up);
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = ray.origin;
			bullseyeSearch.searchDirection = ray.direction;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.RefreshCandidates();
			HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
			bool flag = false;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			RaycastHit hitInfo;
			if ((bool)hurtBox)
			{
				vector = hurtBox.transform.position;
				flag = true;
			}
			else if (Physics.Raycast(ray, out hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
			{
				vector = hitInfo.point;
				flag = true;
			}
			float magnitude = projectileVelocity;
			if (flag)
			{
				UnityEngine.Vector3 vector2 = vector - ray2.origin;
				UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z);
				float magnitude2 = vector3.magnitude;
				UnityEngine.Vector2 vector4 = vector3 / magnitude2;
				if (magnitude2 < minimumDistance)
				{
					magnitude2 = minimumDistance;
				}
				float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector2.y);
				float num = magnitude2 / timeToTarget;
				UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * num, y, vector4.y * num);
				magnitude = direction.magnitude;
				ray2.direction = direction;
			}
			UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(ray2.direction);
			ProjectileManager.instance.FireProjectile(mortarProjectilePrefab, ray2.origin, rotation, base.gameObject, damageStat * mortarDamageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : EntityState
	{
		public static float duration = 0.5f;

		public static string spawnSoundString;

		public static string burrowLoopSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			Util.PlaySound(burrowLoopSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.ScavBackpack
{
	public class Opening : EntityState
	{
		public static float duration = 1f;

		public static int maxItemDropCount;

		private ChestBehavior chestBehavior;

		private float itemDropCount;

		private float timeBetweenDrops;

		private float itemDropAge;

		private static int OpeningStateHash = Animator.StringToHash("Opening");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", OpeningStateHash);
			timeBetweenDrops = duration / (float)maxItemDropCount;
			chestBehavior = GetComponent<ChestBehavior>();
			if ((bool)base.sfxLocator)
			{
				Util.PlaySound(base.sfxLocator.openSound, base.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				itemDropAge += GetDeltaTime();
				if (itemDropCount < (float)maxItemDropCount && itemDropAge > timeBetweenDrops)
				{
					itemDropCount += 1f;
					itemDropAge -= timeBetweenDrops;
					chestBehavior.RollItem();
					chestBehavior.ItemDrop();
				}
				if (base.fixedAge >= duration)
				{
					outer.SetNextState(new Opened());
				}
			}
		}
	}
}
namespace EntityStates.ScavMonster
{
	public class Death : GenericCharacterDeath
	{
		[SerializeField]
		public SpawnCard spawnCard;

		public static float duration;

		private bool shouldDropPack;

		protected override bool shouldAutoDestroy => false;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!NetworkServer.active)
			{
				return;
			}
			CharacterMaster characterMaster = (base.characterBody ? base.characterBody.master : null);
			if ((bool)characterMaster)
			{
				bool flag = characterMaster.IsExtraLifePendingServer();
				bool flag2 = characterMaster.inventory.GetItemCount(RoR2Content.Items.Ghost) > 0;
				bool flag3 = !Stage.instance || Stage.instance.scavPackDroppedServer;
				shouldDropPack = !flag && !flag2 && !flag3;
				if (shouldDropPack)
				{
					Stage.instance.scavPackDroppedServer = true;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				DestroyBodyAsapServer();
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}

		protected override void OnPreDestroyBodyServer()
		{
			base.OnPreDestroyBodyServer();
			if (shouldDropPack)
			{
				AttemptDropPack();
			}
		}

		private void AttemptDropPack()
		{
			DirectorCore instance = DirectorCore.instance;
			if ((bool)instance)
			{
				Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint);
				DirectorPlacementRule placementRule = new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
					position = base.characterBody.footPosition,
					minDistance = 0f,
					maxDistance = float.PositiveInfinity
				};
				_ = (bool)instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, rng));
			}
		}
	}
	public class DeathLunar : Death
	{
	}
	public class EnergyCannonState : BaseState
	{
		public static string muzzleName;

		protected Transform muzzleTransform;

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class PrepEnergyCannon : EnergyCannonState
	{
		public static float baseDuration;

		public static string sound;

		public static GameObject chargeEffectPrefab;

		private GameObject chargeInstance;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "PrepEnergyCannon", "PrepEnergyCannon.playbackRate", duration, 0.1f);
			Util.PlaySound(sound, base.gameObject);
			if ((bool)muzzleTransform && (bool)chargeEffectPrefab)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
				chargeInstance.transform.parent = muzzleTransform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			StartAimMode(0.5f);
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireEnergyCannon());
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
		}
	}
	public class FireEnergyCannon : EnergyCannonState
	{
		public static float baseDuration;

		public static float baseRefireDuration;

		public static string sound;

		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static float recoilAmplitude = 1f;

		public static float projectilePitchBonus;

		public static float projectileYawBonusPerRefire;

		public static int projectileCount;

		public static int maxRefireCount;

		public int currentRefire;

		private float duration;

		private float refireDuration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			refireDuration = baseRefireDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat);
			PlayCrossfade("Body", "FireEnergyCannon", "FireEnergyCannon.playbackRate", duration, 0.1f);
			AddRecoil(-2f * recoilAmplitude, -3f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, EnergyCannonState.muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				float num = ((currentRefire % 2 == 0) ? 1 : (-1));
				float num2 = Mathf.Ceil((float)currentRefire / 2f) * projectileYawBonusPerRefire;
				for (int i = 0; i < projectileCount; i++)
				{
					Ray aimRay = GetAimRay();
					aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, num * num2, projectilePitchBonus);
					ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= refireDuration && currentRefire + 1 < maxRefireCount && base.isAuthority)
			{
				FireEnergyCannon fireEnergyCannon = new FireEnergyCannon();
				fireEnergyCannon.currentRefire = currentRefire + 1;
				outer.SetNextState(fireEnergyCannon);
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class FindItem : BaseState
	{
		public static float baseDuration;

		public static float tier1Chance;

		public static int tier1Count;

		public static float tier2Chance;

		public static int tier2Count;

		public static float tier3Chance;

		public static int tier3Count;

		public static string sound;

		private float duration;

		private PickupIndex dropPickup;

		private int itemsToGrant;

		private PickupDisplay pickupDisplay;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "SitRummage", "Sit.playbackRate", duration, 0.1f);
			Util.PlaySound(sound, base.gameObject);
			if (base.isAuthority)
			{
				WeightedSelection<List<PickupIndex>> weightedSelection = new WeightedSelection<List<PickupIndex>>();
				weightedSelection.AddChoice(Run.instance.availableTier1DropList.Where(PickupIsNonBlacklistedItem).ToList(), tier1Chance);
				weightedSelection.AddChoice(Run.instance.availableTier2DropList.Where(PickupIsNonBlacklistedItem).ToList(), tier2Chance);
				weightedSelection.AddChoice(Run.instance.availableTier3DropList.Where(PickupIsNonBlacklistedItem).ToList(), tier3Chance);
				List<PickupIndex> list = weightedSelection.Evaluate(UnityEngine.Random.value);
				dropPickup = list[UnityEngine.Random.Range(0, list.Count)];
				PickupDef pickupDef = PickupCatalog.GetPickupDef(dropPickup);
				if (pickupDef != null)
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
					if (itemDef != null)
					{
						itemsToGrant = 0;
						switch (itemDef.tier)
						{
						case ItemTier.Tier1:
							itemsToGrant = tier1Count;
							break;
						case ItemTier.Tier2:
							itemsToGrant = tier2Count;
							break;
						case ItemTier.Tier3:
							itemsToGrant = tier3Count;
							break;
						default:
							itemsToGrant = 1;
							break;
						}
					}
				}
			}
			Transform transform = FindModelChild("PickupDisplay");
			pickupDisplay = transform.GetComponent<PickupDisplay>();
			pickupDisplay.SetPickupIndex(dropPickup);
		}

		public override void OnExit()
		{
			pickupDisplay.SetPickupIndex(PickupIndex.none);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new GrantItem
				{
					dropPickup = dropPickup,
					itemsToGrant = itemsToGrant
				});
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(dropPickup);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			dropPickup = reader.ReadPickupIndex();
		}

		private bool PickupIsNonBlacklistedItem(PickupIndex pickupIndex)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef == null)
			{
				return false;
			}
			ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
			if (itemDef == null)
			{
				return false;
			}
			return itemDef.DoesNotContainTag(ItemTag.AIBlacklist);
		}
	}
	public class GrantItem : BaseState
	{
		public PickupIndex dropPickup;

		public int itemsToGrant;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				GrantPickupServer(dropPickup, itemsToGrant);
			}
			if (base.isAuthority)
			{
				outer.SetNextState(new ExitSit());
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(dropPickup);
			writer.WritePackedUInt32((uint)itemsToGrant);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			dropPickup = reader.ReadPickupIndex();
			itemsToGrant = (int)reader.ReadPackedUInt32();
		}

		private void GrantPickupServer(PickupIndex pickupIndex, int countToGrant)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef != null)
			{
				ItemIndex itemIndex = pickupDef.itemIndex;
				if (!(ItemCatalog.GetItemDef(itemIndex) == null))
				{
					base.characterBody.inventory.GiveItem(itemIndex, countToGrant);
					Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage
					{
						subjectAsCharacterBody = base.characterBody,
						baseToken = "MONSTER_PICKUP",
						pickupToken = pickupDef.nameToken,
						pickupColor = pickupDef.baseColor,
						pickupQuantity = (uint)itemsToGrant
					});
				}
			}
		}
	}
	public class BaseSitState : BaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost);
			}
			base.OnExit();
		}
	}
	public class EnterSit : BaseSitState
	{
		public static float baseDuration;

		public static string soundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(soundString, base.gameObject);
			PlayCrossfade("Body", "EnterSit", "Sit.playbackRate", duration, 0.1f);
			base.modelLocator.normalizeToFloor = true;
			base.modelLocator.modelTransform.GetComponent<AimAnimator>().enabled = true;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new FindItem());
			}
		}
	}
	public class Sit : BaseSitState
	{
		public static string soundString;

		public static float minimumDuration;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", "SitLoop", 0.1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.inputBank.moveVector.sqrMagnitude >= Mathf.Epsilon && base.fixedAge >= minimumDuration)
			{
				outer.SetNextState(new ExitSit());
			}
		}
	}
	public class ExitSit : BaseSitState
	{
		public static float baseDuration;

		public static string soundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(soundString, base.gameObject);
			PlayCrossfade("Body", "ExitSit", "Sit.playbackRate", duration, 0.1f);
			base.modelLocator.normalizeToFloor = false;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class SackBaseState : BaseState
	{
		public static string muzzleName;

		protected Transform muzzleTransform;

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class PrepSack : SackBaseState
	{
		public static float baseDuration;

		public static string sound;

		public static GameObject chargeEffectPrefab;

		private GameObject chargeInstance;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "PrepSack", "PrepSack.playbackRate", duration, 0.1f);
			Util.PlaySound(sound, base.gameObject);
			StartAimMode(duration);
			if ((bool)muzzleTransform && (bool)chargeEffectPrefab)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
				chargeInstance.transform.parent = muzzleTransform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new ThrowSack());
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
		}
	}
	public class ThrowSack : SackBaseState
	{
		public static float baseDuration;

		public static string sound;

		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static string attackSoundString;

		public static float projectileVelocity;

		public static float minimumDistance;

		public static float timeToTarget = 3f;

		public static int projectileCount;

		private float duration;

		private static int ThrowSackStateHash = Animator.StringToHash("ThrowSack");

		private static int ThrowSackParamHash = Animator.StringToHash("ThrowSack.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat);
			PlayAnimation("Body", ThrowSackStateHash, ThrowSackParamHash, duration);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, SackBaseState.muzzleName, transmit: false);
			}
			Fire();
		}

		private void Fire()
		{
			Ray aimRay = GetAimRay();
			Ray ray = aimRay;
			Ray ray2 = aimRay;
			UnityEngine.Vector3 point = aimRay.GetPoint(minimumDistance);
			bool flag = false;
			if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo, 500f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
			{
				point = hitInfo.point;
				flag = true;
			}
			float magnitude = projectileVelocity;
			if (flag)
			{
				UnityEngine.Vector3 vector = point - ray2.origin;
				UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z);
				float magnitude2 = vector2.magnitude;
				UnityEngine.Vector2 vector3 = vector2 / magnitude2;
				if (magnitude2 < minimumDistance)
				{
					magnitude2 = minimumDistance;
				}
				float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector.y);
				float num = magnitude2 / timeToTarget;
				UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector3.x * num, y, vector3.y * num);
				magnitude = direction.magnitude;
				ray2.direction = direction;
			}
			for (int i = 0; i < projectileCount; i++)
			{
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(Util.ApplySpread(ray2.direction, minSpread, maxSpread, 1f, 1f));
				ProjectileManager.instance.FireProjectile(projectilePrefab, ray2.origin, rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.RoboBallBoss
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialEffect;

		public static GameObject deathEffect;

		public static float duration = 2f;

		private float stopwatch;

		private Transform modelBaseTransform;

		private Transform centerTransform;

		private bool attemptedDeathBehavior;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.modelLocator)
			{
				return;
			}
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				centerTransform = component.FindChild("Center");
				if ((bool)initialEffect)
				{
					GameObject obj = UnityEngine.Object.Instantiate(initialEffect, centerTransform.position, centerTransform.rotation);
					obj.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
					obj.transform.parent = centerTransform;
				}
			}
			modelBaseTransform = base.modelLocator.modelBaseTransform;
		}

		private void AttemptDeathBehavior()
		{
			if (!attemptedDeathBehavior)
			{
				attemptedDeathBehavior = true;
				if ((bool)deathEffect && NetworkServer.active && (bool)centerTransform)
				{
					EffectManager.SpawnEffect(deathEffect, new EffectData
					{
						origin = centerTransform.position
					}, transmit: true);
				}
				if ((bool)modelBaseTransform)
				{
					EntityState.Destroy(modelBaseTransform.gameObject);
					modelBaseTransform = null;
				}
				if (NetworkServer.active)
				{
					EntityState.Destroy(base.gameObject);
				}
			}
		}

		public override void FixedUpdate()
		{
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration)
			{
				AttemptDeathBehavior();
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				AttemptDeathBehavior();
			}
			base.OnExit();
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
		public static GameObject spawnEffectPrefab;

		public static float spawnEffectRadius;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = spawnEffectRadius
				}, transmit: false);
			}
		}
	}
}
namespace EntityStates.RoboBallBoss.Weapon
{
	public class DeployMinions : BaseState
	{
		public static float baseDuration = 3.5f;

		public static string attackSoundString;

		public static string summonSoundString;

		public static int maxSummonCount = 5;

		public static float summonDuration = 3.26f;

		public static string summonMuzzleString;

		public static string spawnCard;

		private Animator animator;

		private Transform modelTransform;

		private ChildLocator childLocator;

		private float duration;

		private float summonInterval;

		private float summonTimer;

		private int summonCount;

		private bool isSummoning;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			duration = baseDuration;
			PlayCrossfade("Gesture, Additive", "DeployMinions", "DeployMinions.playbackRate", duration, 0.1f);
			Util.PlaySound(attackSoundString, base.gameObject);
			summonInterval = summonDuration / (float)maxSummonCount;
		}

		private Transform FindTargetClosest(UnityEngine.Vector3 point, TeamIndex enemyTeam)
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(enemyTeam);
			float num = 99999f;
			Transform result = null;
			for (int i = 0; i < teamMembers.Count; i++)
			{
				float num2 = UnityEngine.Vector3.SqrMagnitude(teamMembers[i].transform.position - point);
				if (num2 < num)
				{
					num = num2;
					result = teamMembers[i].transform;
				}
			}
			return result;
		}

		private void SummonMinion()
		{
			if (!base.characterBody || !base.characterBody.master || base.characterBody.master.GetDeployableCount(DeployableSlot.RoboBallMini) >= base.characterBody.master.GetDeployableSameSlotLimit(DeployableSlot.RoboBallMini))
			{
				return;
			}
			Util.PlaySound(summonSoundString, base.gameObject);
			if (!NetworkServer.active)
			{
				return;
			}
			UnityEngine.Vector3 position = FindModelChild(summonMuzzleString).position;
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>($"SpawnCards/CharacterSpawnCards/{spawnCard}"), new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Direct,
				minDistance = 0f,
				maxDistance = 0f,
				position = position
			}, RoR2Application.rng);
			directorSpawnRequest.summonerBodyObject = base.gameObject;
			GameObject gameObject = DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			if ((bool)gameObject)
			{
				CharacterMaster component = gameObject.GetComponent<CharacterMaster>();
				RoR2.Inventory component2 = gameObject.GetComponent<RoR2.Inventory>();
				component2.SetEquipmentIndex(base.characterBody.inventory.currentEquipmentIndex);
				if (base.characterBody.inventory.GetItemCount(RoR2Content.Items.Ghost) > 0)
				{
					component2.GiveItem(RoR2Content.Items.Ghost);
					component2.GiveItem(RoR2Content.Items.HealthDecay, 30);
					component2.GiveItem(RoR2Content.Items.BoostDamage, 150);
				}
				Deployable deployable = gameObject.AddComponent<Deployable>();
				deployable.onUndeploy = new UnityEvent();
				deployable.onUndeploy.AddListener(component.TrueKill);
				base.characterBody.master.AddDeployable(deployable, DeployableSlot.RoboBallMini);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)animator)
			{
				bool flag = animator.GetFloat("DeployMinions.active") > 0.9f;
				if (isSummoning)
				{
					summonTimer += GetDeltaTime();
					if (NetworkServer.active && summonTimer > 0f && summonCount < maxSummonCount)
					{
						summonCount++;
						summonTimer -= summonInterval;
						SummonMinion();
					}
				}
				isSummoning = flag;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class EnableEyebeams : BaseState
	{
		public static float baseDuration;

		public static string soundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(soundString, base.gameObject);
			EntityStateMachine[] components = base.gameObject.GetComponents<EntityStateMachine>();
			foreach (EntityStateMachine entityStateMachine in components)
			{
				if (entityStateMachine.customName.Contains("EyeBeam"))
				{
					entityStateMachine.SetNextState(new FireSpinningEyeBeam());
				}
			}
		}
	}
	public class ChargeEyeblast : BaseState
	{
		public static float baseDuration = 1f;

		public static GameObject chargeEffectPrefab;

		public static string attackString;

		public static string muzzleString;

		private float duration;

		private GameObject chargeInstance;

		protected EffectManagerHelper _emh_chargeInstance;

		public override void Reset()
		{
			base.Reset();
			chargeInstance = null;
			_emh_chargeInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Animator modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(muzzleString);
					if ((bool)transform && (bool)chargeEffectPrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
						{
							chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
							chargeInstance = _emh_chargeInstance.gameObject;
						}
						chargeInstance.transform.parent = transform;
						ScaleParticleSystemDuration component2 = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = duration;
						}
					}
				}
			}
			if ((bool)modelAnimator)
			{
				PlayCrossfade("Gesture, Additive", "ChargeEyeBlast", "ChargeEyeBlast.playbackRate", duration, 0.1f);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null)
			{
				_emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance);
			}
			else
			{
				EntityState.Destroy(chargeInstance);
			}
			chargeInstance = null;
			_emh_chargeInstance = null;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(GetNextState());
			}
		}

		public virtual EntityState GetNextState()
		{
			return new FireEyeBlast();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireEyeBlast : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		public static GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public int projectileCount = 3;

		[SerializeField]
		public float totalYawSpread = 5f;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float baseFireDuration = 0.2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float projectileSpeed;

		public static float force = 20f;

		public static float selfForce;

		public static string attackString;

		public static string muzzleString;

		private float duration;

		private float fireDuration;

		private int projectilesFired;

		private bool projectileSpreadIsYaw;

		private static int FireEyeBlastStateHash = Animator.StringToHash("FireEyeBlast");

		private static int FireEyeBlastParamHash = Animator.StringToHash("FireEyeBlast.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			fireDuration = baseFireDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", FireEyeBlastStateHash, FireEyeBlastParamHash, duration);
			Util.PlaySound(attackString, base.gameObject);
			if (base.isAuthority)
			{
				base.healthComponent.TakeDamageForce(GetAimRay().direction * selfForce);
			}
			if (UnityEngine.Random.value <= 0.5f)
			{
				projectileSpreadIsYaw = true;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount);
				if (projectilesFired <= num && projectilesFired < projectileCount)
				{
					if ((bool)muzzleflashEffectPrefab)
					{
						EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
					}
					Ray aimRay = GetAimRay();
					float speedOverride = projectileSpeed;
					int num2 = Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f);
					float bonusYaw = 0f;
					float bonusPitch = 0f;
					if (projectileSpreadIsYaw)
					{
						bonusYaw = (float)num2 / (float)(projectileCount - 1) * totalYawSpread;
					}
					else
					{
						bonusPitch = (float)num2 / (float)(projectileCount - 1) * totalYawSpread;
					}
					UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch);
					ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speedOverride);
					projectilesFired++;
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeSuperEyeblast : ChargeEyeblast
	{
		public override EntityState GetNextState()
		{
			return new FireSuperEyeblast();
		}
	}
	public class FireSuperEyeblast : FireEyeBlast
	{
	}
	public class FireDelayKnockup : BaseState
	{
		[SerializeField]
		public int knockupCount;

		[SerializeField]
		public float randomPositionRadius;

		public static float baseDuration;

		public static GameObject projectilePrefab;

		public static GameObject muzzleEffectPrefab;

		public static float maxDistance;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Gesture, Additive", "FireDelayKnockup", 0.1f);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "EyeballMuzzle1", transmit: false);
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "EyeballMuzzle2", transmit: false);
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "EyeballMuzzle3", transmit: false);
			}
			if (!NetworkServer.active)
			{
				return;
			}
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			bullseyeSearch.maxDistanceFilter = maxDistance;
			bullseyeSearch.maxAngleFilter = 360f;
			Ray aimRay = GetAimRay();
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.RefreshCandidates();
			List<HurtBox> list = bullseyeSearch.GetResults().ToList();
			int num = 0;
			for (int i = 0; i < knockupCount; i++)
			{
				if (num >= list.Count)
				{
					num = 0;
				}
				HurtBox hurtBox = list[num];
				if ((bool)hurtBox)
				{
					UnityEngine.Vector2 vector = UnityEngine.Random.insideUnitCircle * randomPositionRadius;
					UnityEngine.Vector3 vector2 = hurtBox.transform.position + new UnityEngine.Vector3(vector.x, 0f, vector.y);
					if (Physics.Raycast(new Ray(vector2 + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down), out var hitInfo, 200f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						vector2 = hitInfo.point;
					}
					ProjectileManager.instance.FireProjectile(projectilePrefab, vector2, UnityEngine.Quaternion.identity, base.gameObject, damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master));
				}
				num++;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class FireSuperDelayKnockup : FireDelayKnockup
	{
		public static float shieldDuration;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.EngiShield, shieldDuration);
			}
		}
	}
	public class FireSpinningEyeBeam : FireEyeBeam
	{
		private Transform eyeBeamOriginTransform;

		public override void OnEnter()
		{
			string customName = outer.customName;
			eyeBeamOriginTransform = FindModelChild(customName);
			muzzleString = customName;
			base.OnEnter();
		}

		public override Ray GetLaserRay()
		{
			Ray result = default(Ray);
			if ((bool)eyeBeamOriginTransform)
			{
				result.origin = eyeBeamOriginTransform.position;
				result.direction = eyeBeamOriginTransform.forward;
			}
			return result;
		}

		public override bool ShouldFireLaser()
		{
			return true;
		}
	}
}
namespace EntityStates.RoboBallMini
{
	public class DeathState : EntityStates.Drone.DeathState
	{
		public override void OnImpactServer(UnityEngine.Vector3 contactPoint)
		{
		}
	}
}
namespace EntityStates.RoboBallMini.Weapon
{
	public class FireEyeBeam : FireBeam
	{
		public override void ModifyBullet(BulletAttack bulletAttack)
		{
		}
	}
}
namespace EntityStates.Railgunner.Weapon
{
	public class ActiveReload : BaseState
	{
		private const string reloadStateMachineName = "Reload";

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Reload");
			if ((bool)entityStateMachine && entityStateMachine.state is Reloading reloading)
			{
				reloading.AttemptBoost();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public abstract class BaseChargeSnipe : BaseState, IBaseWeaponState
	{
		private const string backpackStateMachineName = "Backpack";

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Backpack");
			if ((bool)entityStateMachine)
			{
				entityStateMachine.SetNextState(InstantiateBackpackState());
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public bool CanScope()
		{
			return false;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		protected abstract EntityState InstantiateBackpackState();
	}
	public class BaseFireMine : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float baseCrossfadeDuration;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			float crossfadeDuration = baseCrossfadeDuration / attackSpeedStat;
			Util.PlaySound(enterSoundString, base.gameObject);
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			if ((bool)GetModelAnimator())
			{
				PlayCrossfade(animationLayerName, animationStateName, animationPlaybackRateParam, duration, crossfadeDuration);
			}
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public abstract class BaseFireSnipe : GenericBulletBaseState, IBaseWeaponState
	{
		private const string reloadStateMachineName = "Reload";

		private const string backpackStateMachineName = "Backpack";

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public bool useSecondaryStocks;

		[SerializeField]
		public bool queueReload;

		[SerializeField]
		[Header("Projectile")]
		public float critDamageMultiplier;

		[SerializeField]
		public float selfKnockbackForce;

		[SerializeField]
		public bool isPiercing;

		[SerializeField]
		public float piercingDamageCoefficientPerTarget;

		[SerializeField]
		public float trajectoryAimAssistMultiplier = 0.3f;

		[Header("Animation")]
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private bool wasMiss;

		private bool wasAtLeastOneWeakpoint;

		public static event Action<DamageInfo> onWeakPointHit;

		public static event Action onWeakPointMissed;

		public static event Action<BaseFireSnipe> onFireSnipe;

		public override void OnEnter()
		{
			wasMiss = true;
			BaseFireSnipe.onFireSnipe?.Invoke(this);
			base.OnEnter();
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			if (base.isAuthority && useSecondaryStocks && (bool)base.skillLocator && (bool)base.skillLocator.secondary)
			{
				base.skillLocator.secondary.DeductStock(1);
			}
		}

		public override void OnExit()
		{
			if (base.isAuthority && (wasMiss || (!wasAtLeastOneWeakpoint && !wasMiss)))
			{
				BaseFireSnipe.onWeakPointMissed?.Invoke();
			}
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}

		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			bulletAttack.sniper = true;
			bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
			EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Reload");
			if ((bool)entityStateMachine)
			{
				if (entityStateMachine.state is Boosted boosted)
				{
					bulletAttack.damage += boosted.GetBonusDamage();
					boosted.ConsumeBoost(queueReload);
				}
				else if (queueReload && entityStateMachine.state is Waiting waiting)
				{
					waiting.QueueReload();
				}
			}
			if (isPiercing)
			{
				bulletAttack.stopperMask = LayerIndex.world.mask;
			}
			bulletAttack.modifyOutgoingDamageCallback = delegate(BulletAttack _bulletAttack, ref BulletAttack.BulletHit hitInfo, DamageInfo damageInfo)
			{
				_bulletAttack.damage *= piercingDamageCoefficientPerTarget;
				wasMiss = false;
				if (damageInfo.crit)
				{
					damageInfo.damage *= critDamageMultiplier;
					if ((bool)hitInfo.hitHurtBox && (bool)hitInfo.hitHurtBox.healthComponent && (bool)hitInfo.hitHurtBox.healthComponent.body && hitInfo.hitHurtBox.healthComponent.body.teamComponent.teamIndex != base.characterBody.teamComponent.teamIndex)
					{
						BaseFireSnipe.onWeakPointHit?.Invoke(damageInfo);
						wasAtLeastOneWeakpoint = true;
					}
				}
			};
			EntityStateMachine entityStateMachine2 = EntityStateMachine.FindByCustomName(base.gameObject, "Backpack");
			EntityState entityState = InstantiateBackpackState();
			if ((bool)entityStateMachine2 && entityState != null)
			{
				entityStateMachine2.SetNextState(entityState);
			}
			bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier;
		}

		protected override void OnFireBulletAuthority(Ray aimRay)
		{
			base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction);
		}

		protected override void PlayFireAnimation()
		{
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
		}

		public bool CanScope()
		{
			return true;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		protected virtual EntityState InstantiateBackpackState()
		{
			return null;
		}
	}
	public abstract class BaseWindupSnipe : BaseState, IBaseWeaponState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public GameObject windupEffectPrefab;

		[SerializeField]
		public string windupEffectMuzzle;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private GameObject windupEffectInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			if ((bool)windupEffectPrefab)
			{
				Transform transform = FindModelChild(windupEffectMuzzle);
				if ((bool)transform)
				{
					windupEffectInstance = UnityEngine.Object.Instantiate(windupEffectPrefab, transform.position, transform.rotation);
					windupEffectInstance.transform.parent = transform;
				}
			}
		}

		public override void Update()
		{
			base.Update();
			base.characterBody.SetSpreadBloom(base.age / duration, canOnlyIncreaseBloom: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(InstantiateNextState());
			}
		}

		public override void OnExit()
		{
			crosshairOverrideRequest?.Dispose();
			if ((bool)windupEffectInstance)
			{
				EntityState.Destroy(windupEffectInstance);
			}
			base.OnExit();
		}

		protected abstract EntityState InstantiateNextState();

		public bool CanScope()
		{
			return true;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class ChargeSnipeCryo : BaseChargeSnipe
	{
		protected override EntityState InstantiateBackpackState()
		{
			return new ChargingCryo();
		}
	}
	public class ChargeSnipeSuper : BaseChargeSnipe
	{
		protected override EntityState InstantiateBackpackState()
		{
			return new ChargingSuper();
		}
	}
	public class FireMineBlinding : BaseFireMine
	{
	}
	public class FireMineConcussive : BaseFireMine
	{
	}
	public class FirePistol : BaseState, IBaseWeaponState
	{
		[SerializeField]
		public float baseDuration;

		[Header("Projectile")]
		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public float spreadBloomValue;

		[SerializeField]
		public float recoilYMin;

		[SerializeField]
		public float recoilXMin;

		[SerializeField]
		public float recoilYMax;

		[SerializeField]
		public float recoilXMax;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float selfKnockbackForce;

		[SerializeField]
		public float baseInaccuracyDegrees;

		[Header("Effects")]
		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public string fireSoundString;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[Header("Animation")]
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		protected float duration;

		protected virtual void FireBullet(Ray aimRay)
		{
			StartAimMode(aimRay);
			Util.PlaySound(fireSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, muzzleName, transmit: false);
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			AddRecoil(recoilYMin, recoilYMax, recoilXMin, recoilXMax);
			if (base.isAuthority)
			{
				float num = 0f;
				if ((bool)base.characterBody)
				{
					num = base.characterBody.spreadBloomAngle;
				}
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.forward);
				UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, baseInaccuracyDegrees + num), UnityEngine.Vector3.left);
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction, UnityEngine.Vector3.up) * quaternion * quaternion2;
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = aimRay.origin;
				fireProjectileInfo.rotation = rotation;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.crit = RollCrit();
				fireProjectileInfo.force = force;
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
				base.characterBody.characterMotor.ApplyForce((0f - selfKnockbackForce) * aimRay.direction);
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			FireBullet(GetAimRay());
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public bool CanScope()
		{
			return true;
		}
	}
	public class FireSnipeCryo : BaseFireSnipe
	{
		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.damageType |= (DamageTypeCombo)DamageType.Freeze2s;
		}

		protected override EntityState InstantiateBackpackState()
		{
			return new UseCryo();
		}
	}
	public class FireSnipeHeavy : BaseFireSnipe
	{
	}
	public class FireSnipeLight : BaseFireSnipe
	{
	}
	public class FireSnipeSuper : BaseFireSnipe
	{
		protected override EntityState InstantiateBackpackState()
		{
			return new Offline();
		}
	}
	public interface IBaseWeaponState
	{
		bool CanScope();
	}
	public class WindupSnipeCryo : BaseWindupSnipe
	{
		protected override EntityState InstantiateNextState()
		{
			return new FireSnipeCryo();
		}
	}
	public class WindupSnipeSuper : BaseWindupSnipe
	{
		protected override EntityState InstantiateNextState()
		{
			return new FireSnipeSuper();
		}
	}
}
namespace EntityStates.Railgunner.Scope
{
	public class ActiveScopeHeavy : BaseActive
	{
		protected override BaseWindDown GetNextState()
		{
			return new WindDownScopeHeavy();
		}
	}
	public class ActiveScopeLight : BaseActive
	{
		protected override BaseWindDown GetNextState()
		{
			return new WindDownScopeLight();
		}
	}
	public class BaseScopeState : BaseSkillState
	{
		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public GameObject scopeOverlayPrefab;

		[SerializeField]
		public CharacterCameraParams cameraParams;

		[SerializeField]
		public float cameraOverridePriority;

		public static string mecanimBoolName;

		private OverlayController overlayController;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private CameraTargetParams.CameraParamsOverrideHandle cameraParamsOverrideHandle;

		public static bool inScope;

		public override void OnEnter()
		{
			base.OnEnter();
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams
			{
				prefab = scopeOverlayPrefab,
				childLocatorEntry = "ScopeContainer"
			});
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(mecanimBoolName, value: true);
			}
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			inScope = true;
		}

		public override void OnExit()
		{
			inScope = false;
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(mecanimBoolName, value: false);
			}
			RemoveOverlay(0f);
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}

		protected void SetScopeAlpha(float alpha)
		{
			if (overlayController != null)
			{
				overlayController.alpha = alpha;
			}
		}

		protected void RemoveOverlay(float transitionDuration)
		{
			if (overlayController != null)
			{
				HudOverlayManager.RemoveOverlay(overlayController);
				overlayController = null;
			}
		}

		protected void StartScopeParamsOverride(float transitionDuration)
		{
			if (!cameraParamsOverrideHandle.isValid)
			{
				cameraParamsOverrideHandle = base.cameraTargetParams.AddParamsOverride(new CameraTargetParams.CameraParamsOverrideRequest
				{
					cameraParamsData = cameraParams.data,
					priority = cameraOverridePriority
				}, transitionDuration);
			}
		}

		protected void EndScopeParamsOverride(float transitionDuration)
		{
			if (cameraParamsOverrideHandle.isValid)
			{
				base.cameraTargetParams.RemoveParamsOverride(cameraParamsOverrideHandle, transitionDuration);
				cameraParamsOverrideHandle = default(CameraTargetParams.CameraParamsOverrideHandle);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		protected virtual CharacterCameraParams GetCameraParams()
		{
			return cameraParams;
		}

		protected virtual float GetScopeEntryDuration()
		{
			return 0f;
		}
	}
	public class BaseWindUp : BaseScopeState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string enterSoundString;

		private float duration;

		public override void OnEnter()
		{
			duration = baseDuration;
			base.OnEnter();
			SetScopeAlpha(0f);
			StartScopeParamsOverride(duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void OnExit()
		{
			EndScopeParamsOverride(0f);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				BaseActive nextState = GetNextState();
				nextState.activatorSkillSlot = base.activatorSkillSlot;
				outer.SetNextState(nextState);
			}
		}

		public override void Update()
		{
			base.Update();
			SetScopeAlpha(Mathf.Clamp01(base.age / duration));
		}

		protected virtual BaseActive GetNextState()
		{
			return new BaseActive();
		}

		protected override float GetScopeEntryDuration()
		{
			return duration;
		}

		public override void ModifyNextState(EntityState nextState)
		{
		}
	}
	public class BaseWindDown : BaseScopeState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string enterSoundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			SetScopeAlpha(1f);
			RemoveOverlay(duration);
			StartScopeParamsOverride(0f);
			EndScopeParamsOverride(duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void Update()
		{
			base.Update();
			SetScopeAlpha(1f - Mathf.Clamp01(base.age / duration));
		}

		protected override CharacterCameraParams GetCameraParams()
		{
			return null;
		}
	}
	public class BaseActive : BaseScopeState
	{
		[SerializeField]
		public SkillDef primaryOverride;

		[SerializeField]
		public LoopSoundDef loopSound;

		private GenericSkill overriddenSkill;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		public override void OnEnter()
		{
			base.OnEnter();
			SetScopeAlpha(1f);
			StartScopeParamsOverride(0f);
			GenericSkill genericSkill = base.skillLocator?.primary;
			if ((bool)genericSkill)
			{
				TryOverrideSkill(genericSkill);
				genericSkill.onSkillChanged += TryOverrideSkill;
			}
			if (base.isAuthority)
			{
				loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSound);
			}
		}

		public override void OnExit()
		{
			if (loopPtr.isValid)
			{
				LoopSoundManager.StopSoundLoopLocal(loopPtr);
			}
			GenericSkill genericSkill = base.skillLocator?.primary;
			if ((bool)genericSkill)
			{
				genericSkill.onSkillChanged -= TryOverrideSkill;
			}
			if ((bool)overriddenSkill)
			{
				overriddenSkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
			}
			EndScopeParamsOverride(0f);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (!IsKeyDownAuthority() || base.characterBody.isSprinting))
			{
				outer.SetNextState(GetNextState());
			}
		}

		private void TryOverrideSkill(GenericSkill skill)
		{
			if ((bool)skill && !overriddenSkill && !skill.HasSkillOverrideOfPriority(GenericSkill.SkillOverridePriority.Contextual))
			{
				overriddenSkill = skill;
				overriddenSkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
				overriddenSkill.stock = base.skillLocator.secondary.stock;
			}
		}

		protected virtual BaseWindDown GetNextState()
		{
			return new BaseWindDown();
		}
	}
	public class WindDownScopeHeavy : BaseWindDown
	{
	}
	public class WindDownScopeLight : BaseWindDown
	{
	}
	public class WindUpScopeHeavy : BaseWindUp
	{
		protected override BaseActive GetNextState()
		{
			return new ActiveScopeHeavy();
		}
	}
	public class WindUpScopeLight : BaseWindUp
	{
		protected override BaseActive GetNextState()
		{
			return new ActiveScopeLight();
		}
	}
}
namespace EntityStates.Railgunner.Reload
{
	public class BoostConfirm : EntityState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		public OverlayController overlayController;

		private GenericSkill primarySkill;

		public SkillDef primaryOverride;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			if (overlayController == null)
			{
				return;
			}
			foreach (GameObject instances in overlayController.instancesList)
			{
				ActiveReloadBarController component = instances.GetComponent<ActiveReloadBarController>();
				if ((bool)component)
				{
					component.SetWasWindowHit(wasWindowHit: true);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new Boosted());
			}
		}

		public override void OnExit()
		{
			if (overlayController != null)
			{
				HudOverlayManager.RemoveOverlay(overlayController);
			}
			if ((bool)primarySkill)
			{
				primarySkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
			}
			base.OnExit();
		}

		public void OverridePrimary(GenericSkill skill, SkillDef overrideDef)
		{
			primarySkill = skill;
			primaryOverride = overrideDef;
			primarySkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
		}
	}
	public class Boosted : BaseState
	{
		[SerializeField]
		public float bonusDamageCoefficient;

		[SerializeField]
		public string boostConsumeSoundString;

		[SerializeField]
		public GameObject overlayPrefab;

		[SerializeField]
		public string overlayChildLocatorEntry;

		private OverlayController overlayController;

		public float GetBonusDamage()
		{
			return bonusDamageCoefficient * damageStat;
		}

		public void ConsumeBoost(bool queueReload)
		{
			Util.PlaySound(boostConsumeSoundString, base.gameObject);
			outer.SetNextState(new Waiting(queueReload));
		}

		public override void OnEnter()
		{
			base.OnEnter();
			OverlayCreationParams overlayCreationParams = default(OverlayCreationParams);
			overlayCreationParams.prefab = overlayPrefab;
			overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry;
			OverlayCreationParams overlayCreationParams2 = overlayCreationParams;
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2);
		}

		public override void OnExit()
		{
			HudOverlayManager.RemoveOverlay(overlayController);
			base.OnExit();
		}
	}
	public class Reloading : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float boostWindowDelay;

		[SerializeField]
		public float boostWindowDuration;

		[SerializeField]
		public float boostGracePeriod;

		[SerializeField]
		public SkillDef primaryOverride;

		[SerializeField]
		public GameObject overlayPrefab;

		[SerializeField]
		public string overlayChildLocatorEntry;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public LoopSoundDef loopSoundDef;

		[SerializeField]
		public string endNoBoostSoundString;

		[SerializeField]
		public string failSoundString;

		private float duration;

		private float adjustedBoostWindowDelay;

		private float adjustedBoostWindowDuration;

		private GenericSkill primarySkill;

		private OverlayController overlayController;

		private List<ActiveReloadBarController> reloadUiList = new List<ActiveReloadBarController>();

		private bool hasAttempted;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		public bool AttemptBoost()
		{
			if (IsInBoostWindow())
			{
				outer.SetNextState(new BoostConfirm());
				return true;
			}
			foreach (ActiveReloadBarController reloadUi in reloadUiList)
			{
				reloadUi.SetWasFailure(wasFailure: true);
			}
			return false;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			float num = boostWindowDelay + boostWindowDuration;
			float num2 = baseDuration - num;
			duration = num + num2 / attackSpeedStat;
			adjustedBoostWindowDelay = Mathf.Min(boostWindowDelay / baseDuration * duration, boostWindowDelay);
			adjustedBoostWindowDuration = Mathf.Max((boostWindowDelay + boostWindowDuration) / baseDuration * duration, num) - adjustedBoostWindowDelay;
			if ((bool)loopSoundDef)
			{
				loopPtr = LoopSoundManager.PlaySoundLoopLocalRtpc(base.gameObject, loopSoundDef, "attackSpeed", Util.CalculateAttackSpeedRtpcValue(attackSpeedStat));
			}
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			SkillLocator component = base.gameObject.GetComponent<SkillLocator>();
			if ((bool)component && (bool)component.primary)
			{
				primarySkill = component.primary;
				primarySkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
			}
			OverlayCreationParams overlayCreationParams = default(OverlayCreationParams);
			overlayCreationParams.prefab = overlayPrefab;
			overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry;
			OverlayCreationParams overlayCreationParams2 = overlayCreationParams;
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2);
			overlayController.onInstanceAdded += OnOverlayInstanceAdded;
			overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float num = ((duration > 0f) ? (base.fixedAge / duration) : 0f);
			foreach (ActiveReloadBarController reloadUi in reloadUiList)
			{
				reloadUi.SetTValue(num);
				reloadUi.SetIsWindowActive(IsInBoostWindow());
			}
			if (duration <= 0f || num >= 1f)
			{
				Util.PlaySound(endNoBoostSoundString, base.gameObject);
				outer.SetNextState(new Waiting());
			}
			if ((bool)base.inputBank && base.inputBank.skill1.justPressed && !hasAttempted)
			{
				hasAttempted = true;
				if (!AttemptBoost())
				{
					Util.PlaySound(failSoundString, base.gameObject);
				}
			}
		}

		public override void OnExit()
		{
			if (overlayController != null)
			{
				overlayController.onInstanceAdded -= OnOverlayInstanceAdded;
				overlayController.onInstanceRemove -= OnOverlayInstanceRemoved;
				reloadUiList.Clear();
			}
			if ((bool)base.skillLocator)
			{
				primarySkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
			}
			for (int i = 0; i < base.skillLocator.skillSlotCount; i++)
			{
				GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i);
				if ((bool)skillAtIndex)
				{
					RailgunSkillDef railgunSkillDef = skillAtIndex.skillDef as RailgunSkillDef;
					if ((bool)railgunSkillDef && railgunSkillDef.restockOnReload)
					{
						skillAtIndex.stock = skillAtIndex.maxStock;
					}
				}
			}
			if (loopPtr.isValid)
			{
				LoopSoundManager.StopSoundLoopLocal(loopPtr);
			}
			base.OnExit();
		}

		public bool IsInBoostWindow()
		{
			if (adjustedBoostWindowDelay - base.fixedAge < boostGracePeriod)
			{
				return base.fixedAge - (adjustedBoostWindowDelay + adjustedBoostWindowDuration) < boostGracePeriod;
			}
			return false;
		}

		public override void ModifyNextState(EntityState nextState)
		{
			if (nextState is BoostConfirm boostConfirm)
			{
				boostConfirm.overlayController = overlayController;
				if ((bool)primarySkill)
				{
					boostConfirm.OverridePrimary(primarySkill, primaryOverride);
				}
			}
			else if (overlayController != null)
			{
				HudOverlayManager.RemoveOverlay(overlayController);
			}
		}

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			ActiveReloadBarController component = instance.GetComponent<ActiveReloadBarController>();
			float num = ((duration > 0f) ? (1f / duration) : 0f);
			component.SetWindowRange(num * adjustedBoostWindowDelay, num * (adjustedBoostWindowDelay + adjustedBoostWindowDuration));
			reloadUiList.Add(component);
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			ActiveReloadBarController component = instance.GetComponent<ActiveReloadBarController>();
			reloadUiList.Remove(component);
		}
	}
	public class Waiting : EntityState
	{
		private const string backpackStateMachineName = "Backpack";

		private const string scopeStateMachineName = "Scope";

		private List<GenericSkill> restockOnReloadList = new List<GenericSkill>();

		private EntityStateMachine backpackStateMachine;

		private EntityStateMachine scopeStateMachine;

		private bool isReloadQueued;

		public Waiting()
		{
			isReloadQueued = false;
		}

		public Waiting(bool queueReload)
		{
			isReloadQueued = queueReload;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.skillLocator)
			{
				for (int i = 0; i < base.skillLocator.skillSlotCount; i++)
				{
					GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i);
					if ((bool)skillAtIndex)
					{
						skillAtIndex.onSkillChanged += OnSkillChanged;
					}
				}
				ReevaluateSkills();
			}
			backpackStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Backpack");
			scopeStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Scope");
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!isReloadQueued)
			{
				foreach (GenericSkill restockOnReload in restockOnReloadList)
				{
					if (restockOnReload.stock == 0)
					{
						isReloadQueued = true;
						break;
					}
				}
			}
			if (isReloadQueued && CanReload())
			{
				outer.SetNextState(new Reloading());
			}
		}

		public override void OnExit()
		{
			if ((bool)base.skillLocator)
			{
				for (int i = 0; i < base.skillLocator.skillSlotCount; i++)
				{
					GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i);
					if ((bool)skillAtIndex)
					{
						skillAtIndex.onSkillChanged -= OnSkillChanged;
					}
				}
			}
			base.OnExit();
		}

		public bool CanReload()
		{
			if (!(backpackStateMachine.state is Offline))
			{
				return scopeStateMachine.IsInMainState();
			}
			return false;
		}

		public void QueueReload()
		{
			isReloadQueued = true;
		}

		private void OnSkillChanged(GenericSkill skill)
		{
			ReevaluateSkills();
		}

		private void ReevaluateSkills()
		{
			restockOnReloadList.Clear();
			for (int i = 0; i < base.skillLocator.skillSlotCount; i++)
			{
				GenericSkill skillAtIndex = base.skillLocator.GetSkillAtIndex(i);
				if ((bool)skillAtIndex)
				{
					RailgunSkillDef railgunSkillDef = skillAtIndex.skillDef as RailgunSkillDef;
					if ((bool)railgunSkillDef && railgunSkillDef.restockOnReload)
					{
						restockOnReloadList.Add(skillAtIndex);
					}
				}
			}
		}
	}
}
namespace EntityStates.Railgunner.Backpack
{
	public abstract class BaseBackpack : BaseState
	{
		[SerializeField]
		public LoopSoundDef loopSoundDef;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string mecanimBoolName;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		protected bool isSoundScaledByAttackSpeed;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)loopSoundDef)
			{
				if (isSoundScaledByAttackSpeed)
				{
					loopPtr = LoopSoundManager.PlaySoundLoopLocalRtpc(base.gameObject, loopSoundDef, "attackSpeed", Util.CalculateAttackSpeedRtpcValue(attackSpeedStat));
				}
				else
				{
					loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef);
				}
			}
			if (!string.IsNullOrEmpty(enterSoundString))
			{
				if (isSoundScaledByAttackSpeed)
				{
					Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
				}
				else
				{
					Util.PlaySound(enterSoundString, base.gameObject);
				}
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator && !string.IsNullOrEmpty(mecanimBoolName))
			{
				modelAnimator.SetBool(mecanimBoolName, value: true);
			}
		}

		public override void OnExit()
		{
			if (loopPtr.isValid)
			{
				LoopSoundManager.StopSoundLoopLocal(loopPtr);
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator && !string.IsNullOrEmpty(mecanimBoolName))
			{
				modelAnimator.SetBool(mecanimBoolName, value: false);
			}
			base.OnExit();
		}
	}
	public abstract class BaseCharged : BaseBackpack
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public SkillDef primaryOverride;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public GameObject overlayPrefab;

		[SerializeField]
		public string overlayChildLocatorEntry;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private OverlayController overlayController;

		private GenericSkill primarySkill;

		private List<ImageFillController> fillUiList = new List<ImageFillController>();

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			SkillLocator component = base.gameObject.GetComponent<SkillLocator>();
			if ((bool)component && (bool)component.primary)
			{
				primarySkill = component.primary;
				primarySkill.SetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
			}
			OverlayCreationParams overlayCreationParams = default(OverlayCreationParams);
			overlayCreationParams.prefab = overlayPrefab;
			overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry;
			OverlayCreationParams overlayCreationParams2 = overlayCreationParams;
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2);
			overlayController.onInstanceAdded += OnOverlayInstanceAdded;
			overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.PrioritySkill);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (duration > 0f)
			{
				foreach (ImageFillController fillUi in fillUiList)
				{
					fillUi.SetTValue(1f - base.fixedAge / duration);
				}
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(InstantiateExpiredState());
			}
			base.characterBody.SetAimTimer(3f);
		}

		public override void OnExit()
		{
			crosshairOverrideRequest?.Dispose();
			if (overlayController != null)
			{
				overlayController.onInstanceAdded -= OnOverlayInstanceAdded;
				overlayController.onInstanceRemove -= OnOverlayInstanceRemoved;
				fillUiList.Clear();
				HudOverlayManager.RemoveOverlay(overlayController);
			}
			if ((bool)base.skillLocator)
			{
				primarySkill.UnsetSkillOverride(this, primaryOverride, GenericSkill.SkillOverridePriority.Contextual);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}

		protected abstract EntityState InstantiateExpiredState();

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			fillUiList.Add(instance.GetComponent<ImageFillController>());
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			fillUiList.Remove(instance.GetComponent<ImageFillController>());
		}
	}
	public abstract class BaseCharging : BaseBackpack
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public GameObject overlayPrefab;

		[SerializeField]
		public string overlayChildLocatorEntry;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private OverlayController overlayController;

		private List<ImageFillController> fillUiList = new List<ImageFillController>();

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private float duration;

		public override void OnEnter()
		{
			isSoundScaledByAttackSpeed = true;
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			OverlayCreationParams overlayCreationParams = default(OverlayCreationParams);
			overlayCreationParams.prefab = overlayPrefab;
			overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry;
			OverlayCreationParams overlayCreationParams2 = overlayCreationParams;
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2);
			overlayController.onInstanceAdded += OnOverlayInstanceAdded;
			overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.PrioritySkill);
			}
		}

		public override void OnExit()
		{
			crosshairOverrideRequest?.Dispose();
			if (overlayController != null)
			{
				overlayController.onInstanceAdded -= OnOverlayInstanceAdded;
				overlayController.onInstanceRemove -= OnOverlayInstanceRemoved;
				fillUiList.Clear();
				HudOverlayManager.RemoveOverlay(overlayController);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (duration > 0f)
			{
				foreach (ImageFillController fillUi in fillUiList)
				{
					fillUi.SetTValue(base.fixedAge / duration);
				}
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(InstantiateChargedState());
			}
		}

		protected abstract EntityState InstantiateChargedState();

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			fillUiList.Add(instance.GetComponent<ImageFillController>());
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			fillUiList.Remove(instance.GetComponent<ImageFillController>());
		}
	}
	public abstract class BaseExpired : BaseBackpack
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public bool forceShieldRegen;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if (forceShieldRegen)
			{
				base.characterBody?.healthComponent?.ForceShieldRegen();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(InstantiateNextState());
			}
		}

		protected abstract EntityState InstantiateNextState();

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public abstract class BaseOnline : BaseBackpack
	{
		[SerializeField]
		public SkillDef requiredSkillDef;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string cooldownParamName;

		private int animationStateHash;

		private int cooldownParamHash;

		private Animator animator;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			animator = GetModelAnimator();
			cooldownParamHash = Animator.StringToHash(cooldownParamName);
			animationStateHash = Animator.StringToHash(animationStateName);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((object)base.skillLocator.special.skillDef != requiredSkillDef)
			{
				outer.SetNextState(new Disconnected());
			}
			else if ((bool)animator)
			{
				float num = base.skillLocator.special.CalculateFinalRechargeInterval();
				float value = 0f;
				if (num > 0f)
				{
					value = base.skillLocator.special.cooldownRemaining / num;
				}
				animator.SetFloat(cooldownParamHash, value);
			}
		}

		public override void OnExit()
		{
			if ((bool)animator)
			{
				animator.SetFloat(cooldownParamHash, 0f);
			}
			base.OnExit();
		}
	}
	public class ChargedCryo : BaseCharged
	{
		protected override EntityState InstantiateExpiredState()
		{
			return new ExpiredCryo();
		}
	}
	public class ChargedSuper : BaseCharged
	{
		protected override EntityState InstantiateExpiredState()
		{
			return new ExpiredSuper();
		}
	}
	public class ChargingCryo : BaseCharging
	{
		protected override EntityState InstantiateChargedState()
		{
			return new ChargedCryo();
		}
	}
	public class ChargingSuper : BaseCharging
	{
		protected override EntityState InstantiateChargedState()
		{
			return new ChargedSuper();
		}
	}
	public class Disconnected : BaseBackpack
	{
		[SerializeField]
		public SkillDef superSkillDef;

		[SerializeField]
		public SkillDef cryoSkillDef;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((object)base.skillLocator.special.skillDef == superSkillDef)
			{
				outer.SetNextState(new OnlineSuper());
			}
			else if ((object)base.skillLocator.special.skillDef == cryoSkillDef)
			{
				outer.SetNextState(new OnlineCryo());
			}
		}
	}
	public class ExpiredCryo : BaseExpired
	{
		protected override EntityState InstantiateNextState()
		{
			return new OnlineCryo();
		}
	}
	public class ExpiredSuper : BaseExpired
	{
		protected override EntityState InstantiateNextState()
		{
			return new OnlineSuper();
		}
	}
	public class Offline : BaseBackpack
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public GameObject overlayPrefab;

		[SerializeField]
		public string overlayChildLocatorEntry;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private OverlayController overlayController;

		private List<ImageFillController> fillUiList = new List<ImageFillController>();

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			OverlayCreationParams overlayCreationParams = default(OverlayCreationParams);
			overlayCreationParams.prefab = overlayPrefab;
			overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry;
			OverlayCreationParams overlayCreationParams2 = overlayCreationParams;
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2);
			overlayController.onInstanceAdded += OnOverlayInstanceAdded;
			overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new Reboot());
			}
			if (!(duration > 0f))
			{
				return;
			}
			foreach (ImageFillController fillUi in fillUiList)
			{
				fillUi.SetTValue(base.fixedAge / duration);
			}
		}

		public override void OnExit()
		{
			crosshairOverrideRequest?.Dispose();
			if (overlayController != null)
			{
				overlayController.onInstanceAdded -= OnOverlayInstanceAdded;
				overlayController.onInstanceRemove -= OnOverlayInstanceRemoved;
				fillUiList.Clear();
				HudOverlayManager.RemoveOverlay(overlayController);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			fillUiList.Add(instance.GetComponent<ImageFillController>());
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			fillUiList.Remove(instance.GetComponent<ImageFillController>());
		}
	}
	public class OnlineCryo : BaseOnline
	{
	}
	public class OnlineSuper : BaseOnline
	{
	}
	public class Reboot : BaseBackpack
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new OnlineSuper());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class UseCryo : BaseBackpack
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new OnlineCryo());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.QuestVolatileBattery
{
	public class QuestVolatileBatteryBaseState : BaseState
	{
		protected NetworkedBodyAttachment networkedBodyAttachment { get; private set; }

		protected HealthComponent attachedHealthComponent { get; private set; }

		protected CharacterModel attachedCharacterModel { get; private set; }

		protected Transform[] displays { get; private set; } = Array.Empty<Transform>();


		public override void OnEnter()
		{
			base.OnEnter();
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
			if (!networkedBodyAttachment || !networkedBodyAttachment.attachedBody)
			{
				return;
			}
			attachedHealthComponent = networkedBodyAttachment.attachedBody.healthComponent;
			ModelLocator modelLocator = networkedBodyAttachment.attachedBody.modelLocator;
			if ((bool)modelLocator)
			{
				Transform modelTransform = modelLocator.modelTransform;
				if ((bool)modelTransform)
				{
					attachedCharacterModel = modelTransform.GetComponent<CharacterModel>();
				}
			}
		}
	}
	public class Monitor : QuestVolatileBatteryBaseState
	{
		private float previousHealthFraction;

		private static readonly float healthFractionDetonationThreshold = 0.5f;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		private void FixedUpdateServer()
		{
			if ((bool)base.attachedHealthComponent)
			{
				float combinedHealthFraction = base.attachedHealthComponent.combinedHealthFraction;
				if (combinedHealthFraction <= healthFractionDetonationThreshold && healthFractionDetonationThreshold < previousHealthFraction)
				{
					outer.SetNextState(new CountDown());
				}
				previousHealthFraction = combinedHealthFraction;
			}
		}
	}
	public class CountDown : QuestVolatileBatteryBaseState
	{
		public static float duration;

		public static GameObject vfxPrefab;

		public static float explosionRadius;

		public static GameObject explosionEffectPrefab;

		private GameObject[] vfxInstances = Array.Empty<GameObject>();

		private bool detonated;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!vfxPrefab || !base.attachedCharacterModel)
			{
				return;
			}
			List<GameObject> equipmentDisplayObjects = base.attachedCharacterModel.GetEquipmentDisplayObjects(RoR2Content.Equipment.QuestVolatileBattery.equipmentIndex);
			if (equipmentDisplayObjects.Count > 0)
			{
				vfxInstances = new GameObject[equipmentDisplayObjects.Count];
				for (int i = 0; i < vfxInstances.Length; i++)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(vfxPrefab, equipmentDisplayObjects[i].transform);
					gameObject.transform.localPosition = UnityEngine.Vector3.zero;
					gameObject.transform.localRotation = UnityEngine.Quaternion.identity;
					vfxInstances[i] = gameObject;
				}
			}
		}

		public override void OnExit()
		{
			GameObject[] array = vfxInstances;
			for (int i = 0; i < array.Length; i++)
			{
				EntityState.Destroy(array[i]);
			}
			vfxInstances = Array.Empty<GameObject>();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		private void FixedUpdateServer()
		{
			if (base.fixedAge >= duration && !detonated)
			{
				detonated = true;
				Detonate();
			}
		}

		public void Detonate()
		{
			if ((bool)base.networkedBodyAttachment.attachedBody)
			{
				UnityEngine.Vector3 corePosition = base.networkedBodyAttachment.attachedBody.corePosition;
				float baseDamage = 0f;
				if ((bool)base.attachedHealthComponent)
				{
					baseDamage = base.attachedHealthComponent.fullCombinedHealth * 3f;
				}
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = corePosition,
					scale = explosionRadius
				}, transmit: true);
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.position = corePosition + UnityEngine.Random.onUnitSphere;
				blastAttack.radius = explosionRadius;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.attacker = base.networkedBodyAttachment.attachedBodyObject;
				blastAttack.inflictor = base.networkedBodyAttachment.gameObject;
				blastAttack.damageColorIndex = DamageColorIndex.Item;
				blastAttack.baseDamage = baseDamage;
				blastAttack.baseForce = 5000f;
				blastAttack.bonusForce = UnityEngine.Vector3.zero;
				blastAttack.attackerFiltering = AttackerFiltering.AlwaysHit;
				blastAttack.crit = false;
				blastAttack.procChainMask = default(ProcChainMask);
				blastAttack.procCoefficient = 0f;
				blastAttack.teamIndex = base.networkedBodyAttachment.attachedBody.teamComponent.teamIndex;
				blastAttack.Fire();
				base.networkedBodyAttachment.attachedBody.inventory.SetEquipmentIndex(EquipmentIndex.None);
				outer.SetNextState(new Idle());
			}
		}
	}
}
namespace EntityStates.Pot.PotWeapon
{
	public class FireCannon : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject projectilePrefab;

		public static float selfForce = 1000f;

		public static int grenadeCountMax = 3;

		public static float damageCoefficient;

		public static float fireDuration = 1f;

		public static float baseDuration = 2f;

		public static float minSpread = 0f;

		public static float maxSpread = 5f;

		public static float arcAngle = 5f;

		private Ray aimRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		private void FireBullet(string targetMuzzle)
		{
			aimRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						base.rigidbody.AddForceAtPosition(transform.forward * selfForce, transform.position, ForceMode.Impulse);
					}
				}
			}
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				float x = UnityEngine.Random.Range(minSpread, maxSpread);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle;
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			aimRay = GetAimRay();
			StartAimMode(aimRay);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			fireTimer -= GetDeltaTime();
			float num = fireDuration / attackSpeedStat / (float)grenadeCountMax;
			if (fireTimer <= 0f && grenadeCount < grenadeCountMax)
			{
				fireTimer += num;
				if (grenadeCount % 2 == 0)
				{
					FireBullet("MuzzleLeft");
					PlayCrossfade("Gesture, Left Cannon", "FireGrenadeLeft", 0.1f);
				}
				else
				{
					FireBullet("MuzzleRight");
					PlayCrossfade("Gesture, Right Cannon", "FireGrenadeRight", 0.1f);
				}
				grenadeCount++;
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.ParentPod
{
	public class DeathState : GenericCharacterDeath
	{
		public static float deathAnimTimer;

		private float mDeathAnimTimer;

		public static GameObject deathEffect;

		private bool printingStarted;

		public override void OnEnter()
		{
			base.OnEnter();
			mDeathAnimTimer = deathAnimTimer;
			EffectManager.SimpleEffect(deathEffect, base.gameObject.transform.position, base.transform.rotation, transmit: false);
		}

		public override void FixedUpdate()
		{
			mDeathAnimTimer -= Time.deltaTime;
			if (mDeathAnimTimer <= 0f && !printingStarted)
			{
				printingStarted = true;
				PrintController printController = GetComponent<ModelLocator>().modelTransform.gameObject.AddComponent<PrintController>();
				printController.enabled = false;
				printController.printTime = 1f;
				printController.startingPrintHeight = 99999f;
				printController.maxPrintHeight = 99999f;
				printController.startingPrintBias = 0.95f;
				printController.maxPrintBias = 1.95f;
				printController.animateFlowmapPower = true;
				printController.startingFlowmapPower = 1.14f;
				printController.maxFlowmapPower = 30f;
				printController.disableWhenFinished = false;
				printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
				printController.enabled = true;
			}
			if (printingStarted)
			{
				base.FixedUpdate();
			}
		}
	}
}
namespace EntityStates.ParentEgg
{
	public class BaseEggState : BaseState
	{
		protected SpawnerPodsController controller { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			controller = GetComponent<SpawnerPodsController>();
		}
	}
	public class Death : GenericCharacterDeath
	{
		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			GetComponent<SpawnerPodsController>().Dissolve();
		}
	}
	public class Hatch : GenericCharacterDeath
	{
		private SpawnerPodsController controller;

		private static int HatchStateHash = Animator.StringToHash("Hatch");

		public override void OnEnter()
		{
			controller = GetComponent<SpawnerPodsController>();
			base.OnEnter();
			if (NetworkServer.active)
			{
				DoHatch();
			}
		}

		protected override void PlayDeathAnimation(float crossfadeDuration)
		{
			PlayAnimation("Body", HatchStateHash);
			EffectManager.SimpleEffect(controller.hatchEffect, base.gameObject.transform.position, base.transform.rotation, transmit: false);
		}

		protected override void PlayDeathSound()
		{
			Util.PlaySound(controller.podHatchSound, base.gameObject);
		}

		private void DoHatch()
		{
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/CharacterSpawnCards/cscParent"), new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Direct,
				minDistance = 0f,
				maxDistance = 1f,
				spawnOnTarget = base.transform
			}, RoR2Application.rng);
			directorSpawnRequest.summonerBodyObject = base.gameObject;
			directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, new Action<SpawnCard.SpawnResult>(OnHatchlingSpawned));
			DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
		}

		private void OnHatchlingSpawned(SpawnCard.SpawnResult spawnResult)
		{
			CharacterMaster component = spawnResult.spawnedInstance.GetComponent<CharacterMaster>();
			component.teamIndex = base.characterBody.teamComponent.teamIndex;
			CharacterMaster master = base.characterBody.master;
			CharacterMaster characterMaster = (master ? master.minionOwnership.ownerMaster : null);
			if ((bool)component)
			{
				RoR2.Inventory inventory = base.characterBody.master.inventory;
				RoR2.Inventory inventory2 = component.inventory;
				inventory2.CopyItemsFrom(inventory);
				inventory2.CopyEquipmentFrom(inventory);
				GameObject bodyObject = component.GetBodyObject();
				if ((bool)bodyObject && (bool)characterMaster)
				{
					Deployable component2 = bodyObject.GetComponent<Deployable>();
					characterMaster.AddDeployable(component2, DeployableSlot.ParentAlly);
				}
			}
		}
	}
	public class IncubateState : BaseEggState
	{
		private float duration;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = base.controller.incubationDuration;
			PlayAnimation("Body", SpawnStateHash);
			Util.PlaySound(base.controller.podSpawnSound, base.gameObject);
			EffectManager.SimpleEffect(base.controller.spawnEffect, base.gameObject.transform.position, base.transform.rotation, transmit: true);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new PreHatch());
			}
		}
	}
	public class PreHatch : BaseEggState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			GetComponent<CharacterDeathBehavior>().deathState = new SerializableEntityStateType(typeof(Hatch));
			if (NetworkServer.active)
			{
				base.healthComponent.Suicide();
			}
		}
	}
}
namespace EntityStates.ParentMonster
{
	public class DeathState : GenericCharacterDeath
	{
		[SerializeField]
		public float timeBeforeDestealth = 2.5f;

		[SerializeField]
		public float destealthDuration;

		[SerializeField]
		public Material destealthMaterial;

		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public string effectMuzzleString;

		private bool destealth;

		protected override bool shouldAutoDestroy
		{
			get
			{
				if (destealth)
				{
					return base.fixedAge > timeBeforeDestealth + destealthDuration;
				}
				return false;
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > timeBeforeDestealth && !destealth)
			{
				DoDestealth();
			}
			if (destealth && base.fixedAge > timeBeforeDestealth + destealthDuration)
			{
				DestroyModel();
			}
		}

		private void DoDestealth()
		{
			destealth = true;
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, effectMuzzleString, transmit: false);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				CharacterModel component = modelTransform.gameObject.GetComponent<CharacterModel>();
				if ((bool)destealthMaterial)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
					temporaryOverlayInstance.duration = destealthDuration;
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = destealthMaterial;
					temporaryOverlayInstance.inspectorCharacterModel = component;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.animateShaderAlpha = true;
					PrintController component2 = base.modelLocator.modelTransform.gameObject.GetComponent<PrintController>();
					component2.enabled = false;
					component2.printTime = destealthDuration;
					component2.startingPrintHeight = 0f;
					component2.maxPrintHeight = 20f;
					component2.startingPrintBias = 0f;
					component2.maxPrintBias = 2f;
					component2.disableWhenFinished = false;
					component2.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
					component2.enabled = true;
				}
				Transform transform = FindModelChild("CoreLight");
				if ((bool)transform)
				{
					transform.gameObject.SetActive(value: false);
				}
			}
		}
	}
	public class GroundSlam : BaseState
	{
		public static float duration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float radius = 3f;

		private BlastAttack attack;

		public static string attackSoundString;

		public static GameObject slamImpactEffect;

		public static GameObject meleeTrailEffectL;

		public static GameObject meleeTrailEffectR;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasAttacked;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			PlayCrossfade("Body", "Slam", "Slam.playbackRate", duration, 0.1f);
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && modelAnimator.GetFloat("Slam.hitBoxActive") > 0.5f && !hasAttacked)
			{
				if (base.isAuthority)
				{
					if ((bool)base.characterDirection)
					{
						base.characterDirection.moveVector = base.characterDirection.forward;
					}
					if ((bool)modelTransform)
					{
						Transform transform = FindModelChild("SlamZone");
						if ((bool)transform)
						{
							attack = new BlastAttack();
							attack.attacker = base.gameObject;
							attack.inflictor = base.gameObject;
							attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
							attack.baseDamage = damageStat * damageCoefficient;
							attack.baseForce = forceMagnitude;
							attack.position = transform.position;
							attack.radius = radius;
							attack.Fire();
						}
					}
				}
				hasAttacked = true;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class LoomingPresence : BaseState
	{
		private Transform modelTransform;

		public static GameObject blinkPrefab;

		public static Material destealthMaterial;

		private float stopwatch;

		private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero;

		public static float duration = 0.3f;

		public static float blinkDistance = 25f;

		public static string beginSoundString;

		public static string endSoundString;

		public static float destealthDuration;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
			if (base.isAuthority)
			{
				UnityEngine.Vector3 vector = base.inputBank.aimDirection * blinkDistance;
				blinkDestination = base.transform.position;
				blinkStart = base.transform.position;
				NodeGraph groundNodes = SceneInfo.instance.groundNodes;
				NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(base.transform.position + vector, base.characterBody.hullClassification);
				groundNodes.GetNodePosition(nodeIndex, out blinkDestination);
				blinkDestination += base.transform.position - base.characterBody.footPosition;
				vector = blinkDestination - blinkStart;
				CreateBlinkEffect(Util.GetCorePosition(base.gameObject), vector);
			}
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin, UnityEngine.Vector3 direction)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(direction);
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: true);
		}

		private void SetPosition(UnityEngine.Vector3 newPosition)
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			SetPosition(UnityEngine.Vector3.Lerp(blinkStart, blinkDestination, stopwatch / duration));
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(endSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)base.characterDirection)
			{
				base.characterDirection.forward = GetAimRay().direction;
			}
			if ((bool)modelTransform && (bool)destealthMaterial)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance.duration = destealthDuration;
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = destealthMaterial;
				temporaryOverlayInstance.inspectorCharacterModel = modelTransform.gameObject.GetComponent<CharacterModel>();
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.animateShaderAlpha = true;
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = true;
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : EntityState
	{
		public static float duration = 2f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private ParentEnergyFXController FXController;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			GetModelAnimator();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			if ((bool)spawnEffectPrefab)
			{
				EffectData effectData = new EffectData
				{
					origin = base.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("SpawnEffectOrigin").position
				};
				EffectManager.SpawnEffect(spawnEffectPrefab, effectData, transmit: true);
			}
			PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent<PrintController>();
			component.enabled = false;
			component.printTime = duration;
			component.startingPrintHeight = 4f;
			component.maxPrintHeight = -1f;
			component.startingPrintBias = 2f;
			component.maxPrintBias = 0.95f;
			component.disableWhenFinished = true;
			component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
			component.enabled = true;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Paladin
{
	public class DashSlam : BaseState
	{
		private float stopwatch;

		public static float damageCoefficient = 4f;

		public static float baseForceMagnitude = 16f;

		public static float bonusImpactForce;

		public static string initialAttackSoundString;

		public static GameObject chargeEffectPrefab;

		public static GameObject slamEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static float initialSpeedCoefficient;

		public static float finalSpeedCoefficient;

		public static float duration;

		public static float overlapSphereRadius;

		public static float blastAttackRadius;

		private BlastAttack attack;

		private Transform modelTransform;

		private GameObject leftHandChargeEffect;

		private GameObject rightHandChargeEffect;

		private ChildLocator modelChildLocator;

		private UnityEngine.Vector3 initialAimVector;

		private void EnableIndicator(string childLocatorName, ChildLocator childLocator = null)
		{
			if (!childLocator)
			{
				childLocator = GetModelTransform().GetComponent<ChildLocator>();
			}
			Transform transform = childLocator.FindChild(childLocatorName);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: true);
				ObjectScaleCurve component = transform.gameObject.GetComponent<ObjectScaleCurve>();
				if ((bool)component)
				{
					component.time = 0f;
				}
			}
		}

		private void DisableIndicator(string childLocatorName, ChildLocator childLocator = null)
		{
			if (!childLocator)
			{
				childLocator = GetModelTransform().GetComponent<ChildLocator>();
			}
			Transform transform = childLocator.FindChild(childLocatorName);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: false);
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			modelTransform = GetModelTransform();
			Util.PlaySound(initialAttackSoundString, base.gameObject);
			initialAimVector = UnityEngine.Vector3.ProjectOnPlane(GetAimRay().direction, UnityEngine.Vector3.up);
			base.characterMotor.velocity.y = 0f;
			base.characterDirection.forward = initialAimVector;
			attack = new BlastAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.baseDamage = damageCoefficient * damageStat;
			attack.damageType = DamageType.Stun1s;
			attack.baseForce = baseForceMagnitude;
			attack.radius = blastAttackRadius + base.characterBody.radius;
			attack.falloffModel = BlastAttack.FalloffModel.None;
			attack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			if (!modelTransform)
			{
				return;
			}
			modelChildLocator = modelTransform.GetComponent<ChildLocator>();
			if ((bool)modelChildLocator)
			{
				GameObject original = chargeEffectPrefab;
				Transform transform = modelChildLocator.FindChild("HandL");
				Transform transform2 = modelChildLocator.FindChild("HandR");
				if ((bool)transform)
				{
					leftHandChargeEffect = UnityEngine.Object.Instantiate(original, transform);
				}
				if ((bool)transform2)
				{
					rightHandChargeEffect = UnityEngine.Object.Instantiate(original, transform2);
				}
				EnableIndicator("GroundSlamIndicator", modelChildLocator);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active)
			{
				attack.position = base.transform.position;
				attack.bonusForce = (initialAimVector + UnityEngine.Vector3.up * 0.3f) * bonusImpactForce;
				attack.Fire();
			}
			if (base.isAuthority && (bool)modelTransform)
			{
				EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "SlamZone", transmit: true);
			}
			EntityState.Destroy(leftHandChargeEffect);
			EntityState.Destroy(rightHandChargeEffect);
			DisableIndicator("GroundSlamIndicator", modelChildLocator);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (base.isAuthority)
			{
				Collider[] colliders;
				int num = HGPhysics.OverlapSphere(out colliders, base.transform.position, base.characterBody.radius + overlapSphereRadius, LayerIndex.entityPrecise.mask);
				for (int i = 0; i < num; i++)
				{
					HurtBox component = colliders[i].GetComponent<HurtBox>();
					if ((bool)component && component.healthComponent != base.healthComponent)
					{
						HGPhysics.ReturnResults(colliders);
						outer.SetNextStateToMain();
						return;
					}
				}
			}
			if ((bool)base.characterMotor)
			{
				float num2 = Mathf.Lerp(initialSpeedCoefficient, finalSpeedCoefficient, stopwatch / duration) * base.characterBody.moveSpeed;
				UnityEngine.Vector3 velocity = new UnityEngine.Vector3(initialAimVector.x * num2, 0f, initialAimVector.z * num2);
				base.characterMotor.velocity = velocity;
				base.characterMotor.moveDirection = initialAimVector;
			}
			if (stopwatch > duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class LeapSlam : BaseState
	{
		private float stopwatch;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float yBias;

		public static string initialAttackSoundString;

		public static GameObject chargeEffectPrefab;

		public static GameObject slamEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static float leapVelocityCoefficient;

		public static float verticalLeapBonusCoefficient;

		public static float minimumDuration;

		private float leapVelocity;

		private OverlapAttack attack;

		private Transform modelTransform;

		private GameObject leftHandChargeEffect;

		private GameObject rightHandChargeEffect;

		private ChildLocator modelChildLocator;

		private UnityEngine.Vector3 initialAimVector;

		private void EnableIndicator(string childLocatorName, ChildLocator childLocator = null)
		{
			if (!childLocator)
			{
				childLocator = GetModelTransform().GetComponent<ChildLocator>();
			}
			Transform transform = childLocator.FindChild(childLocatorName);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: true);
				ObjectScaleCurve component = transform.gameObject.GetComponent<ObjectScaleCurve>();
				if ((bool)component)
				{
					component.time = 0f;
				}
			}
		}

		private void DisableIndicator(string childLocatorName, ChildLocator childLocator = null)
		{
			if (!childLocator)
			{
				childLocator = GetModelTransform().GetComponent<ChildLocator>();
			}
			Transform transform = childLocator.FindChild(childLocatorName);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: false);
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			leapVelocity = base.characterBody.moveSpeed * leapVelocityCoefficient;
			modelTransform = GetModelTransform();
			Util.PlaySound(initialAttackSoundString, base.gameObject);
			initialAimVector = GetAimRay().direction;
			initialAimVector.y = Mathf.Max(initialAimVector.y, 0f);
			initialAimVector.y += yBias;
			initialAimVector = initialAimVector.normalized;
			base.characterMotor.velocity.y = leapVelocity * initialAimVector.y * verticalLeapBonusCoefficient;
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.damageType = DamageType.Stun1s;
			attack.forceVector = UnityEngine.Vector3.up * forceMagnitude;
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "GroundSlam");
			}
			if (!modelTransform)
			{
				return;
			}
			modelChildLocator = modelTransform.GetComponent<ChildLocator>();
			if ((bool)modelChildLocator)
			{
				GameObject original = chargeEffectPrefab;
				Transform transform = modelChildLocator.FindChild("HandL");
				Transform transform2 = modelChildLocator.FindChild("HandR");
				if ((bool)transform)
				{
					leftHandChargeEffect = UnityEngine.Object.Instantiate(original, transform);
				}
				if ((bool)transform2)
				{
					rightHandChargeEffect = UnityEngine.Object.Instantiate(original, transform2);
				}
				EnableIndicator("GroundSlamIndicator", modelChildLocator);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active)
			{
				attack.Fire();
			}
			if (base.isAuthority && (bool)modelTransform)
			{
				EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "SlamZone", transmit: true);
			}
			EntityState.Destroy(leftHandChargeEffect);
			EntityState.Destroy(rightHandChargeEffect);
			DisableIndicator("GroundSlamIndicator", modelChildLocator);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if ((bool)base.characterMotor)
			{
				UnityEngine.Vector3 velocity = base.characterMotor.velocity;
				UnityEngine.Vector3 velocity2 = new UnityEngine.Vector3(initialAimVector.x * leapVelocity, velocity.y, initialAimVector.z * leapVelocity);
				base.characterMotor.velocity = velocity2;
				base.characterMotor.moveDirection = initialAimVector;
			}
			if (base.characterMotor.isGrounded && stopwatch > minimumDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.Paladin.PaladinWeapon
{
	public class BarrierUp : BaseState
	{
		public static float duration = 5f;

		public static string soundEffectString;

		private float stopwatch;

		private PaladinBarrierController paladinBarrierController;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(soundEffectString, base.gameObject);
			stopwatch = 0f;
			paladinBarrierController = GetComponent<PaladinBarrierController>();
			if ((bool)paladinBarrierController)
			{
				paladinBarrierController.EnableBarrier();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)paladinBarrierController)
			{
				paladinBarrierController.DisableBarrier();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= 0.1f && !base.inputBank.skill2.down && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireBigRocket : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static string soundEffectString;

		public static float damageCoefficient;

		public static float force;

		public static float baseDuration = 2f;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(soundEffectString, base.gameObject);
			duration = baseDuration / attackSpeedStat;
			base.characterBody.AddSpreadBloom(1f);
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			string muzzleName = "MuzzleCenter";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireRocket : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static string soundEffectString;

		public static float damageCoefficient;

		public static float force;

		public static float baseDuration = 2f;

		private float duration;

		public int bulletCountCurrent = 1;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(soundEffectString, base.gameObject);
			duration = baseDuration / attackSpeedStat;
			base.characterBody.AddSpreadBloom(0.3f);
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			string muzzleName = "MuzzleCenter";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.NullifierMonster
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathBombProjectile;

		public static float duration;

		public static string muzzleName;

		private Transform muzzleTransform;

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayCrossfade("Body", "Death", "Death.playbackRate", duration, 0.1f);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
			if ((bool)muzzleTransform && base.isAuthority)
			{
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = deathBombProjectile;
				fireProjectileInfo.position = muzzleTransform.position;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat;
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				DestroyModel();
				if (NetworkServer.active)
				{
					DestroyBodyAsapServer();
				}
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "PortalEffect", transmit: false);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				modelTransform.GetComponent<PrintController>().enabled = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class AimPortalBomb : BaseState
	{
		private HurtBox target;

		public static float baseDuration;

		public static float arcMultiplier;

		private float duration;

		private UnityEngine.Vector3? pointA;

		private UnityEngine.Vector3? pointB;

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.viewer = base.characterBody;
				bullseyeSearch.searchOrigin = base.characterBody.corePosition;
				bullseyeSearch.searchDirection = base.characterBody.corePosition;
				bullseyeSearch.maxDistanceFilter = FirePortalBomb.maxDistance;
				bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam());
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
				bullseyeSearch.RefreshCandidates();
				target = bullseyeSearch.GetResults().FirstOrDefault();
				if ((bool)target)
				{
					pointA = RaycastToFloor(target.transform.position);
				}
			}
			duration = baseDuration;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority || !(base.fixedAge >= duration))
			{
				return;
			}
			EntityState entityState = null;
			if ((bool)target)
			{
				pointB = RaycastToFloor(target.transform.position);
				if (pointA.HasValue && pointB.HasValue)
				{
					Ray aimRay = GetAimRay();
					UnityEngine.Vector3 forward = pointA.Value - aimRay.origin;
					UnityEngine.Vector3 forward2 = pointB.Value - aimRay.origin;
					UnityEngine.Quaternion a = UnityEngine.Quaternion.LookRotation(forward);
					UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.LookRotation(forward2);
					UnityEngine.Quaternion value = quaternion;
					UnityEngine.Quaternion value2 = UnityEngine.Quaternion.SlerpUnclamped(a, quaternion, 1f + arcMultiplier);
					entityState = new FirePortalBomb
					{
						startRotation = value,
						endRotation = value2
					};
				}
			}
			if (entityState != null)
			{
				outer.SetNextState(entityState);
			}
			else
			{
				outer.SetNextStateToMain();
			}
		}

		private UnityEngine.Vector3? RaycastToFloor(UnityEngine.Vector3 position)
		{
			if (Physics.Raycast(new Ray(position, UnityEngine.Vector3.down), out var hitInfo, 10f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				return hitInfo.point;
			}
			return null;
		}
	}
	public class FirePortalBomb : BaseState
	{
		public static GameObject portalBombProjectileEffect;

		public static GameObject muzzleflashEffectPrefab;

		public static string muzzleString;

		public static int portalBombCount;

		public static float baseDuration;

		public static float maxDistance;

		public static float damageCoefficient;

		public static float procCoefficient;

		public static float randomRadius;

		public static float force;

		public static float minimumDistanceBetweenBombs;

		public UnityEngine.Quaternion? startRotation;

		public UnityEngine.Quaternion? endRotation;

		private float duration;

		private int bombsFired;

		private float fireTimer;

		private float fireInterval;

		private UnityEngine.Vector3 lastBombPosition;

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			StartAimMode(4f);
			if (base.isAuthority)
			{
				fireInterval = duration / (float)portalBombCount;
				fireTimer = 0f;
			}
		}

		private void FireBomb(Ray fireRay)
		{
			if (Physics.Raycast(fireRay, out var hitInfo, maxDistance, LayerIndex.world.mask))
			{
				UnityEngine.Vector3 point = hitInfo.point;
				UnityEngine.Vector3 vector = point - lastBombPosition;
				if (bombsFired > 0 && vector.sqrMagnitude < minimumDistanceBetweenBombs * minimumDistanceBetweenBombs)
				{
					point += vector.normalized * minimumDistanceBetweenBombs;
				}
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = portalBombProjectileEffect;
				fireProjectileInfo.position = point;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.force = force;
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
				lastBombPosition = point;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			fireTimer -= GetDeltaTime();
			if (fireTimer <= 0f)
			{
				fireTimer += fireInterval;
				if (startRotation.HasValue && endRotation.HasValue)
				{
					float num = 1f / ((float)portalBombCount - 1f);
					float t = (float)bombsFired * num;
					Ray aimRay = GetAimRay();
					UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Slerp(startRotation.Value, endRotation.Value, t);
					aimRay.direction = quaternion * UnityEngine.Vector3.forward;
					FireBomb(aimRay);
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
				}
				bombsFired++;
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.NewtMonster
{
	public class KickFromShop : BaseState
	{
		public static float duration = 3.5f;

		public static string attackSoundString;

		public static string stompSoundString;

		public static GameObject chargeEffectPrefab;

		public static GameObject stompEffectPrefab;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasAttacked;

		private GameObject chargeEffectInstance;

		private EffectManagerHelper _emh_chargeEffectInstance;

		public override void Reset()
		{
			base.Reset();
			modelAnimator = null;
			modelTransform = null;
			hasAttacked = false;
			chargeEffectInstance = null;
			_emh_chargeEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			PlayCrossfade("Body", "Stomp", "Stomp.playbackRate", duration, 0.1f);
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("StompMuzzle");
			if ((bool)transform)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform);
					return;
				}
				_emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform, inResetLocal: true);
				chargeEffectInstance = _emh_chargeEffectInstance.gameObject;
			}
		}

		protected void DestroyChargeEffect()
		{
			if (chargeEffectInstance != null)
			{
				if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null)
				{
					_emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance);
				}
				else
				{
					EntityState.Destroy(chargeEffectInstance);
				}
				chargeEffectInstance = null;
				_emh_chargeEffectInstance = null;
			}
		}

		public override void OnExit()
		{
			DestroyChargeEffect();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && modelAnimator.GetFloat("Stomp.hitBoxActive") > 0.5f && !hasAttacked)
			{
				Util.PlayAttackSpeedSound(stompSoundString, base.gameObject, attackSpeedStat);
				EffectManager.SimpleMuzzleFlash(stompEffectPrefab, base.gameObject, "HealthBarOrigin", transmit: false);
				if ((bool)SceneInfo.instance)
				{
					GameObject gameObject = SceneInfo.instance.transform.Find("KickOutOfShop").gameObject;
					if ((bool)gameObject)
					{
						gameObject.gameObject.SetActive(value: true);
					}
				}
				if (base.isAuthority)
				{
					HurtBoxGroup component = modelTransform.GetComponent<HurtBoxGroup>();
					if ((bool)component)
					{
						int hurtBoxesDeactivatorCounter = component.hurtBoxesDeactivatorCounter + 1;
						component.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
					}
				}
				hasAttacked = true;
				DestroyChargeEffect();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : EntityState
	{
		public static float duration = 2f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			GetModelAnimator();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "SpawnEffectOrigin", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.MoonElevator
{
	public abstract class MoonElevatorBaseState : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string enterSfxString;

		protected GenericInteraction genericInteraction;

		public virtual EntityState nextState => new Uninitialized();

		public virtual Interactability interactability => Interactability.Disabled;

		public virtual bool goToNextStateAutomatically => false;

		public virtual bool showBaseEffects => false;

		public override void OnEnter()
		{
			base.OnEnter();
			genericInteraction = GetComponent<GenericInteraction>();
			Util.PlaySound(enterSfxString, base.gameObject);
			if (NetworkServer.active)
			{
				genericInteraction.Networkinteractability = interactability;
				if (interactability == Interactability.Available)
				{
					genericInteraction.onActivation?.AddListener(OnInteractionBegin);
				}
			}
			FindModelChild("EffectBase").gameObject.SetActive(showBaseEffects);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration && base.isAuthority && goToNextStateAutomatically)
			{
				outer.SetNextState(nextState);
			}
		}

		protected virtual void OnInteractionBegin(Interactor activator)
		{
		}
	}
	public class Inactive : MoonElevatorBaseState
	{
		private static int InactiveStateHash = Animator.StringToHash("Inactive");

		public override Interactability interactability => Interactability.ConditionsNotMet;

		public override bool goToNextStateAutomatically => false;

		public override bool showBaseEffects => false;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", InactiveStateHash);
		}
	}
	public class InactiveToReady : MoonElevatorBaseState
	{
		private static int InactiveToActiveStateHash = Animator.StringToHash("InactiveToActive");

		private static int playbackRateParamHash = Animator.StringToHash("playbackRate");

		public override Interactability interactability => Interactability.Disabled;

		public override bool goToNextStateAutomatically => true;

		public override EntityState nextState => new Ready();

		public override bool showBaseEffects => true;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", InactiveToActiveStateHash, playbackRateParamHash, duration);
		}
	}
	public class Ready : MoonElevatorBaseState
	{
		private static int ReadyStateHash = Animator.StringToHash("Ready");

		public override Interactability interactability => Interactability.Available;

		public override bool goToNextStateAutomatically => false;

		public override bool showBaseEffects => true;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", ReadyStateHash);
		}

		protected override void OnInteractionBegin(Interactor activator)
		{
			base.OnInteractionBegin(activator);
			_ = base.isAuthority;
		}
	}
}
namespace EntityStates.BrotherHaunt
{
	public class FireRandomProjectiles : BaseState
	{
		public static GameObject projectilePrefab;

		public static float damageCoefficient;

		public static int initialCharges;

		public static int maximumCharges;

		public static float chargeRechargeDuration;

		public static float chanceToFirePerSecond;

		public static float projectileVerticalOffset;

		private int charges;

		private float chargeTimer;

		public override void OnEnter()
		{
			base.OnEnter();
			charges = initialCharges;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				chargeTimer -= GetDeltaTime();
				if (chargeTimer <= 0f)
				{
					chargeTimer = chargeRechargeDuration;
					charges = Mathf.Min(charges + 1, maximumCharges);
				}
				if (UnityEngine.Random.value < chanceToFirePerSecond && charges > 0)
				{
					FireProjectile();
				}
			}
		}

		private void FireProjectile()
		{
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			if ((bool)groundNodes)
			{
				List<NodeGraph.NodeIndex> activeNodesForHullMaskWithFlagConditions = groundNodes.GetActiveNodesForHullMaskWithFlagConditions(HullMask.Golem, NodeFlags.None, NodeFlags.NoCharacterSpawn);
				NodeGraph.NodeIndex nodeIndex = activeNodesForHullMaskWithFlagConditions[UnityEngine.Random.Range(0, activeNodesForHullMaskWithFlagConditions.Count)];
				charges--;
				groundNodes.GetNodePosition(nodeIndex, out var position);
				ProjectileManager.instance.FireProjectile(new FireProjectileInfo
				{
					projectilePrefab = projectilePrefab,
					owner = base.gameObject,
					damage = damageStat * damageCoefficient,
					position = position + UnityEngine.Vector3.up * projectileVerticalOffset,
					rotation = UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f)
				});
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Missions.SuperRoboBallEncounter
{
	public class Listening : EntityState
	{
		public static float delayBeforeBeginningEncounter;

		public static int eggsDestroyedToTriggerEncounter;

		private ScriptedCombatEncounter scriptedCombatEncounter;

		private List<GameObject> eggList = new List<GameObject>();

		private const float delayBeforeRegisteringEggs = 2f;

		private bool hasRegisteredEggs;

		private int previousDestroyedEggCount;

		private bool beginEncounterCountdown;

		private float encounterCountdown;

		public override void OnEnter()
		{
			base.OnEnter();
			scriptedCombatEncounter = GetComponent<ScriptedCombatEncounter>();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!NetworkServer.active)
			{
				return;
			}
			if (base.fixedAge >= 2f)
			{
				RegisterEggs();
			}
			if (!hasRegisteredEggs)
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < eggList.Count; i++)
			{
				if (eggList[i] == null)
				{
					num++;
				}
			}
			int num2 = eggsDestroyedToTriggerEncounter - 1;
			if (previousDestroyedEggCount < num2 && num >= num2)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "VULTURE_EGG_WARNING"
				});
			}
			if (num >= eggsDestroyedToTriggerEncounter && !beginEncounterCountdown)
			{
				encounterCountdown = delayBeforeBeginningEncounter;
				beginEncounterCountdown = true;
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "VULTURE_EGG_BEGIN"
				});
			}
			if (beginEncounterCountdown)
			{
				encounterCountdown -= GetDeltaTime();
				if (encounterCountdown <= 0f)
				{
					scriptedCombatEncounter.BeginEncounter();
					outer.SetNextState(new Idle());
				}
			}
			previousDestroyedEggCount = num;
		}

		private void RegisterEggs()
		{
			if (hasRegisteredEggs)
			{
				return;
			}
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				if (readOnlyInstancesList[i].name.Contains("VultureEgg"))
				{
					eggList.Add(readOnlyInstancesList[i].gameObject);
				}
			}
			hasRegisteredEggs = true;
		}
	}
}
namespace EntityStates.Missions.RaidGauntletEncounterSlowDeath
{
	public class Listening : EntityState
	{
		public static float delayBeforeBeginningEncounter;

		public static int shardsDestroyedToTriggerEncounter;

		private List<GameObject> shardList = new List<GameObject>();

		private const float delayBeforeRegisteringShards = 2f;

		private bool hasRegisteredShards;

		private int previousDestroyedShardCount;

		private bool beginEncounterCountdown;

		private bool beginGauntletCountdown;

		private bool gauntletTwentySecondWarning;

		private bool gauntletTenSecondWarning;

		private bool gauntletFiveSecondWarning;

		private bool beginGauntletFinalCountdown;

		private const float delayBeforeBeginningGauntletCountdown = 15f;

		private float gauntletFinalCountdown;

		private int secondsRemaining = 4;

		private bool gauntletEnd;

		private int totalSeconds;

		private GameObject slowDeathEffect;

		private bool slowDeathEffectActive;

		private GauntletMissionController gauntletMissionController;

		private GameObject gMC;

		private float degenTickFrequency;

		private float percentDegenPerSecond;

		private bool hasGauntletMissionController;

		private bool theEnd;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!NetworkServer.active)
			{
				return;
			}
			if (base.fixedAge >= 2f)
			{
				RegisterShards();
				RegisterGauntletMissionController();
			}
			if (base.fixedAge >= 15f && !beginGauntletCountdown)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_START"
				});
				beginGauntletCountdown = true;
			}
			if (base.fixedAge >= 25f && !gauntletTwentySecondWarning)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_TWENTY_SECONDS_WARNING"
				});
				gauntletTwentySecondWarning = true;
			}
			if (base.fixedAge >= 35f && !gauntletTenSecondWarning)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_TEN_SECONDS_WARNING"
				});
				gauntletTenSecondWarning = true;
			}
			if (base.fixedAge >= 40f && !gauntletFiveSecondWarning)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_FIVE_SECONDS_WARNING"
				});
				gauntletFiveSecondWarning = true;
				beginGauntletFinalCountdown = true;
			}
			if (!hasRegisteredShards)
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < shardList.Count; i++)
			{
				if (shardList[i] == null)
				{
					num++;
				}
			}
			if (previousDestroyedShardCount != num)
			{
				_ = shardsDestroyedToTriggerEncounter;
			}
			int num2 = shardsDestroyedToTriggerEncounter - 1;
			if (previousDestroyedShardCount < num2 && num >= num2)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_ONE_SHARD_REMAINING"
				});
			}
			if (num >= shardsDestroyedToTriggerEncounter && !beginEncounterCountdown)
			{
				beginEncounterCountdown = true;
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_ALL_SHARDS_DESTROYED"
				});
			}
			if (beginGauntletFinalCountdown && !gauntletEnd)
			{
				gauntletFinalCountdown += GetDeltaTime();
				if (gauntletFinalCountdown >= 1f)
				{
					secondsRemaining--;
					totalSeconds++;
					if (totalSeconds == 1)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_FOUR_SECONDS_REMAINING"
						});
					}
					else if (totalSeconds == 2)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_THREE_SECONDS_REMAINING"
						});
					}
					else if (totalSeconds == 3)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_TWO_SECONDS_REMAINING"
						});
					}
					else if (totalSeconds == 4)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_ONE_SECOND_REMAINING"
						});
					}
					gauntletFinalCountdown = 0f;
				}
				if (secondsRemaining == 0)
				{
					gauntletEnd = true;
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "GAUNTLET_SLOWDEATH_END"
					});
				}
			}
			if (gauntletEnd && !theEnd)
			{
				gauntletMissionController.GauntletMissionTimesUp();
				theEnd = true;
			}
			previousDestroyedShardCount = num;
		}

		private void RegisterShards()
		{
			if (hasRegisteredShards)
			{
				return;
			}
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				if (readOnlyInstancesList[i].name.Contains("GauntletShard"))
				{
					shardList.Add(readOnlyInstancesList[i].gameObject);
				}
			}
			shardsDestroyedToTriggerEncounter = shardList.Count;
			hasRegisteredShards = true;
		}

		private void RegisterGauntletMissionController()
		{
			if (!hasGauntletMissionController)
			{
				gMC = GameObject.Find("GauntletMissionController");
				gauntletMissionController = gMC.GetComponent<GauntletMissionController>();
				if ((bool)gauntletMissionController)
				{
					slowDeathEffect = gauntletMissionController.clearedEffect;
					degenTickFrequency = gauntletMissionController.degenTickFrequency;
					percentDegenPerSecond = gauntletMissionController.percentDegenPerSecond;
					hasGauntletMissionController = true;
				}
			}
		}
	}
}
namespace EntityStates.Missions.RaidGauntletEncounter
{
	public class Listening : EntityState
	{
		public static float delayBeforeBeginningEncounter;

		public static int shardsDestroyedToTriggerEncounter = 5;

		private GameObject exitPortal;

		private List<GameObject> shardList = new List<GameObject>();

		private const float delayBeforeRegisteringShards = 2f;

		private bool hasRegisteredShards;

		private int previousDestroyedShardCount;

		private bool beginEncounterCountdown;

		private bool beginGauntletCountdown;

		private bool gauntletTwentySecondWarning;

		private bool gauntletTenSecondWarning;

		private bool gauntletFiveSecondWarning;

		private bool beginGauntletFinalCountdown;

		private const float delayBeforeBeginningGauntletCountdown = 15f;

		private float gauntletFinalCountdown;

		private int secondsRemaining = 4;

		private bool gauntletEnd;

		private bool hasExitPortal;

		private int totalSeconds;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!NetworkServer.active)
			{
				return;
			}
			if (base.fixedAge >= 2f)
			{
				RegisterShards();
				RegisterExitPortal();
			}
			if (base.fixedAge >= 15f && !beginGauntletCountdown)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_START"
				});
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_FIVE_SHARDS_REMAINING"
				});
				beginGauntletCountdown = true;
			}
			if (base.fixedAge >= 25f && !gauntletTwentySecondWarning)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_TWENTY_SECONDS_WARNING"
				});
				gauntletTwentySecondWarning = true;
			}
			if (base.fixedAge >= 35f && !gauntletTenSecondWarning)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_TEN_SECONDS_WARNING"
				});
				gauntletTenSecondWarning = true;
			}
			if (base.fixedAge >= 40f && !gauntletFiveSecondWarning)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_FIVE_SECONDS_WARNING"
				});
				gauntletFiveSecondWarning = true;
				beginGauntletFinalCountdown = true;
			}
			if (!hasRegisteredShards)
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < shardList.Count; i++)
			{
				if (shardList[i] == null)
				{
					num++;
				}
			}
			if (previousDestroyedShardCount != num)
			{
				switch (shardsDestroyedToTriggerEncounter - num)
				{
				case 4:
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "GAUNTLET_FOUR_SHARDS_REMAINING"
					});
					break;
				case 3:
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "GAUNTLET_THREE_SHARDS_REMAINING"
					});
					break;
				case 2:
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "GAUNTLET_TWO_SHARDS_REMAINING"
					});
					break;
				}
			}
			int num2 = shardsDestroyedToTriggerEncounter - 1;
			if (previousDestroyedShardCount < num2 && num >= num2)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_ONE_SHARD_REMAINING"
				});
			}
			if (num >= shardsDestroyedToTriggerEncounter && !beginEncounterCountdown)
			{
				beginEncounterCountdown = true;
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "GAUNTLET_ALL_SHARDS_DESTROYED"
				});
			}
			if (beginGauntletFinalCountdown && !gauntletEnd)
			{
				gauntletFinalCountdown += GetDeltaTime();
				if (gauntletFinalCountdown >= 1f)
				{
					secondsRemaining--;
					totalSeconds++;
					if (totalSeconds == 1)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_FOUR_SECONDS_REMAINING"
						});
					}
					else if (totalSeconds == 2)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_THREE_SECONDS_REMAINING"
						});
					}
					else if (totalSeconds == 3)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_TWO_SECONDS_REMAINING"
						});
					}
					else if (totalSeconds == 4)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "GAUNTLET_ONE_SECOND_REMAINING"
						});
					}
					gauntletFinalCountdown = 0f;
				}
				if (secondsRemaining == 0)
				{
					gauntletEnd = true;
					exitPortal.SetActive(value: false);
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "GAUNTLET_END"
					});
				}
			}
			previousDestroyedShardCount = num;
		}

		private void RegisterShards()
		{
			if (hasRegisteredShards)
			{
				return;
			}
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				if (readOnlyInstancesList[i].name.Contains("GauntletShard"))
				{
					shardList.Add(readOnlyInstancesList[i].gameObject);
				}
			}
			hasRegisteredShards = true;
		}

		private void RegisterExitPortal()
		{
			if (!hasExitPortal)
			{
				exitPortal = GameObject.Find("PortalArena");
				if ((bool)exitPortal)
				{
					hasExitPortal = true;
				}
			}
		}
	}
}
namespace EntityStates.Missions.Moon
{
	public abstract class MoonBatteryBaseState : BaseState
	{
		protected PurchaseInteraction purchaseInteraction;

		protected Animator[] animators;

		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			animators = outer.GetComponentsInChildren<Animator>();
		}
	}
	public class MoonBatteryInactive : MoonBatteryBaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction.SetAvailable(newAvailable: true);
			FindModelChild("InactiveFX").gameObject.SetActive(value: true);
		}

		public override void OnExit()
		{
			FindModelChild("InactiveFX").gameObject.SetActive(value: false);
			purchaseInteraction.SetAvailable(newAvailable: false);
			base.OnExit();
		}
	}
	public class MoonBatteryActive : MoonBatteryBaseState
	{
		public static string soundEntryEvent;

		public static string soundLoopStartEvent;

		public static string soundLoopEndEvent;

		public static string soundExitEvent;

		public static string activeTriggerName;

		public static string completeTriggerName;

		private HoldoutZoneController holdoutZoneController;

		private ChargeIndicatorController chargeIndicatorController;

		private static int ActivecycleOffsetParamHash = Animator.StringToHash("Active.cycleOffset");

		public override void OnEnter()
		{
			base.OnEnter();
			holdoutZoneController = GetComponent<HoldoutZoneController>();
			holdoutZoneController.enabled = true;
			if (NetworkServer.active)
			{
				GetComponent<CombatDirector>().enabled = true;
			}
			Animator[] array = animators;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetTrigger(activeTriggerName);
			}
			Util.PlaySound(soundEntryEvent, base.gameObject);
			Util.PlaySound(soundLoopStartEvent, base.gameObject);
			FindModelChild("ChargingFX").gameObject.SetActive(value: true);
			Transform targetTransform = FindModelChild("PositionIndicatorPosition").transform;
			PositionIndicator component = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/PositionIndicators/PillarChargingPositionIndicator"), base.transform.position, UnityEngine.Quaternion.identity).GetComponent<PositionIndicator>();
			component.targetTransform = targetTransform;
			chargeIndicatorController = component.GetComponent<ChargeIndicatorController>();
			chargeIndicatorController.holdoutZoneController = holdoutZoneController;
		}

		public override void Update()
		{
			base.Update();
			if ((bool)holdoutZoneController)
			{
				Animator[] array = animators;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetFloat(ActivecycleOffsetParamHash, holdoutZoneController.charge * 0.99f);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && holdoutZoneController.charge >= 1f)
			{
				outer.SetNextState(new MoonBatteryComplete());
			}
		}

		public override void OnExit()
		{
			FindModelChild("ChargingFX").gameObject.SetActive(value: false);
			if ((bool)holdoutZoneController)
			{
				holdoutZoneController.enabled = false;
			}
			Animator[] array = animators;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetTrigger(completeTriggerName);
			}
			Util.PlaySound(soundLoopEndEvent, base.gameObject);
			Util.PlaySound(soundExitEvent, base.gameObject);
			if ((bool)chargeIndicatorController)
			{
				EntityState.Destroy(chargeIndicatorController.gameObject);
			}
			base.OnExit();
		}
	}
	public class MoonBatteryComplete : MoonBatteryBaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			FindModelChild("ChargedFX").gameObject.SetActive(value: true);
		}
	}
	public class MoonBatteryDisabled : MoonBatteryBaseState
	{
	}
	public class MoonBatteryDesignActive : MoonBatteryActive
	{
		private TeamFilter teamFilter;

		public static GameObject pulsePrefab;

		public static float pulseInterval;

		public static BuffDef buffDef;

		public static float buffDuration;

		public static float baseForce;

		private float pulseTimer;

		public override void OnEnter()
		{
			base.OnEnter();
			teamFilter = GetComponent<TeamFilter>();
			pulseTimer = 0f;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				pulseTimer -= GetDeltaTime();
				if (pulseTimer < 0f)
				{
					pulseTimer = pulseInterval;
					CreatePulseServer();
				}
			}
		}

		private void CreatePulseServer()
		{
			if (!FindModelChild("PulseOrigin"))
			{
				_ = base.transform;
			}
			GameObject obj = UnityEngine.Object.Instantiate(pulsePrefab, base.transform.position, base.transform.rotation);
			SphereSearch sphereSearch = new SphereSearch();
			PulseController component = obj.GetComponent<PulseController>();
			component.performSearch += PerformPulseSearch;
			component.onPulseHit += OnPulseHit;
			component.StartPulseServer();
			NetworkServer.Spawn(obj);
			static void OnPulseHit(PulseController _, PulseController.PulseHit hitInfo)
			{
				HealthComponent healthComponent = hitInfo.hitObject as HealthComponent;
				if ((bool)healthComponent)
				{
					CharacterBody body = healthComponent.body;
					if ((bool)body.characterMotor && body.characterMotor.isGrounded)
					{
						UnityEngine.Vector3 normalized = (hitInfo.hitPos - hitInfo.pulseOrigin).normalized;
						body.characterMotor.ApplyForce(normalized * (baseForce * hitInfo.hitSeverity));
						body.AddTimedBuff(buffDef, buffDuration);
					}
				}
			}
			void PerformPulseSearch(PulseController _, UnityEngine.Vector3 origin, float radius, List<PulseController.PulseSearchResult> dest)
			{
				TeamMask none = TeamMask.none;
				none.AddTeam(teamFilter.teamIndex);
				sphereSearch.origin = origin;
				sphereSearch.radius = radius;
				sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.Ignore;
				sphereSearch.mask = LayerIndex.entityPrecise.mask;
				sphereSearch.RefreshCandidates();
				sphereSearch.FilterCandidatesByHurtBoxTeam(none);
				sphereSearch.OrderCandidatesByDistance();
				sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
				List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
				sphereSearch.GetHurtBoxes(list);
				for (int i = 0; i < list.Count; i++)
				{
					HurtBox hurtBox = list[i];
					if ((bool)hurtBox)
					{
						_ = hurtBox.healthComponent;
						if ((bool)hurtBox.healthComponent)
						{
							UnityEngine.Vector3 vector = hurtBox.collider.ClosestPoint(origin);
							UnityEngine.Vector3.Distance(origin, vector);
							PulseController.PulseSearchResult pulseSearchResult = default(PulseController.PulseSearchResult);
							pulseSearchResult.hitObject = hurtBox.healthComponent;
							pulseSearchResult.hitPos = vector;
							PulseController.PulseSearchResult item = pulseSearchResult;
							dest.Add(item);
						}
					}
				}
				list = CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
			}
		}
	}
	public class MoonBatteryBloodActive : MoonBatteryActive
	{
		[SerializeField]
		public GameObject siphonPrefab;

		[SerializeField]
		public string siphonRootName;

		private GameObject siphonObject;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				Transform transform = FindModelChild(siphonRootName);
				if (!transform)
				{
					transform = base.transform;
				}
				siphonObject = UnityEngine.Object.Instantiate(siphonPrefab, transform.position, transform.rotation, transform);
				NetworkServer.Spawn(siphonObject);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active && (bool)siphonObject)
			{
				NetworkServer.Destroy(siphonObject);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.Missions.GeodeSecretMission
{
	public class GeodeSecretMissionEntityStates : EntityState
	{
		protected GeodeSecretMissionController geodeSecretMissionController;

		public override void OnEnter()
		{
			geodeSecretMissionController = base.gameObject.GetComponent<GeodeSecretMissionController>();
			base.OnEnter();
		}
	}
	public class GeodeSecretMissionEntryState : GeodeSecretMissionEntityStates
	{
	}
	public class GeodeSecretMissionRewardState : GeodeSecretMissionEntityStates
	{
		private Xoroshiro128Plus rng;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
				DropRewards();
			}
		}

		public void DropRewards()
		{
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (participatingPlayerCount > 0 && (bool)base.gameObject && (bool)geodeSecretMissionController.rewardDropTable)
			{
				int num = geodeSecretMissionController.numberOfRewardsSpawned;
				if (geodeSecretMissionController.increaseRewardPerPlayer)
				{
					num *= participatingPlayerCount;
				}
				float angle = 360f / (float)num;
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				UnityEngine.Vector3 position = geodeSecretMissionController.rewardSpawnLocation.transform.position;
				int num2 = 0;
				while (num2 < num)
				{
					GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo);
					pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(geodeSecretMissionController.rewardDisplayTier);
					pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTablePlusForcedStorm(geodeSecretMissionController.numberOfRewardOptions, geodeSecretMissionController.rewardDropTable, geodeSecretMissionController.rewardDropTable, rng);
					pickupInfo.rotation = UnityEngine.Quaternion.identity;
					pickupInfo.prefabOverride = geodeSecretMissionController.rewardPrefab;
					PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector);
					num2++;
					vector = quaternion * vector;
				}
			}
		}
	}
}
namespace EntityStates.Missions.LunarScavengerEncounter
{
	public class WaitForAllMonstersDead : BaseState
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		private void FixedUpdateServer()
		{
			if (TeamComponent.GetTeamMembers(TeamIndex.Monster).Count == 0)
			{
				outer.SetNextState(new FadeOut());
			}
		}
	}
	public class FadeOut : BaseState
	{
		public static float delay;

		public static float duration;

		private Run.TimeStamp startTime;

		private Light light;

		private float initialIntensity;

		private float initialAmbientIntensity;

		private UnityEngine.Color initialAmbientColor;

		private UnityEngine.Color initialFogColor;

		private PostProcessVolume postProcessVolume;

		private bool finished;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				startTime = Run.TimeStamp.now + delay;
			}
			light = GetComponent<ChildLocator>().FindChild("PrimaryLight").GetComponent<Light>();
			initialIntensity = light.intensity;
			initialAmbientIntensity = RenderSettings.ambientIntensity;
			initialAmbientColor = RenderSettings.ambientLight;
			initialFogColor = RenderSettings.fogColor;
			light.GetComponent<FlickerLight>().enabled = false;
			postProcessVolume = GetComponent<PostProcessVolume>();
			postProcessVolume.enabled = true;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(startTime);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			startTime = reader.ReadTimeStamp();
		}

		public override void Update()
		{
			base.Update();
			float num = Mathf.Clamp01(startTime.timeSince / duration);
			num *= num;
			light.intensity = Mathf.Lerp(initialIntensity, 0f, num);
			RenderSettings.ambientIntensity = Mathf.Lerp(initialAmbientIntensity, 0f, num);
			RenderSettings.ambientLight = UnityEngine.Color.Lerp(initialAmbientColor, UnityEngine.Color.black, num);
			RenderSettings.fogColor = UnityEngine.Color.Lerp(initialFogColor, UnityEngine.Color.black, num);
			if (!Mathf.Approximately(postProcessVolume.weight, num))
			{
				PostProcessVolume.DispatchVolumeSettingsChangedEvent();
			}
			postProcessVolume.weight = num;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
			if (!(startTime.timeSince > duration))
			{
				return;
			}
			foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
			{
				if (readOnlyInstances.hasEffectiveAuthority)
				{
					EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(readOnlyInstances.gameObject, "Body");
					if ((bool)entityStateMachine && !(entityStateMachine.state is Idle))
					{
						entityStateMachine.SetInterruptState(new Idle(), InterruptPriority.Frozen);
					}
				}
			}
		}

		private void FixedUpdateServer()
		{
			if ((startTime + duration).hasPassed && !finished)
			{
				finished = true;
				Run.instance.BeginGameOver(RoR2Content.GameEndings.LimboEnding);
			}
		}
	}
}
namespace EntityStates.Missions.Goldshores
{
	public class ActivateBeacons : EntityState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)GoldshoresMissionController.instance)
			{
				GoldshoresMissionController.instance.SpawnBeacons();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (!outer.destroying && (bool)GoldshoresMissionController.instance)
			{
				GoldshoresMissionController.instance.BeginTransitionIntoBossfight();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)GoldshoresMissionController.instance && GoldshoresMissionController.instance.beaconsActive >= GoldshoresMissionController.instance.beaconsRequiredToSpawnBoss)
			{
				outer.SetNextState(new GoldshoresBossfight());
			}
		}
	}
	public class Exit : EntityState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/iscGoldshoresPortal"), new DirectorPlacementRule
				{
					maxDistance = float.PositiveInfinity,
					minDistance = 10f,
					placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
					position = base.transform.position,
					spawnOnTarget = GoldshoresMissionController.instance.bossSpawnPosition
				}, Run.instance.stageRng));
				if ((bool)gameObject)
				{
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "PORTAL_GOLDSHORES_OPEN"
					});
					gameObject.GetComponent<SceneExitController>().useRunNextStageScene = true;
				}
				if ((string.IsNullOrEmpty("FalseSonBossComplete") || !Run.instance.GetEventFlag("FalseSonBossComplete")) && IsValidStormTier() && (bool)DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/iscColossusPortal"), new DirectorPlacementRule
				{
					maxDistance = 30f,
					minDistance = 10f,
					placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
					position = base.transform.position
				}, Run.instance.stageRng)))
				{
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "PORTAL_STORM_OPEN"
					});
				}
				for (int num = CombatDirector.instancesList.Count - 1; num >= 0; num--)
				{
					CombatDirector.instancesList[num].enabled = false;
				}
			}
		}

		private bool IsValidStormTier()
		{
			Run instance = Run.instance;
			int stageOrder = instance.nextStageScene.stageOrder;
			ExpansionDef requiredExpansion = GoldshoresMissionController.instance.requiredExpansion;
			if (instance.IsExpansionEnabled(requiredExpansion) && (stageOrder == 2 || stageOrder == 3 || stageOrder == 4))
			{
				return true;
			}
			return false;
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class GoldshoresBossfight : EntityState
	{
		private GoldshoresMissionController missionController;

		public static float shieldRemovalDuration;

		public static GameObject shieldRemovalEffectPrefab;

		public static GameObject shieldRegenerationEffectPrefab;

		public static GameObject combatEncounterPrefab;

		private static float transitionDuration = 3f;

		private bool hasSpawnedBoss;

		private int serverCycleCount;

		private Run.FixedTimeStamp bossInvulnerabilityStartTime;

		private ScriptedCombatEncounter scriptedCombatEncounter;

		private bool bossImmunity;

		private bool bossShouldBeInvulnerable => missionController.beaconsActive < missionController.beaconsToSpawnOnMap;

		public static event Action onOneCycleGoldTitanKill;

		public override void OnEnter()
		{
			base.OnEnter();
			missionController = GetComponent<GoldshoresMissionController>();
			bossInvulnerabilityStartTime = Run.FixedTimeStamp.negativeInfinity;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				ServerFixedUpdate();
			}
		}

		private void SetBossImmunity(bool newBossImmunity)
		{
			if (!scriptedCombatEncounter || newBossImmunity == bossImmunity)
			{
				return;
			}
			bossImmunity = newBossImmunity;
			foreach (CharacterMaster readOnlyMembers in scriptedCombatEncounter.combatSquad.readOnlyMembersList)
			{
				CharacterBody body = readOnlyMembers.GetBody();
				if ((bool)body)
				{
					if (bossImmunity)
					{
						body.AddBuff(RoR2Content.Buffs.Immune);
						continue;
					}
					EffectManager.SpawnEffect(shieldRemovalEffectPrefab, new EffectData
					{
						origin = body.coreTransform.position
					}, transmit: true);
					body.RemoveBuff(RoR2Content.Buffs.Immune);
				}
			}
		}

		private void ExtinguishBeacons()
		{
			foreach (GameObject beaconInstance in missionController.beaconInstanceList)
			{
				beaconInstance.GetComponent<EntityStateMachine>().SetNextState(new NotReady());
			}
		}

		private void ServerFixedUpdate()
		{
			if (base.fixedAge >= transitionDuration)
			{
				missionController.ExitTransitionIntoBossfight();
				if (!hasSpawnedBoss)
				{
					SpawnBoss();
				}
				else if (scriptedCombatEncounter.combatSquad.readOnlyMembersList.Count == 0)
				{
					outer.SetNextState(new Exit());
					if (serverCycleCount < 1)
					{
						GoldshoresBossfight.onOneCycleGoldTitanKill?.Invoke();
					}
					return;
				}
			}
			if (!scriptedCombatEncounter)
			{
				return;
			}
			if (!bossImmunity)
			{
				if (bossInvulnerabilityStartTime.hasPassed)
				{
					ExtinguishBeacons();
					SetBossImmunity(newBossImmunity: true);
					serverCycleCount++;
				}
			}
			else if (missionController.beaconsActive >= missionController.beaconsToSpawnOnMap)
			{
				SetBossImmunity(newBossImmunity: false);
				bossInvulnerabilityStartTime = Run.FixedTimeStamp.now + shieldRemovalDuration;
			}
		}

		private void SpawnBoss()
		{
			if (!hasSpawnedBoss)
			{
				if (!scriptedCombatEncounter)
				{
					scriptedCombatEncounter = UnityEngine.Object.Instantiate(combatEncounterPrefab).GetComponent<ScriptedCombatEncounter>();
					scriptedCombatEncounter.GetComponent<BossGroup>().dropPosition = missionController.bossSpawnPosition;
					NetworkServer.Spawn(scriptedCombatEncounter.gameObject);
				}
				scriptedCombatEncounter.BeginEncounter();
				hasSpawnedBoss = scriptedCombatEncounter.hasSpawnedServer;
				if (hasSpawnedBoss)
				{
					SetBossImmunity(newBossImmunity: true);
				}
			}
		}
	}
}
namespace EntityStates.Missions.BrotherEncounter
{
	public class BrotherEncounterBaseState : EntityState
	{
		protected ChildLocator childLocator;

		protected virtual bool shouldEnableArenaWalls => true;

		protected virtual bool shouldEnableArenaNodes => true;

		public override void OnEnter()
		{
			base.OnEnter();
			childLocator = GetComponent<ChildLocator>();
			Transform transform = childLocator.FindChild("ArenaWalls");
			Transform transform2 = childLocator.FindChild("ArenaNodes");
			if ((bool)transform)
			{
				transform.gameObject.SetActive(shouldEnableArenaWalls);
			}
			if ((bool)transform2)
			{
				transform2.gameObject.SetActive(shouldEnableArenaNodes);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public void KillAllMonsters()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (TeamComponent item in new List<TeamComponent>(TeamComponent.GetTeamMembers(TeamIndex.Monster)))
			{
				if ((bool)item)
				{
					HealthComponent component = item.GetComponent<HealthComponent>();
					if ((bool)component)
					{
						component.Suicide();
					}
				}
			}
		}
	}
	public abstract class BrotherEncounterPhaseBaseState : BrotherEncounterBaseState
	{
		[SerializeField]
		public float durationBeforeEnablingCombatEncounter;

		[SerializeField]
		public GameObject speechControllerPrefab;

		protected ScriptedCombatEncounter phaseScriptedCombatEncounter;

		protected GameObject phaseControllerObject;

		protected GameObject phaseControllerSubObjectContainer;

		protected BossGroup phaseBossGroup;

		private bool hasSpawned;

		private bool finishedServer;

		private const float minimumDurationPerPhase = 2f;

		private Run.FixedTimeStamp healthBarShowTime = Run.FixedTimeStamp.positiveInfinity;

		protected abstract EntityState nextState { get; }

		protected abstract string phaseControllerChildString { get; }

		protected virtual float healthBarShowDelay => 0f;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)PhaseCounter.instance)
			{
				PhaseCounter.instance.GoToNextPhase();
			}
			if ((bool)childLocator)
			{
				phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject;
				if ((bool)phaseControllerObject)
				{
					phaseScriptedCombatEncounter = phaseControllerObject.GetComponent<ScriptedCombatEncounter>();
					phaseBossGroup = phaseControllerObject.GetComponent<BossGroup>();
					phaseControllerSubObjectContainer = phaseControllerObject.transform.Find("PhaseObjects").gameObject;
					phaseControllerSubObjectContainer.SetActive(value: true);
				}
				GameObject gameObject = childLocator.FindChild("AllPhases").gameObject;
				if ((bool)gameObject)
				{
					gameObject.SetActive(value: true);
				}
			}
			healthBarShowTime = Run.FixedTimeStamp.now + healthBarShowDelay;
			if ((bool)DirectorCore.instance)
			{
				CombatDirector[] components = DirectorCore.instance.GetComponents<CombatDirector>();
				for (int i = 0; i < components.Length; i++)
				{
					components[i].enabled = false;
				}
			}
			if (NetworkServer.active && (object)phaseScriptedCombatEncounter != null)
			{
				phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer += OnMemberAddedServer;
			}
		}

		public override void OnExit()
		{
			if ((object)phaseScriptedCombatEncounter != null)
			{
				phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer -= OnMemberAddedServer;
			}
			if ((bool)phaseControllerSubObjectContainer)
			{
				phaseControllerSubObjectContainer.SetActive(value: false);
			}
			if ((bool)phaseBossGroup)
			{
				phaseBossGroup.shouldDisplayHealthBarOnHud = false;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			phaseBossGroup.shouldDisplayHealthBarOnHud = healthBarShowTime.hasPassed;
			if (!hasSpawned)
			{
				if (base.fixedAge > durationBeforeEnablingCombatEncounter)
				{
					BeginEncounter();
				}
			}
			else if (NetworkServer.active && !finishedServer && base.fixedAge > 2f + durationBeforeEnablingCombatEncounter && (bool)phaseScriptedCombatEncounter && phaseScriptedCombatEncounter.combatSquad.memberCount == 0)
			{
				finishedServer = true;
				outer.SetNextState(nextState);
			}
		}

		protected void BeginEncounter()
		{
			hasSpawned = true;
			PreEncounterBegin();
			if (NetworkServer.active)
			{
				phaseScriptedCombatEncounter.BeginEncounter();
			}
		}

		protected virtual void PreEncounterBegin()
		{
		}

		protected virtual void OnMemberAddedServer(CharacterMaster master)
		{
			if ((bool)speechControllerPrefab)
			{
				UnityEngine.Object.Instantiate(speechControllerPrefab, master.transform).GetComponent<CharacterSpeechController>().characterMaster = master;
			}
		}
	}
	public class PreEncounter : BaseState
	{
		public static float duration;

		private ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			childLocator = GetComponent<ChildLocator>();
			childLocator.FindChild("PreEncounter").gameObject.SetActive(value: true);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new Phase1());
			}
		}

		public override void OnExit()
		{
			childLocator.FindChild("PreEncounter").gameObject.SetActive(value: false);
			base.OnExit();
		}
	}
	public class Phase1 : BrotherEncounterPhaseBaseState
	{
		public static string prespawnSoundString;

		public static float prespawnSoundDelay;

		public static GameObject centerOrbDestroyEffect;

		private bool hasPlayedPrespawnSound;

		protected override string phaseControllerChildString => "Phase1";

		protected override EntityState nextState => new Phase2();

		public override void OnEnter()
		{
			KillAllMonsters();
			base.OnEnter();
		}

		protected override void PreEncounterBegin()
		{
			base.PreEncounterBegin();
			Transform transform = childLocator.FindChild("CenterOrbEffect");
			transform.gameObject.SetActive(value: false);
			EffectManager.SpawnEffect(centerOrbDestroyEffect, new EffectData
			{
				origin = transform.transform.position
			}, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!hasPlayedPrespawnSound && base.fixedAge > prespawnSoundDelay)
			{
				Transform transform = childLocator.FindChild("CenterOrbEffect");
				Util.PlaySound(prespawnSoundString, transform.gameObject);
				hasPlayedPrespawnSound = true;
			}
		}

		protected override void OnMemberAddedServer(CharacterMaster master)
		{
			base.OnMemberAddedServer(master);
		}
	}
	public class Phase2 : BrotherEncounterPhaseBaseState
	{
		public static float delayBetweenPillarActivation;

		private List<GameObject> pillarsToActive = new List<GameObject>();

		private float pillarActivationStopwatch;

		protected override string phaseControllerChildString => "Phase2";

		protected override EntityState nextState => new Phase3();

		public override void OnEnter()
		{
			base.OnEnter();
			GameObject gameObject = childLocator.FindChild("BlockingPillars").gameObject;
			if ((bool)gameObject)
			{
				gameObject.SetActive(value: true);
				for (int i = 0; i < gameObject.transform.childCount; i++)
				{
					pillarsToActive.Add(gameObject.transform.GetChild(i).gameObject);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			pillarActivationStopwatch += GetDeltaTime();
			if (pillarsToActive.Count > 0 && pillarActivationStopwatch > delayBetweenPillarActivation)
			{
				pillarActivationStopwatch = 0f;
				pillarsToActive[0].SetActive(value: true);
				pillarsToActive.RemoveAt(0);
			}
		}
	}
	public class Phase3 : BrotherEncounterPhaseBaseState
	{
		protected override string phaseControllerChildString => "Phase3";

		protected override EntityState nextState => new Phase4();

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void OnExit()
		{
			KillAllMonsters();
			base.OnExit();
		}

		protected override void OnMemberAddedServer(CharacterMaster master)
		{
			base.OnMemberAddedServer(master);
			if (!master.hasBody)
			{
				return;
			}
			CharacterBody body = master.GetBody();
			if ((bool)body)
			{
				CharacterDeathBehavior component = body.GetComponent<CharacterDeathBehavior>();
				if ((bool)component)
				{
					component.deathState = new SerializableEntityStateType(typeof(InstantDeathState));
				}
			}
		}
	}
	public class Phase4 : BrotherEncounterPhaseBaseState
	{
		protected override string phaseControllerChildString => "Phase4";

		protected override EntityState nextState => new BossDeath();

		protected override float healthBarShowDelay => 6f;

		public override void OnEnter()
		{
			base.OnEnter();
			BeginEncounter();
		}
	}
	public class BossDeath : BrotherEncounterBaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				outer.SetNextState(new EncounterFinished());
			}
		}
	}
	public class EncounterFinished : BrotherEncounterBaseState
	{
		protected override bool shouldEnableArenaNodes => false;

		public override void OnEnter()
		{
			base.OnEnter();
		}
	}
}
namespace EntityStates.Missions.ArtifactWorld.TrialController
{
	public class BeforeTrial1 : BeforeTrial
	{
	}
	public class DuringTrial1 : DuringTrial
	{
		public static float trialDuration;

		public override EntityState GetNextState()
		{
			return new AfterTrial1();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= trialDuration)
			{
				outer.SetNextState(GetNextState());
			}
		}
	}
	public class AfterTrial1 : AfterTrial
	{
		public override Type GetNextStateType()
		{
			return typeof(FinishTrial1);
		}
	}
	public class FinishTrial1 : FinishTrial
	{
	}
	public class AfterTrial2 : AfterTrial
	{
		public override Type GetNextStateType()
		{
			return typeof(FinishTrial2);
		}
	}
	public class FinishTrial2 : FinishTrial
	{
	}
	public class ArtifactTrialControllerBaseState : EntityState
	{
		protected PurchaseInteraction purchaseInteraction;

		protected ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			childLocator = GetComponent<ChildLocator>();
		}
	}
	public class BeforeTrial : ArtifactTrialControllerBaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction.enabled = true;
			childLocator.FindChild("BeforeTrial").gameObject.SetActive(value: true);
		}

		public override void OnExit()
		{
			childLocator.FindChild("BeforeTrial").gameObject.SetActive(value: false);
			base.OnExit();
		}
	}
	public class DuringTrial : ArtifactTrialControllerBaseState
	{
		public virtual EntityState GetNextState()
		{
			return new AfterTrial();
		}

		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction.enabled = false;
			childLocator.FindChild("DuringTrial").gameObject.SetActive(value: true);
		}

		public override void OnExit()
		{
			childLocator.FindChild("DuringTrial").gameObject.SetActive(value: false);
			base.OnExit();
		}
	}
	public class AfterTrial : ArtifactTrialControllerBaseState
	{
		public virtual Type GetNextStateType()
		{
			return typeof(FinishTrial);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction.enabled = true;
			childLocator.FindChild("AfterTrial").gameObject.SetActive(value: true);
			outer.mainStateType = new SerializableEntityStateType(GetNextStateType());
			Highlight component = GetComponent<Highlight>();
			Transform transform = childLocator.FindChild("CompletedArtifactMesh");
			if ((bool)component && (bool)transform)
			{
				component.targetRenderer = transform.GetComponent<MeshRenderer>();
			}
		}

		public override void OnExit()
		{
			childLocator.FindChild("AfterTrial").gameObject.SetActive(value: false);
			base.OnExit();
		}
	}
	public class FinishTrial : ArtifactTrialControllerBaseState
	{
		[SerializeField]
		public string achievementName;

		public override void OnEnter()
		{
			base.OnEnter();
			childLocator.FindChild("FinishTrial").gameObject.SetActive(value: true);
			AchievementDef achievementDef = AchievementManager.GetAchievementDef(achievementName);
			if (achievementDef == null)
			{
				return;
			}
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				AchievementManager.GetUserAchievementManager(readOnlyLocalUsers).GrantAchievement(achievementDef);
			}
		}
	}
}
namespace EntityStates.Missions.Arena.NullWard
{
	public class NullWardBaseState : EntityState
	{
		public static float wardRadiusOff;

		public static float wardRadiusOn;

		public static float wardWaitingRadius;

		protected SphereZone sphereZone;

		protected PurchaseInteraction purchaseInteraction;

		protected ChildLocator childLocator;

		protected ArenaMissionController arenaMissionController => ArenaMissionController.instance;

		public override void OnEnter()
		{
			base.OnEnter();
			sphereZone = GetComponent<SphereZone>();
			sphereZone.enabled = true;
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			childLocator = GetComponent<ChildLocator>();
			base.gameObject.GetComponent<TeamFilter>().teamIndex = TeamIndex.Player;
		}
	}
	public class Off : NullWardBaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			sphereZone.Networkradius = NullWardBaseState.wardRadiusOff;
			purchaseInteraction.SetAvailable(newAvailable: false);
			sphereZone.enabled = false;
		}
	}
	public class WardOnAndReady : NullWardBaseState
	{
		public static string soundLoopStartEvent;

		public static string soundLoopEndEvent;

		public override void OnEnter()
		{
			base.OnEnter();
			sphereZone.Networkradius = NullWardBaseState.wardWaitingRadius;
			purchaseInteraction.SetAvailable(newAvailable: true);
			childLocator.FindChild("WardOnEffect").gameObject.SetActive(value: true);
			sphereZone.enabled = true;
			Util.PlaySound(soundLoopStartEvent, base.gameObject);
		}

		public override void OnExit()
		{
			Util.PlaySound(soundLoopEndEvent, base.gameObject);
			base.OnExit();
		}
	}
	public class Active : NullWardBaseState
	{
		public static string soundEntryEvent;

		public static string soundLoopStartEvent;

		public static string soundLoopEndEvent;

		private static Run.FixedTimeStamp startTime;

		private HoldoutZoneController holdoutZoneController;

		public override void OnEnter()
		{
			base.OnEnter();
			holdoutZoneController = GetComponent<HoldoutZoneController>();
			holdoutZoneController.enabled = true;
			holdoutZoneController.baseRadius = NullWardBaseState.wardRadiusOn;
			purchaseInteraction.SetAvailable(newAvailable: false);
			base.arenaMissionController.rewardSpawnPosition = childLocator.FindChild("RewardSpawn").gameObject;
			base.arenaMissionController.monsterSpawnPosition = childLocator.FindChild("MonsterSpawn").gameObject;
			childLocator.FindChild("ActiveEffect").gameObject.SetActive(value: true);
			if (NetworkServer.active)
			{
				base.arenaMissionController.BeginRound();
			}
			if (base.isAuthority)
			{
				startTime = Run.FixedTimeStamp.now;
			}
			Util.PlaySound(soundEntryEvent, base.gameObject);
			Util.PlaySound(soundLoopStartEvent, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			sphereZone.Networkradius = holdoutZoneController.currentRadius;
			if (base.isAuthority && holdoutZoneController.charge >= 1f)
			{
				outer.SetNextState(new Complete());
			}
		}

		public override void OnExit()
		{
			if ((bool)holdoutZoneController)
			{
				holdoutZoneController.enabled = false;
			}
			Util.PlaySound(soundLoopEndEvent, base.gameObject);
			childLocator.FindChild("ActiveEffect").gameObject.SetActive(value: false);
			childLocator.FindChild("WardOnEffect").gameObject.SetActive(value: false);
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(startTime);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			startTime = reader.ReadFixedTimeStamp();
		}
	}
	public class Complete : NullWardBaseState
	{
		public static float duration;

		public static string soundEntryEvent;

		public override void OnEnter()
		{
			base.OnEnter();
			sphereZone.Networkradius = NullWardBaseState.wardRadiusOn;
			purchaseInteraction.SetAvailable(newAvailable: false);
			childLocator.FindChild("CompleteEffect").gameObject.SetActive(value: true);
			if (NetworkServer.active)
			{
				base.arenaMissionController.EndRound();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			sphereZone.Networkradius = Mathf.Lerp(NullWardBaseState.wardRadiusOn, NullWardBaseState.wardRadiusOff, base.fixedAge / duration);
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new Off());
			}
		}
	}
}
namespace EntityStates.MinorConstruct
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject explosionPrefab;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				EffectManager.SimpleEffect(explosionPrefab, base.transform.position, base.transform.rotation, transmit: true);
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class FindSurface : NoCastSpawn
	{
		[SerializeField]
		public int raycastCount;

		[SerializeField]
		public float maxRaycastLength;

		public override void OnEnter()
		{
			RaycastHit hitInfo = default(RaycastHit);
			UnityEngine.Vector3 corePosition = base.characterBody.corePosition;
			if (base.isAuthority && !(base.characterBody.master.minionOwnership?.ownerMaster))
			{
				for (int i = 0; i < raycastCount; i++)
				{
					if (Physics.Raycast(corePosition, UnityEngine.Random.onUnitSphere, out hitInfo, maxRaycastLength, LayerIndex.world.mask))
					{
						base.transform.position = hitInfo.point;
						base.transform.up = hitInfo.normal;
					}
				}
			}
			base.OnEnter();
		}
	}
	public class NoCastSpawn : BaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			outer.SetNextStateToMain();
		}
	}
	public class BaseHideState : BaseState
	{
		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string childToEnable;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			Transform transform = FindModelChild(childToEnable);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: true);
			}
		}

		public override void OnExit()
		{
			Transform transform = FindModelChild(childToEnable);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: false);
			}
			base.OnExit();
		}
	}
	public class Hidden : BaseHideState
	{
		[SerializeField]
		public BuffDef buffDef;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)buffDef)
			{
				base.characterBody.AddBuff(buffDef);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.characterBody.outOfCombat || !base.characterBody.outOfDanger)
			{
				outer.SetNextState(new Revealed());
			}
		}

		public override void OnExit()
		{
			if ((bool)buffDef)
			{
				base.characterBody.RemoveBuff(buffDef);
			}
			base.OnExit();
		}
	}
	public class Revealed : BaseHideState
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.characterBody.outOfCombat && base.characterBody.outOfDanger)
			{
				outer.SetNextState(new Hidden());
			}
		}
	}
}
namespace EntityStates.MinorConstruct.Weapon
{
	public class ChargeConstructBeam : BaseState
	{
		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string exitSoundString;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string chargeEffectMuzzle;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public float baseDuration;

		private float duration;

		private GameObject chargeInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			Transform transform = FindModelChild(chargeEffectMuzzle);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeInstance.transform.parent = base.gameObject.transform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
		}

		public override void Update()
		{
			base.Update();
			if ((bool)chargeInstance)
			{
				Ray aimRay = GetAimRay();
				chargeInstance.transform.forward = aimRay.direction;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new FireConstructBeam());
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(exitSoundString, base.gameObject);
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireConstructBeam : GenericProjectileBaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.MiniMushroom
{
	public class InPlant : BaseState
	{
		public static GameObject burrowPrefab;

		public static float baseDuration;

		public static string burrowInSoundString;

		private float duration;

		private static int PlantStartStateHash = Animator.StringToHash("PlantStart");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int PlantStartParamHash = Animator.StringToHash("PlantStart.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(burrowInSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false);
			PlayAnimation("Plant", PlantStartStateHash, PlantStartParamHash, duration);
		}

		public override void OnExit()
		{
			PlayAnimation("Plant", EmptyStateHash);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new Plant());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Plant : BaseState
	{
		public static float healFraction;

		public static float baseMaxDuration;

		public static float baseMinDuration;

		public static float mushroomRadius;

		public static string healSoundLoop;

		public static string healSoundStop;

		private float maxDuration;

		private float minDuration;

		private GameObject mushroomWard;

		private uint soundID;

		private static int PlantLoopStateHash = Animator.StringToHash("PlantLoop");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Plant", PlantLoopStateHash);
			maxDuration = baseMaxDuration / attackSpeedStat;
			minDuration = baseMinDuration / attackSpeedStat;
			soundID = Util.PlaySound(healSoundLoop, base.characterBody.modelLocator.modelTransform.gameObject);
			if (NetworkServer.active && mushroomWard == null)
			{
				mushroomWard = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/MiniMushroomWard"), base.characterBody.footPosition, UnityEngine.Quaternion.identity);
				mushroomWard.GetComponent<TeamFilter>().teamIndex = base.teamComponent.teamIndex;
				if ((bool)mushroomWard)
				{
					HealingWard component = mushroomWard.GetComponent<HealingWard>();
					component.healFraction = healFraction;
					component.healPoints = 0f;
					component.Networkradius = mushroomRadius;
				}
				NetworkServer.Spawn(mushroomWard);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				bool flag = base.inputBank.moveVector.sqrMagnitude > 0.1f;
				if (base.fixedAge > maxDuration || (base.fixedAge > minDuration && flag))
				{
					outer.SetNextState(new UnPlant());
				}
			}
		}

		public override void OnExit()
		{
			PlayAnimation("Plant", EmptyStateHash);
			AkSoundEngine.StopPlayingID(soundID);
			Util.PlaySound(healSoundStop, base.gameObject);
			if ((bool)mushroomWard)
			{
				EntityState.Destroy(mushroomWard);
			}
			base.OnExit();
		}
	}
	public class SpawnState : BaseState
	{
		public static GameObject burrowPrefab;

		public static float duration = 4f;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class SporeGrenade : BaseState
	{
		public static GameObject chargeEffectPrefab;

		public static string attackSoundString;

		public static string chargeUpSoundString;

		public static float recoilAmplitude = 1f;

		public static GameObject projectilePrefab;

		public static float baseDuration = 2f;

		public static string muzzleString;

		public static float damageCoefficient;

		public static float timeToTarget = 3f;

		public static float projectileVelocity = 55f;

		public static float minimumDistance;

		public static float maximumDistance;

		public static float baseChargeTime = 2f;

		private uint chargeupSoundID;

		private Ray projectileRay;

		private Transform modelTransform;

		private float duration;

		private float chargeTime;

		private bool hasFired;

		private Animator modelAnimator;

		private GameObject chargeEffectInstance;

		private static int ChargeStateHash = Animator.StringToHash("Charge");

		private static int isChargedParamHash = Animator.StringToHash("isCharged");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			chargeTime = baseChargeTime / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(isChargedParamHash, value: false);
				PlayAnimation("Gesture, Additive", ChargeStateHash);
				chargeupSoundID = Util.PlaySound(chargeUpSoundString, base.characterBody.modelLocator.modelTransform.gameObject);
			}
			Transform transform = FindModelChild("ChargeSpot");
			if ((bool)transform)
			{
				chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!(base.fixedAge >= chargeTime))
			{
				return;
			}
			if (!hasFired)
			{
				hasFired = true;
				modelAnimator?.SetBool(isChargedParamHash, value: true);
				if (base.isAuthority)
				{
					FireGrenade(muzzleString);
				}
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			PlayAnimation("Gesture, Additive", EmptyStateHash);
			AkSoundEngine.StopPlayingID(chargeupSoundID);
			if ((bool)chargeEffectInstance)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
			base.OnExit();
		}

		private void FireGrenade(string targetMuzzle)
		{
			Ray aimRay = GetAimRay();
			Ray ray = new Ray(aimRay.origin, UnityEngine.Vector3.up);
			Transform transform = FindModelChild(targetMuzzle);
			if ((bool)transform)
			{
				ray.origin = transform.position;
			}
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.RefreshCandidates();
			HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
			bool flag = false;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			RaycastHit hitInfo;
			if ((bool)hurtBox)
			{
				vector = hurtBox.transform.position;
				flag = true;
			}
			else if (Physics.Raycast(aimRay, out hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
			{
				vector = hitInfo.point;
				flag = true;
			}
			float magnitude = projectileVelocity;
			if (flag)
			{
				UnityEngine.Vector3 vector2 = vector - ray.origin;
				UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z);
				float magnitude2 = vector3.magnitude;
				UnityEngine.Vector2 vector4 = vector3 / magnitude2;
				if (magnitude2 < minimumDistance)
				{
					magnitude2 = minimumDistance;
				}
				if (magnitude2 > maximumDistance)
				{
					magnitude2 = maximumDistance;
				}
				float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector2.y);
				float num = magnitude2 / timeToTarget;
				UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * num, y, vector4.y * num);
				magnitude = direction.magnitude;
				ray.direction = direction;
			}
			UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(ray.direction + UnityEngine.Random.insideUnitSphere * 0.05f);
			ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude);
		}
	}
	public class UnPlant : BaseState
	{
		public static GameObject plantEffectPrefab;

		public static float baseDuration;

		public static string UnplantOutSoundString;

		private float stopwatch;

		private Transform modelTransform;

		private ChildLocator childLocator;

		private float duration;

		private static int PlantEndStateHash = Animator.StringToHash("PlantEnd");

		private static int PlantEndParamHash = Animator.StringToHash("PlantEnd.playbackRate");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			EffectManager.SimpleMuzzleFlash(plantEffectPrefab, base.gameObject, "BurrowCenter", transmit: false);
			Util.PlaySound(UnplantOutSoundString, base.gameObject);
			PlayAnimation("Plant", PlantEndStateHash, PlantEndParamHash, duration);
		}

		public override void OnExit()
		{
			PlayAnimation("Plant, Additive", EmptyStateHash);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Merc
{
	public class Assaulter : BaseState
	{
		private Transform modelTransform;

		public static GameObject dashPrefab;

		public static float smallHopVelocity;

		public static float dashPrepDuration;

		public static float dashDuration = 0.3f;

		public static float speedCoefficient = 25f;

		public static string beginSoundString;

		public static string endSoundString;

		public static float damageCoefficient;

		public static float procCoefficient;

		public static GameObject hitEffectPrefab;

		public static float hitPauseDuration;

		private float stopwatch;

		private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private OverlapAttack overlapAttack;

		private ChildLocator childLocator;

		private bool isDashing;

		private bool inHitPause;

		private float hitPauseTimer;

		private CameraTargetParams.AimRequest aimRequest;

		private int originalLayer;

		private static int AssaulterPrepStateHash = Animator.StringToHash("AssaulterPrep");

		private static int AssaulterPrepParamHash = Animator.StringToHash("AssaulterPrep.playbackRate");

		private static int EvisLoopExitStateHash = Animator.StringToHash("EvisLoopExit");

		public bool hasHit { get; private set; }

		public int dashIndex { private get; set; }

		public override void Reset()
		{
			base.Reset();
			modelTransform = null;
			stopwatch = 0f;
			dashVector = UnityEngine.Vector3.zero;
			animator = null;
			characterModel = null;
			hurtboxGroup = null;
			if (overlapAttack != null)
			{
				overlapAttack.Reset();
			}
			childLocator = null;
			isDashing = false;
			inHitPause = false;
			hitPauseTimer = 0f;
			hasHit = false;
			dashIndex = 0;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
				childLocator = modelTransform.GetComponent<ChildLocator>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
				if ((bool)childLocator)
				{
					childLocator.FindChild("PreDashEffect").gameObject.SetActive(value: true);
				}
			}
			SmallHop(base.characterMotor, smallHopVelocity);
			PlayAnimation("FullBody, Override", AssaulterPrepStateHash, AssaulterPrepParamHash, dashPrepDuration);
			dashVector = base.inputBank.aimDirection;
			overlapAttack = InitMeleeOverlap(damageCoefficient, hitEffectPrefab, modelTransform, "Assaulter");
			overlapAttack.damageType = DamageType.Stun1s;
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
		}

		private void CreateDashEffect()
		{
			Transform transform = childLocator.FindChild("DashCenter");
			if ((bool)transform && (bool)dashPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(dashPrefab))
				{
					UnityEngine.Object.Instantiate(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform);
				}
				else
				{
					EffectManager.GetAndActivatePooledEffect(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform);
				}
			}
			if ((bool)childLocator)
			{
				childLocator.FindChild("PreDashEffect").gameObject.SetActive(value: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterDirection.forward = dashVector;
			if (stopwatch > dashPrepDuration / attackSpeedStat && !isDashing)
			{
				isDashing = true;
				dashVector = base.inputBank.aimDirection;
				CreateDashEffect();
				PlayCrossfade("FullBody, Override", "AssaulterLoop", 0.1f);
				originalLayer = base.gameObject.layer;
				base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
				base.characterMotor.Motor.RebuildCollidableLayers();
				if ((bool)modelTransform)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
					temporaryOverlayInstance.duration = 0.7f;
					temporaryOverlayInstance.animateShaderAlpha = true;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matMercEnergized");
					temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
				}
			}
			float deltaTime = GetDeltaTime();
			if (!isDashing)
			{
				stopwatch += deltaTime;
			}
			else if (base.isAuthority)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				if (!inHitPause)
				{
					bool num = overlapAttack.Fire();
					stopwatch += deltaTime;
					if (num)
					{
						if (!hasHit)
						{
							hasHit = true;
						}
						inHitPause = true;
						hitPauseTimer = hitPauseDuration / attackSpeedStat;
						if ((bool)modelTransform)
						{
							TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
							temporaryOverlayInstance2.duration = hitPauseDuration / attackSpeedStat;
							temporaryOverlayInstance2.animateShaderAlpha = true;
							temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
							temporaryOverlayInstance2.destroyComponentOnEnd = true;
							temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matMercEvisTarget");
							temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
						}
					}
					base.characterMotor.rootMotion += dashVector * moveSpeedStat * speedCoefficient * deltaTime;
				}
				else
				{
					hitPauseTimer -= deltaTime;
					if (hitPauseTimer < 0f)
					{
						inHitPause = false;
					}
				}
			}
			if (stopwatch >= dashDuration + dashPrepDuration / attackSpeedStat && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			Util.PlaySound(endSoundString, base.gameObject);
			if (base.isAuthority)
			{
				base.characterMotor.velocity *= 0.1f;
				SmallHop(base.characterMotor, smallHopVelocity);
			}
			aimRequest?.Dispose();
			if ((bool)childLocator)
			{
				childLocator.FindChild("PreDashEffect").gameObject.SetActive(value: false);
			}
			PlayAnimation("FullBody, Override", EvisLoopExitStateHash);
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)dashIndex);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			dashIndex = reader.ReadByte();
		}
	}
	public class PrepAssaulter2 : BaseState
	{
		public static float baseDuration;

		public static float smallHopVelocity;

		public static string enterSoundString;

		private float duration;

		private static int AssaulterPrepStateHash = Animator.StringToHash("AssaulterPrep");

		private static int AssaulterPrepParamHash = Animator.StringToHash("AssaulterPrep.playbackRate");

		public int dashIndex { private get; set; }

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("FullBody, Override", AssaulterPrepStateHash, AssaulterPrepParamHash, baseDuration);
			FindModelChild("PreDashEffect").gameObject.SetActive(value: true);
			Util.PlaySound(enterSoundString, base.gameObject);
			Ray aimRay = GetAimRay();
			base.characterDirection.forward = aimRay.direction;
			base.characterDirection.moveVector = aimRay.direction;
			SmallHop(base.characterMotor, smallHopVelocity);
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 0.2f);
			}
			FindModelChild("PreDashEffect").gameObject.SetActive(value: false);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new Assaulter2());
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)dashIndex);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			dashIndex = reader.ReadByte();
		}
	}
	public class Assaulter2 : BasicMeleeAttack
	{
		public static float speedCoefficientOnExit;

		public static float speedCoefficient;

		public static string endSoundString;

		public static float exitSmallHop;

		public static GameObject selfOnHitOverlayEffectPrefab;

		public bool grantAnotherDash;

		private Transform modelTransform;

		private UnityEngine.Vector3 dashVector;

		private int originalLayer;

		private static int EvisLoopExitStateHash = Animator.StringToHash("EvisLoopExit");

		private static int AssaulterLoopStateHash = Animator.StringToHash("AssaulterLoop");

		private bool bufferedSkill2;

		private UnityEngine.Vector3 dashVelocity => dashVector * moveSpeedStat * speedCoefficient;

		public override void OnEnter()
		{
			base.OnEnter();
			dashVector = base.inputBank.aimDirection;
			originalLayer = base.gameObject.layer;
			base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
			base.characterMotor.Motor.RebuildCollidableLayers();
			base.characterMotor.Motor.ForceUnground();
			base.characterMotor.velocity = UnityEngine.Vector3.zero;
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance.duration = 0.7f;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matMercEnergized");
				temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
			}
			PlayCrossfade("FullBody, Override", "AssaulterLoop", 0.1f);
			base.characterDirection.forward = base.characterMotor.velocity.normalized;
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
			base.characterMotor.velocity *= speedCoefficientOnExit;
			SmallHop(base.characterMotor, exitSmallHop);
			Util.PlaySound(endSoundString, base.gameObject);
			PlayAnimation("FullBody, Override", EvisLoopExitStateHash);
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			base.OnExit();
		}

		protected override void PlayAnimation()
		{
			base.PlayAnimation();
			PlayCrossfade("FullBody, Override", AssaulterLoopStateHash, 0.1f);
		}

		protected override void AuthorityFixedUpdate()
		{
			base.AuthorityFixedUpdate();
			if (!base.authorityInHitPause)
			{
				base.characterMotor.rootMotion += dashVelocity * GetDeltaTime();
				base.characterDirection.forward = dashVelocity;
				base.characterDirection.moveVector = dashVelocity;
				base.characterBody.isSprinting = true;
				if (bufferedSkill2)
				{
					base.skillLocator.secondary.ExecuteIfReady();
					bufferedSkill2 = false;
				}
			}
			if ((bool)base.skillLocator && base.skillLocator.secondary.IsReady() && base.inputBank.skill2.down)
			{
				bufferedSkill2 = true;
			}
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			overlapAttack.damageType = DamageType.Stun1s;
			overlapAttack.damage = damageCoefficient * damageStat;
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			grantAnotherDash = true;
			float num = hitPauseDuration / attackSpeedStat;
			if ((bool)selfOnHitOverlayEffectPrefab && num > 1f / 30f)
			{
				EffectData effectData = new EffectData
				{
					origin = base.transform.position,
					genericFloat = hitPauseDuration / attackSpeedStat
				};
				effectData.SetNetworkedObjectReference(base.gameObject);
				EffectManager.SpawnEffect(selfOnHitOverlayEffectPrefab, effectData, transmit: true);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class Evis : BaseState
	{
		private Transform modelTransform;

		public static GameObject blinkPrefab;

		public static float duration = 2f;

		public static float damageCoefficient;

		public static float damageFrequency;

		public static float procCoefficient;

		public static string beginSoundString;

		public static string endSoundString;

		public static float maxRadius;

		public static GameObject hitEffectPrefab;

		public static string slashSoundString;

		public static string impactSoundString;

		public static string dashSoundString;

		public static float slashPitch;

		public static float smallHopVelocity;

		public static float lingeringInvincibilityDuration;

		private Animator animator;

		private CharacterModel characterModel;

		private float stopwatch;

		private float attackStopwatch;

		private bool crit;

		private static float minimumDuration = 0.5f;

		private CameraTargetParams.AimRequest aimRequest;

		public override void OnEnter()
		{
			base.OnEnter();
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
			Util.PlayAttackSpeedSound(beginSoundString, base.gameObject, 1.2f);
			crit = Util.CheckRoll(critStat, base.characterBody.master);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			stopwatch += deltaTime;
			attackStopwatch += deltaTime;
			float num = 1f / damageFrequency / attackSpeedStat;
			if (attackStopwatch >= num)
			{
				attackStopwatch -= num;
				HurtBox hurtBox = SearchForTarget();
				if ((bool)hurtBox)
				{
					Util.PlayAttackSpeedSound(slashSoundString, base.gameObject, slashPitch);
					Util.PlaySound(dashSoundString, base.gameObject);
					Util.PlaySound(impactSoundString, base.gameObject);
					HurtBoxGroup hurtBoxGroup = hurtBox.hurtBoxGroup;
					HurtBox hurtBox2 = hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, hurtBoxGroup.hurtBoxes.Length - 1)];
					if ((bool)hurtBox2)
					{
						UnityEngine.Vector3 position = hurtBox2.transform.position;
						UnityEngine.Vector2 normalized = UnityEngine.Random.insideUnitCircle.normalized;
						EffectManager.SimpleImpactEffect(normal: new UnityEngine.Vector3(normalized.x, 0f, normalized.y), effectPrefab: hitEffectPrefab, hitPos: position, transmit: false);
						Transform transform = hurtBox.hurtBoxGroup.transform;
						TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(transform.gameObject);
						temporaryOverlayInstance.duration = num;
						temporaryOverlayInstance.animateShaderAlpha = true;
						temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
						temporaryOverlayInstance.destroyComponentOnEnd = true;
						temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matMercEvisTarget");
						temporaryOverlayInstance.AddToCharacterModel(transform.GetComponent<CharacterModel>());
						if (NetworkServer.active)
						{
							DamageInfo damageInfo = new DamageInfo();
							damageInfo.damage = damageCoefficient * damageStat;
							damageInfo.attacker = base.gameObject;
							damageInfo.procCoefficient = procCoefficient;
							damageInfo.position = hurtBox2.transform.position;
							damageInfo.crit = crit;
							hurtBox2.healthComponent.TakeDamage(damageInfo);
							GlobalEventManager.instance.OnHitEnemy(damageInfo, hurtBox2.healthComponent.gameObject);
							GlobalEventManager.instance.OnHitAll(damageInfo, hurtBox2.healthComponent.gameObject);
						}
					}
				}
				else if (base.isAuthority && stopwatch > minimumDuration)
				{
					outer.SetNextStateToMain();
				}
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private HurtBox SearchForTarget()
		{
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = base.transform.position;
			bullseyeSearch.searchDirection = UnityEngine.Random.onUnitSphere;
			bullseyeSearch.maxDistanceFilter = maxRadius;
			bullseyeSearch.teamMaskFilter = TeamMask.GetUnprotectedTeams(GetTeam());
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.RefreshCandidates();
			bullseyeSearch.FilterOutGameObject(base.gameObject);
			return bullseyeSearch.GetResults().FirstOrDefault();
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up);
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false);
		}

		public override void OnExit()
		{
			Util.PlaySound(endSoundString, base.gameObject);
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance.duration = 0.6f;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matMercEvisTarget");
				temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
				TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance2.duration = 0.7f;
				temporaryOverlayInstance2.animateShaderAlpha = true;
				temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance2.destroyComponentOnEnd = true;
				temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashExpanded");
				temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			aimRequest?.Dispose();
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, lingeringInvincibilityDuration);
			}
			Util.PlaySound(endSoundString, base.gameObject);
			SmallHop(base.characterMotor, smallHopVelocity);
			base.OnExit();
		}
	}
	public class EvisDash : BaseState
	{
		private Transform modelTransform;

		public static GameObject blinkPrefab;

		private float stopwatch;

		private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero;

		public static float smallHopVelocity;

		public static float dashPrepDuration;

		public static float dashDuration = 0.3f;

		public static float speedCoefficient = 25f;

		public static string beginSoundString;

		public static string endSoundString;

		public static float overlapSphereRadius;

		public static float lollypopFactor;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private bool isDashing;

		private CameraTargetParams.AimRequest aimRequest;

		private static int EvisPrepStateHash = Animator.StringToHash("EvisPrep");

		private static int EvisPrepParamHash = Animator.StringToHash("EvisPrep.playbackRate");

		private static int EvisLoopExitStateHash = Animator.StringToHash("EvisLoopExit");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
			}
			if (base.isAuthority)
			{
				SmallHop(base.characterMotor, smallHopVelocity);
			}
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
			PlayAnimation("FullBody, Override", EvisPrepStateHash, EvisPrepParamHash, dashPrepDuration);
			dashVector = base.inputBank.aimDirection;
			base.characterDirection.forward = dashVector;
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(dashVector);
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch > dashPrepDuration && !isDashing)
			{
				isDashing = true;
				dashVector = base.inputBank.aimDirection;
				CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
				PlayCrossfade("FullBody, Override", "EvisLoop", 0.1f);
				if ((bool)modelTransform)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
					temporaryOverlayInstance.duration = 0.6f;
					temporaryOverlayInstance.animateShaderAlpha = true;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashBright");
					temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
					TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
					temporaryOverlayInstance2.duration = 0.7f;
					temporaryOverlayInstance2.animateShaderAlpha = true;
					temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance2.destroyComponentOnEnd = true;
					temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashExpanded");
					temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
				}
			}
			bool flag = stopwatch >= dashDuration + dashPrepDuration;
			if (isDashing)
			{
				if ((bool)base.characterMotor && (bool)base.characterDirection)
				{
					base.characterMotor.rootMotion += dashVector * (moveSpeedStat * speedCoefficient * GetDeltaTime());
				}
				if (base.isAuthority)
				{
					Collider[] colliders;
					int num = HGPhysics.OverlapSphere(out colliders, base.transform.position, base.characterBody.radius + overlapSphereRadius * (flag ? lollypopFactor : 1f), LayerIndex.entityPrecise.mask);
					for (int i = 0; i < num; i++)
					{
						HurtBox component = colliders[i].GetComponent<HurtBox>();
						if ((bool)component && component.healthComponent != base.healthComponent)
						{
							Evis nextState = new Evis();
							outer.SetNextState(nextState);
							break;
						}
					}
					HGPhysics.ReturnResults(colliders);
				}
			}
			if (flag && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(endSoundString, base.gameObject);
			base.characterMotor.velocity *= 0.1f;
			SmallHop(base.characterMotor, smallHopVelocity);
			aimRequest?.Dispose();
			PlayAnimation("FullBody, Override", EvisLoopExitStateHash);
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
			base.OnExit();
		}
	}
	public class FocusedAssaultDash : BasicMeleeAttack
	{
		[SerializeField]
		public float speedCoefficientOnExit;

		[SerializeField]
		public float speedCoefficient;

		[SerializeField]
		public string endSoundString;

		[SerializeField]
		public float exitSmallHop;

		[SerializeField]
		public float delayedDamageCoefficient;

		[SerializeField]
		public float delayedProcCoefficient;

		[SerializeField]
		public float delay;

		[SerializeField]
		public string enterAnimationLayerName = "FullBody, Override";

		[SerializeField]
		public string enterAnimationStateName = "AssaulterLoop";

		[SerializeField]
		public float enterAnimationCrossfadeDuration = 0.1f;

		[SerializeField]
		public string exitAnimationLayerName = "FullBody, Override";

		[SerializeField]
		public string exitAnimationStateName = "EvisLoopExit";

		[SerializeField]
		public Material enterOverlayMaterial;

		[SerializeField]
		public float enterOverlayDuration = 0.7f;

		[SerializeField]
		public GameObject delayedEffectPrefab;

		[SerializeField]
		public GameObject orbEffect;

		[SerializeField]
		public float delayPerHit;

		[SerializeField]
		public GameObject selfOnHitOverlayEffectPrefab;

		private Transform modelTransform;

		private UnityEngine.Vector3 dashVector;

		private int originalLayer;

		private int currentHitCount;

		private UnityEngine.Vector3 dashVelocity => dashVector * moveSpeedStat * speedCoefficient;

		public override void OnEnter()
		{
			base.OnEnter();
			dashVector = base.inputBank.aimDirection;
			originalLayer = base.gameObject.layer;
			base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
			base.characterMotor.Motor.RebuildCollidableLayers();
			base.characterMotor.Motor.ForceUnground();
			base.characterMotor.velocity = UnityEngine.Vector3.zero;
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance.duration = enterOverlayDuration;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = enterOverlayMaterial;
				temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
			}
			PlayCrossfade(enterAnimationLayerName, enterAnimationStateName, enterAnimationCrossfadeDuration);
			base.characterDirection.forward = base.characterMotor.velocity.normalized;
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
			base.characterMotor.velocity *= speedCoefficientOnExit;
			SmallHop(base.characterMotor, exitSmallHop);
			Util.PlaySound(endSoundString, base.gameObject);
			PlayAnimation(exitAnimationLayerName, exitAnimationStateName);
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			base.OnExit();
		}

		protected override void PlayAnimation()
		{
			base.PlayAnimation();
			PlayCrossfade(enterAnimationLayerName, enterAnimationStateName, enterAnimationCrossfadeDuration);
		}

		protected override void AuthorityFixedUpdate()
		{
			base.AuthorityFixedUpdate();
			if (!base.authorityInHitPause)
			{
				base.characterMotor.rootMotion += dashVelocity * GetDeltaTime();
				base.characterDirection.forward = dashVelocity;
				base.characterDirection.moveVector = dashVelocity;
				base.characterBody.isSprinting = true;
			}
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			overlapAttack.damage = damageCoefficient * damageStat;
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			float num = hitPauseDuration / attackSpeedStat;
			if ((bool)selfOnHitOverlayEffectPrefab && num > 1f / 30f)
			{
				EffectData effectData = new EffectData
				{
					origin = base.transform.position,
					genericFloat = hitPauseDuration / attackSpeedStat
				};
				effectData.SetNetworkedObjectReference(base.gameObject);
				EffectManager.SpawnEffect(selfOnHitOverlayEffectPrefab, effectData, transmit: true);
			}
			foreach (HurtBox hitResult in hitResults)
			{
				currentHitCount++;
				float damageValue = base.characterBody.damage * delayedDamageCoefficient;
				float num2 = delay + delayPerHit * (float)currentHitCount;
				bool isCrit = RollCrit();
				HandleHit(base.gameObject, hitResult, damageValue, delayedProcCoefficient, isCrit, num2, orbEffect, delayedEffectPrefab);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		private static void HandleHit(GameObject attackerObject, HurtBox victimHurtBox, float damageValue, float procCoefficient, bool isCrit, float delay, GameObject orbEffectPrefab, GameObject orbImpactEffectPrefab)
		{
			if (!NetworkServer.active)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				networkWriter.StartMessage(77);
				networkWriter.Write(attackerObject);
				networkWriter.Write(HurtBoxReference.FromHurtBox(victimHurtBox));
				networkWriter.Write(damageValue);
				networkWriter.Write(procCoefficient);
				networkWriter.Write(isCrit);
				networkWriter.Write(delay);
				networkWriter.WriteEffectIndex(EffectCatalog.FindEffectIndexFromPrefab(orbEffectPrefab));
				networkWriter.WriteEffectIndex(EffectCatalog.FindEffectIndexFromPrefab(orbImpactEffectPrefab));
				networkWriter.FinishMessage();
				ClientScene.readyConnection?.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
			}
			else if ((bool)victimHurtBox && (bool)victimHurtBox.healthComponent)
			{
				SetStateOnHurt.SetStunOnObject(victimHurtBox.healthComponent.gameObject, delay);
				OrbManager.instance.AddOrb(new DelayedHitOrb
				{
					attacker = attackerObject,
					target = victimHurtBox,
					damageColorIndex = DamageColorIndex.Default,
					damageValue = damageValue,
					damageType = DamageType.ApplyMercExpose,
					isCrit = isCrit,
					procChainMask = default(ProcChainMask),
					procCoefficient = procCoefficient,
					delay = delay,
					orbEffect = orbEffectPrefab,
					delayedEffectPrefab = orbImpactEffectPrefab
				});
			}
		}

		[NetworkMessageHandler(msgType = 77, client = false, server = true)]
		private static void HandleReportMercFocusedAssaultHitReplaceMeLater(NetworkMessage netMsg)
		{
			GameObject attackerObject = netMsg.reader.ReadGameObject();
			HurtBox victimHurtBox = netMsg.reader.ReadHurtBoxReference().ResolveHurtBox();
			float damageValue = netMsg.reader.ReadSingle();
			float num = netMsg.reader.ReadSingle();
			bool isCrit = netMsg.reader.ReadBoolean();
			float num2 = netMsg.reader.ReadSingle();
			GameObject orbEffectPrefab = EffectCatalog.GetEffectDef(netMsg.reader.ReadEffectIndex())?.prefab ?? null;
			GameObject orbImpactEffectPrefab = EffectCatalog.GetEffectDef(netMsg.reader.ReadEffectIndex())?.prefab ?? null;
			HandleHit(attackerObject, victimHurtBox, damageValue, num, isCrit, num2, orbEffectPrefab, orbImpactEffectPrefab);
		}
	}
	public class FocusedAssaultPrep : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float smallHopVelocity;

		[SerializeField]
		public string enterSoundString;

		private float duration;

		private static int AssaulterPrepStateHash = Animator.StringToHash("AssaulterPrep");

		private static int AssaulterPrepParamHash = Animator.StringToHash("AssaulterPrep.playbackRate");

		public int dashIndex { private get; set; }

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("FullBody, Override", AssaulterPrepStateHash, AssaulterPrepParamHash, baseDuration);
			FindModelChildGameObject("PreDashEffect")?.SetActive(value: true);
			Util.PlaySound(enterSoundString, base.gameObject);
			Ray aimRay = GetAimRay();
			base.characterDirection.forward = aimRay.direction;
			base.characterDirection.moveVector = aimRay.direction;
			SmallHop(base.characterMotor, smallHopVelocity);
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 0.2f);
			}
			FindModelChildGameObject("PreDashEffect")?.SetActive(value: false);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new FocusedAssaultDash());
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)dashIndex);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			dashIndex = reader.ReadByte();
		}
	}
	public class GroundLight : BaseState
	{
		public enum ComboState
		{
			GroundLight1,
			GroundLight2,
			GroundLight3
		}

		private struct ComboStateInfo
		{
			private string mecanimStateName;

			private string mecanimPlaybackRateName;
		}

		public static float baseComboAttackDuration;

		public static float baseFinisherAttackDuration;

		public static float baseEarlyExitDuration;

		public static string comboAttackSoundString;

		public static string finisherAttackSoundString;

		public static float comboDamageCoefficient;

		public static float finisherDamageCoefficient;

		public static float forceMagnitude;

		public static GameObject comboHitEffectPrefab;

		public static GameObject finisherHitEffectPrefab;

		public static GameObject comboSwingEffectPrefab;

		public static GameObject finisherSwingEffectPrefab;

		public static float hitPauseDuration;

		public static float selfForceMagnitude;

		public static string hitSoundString;

		public static float slashPitch;

		private float stopwatch;

		private float attackDuration;

		private float earlyExitDuration;

		private Animator animator;

		private OverlapAttack overlapAttack;

		private float hitPauseTimer;

		private bool isInHitPause;

		private bool hasSwung;

		private bool hasHit;

		private GameObject swingEffectInstance;

		public ComboState comboState;

		private UnityEngine.Vector3 characterForward;

		private string slashChildName;

		private HitStopCachedState hitStopCachedState;

		private GameObject swingEffectPrefab;

		private GameObject hitEffectPrefab;

		private string attackSoundString;

		private static int GroundLight1StateHash = Animator.StringToHash("GroundLight1");

		private static int GroundLight2StateHash = Animator.StringToHash("GroundLight2");

		private static int GroundLight3StateHash = Animator.StringToHash("GroundLight3");

		private static int GroundLightParamHash = Animator.StringToHash("GroundLight.playbackRate");

		private static int SwordactiveParamHash = Animator.StringToHash("Sword.active");

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			earlyExitDuration = baseEarlyExitDuration / attackSpeedStat;
			animator = GetModelAnimator();
			bool @bool = animator.GetBool("isMoving");
			bool bool2 = animator.GetBool("isGrounded");
			switch (comboState)
			{
			case ComboState.GroundLight1:
				attackDuration = baseComboAttackDuration / attackSpeedStat;
				overlapAttack = InitMeleeOverlap(comboDamageCoefficient, hitEffectPrefab, GetModelTransform(), "Sword");
				if (@bool || !bool2)
				{
					PlayAnimation("Gesture, Additive", GroundLight1StateHash, GroundLightParamHash, attackDuration);
					PlayAnimation("Gesture, Override", GroundLight1StateHash, GroundLightParamHash, attackDuration);
				}
				else
				{
					PlayAnimation("FullBody, Override", GroundLight1StateHash, GroundLightParamHash, attackDuration);
				}
				slashChildName = "GroundLight1Slash";
				swingEffectPrefab = comboSwingEffectPrefab;
				hitEffectPrefab = comboHitEffectPrefab;
				attackSoundString = comboAttackSoundString;
				break;
			case ComboState.GroundLight2:
				attackDuration = baseComboAttackDuration / attackSpeedStat;
				overlapAttack = InitMeleeOverlap(comboDamageCoefficient, hitEffectPrefab, GetModelTransform(), "Sword");
				if (@bool || !bool2)
				{
					PlayAnimation("Gesture, Additive", GroundLight2StateHash, GroundLightParamHash, attackDuration);
					PlayAnimation("Gesture, Override", GroundLight2StateHash, GroundLightParamHash, attackDuration);
				}
				else
				{
					PlayAnimation("FullBody, Override", GroundLight2StateHash, GroundLightParamHash, attackDuration);
				}
				slashChildName = "GroundLight2Slash";
				swingEffectPrefab = comboSwingEffectPrefab;
				hitEffectPrefab = comboHitEffectPrefab;
				attackSoundString = comboAttackSoundString;
				break;
			case ComboState.GroundLight3:
				attackDuration = baseFinisherAttackDuration / attackSpeedStat;
				overlapAttack = InitMeleeOverlap(finisherDamageCoefficient, hitEffectPrefab, GetModelTransform(), "SwordLarge");
				if (@bool || !bool2)
				{
					PlayAnimation("Gesture, Additive", GroundLight3StateHash, GroundLightParamHash, attackDuration);
					PlayAnimation("Gesture, Override", GroundLight3StateHash, GroundLightParamHash, attackDuration);
				}
				else
				{
					PlayAnimation("FullBody, Override", GroundLight3StateHash, GroundLightParamHash, attackDuration);
				}
				slashChildName = "GroundLight3Slash";
				swingEffectPrefab = finisherSwingEffectPrefab;
				hitEffectPrefab = finisherHitEffectPrefab;
				attackSoundString = finisherAttackSoundString;
				break;
			}
			base.characterBody.SetAimTimer(attackDuration + 1f);
			overlapAttack.hitEffectPrefab = hitEffectPrefab;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			hitPauseTimer -= GetDeltaTime();
			if (base.isAuthority)
			{
				bool flag = FireMeleeOverlap(overlapAttack, animator, "Sword.active", forceMagnitude);
				hasHit |= flag;
				if (flag)
				{
					Util.PlaySound(hitSoundString, base.gameObject);
					if (!isInHitPause)
					{
						hitStopCachedState = CreateHitStopCachedState(base.characterMotor, animator, "GroundLight.playbackRate");
						hitPauseTimer = hitPauseDuration / attackSpeedStat;
						isInHitPause = true;
					}
				}
				if (hitPauseTimer <= 0f && isInHitPause)
				{
					ConsumeHitStopCachedState(hitStopCachedState, base.characterMotor, animator);
					isInHitPause = false;
				}
			}
			if (animator.GetFloat(SwordactiveParamHash) > 0f && !hasSwung)
			{
				Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, slashPitch);
				HealthComponent healthComponent = base.characterBody.healthComponent;
				CharacterDirection component = base.characterBody.GetComponent<CharacterDirection>();
				if ((bool)healthComponent)
				{
					healthComponent.TakeDamageForce(selfForceMagnitude * component.forward, alwaysApply: true);
				}
				hasSwung = true;
				EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, slashChildName, transmit: false);
			}
			if (!isInHitPause)
			{
				stopwatch += GetDeltaTime();
			}
			else
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				animator.SetFloat(GroundLightParamHash, 0f);
			}
			if (base.isAuthority && stopwatch >= attackDuration - earlyExitDuration)
			{
				if (!hasSwung)
				{
					overlapAttack.Fire();
				}
				if (base.inputBank.skill1.down && comboState != ComboState.GroundLight3)
				{
					GroundLight groundLight = new GroundLight();
					groundLight.comboState = comboState + 1;
					outer.SetNextState(groundLight);
				}
				else if (stopwatch >= attackDuration)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)comboState);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			comboState = (ComboState)reader.ReadByte();
		}
	}
	public class Uppercut : BaseState
	{
		public static GameObject swingEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static string enterSoundString;

		public static string attackSoundString;

		public static string hitSoundString;

		public static float slashPitch;

		public static float hitPauseDuration;

		public static float upwardForceStrength;

		public static float baseDuration;

		public static float baseDamageCoefficient;

		public static string slashChildName;

		public static float moveSpeedBonusCoefficient;

		public static string hitboxString;

		public static AnimationCurve yVelocityCurve;

		protected Animator animator;

		protected float duration;

		protected float hitInterval;

		protected bool hasSwung;

		protected float hitPauseTimer;

		protected bool isInHitPause;

		protected OverlapAttack overlapAttack;

		protected HitStopCachedState hitStopCachedState;

		private static int UppercutExitStateHash = Animator.StringToHash("UppercutExit");

		private static int UppercutStateHash = Animator.StringToHash("Uppercut");

		private static int UppercutParamHash = Animator.StringToHash("Uppercut.playbackRate");

		private static int SwordactiveParamHash = Animator.StringToHash("Sword.active");

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			duration = baseDuration / attackSpeedStat;
			overlapAttack = InitMeleeOverlap(baseDamageCoefficient, hitEffectPrefab, GetModelTransform(), hitboxString);
			overlapAttack.forceVector = UnityEngine.Vector3.up * upwardForceStrength;
			if ((bool)base.characterDirection && (bool)base.inputBank)
			{
				base.characterDirection.forward = base.inputBank.aimDirection;
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			PlayAnim();
		}

		protected virtual void PlayAnim()
		{
			PlayCrossfade("FullBody, Override", UppercutStateHash, UppercutParamHash, duration, 0.1f);
		}

		public override void OnExit()
		{
			base.OnExit();
			PlayAnimation("FullBody, Override", UppercutExitStateHash);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			hitPauseTimer -= deltaTime;
			if (!base.isAuthority)
			{
				return;
			}
			if (animator.GetFloat(SwordactiveParamHash) > 0.2f && !hasSwung)
			{
				hasSwung = true;
				base.characterMotor.Motor.ForceUnground();
				Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, slashPitch);
				EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, slashChildName, transmit: true);
			}
			if (FireMeleeOverlap(overlapAttack, animator, SwordactiveParamHash, 0f, calculateForceVector: false))
			{
				Util.PlaySound(hitSoundString, base.gameObject);
				if (!isInHitPause)
				{
					hitStopCachedState = CreateHitStopCachedState(base.characterMotor, animator, "Uppercut.playbackRate");
					hitPauseTimer = hitPauseDuration / attackSpeedStat;
					isInHitPause = true;
				}
			}
			if (hitPauseTimer <= 0f && isInHitPause)
			{
				ConsumeHitStopCachedState(hitStopCachedState, base.characterMotor, animator);
				base.characterMotor.Motor.ForceUnground();
				isInHitPause = false;
			}
			if (!isInHitPause)
			{
				if ((bool)base.characterMotor && (bool)base.characterDirection)
				{
					UnityEngine.Vector3 velocity = base.characterDirection.forward * moveSpeedStat * Mathf.Lerp(moveSpeedBonusCoefficient, 0f, base.age / duration);
					velocity.y = yVelocityCurve.Evaluate(base.fixedAge / duration);
					base.characterMotor.velocity = velocity;
				}
			}
			else
			{
				base.fixedAge -= deltaTime;
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				hitPauseTimer -= deltaTime;
				animator.SetFloat(UppercutParamHash, 0f);
			}
			if (base.fixedAge >= duration)
			{
				if (hasSwung)
				{
					hasSwung = true;
					overlapAttack.Fire();
				}
				outer.SetNextStateToMain();
			}
		}
	}
	public class WhirlwindBase : BaseState
	{
		public static GameObject swingEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static string attackSoundString;

		public static string hitSoundString;

		public static float slashPitch;

		public static float hitPauseDuration;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float baseDamageCoefficient;

		[SerializeField]
		public string slashChildName;

		[SerializeField]
		public float selfForceMagnitude;

		[SerializeField]
		public float moveSpeedBonusCoefficient;

		[SerializeField]
		public float smallHopVelocity;

		[SerializeField]
		public string hitboxString;

		protected Animator animator;

		protected float duration;

		protected float hitInterval;

		protected int swingCount;

		protected float hitPauseTimer;

		protected bool isInHitPause;

		protected OverlapAttack overlapAttack;

		protected HitStopCachedState hitStopCachedState;

		private static int SwordactiveParamHash = Animator.StringToHash("Sword.active");

		private static int WhirlwindplaybackRateParamHash = Animator.StringToHash("Whirlwind.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			duration = baseDuration / attackSpeedStat;
			overlapAttack = InitMeleeOverlap(baseDamageCoefficient, hitEffectPrefab, GetModelTransform(), hitboxString);
			if ((bool)base.characterDirection && (bool)base.inputBank)
			{
				base.characterDirection.forward = base.inputBank.aimDirection;
			}
			SmallHop(base.characterMotor, smallHopVelocity);
			PlayAnim();
		}

		protected virtual void PlayAnim()
		{
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			hitPauseTimer -= GetDeltaTime();
			if (animator.GetFloat("Sword.active") > (float)swingCount)
			{
				swingCount++;
				Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, slashPitch);
				EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, slashChildName, transmit: false);
				if (base.isAuthority)
				{
					overlapAttack.ResetIgnoredHealthComponents();
					if ((bool)base.characterMotor)
					{
						base.characterMotor.ApplyForce(selfForceMagnitude * base.characterDirection.forward, alwaysApply: true);
					}
				}
			}
			if (!base.isAuthority)
			{
				return;
			}
			if (FireMeleeOverlap(overlapAttack, animator, SwordactiveParamHash, 0f))
			{
				Util.PlaySound(hitSoundString, base.gameObject);
				if (!isInHitPause)
				{
					hitStopCachedState = CreateHitStopCachedState(base.characterMotor, animator, "Whirlwind.playbackRate");
					hitPauseTimer = hitPauseDuration / attackSpeedStat;
					isInHitPause = true;
				}
			}
			if (hitPauseTimer <= 0f && isInHitPause)
			{
				ConsumeHitStopCachedState(hitStopCachedState, base.characterMotor, animator);
				isInHitPause = false;
			}
			if (!isInHitPause)
			{
				if ((bool)base.characterMotor && (bool)base.characterDirection)
				{
					UnityEngine.Vector3 velocity = base.characterDirection.forward * moveSpeedStat * Mathf.Lerp(moveSpeedBonusCoefficient, 1f, base.age / duration);
					velocity.y = base.characterMotor.velocity.y;
					base.characterMotor.velocity = velocity;
				}
			}
			else
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				hitPauseTimer -= GetDeltaTime();
				animator.SetFloat(WhirlwindplaybackRateParamHash, 0f);
			}
			if (base.fixedAge >= duration)
			{
				while (swingCount < 2)
				{
					swingCount++;
					overlapAttack.Fire();
				}
				outer.SetNextStateToMain();
			}
		}
	}
	public class WhirlwindAir : WhirlwindBase
	{
		private static int WhirlwindAirExitStateHash = Animator.StringToHash("WhirlwindAirExit");

		private static int WhirlwindAirStateHash = Animator.StringToHash("WhirlwindAir");

		private static int WhirlwindParamHash = Animator.StringToHash("Whirlwind.playbackRate");

		protected override void PlayAnim()
		{
			PlayCrossfade("FullBody, Override", WhirlwindAirStateHash, WhirlwindParamHash, duration, 0.1f);
		}

		public override void OnExit()
		{
			base.OnExit();
			PlayAnimation("FullBody, Override", WhirlwindAirExitStateHash);
		}
	}
	public class WhirlwindEntry : BaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				EntityState nextState = (((bool)base.characterMotor && base.characterMotor.isGrounded) ? ((WhirlwindBase)new WhirlwindGround()) : ((WhirlwindBase)new WhirlwindAir()));
				outer.SetNextState(nextState);
			}
		}
	}
	public class WhirlwindGround : WhirlwindBase
	{
		private static int WhirlwindGroundStateHash = Animator.StringToHash("WhirlwindGround");

		private static int LightImpactStateHash = Animator.StringToHash("LightImpact");

		private static int WhirlwindParamHash = Animator.StringToHash("Whirlwind.playbackRate");

		protected override void PlayAnim()
		{
			PlayCrossfade("FullBody, Override", WhirlwindGroundStateHash, WhirlwindParamHash, duration, 0.1f);
		}

		public override void OnExit()
		{
			base.OnExit();
			int layerIndex = animator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, 3f);
				PlayAnimation("Impact", LightImpactStateHash);
			}
		}
	}
}
namespace EntityStates.Merc.Weapon
{
	public class GroundLight2 : BasicMeleeAttack, SteppedSkillDef.IStepSetter
	{
		public int step;

		public static float recoilAmplitude;

		public static float baseDurationBeforeInterruptable;

		[SerializeField]
		public float bloom;

		public static float comboFinisherBaseDuration;

		public static GameObject comboFinisherSwingEffectPrefab;

		public static float comboFinisherhitPauseDuration;

		public static float comboFinisherDamageCoefficient;

		public static float comboFinisherBloom;

		public static float comboFinisherBaseDurationBeforeInterruptable;

		public static string slash1Sound;

		public static string slash3Sound;

		private string animationStateName;

		private float durationBeforeInterruptable;

		private bool isComboFinisher => step == 2;

		protected override bool allowExitFire
		{
			get
			{
				if ((bool)base.characterBody)
				{
					return !base.characterBody.isSprinting;
				}
				return false;
			}
		}

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			step = i;
		}

		public override void OnEnter()
		{
			if (isComboFinisher)
			{
				swingEffectPrefab = comboFinisherSwingEffectPrefab;
				hitPauseDuration = comboFinisherhitPauseDuration;
				damageCoefficient = comboFinisherDamageCoefficient;
				bloom = comboFinisherBloom;
				hitBoxGroupName = "SwordLarge";
				baseDuration = comboFinisherBaseDuration;
			}
			base.OnEnter();
			base.characterDirection.forward = GetAimRay().direction;
			durationBeforeInterruptable = (isComboFinisher ? (comboFinisherBaseDurationBeforeInterruptable / attackSpeedStat) : (baseDurationBeforeInterruptable / attackSpeedStat));
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			if (isComboFinisher)
			{
				overlapAttack.damageType = DamageType.ApplyMercExpose;
			}
		}

		protected override void PlayAnimation()
		{
			animationStateName = "";
			string soundString = null;
			switch (step)
			{
			case 0:
				animationStateName = "GroundLight1";
				soundString = slash1Sound;
				break;
			case 1:
				animationStateName = "GroundLight2";
				soundString = slash1Sound;
				break;
			case 2:
				animationStateName = "GroundLight3";
				soundString = slash3Sound;
				break;
			}
			bool @bool = animator.GetBool("isMoving");
			bool bool2 = animator.GetBool("isGrounded");
			if (!@bool && bool2)
			{
				PlayCrossfade("FullBody, Override", animationStateName, "GroundLight.playbackRate", duration, 0.05f);
			}
			else
			{
				PlayCrossfade("Gesture, Additive", animationStateName, "GroundLight.playbackRate", duration, 0.05f);
				PlayCrossfade("Gesture, Override", animationStateName, "GroundLight.playbackRate", duration, 0.05f);
			}
			Util.PlaySound(soundString, base.gameObject);
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			base.characterBody.AddSpreadBloom(bloom);
		}

		protected override void BeginMeleeAttackEffect()
		{
			swingEffectMuzzleString = animationStateName;
			AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			base.BeginMeleeAttackEffect();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)step);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			step = reader.ReadByte();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge < durationBeforeInterruptable))
			{
				return InterruptPriority.Skill;
			}
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ThrowEvisProjectile : GenericProjectileBaseState
	{
		public static float shortHopVelocity;

		private static int GroundLight3StateHash = Animator.StringToHash("GroundLight3");

		private static int GroundLightParamHash = Animator.StringToHash("GroundLight.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity);
			}
		}

		protected override void PlayAnimation(float duration)
		{
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				bool @bool = modelAnimator.GetBool("isMoving");
				bool bool2 = modelAnimator.GetBool("isGrounded");
				if (@bool || !bool2)
				{
					PlayAnimation("Gesture, Additive", GroundLight3StateHash, GroundLightParamHash, duration);
					PlayAnimation("Gesture, Override", GroundLight3StateHash, GroundLightParamHash, duration);
				}
				else
				{
					PlayAnimation("FullBody, Override", GroundLight3StateHash, GroundLightParamHash, duration);
				}
			}
		}

		protected override Ray ModifyProjectileAimRay(Ray aimRay)
		{
			TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, projectilePrefab, base.gameObject);
			return aimRay;
		}
	}
}
namespace EntityStates.MegaConstruct
{
	public class FallingDeath : GenericCharacterDeath
	{
		public static float deathDelay;

		public static GameObject enterEffectPrefab;

		public static GameObject deathEffectPrefab;

		public static float explosionForce;

		public static string standableSurfaceChildName;

		private bool hasDied;

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleImpactEffect(enterEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true);
			MasterSpawnSlotController component = GetComponent<MasterSpawnSlotController>();
			if (NetworkServer.active && (bool)component)
			{
				component.KillAll();
			}
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				Transform transform = modelChildLocator.FindChild(standableSurfaceChildName);
				if ((bool)transform)
				{
					transform.gameObject.SetActive(value: false);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > deathDelay && NetworkServer.active && !hasDied)
			{
				hasDied = true;
				EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true);
				DestroyBodyAsapServer();
			}
		}

		public override void OnExit()
		{
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				Rigidbody component = GetComponent<Rigidbody>();
				RagdollController component2 = modelTransform.GetComponent<RagdollController>();
				if ((bool)component2 && (bool)component)
				{
					component2.BeginRagdoll(component.velocity);
				}
				ExplodeRigidbodiesOnStart component3 = modelTransform.GetComponent<ExplodeRigidbodiesOnStart>();
				if ((bool)component3)
				{
					component3.force = explosionForce;
					component3.enabled = true;
				}
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.enabled = false;
			}
			base.OnExit();
		}
	}
	public class RaiseShield : FlyState
	{
		[SerializeField]
		public GameObject attachmentPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationEnterStateName;

		[SerializeField]
		public float duration;

		private NetworkedBodyAttachment attachment;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active && (bool)attachmentPrefab)
			{
				attachment = UnityEngine.Object.Instantiate(attachmentPrefab).GetComponent<NetworkedBodyAttachment>();
				attachment.AttachToGameObjectAndSpawn(base.characterBody.gameObject);
			}
			MasterSpawnSlotController component = GetComponent<MasterSpawnSlotController>();
			if (NetworkServer.active && (bool)component)
			{
				component.SpawnAllOpen(base.gameObject, Run.instance.stageRng);
			}
			PlayAnimation(animationLayerName, animationEnterStateName);
		}

		protected override bool CanExecuteSkill(GenericSkill skillSlot)
		{
			return false;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new ExitShield());
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active && (bool)attachment)
			{
				EntityState.Destroy(attachment.gameObject);
			}
			base.OnExit();
		}
	}
	public class ExitShield : BaseState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackParameterName;

		[SerializeField]
		public float baseDuration;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, baseDuration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > baseDuration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class Spawn : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public int numPads;

		[SerializeField]
		public string padChildLocatorName;

		[SerializeField]
		public GameObject padPrefab;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public bool depleteStocksPrimary;

		[SerializeField]
		public bool depleteStocksSecondary;

		[SerializeField]
		public bool depleteStocksUtility;

		[SerializeField]
		public bool depleteStocksSpecial;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		private void CheckForDepleteStocks(SkillSlot slot, bool deplete)
		{
			GenericSkill skill = base.skillLocator.GetSkill(slot);
			if (deplete && (bool)skill)
			{
				skill.RemoveAllStocks();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (base.isAuthority)
			{
				CheckForDepleteStocks(SkillSlot.Primary, depleteStocksPrimary);
				CheckForDepleteStocks(SkillSlot.Secondary, depleteStocksSecondary);
				CheckForDepleteStocks(SkillSlot.Utility, depleteStocksUtility);
				CheckForDepleteStocks(SkillSlot.Special, depleteStocksSpecial);
			}
			base.OnExit();
		}
	}
	public class SpawnMinorConstructs : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public int numToSpawn;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			MasterSpawnSlotController component = GetComponent<MasterSpawnSlotController>();
			if (NetworkServer.active && (bool)component)
			{
				component.SpawnRandomOpen(numToSpawn, Run.instance.stageRng, base.gameObject);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.MajorConstruct
{
	public class Death : GenericCharacterDeath
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public GameObject beginEffect;

		[SerializeField]
		public string beginMuzzleName;

		[SerializeField]
		public GameObject padEffect;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayAnimation(animationLayerName, animationStateName);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)beginEffect)
			{
				EffectManager.SimpleMuzzleFlash(beginEffect, base.gameObject, beginMuzzleName, transmit: false);
			}
			FindModelChild("Collision").gameObject.SetActive(value: false);
			MasterSpawnSlotController component = GetComponent<MasterSpawnSlotController>();
			if (NetworkServer.active)
			{
				_ = (bool)component;
			}
		}
	}
	public class Spawn : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public int numPads;

		[SerializeField]
		public float padRingRadius;

		[SerializeField]
		public float maxRaycastDistance;

		[SerializeField]
		public GameObject padPrefab;

		[SerializeField]
		public float maxPadDistance;

		[SerializeField]
		public GameObject padEffectPrefab;

		[SerializeField]
		public bool alignPadsToNormal;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public bool depleteStocksPrimary;

		[SerializeField]
		public bool depleteStocksSecondary;

		[SerializeField]
		public bool depleteStocksUtility;

		[SerializeField]
		public bool depleteStocksSpecial;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			MasterSpawnSlotController component = GetComponent<MasterSpawnSlotController>();
			if (!NetworkServer.active || !padPrefab || !component)
			{
				return;
			}
			RaycastHit hitInfo = default(RaycastHit);
			for (int i = 0; i < numPads; i++)
			{
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, 360f * ((float)i / (float)numPads), 0f);
				UnityEngine.Vector3 vector = base.characterBody.corePosition + quaternion * UnityEngine.Vector3.forward * padRingRadius;
				UnityEngine.Vector3 origin = vector + UnityEngine.Vector3.up * maxRaycastDistance;
				if (Physics.Raycast(vector, UnityEngine.Vector3.up, out hitInfo, maxRaycastDistance, LayerIndex.world.mask))
				{
					origin = hitInfo.point;
				}
				if (Physics.Raycast(origin, UnityEngine.Vector3.down, out hitInfo, maxRaycastDistance * 2f, LayerIndex.world.mask) && UnityEngine.Vector3.Distance(base.characterBody.corePosition, hitInfo.point) < maxPadDistance)
				{
					if (alignPadsToNormal)
					{
						quaternion = UnityEngine.Quaternion.FromToRotation(UnityEngine.Vector3.up, hitInfo.normal) * quaternion;
					}
					GameObject obj = UnityEngine.Object.Instantiate(padPrefab, hitInfo.point, quaternion);
					NetworkedBodySpawnSlot component2 = obj.GetComponent<NetworkedBodySpawnSlot>();
					if ((bool)component2)
					{
						component.slots.Add(component2);
					}
					NetworkServer.Spawn(obj);
					if ((bool)padEffectPrefab)
					{
						EffectData effectData = new EffectData
						{
							origin = hitInfo.point,
							rotation = quaternion
						};
						EffectManager.SpawnEffect(padEffectPrefab, effectData, transmit: true);
					}
				}
			}
		}

		private void CheckForDepleteStocks(SkillSlot slot, bool deplete)
		{
			GenericSkill skill = base.skillLocator.GetSkill(slot);
			if (deplete && (bool)skill)
			{
				skill.RemoveAllStocks();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (base.isAuthority)
			{
				CheckForDepleteStocks(SkillSlot.Primary, depleteStocksPrimary);
				CheckForDepleteStocks(SkillSlot.Secondary, depleteStocksSecondary);
				CheckForDepleteStocks(SkillSlot.Utility, depleteStocksUtility);
				CheckForDepleteStocks(SkillSlot.Special, depleteStocksSpecial);
			}
			base.OnExit();
		}
	}
	public class SpawnMinorConstructs : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public int numToSpawn;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParam;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParam, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			MasterSpawnSlotController component = GetComponent<MasterSpawnSlotController>();
			if (NetworkServer.active && (bool)component)
			{
				component.SpawnRandomOpen(numToSpawn, Run.instance.stageRng, base.gameObject);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SwitchStance : BaseState
	{
		private const string stanceStateMachineName = "Stance";

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.isAuthority)
			{
				return;
			}
			EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Stance");
			EntityState state = entityStateMachine.state;
			if (!(state is Raised))
			{
				if (state is Lowered)
				{
					entityStateMachine.SetNextState(new LoweredToRaised());
				}
			}
			else
			{
				entityStateMachine.SetNextState(new RaisedToLowered());
			}
			outer.SetNextStateToMain();
		}
	}
}
namespace EntityStates.MajorConstruct.Stance
{
	public class Lowered : BaseState
	{
		[SerializeField]
		public GameObject attachmentPrefab;

		private NetworkedBodyAttachment attachment;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active && (bool)attachmentPrefab)
			{
				attachment = UnityEngine.Object.Instantiate(attachmentPrefab).GetComponent<NetworkedBodyAttachment>();
				attachment.AttachToGameObjectAndSpawn(base.characterBody.gameObject);
			}
		}

		public override void OnExit()
		{
			if ((bool)attachment)
			{
				EntityState.Destroy(attachment.gameObject);
			}
			base.OnExit();
		}
	}
	public class LoweredToRaised : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParameter;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParameter, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new Raised());
			}
		}
	}
	public class Raised : BaseState
	{
	}
	public class RaisedToLowered : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackRateParameter;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackRateParameter, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new Lowered());
			}
		}
	}
}
namespace EntityStates.MajorConstruct.Weapon
{
	public class ChargeLaser : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackParameterName;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireLaser());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class FireLaser : FireBeam
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public float aimMaxSpeed;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackParameterName;

		[SerializeField]
		public LoopSoundDef loopSoundDef;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		private AimAnimator.DirectionOverrideRequest animatorDirectionOverrideRequest;

		private UnityEngine.Vector3 aimDirection;

		private UnityEngine.Vector3 aimVelocity;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration);
			if ((bool)loopSoundDef)
			{
				loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef);
			}
			AimAnimator component = GetComponent<AimAnimator>();
			if ((bool)component)
			{
				animatorDirectionOverrideRequest = component.RequestDirectionOverride(GetAimDirection);
			}
			aimDirection = GetTargetDirection();
		}

		public override void OnExit()
		{
			animatorDirectionOverrideRequest?.Dispose();
			LoopSoundManager.StopSoundLoopLocal(loopPtr);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			aimDirection = UnityEngine.Vector3.RotateTowards(aimDirection, GetTargetDirection(), aimMaxSpeed * (MathF.PI / 180f) * GetDeltaTime(), float.PositiveInfinity);
			base.FixedUpdate();
		}

		public override void ModifyBullet(BulletAttack bulletAttack)
		{
		}

		protected override EntityState GetNextState()
		{
			return new TerminateLaser(GetBeamEndPoint());
		}

		public override bool ShouldFireLaser()
		{
			return duration > base.fixedAge;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}

		private UnityEngine.Vector3 GetAimDirection()
		{
			return aimDirection;
		}

		private UnityEngine.Vector3 GetTargetDirection()
		{
			if ((bool)base.inputBank)
			{
				return base.inputBank.aimDirection;
			}
			return base.transform.forward;
		}

		public override Ray GetLaserRay()
		{
			if ((bool)base.inputBank)
			{
				return new Ray(base.inputBank.aimOrigin, aimDirection);
			}
			return new Ray(base.transform.position, aimDirection);
		}
	}
	public class TerminateLaser : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string animationPlaybackParameterName;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public GameObject explosionEffectPrefab;

		[SerializeField]
		public float blastDamageCoefficient;

		[SerializeField]
		public float blastForceMagnitude;

		[SerializeField]
		public float blastRadius;

		[SerializeField]
		public UnityEngine.Vector3 blastBonusForce;

		[SerializeField]
		public string enterSoundString;

		private UnityEngine.Vector3 blastPosition;

		public TerminateLaser()
		{
		}

		public TerminateLaser(UnityEngine.Vector3 blastPosition)
		{
			this.blastPosition = blastPosition;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName, animationPlaybackParameterName, duration);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			if (base.isAuthority)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.gameObject;
				blastAttack.inflictor = base.gameObject;
				blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				blastAttack.baseDamage = damageStat * blastDamageCoefficient;
				blastAttack.baseForce = blastForceMagnitude;
				blastAttack.position = blastPosition;
				blastAttack.radius = blastRadius;
				blastAttack.bonusForce = blastBonusForce;
				blastAttack.Fire();
				EffectData effectData = new EffectData
				{
					origin = blastPosition,
					scale = blastRadius
				};
				EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Mage
{
	public class FlyUpState : MageCharacterMain
	{
		public static GameObject blinkPrefab;

		public static float duration = 0.3f;

		public static string beginSoundString;

		public static string endSoundString;

		public static AnimationCurve speedCoefficientCurve;

		public static GameObject muzzleflashEffect;

		public static float blastAttackRadius;

		public static float blastAttackDamageCoefficient;

		public static float blastAttackProcCoefficient;

		public static float blastAttackForce;

		private UnityEngine.Vector3 flyVector = UnityEngine.Vector3.zero;

		private Transform modelTransform;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private UnityEngine.Vector3 blastPosition;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			flyVector = UnityEngine.Vector3.up;
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
			PlayCrossfade("Body", "FlyUp", "FlyUp.playbackRate", duration, 0.1f);
			base.characterMotor.Motor.ForceUnground();
			base.characterMotor.velocity = UnityEngine.Vector3.zero;
			EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleLeft", transmit: false);
			EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleRight", transmit: false);
			if (base.isAuthority)
			{
				blastPosition = base.characterBody.corePosition;
			}
			if (NetworkServer.active)
			{
				BlastAttack obj = new BlastAttack
				{
					radius = blastAttackRadius,
					procCoefficient = blastAttackProcCoefficient,
					position = blastPosition,
					attacker = base.gameObject,
					crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master),
					baseDamage = base.characterBody.damage * blastAttackDamageCoefficient,
					falloffModel = BlastAttack.FalloffModel.None,
					baseForce = blastAttackForce
				};
				obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
				obj.damageType = DamageType.Stun1s;
				obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
				obj.Fire();
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(blastPosition);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			blastPosition = reader.ReadVector3();
		}

		public override void HandleMovements()
		{
			base.HandleMovements();
			base.characterMotor.rootMotion += flyVector * (moveSpeedStat * speedCoefficientCurve.Evaluate(base.fixedAge / duration) * GetDeltaTime());
			base.characterMotor.velocity.y = 0f;
		}

		protected override void UpdateAnimationParameters()
		{
			base.UpdateAnimationParameters();
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(flyVector);
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				Util.PlaySound(endSoundString, base.gameObject);
			}
			base.OnExit();
		}
	}
	public class MageCharacterMain : GenericCharacterMain
	{
		private EntityStateMachine jetpackStateMachine;

		public bool jumpButtonState;

		private bool heldPress;

		private bool jumpToggledState;

		private float oldJumpHeldTime;

		private float jumpButtonHeldTime;

		public override void OnEnter()
		{
			base.OnEnter();
			jetpackStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Jet");
		}

		public override void ProcessJump()
		{
			if (hasCharacterMotor && hasInputBank && base.isAuthority)
			{
				if (NetworkUser.readOnlyLocalPlayersList[0]?.localUser?.userProfile.toggleArtificerHover ?? true)
				{
					if (base.inputBank.jump.down)
					{
						oldJumpHeldTime = jumpButtonHeldTime;
						jumpButtonHeldTime += Time.deltaTime;
						heldPress = oldJumpHeldTime < 0.5f && jumpButtonHeldTime >= 0.5f;
					}
					else
					{
						oldJumpHeldTime = 0f;
						jumpButtonHeldTime = 0f;
						heldPress = false;
					}
					if (!base.characterMotor.isGrounded)
					{
						if (base.characterMotor.jumpCount == base.characterBody.maxJumpCount)
						{
							if (base.inputBank.jump.justPressed)
							{
								jumpButtonState = !jumpButtonState;
							}
						}
						else if (heldPress)
						{
							jumpButtonState = !jumpButtonState;
						}
					}
					else
					{
						jumpButtonState = false;
					}
				}
				else
				{
					jumpButtonState = base.inputBank.jump.down;
				}
				bool num = jumpButtonState && base.characterMotor.velocity.y < 0f && !base.characterMotor.isGrounded;
				bool flag = jetpackStateMachine.state.GetType() == typeof(JetpackOn);
				if (num && !flag)
				{
					jetpackStateMachine.SetNextState(new JetpackOn());
				}
				if (!num && flag)
				{
					jetpackStateMachine.SetNextState(new Idle());
				}
			}
			base.ProcessJump();
		}

		public override void OnExit()
		{
			if (base.isAuthority && (bool)jetpackStateMachine)
			{
				jetpackStateMachine.SetNextState(new Idle());
			}
			base.OnExit();
		}
	}
	public class JetpackOn : BaseState
	{
		public static float hoverVelocity;

		public static float hoverAcceleration;

		private Transform jetOnEffect;

		protected static UnityEngine.Vector3 _tempVec3 = UnityEngine.Vector3.one;

		public override void Reset()
		{
			base.Reset();
			jetOnEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			jetOnEffect = FindModelChild("JetOn");
			if ((bool)jetOnEffect)
			{
				jetOnEffect.gameObject.SetActive(value: true);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				float y = base.characterMotor.velocity.y;
				y = Mathf.MoveTowards(y, hoverVelocity, hoverAcceleration * GetDeltaTime());
				base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, y, base.characterMotor.velocity.z);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)jetOnEffect)
			{
				jetOnEffect.gameObject.SetActive(value: false);
			}
		}
	}
}
namespace EntityStates.Mage.Weapon
{
	public class ChargeMeteor : BaseState
	{
		public static float baseChargeDuration;

		public static float baseDuration;

		public static GameObject areaIndicatorPrefab;

		public static float minMeteorRadius = 0f;

		public static float maxMeteorRadius = 10f;

		public static GameObject meteorEffect;

		public static float minDamageCoefficient;

		public static float maxDamageCoefficient;

		public static float procCoefficient;

		public static float force;

		public static GameObject muzzleflashEffect;

		private float stopwatch;

		private GameObject areaIndicatorInstance;

		private bool fireMeteor;

		private float radius;

		private float chargeDuration;

		private float duration;

		private BlastAttack blastAttack;

		private EffectData _effectData;

		private UnityEngine.Vector3 _cachedScale = UnityEngine.Vector3.one;

		private EffectManagerHelper _emh_areaIndicatorInstance;

		public override void Reset()
		{
			base.Reset();
			stopwatch = 0f;
			areaIndicatorInstance = null;
			fireMeteor = false;
			radius = 0f;
			chargeDuration = 0f;
			duration = 0f;
			if (blastAttack != null)
			{
				blastAttack.Reset();
			}
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			_emh_areaIndicatorInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = baseChargeDuration / attackSpeedStat;
			duration = baseDuration / attackSpeedStat;
			UpdateAreaIndicator();
		}

		private void UpdateAreaIndicator()
		{
			if ((bool)areaIndicatorInstance)
			{
				float maxDistance = 1000f;
				if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask))
				{
					areaIndicatorInstance.transform.position = hitInfo.point;
					areaIndicatorInstance.transform.up = hitInfo.normal;
				}
			}
			else if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab))
			{
				areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab);
			}
			else
			{
				_emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
				areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject;
			}
			radius = Util.Remap(Mathf.Clamp01(stopwatch / chargeDuration), 0f, 1f, minMeteorRadius, maxMeteorRadius);
			_cachedScale.x = radius;
			_cachedScale.y = radius;
			_cachedScale.z = radius;
			areaIndicatorInstance.transform.localScale = _cachedScale;
		}

		public override void Update()
		{
			base.Update();
			UpdateAreaIndicator();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if ((stopwatch >= duration || base.inputBank.skill2.justReleased) && base.isAuthority)
			{
				fireMeteor = true;
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "Muzzle", transmit: false);
			if ((bool)areaIndicatorInstance)
			{
				if (fireMeteor)
				{
					float num = Util.Remap(Mathf.Clamp01(stopwatch / chargeDuration), 0f, 1f, minDamageCoefficient, maxDamageCoefficient);
					if (_effectData == null)
					{
						_effectData = new EffectData();
					}
					_effectData.origin = areaIndicatorInstance.transform.position;
					_effectData.scale = radius;
					EffectManager.SpawnEffect(meteorEffect, _effectData, transmit: true);
					if (blastAttack == null)
					{
						blastAttack = new BlastAttack();
					}
					blastAttack.radius = radius;
					blastAttack.procCoefficient = procCoefficient;
					blastAttack.position = areaIndicatorInstance.transform.position;
					blastAttack.attacker = base.gameObject;
					blastAttack.crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master);
					blastAttack.baseDamage = base.characterBody.damage * num;
					blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot;
					blastAttack.baseForce = force;
					blastAttack.teamIndex = TeamComponent.GetObjectTeam(blastAttack.attacker);
					blastAttack.Fire();
				}
				if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null)
				{
					_emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance);
				}
				else
				{
					EntityState.Destroy(areaIndicatorInstance.gameObject);
				}
				areaIndicatorInstance = null;
				_emh_areaIndicatorInstance = null;
			}
			base.OnExit();
		}
	}
	public abstract class BaseChargeBombState : BaseSkillState
	{
		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string chargeSoundString;

		[SerializeField]
		public float baseDuration = 1.5f;

		[SerializeField]
		public float minBloomRadius;

		[SerializeField]
		public float maxBloomRadius;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		[SerializeField]
		public float minChargeDuration = 0.5f;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private uint loopSoundInstanceId;

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int ChargeNovaBombStateHash = Animator.StringToHash("ChargeNovaBomb");

		private static int ChargeNovaBombParamHash = Animator.StringToHash("ChargeNovaBomb.playbackRate");

		protected float duration { get; private set; }

		protected Animator animator { get; private set; }

		protected ChildLocator childLocator { get; private set; }

		protected GameObject chargeEffectInstance { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			animator = GetModelAnimator();
			childLocator = GetModelChildLocator();
			if ((bool)childLocator)
			{
				Transform transform = childLocator.FindChild("MuzzleBetween") ?? base.characterBody.coreTransform;
				if ((bool)transform && (bool)chargeEffectPrefab)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
					ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
					ObjectScaleCurve component2 = chargeEffectInstance.GetComponent<ObjectScaleCurve>();
					if ((bool)component)
					{
						component.newDuration = duration;
					}
					if ((bool)component2)
					{
						component2.timeMax = duration;
					}
				}
			}
			PlayChargeAnimation();
			loopSoundInstanceId = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat);
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			StartAimMode(duration + 2f);
		}

		public override void OnExit()
		{
			crosshairOverrideRequest?.Dispose();
			AkSoundEngine.StopPlayingID(loopSoundInstanceId);
			if (!outer.destroying)
			{
				PlayAnimation("Gesture, Additive", EmptyStateHash);
			}
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		protected float CalcCharge()
		{
			return Mathf.Clamp01(base.fixedAge / duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float charge = CalcCharge();
			if (base.isAuthority && ((!IsKeyDownAuthority() && base.fixedAge >= minChargeDuration) || base.fixedAge >= duration))
			{
				BaseThrowBombState nextState = GetNextState();
				nextState.charge = charge;
				outer.SetNextState(nextState);
			}
		}

		public override void Update()
		{
			base.Update();
			base.characterBody.SetSpreadBloom(Util.Remap(CalcCharge(), 0f, 1f, minBloomRadius, maxBloomRadius));
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		protected abstract BaseThrowBombState GetNextState();

		protected virtual void PlayChargeAnimation()
		{
			PlayAnimation("Gesture, Additive", ChargeNovaBombStateHash, ChargeNovaBombParamHash, duration);
		}
	}
	public abstract class BaseThrowBombState : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float minDamageCoefficient;

		[SerializeField]
		public float maxDamageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public float selfForce;

		protected float duration;

		public float charge;

		private static int FireNovaBombStateHash = Animator.StringToHash("FireNovaBomb");

		private static int FireNovaBombParamHash = Animator.StringToHash("FireNovaBomb.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayThrowAnimation();
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleLeft", transmit: false);
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleRight", transmit: false);
			}
			Fire();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void Fire()
		{
			if (base.isAuthority)
			{
				Ray ray = GetAimRay();
				if (projectilePrefab != null)
				{
					float num = Util.Remap(charge, 0f, 1f, minDamageCoefficient, maxDamageCoefficient);
					float num2 = charge * force;
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.projectilePrefab = projectilePrefab;
					fireProjectileInfo.position = ray.origin;
					fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction);
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.damage = damageStat * num;
					fireProjectileInfo.force = num2;
					fireProjectileInfo.crit = RollCrit();
					FireProjectileInfo projectileInfo = fireProjectileInfo;
					ModifyProjectile(ref projectileInfo);
					TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, ref projectileInfo);
					ProjectileManager.instance.FireProjectile(projectileInfo);
				}
				if ((bool)base.characterMotor)
				{
					base.characterMotor.ApplyForce(ray.direction * ((0f - selfForce) * charge));
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		protected virtual void PlayThrowAnimation()
		{
			PlayAnimation("Gesture, Additive", FireNovaBombStateHash, FireNovaBombParamHash, duration);
		}

		protected virtual void ModifyProjectile(ref FireProjectileInfo projectileInfo)
		{
		}
	}
	public class ChargeNovabomb : BaseChargeBombState
	{
		protected override BaseThrowBombState GetNextState()
		{
			return new ThrowNovabomb();
		}
	}
	public class ThrowNovabomb : BaseThrowBombState
	{
	}
	public class ChargeIcebomb : BaseChargeBombState
	{
		protected override BaseThrowBombState GetNextState()
		{
			return new ThrowIcebomb();
		}
	}
	public class ThrowIcebomb : BaseThrowBombState
	{
	}
	public class FireFireBolt : BaseState, SteppedSkillDef.IStepSetter
	{
		public enum Gauntlet
		{
			Left,
			Right
		}

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force = 20f;

		public static float attackSpeedAltAnimationThreshold;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float attackSoundPitch;

		public static float bloom;

		private float duration;

		private bool hasFiredGauntlet;

		private string muzzleString;

		private Transform muzzleTransform;

		private Animator animator;

		private ChildLocator childLocator;

		private Gauntlet gauntlet;

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int Cast1LeftStateHash = Animator.StringToHash("Cast1Left");

		private static int FireGauntletLeftStateHash = Animator.StringToHash("FireGauntletLeft");

		private static int Cast1RightStateHash = Animator.StringToHash("Cast1Right");

		private static int FireGauntletRightStateHash = Animator.StringToHash("FireGauntletRight");

		private static int HoldGauntletsUpStateHash = Animator.StringToHash("HoldGauntletsUp");

		private static int FireGauntletParamHash = Animator.StringToHash("FireGauntlet.playbackRate");

		public void SetStep(int i)
		{
			gauntlet = (Gauntlet)i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch);
			base.characterBody.SetAimTimer(2f);
			animator = GetModelAnimator();
			if ((bool)animator)
			{
				childLocator = animator.GetComponent<ChildLocator>();
			}
			switch (gauntlet)
			{
			case Gauntlet.Left:
				muzzleString = "MuzzleLeft";
				if (attackSpeedStat < attackSpeedAltAnimationThreshold)
				{
					PlayCrossfade("Gesture, Additive", Cast1LeftStateHash, FireGauntletParamHash, duration, 0.1f);
					PlayAnimation("Gesture Left, Additive", EmptyStateHash);
					PlayAnimation("Gesture Right, Additive", EmptyStateHash);
				}
				else
				{
					PlayAnimation("Gesture Left, Additive", FireGauntletLeftStateHash, FireGauntletParamHash, duration);
					PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration);
					FireGauntlet();
				}
				break;
			case Gauntlet.Right:
				muzzleString = "MuzzleRight";
				if (attackSpeedStat < attackSpeedAltAnimationThreshold)
				{
					PlayCrossfade("Gesture, Additive", Cast1RightStateHash, FireGauntletParamHash, duration, 0.1f);
					PlayAnimation("Gesture Left, Additive", EmptyStateHash);
					PlayAnimation("Gesture Right, Additive", EmptyStateHash);
				}
				else
				{
					PlayAnimation("Gesture Right, Additive", FireGauntletRightStateHash, FireGauntletParamHash, duration);
					PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration);
					FireGauntlet();
				}
				break;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireGauntlet()
		{
			if (!hasFiredGauntlet)
			{
				base.characterBody.AddSpreadBloom(bloom);
				hasFiredGauntlet = true;
				Ray ray = GetAimRay();
				if ((bool)childLocator)
				{
					muzzleTransform = childLocator.FindChild(muzzleString);
				}
				if ((bool)muzzleflashEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
				}
				if (base.isAuthority)
				{
					TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
					ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageCoefficient * damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master));
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (animator.GetFloat("FireGauntlet.fire") > 0f && !hasFiredGauntlet)
			{
				FireGauntlet();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)gauntlet);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			gauntlet = (Gauntlet)reader.ReadByte();
		}
	}
	public class FireIceBolt : FireFireBolt
	{
	}
	public class FireLightningBolt : FireFireBolt
	{
	}
	public class FireIceOrb : BaseState
	{
		public enum Gauntlet
		{
			Left,
			Right
		}

		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static string attackString;

		private float duration;

		private bool hasFiredGauntlet;

		private string muzzleString;

		private Animator animator;

		public Gauntlet gauntlet;

		private static int FireGauntletLeftStateHash = Animator.StringToHash("FireGauntletLeft");

		private static int FireGauntletRightStateHash = Animator.StringToHash("FireGauntletRight");

		private static int HoldGauntletsUpStateHash = Animator.StringToHash("HoldGauntletsUp");

		private static int FireGauntletParamHash = Animator.StringToHash("FireGauntlet.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			switch (gauntlet)
			{
			case Gauntlet.Left:
				muzzleString = "MuzzleLeft";
				PlayAnimation("Gesture Left, Additive", FireGauntletLeftStateHash, FireGauntletParamHash, duration);
				break;
			case Gauntlet.Right:
				muzzleString = "MuzzleRight";
				PlayAnimation("Gesture Right, Additive", FireGauntletRightStateHash, FireGauntletParamHash, duration);
				break;
			}
			PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration);
			Util.PlaySound(attackString, base.gameObject);
			animator = GetModelAnimator();
			base.characterBody.SetAimTimer(2f);
			FireGauntlet();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireGauntlet()
		{
			hasFiredGauntlet = true;
			Ray aimRay = GetAimRay();
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (animator.GetFloat("FireGauntlet.fire") > 0f && !hasFiredGauntlet)
			{
				FireGauntlet();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireLaserbolt : BaseState
	{
		public enum Gauntlet
		{
			Left,
			Right
		}

		public static GameObject muzzleEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static GameObject impactEffectPrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string attackString;

		private float duration;

		private bool hasFiredGauntlet;

		private string muzzleString;

		private Animator animator;

		public Gauntlet gauntlet;

		private static int FireGauntletLeftStateHash = Animator.StringToHash("FireGauntletLeft");

		private static int FireGauntletRightStateHash = Animator.StringToHash("FireGauntletRight");

		private static int HoldGauntletsUpStateHash = Animator.StringToHash("HoldGauntletsUp");

		private static int FireGauntletParamHash = Animator.StringToHash("FireGauntlet.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			switch (gauntlet)
			{
			case Gauntlet.Left:
				muzzleString = "MuzzleLeft";
				PlayAnimation("Gesture Left, Additive", FireGauntletLeftStateHash, FireGauntletParamHash, duration);
				break;
			case Gauntlet.Right:
				muzzleString = "MuzzleRight";
				PlayAnimation("Gesture Right, Additive", FireGauntletRightStateHash, FireGauntletParamHash, duration);
				break;
			}
			PlayAnimation("Gesture, Additive", HoldGauntletsUpStateHash, FireGauntletParamHash, duration);
			Util.PlaySound(attackString, base.gameObject);
			animator = GetModelAnimator();
			base.characterBody.SetAimTimer(2f);
			FireGauntlet();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireGauntlet()
		{
			hasFiredGauntlet = true;
			Ray aimRay = GetAimRay();
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = base.characterBody.spreadBloomAngle;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleString;
				bulletAttack.hitEffectPrefab = impactEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.radius = 0.1f;
				bulletAttack.smartCollision = false;
				bulletAttack.Fire();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (animator.GetFloat("FireGauntlet.fire") > 0f && !hasFiredGauntlet)
			{
				FireGauntlet();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				if (base.inputBank.skill1.down)
				{
					FireLaserbolt fireLaserbolt = new FireLaserbolt();
					fireLaserbolt.gauntlet = ((gauntlet == Gauntlet.Left) ? Gauntlet.Right : Gauntlet.Left);
					outer.SetNextState(fireLaserbolt);
				}
				else
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireRoller : BaseState
	{
		public static GameObject fireProjectilePrefab;

		public static GameObject iceProjectilePrefab;

		public static GameObject lightningProjectilePrefab;

		public static GameObject fireMuzzleflashEffectPrefab;

		public static GameObject iceMuzzleflashEffectPrefab;

		public static GameObject lightningMuzzleflashEffectPrefab;

		public static GameObject fireAreaIndicatorPrefab;

		public static GameObject iceAreaIndicatorPrefab;

		public static GameObject lightningAreaIndicatorPrefab;

		public static string fireAttackSoundString;

		public static string iceAttackSoundString;

		public static string lightningAttackSoundString;

		public static float targetProjectileSpeed;

		public static float baseEntryDuration = 2f;

		public static float baseDuration = 2f;

		public static float baseExitDuration = 2f;

		public static float fireDamageCoefficient;

		public static float iceDamageCoefficient;

		public static float lightningDamageCoefficient;

		private float stopwatch;

		private float fireDuration;

		private float entryDuration;

		private float exitDuration;

		private bool hasFiredRoller;

		private bool hasBegunExit;

		private GameObject areaIndicatorInstance;

		private string muzzleString;

		private Transform muzzleTransform;

		private Animator animator;

		private ChildLocator childLocator;

		private GameObject areaIndicatorPrefab;

		private float damageCoefficient = 1.2f;

		private string attackString;

		private GameObject projectilePrefab;

		private GameObject muzzleflashEffectPrefab;

		private EffectManagerHelper _emh_areaIndicatorInstance;

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int EnterRollerStateHash = Animator.StringToHash("EnterRoller");

		private static int EnterRollerParamHash = Animator.StringToHash("EnterRoller.playbackRate");

		private static int FireRollerStateHash = Animator.StringToHash("FireRoller");

		private static int FireRollerParamHash = Animator.StringToHash("FireRoller.playbackRate");

		private static int ExitRollerStateHash = Animator.StringToHash("ExitRoller");

		private static int ExitRollerParamHash = Animator.StringToHash("ExitRoller.playbackRate");

		public override void Reset()
		{
			base.Reset();
			fireDuration = 0f;
			entryDuration = 0f;
			exitDuration = 0f;
			hasFiredRoller = false;
			hasBegunExit = false;
			areaIndicatorInstance = null;
			muzzleString = string.Empty;
			muzzleTransform = null;
			animator = null;
			childLocator = null;
			areaIndicatorPrefab = null;
			damageCoefficient = 1.2f;
			attackString = string.Empty;
			projectilePrefab = null;
			muzzleflashEffectPrefab = null;
			_emh_areaIndicatorInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			InitElement(MageElement.Ice);
			stopwatch = 0f;
			entryDuration = baseEntryDuration / attackSpeedStat;
			fireDuration = baseDuration / attackSpeedStat;
			exitDuration = baseExitDuration / attackSpeedStat;
			Util.PlaySound(attackString, base.gameObject);
			base.characterBody.SetAimTimer(fireDuration + entryDuration + exitDuration + 2f);
			animator = GetModelAnimator();
			if ((bool)animator)
			{
				childLocator = animator.GetComponent<ChildLocator>();
			}
			muzzleString = "MuzzleRight";
			if ((bool)childLocator)
			{
				muzzleTransform = childLocator.FindChild(muzzleString);
			}
			PlayAnimation("Gesture Left, Additive", EmptyStateHash);
			PlayAnimation("Gesture Right, Additive", EmptyStateHash);
			PlayAnimation("Gesture, Additive", EnterRollerStateHash, EnterRollerParamHash, entryDuration);
			if ((bool)areaIndicatorPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab))
				{
					areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab);
					return;
				}
				_emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
				areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject;
			}
		}

		private void UpdateAreaIndicator()
		{
			if ((bool)areaIndicatorInstance)
			{
				float maxDistance = 1000f;
				if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask))
				{
					areaIndicatorInstance.transform.position = hitInfo.point;
					areaIndicatorInstance.transform.rotation = Util.QuaternionSafeLookRotation(base.transform.position - areaIndicatorInstance.transform.position, hitInfo.normal);
				}
			}
		}

		public override void Update()
		{
			base.Update();
			UpdateAreaIndicator();
		}

		protected void DestroyAreaIndicator()
		{
			if (areaIndicatorInstance != null)
			{
				if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null)
				{
					_emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance);
				}
				else
				{
					EntityState.Destroy(areaIndicatorInstance);
				}
				areaIndicatorInstance = null;
				_emh_areaIndicatorInstance = null;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			DestroyAreaIndicator();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= entryDuration && !hasFiredRoller)
			{
				PlayAnimation("Gesture, Additive", FireRollerStateHash, FireRollerParamHash, fireDuration);
				FireRollerProjectile();
				DestroyAreaIndicator();
			}
			if (stopwatch >= entryDuration + fireDuration && !hasBegunExit)
			{
				hasBegunExit = true;
				PlayAnimation("Gesture, Additive", ExitRollerStateHash, ExitRollerParamHash, exitDuration);
			}
			if (stopwatch >= entryDuration + fireDuration + exitDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireRollerProjectile()
		{
			hasFiredRoller = true;
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if (!base.isAuthority || !(projectilePrefab != null))
			{
				return;
			}
			float maxDistance = 1000f;
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 forward = aimRay.direction;
			UnityEngine.Vector3 vector = aimRay.origin;
			float magnitude = targetProjectileSpeed;
			if ((bool)muzzleTransform)
			{
				vector = muzzleTransform.position;
				if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, LayerIndex.world.mask))
				{
					float num = magnitude;
					UnityEngine.Vector3 vector2 = hitInfo.point - vector;
					UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z);
					float magnitude2 = vector3.magnitude;
					float y = Trajectory.CalculateInitialYSpeed(magnitude2 / num, vector2.y);
					UnityEngine.Vector3 vector4 = new UnityEngine.Vector3(vector3.x / magnitude2 * num, y, vector3.y / magnitude2 * num);
					magnitude = vector4.magnitude;
					forward = vector4 / magnitude;
				}
			}
			ProjectileManager.instance.FireProjectile(projectilePrefab, vector, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude);
		}

		private void InitElement(MageElement defaultElement)
		{
			MageCalibrationController component = GetComponent<MageCalibrationController>();
			if ((bool)component)
			{
				MageElement activeCalibrationElement = component.GetActiveCalibrationElement();
				if (activeCalibrationElement != 0)
				{
					defaultElement = activeCalibrationElement;
				}
			}
			switch (defaultElement)
			{
			case MageElement.Fire:
				damageCoefficient = fireDamageCoefficient;
				attackString = fireAttackSoundString;
				projectilePrefab = fireProjectilePrefab;
				muzzleflashEffectPrefab = fireMuzzleflashEffectPrefab;
				areaIndicatorPrefab = fireAreaIndicatorPrefab;
				break;
			case MageElement.Ice:
				damageCoefficient = iceDamageCoefficient;
				attackString = iceAttackSoundString;
				projectilePrefab = iceProjectilePrefab;
				muzzleflashEffectPrefab = iceMuzzleflashEffectPrefab;
				areaIndicatorPrefab = iceAreaIndicatorPrefab;
				break;
			case MageElement.Lightning:
				damageCoefficient = lightningDamageCoefficient;
				attackString = lightningAttackSoundString;
				projectilePrefab = lightningProjectilePrefab;
				muzzleflashEffectPrefab = lightningMuzzleflashEffectPrefab;
				areaIndicatorPrefab = lightningAreaIndicatorPrefab;
				break;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Flamethrower : BaseState
	{
		[SerializeField]
		public GameObject flamethrowerEffectPrefab;

		public static GameObject impactEffectPrefab;

		public static GameObject tracerEffectPrefab;

		[SerializeField]
		public float maxDistance;

		public static float radius;

		public static float baseEntryDuration = 1f;

		public static float baseFlamethrowerDuration = 2f;

		public static float totalDamageCoefficient = 1.2f;

		public static float procCoefficientPerTick;

		public static float tickFrequency;

		public static float force = 20f;

		public static string startAttackSoundString;

		public static string endAttackSoundString;

		public static float ignitePercentChance;

		public static float recoilForce;

		private float tickDamageCoefficient;

		private float flamethrowerStopwatch;

		private float stopwatch;

		private float entryDuration;

		private float flamethrowerDuration;

		private bool hasBegunFlamethrower;

		private ChildLocator childLocator;

		private Transform leftFlamethrowerTransform;

		private Transform rightFlamethrowerTransform;

		private Transform leftMuzzleTransform;

		private Transform rightMuzzleTransform;

		private bool isCrit;

		private static int PrepFlamethrowerStateHash = Animator.StringToHash("PrepFlamethrower");

		private static int ExitFlamethrowerStateHash = Animator.StringToHash("ExitFlamethrower");

		private static int FlamethrowerParamHash = Animator.StringToHash("Flamethrower.playbackRate");

		private const float flamethrowerEffectBaseDistance = 16f;

		private static int FlamethrowerStateHash = Animator.StringToHash("Flamethrower");

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			entryDuration = baseEntryDuration / attackSpeedStat;
			flamethrowerDuration = baseFlamethrowerDuration;
			Transform modelTransform = GetModelTransform();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(entryDuration + flamethrowerDuration + 1f);
			}
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				leftMuzzleTransform = childLocator.FindChild("MuzzleLeft");
				rightMuzzleTransform = childLocator.FindChild("MuzzleRight");
			}
			int num = Mathf.CeilToInt(flamethrowerDuration * tickFrequency);
			tickDamageCoefficient = totalDamageCoefficient / (float)num;
			if (base.isAuthority && (bool)base.characterBody)
			{
				isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			}
			PlayAnimation("Gesture, Additive", PrepFlamethrowerStateHash, FlamethrowerParamHash, entryDuration);
		}

		public override void OnExit()
		{
			Util.PlaySound(endAttackSoundString, base.gameObject);
			PlayCrossfade("Gesture, Additive", ExitFlamethrowerStateHash, 0.1f);
			if ((bool)leftFlamethrowerTransform)
			{
				EntityState.Destroy(leftFlamethrowerTransform.gameObject);
			}
			if ((bool)rightFlamethrowerTransform)
			{
				EntityState.Destroy(rightFlamethrowerTransform.gameObject);
			}
			base.OnExit();
		}

		private void FireGauntlet(string muzzleString)
		{
			Ray aimRay = GetAimRay();
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = 0f;
				bulletAttack.damage = tickDamageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.muzzleName = muzzleString;
				bulletAttack.hitEffectPrefab = impactEffectPrefab;
				bulletAttack.isCrit = isCrit;
				bulletAttack.radius = radius;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.stopperMask = LayerIndex.world.mask;
				bulletAttack.procCoefficient = procCoefficientPerTick;
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.smartCollision = true;
				bulletAttack.damageType = (Util.CheckRoll(ignitePercentChance, base.characterBody.master) ? DamageType.IgniteOnHit : DamageType.Generic);
				bulletAttack.allowTrajectoryAimAssist = false;
				bulletAttack.Fire();
				if ((bool)base.characterMotor)
				{
					base.characterMotor.ApplyForce(aimRay.direction * (0f - recoilForce));
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= entryDuration && !hasBegunFlamethrower)
			{
				hasBegunFlamethrower = true;
				Util.PlaySound(startAttackSoundString, base.gameObject);
				PlayAnimation("Gesture, Additive", FlamethrowerStateHash, FlamethrowerParamHash, flamethrowerDuration);
				if ((bool)childLocator)
				{
					Transform transform = childLocator.FindChild("MuzzleLeft");
					Transform transform2 = childLocator.FindChild("MuzzleRight");
					if ((bool)transform)
					{
						leftFlamethrowerTransform = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, transform).transform;
					}
					if ((bool)transform2)
					{
						rightFlamethrowerTransform = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, transform2).transform;
					}
					if ((bool)leftFlamethrowerTransform)
					{
						leftFlamethrowerTransform.GetComponent<ScaleParticleSystemDuration>().newDuration = flamethrowerDuration;
					}
					if ((bool)rightFlamethrowerTransform)
					{
						rightFlamethrowerTransform.GetComponent<ScaleParticleSystemDuration>().newDuration = flamethrowerDuration;
					}
				}
				FireGauntlet("MuzzleCenter");
			}
			if (hasBegunFlamethrower)
			{
				flamethrowerStopwatch += Time.deltaTime;
				float num = 1f / tickFrequency / attackSpeedStat;
				if (flamethrowerStopwatch > num)
				{
					flamethrowerStopwatch -= num;
					FireGauntlet("MuzzleCenter");
				}
				UpdateFlamethrowerEffect();
			}
			if (stopwatch >= flamethrowerDuration + entryDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void UpdateFlamethrowerEffect()
		{
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 direction = aimRay.direction;
			UnityEngine.Vector3 direction2 = aimRay.direction;
			if ((bool)leftFlamethrowerTransform)
			{
				leftFlamethrowerTransform.forward = direction;
			}
			if ((bool)rightFlamethrowerTransform)
			{
				rightFlamethrowerTransform.forward = direction2;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class IceNova : BaseState
	{
		public static GameObject impactEffectPrefab;

		public static GameObject novaEffectPrefab;

		public static float baseStartDuration;

		public static float baseEndDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float procCoefficient;

		public static float force = 20f;

		public static float novaRadius;

		public static string attackString;

		private float stopwatch;

		private float startDuration;

		private float endDuration;

		private bool hasCastNova;

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			endDuration = baseEndDuration / attackSpeedStat;
			startDuration = baseStartDuration / attackSpeedStat;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= startDuration && !hasCastNova)
			{
				hasCastNova = true;
				EffectManager.SpawnEffect(novaEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = novaRadius
				}, transmit: true);
				BlastAttack obj = new BlastAttack
				{
					radius = novaRadius,
					procCoefficient = procCoefficient,
					position = base.transform.position,
					attacker = base.gameObject,
					crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master),
					baseDamage = base.characterBody.damage * damageCoefficient,
					falloffModel = BlastAttack.FalloffModel.None,
					damageType = DamageType.Freeze2s,
					baseForce = force
				};
				obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
				obj.Fire();
			}
			if (stopwatch >= startDuration + endDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class PrepWall : BaseState
	{
		public static float baseDuration;

		public static GameObject areaIndicatorPrefab;

		public static GameObject projectilePrefab;

		public static float damageCoefficient;

		public static GameObject muzzleflashEffect;

		public static GameObject goodCrosshairPrefab;

		public static GameObject badCrosshairPrefab;

		public static string prepWallSoundString;

		public static float maxDistance;

		public static string fireSoundString;

		public static float maxSlopeAngle;

		private float duration;

		private float stopwatch;

		private bool goodPlacement;

		private GameObject areaIndicatorInstance;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private EffectManagerHelper _emh_areaIndicatorInstance;

		private static int PrepWallStateHash = Animator.StringToHash("PrepWall");

		private static int PrepWallParamHash = Animator.StringToHash("PrepWall.playbackRate");

		private static int FireWallStateHash = Animator.StringToHash("FireWall");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			stopwatch = 0f;
			goodPlacement = false;
			areaIndicatorInstance = null;
			_emh_areaIndicatorInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			base.characterBody.SetAimTimer(duration + 2f);
			PlayAnimation("Gesture, Additive", PrepWallStateHash, PrepWallParamHash, duration);
			Util.PlaySound(prepWallSoundString, base.gameObject);
			if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab))
			{
				areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab);
			}
			else
			{
				_emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
				areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject;
			}
			UpdateAreaIndicator();
		}

		private void UpdateAreaIndicator()
		{
			bool flag = goodPlacement;
			goodPlacement = false;
			areaIndicatorInstance.SetActive(value: true);
			if ((bool)areaIndicatorInstance)
			{
				float num = maxDistance;
				float extraRaycastDistance = 0f;
				Ray aimRay = GetAimRay();
				if (Physics.Raycast(CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out extraRaycastDistance), out var hitInfo, num + extraRaycastDistance, LayerIndex.world.mask))
				{
					areaIndicatorInstance.transform.position = hitInfo.point;
					areaIndicatorInstance.transform.up = hitInfo.normal;
					areaIndicatorInstance.transform.forward = -aimRay.direction;
					goodPlacement = UnityEngine.Vector3.Angle(UnityEngine.Vector3.up, hitInfo.normal) < maxSlopeAngle;
				}
				if (flag != goodPlacement || crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest?.Dispose();
					GameObject crosshairPrefab = (goodPlacement ? goodCrosshairPrefab : badCrosshairPrefab);
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairPrefab, CrosshairUtils.OverridePriority.Skill);
				}
			}
			areaIndicatorInstance.SetActive(goodPlacement);
		}

		public override void Update()
		{
			base.Update();
			UpdateAreaIndicator();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && !base.inputBank.skill3.down && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				if (goodPlacement)
				{
					PlayAnimation("Gesture, Additive", FireWallStateHash);
					Util.PlaySound(fireSoundString, base.gameObject);
					if ((bool)areaIndicatorInstance && base.isAuthority)
					{
						EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleLeft", transmit: true);
						EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, "MuzzleRight", transmit: true);
						UnityEngine.Vector3 forward = areaIndicatorInstance.transform.forward;
						forward.y = 0f;
						forward.Normalize();
						UnityEngine.Vector3 vector = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward);
						bool crit = Util.CheckRoll(critStat, base.characterBody.master);
						ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position + UnityEngine.Vector3.up, Util.QuaternionSafeLookRotation(vector), base.gameObject, damageStat * damageCoefficient, 0f, crit);
						ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position + UnityEngine.Vector3.up, Util.QuaternionSafeLookRotation(-vector), base.gameObject, damageStat * damageCoefficient, 0f, crit);
					}
				}
				else
				{
					base.skillLocator.utility.AddOneStock();
					PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f);
				}
			}
			if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null)
			{
				_emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance);
			}
			else
			{
				EntityState.Destroy(areaIndicatorInstance.gameObject);
			}
			areaIndicatorInstance = null;
			_emh_areaIndicatorInstance = null;
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
}
namespace EntityStates.LunarWisp
{
	public class ChargeLunarGuns : BaseState
	{
		public static string muzzleNameRoot;

		public static string muzzleNameOne;

		public static string muzzleNameTwo;

		public static float baseDuration;

		public static string windUpSound;

		public static GameObject chargeEffectPrefab;

		private GameObject chargeInstance;

		private GameObject chargeInstanceTwo;

		private float duration;

		public static float spinUpDuration;

		public static float chargeEffectDelay;

		private bool chargeEffectSpawned;

		private bool upToSpeed;

		private uint loopedSoundID;

		protected Transform muzzleTransformRoot;

		protected Transform muzzleTransformOne;

		protected Transform muzzleTransformTwo;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = (baseDuration + spinUpDuration) / attackSpeedStat;
			muzzleTransformRoot = FindModelChild(muzzleNameRoot);
			muzzleTransformOne = FindModelChild(muzzleNameOne);
			muzzleTransformTwo = FindModelChild(muzzleNameTwo);
			loopedSoundID = Util.PlaySound(windUpSound, base.gameObject);
			PlayCrossfade("Gesture", "MinigunSpinUp", 0.2f);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			StartAimMode(0.5f);
			if (base.fixedAge >= chargeEffectDelay && !chargeEffectSpawned)
			{
				chargeEffectSpawned = true;
				if ((bool)muzzleTransformOne && (bool)muzzleTransformTwo && (bool)chargeEffectPrefab)
				{
					chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransformOne.position, muzzleTransformOne.rotation);
					chargeInstance.transform.parent = muzzleTransformOne;
					chargeInstanceTwo = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransformTwo.position, muzzleTransformTwo.rotation);
					chargeInstanceTwo.transform.parent = muzzleTransformTwo;
					ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = duration;
					}
				}
			}
			if (base.fixedAge >= spinUpDuration && !upToSpeed)
			{
				upToSpeed = true;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireLunarGuns fireLunarGuns = new FireLunarGuns();
				fireLunarGuns.muzzleTransformOne = muzzleTransformOne;
				fireLunarGuns.muzzleTransformTwo = muzzleTransformTwo;
				fireLunarGuns.muzzleNameOne = muzzleNameOne;
				fireLunarGuns.muzzleNameTwo = muzzleNameTwo;
				outer.SetNextState(fireLunarGuns);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			AkSoundEngine.StopPlayingID(loopedSoundID);
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
			if ((bool)chargeInstanceTwo)
			{
				EntityState.Destroy(chargeInstanceTwo);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathEffectPrefab;

		public static string deathEffectMuzzleName;

		public static float velocityMagnitude;

		public static float explosionForce;

		private LunarWispFXController FXController;

		protected override bool shouldAutoDestroy => false;

		public override void OnEnter()
		{
			base.OnEnter();
			LunarWispFXController component = base.characterBody.GetComponent<LunarWispFXController>();
			if ((bool)component)
			{
				component.TurnOffFX();
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				RagdollController component2 = modelTransform.GetComponent<RagdollController>();
				Rigidbody component3 = GetComponent<Rigidbody>();
				if ((bool)component2 && (bool)component3)
				{
					component2.BeginRagdoll(component3.velocity * velocityMagnitude);
				}
				ExplodeRigidbodiesOnStart component4 = modelTransform.GetComponent<ExplodeRigidbodiesOnStart>();
				if ((bool)component4)
				{
					component4.force = explosionForce;
					component4.enabled = true;
				}
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.autoUpdateModelTransform = false;
			}
			FindModelChild("StandableSurface").gameObject.SetActive(value: false);
			if (NetworkServer.active)
			{
				EffectData effectData = new EffectData
				{
					origin = FindModelChild(deathEffectMuzzleName).position
				};
				EffectManager.SpawnEffect(deathEffectPrefab, effectData, transmit: true);
				DestroyBodyAsapServer();
			}
		}
	}
	public class FireLunarGuns : BaseState
	{
		public static GameObject muzzleVfxPrefab;

		public static float baseDuration;

		private float duration;

		public static float baseFireInterval;

		public static int baseBulletCount;

		public static float baseDamagePerSecondCoefficient;

		public static float baseForcePerSecond;

		public static float baseProcCoefficientPerSecond;

		public static float bulletMinSpread;

		public static float bulletMaxSpread;

		public static GameObject bulletTracerEffectPrefab;

		public static GameObject bulletHitEffectPrefab;

		public static bool bulletHitEffectNormal;

		public static float bulletMaxDistance;

		public static string fireSound;

		public static string windLoopSound;

		public static string windDownSound;

		public static string shootLoopSound;

		private uint windLoopSoundID;

		private uint shootLoopSoundID;

		private Transform muzzleTransform;

		public Transform muzzleTransformOne;

		public Transform muzzleTransformTwo;

		[SerializeField]
		public string muzzleNameOne;

		[SerializeField]
		public string muzzleNameTwo;

		private GameObject muzzleVFXInstanceOne;

		private GameObject muzzleVFXInstanceTwo;

		private float fireTimer;

		private float baseFireRate;

		private float baseBulletsPerSecond;

		private Run.FixedTimeStamp critEndTime;

		private Run.FixedTimeStamp lastCritCheck;

		protected ref InputBankTest.ButtonState skillButtonState => ref base.inputBank.skill1;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			muzzleTransformOne = FindModelChild(muzzleNameOne);
			muzzleTransformTwo = FindModelChild(muzzleNameTwo);
			if ((bool)muzzleTransformOne && (bool)muzzleTransformTwo && (bool)muzzleVfxPrefab)
			{
				muzzleVFXInstanceOne = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransformOne.position, muzzleTransformOne.rotation);
				muzzleVFXInstanceOne.transform.parent = muzzleTransformOne;
				muzzleVFXInstanceTwo = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransformTwo.position, muzzleTransformTwo.rotation);
				muzzleVFXInstanceTwo.transform.parent = muzzleTransformTwo;
			}
			baseFireRate = 1f / baseFireInterval;
			baseBulletsPerSecond = (float)baseBulletCount * baseFireRate;
			critEndTime = Run.FixedTimeStamp.negativeInfinity;
			lastCritCheck = Run.FixedTimeStamp.negativeInfinity;
			windLoopSoundID = Util.PlaySound(windLoopSound, base.gameObject);
			shootLoopSoundID = Util.PlaySound(shootLoopSound, base.gameObject);
		}

		private void UpdateCrits()
		{
			if (lastCritCheck.timeSince >= 1f)
			{
				lastCritCheck = Run.FixedTimeStamp.now;
				if (RollCrit())
				{
					critEndTime = Run.FixedTimeStamp.now + 2f;
				}
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(windDownSound, base.gameObject);
			if ((bool)muzzleVFXInstanceOne)
			{
				EntityState.Destroy(muzzleVFXInstanceOne.gameObject);
				muzzleVFXInstanceOne = null;
			}
			if ((bool)muzzleVFXInstanceTwo)
			{
				EntityState.Destroy(muzzleVFXInstanceTwo.gameObject);
				muzzleVFXInstanceTwo = null;
			}
			AkSoundEngine.StopPlayingID(windLoopSoundID);
			AkSoundEngine.StopPlayingID(shootLoopSoundID);
			PlayCrossfade("Gesture", "MinigunSpinDown", 0.2f);
			base.OnExit();
		}

		private void OnFireShared()
		{
			Util.PlaySound(fireSound, base.gameObject);
			if (base.isAuthority)
			{
				OnFireAuthority();
			}
		}

		private void OnFireAuthority()
		{
			UpdateCrits();
			bool isCrit = !critEndTime.hasPassed;
			float damage = baseDamagePerSecondCoefficient / baseBulletsPerSecond * damageStat;
			float force = baseForcePerSecond / baseBulletsPerSecond;
			float procCoefficient = baseProcCoefficientPerSecond / baseBulletsPerSecond;
			StartAimMode(0.5f);
			Ray aimRay = GetAimRay();
			BulletAttack bulletAttack = new BulletAttack();
			bulletAttack.bulletCount = (uint)baseBulletCount / 2u;
			bulletAttack.aimVector = aimRay.direction;
			bulletAttack.origin = aimRay.origin;
			bulletAttack.damage = damage;
			bulletAttack.damageColorIndex = DamageColorIndex.Default;
			bulletAttack.damageType = DamageType.Generic;
			bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
			bulletAttack.maxDistance = bulletMaxDistance;
			bulletAttack.force = force;
			bulletAttack.hitMask = LayerIndex.CommonMasks.bullet;
			bulletAttack.minSpread = bulletMinSpread;
			bulletAttack.maxSpread = bulletMaxSpread;
			bulletAttack.isCrit = isCrit;
			bulletAttack.owner = base.gameObject;
			bulletAttack.muzzleName = muzzleNameOne;
			bulletAttack.smartCollision = false;
			bulletAttack.procChainMask = default(ProcChainMask);
			bulletAttack.procCoefficient = procCoefficient;
			bulletAttack.radius = 0f;
			bulletAttack.sniper = false;
			bulletAttack.stopperMask = LayerIndex.CommonMasks.bullet;
			bulletAttack.weapon = null;
			bulletAttack.tracerEffectPrefab = bulletTracerEffectPrefab;
			bulletAttack.spreadPitchScale = 1f;
			bulletAttack.spreadYawScale = 1f;
			bulletAttack.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			bulletAttack.hitEffectPrefab = bulletHitEffectPrefab;
			bulletAttack.HitEffectNormal = bulletHitEffectNormal;
			bulletAttack.Fire();
			BulletAttack bulletAttack2 = new BulletAttack();
			bulletAttack2.bulletCount = (uint)baseBulletCount / 2u;
			bulletAttack2.aimVector = aimRay.direction;
			bulletAttack2.origin = aimRay.origin;
			bulletAttack2.damage = damage;
			bulletAttack2.damageColorIndex = DamageColorIndex.Default;
			bulletAttack2.damageType = DamageType.Generic;
			bulletAttack2.falloffModel = BulletAttack.FalloffModel.None;
			bulletAttack2.maxDistance = bulletMaxDistance;
			bulletAttack2.force = force;
			bulletAttack2.hitMask = LayerIndex.CommonMasks.bullet;
			bulletAttack2.minSpread = bulletMinSpread;
			bulletAttack2.maxSpread = bulletMaxSpread;
			bulletAttack2.isCrit = isCrit;
			bulletAttack2.owner = base.gameObject;
			bulletAttack2.muzzleName = muzzleNameTwo;
			bulletAttack2.smartCollision = false;
			bulletAttack2.procChainMask = default(ProcChainMask);
			bulletAttack2.procCoefficient = procCoefficient;
			bulletAttack2.radius = 0f;
			bulletAttack2.sniper = false;
			bulletAttack2.stopperMask = LayerIndex.CommonMasks.bullet;
			bulletAttack2.weapon = null;
			bulletAttack2.tracerEffectPrefab = bulletTracerEffectPrefab;
			bulletAttack2.spreadPitchScale = 1f;
			bulletAttack2.spreadYawScale = 1f;
			bulletAttack2.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			bulletAttack2.hitEffectPrefab = bulletHitEffectPrefab;
			bulletAttack2.HitEffectNormal = bulletHitEffectNormal;
			bulletAttack2.Fire();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			if (fireTimer <= 0f)
			{
				float num = baseFireInterval / attackSpeedStat;
				fireTimer += num;
				OnFireShared();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SeekingBomb : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargingEffectPrefab;

		public static GameObject projectilePrefab;

		public static string spinUpSoundString;

		public static string fireBombSoundString;

		public static string spinDownSoundString;

		public static float bombDamageCoefficient;

		public static float bombForce;

		public static string muzzleName;

		public float novaRadius;

		private float duration;

		public static float spinUpDuration;

		private bool upToSpeed;

		private GameObject chargeEffectInstance;

		private uint chargeLoopSoundID;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = (baseDuration + spinUpDuration) / attackSpeedStat;
			chargeLoopSoundID = Util.PlaySound(spinUpSoundString, base.gameObject);
			PlayCrossfade("Gesture", "BombStart", 0.2f);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			AkSoundEngine.StopPlayingID(chargeLoopSoundID);
			if ((bool)chargeEffectInstance)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= spinUpDuration && !upToSpeed)
			{
				upToSpeed = true;
				Transform modelTransform = GetModelTransform();
				if ((bool)modelTransform)
				{
					ChildLocator component = modelTransform.GetComponent<ChildLocator>();
					if ((bool)component)
					{
						Transform transform = component.FindChild(muzzleName);
						if ((bool)transform && (bool)chargingEffectPrefab)
						{
							chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation);
							chargeEffectInstance.transform.parent = transform;
							chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
						}
					}
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireBomb();
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		private void FireBomb()
		{
			Util.PlaySound(fireBombSoundString, base.gameObject);
			Ray aimRay = GetAimRay();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					aimRay.origin = component.FindChild(muzzleName).transform.position;
				}
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * bombDamageCoefficient, bombForce, Util.CheckRoll(critStat, base.characterBody.master));
			}
			Util.PlaySound(spinDownSoundString, base.gameObject);
			PlayCrossfade("Gesture", "BombStop", 0.2f);
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration;

		public static string spawnSoundString;

		public static float spawnEffectsDelay;

		private bool spawnEffectsTriggered;

		public static GameObject spawnEffectPrefab;

		public static string spawnEffectMuzzleName;

		public static float printDuration;

		private float mPrintDuration;

		private LunarWispFXController FXController;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		public override void OnEnter()
		{
			base.OnEnter();
			FXController = base.characterBody.GetComponent<LunarWispFXController>();
			FXController.TurnOffFX();
			mPrintDuration = printDuration;
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash);
			PrintController component = GetModelTransform().gameObject.GetComponent<PrintController>();
			component.enabled = false;
			component.printTime = mPrintDuration;
			component.startingPrintHeight = 25f;
			component.maxPrintHeight = 3.15f;
			component.startingPrintBias = 4f;
			component.maxPrintBias = 1.4f;
			component.disableWhenFinished = true;
			component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
			component.enabled = true;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= spawnEffectsDelay && !spawnEffectsTriggered)
			{
				spawnEffectsTriggered = true;
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectMuzzleName, transmit: false);
				if ((bool)FXController)
				{
					FXController.TurnOnFX();
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.LunarTeleporter
{
	public class LunarTeleporterBaseState : BaseState
	{
		protected GenericInteraction genericInteraction;

		protected Interactability preferredInteractability = Interactability.Available;

		protected TeleporterInteraction teleporterInteraction;

		public override void OnEnter()
		{
			base.OnEnter();
			genericInteraction = GetComponent<GenericInteraction>();
			teleporterInteraction = base.transform.root.GetComponent<TeleporterInteraction>();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)TeleporterInteraction.instance)
			{
				if (TeleporterInteraction.instance.isIdle)
				{
					genericInteraction.Networkinteractability = preferredInteractability;
				}
				else
				{
					genericInteraction.Networkinteractability = Interactability.Disabled;
				}
			}
		}
	}
	public class Idle : LunarTeleporterBaseState
	{
		private static int IdleStateHash = Animator.StringToHash("Idle");

		public override void OnEnter()
		{
			base.OnEnter();
			preferredInteractability = Interactability.Available;
			PlayAnimation("Base", IdleStateHash);
			outer.mainStateType = new SerializableEntityStateType(typeof(IdleToActive));
			if (NetworkServer.active)
			{
				teleporterInteraction.sceneExitController.useRunNextStageScene = true;
			}
		}
	}
	public class Active : LunarTeleporterBaseState
	{
		private static int ActiveStateHash = Animator.StringToHash("Active");

		public override void OnEnter()
		{
			base.OnEnter();
			preferredInteractability = Interactability.Available;
			PlayAnimation("Base", ActiveStateHash);
			outer.mainStateType = new SerializableEntityStateType(typeof(ActiveToIdle));
			if (NetworkServer.active)
			{
				teleporterInteraction.sceneExitController.useRunNextStageScene = false;
			}
		}
	}
	public class IdleToActive : LunarTeleporterBaseState
	{
		public static float duration;

		private static int IdleToActiveStateHash = Animator.StringToHash("IdleToActive");

		private static int playbackRateParamHash = Animator.StringToHash("playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", IdleToActiveStateHash, playbackRateParamHash, duration);
			preferredInteractability = Interactability.Disabled;
			Util.PlaySound("Play_boss_spawn_rumble", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new Active());
			}
		}

		public override void OnExit()
		{
			Chat.SendBroadcastChat(new Chat.SimpleChatMessage
			{
				baseToken = "LUNAR_TELEPORTER_ACTIVE"
			});
			base.OnExit();
		}
	}
	public class ActiveToIdle : LunarTeleporterBaseState
	{
		public static float duration;

		private static int ActiveToIdleStateHash = Animator.StringToHash("ActiveToIdle");

		private static int playbackRateParamHash = Animator.StringToHash("playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", ActiveToIdleStateHash, playbackRateParamHash, duration);
			preferredInteractability = Interactability.Disabled;
			Util.PlaySound("Play_boss_spawn_rumble", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new Idle());
			}
		}

		public override void OnExit()
		{
			Chat.SendBroadcastChat(new Chat.SimpleChatMessage
			{
				baseToken = "LUNAR_TELEPORTER_IDLE"
			});
			base.OnExit();
		}
	}
}
namespace EntityStates.LunarGolem
{
	public class ChargeTwinShot : BaseState
	{
		public static float baseDuration = 3f;

		public static float laserMaxWidth = 0.2f;

		public static GameObject effectPrefab;

		public static string chargeSoundString;

		private float duration;

		private uint chargePlayID;

		private List<GameObject> chargeEffects = new List<GameObject>();

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			chargePlayID = Util.PlayAttackSpeedSound(chargeSoundString, base.gameObject, attackSpeedStat);
			PlayCrossfade("Gesture, Additive", "ChargeTwinShot", "TwinShot.playbackRate", duration, 0.1f);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					List<Transform> list = new List<Transform>();
					list.Add(component.FindChild("MuzzleLT"));
					list.Add(component.FindChild("MuzzleLB"));
					list.Add(component.FindChild("MuzzleRT"));
					list.Add(component.FindChild("MuzzleRB"));
					if ((bool)effectPrefab)
					{
						for (int i = 0; i < list.Count; i++)
						{
							if ((bool)list[i])
							{
								GameObject gameObject = UnityEngine.Object.Instantiate(effectPrefab, list[i].position, list[i].rotation);
								gameObject.transform.parent = list[i];
								ScaleParticleSystemDuration component2 = gameObject.GetComponent<ScaleParticleSystemDuration>();
								if ((bool)component2)
								{
									component2.newDuration = duration;
								}
								chargeEffects.Add(gameObject);
							}
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(chargePlayID);
			base.OnExit();
			for (int i = 0; i < chargeEffects.Count; i++)
			{
				if ((bool)chargeEffects[i])
				{
					EntityState.Destroy(chargeEffects[i]);
				}
			}
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireTwinShots nextState = new FireTwinShots();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathExplosionEffect;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)deathExplosionEffect)
			{
				EffectManager.SimpleMuzzleFlash(deathExplosionEffect, base.gameObject, "Center", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}
	}
	public class FireTwinShots : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static GameObject dustEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float blastRadius;

		public static float force;

		public static float baseDuration = 2f;

		public static string attackSoundString;

		public static float aimTime = 2f;

		public static string leftMuzzleTop;

		public static string rightMuzzleTop;

		public static string leftMuzzleBot;

		public static string rightMuzzleBot;

		public static int refireCount = 6;

		public static float baseAimDelay = 0.1f;

		public static float minLeadTime = 2f;

		public static float maxLeadTime = 2f;

		public static float fireSoundPlaybackRate;

		public static bool useSeriesFire = true;

		private int refireIndex;

		private Ray initialAimRay;

		private bool fired;

		private float aimDelay;

		private float duration;

		private static int FireTwinShotStateHash = Animator.StringToHash("FireTwinShot");

		private static int BufferEmptyShotStateHash = Animator.StringToHash("BufferEmpty");

		private static int FireTwinShotParamHash = Animator.StringToHash("FireTwinShot.playbackRate");

		private static int FireRightShotStateHash = Animator.StringToHash("FireRightShot");

		private static int FireLeftShotStateHash = Animator.StringToHash("FireLeftShot");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			aimDelay = baseAimDelay / attackSpeedStat;
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(aimTime);
			}
			if (!useSeriesFire)
			{
				PlayAnimation("Gesture, Additive", FireTwinShotStateHash, FireTwinShotParamHash, duration);
			}
			else
			{
				PlayAnimation("Gesture, Additive", BufferEmptyShotStateHash);
			}
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, fireSoundPlaybackRate);
			initialAimRay = GetAimRay();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!fired && aimDelay <= base.fixedAge)
			{
				fired = true;
				if (base.isAuthority)
				{
					Fire();
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				if (refireIndex < refireCount)
				{
					outer.SetNextState(new FireTwinShots
					{
						refireIndex = refireIndex + 1
					});
				}
				else
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.WritePackedUInt32((uint)refireIndex);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			refireIndex = (int)reader.ReadPackedUInt32();
		}

		private void Fire()
		{
			Ray aimRay = GetAimRay();
			UnityEngine.Quaternion a = UnityEngine.Quaternion.LookRotation(initialAimRay.direction);
			UnityEngine.Quaternion b = UnityEngine.Quaternion.LookRotation(aimRay.direction);
			float num = Util.Remap(Util.Remap(refireIndex, 0f, refireCount - 1, 0f, 1f), 0f, 1f, minLeadTime, maxLeadTime) / aimDelay;
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.SlerpUnclamped(a, b, 1f + num);
			Ray ray = new Ray(aimRay.origin, quaternion * UnityEngine.Vector3.forward);
			if (refireIndex == 0 && (bool)dustEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(dustEffectPrefab, base.gameObject, "Root", transmit: true);
			}
			int num2 = refireIndex;
			if (!useSeriesFire)
			{
				num2 = refireIndex + 3;
			}
			while (refireIndex <= num2)
			{
				string muzzleName = "";
				bool flipProjectile = false;
				switch (refireIndex % 4)
				{
				case 0:
					muzzleName = rightMuzzleTop;
					PlayAnimation("Gesture, Right Additive", FireRightShotStateHash);
					flipProjectile = true;
					break;
				case 1:
					muzzleName = leftMuzzleTop;
					PlayAnimation("Gesture, Left Additive", FireLeftShotStateHash);
					break;
				case 2:
					muzzleName = rightMuzzleBot;
					PlayAnimation("Gesture, Right Additive", FireRightShotStateHash);
					flipProjectile = true;
					break;
				case 3:
					muzzleName = leftMuzzleBot;
					PlayAnimation("Gesture, Left Additive", FireLeftShotStateHash);
					break;
				}
				FireSingle(muzzleName, ray.direction, flipProjectile);
				refireIndex++;
			}
			refireIndex--;
		}

		private void FireSingle(string muzzleName, UnityEngine.Vector3 aimDirection, bool flipProjectile)
		{
			ChildLocator modelChildLocator = GetModelChildLocator();
			if (!modelChildLocator)
			{
				return;
			}
			Transform transform = modelChildLocator.FindChild(muzzleName);
			if ((bool)transform)
			{
				if ((bool)effectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: true);
				}
				if (base.isAuthority)
				{
					ProjectileManager.instance.FireProjectile(projectilePrefab, transform.position, Util.QuaternionSafeLookRotation(aimDirection, (!flipProjectile) ? UnityEngine.Vector3.up : UnityEngine.Vector3.down), base.gameObject, damageStat * damageCoefficient, force, RollCrit());
				}
			}
		}
	}
	public class Shell : BaseState
	{
		public static float baseDuration;

		public static float buffDuration;

		public static float preShieldAnimDuration;

		public static GameObject preShieldEffect;

		public static string preShieldSoundString;

		public static string shieldActivateSoundString;

		private bool readyToActivate;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(preShieldSoundString, base.gameObject);
			PlayCrossfade("Gesture, Additive", "PreShield", 0.2f);
			EffectManager.SimpleMuzzleFlash(preShieldEffect, base.gameObject, "Center", transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= preShieldAnimDuration && !readyToActivate)
			{
				readyToActivate = true;
				Util.PlaySound(shieldActivateSoundString, base.gameObject);
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.LunarShell, buffDuration);
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 1.333f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.LunarExploderMonster
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathPreExplosionVFX;

		public static GameObject deathExplosionEffect;

		public static GameObject projectilePrefab;

		public static float projectileVerticalSpawnOffset;

		public static float projectileDamageCoefficient;

		public static int projectileCount;

		public static float duration;

		public static float deathExplosionRadius;

		public static string muzzleName;

		private GameObject deathPreExplosionInstance;

		private Transform muzzleTransform;

		private bool hasExploded;

		private UnityEngine.Vector3? explosionPosition;

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayCrossfade("Body", "Death", "Death.playbackRate", duration, 0.1f);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
			if (!muzzleTransform)
			{
				return;
			}
			explosionPosition = muzzleTransform.position;
			if ((bool)deathPreExplosionVFX)
			{
				deathPreExplosionInstance = UnityEngine.Object.Instantiate(deathPreExplosionVFX, muzzleTransform.position, muzzleTransform.rotation);
				deathPreExplosionInstance.transform.parent = muzzleTransform;
				deathPreExplosionInstance.transform.localScale = UnityEngine.Vector3.one * deathExplosionRadius;
				ScaleParticleSystemDuration component = deathPreExplosionInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)muzzleTransform)
			{
				explosionPosition = muzzleTransform.position;
			}
			if (base.fixedAge >= duration && !hasExploded)
			{
				if (base.isAuthority)
				{
					FireExplosion();
				}
				base.modelLocator?.modelTransform?.gameObject.SetActive(value: false);
				ProjectileDotZone projectileDotZone = projectilePrefab?.GetComponent<ProjectileDotZone>();
				if ((bool)projectileDotZone)
				{
					base.modelLocator?.StartCoroutine(DoDestroyAfrerProjectileDestroyed(projectileDotZone.lifetime + 0.5f));
				}
				hasExploded = true;
			}
		}

		private IEnumerator DoDestroyAfrerProjectileDestroyed(float delay)
		{
			yield return new WaitForSeconds(delay);
			DestroyModel();
			if (NetworkServer.active)
			{
				DestroyBodyAsapServer();
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}

		private void FireExplosion()
		{
			if (!hasExploded && (bool)base.cachedModelTransform && base.isAuthority)
			{
				for (int i = 0; i < projectileCount; i++)
				{
					float num = 360f / (float)projectileCount;
					UnityEngine.Vector3 forward = Util.QuaternionSafeLookRotation(base.cachedModelTransform.forward, base.cachedModelTransform.up) * Util.ApplySpread(UnityEngine.Vector3.forward, 0f, 0f, 1f, 1f, num * (float)i);
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.projectilePrefab = projectilePrefab;
					fireProjectileInfo.position = base.characterBody.corePosition + UnityEngine.Vector3.up * projectileVerticalSpawnOffset;
					fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(forward);
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.damage = damageStat * projectileDamageCoefficient;
					fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
					ProjectileManager.instance.FireProjectile(fireProjectileInfo);
				}
				if ((bool)deathExplosionEffect)
				{
					EffectManager.SpawnEffect(deathExplosionEffect, new EffectData
					{
						origin = base.characterBody.corePosition,
						scale = deathExplosionRadius
					}, transmit: true);
				}
			}
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
		public static GameObject spawnEffectPrefab;

		public static string spawnEffectChildString;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectChildString, transmit: false);
			}
		}
	}
}
namespace EntityStates.LunarExploderMonster.Weapon
{
	public class FireExploderShards : GenericProjectileBaseState
	{
		private static int FireExploderShardsStateHash = Animator.StringToHash("FireExploderShards");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Gesture, Additive", FireExploderShardsStateHash);
			base.characterBody.SetAimTimer(0f);
		}
	}
}
namespace EntityStates.LockedMage
{
	public class UnlockingMage : BaseState
	{
		public static GameObject unlockingMageChargeEffectPrefab;

		public static GameObject unlockingMageExplosionEffectPrefab;

		public static float unlockingDuration;

		public static string unlockingChargeSFXString;

		public static float unlockingChargeSFXStringPitch;

		public static string unlockingExplosionSFXString;

		public static float unlockingExplosionSFXStringPitch;

		private bool unlocked;

		public static event Action<Interactor> onOpened;

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleEffect(unlockingMageChargeEffectPrefab, base.transform.position, Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up), transmit: false);
			Util.PlayAttackSpeedSound(unlockingChargeSFXString, base.gameObject, unlockingChargeSFXStringPitch);
			GetModelTransform().GetComponent<ChildLocator>().FindChild("Suspension").gameObject.SetActive(value: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!(base.fixedAge >= unlockingDuration) || unlocked)
			{
				return;
			}
			base.gameObject.SetActive(value: false);
			EffectManager.SimpleEffect(unlockingMageExplosionEffectPrefab, base.transform.position, Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up), transmit: false);
			Util.PlayAttackSpeedSound(unlockingExplosionSFXString, base.gameObject, unlockingExplosionSFXStringPitch);
			unlocked = true;
			if (NetworkServer.active)
			{
				PurchaseInteraction component = GetComponent<PurchaseInteraction>();
				if ((bool)component && (bool)component.lastActivator)
				{
					UnlockingMage.onOpened?.Invoke(component.lastActivator);
				}
			}
		}
	}
}
namespace EntityStates.Loader
{
	public class BeginOvercharge : BaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				GetComponent<LoaderStaticChargeComponent>().ConsumeChargeAuthority();
			}
			outer.SetNextStateToMain();
		}
	}
	public class BigPunch : LoaderMeleeAttack
	{
		public static int maxShockCount;

		public static float maxShockFOV;

		public static float maxShockDistance;

		public static float shockDamageCoefficient;

		public static float shockProcCoefficient;

		public static float knockbackForce;

		public static float shorthopVelocityOnEnter;

		private bool hasHit;

		private bool hasKnockbackedSelf;

		private static int BigPunchStateHash = Animator.StringToHash("BigPunch");

		private static int BigPunchParamHash = Animator.StringToHash("BigPunch.playbackRate");

		private UnityEngine.Vector3 punchVector => base.characterDirection.forward.normalized;

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterMotor.velocity.y = shorthopVelocityOnEnter;
		}

		protected override void PlayAnimation()
		{
			base.PlayAnimation();
			PlayAnimation("FullBody, Override", BigPunchStateHash, BigPunchParamHash, duration);
		}

		protected override void AuthorityFixedUpdate()
		{
			base.AuthorityFixedUpdate();
			if (hasHit && !hasKnockbackedSelf && !base.authorityInHitPause)
			{
				hasKnockbackedSelf = true;
				base.healthComponent.TakeDamageForce(punchVector * (0f - knockbackForce), alwaysApply: true);
			}
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			overlapAttack.maximumOverlapTargets = 1;
		}

		protected override void OnMeleeHitAuthority()
		{
			if (!hasHit)
			{
				base.OnMeleeHitAuthority();
				hasHit = true;
				if ((bool)FindModelChild(swingEffectMuzzleString))
				{
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.position = GetAimRay().origin;
					fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(punchVector);
					fireProjectileInfo.crit = RollCrit();
					fireProjectileInfo.damage = 1f * damageStat;
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/LoaderZapCone");
					ProjectileManager.instance.FireProjectile(fireProjectileInfo);
				}
			}
		}

		private void FireSecondaryRaysServer()
		{
			Ray aimRay = GetAimRay();
			TeamIndex team = GetTeam();
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(team);
			bullseyeSearch.maxAngleFilter = maxShockFOV * 0.5f;
			bullseyeSearch.maxDistanceFilter = maxShockDistance;
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = punchVector;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.RefreshCandidates();
			List<HurtBox> list = bullseyeSearch.GetResults().Where(Util.IsValid).ToList();
			Transform transform = FindModelChild(swingEffectMuzzleString);
			if (!transform)
			{
				return;
			}
			for (int i = 0; i < Mathf.Min(list.Count, maxShockCount); i++)
			{
				HurtBox hurtBox = list[i];
				if ((bool)hurtBox)
				{
					LightningOrb lightningOrb = new LightningOrb();
					lightningOrb.bouncedObjects = new List<HealthComponent>();
					lightningOrb.attacker = base.gameObject;
					lightningOrb.teamIndex = team;
					lightningOrb.damageValue = damageStat * shockDamageCoefficient;
					lightningOrb.isCrit = RollCrit();
					lightningOrb.origin = transform.position;
					lightningOrb.bouncesRemaining = 0;
					lightningOrb.lightningType = LightningOrb.LightningType.Loader;
					lightningOrb.procCoefficient = shockProcCoefficient;
					lightningOrb.target = hurtBox;
					OrbManager.instance.AddOrb(lightningOrb);
				}
			}
		}
	}
	public class BaseChargeFist : BaseSkillState
	{
		private class ArcVisualizer : IDisposable
		{
			private readonly UnityEngine.Vector3[] points;

			private readonly float duration;

			private readonly GameObject arcVisualizerInstance;

			private readonly LineRenderer lineRenderer;

			public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount)
			{
				arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab);
				lineRenderer = arcVisualizerInstance.GetComponent<LineRenderer>();
				lineRenderer.positionCount = vertexCount;
				points = new UnityEngine.Vector3[vertexCount];
				this.duration = duration;
			}

			public void Dispose()
			{
				EntityState.Destroy(arcVisualizerInstance);
			}

			public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration)
			{
				arcVisualizerInstance.transform.position = origin;
				if (!lineRenderer.useWorldSpace)
				{
					UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles;
					eulerAngles.x = 0f;
					eulerAngles.z = 0f;
					UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles);
					arcVisualizerInstance.transform.rotation = rotation;
					origin = UnityEngine.Vector3.zero;
					initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity;
				}
				else
				{
					arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up));
				}
				float y = Physics.gravity.y;
				float num = duration / (float)points.Length;
				UnityEngine.Vector3 vector = origin;
				UnityEngine.Vector3 vector2 = initialVelocity;
				float num2 = num;
				float num3 = y * num2;
				float maxDistanceDelta = characterAcceleration * num2;
				for (int i = 0; i < points.Length; i++)
				{
					points[i] = vector;
					UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2);
					current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta);
					vector2.x = current.x;
					vector2.z = current.y;
					vector2.y += num3;
					vector += vector2 * num2;
				}
				lineRenderer.SetPositions(points);
			}
		}

		public static GameObject arcVisualizerPrefab;

		public static float arcVisualizerSimulationLength;

		public static int arcVisualizerVertexCount;

		[SerializeField]
		public float baseChargeDuration = 1f;

		public static float minChargeForChargedAttack;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private Transform chargeVfxInstanceTransform;

		private int gauntlet;

		private uint soundID;

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		private static int ChargePunchIntroStateHash = Animator.StringToHash("ChargePunchIntro");

		private static int ChargePunchIntroParamHash = Animator.StringToHash("ChargePunchIntro.playbackRate");

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = baseChargeDuration / attackSpeedStat;
			Util.PlaySound(enterSFXString, base.gameObject);
			soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnExit()
		{
			if ((bool)chargeVfxInstanceTransform)
			{
				EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
				PlayAnimation("Gesture, Additive", EmptyStateHash);
				PlayAnimation("Gesture, Override", EmptyStateHash);
				crosshairOverrideRequest?.Dispose();
				chargeVfxInstanceTransform = null;
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			Util.PlaySound(endChargeLoopSFXString, base.gameObject);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			AkSoundEngine.SetRTPCValueByPlayingID("loaderShift_chargeAmount", charge * 100f, soundID);
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab)
			{
				if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
				}
				Transform transform = FindModelChild(chargeVfxChildLocatorName);
				if ((bool)transform)
				{
					chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform;
					ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration;
					}
				}
				PlayCrossfade("Gesture, Additive", ChargePunchIntroStateHash, ChargePunchIntroParamHash, chargeDuration, 0.1f);
				PlayCrossfade("Gesture, Override", ChargePunchIntroStateHash, ChargePunchIntroParamHash, chargeDuration, 0.1f);
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		public override void Update()
		{
			base.Update();
			Mathf.Clamp01(base.age / chargeDuration);
		}

		private void AuthorityFixedUpdate()
		{
			if (!ShouldKeepChargingAuthority())
			{
				outer.SetNextState(GetNextStateAuthority());
			}
		}

		protected virtual bool ShouldKeepChargingAuthority()
		{
			return IsKeyDownAuthority();
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			return new SwingChargedFist
			{
				charge = charge
			};
		}
	}
	public class ChargeFist : BaseChargeFist
	{
	}
	public class ChargeZapFist : BaseChargeFist
	{
		protected override bool ShouldKeepChargingAuthority()
		{
			return base.fixedAge < base.chargeDuration;
		}

		protected override EntityState GetNextStateAuthority()
		{
			return new SwingZapFist
			{
				charge = base.charge
			};
		}
	}
	public class FireHook : BaseSkillState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		public static float damageCoefficient;

		public static GameObject muzzleflashEffectPrefab;

		public static string fireSoundString;

		public GameObject hookInstance;

		protected ProjectileStickOnImpact hookStickOnImpact;

		private bool isStuck;

		private bool hadHookInstance;

		private uint soundID;

		private static int FireHookIntroStateHash = Animator.StringToHash("FireHookIntro");

		private static int FireHookLoopStateHash = Animator.StringToHash("FireHookLoop");

		private static int FireHookExitStateHash = Animator.StringToHash("FireHookExit");

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				Ray ray = GetAimRay();
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.position = ray.origin;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(ray.direction);
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.owner = base.gameObject;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
			EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleLeft", transmit: false);
			Util.PlaySound(fireSoundString, base.gameObject);
			PlayAnimation("Grapple", FireHookIntroStateHash);
		}

		public void SetHookReference(GameObject hook)
		{
			hookInstance = hook;
			hookStickOnImpact = hook.GetComponent<ProjectileStickOnImpact>();
			hadHookInstance = true;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)hookStickOnImpact)
			{
				if (hookStickOnImpact.stuck && !isStuck)
				{
					PlayAnimation("Grapple", FireHookLoopStateHash);
				}
				isStuck = hookStickOnImpact.stuck;
			}
			if (base.isAuthority && !hookInstance && hadHookInstance)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			PlayAnimation("Grapple", FireHookExitStateHash);
			EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, "MuzzleLeft", transmit: false);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class FireYankHook : FireHook
	{
	}
	public class PreGroundSlam : BaseCharacterMain
	{
		public static float baseDuration;

		public static string enterSoundString;

		public static float upwardVelocity;

		private float duration;

		private static int PreGroundSlamStateHash = Animator.StringToHash("PreGroundSlam");

		private static int GroundSlamParamHash = Animator.StringToHash("GroundSlam.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Body", PreGroundSlamStateHash, GroundSlamParamHash, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			base.characterMotor.Motor.ForceUnground();
			base.characterMotor.disableAirControlUntilCollision = false;
			base.characterMotor.velocity.y = upwardVelocity;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterMotor.moveDirection = base.inputBank.moveVector;
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new GroundSlam());
			}
		}
	}
	public class GroundSlam : BaseCharacterMain
	{
		public static float airControl;

		public static float minimumDuration;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static string enterSoundString;

		public static float initialVerticalVelocity;

		public static float exitVerticalVelocity;

		public static float verticalAcceleration;

		public static float exitSlowdownCoefficient;

		public static UnityEngine.Vector3 blastBonusForce;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static GameObject fistEffectPrefab;

		private float previousAirControl;

		private GameObject leftFistEffectInstance;

		private GameObject rightFistEffectInstance;

		private bool detonateNextFrame;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", "GroundSlam", 0.2f);
			if (base.isAuthority)
			{
				base.characterMotor.onMovementHit += OnMovementHit;
				base.characterMotor.velocity.y = initialVerticalVelocity;
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			previousAirControl = base.characterMotor.airControl;
			base.characterMotor.airControl = airControl;
			leftFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MechHandR"));
			rightFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MechHandL"));
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (bool)base.characterMotor)
			{
				base.characterMotor.moveDirection = base.inputBank.moveVector;
				base.characterDirection.moveVector = base.characterMotor.moveDirection;
				base.characterMotor.velocity.y += verticalAcceleration * GetDeltaTime();
				if (base.fixedAge >= minimumDuration && (detonateNextFrame || base.characterMotor.Motor.GroundingStatus.IsStableOnGround))
				{
					DetonateAuthority();
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			if (base.isAuthority)
			{
				base.characterMotor.onMovementHit -= OnMovementHit;
				base.characterMotor.Motor.ForceUnground();
				base.characterMotor.velocity *= exitSlowdownCoefficient;
				base.characterMotor.velocity.y = exitVerticalVelocity;
			}
			base.characterMotor.airControl = previousAirControl;
			EntityState.Destroy(leftFistEffectInstance);
			EntityState.Destroy(rightFistEffectInstance);
			base.OnExit();
		}

		private void OnMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo)
		{
			detonateNextFrame = true;
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = footPosition,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				damageType = DamageType.Stun1s,
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = footPosition,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}
	}
	public class LoaderMeleeAttack : BasicMeleeAttack
	{
		public static GameObject overchargeImpactEffectPrefab;

		public static float barrierPercentagePerHit;

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			if (HasBuff(JunkContent.Buffs.LoaderOvercharged))
			{
				overlapAttack.damage *= 2f;
				overlapAttack.hitEffectPrefab = overchargeImpactEffectPrefab;
				overlapAttack.damageType |= (DamageTypeCombo)DamageType.Stun1s;
			}
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			base.healthComponent.AddBarrierAuthority(barrierPercentagePerHit * base.healthComponent.fullBarrier);
		}
	}
	public class BaseSwingChargedFist : LoaderMeleeAttack
	{
		public float charge;

		[SerializeField]
		public float minLungeSpeed;

		[SerializeField]
		public float maxLungeSpeed;

		[SerializeField]
		public float minPunchForce;

		[SerializeField]
		public float maxPunchForce;

		[SerializeField]
		public float minDuration;

		[SerializeField]
		public float maxDuration;

		public static bool disableAirControlUntilCollision;

		public static float speedCoefficientOnExit;

		public static float velocityDamageCoefficient;

		protected UnityEngine.Vector3 punchVelocity;

		private float bonusDamage;

		private static int ChargePunchStateHash = Animator.StringToHash("ChargePunch");

		private static int ChargePunchParamHash = Animator.StringToHash("ChargePunch.playbackRate");

		public float punchSpeed { get; private set; }

		public static event Action<BaseSwingChargedFist> onHitAuthorityGlobal;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				base.characterMotor.Motor.ForceUnground();
				base.characterMotor.disableAirControlUntilCollision |= disableAirControlUntilCollision;
				punchVelocity = CalculateLungeVelocity(base.characterMotor.velocity, GetAimRay().direction, charge, minLungeSpeed, maxLungeSpeed);
				base.characterMotor.velocity = punchVelocity;
				base.characterDirection.forward = base.characterMotor.velocity.normalized;
				punchSpeed = base.characterMotor.velocity.magnitude;
				bonusDamage = punchSpeed * (velocityDamageCoefficient * damageStat);
			}
		}

		protected override float CalcDuration()
		{
			return Mathf.Lerp(minDuration, maxDuration, charge);
		}

		protected override void PlayAnimation()
		{
			base.PlayAnimation();
			PlayAnimation("FullBody, Override", ChargePunchStateHash, ChargePunchParamHash, duration);
		}

		protected override void AuthorityFixedUpdate()
		{
			base.AuthorityFixedUpdate();
			if (!base.authorityInHitPause)
			{
				base.characterMotor.velocity = punchVelocity;
				base.characterDirection.forward = punchVelocity;
				base.characterBody.isSprinting = true;
			}
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			overlapAttack.damage = damageCoefficient * damageStat + bonusDamage;
			overlapAttack.forceVector = base.characterMotor.velocity + GetAimRay().direction * Mathf.Lerp(minPunchForce, maxPunchForce, charge);
			if (base.fixedAge + GetDeltaTime() >= duration)
			{
				HitBoxGroup hitBoxGroup = FindHitBoxGroup("PunchLollypop");
				if ((bool)hitBoxGroup)
				{
					base.hitBoxGroup = hitBoxGroup;
					overlapAttack.hitBoxGroup = hitBoxGroup;
				}
			}
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			BaseSwingChargedFist.onHitAuthorityGlobal?.Invoke(this);
		}

		public override void OnExit()
		{
			base.OnExit();
			base.characterMotor.velocity *= speedCoefficientOnExit;
		}

		public static UnityEngine.Vector3 CalculateLungeVelocity(UnityEngine.Vector3 currentVelocity, UnityEngine.Vector3 aimDirection, float charge, float minLungeSpeed, float maxLungeSpeed)
		{
			currentVelocity = ((UnityEngine.Vector3.Dot(currentVelocity, aimDirection) < 0f) ? UnityEngine.Vector3.zero : UnityEngine.Vector3.Project(currentVelocity, aimDirection));
			return currentVelocity + aimDirection * Mathf.Lerp(minLungeSpeed, maxLungeSpeed, charge);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SwingChargedFist : BaseSwingChargedFist
	{
	}
	public class SwingZapFist : BaseSwingChargedFist
	{
		public static float selfKnockback;

		private bool hasHit;

		protected override void OnMeleeHitAuthority()
		{
			if (!hasHit)
			{
				base.OnMeleeHitAuthority();
				hasHit = true;
				if ((bool)FindModelChild(swingEffectMuzzleString))
				{
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.position = FindModelChild(swingEffectMuzzleString).position;
					fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(punchVelocity);
					fireProjectileInfo.crit = base.isCritAuthority;
					fireProjectileInfo.damage = 1f * damageStat;
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/LoaderZapCone");
					ProjectileManager.instance.FireProjectile(fireProjectileInfo);
				}
			}
		}

		protected override void AuthorityExitHitPause()
		{
			base.AuthorityExitHitPause();
			outer.SetNextStateToMain();
		}

		public override void OnExit()
		{
			base.OnExit();
			if (base.isAuthority && hasHit && (bool)base.healthComponent)
			{
				UnityEngine.Vector3 vector = punchVelocity;
				vector.y = Mathf.Min(vector.y, 0f);
				vector = vector.normalized;
				vector *= 0f - selfKnockback;
				if ((bool)base.characterMotor)
				{
					base.characterMotor.ApplyForce(vector, alwaysApply: true);
				}
			}
		}
	}
	public class SwingComboFist : LoaderMeleeAttack, SteppedSkillDef.IStepSetter
	{
		public int gauntlet;

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			gauntlet = i;
		}

		protected override void PlayAnimation()
		{
			string animationStateName = ((gauntlet == 0) ? "SwingFistRight" : "SwingFistLeft");
			float num = Mathf.Max(duration, 0.2f);
			PlayCrossfade("Gesture, Additive", animationStateName, "SwingFist.playbackRate", num, 0.1f);
			PlayCrossfade("Gesture, Override", animationStateName, "SwingFist.playbackRate", num, 0.1f);
		}

		protected override void BeginMeleeAttackEffect()
		{
			swingEffectMuzzleString = ((gauntlet == 0) ? "SwingRight" : "SwingLeft");
			base.BeginMeleeAttackEffect();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)gauntlet);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			gauntlet = reader.ReadByte();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ThrowPylon : BaseState
	{
		public static GameObject projectilePrefab;

		public static float baseDuration;

		public static float damageCoefficient;

		public static string muzzleString;

		public static GameObject muzzleflashObject;

		public static string soundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.crit = RollCrit();
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.position = aimRay.origin;
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction);
				fireProjectileInfo.target = null;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
			EffectManager.SimpleMuzzleFlash(muzzleflashObject, base.gameObject, muzzleString, transmit: false);
			Util.PlaySound(soundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && duration <= base.age)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
}
namespace EntityStates.LemurianBruiserMonster
{
	public class ChargeMegaFireball : BaseState
	{
		public static float baseDuration = 1f;

		public static GameObject chargeEffectPrefab;

		public static string attackString;

		private float duration;

		private GameObject chargeInstance;

		private EffectManagerHelper _emh_chargeInstance;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeInstance = null;
			_emh_chargeInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Animator modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleMouth");
					if ((bool)transform && (bool)chargeEffectPrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
						{
							chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
							chargeInstance = _emh_chargeInstance.gameObject;
						}
						chargeInstance.transform.parent = transform;
						ScaleParticleSystemDuration component2 = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = duration;
						}
					}
				}
			}
			if ((bool)modelAnimator)
			{
				PlayCrossfade("Gesture, Additive", "ChargeMegaFireball", "ChargeMegaFireball.playbackRate", duration, 0.1f);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeInstance)
			{
				if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null)
				{
					_emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance);
				}
				else
				{
					EntityState.Destroy(chargeInstance);
				}
				chargeInstance = null;
				_emh_chargeInstance = null;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireMegaFireball nextState = new FireMegaFireball();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireMegaFireball : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject muzzleflashEffectPrefab;

		public static int projectileCount = 3;

		public static float totalYawSpread = 5f;

		public static float baseDuration = 2f;

		public static float baseFireDuration = 0.2f;

		public static float damageCoefficient = 1.2f;

		public static float projectileSpeed;

		public static float force = 20f;

		public static string attackString;

		private float duration;

		private float fireDuration;

		private int projectilesFired;

		private static int FireMegaFireballStateHash = Animator.StringToHash("FireMegaFireball");

		private static int FireMegaFireballParamHash = Animator.StringToHash("FireMegaFireball.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			fireDuration = baseFireDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", FireMegaFireballStateHash, FireMegaFireballParamHash, duration);
			Util.PlaySound(attackString, base.gameObject);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			string muzzleName = "MuzzleMouth";
			if (base.isAuthority)
			{
				int num = Mathf.FloorToInt(base.fixedAge / fireDuration * (float)projectileCount);
				if (projectilesFired <= num && projectilesFired < projectileCount)
				{
					if ((bool)muzzleflashEffectPrefab)
					{
						EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleName, transmit: false);
					}
					Ray aimRay = GetAimRay();
					float speedOverride = projectileSpeed;
					float bonusYaw = (float)Mathf.FloorToInt((float)projectilesFired - (float)(projectileCount - 1) / 2f) / (float)(projectileCount - 1) * totalYawSpread;
					UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw);
					ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speedOverride);
					projectilesFired++;
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Flamebreath : BaseState
	{
		public static GameObject flamethrowerEffectPrefab;

		public static GameObject impactEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float maxDistance;

		public static float radius;

		public static float baseEntryDuration = 1f;

		public static float baseExitDuration = 0.5f;

		public static float baseFlamethrowerDuration = 2f;

		public static float totalDamageCoefficient = 1.2f;

		public static float procCoefficientPerTick;

		public static float tickFrequency;

		public static float force = 20f;

		public static string startAttackSoundString;

		public static string endAttackSoundString;

		public static float ignitePercentChance;

		public static float maxSpread;

		private float tickDamageCoefficient;

		private float flamethrowerStopwatch;

		private float stopwatch;

		private float entryDuration;

		private float exitDuration;

		private float flamethrowerDuration;

		private bool hasBegunFlamethrower;

		private ChildLocator childLocator;

		private Transform flamethrowerEffectInstance;

		private Transform muzzleTransform;

		private bool isCrit;

		private BulletAttack bulletAttack;

		private EffectManagerHelper _emh_flamethrowerEffectInstance;

		private static int PrepFlamebreathStateHash = Animator.StringToHash("PrepFlamebreath");

		private static int PrepFlamebreathParamHash = Animator.StringToHash("PrepFlamebreath.playbackRate");

		private const float flamethrowerEffectBaseDistance = 16f;

		private static int FlamebreathStateHash = Animator.StringToHash("Flamebreath");

		private static int FlamebreathParamHash = Animator.StringToHash("Flamebreath.playbackRate");

		public override void Reset()
		{
			base.Reset();
			tickDamageCoefficient = 0f;
			flamethrowerStopwatch = 0f;
			stopwatch = 0f;
			entryDuration = 0f;
			exitDuration = 0f;
			flamethrowerDuration = 0f;
			hasBegunFlamethrower = false;
			childLocator = null;
			flamethrowerEffectInstance = null;
			muzzleTransform = null;
			isCrit = false;
			if (bulletAttack != null)
			{
				bulletAttack.Reset();
			}
			_emh_flamethrowerEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			entryDuration = baseEntryDuration / attackSpeedStat;
			exitDuration = baseExitDuration / attackSpeedStat;
			flamethrowerDuration = baseFlamethrowerDuration;
			Transform modelTransform = GetModelTransform();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(entryDuration + flamethrowerDuration + 1f);
			}
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				modelTransform.GetComponent<AimAnimator>().enabled = true;
			}
			float num = flamethrowerDuration * tickFrequency;
			tickDamageCoefficient = totalDamageCoefficient / num;
			if (base.isAuthority && (bool)base.characterBody)
			{
				isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			}
			PlayAnimation("Gesture, Override", PrepFlamebreathStateHash, PrepFlamebreathParamHash, entryDuration);
		}

		protected void DestroyFlameThrowerEffect()
		{
			if (flamethrowerEffectInstance != null)
			{
				if (_emh_flamethrowerEffectInstance != null && _emh_flamethrowerEffectInstance.OwningPool != null)
				{
					_emh_flamethrowerEffectInstance.OwningPool.ReturnObject(_emh_flamethrowerEffectInstance);
				}
				else
				{
					EntityState.Destroy(flamethrowerEffectInstance.gameObject);
				}
				flamethrowerEffectInstance = null;
				_emh_flamethrowerEffectInstance = null;
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(endAttackSoundString, base.gameObject);
			PlayCrossfade("Gesture, Override", "BufferEmpty", 0.1f);
			DestroyFlameThrowerEffect();
			base.OnExit();
		}

		private void FireFlame(string muzzleString)
		{
			GetAimRay();
			if (base.isAuthority && (bool)muzzleTransform)
			{
				if (bulletAttack == null)
				{
					bulletAttack = new BulletAttack();
				}
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = muzzleTransform.position;
				bulletAttack.aimVector = muzzleTransform.forward;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.damage = tickDamageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.muzzleName = muzzleString;
				bulletAttack.hitEffectPrefab = impactEffectPrefab;
				bulletAttack.isCrit = isCrit;
				bulletAttack.radius = radius;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.stopperMask = LayerIndex.world.mask;
				bulletAttack.procCoefficient = procCoefficientPerTick;
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.smartCollision = true;
				bulletAttack.damageType = (Util.CheckRoll(ignitePercentChance, base.characterBody.master) ? DamageType.IgniteOnHit : DamageType.Generic);
				bulletAttack.Fire();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= entryDuration && stopwatch < entryDuration + flamethrowerDuration && !hasBegunFlamethrower)
			{
				hasBegunFlamethrower = true;
				Util.PlaySound(startAttackSoundString, base.gameObject);
				PlayAnimation("Gesture, Override", FlamebreathStateHash, FlamebreathParamHash, flamethrowerDuration);
				if ((bool)childLocator)
				{
					muzzleTransform = childLocator.FindChild("MuzzleMouth");
					if (!EffectManager.ShouldUsePooledEffect(flamethrowerEffectPrefab))
					{
						flamethrowerEffectInstance = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, muzzleTransform).transform;
					}
					else
					{
						_emh_flamethrowerEffectInstance = EffectManager.GetAndActivatePooledEffect(flamethrowerEffectPrefab, muzzleTransform, inResetLocal: true);
						flamethrowerEffectInstance = _emh_flamethrowerEffectInstance.gameObject.transform;
					}
					flamethrowerEffectInstance.transform.localPosition = UnityEngine.Vector3.zero;
					flamethrowerEffectInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = flamethrowerDuration;
				}
			}
			if (stopwatch >= entryDuration + flamethrowerDuration && hasBegunFlamethrower)
			{
				hasBegunFlamethrower = false;
				PlayCrossfade("Gesture, Override", "ExitFlamebreath", "ExitFlamebreath.playbackRate", exitDuration, 0.1f);
			}
			if (hasBegunFlamethrower)
			{
				flamethrowerStopwatch += Time.deltaTime;
				if (flamethrowerStopwatch > 1f / tickFrequency)
				{
					flamethrowerStopwatch -= 1f / tickFrequency;
					FireFlame("MuzzleCenter");
				}
			}
			else
			{
				DestroyFlameThrowerEffect();
			}
			if (stopwatch >= flamethrowerDuration + entryDuration + exitDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : EntityState
	{
		public static float duration = 2f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			GetModelAnimator();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "SpawnEffectOrigin", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.LemurianMonster
{
	public class Bite : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float radius = 3f;

		public static GameObject hitEffectPrefab;

		public static GameObject biteEffectPrefab;

		public static string attackString;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private bool hasBit;

		private static int BiteStateHash = Animator.StringToHash("Bite");

		private static int BiteParamHash = Animator.StringToHash("Bite.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat);
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Bite");
			}
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", BiteStateHash, BiteParamHash, duration);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Bite.hitBoxActive") > 0.1f)
			{
				if (!hasBit)
				{
					EffectManager.SimpleMuzzleFlash(biteEffectPrefab, base.gameObject, "MuzzleMouth", transmit: true);
					hasBit = true;
				}
				attack.forceVector = base.transform.forward * forceMagnitude;
				attack.Fire();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ChargeFireball : BaseState
	{
		public static float baseDuration = 1f;

		public static GameObject chargeVfxPrefab;

		public static string attackString;

		private float duration;

		private GameObject chargeVfxInstance;

		protected EffectManagerHelper _efhChargeEffect;

		private static int ChargeFireballStateHash = Animator.StringToHash("ChargeFireball");

		private static int ChargeFireballParamHash = Animator.StringToHash("ChargeFireball.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeVfxInstance = null;
			_efhChargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleMouth");
					if ((bool)transform)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargeVfxPrefab))
						{
							chargeVfxInstance = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform.position, transform.rotation);
						}
						else
						{
							_efhChargeEffect = EffectManager.GetAndActivatePooledEffect(chargeVfxPrefab, transform.position, transform.rotation);
							chargeVfxInstance = _efhChargeEffect.gameObject;
						}
						chargeVfxInstance.transform.parent = transform;
					}
				}
			}
			PlayAnimation("Gesture", ChargeFireballStateHash, ChargeFireballParamHash, duration);
		}

		public override void OnExit()
		{
			base.OnExit();
			if (!chargeVfxInstance)
			{
				return;
			}
			if (!EffectManager.UsePools)
			{
				EntityState.Destroy(chargeVfxInstance);
				return;
			}
			if (_efhChargeEffect != null && _efhChargeEffect.OwningPool != null)
			{
				_efhChargeEffect.OwningPool.ReturnObject(_efhChargeEffect);
				return;
			}
			if (_efhChargeEffect != null)
			{
				UnityEngine.Debug.LogFormat("ChargeFireball has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID());
			}
			EntityState.Destroy(chargeVfxInstance);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireFireball nextState = new FireFireball();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireFireball : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string attackString;

		private float duration;

		private static int FireFireballStateHash = Animator.StringToHash("FireFireball");

		private static int FireFireballParamHash = Animator.StringToHash("FireFireball.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture", FireFireballStateHash, FireFireballParamHash, duration);
			Util.PlaySound(attackString, base.gameObject);
			Ray aimRay = GetAimRay();
			string muzzleName = "MuzzleMouth";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class LeapAttackState : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damage = 10f;

		public static float forceMagnitude = 16f;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private RootMotionAccumulator rootMotionAccumulator;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			rootMotionAccumulator = GetModelRootMotionAccumulator();
			modelAnimator = GetModelAnimator();
			duration = baseDuration / attackSpeedStat;
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damage;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "LeapAttack");
			}
			PlayCrossfade("Body", "LeapAttack", "LeapAttack.playbackRate", duration, 0.1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)rootMotionAccumulator)
			{
				UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion();
				if (vector != UnityEngine.Vector3.zero && base.isAuthority && (bool)base.characterMotor)
				{
					base.characterMotor.rootMotion += vector;
				}
			}
			if (base.isAuthority)
			{
				attack.forceVector = (base.characterDirection ? (base.characterDirection.forward * forceMagnitude) : UnityEngine.Vector3.zero);
				if ((bool)modelAnimator && modelAnimator.GetFloat("LeapAttack.hitBoxActive") > 0.5f)
				{
					attack.Fire();
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : EntityState
	{
		public static float duration = 2f;

		public static string spawnSoundString;

		public static string devotionHissSoundString;

		public static string devotionSpawnSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			CharacterBody component = base.gameObject.GetComponent<CharacterBody>();
			if ((component.bodyFlags & CharacterBody.BodyFlags.Devotion) != 0 && component.master.devotionInventoryPrefab != null)
			{
				Util.PlaySound(devotionHissSoundString, base.gameObject);
				Util.PlaySound(devotionSpawnSoundString, base.gameObject);
			}
			else
			{
				Util.PlaySound(spawnSoundString, base.gameObject);
			}
			PlayAnimation("Body", "Spawn1", "Spawn1.playbackRate", duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.LaserTurbine
{
	public class LaserTurbineBaseState : EntityState
	{
		private GenericOwnership genericOwnership;

		private SimpleLeash simpleLeash;

		private MemoizedGetComponent<CharacterBody> bodyGetComponent;

		protected LaserTurbineController laserTurbineController { get; private set; }

		protected SimpleRotateToDirection simpleRotateToDirection { get; private set; }

		protected CharacterBody ownerBody => bodyGetComponent.Get(genericOwnership?.ownerObject);

		protected virtual bool shouldFollow => true;

		public override void OnEnter()
		{
			base.OnEnter();
			genericOwnership = GetComponent<GenericOwnership>();
			simpleLeash = GetComponent<SimpleLeash>();
			simpleRotateToDirection = GetComponent<SimpleRotateToDirection>();
			laserTurbineController = GetComponent<LaserTurbineController>();
		}

		protected InputBankTest GetInputBank()
		{
			return ownerBody?.inputBank;
		}

		protected Ray GetAimRay()
		{
			return new Ray(base.transform.position, base.transform.forward);
		}

		protected Transform GetMuzzleTransform()
		{
			return base.transform;
		}

		public override void Update()
		{
			base.Update();
			if ((bool)ownerBody && shouldFollow)
			{
				simpleLeash.leashOrigin = ownerBody.corePosition;
				simpleRotateToDirection.targetRotation = UnityEngine.Quaternion.LookRotation(ownerBody.inputBank.aimDirection);
			}
		}

		protected float GetDamage()
		{
			float num = 1f;
			if ((bool)ownerBody)
			{
				num = ownerBody.damage;
				if ((bool)ownerBody.inventory)
				{
					num *= (float)ownerBody.inventory.GetItemCount(RoR2Content.Items.LaserTurbine);
				}
			}
			return num;
		}
	}
	public class RechargeState : LaserTurbineBaseState
	{
		public static float baseDuration = 60f;

		public static int killChargesRequired = 4;

		public static int killChargeDuration = 4;

		public Run.FixedTimeStamp startTime { get; private set; }

		public Run.FixedTimeStamp readyTime { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				startTime = Run.FixedTimeStamp.now;
				readyTime = startTime + baseDuration;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.ownerBody.GetBuffCount(RoR2Content.Buffs.LaserTurbineKillCharge) >= killChargesRequired)
			{
				if (NetworkServer.active)
				{
					base.laserTurbineController.ExpendCharge();
				}
				outer.SetNextState(new ReadyState());
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(startTime);
			writer.Write(readyTime);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			startTime = reader.ReadFixedTimeStamp();
			readyTime = reader.ReadFixedTimeStamp();
		}
	}
	public class ReadyState : LaserTurbineBaseState
	{
		public static float baseDuration;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= baseDuration)
			{
				outer.SetNextState(new AimState());
			}
		}
	}
	public class AimState : LaserTurbineBaseState
	{
		public static float targetAcquisitionRadius;

		private bool foundTarget;

		protected override bool shouldFollow => false;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.isAuthority)
			{
				return;
			}
			TeamMask enemyTeams = TeamMask.GetEnemyTeams(base.ownerBody.teamComponent.teamIndex);
			HurtBox[] hurtBoxes = new SphereSearch
			{
				radius = targetAcquisitionRadius,
				mask = LayerIndex.entityPrecise.mask,
				origin = base.transform.position,
				queryTriggerInteraction = QueryTriggerInteraction.UseGlobal
			}.RefreshCandidates().FilterCandidatesByHurtBoxTeam(enemyTeams).OrderCandidatesByDistance()
				.FilterCandidatesByDistinctHurtBoxEntities()
				.GetHurtBoxes();
			float blastRadius = FireMainBeamState.secondBombPrefab.GetComponent<ProjectileImpactExplosion>().blastRadius;
			int num = -1;
			int num2 = 0;
			for (int i = 0; i < hurtBoxes.Length; i++)
			{
				HurtBox[] hurtBoxes2 = new SphereSearch
				{
					radius = blastRadius,
					mask = LayerIndex.entityPrecise.mask,
					origin = hurtBoxes[i].transform.position,
					queryTriggerInteraction = QueryTriggerInteraction.UseGlobal
				}.RefreshCandidates().FilterCandidatesByHurtBoxTeam(enemyTeams).FilterCandidatesByDistinctHurtBoxEntities()
					.GetHurtBoxes();
				if (hurtBoxes2.Length > num2)
				{
					num = i;
					num2 = hurtBoxes2.Length;
				}
			}
			if (num != -1)
			{
				base.simpleRotateToDirection.targetRotation = UnityEngine.Quaternion.LookRotation(hurtBoxes[num].transform.position - base.transform.position);
				foundTarget = true;
			}
		}

		public override void Update()
		{
			base.Update();
			if (base.isAuthority)
			{
				if (foundTarget)
				{
					outer.SetNextState(new ChargeMainBeamState());
				}
				else
				{
					outer.SetNextState(new ReadyState());
				}
			}
		}
	}
	public class ChargeMainBeamState : LaserTurbineBaseState
	{
		public static float baseDuration;

		public static GameObject beamIndicatorPrefab;

		private GameObject beamIndicatorInstance;

		private ChildLocator beamIndicatorChildLocator;

		private Transform beamIndicatorEndTransform;

		protected override bool shouldFollow => false;

		public override void OnEnter()
		{
			base.OnEnter();
			beamIndicatorInstance = UnityEngine.Object.Instantiate(beamIndicatorPrefab, GetMuzzleTransform(), worldPositionStays: false);
			beamIndicatorChildLocator = beamIndicatorInstance.GetComponent<ChildLocator>();
			if ((bool)beamIndicatorChildLocator)
			{
				beamIndicatorEndTransform = beamIndicatorChildLocator.FindChild("End");
			}
		}

		public override void OnExit()
		{
			EntityState.Destroy(beamIndicatorInstance);
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			if (base.isAuthority && base.fixedAge >= baseDuration)
			{
				outer.SetNextState(new FireMainBeamState());
			}
			if ((bool)beamIndicatorInstance && (bool)beamIndicatorEndTransform)
			{
				float num = 1000f;
				Ray aimRay = GetAimRay();
				_ = beamIndicatorInstance.transform.parent.position;
				UnityEngine.Vector3 point = aimRay.GetPoint(num);
				if (Util.CharacterRaycast(base.ownerBody.gameObject, aimRay, out var hitInfo, num, (int)LayerIndex.entityPrecise.mask | (int)LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal))
				{
					point = hitInfo.point;
				}
				beamIndicatorEndTransform.transform.position = point;
			}
		}
	}
	public class FireMainBeamState : LaserTurbineBaseState
	{
		public static float baseDuration;

		public static float mainBeamDamageCoefficient;

		public static float mainBeamProcCoefficient;

		public static float mainBeamForce;

		public static float mainBeamRadius;

		public static float mainBeamMaxDistance;

		public static GameObject forwardBeamTracerEffect;

		public static GameObject backwardBeamTracerEffect;

		public static GameObject mainBeamImpactEffect;

		public static GameObject secondBombPrefab;

		public static float secondBombDamageCoefficient;

		private Ray initialAimRay;

		private UnityEngine.Vector3 beamHitPosition;

		private bool isCrit;

		protected override bool shouldFollow => true;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				initialAimRay = GetAimRay();
			}
			if (NetworkServer.active)
			{
				isCrit = base.ownerBody.RollCrit();
				FireBeamServer(initialAimRay, forwardBeamTracerEffect, mainBeamMaxDistance, isInitialBeam: true);
			}
			base.laserTurbineController.showTurbineDisplay = false;
		}

		public override void Update()
		{
			base.Update();
			if (base.isAuthority && base.fixedAge >= baseDuration)
			{
				outer.SetNextState(new RechargeState());
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active && !outer.destroying)
			{
				UnityEngine.Vector3 direction = initialAimRay.origin - beamHitPosition;
				Ray aimRay = new Ray(beamHitPosition, direction);
				FireBeamServer(aimRay, backwardBeamTracerEffect, direction.magnitude, isInitialBeam: false);
			}
			base.laserTurbineController.showTurbineDisplay = true;
			base.OnExit();
		}

		private void FireBeamServer(Ray aimRay, GameObject tracerEffectPrefab, float maxDistance, bool isInitialBeam)
		{
			bool didHit = false;
			BulletAttack obj = new BulletAttack
			{
				origin = aimRay.origin,
				aimVector = aimRay.direction,
				bulletCount = 1u,
				damage = GetDamage() * mainBeamDamageCoefficient,
				damageColorIndex = DamageColorIndex.Item,
				damageType = DamageType.Generic,
				falloffModel = BulletAttack.FalloffModel.None,
				force = mainBeamForce,
				hitEffectPrefab = mainBeamImpactEffect,
				HitEffectNormal = false,
				hitMask = LayerIndex.entityPrecise.mask,
				isCrit = isCrit,
				maxDistance = maxDistance,
				minSpread = 0f,
				maxSpread = 0f,
				muzzleName = "",
				owner = base.ownerBody.gameObject,
				procChainMask = default(ProcChainMask),
				procCoefficient = mainBeamProcCoefficient,
				queryTriggerInteraction = QueryTriggerInteraction.UseGlobal,
				radius = mainBeamRadius,
				smartCollision = true,
				sniper = false,
				spreadPitchScale = 1f,
				spreadYawScale = 1f,
				stopperMask = LayerIndex.world.mask,
				tracerEffectPrefab = (isInitialBeam ? tracerEffectPrefab : null),
				weapon = base.gameObject
			};
			TeamIndex teamIndex = base.ownerBody.teamComponent.teamIndex;
			obj.hitCallback = delegate(BulletAttack _bulletAttack, ref BulletAttack.BulletHit info)
			{
				bool flag = BulletAttack.defaultHitCallback(_bulletAttack, ref info);
				if (!isInitialBeam)
				{
					return true;
				}
				if (flag)
				{
					HealthComponent healthComponent = (info.hitHurtBox ? info.hitHurtBox.healthComponent : null);
					if ((bool)healthComponent && healthComponent.alive && info.hitHurtBox.teamIndex != teamIndex)
					{
						flag = false;
					}
				}
				if (!flag)
				{
					didHit = true;
					beamHitPosition = info.point;
				}
				return flag;
			};
			obj.filterCallback = delegate(BulletAttack _bulletAttack, ref BulletAttack.BulletHit info)
			{
				return (!info.entityObject || (object)info.entityObject != _bulletAttack.owner) && BulletAttack.defaultFilterCallback(_bulletAttack, ref info);
			};
			obj.Fire();
			if (!didHit)
			{
				if (Physics.Raycast(aimRay, out var hitInfo, mainBeamMaxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					didHit = true;
					beamHitPosition = hitInfo.point;
				}
				else
				{
					beamHitPosition = aimRay.GetPoint(mainBeamMaxDistance);
				}
			}
			if (didHit && isInitialBeam)
			{
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = secondBombPrefab;
				fireProjectileInfo.owner = base.ownerBody.gameObject;
				fireProjectileInfo.position = beamHitPosition - aimRay.direction * 0.5f;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
				fireProjectileInfo.damage = GetDamage() * secondBombDamageCoefficient;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
				fireProjectileInfo.crit = isCrit;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
			if (!isInitialBeam)
			{
				EffectData effectData = new EffectData
				{
					origin = aimRay.origin,
					start = base.transform.position
				};
				effectData.SetNetworkedObjectReference(base.gameObject);
				EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			UnityEngine.Vector3 origin = initialAimRay.origin;
			UnityEngine.Vector3 direction = initialAimRay.direction;
			writer.Write(origin);
			writer.Write(direction);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			UnityEngine.Vector3 origin = reader.ReadVector3();
			UnityEngine.Vector3 direction = reader.ReadVector3();
			initialAimRay = new Ray(origin, direction);
		}
	}
}
namespace EntityStates.VagrantMonster
{
	public class ChargeMegaNova : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargingEffectPrefab;

		public static GameObject areaIndicatorPrefab;

		public static string chargingSoundString;

		public static float novaRadius;

		private float duration;

		private float stopwatch;

		private GameObject chargeEffectInstance;

		private GameObject areaIndicatorInstance;

		private uint soundID;

		private EffectManagerHelper _emh_chargeEffectInstance;

		private EffectManagerHelper _emh_areaIndicatorInstance;

		private UnityEngine.Vector3 _cachedScaleVector = UnityEngine.Vector3.one;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			stopwatch = 0f;
			chargeEffectInstance = null;
			areaIndicatorInstance = null;
			soundID = 0u;
			_emh_chargeEffectInstance = null;
			_emh_areaIndicatorInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayCrossfade("Gesture, Override", "ChargeMegaNova", "ChargeMegaNova.playbackRate", duration, 0.3f);
			soundID = Util.PlayAttackSpeedSound(chargingSoundString, base.gameObject, attackSpeedStat);
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("HullCenter");
			Transform transform2 = component.FindChild("NovaCenter");
			if ((bool)transform && (bool)chargingEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargingEffectPrefab))
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation);
				}
				else
				{
					_emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargingEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance = _emh_chargeEffectInstance.gameObject;
				}
				_cachedScaleVector.x = novaRadius;
				_cachedScaleVector.y = novaRadius;
				_cachedScaleVector.z = novaRadius;
				chargeEffectInstance.transform.localScale = _cachedScaleVector;
				chargeEffectInstance.transform.parent = transform;
				chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
			}
			if ((bool)transform2 && (bool)areaIndicatorPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab))
				{
					areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab, transform2.position, transform2.rotation);
				}
				else
				{
					_emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, transform2.position, transform2.rotation);
					areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject;
				}
				_cachedScaleVector.x = novaRadius * 2f;
				_cachedScaleVector.y = novaRadius * 2f;
				_cachedScaleVector.z = novaRadius * 2f;
				areaIndicatorInstance.transform.localScale = _cachedScaleVector;
				areaIndicatorInstance.transform.parent = transform2;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			AkSoundEngine.StopPlayingID(soundID);
			if ((bool)chargeEffectInstance)
			{
				if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null)
				{
					_emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance);
				}
				else
				{
					EntityState.Destroy(chargeEffectInstance);
				}
				_emh_chargeEffectInstance = null;
				chargeEffectInstance = null;
			}
			if ((bool)areaIndicatorInstance)
			{
				if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null)
				{
					_emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance);
				}
				else
				{
					EntityState.Destroy(areaIndicatorInstance);
				}
				_emh_areaIndicatorInstance = null;
				areaIndicatorInstance = null;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				FireMegaNova fireMegaNova = new FireMegaNova();
				fireMegaNova.novaRadius = novaRadius;
				outer.SetNextState(fireMegaNova);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class ChargeTrackingBomb : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargingEffectPrefab;

		public static string chargingSoundString;

		private float duration;

		private float stopwatch;

		private GameObject chargeEffectInstance;

		private uint soundID;

		private EffectManagerHelper _emh_chargeEffectInstance;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			stopwatch = 0f;
			chargeEffectInstance = null;
			soundID = 0u;
			_emh_chargeEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayCrossfade("Gesture, Override", "ChargeTrackingBomb", "ChargeTrackingBomb.playbackRate", duration, 0.3f);
			soundID = Util.PlayAttackSpeedSound(chargingSoundString, base.gameObject, attackSpeedStat);
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("TrackingBombMuzzle");
			if ((bool)transform && (bool)chargingEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargingEffectPrefab))
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation);
				}
				else
				{
					_emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargingEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance = _emh_chargeEffectInstance.gameObject;
				}
				chargeEffectInstance.transform.parent = transform;
				chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			AkSoundEngine.StopPlayingID(soundID);
			if ((bool)chargeEffectInstance)
			{
				if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null)
				{
					_emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance);
				}
				else
				{
					EntityState.Destroy(chargeEffectInstance);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireTrackingBomb());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class DeathState : BaseState
	{
		public static GameObject initialExplosion;

		public static string deathString;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(deathString, base.gameObject);
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if (base.isAuthority && (bool)initialExplosion)
			{
				EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true);
			}
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class ExplosionAttack : BaseState
	{
		public static float minRadius;

		public static float maxRadius;

		public static int explosionCount;

		public static float baseDuration;

		public static float damageCoefficient;

		public static float force;

		public static float damageScaling;

		public static GameObject novaEffectPrefab;

		private float explosionTimer;

		private float explosionInterval;

		private int explosionIndex;

		public override void OnEnter()
		{
			base.OnEnter();
			explosionInterval = baseDuration / (float)explosionCount;
			explosionIndex = 0;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			explosionTimer -= GetDeltaTime();
			if (!(explosionTimer <= 0f))
			{
				return;
			}
			if (explosionIndex >= explosionCount)
			{
				if (base.isAuthority)
				{
					outer.SetNextStateToMain();
				}
			}
			else
			{
				explosionTimer += explosionInterval;
				Explode();
				explosionIndex++;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void Explode()
		{
			float t = (float)explosionIndex / (float)(explosionCount - 1);
			float num = Mathf.Lerp(minRadius, maxRadius, t);
			EffectManager.SpawnEffect(novaEffectPrefab, new EffectData
			{
				origin = base.transform.position,
				scale = num
			}, transmit: false);
			if (NetworkServer.active)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.gameObject;
				blastAttack.inflictor = base.gameObject;
				blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				blastAttack.baseDamage = damageStat * damageCoefficient * Mathf.Pow(damageScaling, explosionIndex);
				blastAttack.baseForce = force;
				blastAttack.position = base.transform.position;
				blastAttack.radius = num;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.Fire();
			}
		}
	}
	public class FireMegaNova : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject novaEffectPrefab;

		public static GameObject novaImpactEffectPrefab;

		public static string novaSoundString;

		public static float novaDamageCoefficient;

		public static float novaForce;

		public float novaRadius;

		private float duration;

		private float stopwatch;

		private static int FireMegaNovaStateHash = Animator.StringToHash("FireMegaNova");

		private static int FireMegaNovaParamHash = Animator.StringToHash("FireMegaNova.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Override", FireMegaNovaStateHash, FireMegaNovaParamHash, duration);
			Detonate();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void Detonate()
		{
			UnityEngine.Vector3 position = base.transform.position;
			Util.PlaySound(novaSoundString, base.gameObject);
			if ((bool)novaEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(novaEffectPrefab, base.gameObject, "NovaCenter", transmit: false);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance.duration = 3f;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matVagrantEnergized");
				temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
			}
			if (NetworkServer.active)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.gameObject;
				blastAttack.baseDamage = damageStat * novaDamageCoefficient;
				blastAttack.baseForce = novaForce;
				blastAttack.bonusForce = UnityEngine.Vector3.zero;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.crit = base.characterBody.RollCrit();
				blastAttack.damageColorIndex = DamageColorIndex.Default;
				blastAttack.damageType = DamageType.Generic;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.inflictor = base.gameObject;
				blastAttack.position = position;
				blastAttack.procChainMask = default(ProcChainMask);
				blastAttack.procCoefficient = 3f;
				blastAttack.radius = novaRadius;
				blastAttack.losType = BlastAttack.LoSType.NearestHit;
				blastAttack.teamIndex = base.teamComponent.teamIndex;
				blastAttack.impactEffect = EffectCatalog.FindEffectIndexFromPrefab(novaImpactEffectPrefab);
				blastAttack.Fire();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class FireTrackingBomb : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject projectilePrefab;

		public static GameObject muzzleEffectPrefab;

		public static string fireBombSoundString;

		public static float bombDamageCoefficient;

		public static float bombForce;

		public float novaRadius;

		private float duration;

		private float stopwatch;

		private static int FireTrackingBombStateHash = Animator.StringToHash("FireTrackingBomb");

		private static int FireTrackingBombParamHash = Animator.StringToHash("FireTrackingBomb.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Override", FireTrackingBombStateHash, FireTrackingBombParamHash, duration);
			FireBomb();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireBomb()
		{
			Ray aimRay = GetAimRay();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					aimRay.origin = component.FindChild("TrackingBombMuzzle").transform.position;
				}
			}
			EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "TrackingBombMuzzle", transmit: false);
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * bombDamageCoefficient, bombForce, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}
	}
	public class SpawnState : BaseState
	{
		private float stopwatch;

		public static float duration = 4f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "SpawnOrigin", transmit: false);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				modelTransform.GetComponent<PrintController>().enabled = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.VagrantMonster.Weapon
{
	public class JellyBarrage : BaseState
	{
		private float stopwatch;

		private float missileStopwatch;

		public static float baseDuration;

		public static string muzzleString;

		public static float missileSpawnFrequency;

		public static float missileSpawnDelay;

		public static float damageCoefficient;

		public static float maxSpread;

		public static GameObject projectilePrefab;

		public static GameObject muzzleflashPrefab;

		private ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			missileStopwatch -= missileSpawnDelay;
			if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				if ((bool)childLocator)
				{
					_ = (bool)childLocator.FindChild(muzzleString);
				}
			}
		}

		private void FireBlob(Ray projectileRay, float bonusPitch, float bonusYaw)
		{
			projectileRay.direction = Util.ApplySpread(projectileRay.direction, 0f, maxSpread, 1f, 1f, bonusYaw, bonusPitch);
			ProjectileManager.instance.FireProjectile(projectilePrefab, projectileRay.origin, Util.QuaternionSafeLookRotation(projectileRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			stopwatch += deltaTime;
			missileStopwatch += deltaTime;
			if (missileStopwatch >= 1f / missileSpawnFrequency)
			{
				missileStopwatch -= 1f / missileSpawnFrequency;
				Transform transform = childLocator.FindChild(muzzleString);
				if ((bool)transform)
				{
					Ray projectileRay = default(Ray);
					projectileRay.origin = transform.position;
					projectileRay.direction = GetAimRay().direction;
					float maxDistance = 1000f;
					if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask))
					{
						projectileRay.direction = hitInfo.point - transform.position;
					}
					FireBlob(projectileRay, 0f, 0f);
				}
			}
			if (stopwatch >= baseDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class JellyStorm : BaseState
	{
		private float stopwatch;

		private float missileStopwatch;

		public static float stormDuration;

		public static float stormToIdleTransitionDuration;

		public static string stormPointChildString;

		public static float missileSpawnFrequency;

		public static float missileSpawnDelay;

		public static int missileTurretCount;

		public static float missileTurretYawFrequency;

		public static float missileTurretPitchFrequency;

		public static float missileTurretPitchMagnitude;

		public static float missileSpeed;

		public static float damageCoefficient;

		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		private bool beginExitTransition;

		private ChildLocator childLocator;

		private static int StormEnterStateHash = Animator.StringToHash("StormEnter");

		public override void OnEnter()
		{
			base.OnEnter();
			missileStopwatch -= missileSpawnDelay;
			if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			PlayAnimation("Gesture", StormEnterStateHash);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				if ((bool)childLocator)
				{
					_ = (bool)childLocator.FindChild(stormPointChildString);
				}
			}
		}

		private void FireBlob(Ray aimRay, float bonusPitch, float bonusYaw, float speed)
		{
			UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch);
			ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speed);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			stopwatch += deltaTime;
			missileStopwatch += deltaTime;
			if (missileStopwatch >= 1f / missileSpawnFrequency && !beginExitTransition)
			{
				missileStopwatch -= 1f / missileSpawnFrequency;
				Transform transform = childLocator.FindChild(stormPointChildString);
				if ((bool)transform)
				{
					for (int i = 0; i < missileTurretCount; i++)
					{
						float bonusYaw = 360f / (float)missileTurretCount * (float)i + 360f * missileTurretYawFrequency * stopwatch;
						float bonusPitch = Mathf.Sin(MathF.PI * 2f * missileTurretPitchFrequency * stopwatch) * missileTurretPitchMagnitude;
						Ray aimRay = default(Ray);
						aimRay.origin = transform.position;
						aimRay.direction = transform.transform.forward;
						FireBlob(aimRay, bonusPitch, bonusYaw, missileSpeed);
					}
				}
			}
			if (stopwatch >= stormDuration - stormToIdleTransitionDuration && !beginExitTransition)
			{
				beginExitTransition = true;
				PlayCrossfade("Gesture", "StormExit", "StormExit.playbackRate", stormToIdleTransitionDuration, 0.5f);
			}
			if (stopwatch >= stormDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.JellyfishMonster
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject enterEffectPrefab;

		public override void OnEnter()
		{
			base.OnEnter();
			DestroyModel();
			if (NetworkServer.active)
			{
				DestroyBodyAsapServer();
			}
		}

		protected override void CreateDeathEffects()
		{
			base.CreateDeathEffects();
			if ((bool)enterEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(enterEffectPrefab))
				{
					EffectManager.SimpleEffect(enterEffectPrefab, base.transform.position, base.transform.rotation, transmit: false);
				}
				else
				{
					EffectManager.GetAndActivatePooledEffect(enterEffectPrefab, base.transform.position, base.transform.rotation);
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class JellyNova : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargingEffectPrefab;

		public static GameObject novaEffectPrefab;

		public static string chargingSoundString;

		public static string novaSoundString;

		public static float novaDamageCoefficient;

		public static float novaRadius;

		public static float novaForce;

		private bool hasExploded;

		private float duration;

		private float stopwatch;

		private GameObject chargeEffect;

		private PrintController printController;

		private uint soundID;

		private UnityEngine.Vector3 _cachedScale = UnityEngine.Vector3.one;

		private BlastAttack attack;

		private EffectData _effectData;

		private EffectManagerHelper _emh_chargeEffect;

		public override void Reset()
		{
			base.Reset();
			hasExploded = false;
			duration = 0f;
			chargeEffect = null;
			printController = null;
			soundID = 0u;
			if (attack != null)
			{
				attack.Reset();
			}
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			_emh_chargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayCrossfade("Body", "Nova", "Nova.playbackRate", duration, 0.1f);
			soundID = Util.PlaySound(chargingSoundString, base.gameObject);
			if ((bool)chargingEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargingEffectPrefab))
				{
					chargeEffect = UnityEngine.Object.Instantiate(chargingEffectPrefab, base.transform.position, base.transform.rotation);
				}
				else
				{
					_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargingEffectPrefab, base.transform.position, base.transform.rotation);
					chargeEffect = _emh_chargeEffect.gameObject;
				}
				chargeEffect.transform.parent = base.transform;
				_cachedScale.x = novaRadius;
				_cachedScale.y = novaRadius;
				_cachedScale.z = novaRadius;
				chargeEffect.transform.localScale = _cachedScale;
				chargeEffect.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
			}
			if ((bool)modelTransform)
			{
				printController = modelTransform.GetComponent<PrintController>();
				if ((bool)printController)
				{
					printController.enabled = true;
					printController.printTime = duration;
				}
			}
		}

		protected void DestroyChargeEffect()
		{
			if ((bool)chargeEffect)
			{
				if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffect);
				}
				_emh_chargeEffect = null;
				chargeEffect = null;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			AkSoundEngine.StopPlayingID(soundID);
			DestroyChargeEffect();
			if ((bool)printController)
			{
				printController.enabled = false;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority && !hasExploded)
			{
				Detonate();
			}
		}

		private void Detonate()
		{
			hasExploded = true;
			Util.PlaySound(novaSoundString, base.gameObject);
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			DestroyChargeEffect();
			if ((bool)novaEffectPrefab)
			{
				if (_effectData == null)
				{
					_effectData = new EffectData();
				}
				_effectData.origin = base.transform.position;
				_effectData.scale = novaRadius;
				EffectManager.SpawnEffect(novaEffectPrefab, _effectData, transmit: true);
			}
			if (attack == null)
			{
				attack = new BlastAttack();
			}
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
			attack.baseDamage = damageStat * novaDamageCoefficient;
			attack.baseForce = novaForce;
			attack.position = base.transform.position;
			attack.radius = novaRadius;
			attack.procCoefficient = 2f;
			attack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			attack.Fire();
			if ((bool)base.healthComponent)
			{
				base.healthComponent.Suicide();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Jellyfish
{
	public class Dash : BaseState
	{
		public static float duration = 1.8f;

		public static float speedCoefficient = 2f;

		private Animator modelAnimator;

		private static int swimrateParamHash = Animator.StringToHash("swim.rate");

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = base.rigidbodyMotor.rigid.transform.forward * base.characterBody.moveSpeed * speedCoefficient;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.rigidbodyMotor && (bool)modelAnimator)
			{
				modelAnimator.SetFloat(swimrateParamHash, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity));
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new SwimState());
			}
		}
	}
	public class SwimState : BaseState
	{
		private Animator modelAnimator;

		private bool skill1InputReceived;

		private bool skill2InputReceived;

		private bool skill3InputReceived;

		private bool skill4InputReceived;

		private bool jumpInputReceived;

		private static int swimrateParamHash = Animator.StringToHash("swim.rate");

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
		}

		public override void Update()
		{
			base.Update();
			if ((bool)base.inputBank)
			{
				skill1InputReceived = base.inputBank.skill1.down;
				skill2InputReceived |= base.inputBank.skill2.down;
				skill3InputReceived |= base.inputBank.skill3.down;
				skill4InputReceived |= base.inputBank.skill4.down;
				jumpInputReceived |= base.inputBank.jump.down;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			if ((bool)base.inputBank)
			{
				if ((bool)base.rigidbodyMotor)
				{
					base.rigidbodyMotor.moveVector = base.inputBank.moveVector * base.characterBody.moveSpeed;
					if ((bool)modelAnimator)
					{
						modelAnimator.SetFloat(swimrateParamHash, UnityEngine.Vector3.Magnitude(base.rigidbodyMotor.rigid.velocity));
					}
				}
				if ((bool)base.rigidbodyDirection)
				{
					base.rigidbodyDirection.aimDirection = GetAimRay().direction;
				}
			}
			if ((bool)base.skillLocator)
			{
				if ((bool)base.skillLocator.primary && skill1InputReceived)
				{
					base.skillLocator.primary.ExecuteIfReady();
				}
				if ((bool)base.skillLocator.secondary && skill2InputReceived)
				{
					base.skillLocator.secondary.ExecuteIfReady();
				}
				if ((bool)base.skillLocator.utility && skill3InputReceived)
				{
					base.skillLocator.utility.ExecuteIfReady();
				}
				if ((bool)base.skillLocator.special && skill4InputReceived)
				{
					base.skillLocator.special.ExecuteIfReady();
				}
			}
		}
	}
}
namespace EntityStates.Interactables.StoneGate
{
	public class Opening : BaseState
	{
		public static string leftGateChildLocatorEntry;

		public static string rightGateChildLocatorEntry;

		public static AnimationCurve doorPositionCurve;

		public static float duration;

		public static string doorBeginOpenEffectChildLocatorEntry;

		public static string doorBeginOpenSoundString;

		public static string doorFinishedOpenEffectChildLocatorEntry;

		public static string doorFinishedOpenSoundString;

		private ChildLocator childLocator;

		private bool doorIsOpen;

		private Transform leftGateTransform;

		private Transform rightGateTransform;

		public override void OnEnter()
		{
			base.OnEnter();
			childLocator = GetComponent<ChildLocator>();
			childLocator.FindChild(doorBeginOpenEffectChildLocatorEntry).gameObject.SetActive(value: true);
			Util.PlaySound(doorBeginOpenSoundString, base.gameObject);
			if (NetworkServer.active)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "STONEGATE_OPEN"
				});
			}
		}

		public override void Update()
		{
			base.Update();
			UpdateGateTransform(ref leftGateTransform, leftGateChildLocatorEntry);
			UpdateGateTransform(ref rightGateTransform, rightGateChildLocatorEntry);
		}

		private void UpdateGateTransform(ref Transform gateTransform, string childLocatorString)
		{
			if (!gateTransform)
			{
				gateTransform = childLocator.FindChild(childLocatorString);
				return;
			}
			UnityEngine.Vector3 localPosition = gateTransform.localPosition;
			gateTransform.localPosition = new UnityEngine.Vector3(localPosition.x, localPosition.y, doorPositionCurve.Evaluate(base.age / duration));
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && !doorIsOpen)
			{
				doorIsOpen = true;
				Util.PlaySound(doorFinishedOpenSoundString, base.gameObject);
				childLocator.FindChild(doorBeginOpenEffectChildLocatorEntry).gameObject.SetActive(value: false);
				childLocator.FindChild(doorFinishedOpenEffectChildLocatorEntry).gameObject.SetActive(value: true);
			}
		}
	}
}
namespace EntityStates.Interactables.MSObelisk
{
	public class ReadyToEndGame : BaseState
	{
		public static string chargeupChildString;

		public static string chargeupSoundString;

		public static float chargeupDuration;

		private ChildLocator childLocator;

		private PurchaseInteraction purchaseInteraction;

		private bool ready;

		public override void OnEnter()
		{
			base.OnEnter();
			childLocator = GetComponent<ChildLocator>();
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			purchaseInteraction.NetworkcontextToken = "MSOBELISK_CONTEXT_CONFIRMATION";
			purchaseInteraction.Networkavailable = false;
			childLocator.FindChild(chargeupChildString).gameObject.SetActive(value: true);
			Util.PlaySound(chargeupSoundString, base.gameObject);
			ReadOnlyCollection<PlayerCharacterMasterController> instances = PlayerCharacterMasterController.instances;
			for (int i = 0; i < instances.Count; i++)
			{
				instances[i].master.preventGameOver = true;
			}
			for (int j = 0; j < CameraRigController.readOnlyInstancesList.Count; j++)
			{
				CameraRigController.readOnlyInstancesList[j].disableSpectating = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= chargeupDuration && !ready)
			{
				ready = true;
				purchaseInteraction.Networkavailable = true;
				base.gameObject.GetComponent<EntityStateMachine>().mainStateType = new SerializableEntityStateType(typeof(EndingGame));
			}
		}
	}
	public class EndingGame : BaseState
	{
		public static GameObject destroyEffectPrefab;

		public static float timeBetweenDestroy;

		public static float timeUntilEndGame;

		private float destroyTimer;

		private float endGameTimer;

		private bool beginEndingGame;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		private void FixedUpdateServer()
		{
			destroyTimer -= GetDeltaTime();
			if (!beginEndingGame)
			{
				if (!(destroyTimer <= 0f))
				{
					return;
				}
				destroyTimer = timeBetweenDestroy;
				ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Player);
				if (teamMembers.Count > 0)
				{
					GameObject gameObject = teamMembers[0].gameObject;
					CharacterBody component = gameObject.GetComponent<CharacterBody>();
					if ((bool)component)
					{
						EffectManager.SpawnEffect(destroyEffectPrefab, new EffectData
						{
							origin = component.corePosition,
							scale = component.radius
						}, transmit: true);
						EntityState.Destroy(gameObject.gameObject);
					}
				}
				else
				{
					beginEndingGame = true;
				}
			}
			else
			{
				endGameTimer += GetDeltaTime();
				if (endGameTimer >= timeUntilEndGame && (bool)Run.instance)
				{
					DoFinalAction();
				}
			}
		}

		private void DoFinalAction()
		{
			bool flag = false;
			for (int i = 0; i < CharacterMaster.readOnlyInstancesList.Count; i++)
			{
				if (CharacterMaster.readOnlyInstancesList[i].inventory.GetItemCount(RoR2Content.Items.LunarTrinket) > 0)
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				outer.SetNextState(new TransitionToNextStage());
				return;
			}
			Run.instance.BeginGameOver(RoR2Content.GameEndings.ObliterationEnding);
			outer.SetNextState(new Idle());
		}
	}
	public class TransitionToNextStage : BaseState
	{
		public static float duration;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				Stage.instance.BeginAdvanceStage(SceneCatalog.GetSceneDefFromSceneName("limbo"));
				outer.SetNextState(new Idle());
			}
		}
	}
}
namespace EntityStates.Interactables.GoldBeacon
{
	public class GoldBeaconBaseState : BaseState
	{
		protected void SetReady(bool ready)
		{
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				PrintController component = modelTransform.GetComponent<PrintController>();
				component.paused = !ready;
				if (!ready)
				{
					component.age = 0f;
				}
				ChildLocator component2 = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component2)
				{
					component2.FindChild("Purchased").gameObject.SetActive(ready);
				}
			}
			PurchaseInteraction component3 = GetComponent<PurchaseInteraction>();
			if ((bool)component3)
			{
				component3.SetAvailable(!ready);
			}
			HologramProjector component4 = GetComponent<HologramProjector>();
			if ((bool)component4)
			{
				component4.hologramPivot.gameObject.SetActive(!ready);
			}
		}
	}
	public class NotReady : GoldBeaconBaseState
	{
		public static int count { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			SetReady(ready: false);
			SetPingable(value: true);
			count++;
		}

		public override void OnExit()
		{
			count--;
			base.OnExit();
		}
	}
	public class Ready : GoldBeaconBaseState
	{
		public static GameObject activationEffectPrefab;

		public static int count { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			SetReady(ready: true);
			SetPingable(value: false);
			count++;
		}

		public override void OnExit()
		{
			count--;
			if (!outer.destroying)
			{
				EffectManager.SpawnEffect(activationEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = 10f
				}, transmit: false);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.InfiniteTowerSafeWard
{
	public class Active : BaseSafeWardState
	{
		[SerializeField]
		public float radius;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		private InfiniteTowerRun run;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)safeWardController)
			{
				safeWardController.SetIndicatorEnabled(enabled: false);
			}
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)purchaseInteraction)
			{
				purchaseInteraction.SetAvailable(newAvailable: false);
			}
			if ((bool)zone)
			{
				zone.Networkradius = radius;
			}
			run = Run.instance as InfiniteTowerRun;
		}

		public void SelfDestruct()
		{
			if (NetworkServer.active)
			{
				outer.SetNextState(new SelfDestruct());
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)zone && (bool)run)
			{
				float num = 1f;
				if ((bool)run.waveController)
				{
					num = run.waveController.zoneRadiusPercentage;
				}
				zone.Networkradius = radius * num;
			}
		}
	}
	public class AwaitingActivation : BaseSafeWardState
	{
		[SerializeField]
		public float radius;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)purchaseInteraction)
			{
				purchaseInteraction.SetAvailable(newAvailable: true);
			}
			if ((bool)zone)
			{
				zone.Networkradius = radius;
			}
		}

		public void Activate()
		{
			if (NetworkServer.active)
			{
				outer.SetNextState(new Active());
			}
		}
	}
	public class AwaitingPortalUse : BaseSafeWardState
	{
		[SerializeField]
		public float radius;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)purchaseInteraction)
			{
				purchaseInteraction.SetAvailable(newAvailable: false);
			}
			if ((bool)zone)
			{
				zone.Networkradius = radius;
			}
		}
	}
	public class BaseSafeWardState : EntityState
	{
		protected PurchaseInteraction purchaseInteraction;

		protected VerticalTubeZone zone;

		protected Animator animator;

		[SerializeField]
		public string objectiveToken;

		private GenericObjectiveProvider genericObjectiveProvider;

		protected InfiniteTowerSafeWardController safeWardController;

		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			zone = GetComponent<VerticalTubeZone>();
			animator = base.gameObject.GetComponentInChildren<Animator>();
			safeWardController = base.gameObject.GetComponent<InfiniteTowerSafeWardController>();
			if (!string.IsNullOrEmpty(objectiveToken))
			{
				genericObjectiveProvider = base.gameObject.AddComponent<GenericObjectiveProvider>();
				genericObjectiveProvider.objectiveToken = objectiveToken;
			}
		}

		public override void PlayAnimation(string layerName, string animationStateName)
		{
			if ((bool)animator && !string.IsNullOrEmpty(layerName))
			{
				EntityState.PlayAnimationOnAnimator(animator, layerName, animationStateName);
			}
		}

		public override void OnExit()
		{
			if ((bool)genericObjectiveProvider)
			{
				EntityState.Destroy(genericObjectiveProvider);
			}
			base.OnExit();
		}
	}
	public class Burrow : BaseSafeWardState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public float radius;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)zone)
			{
				zone.Networkradius = radius;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				outer.SetNextState(new AwaitingActivation());
			}
		}
	}
	public class CorrallingPlayers : BaseSafeWardState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public float initialRadius;

		[SerializeField]
		public float finalRadius;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)purchaseInteraction)
			{
				purchaseInteraction.SetAvailable(newAvailable: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)zone)
			{
				float t = Mathf.Min(1f, base.fixedAge / duration);
				zone.Networkradius = Mathf.Lerp(initialRadius, finalRadius, t);
			}
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				outer.SetNextState(new AwaitingActivation());
			}
		}
	}
	public class SelfDestruct : BaseSafeWardState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
	public class Travelling : BaseSafeWardState
	{
		[SerializeField]
		public float radius;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public float minDistanceToNewLocation;

		[SerializeField]
		public float maxDistanceToNewLocation;

		[SerializeField]
		public float travelSpeed;

		[SerializeField]
		public float travelHeight;

		[SerializeField]
		public float pathMaxSlope;

		[SerializeField]
		public float pathMaxJumpHeight;

		[SerializeField]
		public float pathMaxSpeed;

		[SerializeField]
		public int pathNodeInclusionPeriod;

		[SerializeField]
		public string voSoundString;

		[SerializeField]
		public float minimumVoDelay;

		[SerializeField]
		public float maximumVoDelay;

		[SerializeField]
		public LoopSoundDef loopSoundDef;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		private const HullMask wardHullMask = HullMask.Human;

		private const HullClassification pathHullClassification = HullClassification.Human;

		private bool didFail;

		private NodeGraph groundNodeGraph;

		private List<NodeGraph.NodeIndex> potentialEndNodes;

		private List<UnityEngine.Vector3> catmullRomPoints = new List<UnityEngine.Vector3>();

		private UnityEngine.Vector3 rotationVelocity;

		private RoR2.Path groundPath;

		private int catmullRomIndex;

		private CatmullRom3 currentCurve;

		private float tCurve;

		private float voTimer;

		private Xoroshiro128Plus rng;

		public Travelling()
		{
		}

		public Travelling(Xoroshiro128Plus rng)
		{
			this.rng = rng;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			didFail = false;
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			ResetVoTimer();
			if ((bool)loopSoundDef)
			{
				loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopSoundDef);
			}
			if ((bool)zone)
			{
				zone.Networkradius = radius;
			}
			if (NetworkServer.active)
			{
				groundNodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
				potentialEndNodes = groundNodeGraph.FindNodesInRangeWithFlagConditions(base.transform.position, 0f, minDistanceToNewLocation, HullMask.Human, NodeFlags.TeleporterOK, NodeFlags.None, preventOverhead: false);
				Util.ShuffleList(potentialEndNodes, rng);
				List<NodeGraph.NodeIndex> list = groundNodeGraph.FindNodesInRangeWithFlagConditions(base.transform.position, minDistanceToNewLocation, maxDistanceToNewLocation, HullMask.Human, NodeFlags.TeleporterOK, NodeFlags.None, preventOverhead: false);
				Util.ShuffleList(list, rng);
				potentialEndNodes.AddRange(list);
				groundPath = new RoR2.Path(groundNodeGraph);
			}
		}

		public override void OnExit()
		{
			LoopSoundManager.StopSoundLoopLocal(loopPtr);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			voTimer -= GetDeltaTime();
			if (voTimer <= 0f)
			{
				ResetVoTimer();
				Util.PlaySound(voSoundString, base.gameObject);
			}
			if (!NetworkServer.active)
			{
				return;
			}
			if (!didFail)
			{
				if (currentCurve == null)
				{
					if (potentialEndNodes.Count > 0)
					{
						EvaluateNextEndpoint();
					}
					else
					{
						didFail = true;
						UnityEngine.Debug.LogError("SafeWard failed to find endpoint!");
					}
				}
				else
				{
					tCurve = currentCurve.AdvanceTByDistance(tCurve, travelSpeed * GetDeltaTime());
					tCurve = Mathf.Min(1f, tCurve);
					base.transform.position = currentCurve.Evaluate(tCurve);
					UnityEngine.Vector3 vector = currentCurve.EvaluateDerivative(tCurve);
					vector.y = 0f;
					vector = vector.normalized;
					UnityEngine.Vector3 forward = UnityEngine.Vector3.SmoothDamp(base.transform.forward, vector, ref rotationVelocity, 0.5f);
					base.transform.forward = forward;
					while (tCurve >= 1f && GetRemainingCurveSegmentCount() > 0)
					{
						tCurve -= 1f;
						catmullRomIndex++;
						UpdateCurveSegmentPoints();
					}
				}
			}
			if (didFail || (GetRemainingCurveSegmentCount() <= 0 && tCurve >= 1f))
			{
				outer.SetNextState(new Burrow());
			}
		}

		private void EvaluateNextEndpoint()
		{
			int index = potentialEndNodes.Count - 1;
			NodeGraph.NodeIndex nodeIndex = potentialEndNodes[index];
			potentialEndNodes.RemoveAt(index);
			NodeGraph.PathRequest pathRequest = new NodeGraph.PathRequest
			{
				startPos = base.transform.position,
				endPos = nodeIndex,
				hullClassification = HullClassification.Human,
				maxJumpHeight = pathMaxJumpHeight,
				maxSlope = pathMaxSlope,
				maxSpeed = pathMaxSpeed,
				path = groundPath
			};
			PathTask pathTask = groundNodeGraph.ComputePath(pathRequest);
			if (pathTask == null || pathTask.status != PathTask.TaskStatus.Complete || !pathTask.wasReachable || pathTask.path.waypointsCount <= 1 || !groundNodeGraph.GetNodePosition(nodeIndex, out var _))
			{
				return;
			}
			_ = 1f / (float)(pathTask.path.waypointsCount - 1);
			for (int i = 0; i < pathTask.path.waypointsCount; i++)
			{
				if (i % pathNodeInclusionPeriod != 0 && i != pathTask.path.waypointsCount - 1)
				{
					continue;
				}
				RoR2.Path.Waypoint waypoint = pathTask.path[i];
				if (groundNodeGraph.GetNodePosition(waypoint.nodeIndex, out var position2))
				{
					if (i > 0 && i < pathTask.path.waypointsCount - 1)
					{
						position2.y += travelHeight;
					}
					catmullRomPoints.Add(position2);
				}
			}
			if (catmullRomPoints.Count > 1)
			{
				UnityEngine.Vector3 item = 2f * catmullRomPoints[0] - catmullRomPoints[1];
				catmullRomPoints.Insert(0, item);
				UnityEngine.Vector3 item2 = 2f * catmullRomPoints[catmullRomPoints.Count - 1] - catmullRomPoints[catmullRomPoints.Count - 2];
				catmullRomPoints.Add(item2);
				DirectorCore.instance.AddOccupiedNode(groundNodeGraph, nodeIndex);
				catmullRomIndex = 0;
				currentCurve = new CatmullRom3();
				tCurve = 0f;
				UpdateCurveSegmentPoints();
			}
			else
			{
				catmullRomPoints.Clear();
			}
		}

		private void UpdateCurveSegmentPoints()
		{
			currentCurve.SetPoints(catmullRomPoints[catmullRomIndex], catmullRomPoints[catmullRomIndex + 1], catmullRomPoints[catmullRomIndex + 2], catmullRomPoints[catmullRomIndex + 3]);
		}

		private int GetRemainingCurveSegmentCount()
		{
			return catmullRomPoints.Count - 4 - catmullRomIndex;
		}

		private void ResetVoTimer()
		{
			voTimer = UnityEngine.Random.Range(minimumVoDelay, maximumVoDelay);
		}
	}
	public class Unburrow : BaseSafeWardState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public float radius;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		private Xoroshiro128Plus rng;

		public Unburrow()
		{
		}

		public Unburrow(Xoroshiro128Plus rng)
		{
			this.rng = rng;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)safeWardController)
			{
				safeWardController.SetIndicatorEnabled(enabled: true);
			}
			PlayAnimation(animationLayerName, animationStateName);
			Util.PlaySound(enterSoundString, base.gameObject);
			if ((bool)purchaseInteraction)
			{
				purchaseInteraction.SetAvailable(newAvailable: false);
			}
			if ((bool)zone)
			{
				zone.Networkradius = radius;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				outer.SetNextState(new Travelling(rng));
			}
		}
	}
}
namespace EntityStates.MagmaWorm
{
	public class BlinkState : EntityStates.ImpBossMonster.BlinkState
	{
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialDeathExplosionEffect;

		public static string deathSoundString;

		public static float duration;

		private float stopwatch;

		public override void OnEnter()
		{
			base.OnEnter();
			WormBodyPositions2 component = GetComponent<WormBodyPositions2>();
			WormBodyPositionsDriver component2 = GetComponent<WormBodyPositionsDriver>();
			if ((bool)component)
			{
				component2.yDamperConstant = 0f;
				component2.ySpringConstant = 0f;
				component2.maxTurnSpeed = 0f;
				component.meatballCount = 0;
				Util.PlaySound(deathSoundString, component.bones[0].gameObject);
			}
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			PrintController printController = modelTransform.gameObject.AddComponent<PrintController>();
			printController.printTime = duration;
			printController.enabled = true;
			printController.startingPrintHeight = 99999f;
			printController.maxPrintHeight = 99999f;
			printController.startingPrintBias = 1f;
			printController.maxPrintBias = 3.5f;
			printController.animateFlowmapPower = true;
			printController.startingFlowmapPower = 1.14f;
			printController.maxFlowmapPower = 30f;
			printController.disableWhenFinished = false;
			printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
			ParticleSystem[] componentsInChildren = modelTransform.GetComponentsInChildren<ParticleSystem>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].Stop();
			}
			ChildLocator component3 = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component3)
			{
				Transform transform = component3.FindChild("PP");
				if ((bool)transform)
				{
					PostProcessDuration component4 = transform.GetComponent<PostProcessDuration>();
					if ((bool)component4)
					{
						component4.enabled = true;
						component4.maxDuration = duration;
					}
				}
			}
			if (NetworkServer.active)
			{
				EffectManager.SimpleMuzzleFlash(initialDeathExplosionEffect, base.gameObject, "HeadCenter", transmit: true);
			}
		}

		public override void FixedUpdate()
		{
			stopwatch += GetDeltaTime();
			if (NetworkServer.active && stopwatch > duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
	public class Leap : BaseState
	{
		private enum LeapState
		{
			Burrow,
			Ascend,
			Fall,
			Resurface
		}

		private Transform modelBaseTransform;

		private readonly float diveDepth = 200f;

		private readonly UnityEngine.Vector3 idealDiveVelocity = UnityEngine.Vector3.down * 90f;

		private readonly UnityEngine.Vector3 idealLeapVelocity = UnityEngine.Vector3.up * 90f;

		private float leapAcceleration = 80f;

		private float resurfaceSpeed = 60f;

		private UnityEngine.Vector3 velocity;

		private LeapState leapState;

		public override void OnEnter()
		{
			base.OnEnter();
			modelBaseTransform = GetModelBaseTransform();
			leapState = LeapState.Burrow;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			switch (leapState)
			{
			case LeapState.Burrow:
				if ((bool)modelBaseTransform)
				{
					if (modelBaseTransform.position.y >= base.transform.position.y - diveDepth)
					{
						velocity = UnityEngine.Vector3.MoveTowards(velocity, idealDiveVelocity, leapAcceleration * GetDeltaTime());
						modelBaseTransform.position += velocity * GetDeltaTime();
					}
					else
					{
						leapState = LeapState.Ascend;
					}
				}
				break;
			case LeapState.Ascend:
				if ((bool)modelBaseTransform)
				{
					if (modelBaseTransform.position.y <= base.transform.position.y)
					{
						velocity = UnityEngine.Vector3.MoveTowards(velocity, idealLeapVelocity, leapAcceleration * GetDeltaTime());
						modelBaseTransform.position += velocity * GetDeltaTime();
					}
					else
					{
						leapState = LeapState.Fall;
					}
				}
				break;
			case LeapState.Fall:
				if ((bool)modelBaseTransform)
				{
					if (modelBaseTransform.position.y >= base.transform.position.y - diveDepth)
					{
						velocity += Physics.gravity * GetDeltaTime();
						modelBaseTransform.position += velocity * GetDeltaTime();
					}
					else
					{
						leapState = LeapState.Resurface;
					}
				}
				break;
			case LeapState.Resurface:
				velocity = UnityEngine.Vector3.zero;
				modelBaseTransform.position = UnityEngine.Vector3.MoveTowards(modelBaseTransform.position, base.transform.position, resurfaceSpeed * GetDeltaTime());
				if (modelBaseTransform.position.y >= base.transform.position.y)
				{
					outer.SetNextStateToMain();
				}
				break;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SteerAtTarget : BaseSkillState
	{
		private WormBodyPositionsDriver wormBodyPositionsDriver;

		private UnityEngine.Vector3? targetPosition;

		private static readonly float fastTurnThreshold = Mathf.Cos(MathF.PI / 6f);

		private static readonly float slowTurnThreshold = Mathf.Cos(MathF.PI / 3f);

		private static readonly float fastTurnRate = 180f;

		private static readonly float slowTurnRate = 90f;

		public override void OnEnter()
		{
			base.OnEnter();
			wormBodyPositionsDriver = GetComponent<WormBodyPositionsDriver>();
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				if (Util.CharacterRaycast(base.gameObject, aimRay, out var hitInfo, 1000f, LayerIndex.CommonMasks.bullet, QueryTriggerInteraction.UseGlobal))
				{
					targetPosition = hitInfo.point;
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && targetPosition.HasValue)
			{
				UnityEngine.Vector3 vector = targetPosition.Value - wormBodyPositionsDriver.chaserPosition;
				if (vector != UnityEngine.Vector3.zero && wormBodyPositionsDriver.chaserVelocity != UnityEngine.Vector3.zero)
				{
					UnityEngine.Vector3 normalized = vector.normalized;
					UnityEngine.Vector3 normalized2 = wormBodyPositionsDriver.chaserVelocity.normalized;
					float num = UnityEngine.Vector3.Dot(normalized, normalized2);
					float num2 = 0f;
					if (num >= slowTurnThreshold)
					{
						num2 = slowTurnRate;
						if (num >= fastTurnThreshold)
						{
							num2 = fastTurnRate;
						}
					}
					if (num2 != 0f)
					{
						wormBodyPositionsDriver.chaserVelocity = UnityEngine.Vector3.RotateTowards(wormBodyPositionsDriver.chaserVelocity, vector, MathF.PI / 180f * num2 * GetDeltaTime(), 0f);
					}
				}
			}
			if (base.isAuthority && !IsKeyDownAuthority())
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			if (targetPosition.HasValue)
			{
				writer.Write(value: true);
				writer.Write(targetPosition.Value);
			}
			else
			{
				writer.Write(value: false);
			}
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			if (reader.ReadBoolean())
			{
				targetPosition = reader.ReadVector3();
			}
			else
			{
				targetPosition = null;
			}
		}
	}
	public class SwitchStance : BaseState
	{
		public static float leapingDuration = 10f;

		public static float groundStanceSpring = 3f;

		public static float groundStanceDamping = 3f;

		public static float groundStanceSpeedMultiplier = 1.5f;

		public static float leapStanceSpring = 3f;

		public static float leapStanceDamping = 1f;

		public static float leapStanceSpeedMultiplier = 1f;

		public override void OnEnter()
		{
			base.OnEnter();
			SetStanceParameters(leaping: true);
		}

		public override void OnExit()
		{
			base.OnExit();
			SetStanceParameters(leaping: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= leapingDuration)
			{
				outer.SetNextStateToMain();
			}
		}

		private void SetStanceParameters(bool leaping)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			WormBodyPositions2 component = GetComponent<WormBodyPositions2>();
			WormBodyPositionsDriver component2 = GetComponent<WormBodyPositionsDriver>();
			if ((bool)component)
			{
				if (leaping)
				{
					component2.ySpringConstant = leapStanceSpring;
					component2.yDamperConstant = leapStanceDamping;
					component.speedMultiplier = leapStanceSpeedMultiplier;
					component2.allowShoving = false;
				}
				else
				{
					component2.ySpringConstant = groundStanceSpring;
					component2.yDamperConstant = groundStanceDamping;
					component.speedMultiplier = groundStanceSpeedMultiplier;
					component2.allowShoving = true;
				}
				component.shouldFireMeatballsOnImpact = leaping;
			}
		}
	}
}
namespace EntityStates.ImpBossMonster
{
	public class BlinkState : BaseState
	{
		private Transform modelTransform;

		[SerializeField]
		public bool disappearWhileBlinking;

		[SerializeField]
		public GameObject blinkPrefab;

		[SerializeField]
		public GameObject blinkDestinationPrefab;

		[SerializeField]
		public Material destealthMaterial;

		private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero;

		[SerializeField]
		public float duration = 0.3f;

		[SerializeField]
		public float exitDuration;

		[SerializeField]
		public float destinationAlertDuration;

		[SerializeField]
		public float blinkDistance = 25f;

		[SerializeField]
		public string beginSoundString;

		[SerializeField]
		public string endSoundString;

		[SerializeField]
		public float blastAttackRadius;

		[SerializeField]
		public float blastAttackDamageCoefficient;

		[SerializeField]
		public float blastAttackForce;

		[SerializeField]
		public float blastAttackProcCoefficient;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private ChildLocator childLocator;

		private GameObject blinkDestinationInstance;

		private bool isExiting;

		private bool hasBlinked;

		private BullseyeSearch search;

		private BlastAttack attack;

		private EffectData _effectData;

		private EffectManagerHelper _emh_blinkDestinationInstance;

		private int originalLayer;

		private static int BlinkEndStateHash = Animator.StringToHash("BlinkEnd");

		private static int BlinkEndParamHash = Animator.StringToHash("BlinkEnd.playbackRate");

		public override void Reset()
		{
			base.Reset();
			modelTransform = null;
			blinkDestination = UnityEngine.Vector3.zero;
			blinkStart = UnityEngine.Vector3.zero;
			animator = null;
			characterModel = null;
			hurtboxGroup = null;
			childLocator = null;
			blinkDestinationInstance = null;
			isExiting = false;
			hasBlinked = false;
			if (search != null)
			{
				search.Reset();
			}
			if (attack != null)
			{
				attack.Reset();
			}
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			_emh_blinkDestinationInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
				childLocator = modelTransform.GetComponent<ChildLocator>();
			}
			if (disappearWhileBlinking)
			{
				if ((bool)characterModel)
				{
					characterModel.invisibilityCount++;
				}
				if ((bool)hurtboxGroup)
				{
					HurtBoxGroup hurtBoxGroup = hurtboxGroup;
					int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
					hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
				if ((bool)childLocator)
				{
					childLocator.FindChild("DustCenter").gameObject.SetActive(value: false);
				}
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
			originalLayer = base.gameObject.layer;
			base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
			base.characterMotor.Motor.RebuildCollidableLayers();
			CalculateBlinkDestination();
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
		}

		private void CalculateBlinkDestination()
		{
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			Ray aimRay = GetAimRay();
			if (search == null)
			{
				search = new BullseyeSearch();
			}
			search.searchOrigin = aimRay.origin;
			search.searchDirection = aimRay.direction;
			search.maxDistanceFilter = blinkDistance;
			search.teamMaskFilter = TeamMask.allButNeutral;
			search.filterByLoS = false;
			search.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject));
			search.sortMode = BullseyeSearch.SortMode.Angle;
			search.RefreshCandidates();
			HurtBox hurtBox = search.GetResults().FirstOrDefault();
			if ((bool)hurtBox)
			{
				vector = hurtBox.transform.position - base.transform.position;
			}
			blinkDestination = base.transform.position;
			blinkStart = base.transform.position;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(base.transform.position + vector, base.characterBody.hullClassification);
			groundNodes.GetNodePosition(nodeIndex, out blinkDestination);
			blinkDestination += base.transform.position - base.characterBody.footPosition;
			base.characterDirection.forward = vector;
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			if ((bool)blinkPrefab)
			{
				if (_effectData == null)
				{
					_effectData = new EffectData();
				}
				_effectData.rotation = Util.QuaternionSafeLookRotation(blinkDestination - blinkStart);
				_effectData.origin = origin;
				EffectManager.SpawnEffect(blinkPrefab, _effectData, transmit: false);
			}
		}

		private void SetPosition(UnityEngine.Vector3 newPosition)
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			if (!hasBlinked)
			{
				SetPosition(UnityEngine.Vector3.Lerp(blinkStart, blinkDestination, base.fixedAge / duration));
			}
			if (base.fixedAge >= duration - destinationAlertDuration && !hasBlinked)
			{
				hasBlinked = true;
				if ((bool)blinkDestinationPrefab)
				{
					if (!EffectManager.ShouldUsePooledEffect(blinkDestinationPrefab))
					{
						blinkDestinationInstance = UnityEngine.Object.Instantiate(blinkDestinationPrefab, blinkDestination, UnityEngine.Quaternion.identity);
					}
					else
					{
						_emh_blinkDestinationInstance = EffectManager.GetAndActivatePooledEffect(blinkDestinationPrefab, blinkDestination, UnityEngine.Quaternion.identity);
						blinkDestinationInstance = _emh_blinkDestinationInstance.gameObject;
					}
					blinkDestinationInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = destinationAlertDuration;
				}
				SetPosition(blinkDestination);
			}
			if (base.fixedAge >= duration)
			{
				ExitCleanup();
			}
			if (base.fixedAge >= duration + exitDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void ExitCleanup()
		{
			if (isExiting)
			{
				return;
			}
			isExiting = true;
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			Util.PlaySound(endSoundString, base.gameObject);
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
			modelTransform = GetModelTransform();
			if (blastAttackDamageCoefficient > 0f)
			{
				if (attack == null)
				{
					attack = new BlastAttack();
				}
				attack.attacker = base.gameObject;
				attack.inflictor = base.gameObject;
				attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				attack.baseDamage = damageStat * blastAttackDamageCoefficient;
				attack.baseForce = blastAttackForce;
				attack.position = blinkDestination;
				attack.radius = blastAttackRadius;
				attack.falloffModel = BlastAttack.FalloffModel.Linear;
				attack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				attack.Fire();
			}
			if (disappearWhileBlinking)
			{
				if ((bool)modelTransform && (bool)destealthMaterial)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject);
					temporaryOverlayInstance.duration = 1f;
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = destealthMaterial;
					temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent<CharacterModel>();
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.animateShaderAlpha = true;
				}
				if ((bool)characterModel)
				{
					characterModel.invisibilityCount--;
				}
				if ((bool)hurtboxGroup)
				{
					HurtBoxGroup hurtBoxGroup = hurtboxGroup;
					int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
					hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
				if ((bool)childLocator)
				{
					childLocator.FindChild("DustCenter").gameObject.SetActive(value: true);
				}
				PlayAnimation("Gesture, Additive", BlinkEndStateHash, BlinkEndParamHash, exitDuration);
			}
			if ((bool)blinkDestinationInstance)
			{
				if (_emh_blinkDestinationInstance != null && _emh_blinkDestinationInstance.OwningPool != null)
				{
					_emh_blinkDestinationInstance.OwningPool.ReturnObject(_emh_blinkDestinationInstance);
				}
				else
				{
					EntityState.Destroy(blinkDestinationInstance);
				}
				_emh_blinkDestinationInstance = null;
				blinkDestinationInstance = null;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = true;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			ExitCleanup();
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialEffect;

		public static GameObject deathEffect;

		private static float duration = 3.3166666f;

		private float stopwatch;

		private Animator animator;

		private bool hasPlayedDeathEffect;

		private bool attemptedDeathBehavior;

		private EffectManagerHelper _emh_initialEffect;

		private MaterialPropertyBlock block;

		private static int DeathStateHash = Animator.StringToHash("Death");

		private static int DeathEffectParamHash = Animator.StringToHash("DeathEffect");

		public override void Reset()
		{
			base.Reset();
			stopwatch = 0f;
			animator = null;
			hasPlayedDeathEffect = false;
			attemptedDeathBehavior = false;
			_emh_initialEffect = null;
			if (block == null)
			{
				block = new MaterialPropertyBlock();
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
			if ((bool)base.modelLocator)
			{
				Transform modelTransform = base.modelLocator.modelTransform;
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
				if ((bool)component)
				{
					component.FindChild("DustCenter").gameObject.SetActive(value: false);
					if ((bool)initialEffect)
					{
						EffectManager.SimpleMuzzleFlash(initialEffect, base.gameObject, "DeathCenter", transmit: false);
						if (EffectManager.ShouldUsePooledEffect(initialEffect))
						{
							_emh_initialEffect = EffectManager.LastSpawnedEffect;
						}
					}
				}
				if ((bool)component2)
				{
					for (int i = 0; i < component2.baseRendererInfos.Length; i++)
					{
						component2.baseRendererInfos[i].ignoreOverlays = true;
					}
				}
			}
			PlayAnimation("Fullbody Override", DeathStateHash);
		}

		public override void FixedUpdate()
		{
			if ((bool)animator)
			{
				stopwatch += GetDeltaTime();
				if (!hasPlayedDeathEffect && animator.GetFloat(DeathEffectParamHash) > 0.5f)
				{
					hasPlayedDeathEffect = true;
					EffectManager.SimpleMuzzleFlash(deathEffect, base.gameObject, "DeathCenter", transmit: false);
				}
				if (stopwatch >= duration)
				{
					AttemptDeathBehavior();
				}
			}
		}

		private void AttemptDeathBehavior()
		{
			if (attemptedDeathBehavior)
			{
				return;
			}
			attemptedDeathBehavior = true;
			if ((bool)base.modelLocator.modelBaseTransform)
			{
				EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
			}
			if (NetworkServer.active)
			{
				if (_emh_initialEffect != null && _emh_initialEffect.OwningPool != null)
				{
					_emh_initialEffect.OwningPool.ReturnObject(_emh_initialEffect);
					_emh_initialEffect = null;
				}
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				AttemptDeathBehavior();
			}
			base.OnExit();
		}
	}
	public class FireVoidspikes : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float procCoefficient;

		public static float selfForce;

		public static float forceMagnitude = 16f;

		public static GameObject hitEffectPrefab;

		public static GameObject swipeEffectPrefab;

		public static string enterSoundString;

		public static string attackSoundString;

		public static float walkSpeedPenaltyCoefficient;

		public static int projectileCount;

		public static float projectileYawSpread;

		public static float projectileDamageCoefficient;

		public static float projectileSpeed;

		public static float projectileSpeedPerProjectile;

		public static GameObject projectilePrefab;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private int slashCount;

		private Transform modelTransform;

		private int chosenAnim = -1;

		private static int FireVoidspikesLStateHash = Animator.StringToHash("FireVoidspikesL");

		private static int FireVoidspikesRStateHash = Animator.StringToHash("FireVoidspikesR");

		private static int FireVoidspikesParamHash = Animator.StringToHash("FireVoidspikes.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedPenaltyCoefficient;
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = GetTeam();
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			attack.procCoefficient = procCoefficient;
			attack.damageType = DamageType.BleedOnHit;
			Util.PlaySound(enterSoundString, base.gameObject);
			if (base.isAuthority)
			{
				chosenAnim = ((!Util.CheckRoll(50f)) ? 1 : 0);
			}
			if ((bool)modelAnimator)
			{
				int animationStateHash = ((chosenAnim == 1) ? FireVoidspikesLStateHash : FireVoidspikesRStateHash);
				PlayAnimation("Gesture, Additive", animationStateHash, FireVoidspikesParamHash, duration);
				PlayAnimation("Gesture, Override", animationStateHash, FireVoidspikesParamHash, duration);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration + 3f);
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && slashCount <= 0)
			{
				if (modelAnimator.GetFloat("HandR.hitBoxActive") > 0.1f)
				{
					FireSpikeFan(GetAimRay(), "FireVoidspikesR", "HandR");
				}
				if (modelAnimator.GetFloat("HandL.hitBoxActive") > 0.1f)
				{
					FireSpikeFan(GetAimRay(), "FireVoidspikesL", "HandL");
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireSpikeFan(Ray aimRay, string muzzleName, string hitBoxGroupName)
		{
			Util.PlaySound(attackSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, muzzleName, transmit: false);
			slashCount++;
			if (base.isAuthority)
			{
				UnityEngine.Vector3 forward = base.characterDirection.forward;
				if ((bool)modelTransform)
				{
					attack.hitBoxGroup = FindHitBoxGroup(hitBoxGroupName);
					attack.forceVector = forward * forceMagnitude;
					attack.Fire();
				}
				if ((bool)base.characterMotor)
				{
					base.characterMotor.ApplyForce(forward * selfForce, alwaysApply: true);
				}
				for (int i = 0; i < projectileCount; i++)
				{
					FireSpikeAuthority(aimRay, 0f, ((float)projectileCount / 2f - (float)i) * projectileYawSpread, projectileSpeed + projectileSpeedPerProjectile * (float)i);
				}
			}
		}

		private void FireSpikeAuthority(Ray aimRay, float bonusPitch, float bonusYaw, float speed)
		{
			UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch);
			ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * projectileDamageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speed);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((char)chosenAnim);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			chosenAnim = reader.ReadChar();
		}
	}
	public class GroundPound : BaseState
	{
		private float stopwatch;

		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float blastAttackRadius;

		private BlastAttack attack;

		public static string initialAttackSoundString;

		public static GameObject chargeEffectPrefab;

		public static GameObject slamEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject swipeEffectPrefab;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasAttacked;

		private float duration;

		private ChildLocator childLocator;

		private int attackCount;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			Util.PlaySound(initialAttackSoundString, base.gameObject);
			attack = new BlastAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
			attack.baseDamage = damageStat * damageCoefficient;
			attack.baseForce = forceMagnitude;
			attack.radius = blastAttackRadius;
			attack.falloffModel = BlastAttack.FalloffModel.SweetSpot;
			attack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Fullbody Override", "GroundPound", "GroundPound.playbackRate", duration, 0.2f);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration + 3f);
			}
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if ((bool)modelAnimator)
			{
				if (modelAnimator.GetFloat("GroundPound.hitBoxActive") > 0.5f)
				{
					if (!hasAttacked)
					{
						if (NetworkServer.active)
						{
							attack.position = childLocator.FindChild("GroundPoundCenter").transform.position;
							attack.Fire();
						}
						if (base.isAuthority)
						{
							EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "GroundPoundCenter", transmit: true);
						}
						EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, (attackCount % 2 == 0) ? "FireVoidspikesL" : "FireVoidspikesR", transmit: true);
						attackCount++;
						hasAttacked = true;
					}
				}
				else
				{
					hasAttacked = false;
				}
			}
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : BaseState
	{
		private float stopwatch;

		public static float duration = 4f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		public static Material destealthMaterial;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Animator modelAnimator = GetModelAnimator();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectData effectData = new EffectData();
				effectData.origin = base.transform.position;
				EffectManager.SpawnEffect(spawnEffectPrefab, effectData, transmit: false);
			}
			if ((bool)destealthMaterial)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelAnimator.gameObject);
				temporaryOverlayInstance.duration = 1f;
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = destealthMaterial;
				temporaryOverlayInstance.inspectorCharacterModel = modelAnimator.gameObject.GetComponent<CharacterModel>();
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.animateShaderAlpha = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.ImpMonster
{
	public class Backstab : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float radius = 3f;

		public static GameObject hitEffectPrefab;

		public static GameObject biteEffectPrefab;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private bool hasBit;

		private static int BackstabStateHash = Animator.StringToHash("Backstab");

		private static int BackstabParamHash = Animator.StringToHash("Backstab.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Backstab");
			}
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", BackstabStateHash, BackstabParamHash, duration);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Bite.hitBoxActive") > 0.1f)
			{
				if (!hasBit)
				{
					EffectManager.SimpleMuzzleFlash(biteEffectPrefab, base.gameObject, "MuzzleMouth", transmit: true);
					hasBit = true;
				}
				attack.forceVector = base.transform.forward * forceMagnitude;
				attack.Fire();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class BlinkState : BaseState
	{
		private Transform modelTransform;

		public static GameObject blinkPrefab;

		public static Material destealthMaterial;

		private float stopwatch;

		private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero;

		public static float duration = 0.3f;

		public static float blinkDistance = 25f;

		public static string beginSoundString;

		public static string endSoundString;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private static int BlinkEndStateHash = Animator.StringToHash("BlinkEnd");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
			UnityEngine.Vector3 vector = base.inputBank.moveVector * blinkDistance;
			blinkDestination = base.transform.position;
			blinkStart = base.transform.position;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(base.transform.position + vector, base.characterBody.hullClassification);
			groundNodes.GetNodePosition(nodeIndex, out blinkDestination);
			blinkDestination += base.transform.position - base.characterBody.footPosition;
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(blinkDestination - blinkStart);
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false);
		}

		private void SetPosition(UnityEngine.Vector3 newPosition)
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			SetPosition(UnityEngine.Vector3.Lerp(blinkStart, blinkDestination, stopwatch / duration));
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(endSoundString, base.gameObject);
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
			modelTransform = GetModelTransform();
			if ((bool)modelTransform && (bool)destealthMaterial)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject);
				temporaryOverlayInstance.duration = 1f;
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = destealthMaterial;
				temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent<CharacterModel>();
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.animateShaderAlpha = true;
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = true;
			}
			PlayAnimation("Gesture, Additive", BlinkEndStateHash);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ChargeSpines : BaseState
	{
		public static float baseDuration = 1f;

		public static GameObject effectPrefab;

		private float duration;

		private GameObject chargeEffect;

		private EffectManagerHelper _emh_chargeEffect;

		private static int ChargeSpinesStateHash = Animator.StringToHash("ChargeSpines");

		private static int ChargeSpinesParamHash = Animator.StringToHash("ChargeSpines.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffect = null;
			_emh_chargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleMouth");
					if ((bool)transform && (bool)effectPrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
						{
							chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation);
							chargeEffect = _emh_chargeEffect.gameObject;
						}
						chargeEffect.transform.parent = transform;
					}
				}
			}
			PlayAnimation("Gesture", ChargeSpinesStateHash, ChargeSpinesParamHash, duration);
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeEffect)
			{
				if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffect);
				}
				_emh_chargeEffect = null;
				chargeEffect = null;
			}
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireSpines nextState = new FireSpines();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialEffect;

		public static GameObject deathEffect;

		private static float duration = 1.333f;

		private float stopwatch;

		private Animator animator;

		private bool hasPlayedDeathEffect;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
			if ((bool)base.modelLocator && (bool)base.modelLocator.modelTransform.GetComponent<ChildLocator>() && (bool)initialEffect)
			{
				EffectManager.SimpleMuzzleFlash(initialEffect, base.gameObject, "Base", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)animator)
			{
				stopwatch += GetDeltaTime();
				if (!hasPlayedDeathEffect && animator.GetFloat("DeathEffect") > 0.5f)
				{
					hasPlayedDeathEffect = true;
					EffectManager.SimpleMuzzleFlash(deathEffect, base.gameObject, "Center", transmit: false);
				}
				if (stopwatch >= duration)
				{
					EntityState.Destroy(base.gameObject);
				}
			}
		}
	}
	public class DoubleSlash : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float procCoefficient;

		public static float selfForce;

		public static float forceMagnitude = 16f;

		public static GameObject hitEffectPrefab;

		public static GameObject swipeEffectPrefab;

		public static string enterSoundString;

		public static string slashSoundString;

		public static float walkSpeedPenaltyCoefficient;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private int slashCount;

		private Transform modelTransform;

		private static int DoubleSlashStateHash = Animator.StringToHash("DoubleSlash");

		private static int DoubleSlashParamHash = Animator.StringToHash("DoubleSlash.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedPenaltyCoefficient;
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			attack.procCoefficient = procCoefficient;
			attack.damageType = DamageType.BleedOnHit;
			Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture, Additive", DoubleSlashStateHash, DoubleSlashParamHash, duration);
				PlayAnimation("Gesture, Override", DoubleSlashStateHash, DoubleSlashParamHash, duration);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration + 2f);
			}
		}

		public override void OnExit()
		{
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			base.OnExit();
		}

		private void HandleSlash(string animatorParamName, string muzzleName, string hitBoxGroupName)
		{
			if (!(modelAnimator.GetFloat(animatorParamName) > 0.1f))
			{
				return;
			}
			Util.PlaySound(slashSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, muzzleName, transmit: true);
			slashCount++;
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == hitBoxGroupName);
			}
			if ((bool)base.healthComponent)
			{
				base.healthComponent.TakeDamageForce(base.characterDirection.forward * selfForce, alwaysApply: true);
			}
			attack.ResetIgnoredHealthComponents();
			if ((bool)base.characterDirection)
			{
				attack.forceVector = base.characterDirection.forward * forceMagnitude;
			}
			attack.Fire();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator)
			{
				switch (slashCount)
				{
				case 0:
					HandleSlash("HandR.hitBoxActive", "SwipeRight", "HandR");
					break;
				case 1:
					HandleSlash("HandL.hitBoxActive", "SwipeLeft", "HandL");
					break;
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireSpines : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float baseDuration = 2f;

		public static float durationBetweenThrows = 0.1f;

		public static int spineCountMax = 3;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		private int spineCount;

		private float spineTimer;

		private float duration;

		private static int FireSpinesStateHash = Animator.StringToHash("FireSpines");

		private static int FireSpinesParamHash = Animator.StringToHash("FireSpines.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture", FireSpinesStateHash, FireSpinesParamHash, duration);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			spineTimer += GetDeltaTime();
			if (spineTimer >= durationBetweenThrows / attackSpeedStat && spineCount < spineCountMax)
			{
				spineCount++;
				Ray aimRay = GetAimRay();
				string muzzleName = "MuzzleMouth";
				spineTimer -= durationBetweenThrows / attackSpeedStat;
				if ((bool)effectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
				}
				if (base.isAuthority)
				{
					ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : BaseState
	{
		private float stopwatch;

		public static float duration = 4f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "Base", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.ImpMonster.Weapon
{
	public class CloakPermanent : BaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.Cloak);
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.Huntress
{
	public class BeginArrowSnipe : BaseBeginArrowBarrage
	{
		protected override EntityState InstantiateNextState()
		{
			return new AimArrowSnipe();
		}
	}
	public class AimArrowSnipe : BaseArrowBarrage
	{
		public static SkillDef primarySkillDef;

		public static GameObject crosshairOverridePrefab;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private GenericSkill primarySkillSlot;

		private AimAnimator modelAimAnimator;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAimAnimator = GetModelTransform().GetComponent<AimAnimator>();
			if ((bool)modelAimAnimator)
			{
				modelAimAnimator.enabled = true;
			}
			primarySkillSlot = (base.skillLocator ? base.skillLocator.primary : null);
			if ((bool)primarySkillSlot)
			{
				primarySkillSlot.SetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			PlayCrossfade("Body", "ArrowBarrageLoop", 0.1f);
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
		}

		protected override void HandlePrimaryAttack()
		{
			if ((bool)primarySkillSlot)
			{
				primarySkillSlot.ExecuteIfReady();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if (!primarySkillSlot || primarySkillSlot.stock == 0)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)primarySkillSlot)
			{
				primarySkillSlot.UnsetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}
	}
	public class ArrowRain : BaseArrowBarrage
	{
		public static float arrowRainRadius = 0f;

		public static float damageCoefficient;

		public static GameObject projectilePrefab;

		public static GameObject areaIndicatorPrefab;

		public static GameObject muzzleFlashEffect;

		private GameObject areaIndicatorInstance;

		private bool shouldFireArrowRain;

		private EffectManagerHelper _emh_areaIndicatorInstance;

		private UnityEngine.Vector3 _cachedAreaIndicatorScale = UnityEngine.Vector3.one;

		private static int LoopArrowRainStateHash = Animator.StringToHash("LoopArrowRain");

		public override void Reset()
		{
			base.Reset();
			areaIndicatorInstance = null;
			shouldFireArrowRain = false;
			_emh_areaIndicatorInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("FullBody, Override", LoopArrowRainStateHash);
			if ((bool)areaIndicatorPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(areaIndicatorPrefab))
				{
					areaIndicatorInstance = UnityEngine.Object.Instantiate(areaIndicatorPrefab);
				}
				else
				{
					_emh_areaIndicatorInstance = EffectManager.GetAndActivatePooledEffect(areaIndicatorPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
					areaIndicatorInstance = _emh_areaIndicatorInstance.gameObject;
				}
				if (areaIndicatorInstance != null)
				{
					_cachedAreaIndicatorScale.x = arrowRainRadius;
					_cachedAreaIndicatorScale.y = arrowRainRadius;
					_cachedAreaIndicatorScale.z = arrowRainRadius;
					areaIndicatorInstance.transform.localScale = _cachedAreaIndicatorScale;
				}
			}
		}

		private void UpdateAreaIndicator()
		{
			if ((bool)areaIndicatorInstance)
			{
				float maxDistance = 1000f;
				if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask))
				{
					areaIndicatorInstance.transform.position = hitInfo.point;
					areaIndicatorInstance.transform.up = hitInfo.normal;
				}
			}
		}

		public override void Update()
		{
			base.Update();
			UpdateAreaIndicator();
		}

		protected override void HandlePrimaryAttack()
		{
			base.HandlePrimaryAttack();
			shouldFireArrowRain = true;
			outer.SetNextStateToMain();
		}

		protected void DoFireArrowRain()
		{
			EffectManager.SimpleMuzzleFlash(muzzleFlashEffect, base.gameObject, "Muzzle", transmit: false);
			if ((bool)areaIndicatorInstance && shouldFireArrowRain)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, areaIndicatorInstance.transform.position, areaIndicatorInstance.transform.rotation, base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			if (shouldFireArrowRain && !outer.destroying)
			{
				DoFireArrowRain();
			}
			if ((bool)areaIndicatorInstance)
			{
				if (_emh_areaIndicatorInstance != null && _emh_areaIndicatorInstance.OwningPool != null)
				{
					_emh_areaIndicatorInstance.OwningPool.ReturnObject(_emh_areaIndicatorInstance);
				}
				else
				{
					EntityState.Destroy(areaIndicatorInstance.gameObject);
				}
				areaIndicatorInstance = null;
				_emh_areaIndicatorInstance = null;
			}
			base.OnExit();
		}
	}
	public class BaseArrowBarrage : BaseState
	{
		[SerializeField]
		public float maxDuration;

		[SerializeField]
		public string beginLoopSoundString;

		[SerializeField]
		public string endLoopSoundString;

		[SerializeField]
		public string fireSoundString;

		private HuntressTracker huntressTracker;

		private CameraTargetParams.AimRequest aimRequest;

		private static int FireArrowRainStateHash = Animator.StringToHash("FireArrowRain");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginLoopSoundString, base.gameObject);
			huntressTracker = GetComponent<HuntressTracker>();
			if ((bool)huntressTracker)
			{
				huntressTracker.enabled = false;
			}
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			if (base.isAuthority && (bool)base.inputBank)
			{
				if ((bool)base.skillLocator && base.skillLocator.utility.IsReady() && base.inputBank.skill3.justPressed)
				{
					outer.SetNextStateToMain();
				}
				else if (base.fixedAge >= maxDuration || base.inputBank.skill1.justPressed || base.inputBank.skill4.justPressed)
				{
					HandlePrimaryAttack();
				}
			}
		}

		protected virtual void HandlePrimaryAttack()
		{
		}

		public override void OnExit()
		{
			PlayAnimation("FullBody, Override", FireArrowRainStateHash);
			Util.PlaySound(endLoopSoundString, base.gameObject);
			Util.PlaySound(fireSoundString, base.gameObject);
			aimRequest?.Dispose();
			if ((bool)huntressTracker)
			{
				huntressTracker.enabled = true;
			}
			base.OnExit();
		}
	}
	public class BackflipState : BaseState
	{
		public static float duration = 0.9f;

		public static float initialSpeedCoefficient;

		public static float finalSpeedCoefficient;

		public static string dodgeSoundString;

		public static float dodgeFOV;

		public static float orbDamageCoefficient;

		public static float orbRange;

		public static int orbCountMax;

		public static float orbPrefireDuration;

		public static float orbFrequency;

		public static float orbProcCoefficient;

		public static string muzzleString;

		public static float smallHopStrength;

		public static GameObject muzzleflashEffectPrefab;

		private ChildLocator childLocator;

		private float stopwatch;

		private float orbStopwatch;

		private UnityEngine.Vector3 forwardDirection;

		private Animator animator;

		private int orbCount;

		private static int BackflipStateHash = Animator.StringToHash("Backflip");

		private static int BackflipParamHash = Animator.StringToHash("Backflip.playbackRate");

		private static int FireSeekingArrowStateHash = Animator.StringToHash("FireSeekingArrow");

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, 0f);
			animator = GetModelAnimator();
			Util.PlaySound(dodgeSoundString, base.gameObject);
			orbStopwatch = 0f - orbPrefireDuration;
			if ((bool)base.characterMotor && smallHopStrength != 0f)
			{
				base.characterMotor.velocity.y = smallHopStrength;
			}
			if (base.isAuthority && (bool)base.inputBank)
			{
				forwardDirection = -UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up);
			}
			base.characterDirection.moveVector = -forwardDirection;
			PlayAnimation("FullBody, Override", BackflipStateHash, BackflipParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			stopwatch += deltaTime;
			orbStopwatch += deltaTime;
			if ((bool)base.cameraTargetParams)
			{
				base.cameraTargetParams.fovOverride = Mathf.Lerp(dodgeFOV, 60f, stopwatch / duration);
			}
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				UnityEngine.Vector3 velocity = base.characterMotor.velocity;
				UnityEngine.Vector3 velocity2 = forwardDirection * (moveSpeedStat * Mathf.Lerp(initialSpeedCoefficient, finalSpeedCoefficient, stopwatch / duration));
				base.characterMotor.velocity = velocity2;
				base.characterMotor.velocity.y = velocity.y;
				base.characterMotor.moveDirection = forwardDirection;
			}
			if (orbStopwatch >= 1f / orbFrequency / attackSpeedStat && orbCount < orbCountMax)
			{
				orbStopwatch -= 1f / orbFrequency / attackSpeedStat;
				FireOrbArrow();
			}
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireOrbArrow()
		{
			if (NetworkServer.active)
			{
				orbCount++;
				HuntressArrowOrb huntressArrowOrb = new HuntressArrowOrb();
				huntressArrowOrb.damageValue = base.characterBody.damage * orbDamageCoefficient;
				huntressArrowOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master);
				huntressArrowOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				huntressArrowOrb.attacker = base.gameObject;
				huntressArrowOrb.damageColorIndex = DamageColorIndex.Poison;
				huntressArrowOrb.procChainMask.AddProc(ProcType.HealOnHit);
				huntressArrowOrb.procCoefficient = orbProcCoefficient;
				Ray aimRay = GetAimRay();
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.searchOrigin = aimRay.origin;
				bullseyeSearch.searchDirection = aimRay.direction;
				bullseyeSearch.maxDistanceFilter = orbRange;
				bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
				bullseyeSearch.teamMaskFilter.RemoveTeam(huntressArrowOrb.teamIndex);
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
				bullseyeSearch.RefreshCandidates();
				List<HurtBox> list = bullseyeSearch.GetResults().ToList();
				HurtBox hurtBox = ((list.Count > 0) ? list[UnityEngine.Random.Range(0, list.Count)] : null);
				if ((bool)hurtBox)
				{
					Transform transform = childLocator.FindChild(muzzleString).transform;
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
					huntressArrowOrb.origin = transform.position;
					huntressArrowOrb.target = hurtBox;
					PlayAnimation("Gesture, Override", FireSeekingArrowStateHash);
					PlayAnimation("Gesture, Additive", FireSeekingArrowStateHash);
					OrbManager.instance.AddOrb(huntressArrowOrb);
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)base.cameraTargetParams)
			{
				base.cameraTargetParams.fovOverride = -1f;
			}
			int layerIndex = animator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, 1.5f);
				animator.PlayInFixedTime("LightImpact", layerIndex, 0f);
			}
		}
	}
	public class BeginArrowRain : BaseBeginArrowBarrage
	{
		protected override EntityState InstantiateNextState()
		{
			return new ArrowRain();
		}
	}
	public class BaseBeginArrowBarrage : BaseState
	{
		private Transform modelTransform;

		[SerializeField]
		public float basePrepDuration;

		[SerializeField]
		public float blinkDuration = 0.3f;

		[SerializeField]
		public float jumpCoefficient = 25f;

		public static GameObject blinkPrefab;

		public static string blinkSoundString;

		[SerializeField]
		public UnityEngine.Vector3 blinkVector;

		private UnityEngine.Vector3 worldBlinkVector;

		private float prepDuration;

		private bool beginBlink;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		protected CameraTargetParams.AimRequest aimRequest;

		private static int BeginArrowRainStateHash = Animator.StringToHash("BeginArrowRain");

		private static int BeginArrowRainParamHash = Animator.StringToHash("BeginArrowRain.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(blinkSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
			}
			prepDuration = basePrepDuration / attackSpeedStat;
			PlayAnimation("FullBody, Override", BeginArrowRainStateHash, BeginArrowRainParamHash, prepDuration);
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			UnityEngine.Vector3 direction = GetAimRay().direction;
			direction.y = 0f;
			direction.Normalize();
			UnityEngine.Vector3 up = UnityEngine.Vector3.up;
			worldBlinkVector = UnityEngine.Matrix4x4.TRS(base.transform.position, Util.QuaternionSafeLookRotation(direction, up), new UnityEngine.Vector3(1f, 1f, 1f)).MultiplyPoint3x4(blinkVector) - base.transform.position;
			worldBlinkVector.Normalize();
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(worldBlinkVector);
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= prepDuration && !beginBlink)
			{
				beginBlink = true;
				CreateBlinkEffect(base.transform.position);
				if ((bool)characterModel)
				{
					characterModel.invisibilityCount++;
				}
				if ((bool)hurtboxGroup)
				{
					HurtBoxGroup hurtBoxGroup = hurtboxGroup;
					int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
					hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
			}
			if (beginBlink && (bool)base.characterMotor)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				base.characterMotor.rootMotion += worldBlinkVector * (base.characterBody.jumpPower * jumpCoefficient * GetDeltaTime());
			}
			if (base.fixedAge >= blinkDuration + prepDuration && base.isAuthority)
			{
				outer.SetNextState(InstantiateNextState());
			}
		}

		protected virtual EntityState InstantiateNextState()
		{
			return null;
		}

		public override void OnExit()
		{
			CreateBlinkEffect(base.transform.position);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance.duration = 0.6f;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashBright");
				temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
				TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
				temporaryOverlayInstance2.duration = 0.7f;
				temporaryOverlayInstance2.animateShaderAlpha = true;
				temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance2.destroyComponentOnEnd = true;
				temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashExpanded");
				temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			aimRequest?.Dispose();
			base.OnExit();
		}
	}
	public class BlinkState : BaseState
	{
		private Transform modelTransform;

		public static GameObject blinkPrefab;

		private float stopwatch;

		private UnityEngine.Vector3 blinkVector = UnityEngine.Vector3.zero;

		[SerializeField]
		public float duration = 0.3f;

		[SerializeField]
		public float speedCoefficient = 25f;

		[SerializeField]
		public string beginSoundString;

		[SerializeField]
		public string endSoundString;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			blinkVector = GetBlinkVector();
			CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
		}

		protected virtual UnityEngine.Vector3 GetBlinkVector()
		{
			return base.inputBank.aimDirection;
		}

		private void CreateBlinkEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.rotation = Util.QuaternionSafeLookRotation(blinkVector);
			effectData.origin = origin;
			EffectManager.SpawnEffect(blinkPrefab, effectData, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				base.characterMotor.rootMotion += blinkVector * (moveSpeedStat * speedCoefficient * GetDeltaTime());
			}
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				Util.PlaySound(endSoundString, base.gameObject);
				CreateBlinkEffect(Util.GetCorePosition(base.gameObject));
				modelTransform = GetModelTransform();
				if ((bool)modelTransform)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
					temporaryOverlayInstance.duration = 0.6f;
					temporaryOverlayInstance.animateShaderAlpha = true;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashBright");
					temporaryOverlayInstance.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
					TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(modelTransform.gameObject);
					temporaryOverlayInstance2.duration = 0.7f;
					temporaryOverlayInstance2.animateShaderAlpha = true;
					temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance2.destroyComponentOnEnd = true;
					temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashExpanded");
					temporaryOverlayInstance2.AddToCharacterModel(modelTransform.GetComponent<CharacterModel>());
				}
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.disableAirControlUntilCollision = false;
			}
			base.OnExit();
		}
	}
	public class MiniBlinkState : BlinkState
	{
		protected override UnityEngine.Vector3 GetBlinkVector()
		{
			return ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized;
		}
	}
}
namespace EntityStates.Huntress.Weapon
{
	public class FireArrowSnipe : GenericBulletBaseState
	{
		public float charge;

		public static float recoilAmplitude;

		private static int FireArrowSnipeStateHash = Animator.StringToHash("FireArrowSnipe");

		private static int FireArrowSnipeParamHash = Animator.StringToHash("FireArrowSnipe.playbackRate");

		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
			_ = (bool)(base.skillLocator ? base.skillLocator.primary : null);
		}

		protected override void FireBullet(Ray aimRay)
		{
			base.FireBullet(aimRay);
			base.characterBody.SetSpreadBloom(0.2f, canOnlyIncreaseBloom: false);
			AddRecoil(-0.6f * recoilAmplitude, -0.8f * recoilAmplitude, -0.1f * recoilAmplitude, 0.1f * recoilAmplitude);
			PlayAnimation("Body", FireArrowSnipeStateHash, FireArrowSnipeParamHash, duration);
			base.healthComponent.TakeDamageForce(aimRay.direction * -400f, alwaysApply: true);
		}
	}
}
namespace EntityStates.Huntress.HuntressWeapon
{
	public class ChargeArrow : BaseState
	{
		public static float baseTotalDuration;

		public static float baseMaxChargeTime;

		public static int maxCharges;

		public static GameObject chargeEffectPrefab;

		public static GameObject muzzleflashEffectPrefab;

		public static string chargeStockSoundString;

		public static string chargeLoopStartSoundString;

		public static string chargeLoopStopSoundString;

		public static float minBonusBloom;

		public static float maxBonusBloom;

		public static float minArrowDamageCoefficient;

		public static float maxArrowDamageCoefficient;

		public static float orbDamageCoefficient;

		public static float orbRange;

		public static float orbFrequency;

		public static float orbProcCoefficient;

		private float stopwatch;

		private GameObject chargeLeftInstance;

		private GameObject chargeRightInstance;

		private Animator animator;

		private int charge;

		private int lastCharge;

		private ChildLocator childLocator;

		private float totalDuration;

		private float maxChargeTime;

		private bool cachedSprinting;

		private float originalMinYaw;

		private float originalMaxYaw;

		private string muzzleString;

		private static int chargingArrowParamHash = Animator.StringToHash("chargingArrow");

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		private static int FireSeekingArrowStateHash = Animator.StringToHash("FireSeekingArrow");

		public override void OnEnter()
		{
			base.OnEnter();
			totalDuration = baseTotalDuration / attackSpeedStat;
			maxChargeTime = baseMaxChargeTime / attackSpeedStat;
			muzzleString = "Muzzle";
			Transform modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			animator = GetModelAnimator();
			cachedSprinting = base.characterBody.isSprinting;
			if (!cachedSprinting)
			{
				animator.SetBool(chargingArrowParamHash, value: true);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(maxChargeTime + 1f);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			animator.SetBool(chargingArrowParamHash, value: false);
			if (!cachedSprinting)
			{
				PlayAnimation("Gesture, Override", BufferEmptyStateHash);
				PlayAnimation("Gesture, Additive", BufferEmptyStateHash);
			}
		}

		private void FireOrbArrow()
		{
			if (NetworkServer.active)
			{
				HuntressArrowOrb huntressArrowOrb = new HuntressArrowOrb();
				huntressArrowOrb.damageValue = base.characterBody.damage * orbDamageCoefficient;
				huntressArrowOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master);
				huntressArrowOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				huntressArrowOrb.attacker = base.gameObject;
				huntressArrowOrb.damageColorIndex = DamageColorIndex.Poison;
				huntressArrowOrb.procChainMask.AddProc(ProcType.HealOnHit);
				huntressArrowOrb.procCoefficient = orbProcCoefficient;
				Ray aimRay = GetAimRay();
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.searchOrigin = aimRay.origin;
				bullseyeSearch.searchDirection = aimRay.direction;
				bullseyeSearch.maxDistanceFilter = orbRange;
				bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
				bullseyeSearch.teamMaskFilter.RemoveTeam(huntressArrowOrb.teamIndex);
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
				bullseyeSearch.RefreshCandidates();
				List<HurtBox> list = bullseyeSearch.GetResults().ToList();
				HurtBox hurtBox = ((list.Count > 0) ? list[UnityEngine.Random.Range(0, list.Count)] : null);
				if ((bool)hurtBox)
				{
					Transform transform = childLocator.FindChild(muzzleString).transform;
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
					huntressArrowOrb.origin = transform.position;
					huntressArrowOrb.target = hurtBox;
					PlayAnimation("Gesture, Override", FireSeekingArrowStateHash);
					PlayAnimation("Gesture, Additive", FireSeekingArrowStateHash);
					OrbManager.instance.AddOrb(huntressArrowOrb);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (cachedSprinting != base.characterBody.isSprinting && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
			else if (!cachedSprinting)
			{
				lastCharge = charge;
				stopwatch += GetDeltaTime();
				charge = Mathf.Min((int)(stopwatch / maxChargeTime * (float)maxCharges), maxCharges);
				float damageCoefficient = Mathf.Lerp(minArrowDamageCoefficient, maxArrowDamageCoefficient, charge);
				if (lastCharge < charge && charge == maxCharges)
				{
					EffectManager.SimpleMuzzleFlash(chargeEffectPrefab, base.gameObject, muzzleString, transmit: false);
				}
				if ((stopwatch >= totalDuration || !base.inputBank || !base.inputBank.skill1.down) && base.isAuthority)
				{
					FireArrow fireArrow = new FireArrow();
					fireArrow.damageCoefficient = damageCoefficient;
					outer.SetNextState(fireArrow);
				}
			}
			else
			{
				stopwatch += GetDeltaTime();
				if (stopwatch >= 1f / orbFrequency / attackSpeedStat)
				{
					stopwatch -= 1f / orbFrequency / attackSpeedStat;
					FireOrbArrow();
				}
				if ((!base.inputBank || !base.inputBank.skill1.down) && base.isAuthority)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireArrow : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject projectilePrefab;

		public static int arrowCountMax = 1;

		public float damageCoefficient;

		public static float fireDuration = 1f;

		public static float baseDuration = 2f;

		public static float arcAngle = 5f;

		public static float recoilAmplitude = 1f;

		public static string attackSoundString;

		public static float spreadBloomValue = 0.3f;

		public static float smallHopStrength;

		private Ray aimRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		private static int fireArrowHash = Animator.StringToHash("FireArrow");

		private static int fireArrowParamHash = Animator.StringToHash("FireArrow.playbackRate");

		private void FireGrenade(string targetMuzzle)
		{
			Util.PlaySound(attackSoundString, base.gameObject);
			aimRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						aimRay.origin = transform.position;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle;
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			if ((bool)base.characterMotor && smallHopStrength != 0f)
			{
				base.characterMotor.velocity.y = smallHopStrength;
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				fireTimer -= GetDeltaTime();
				float num = fireDuration / attackSpeedStat / (float)arrowCountMax;
				if (fireTimer <= 0f && grenadeCount < arrowCountMax)
				{
					PlayAnimation("Gesture, Additive", fireArrowHash, fireArrowParamHash, duration - num);
					PlayAnimation("Gesture, Override", fireArrowHash, fireArrowParamHash, duration - num);
					FireGrenade("Muzzle");
					fireTimer += num;
					grenadeCount++;
				}
				if (base.fixedAge >= duration)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireArrowOld : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			string muzzleName = "Muzzle";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Gesture");
				modelAnimator.SetFloat("FireArrow.playbackRate", attackSpeedStat);
				modelAnimator.PlayInFixedTime("FireArrow", layerIndex, 0f);
				muzzleName = "MuzzleRight";
				modelAnimator.Update(0f);
				if (base.isAuthority)
				{
					ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireGlaive : BaseState
	{
		public static GameObject projectilePrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		private float duration;

		private static int FireGlaiveStateHash = Animator.StringToHash("FireGlaive");

		private static int FireGlaiveParamHash = Animator.StringToHash("FireGlaive.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			Transform modelTransform = GetModelTransform();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture", FireGlaiveStateHash, FireGlaiveParamHash, duration);
			UnityEngine.Vector3 position = aimRay.origin;
			UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(aimRay.direction);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("RightHand");
					if ((bool)transform)
					{
						position = transform.position;
					}
				}
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, position, rotation, base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireSeekingArrow : BaseState
	{
		[SerializeField]
		public float orbDamageCoefficient;

		[SerializeField]
		public float orbProcCoefficient;

		[SerializeField]
		public string muzzleString;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public int maxArrowCount;

		[SerializeField]
		public float baseArrowReloadDuration;

		private float duration;

		protected float arrowReloadDuration;

		private float arrowReloadTimer;

		protected bool isCrit;

		private int firedArrowCount;

		private HurtBox initialOrbTarget;

		private ChildLocator childLocator;

		private HuntressTracker huntressTracker;

		private Animator animator;

		private static int fireSeekingShotStateHash = Animator.StringToHash("FireSeekingShot");

		private static int fireSeekingShotParamHash = Animator.StringToHash("FireSeekingShot.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			huntressTracker = GetComponent<HuntressTracker>();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				animator = modelTransform.GetComponent<Animator>();
			}
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			if ((bool)huntressTracker && base.isAuthority)
			{
				initialOrbTarget = huntressTracker.GetTrackingTarget();
			}
			duration = baseDuration / attackSpeedStat;
			arrowReloadDuration = baseArrowReloadDuration / attackSpeedStat;
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration + 1f);
			}
			PlayCrossfade("Gesture, Override", fireSeekingShotStateHash, fireSeekingShotParamHash, duration, duration * 0.2f / attackSpeedStat);
			PlayCrossfade("Gesture, Additive", fireSeekingShotStateHash, fireSeekingShotParamHash, duration, duration * 0.2f / attackSpeedStat);
			isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master);
		}

		public override void OnExit()
		{
			base.OnExit();
			FireOrbArrow();
		}

		protected virtual GenericDamageOrb CreateArrowOrb()
		{
			return new HuntressArrowOrb();
		}

		private void FireOrbArrow()
		{
			if (firedArrowCount < maxArrowCount && !(arrowReloadTimer > 0f) && NetworkServer.active)
			{
				firedArrowCount++;
				arrowReloadTimer = arrowReloadDuration;
				GenericDamageOrb genericDamageOrb = CreateArrowOrb();
				genericDamageOrb.damageValue = base.characterBody.damage * orbDamageCoefficient;
				genericDamageOrb.isCrit = isCrit;
				genericDamageOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				genericDamageOrb.attacker = base.gameObject;
				genericDamageOrb.procCoefficient = orbProcCoefficient;
				HurtBox hurtBox = initialOrbTarget;
				if ((bool)hurtBox)
				{
					Transform transform = childLocator.FindChild(muzzleString);
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
					genericDamageOrb.origin = transform.position;
					genericDamageOrb.target = hurtBox;
					OrbManager.instance.AddOrb(genericDamageOrb);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			arrowReloadTimer -= GetDeltaTime();
			if (animator.GetFloat("FireSeekingShot.fire") > 0f)
			{
				FireOrbArrow();
			}
			if (base.fixedAge > duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			writer.Write(HurtBoxReference.FromHurtBox(initialOrbTarget));
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			initialOrbTarget = reader.ReadHurtBoxReference().ResolveHurtBox();
		}
	}
	public class FireFlurrySeekingArrow : FireSeekingArrow
	{
		public static GameObject critMuzzleflashEffectPrefab;

		public static int critMaxArrowCount;

		public static float critBaseArrowReloadDuration;

		public override void OnEnter()
		{
			base.OnEnter();
			if (isCrit)
			{
				muzzleflashEffectPrefab = critMuzzleflashEffectPrefab;
				maxArrowCount = critMaxArrowCount;
				arrowReloadDuration = critBaseArrowReloadDuration / attackSpeedStat;
			}
		}

		protected override GenericDamageOrb CreateArrowOrb()
		{
			return new HuntressFlurryArrowOrb();
		}
	}
	public class IdleTracking : BaseState
	{
		public static float maxTrackingDistance = 20f;

		public static float maxTrackingAngle = 20f;

		public static float orbDamageCoefficient;

		public static float orbProcCoefficient;

		public static string muzzleString;

		public static GameObject muzzleflashEffectPrefab;

		public static string attackSoundString;

		public static float fireFrequency;

		private float fireTimer;

		private Transform trackingIndicatorTransform;

		private HurtBox trackingTarget;

		private ChildLocator childLocator;

		private BullseyeSearch search;

		private GameObject TrackingIndicatorPrefab;

		private EffectManagerHelper _emh_trackingIndicator;

		private static int FireSeekingArrowStateHash = Animator.StringToHash("FireSeekingArrow");

		public override void Reset()
		{
			base.Reset();
			fireTimer = 0f;
			trackingIndicatorTransform = null;
			trackingTarget = null;
			childLocator = null;
			if (search != null)
			{
				search.Reset();
			}
			_emh_trackingIndicator = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
			}
		}

		protected void DestroyTrackingIndicator()
		{
			if ((bool)trackingIndicatorTransform)
			{
				if (_emh_trackingIndicator != null && _emh_trackingIndicator.OwningPool != null)
				{
					_emh_trackingIndicator.OwningPool.ReturnObject(_emh_trackingIndicator);
				}
				else
				{
					EntityState.Destroy(trackingIndicatorTransform.gameObject);
				}
				trackingIndicatorTransform = null;
				_emh_trackingIndicator = null;
			}
		}

		public override void OnExit()
		{
			DestroyTrackingIndicator();
			base.OnExit();
		}

		private void FireOrbArrow()
		{
			if (NetworkServer.active)
			{
				HuntressArrowOrb huntressArrowOrb = new HuntressArrowOrb();
				huntressArrowOrb.damageValue = base.characterBody.damage * orbDamageCoefficient;
				huntressArrowOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master);
				huntressArrowOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				huntressArrowOrb.attacker = base.gameObject;
				huntressArrowOrb.damageColorIndex = DamageColorIndex.Poison;
				huntressArrowOrb.procChainMask.AddProc(ProcType.HealOnHit);
				huntressArrowOrb.procCoefficient = orbProcCoefficient;
				HurtBox hurtBox = trackingTarget;
				if ((bool)hurtBox)
				{
					Transform transform = childLocator.FindChild(muzzleString).transform;
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
					huntressArrowOrb.origin = transform.position;
					huntressArrowOrb.target = hurtBox;
					PlayAnimation("Gesture, Override", FireSeekingArrowStateHash);
					PlayAnimation("Gesture, Additive", FireSeekingArrowStateHash);
					Util.PlaySound(attackSoundString, base.gameObject);
					OrbManager.instance.AddOrb(huntressArrowOrb);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			fireTimer -= GetDeltaTime();
			if ((bool)base.characterBody)
			{
				float extraRaycastDistance = 0f;
				Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance);
				if (search == null)
				{
					search = new BullseyeSearch();
				}
				search.searchOrigin = ray.origin;
				search.searchDirection = ray.direction;
				search.maxDistanceFilter = maxTrackingDistance + extraRaycastDistance;
				search.maxAngleFilter = maxTrackingAngle;
				search.teamMaskFilter = TeamMask.allButNeutral;
				search.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject));
				search.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
				search.RefreshCandidates();
				trackingTarget = search.GetResults().FirstOrDefault();
			}
			if ((bool)trackingTarget)
			{
				if (!trackingIndicatorTransform)
				{
					if (TrackingIndicatorPrefab == null)
					{
						TrackingIndicatorPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/ShieldTransferIndicator");
					}
					if (!EffectManager.ShouldUsePooledEffect(TrackingIndicatorPrefab))
					{
						trackingIndicatorTransform = UnityEngine.Object.Instantiate(TrackingIndicatorPrefab, trackingTarget.transform.position, UnityEngine.Quaternion.identity).transform;
					}
					else
					{
						_emh_trackingIndicator = EffectManager.GetAndActivatePooledEffect(TrackingIndicatorPrefab, trackingTarget.transform.position, UnityEngine.Quaternion.identity);
						trackingIndicatorTransform = _emh_trackingIndicator.gameObject.transform;
					}
				}
				trackingIndicatorTransform.position = trackingTarget.transform.position;
				if ((bool)base.inputBank && base.inputBank.skill1.down && fireTimer <= 0f)
				{
					fireTimer = 1f / fireFrequency / attackSpeedStat;
					FireOrbArrow();
				}
			}
			else
			{
				DestroyTrackingIndicator();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public class ThrowGlaive : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargePrefab;

		public static GameObject muzzleFlashPrefab;

		public static float smallHopStrength;

		public static float antigravityStrength;

		public static float damageCoefficient = 1.2f;

		public static float damageCoefficientPerBounce = 1.1f;

		public static float glaiveProcCoefficient;

		public static int maxBounceCount;

		public static float glaiveTravelSpeed;

		public static float glaiveBounceRange;

		public static string attackSoundString;

		private float duration;

		private float stopwatch;

		private Animator animator;

		private GameObject chargeEffect;

		private Transform modelTransform;

		private HuntressTracker huntressTracker;

		private ChildLocator childLocator;

		private bool hasTriedToThrowGlaive;

		private bool hasSuccessfullyThrownGlaive;

		private HurtBox initialOrbTarget;

		private EffectManagerHelper _emh_chargeEffect;

		private static int ThrowGlaiveStateHash = Animator.StringToHash("ThrowGlaive");

		private static int ThrowGlaiveParamHash = Animator.StringToHash("ThrowGlaive.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			stopwatch = 0f;
			animator = null;
			chargeEffect = null;
			modelTransform = null;
			huntressTracker = null;
			childLocator = null;
			hasTriedToThrowGlaive = false;
			hasSuccessfullyThrownGlaive = false;
			initialOrbTarget = null;
			_emh_chargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			animator = GetModelAnimator();
			huntressTracker = GetComponent<HuntressTracker>();
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			if ((bool)huntressTracker && base.isAuthority)
			{
				initialOrbTarget = huntressTracker.GetTrackingTarget();
			}
			if ((bool)base.characterMotor && smallHopStrength != 0f)
			{
				base.characterMotor.velocity.y = smallHopStrength;
			}
			PlayAnimation("FullBody, Override", ThrowGlaiveStateHash, ThrowGlaiveParamHash, duration);
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				if ((bool)childLocator)
				{
					Transform transform = childLocator.FindChild("HandR");
					if ((bool)transform && (bool)chargePrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargePrefab))
						{
							chargeEffect = UnityEngine.Object.Instantiate(chargePrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargePrefab, transform.position, transform.rotation);
							chargeEffect = _emh_chargeEffect.gameObject;
						}
						chargeEffect.transform.parent = transform;
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		protected void DestroyChargeEffect()
		{
			if ((bool)chargeEffect)
			{
				if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffect);
				}
				chargeEffect = null;
				_emh_chargeEffect = null;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			DestroyChargeEffect();
			int layerIndex = animator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, 1.5f);
				animator.PlayInFixedTime("LightImpact", layerIndex, 0f);
			}
			if (!hasTriedToThrowGlaive)
			{
				FireOrbGlaive();
			}
			if (!hasSuccessfullyThrownGlaive && NetworkServer.active)
			{
				base.skillLocator.secondary.AddOneStock();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (!hasTriedToThrowGlaive && animator.GetFloat("ThrowGlaive.fire") > 0f)
			{
				DestroyChargeEffect();
				FireOrbGlaive();
			}
			base.characterMotor.velocity.y += antigravityStrength * GetDeltaTime() * (1f - stopwatch / duration);
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireOrbGlaive()
		{
			if (NetworkServer.active && !hasTriedToThrowGlaive)
			{
				hasTriedToThrowGlaive = true;
				LightningOrb lightningOrb = new LightningOrb();
				lightningOrb.lightningType = LightningOrb.LightningType.HuntressGlaive;
				lightningOrb.damageValue = base.characterBody.damage * damageCoefficient;
				lightningOrb.isCrit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master);
				lightningOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				lightningOrb.attacker = base.gameObject;
				lightningOrb.procCoefficient = glaiveProcCoefficient;
				lightningOrb.bouncesRemaining = maxBounceCount;
				lightningOrb.speed = glaiveTravelSpeed;
				lightningOrb.bouncedObjects = new List<HealthComponent>();
				lightningOrb.range = glaiveBounceRange;
				lightningOrb.damageCoefficientPerBounce = damageCoefficientPerBounce;
				HurtBox hurtBox = initialOrbTarget;
				if ((bool)hurtBox)
				{
					hasSuccessfullyThrownGlaive = true;
					Transform transform = childLocator.FindChild("HandR");
					EffectManager.SimpleMuzzleFlash(muzzleFlashPrefab, base.gameObject, "HandR", transmit: true);
					lightningOrb.origin = transform.position;
					lightningOrb.target = hurtBox;
					OrbManager.instance.AddOrb(lightningOrb);
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			writer.Write(HurtBoxReference.FromHurtBox(initialOrbTarget));
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			initialOrbTarget = reader.ReadHurtBoxReference().ResolveHurtBox();
		}
	}
}
namespace EntityStates.HermitCrab
{
	public class Burrowed : BaseState
	{
		public static float mortarCooldown;

		public float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", "Burrowed", 0.1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				if (base.inputBank.moveVector.sqrMagnitude > 0.1f)
				{
					outer.SetNextState(new BurrowOut());
				}
				if (base.fixedAge >= duration && base.inputBank.skill1.down)
				{
					outer.SetNextState(new FireMortar());
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class BurrowIn : BaseState
	{
		public static GameObject burrowPrefab;

		public static float baseDuration;

		public static string burrowInSoundString;

		private float stopwatch;

		private float duration;

		private Transform modelTransform;

		private ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "BurrowIn", "BurrowIn.playbackRate", duration, 0.1f);
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			Util.PlaySound(burrowInSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				Burrowed nextState = new Burrowed();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class BurrowOut : BaseState
	{
		public static GameObject burrowPrefab;

		public static float baseDuration;

		public static string burrowOutSoundString;

		private float stopwatch;

		private Transform modelTransform;

		private ChildLocator childLocator;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "BurrowOut", "BurrowOut.playbackRate", duration, 0.1f);
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			Util.PlaySound(burrowOutSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireMortar : BaseState
	{
		public static GameObject mortarProjectilePrefab;

		public static GameObject mortarMuzzleflashEffect;

		public static int mortarCount;

		public static string mortarMuzzleName;

		public static string mortarSoundString;

		public static float mortarDamageCoefficient;

		public static float baseDuration;

		public static float timeToTarget = 3f;

		public static float projectileVelocity = 55f;

		public static float minimumDistance;

		private float stopwatch;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Gesture, Additive", "FireMortar", 0f);
			Util.PlaySound(mortarSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(mortarMuzzleflashEffect, base.gameObject, mortarMuzzleName, transmit: false);
			if (base.isAuthority)
			{
				Fire();
			}
		}

		private void Fire()
		{
			Ray aimRay = GetAimRay();
			Ray ray = new Ray(aimRay.origin, UnityEngine.Vector3.up);
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.RefreshCandidates();
			HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
			bool flag = false;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			RaycastHit hitInfo;
			if ((bool)hurtBox)
			{
				vector = hurtBox.transform.position;
				flag = true;
			}
			else if (Physics.Raycast(aimRay, out hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
			{
				vector = hitInfo.point;
				flag = true;
			}
			float magnitude = projectileVelocity;
			if (flag)
			{
				UnityEngine.Vector3 vector2 = vector - ray.origin;
				UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z);
				float magnitude2 = vector3.magnitude;
				UnityEngine.Vector2 vector4 = vector3 / magnitude2;
				if (magnitude2 < minimumDistance)
				{
					magnitude2 = minimumDistance;
				}
				float y = Trajectory.CalculateInitialYSpeed(timeToTarget, vector2.y);
				float num = magnitude2 / timeToTarget;
				UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * num, y, vector4.y * num);
				magnitude = direction.magnitude;
				ray.direction = direction;
			}
			for (int i = 0; i < mortarCount; i++)
			{
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(ray.direction + ((i != 0) ? (UnityEngine.Random.insideUnitSphere * 0.05f) : UnityEngine.Vector3.zero));
				ProjectileManager.instance.FireProjectile(mortarProjectilePrefab, ray.origin, rotation, base.gameObject, damageStat * mortarDamageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, magnitude);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch > duration)
			{
				Burrowed burrowed = new Burrowed();
				burrowed.duration = Burrowed.mortarCooldown;
				outer.SetNextState(burrowed);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : BaseState
	{
		private float stopwatch;

		public static GameObject burrowPrefab;

		public static float duration = 4f;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, "BurrowCenter", transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Heretic
{
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		public static GameObject effectPrefab;

		public static Material overlayMaterial;

		public static float overlayDuration;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			EffectManager.SimpleEffect(effectPrefab, base.characterBody.corePosition, UnityEngine.Quaternion.identity, transmit: false);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				CharacterModel component = modelTransform.GetComponent<CharacterModel>();
				if ((bool)component && (bool)overlayMaterial)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(component.gameObject);
					temporaryOverlayInstance.duration = overlayDuration;
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = overlayMaterial;
					temporaryOverlayInstance.inspectorCharacterModel = component;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.animateShaderAlpha = true;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class SpawnOnNewStageState : SpawnState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			outer.SetNextStateToMain();
		}
	}
}
namespace EntityStates.Heretic.Weapon
{
	public class Squawk : EntityState
	{
		[SerializeField]
		public string soundName;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(soundName, base.gameObject);
			outer.SetNextStateToMain();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Headstompers
{
	public class BaseHeadstompersState : EntityState
	{
		private static readonly List<BaseHeadstompersState> instancesList = new List<BaseHeadstompersState>();

		protected NetworkedBodyAttachment networkedBodyAttachment;

		protected GameObject bodyGameObject;

		protected CharacterBody body;

		protected CharacterMotor bodyMotor;

		protected InputBankTest bodyInputBank;

		protected bool jumpButtonDown
		{
			get
			{
				if ((bool)bodyInputBank)
				{
					return bodyInputBank.jump.down;
				}
				return false;
			}
		}

		protected bool slamButtonDown
		{
			get
			{
				if ((bool)bodyInputBank)
				{
					return bodyInputBank.interact.down;
				}
				return false;
			}
		}

		protected bool isGrounded
		{
			get
			{
				if ((bool)bodyMotor)
				{
					return bodyMotor.isGrounded;
				}
				return false;
			}
		}

		public static BaseHeadstompersState FindForBody(CharacterBody body)
		{
			for (int i = 0; i < instancesList.Count; i++)
			{
				if ((object)instancesList[i].body == body)
				{
					return instancesList[i];
				}
			}
			return null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			instancesList.Add(this);
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
			if ((bool)networkedBodyAttachment)
			{
				bodyGameObject = networkedBodyAttachment.attachedBodyObject;
				body = networkedBodyAttachment.attachedBody;
				if ((bool)bodyGameObject)
				{
					bodyMotor = bodyGameObject.GetComponent<CharacterMotor>();
					bodyInputBank = bodyGameObject.GetComponent<InputBankTest>();
				}
			}
		}

		public override void OnExit()
		{
			instancesList.Remove(this);
			base.OnExit();
		}

		protected bool ReturnToIdleIfGroundedAuthority()
		{
			if ((bool)bodyMotor && bodyMotor.isGrounded)
			{
				outer.SetNextState(new HeadstompersIdle());
				return true;
			}
			return false;
		}
	}
	public class HeadstompersIdle : BaseHeadstompersState
	{
		private float inputStopwatch;

		public static float inputConfirmationDelay = 0.1f;

		private bool jumpBoostOk;

		public static GameObject jumpEffect;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				FixedUpdateAuthority();
			}
		}

		private void FixedUpdateAuthority()
		{
			inputStopwatch = (base.slamButtonDown ? (inputStopwatch + GetDeltaTime()) : 0f);
			if (base.isGrounded)
			{
				jumpBoostOk = true;
			}
			else if (jumpBoostOk && base.jumpButtonDown && (bool)bodyMotor)
			{
				UnityEngine.Vector3 velocity = bodyMotor.velocity;
				if (velocity.y > 0f)
				{
					velocity.y *= 2f;
					bodyMotor.velocity = velocity;
					jumpBoostOk = false;
				}
				EffectManager.SimpleImpactEffect(jumpEffect, bodyGameObject.transform.position, UnityEngine.Vector3.up, transmit: true);
			}
			if (inputStopwatch >= inputConfirmationDelay && !base.isGrounded)
			{
				outer.SetNextState(new HeadstompersCharge());
			}
		}
	}
	public class HeadstompersCharge : BaseHeadstompersState
	{
		private float inputStopwatch;

		public static float maxChargeDuration = 0.5f;

		public static float minVelocityY = 1f;

		public static float accelerationY = 10f;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				FixedUpdateAuthority();
			}
		}

		private void FixedUpdateAuthority()
		{
			if (ReturnToIdleIfGroundedAuthority())
			{
				return;
			}
			inputStopwatch = (base.slamButtonDown ? (inputStopwatch + Time.deltaTime) : 0f);
			if (inputStopwatch >= maxChargeDuration)
			{
				outer.SetNextState(new HeadstompersFall());
			}
			else if (!base.slamButtonDown)
			{
				outer.SetNextState(new HeadstompersIdle());
			}
			else if ((bool)bodyMotor)
			{
				UnityEngine.Vector3 velocity = bodyMotor.velocity;
				if (velocity.y < minVelocityY)
				{
					velocity.y = Mathf.MoveTowards(velocity.y, minVelocityY, accelerationY * Time.deltaTime);
					bodyMotor.velocity = velocity;
				}
			}
		}
	}
	public class HeadstompersFall : BaseHeadstompersState
	{
		private float stopwatch;

		public static float maxFallDuration = 0f;

		public static float maxFallSpeed = 30f;

		public static float maxDistance = 30f;

		public static float initialFallSpeed = 10f;

		public static float accelerationY = 40f;

		public static float minimumRadius = 5f;

		public static float maximumRadius = 100f;

		public static float minimumDamageCoefficient = 10f;

		public static float maximumDamageCoefficient = 100f;

		public static float seekCone = 20f;

		public static float springboardSpeed = 30f;

		private Transform seekTransform;

		private bool seekLost;

		private CharacterMotor onHitGroundProvider;

		private float initialY;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.isAuthority)
			{
				return;
			}
			if ((bool)body)
			{
				TeamMask allButNeutral = TeamMask.allButNeutral;
				TeamIndex objectTeam = TeamComponent.GetObjectTeam(bodyGameObject);
				if (objectTeam != TeamIndex.None)
				{
					allButNeutral.RemoveTeam(objectTeam);
				}
				BullseyeSearch obj = new BullseyeSearch
				{
					filterByLoS = true,
					maxDistanceFilter = 300f,
					maxAngleFilter = seekCone,
					searchOrigin = body.footPosition,
					searchDirection = UnityEngine.Vector3.down,
					sortMode = BullseyeSearch.SortMode.Angle,
					teamMaskFilter = allButNeutral,
					viewer = body
				};
				initialY = body.footPosition.y;
				obj.RefreshCandidates();
				seekTransform = obj.GetResults().FirstOrDefault()?.transform;
			}
			SetOnHitGroundProviderAuthority(bodyMotor);
			if ((bool)bodyMotor)
			{
				bodyMotor.velocity.y = Mathf.Min(bodyMotor.velocity.y, 0f - initialFallSpeed);
			}
		}

		private void SetOnHitGroundProviderAuthority(CharacterMotor newOnHitGroundProvider)
		{
			if ((object)onHitGroundProvider != null)
			{
				onHitGroundProvider.onHitGroundAuthority -= OnMotorHitGroundAuthority;
			}
			onHitGroundProvider = newOnHitGroundProvider;
			if ((object)onHitGroundProvider != null)
			{
				onHitGroundProvider.onHitGroundAuthority += OnMotorHitGroundAuthority;
			}
		}

		public override void OnExit()
		{
			SetOnHitGroundProviderAuthority(null);
			base.OnExit();
		}

		private void OnMotorHitGroundAuthority(ref CharacterMotor.HitGroundInfo hitGroundInfo)
		{
			DoStompExplosionAuthority();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				FixedUpdateAuthority();
			}
		}

		private void FixedUpdateAuthority()
		{
			stopwatch += Time.deltaTime;
			if (base.isGrounded)
			{
				DoStompExplosionAuthority();
			}
			else if (stopwatch >= maxFallDuration)
			{
				outer.SetNextState(new HeadstompersCooldown());
			}
			else
			{
				if (!bodyMotor)
				{
					return;
				}
				UnityEngine.Vector3 velocity = bodyMotor.velocity;
				if (velocity.y > 0f - maxFallSpeed)
				{
					velocity.y = Mathf.MoveTowards(velocity.y, 0f - maxFallSpeed, accelerationY * Time.deltaTime);
				}
				if ((bool)seekTransform && !seekLost)
				{
					UnityEngine.Vector3 normalized = (seekTransform.position - body.footPosition).normalized;
					if (UnityEngine.Vector3.Dot(UnityEngine.Vector3.down, normalized) >= Mathf.Cos(seekCone * (MathF.PI / 180f)))
					{
						if (velocity.y < 0f)
						{
							UnityEngine.Vector3 vector = normalized * (0f - velocity.y);
							vector.y = 0f;
							UnityEngine.Vector3 vector2 = velocity;
							vector2.y = 0f;
							vector2 = vector;
							velocity.x = vector2.x;
							velocity.z = vector2.z;
						}
					}
					else
					{
						seekLost = true;
					}
				}
				bodyMotor.velocity = velocity;
			}
		}

		private void DoStompExplosionAuthority()
		{
			if ((bool)body)
			{
				RoR2.Inventory inventory = body.inventory;
				if (((!inventory || inventory.GetItemCount(RoR2Content.Items.FallBoots) != 0) ? 1 : 0) > (false ? 1 : 0))
				{
					bodyMotor.velocity = UnityEngine.Vector3.zero;
					float num = Mathf.Max(0f, initialY - body.footPosition.y);
					if (num > 0f)
					{
						float t = Mathf.InverseLerp(0f, maxDistance, num);
						float num2 = Mathf.Lerp(minimumDamageCoefficient, maximumDamageCoefficient, t);
						float num3 = Mathf.Lerp(minimumRadius, maximumRadius, t);
						BlastAttack obj = new BlastAttack
						{
							attacker = body.gameObject,
							inflictor = body.gameObject
						};
						obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
						obj.position = body.footPosition;
						obj.procCoefficient = 1f;
						obj.radius = num3;
						obj.baseForce = 200f * num2;
						obj.bonusForce = UnityEngine.Vector3.up * 2000f;
						obj.baseDamage = body.damage * num2;
						obj.falloffModel = BlastAttack.FalloffModel.SweetSpot;
						obj.crit = Util.CheckRoll(body.crit, body.master);
						obj.damageColorIndex = DamageColorIndex.Item;
						obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
						obj.Fire();
						EffectData effectData = new EffectData();
						effectData.origin = body.footPosition;
						effectData.scale = num3;
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/BootShockwave"), effectData, transmit: true);
					}
				}
			}
			SetOnHitGroundProviderAuthority(null);
			outer.SetNextState(new HeadstompersCooldown());
		}
	}
	public class HeadstompersCooldown : BaseHeadstompersState
	{
		public static float baseDuration = 10f;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			if ((bool)body)
			{
				RoR2.Inventory inventory = body.inventory;
				int num = ((!inventory) ? 1 : inventory.GetItemCount(RoR2Content.Items.FallBoots));
				if (num > 0)
				{
					duration /= num;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				FixedUpdateAuthority();
			}
		}

		private void FixedUpdateAuthority()
		{
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new HeadstompersIdle());
			}
		}
	}
}
namespace EntityStates.HAND
{
	public class Overclock : BaseState
	{
		public static float baseDuration = 0.25f;

		public static GameObject healEffectPrefab;

		public static float healPercentage = 0.15f;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				_ = (bool)base.characterBody;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > baseDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.HAND.Weapon
{
	public class ChargeSlam : BaseState
	{
		public static float baseDuration = 3.5f;

		private float duration;

		private Animator modelAnimator;

		private static int ChargeSlamStateHash = Animator.StringToHash("ChargeSlam");

		private static int ChargeSlamParamHash = Animator.StringToHash("ChargeSlam.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", ChargeSlamStateHash, ChargeSlamParamHash, duration);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(4f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.characterMotor.isGrounded && base.isAuthority)
			{
				outer.SetNextState(new Slam());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireWinch : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float duration = 2f;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public override void OnEnter()
		{
			base.OnEnter();
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			string muzzleName = "WinchHole";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration / attackSpeedStat && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FullSwing : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float returnToIdlePercentage;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float radius = 3f;

		public static GameObject hitEffectPrefab;

		public static GameObject swingEffectPrefab;

		private Transform hammerChildTransform;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private bool hasSwung;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Hammer");
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					hammerChildTransform = component.FindChild("SwingCenter");
				}
			}
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Gesture");
				if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("FullSwing3") || modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("FullSwing1"))
				{
					PlayCrossfade("Gesture", "FullSwing2", "FullSwing.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f);
				}
				else if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("FullSwing2"))
				{
					PlayCrossfade("Gesture", "FullSwing3", "FullSwing.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f);
				}
				else
				{
					PlayCrossfade("Gesture", "FullSwing1", "FullSwing.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f);
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Hammer.hitBoxActive") > 0.5f)
			{
				if (!hasSwung)
				{
					EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true);
					hasSwung = true;
				}
				attack.forceVector = hammerChildTransform.right * (0f - forceMagnitude);
				attack.Fire();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		private static void PullEnemies(UnityEngine.Vector3 position, UnityEngine.Vector3 direction, float coneAngle, float maxDistance, float force, TeamIndex excludedTeam)
		{
			float num = Mathf.Cos(coneAngle * 0.5f * (MathF.PI / 180f));
			Collider[] colliders;
			int num2 = HGPhysics.OverlapSphere(out colliders, position, maxDistance);
			for (int i = 0; i < num2; i++)
			{
				Collider collider = colliders[i];
				UnityEngine.Vector3 position2 = collider.transform.position;
				UnityEngine.Vector3 normalized = (position - position2).normalized;
				if (!(UnityEngine.Vector3.Dot(-normalized, direction) >= num))
				{
					continue;
				}
				TeamIndex teamIndex = TeamIndex.Neutral;
				TeamComponent component = collider.GetComponent<TeamComponent>();
				if (!component)
				{
					continue;
				}
				teamIndex = component.teamIndex;
				if (teamIndex != excludedTeam)
				{
					CharacterMotor component2 = collider.GetComponent<CharacterMotor>();
					if ((bool)component2)
					{
						component2.ApplyForce(normalized * force);
					}
					Rigidbody component3 = collider.GetComponent<Rigidbody>();
					if ((bool)component3)
					{
						component3.AddForce(normalized * force, ForceMode.Impulse);
					}
				}
			}
			HGPhysics.ReturnResults(colliders);
		}
	}
	public class Slam : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float returnToIdlePercentage;

		public static float impactDamageCoefficient = 2f;

		public static float earthquakeDamageCoefficient = 2f;

		public static float forceMagnitude = 16f;

		public static float radius = 3f;

		public static GameObject hitEffectPrefab;

		public static GameObject swingEffectPrefab;

		public static GameObject projectilePrefab;

		private Transform hammerChildTransform;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private bool hasSwung;

		private static int SlamStateHash = Animator.StringToHash("Slam");

		private static int SlamParamHash = Animator.StringToHash("Slam.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = impactDamageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Hammer");
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					hammerChildTransform = component.FindChild("SwingCenter");
				}
			}
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", SlamStateHash, SlamParamHash, duration);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Hammer.hitBoxActive") > 0.5f)
			{
				if (!hasSwung)
				{
					Ray aimRay = GetAimRay();
					EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true);
					ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * earthquakeDamageCoefficient, forceMagnitude, Util.CheckRoll(critStat, base.characterBody.master));
					hasSwung = true;
				}
				attack.forceVector = hammerChildTransform.right;
				attack.Fire();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.Halcyonite
{
	public class ChargeTriLaser : BaseState
	{
		public static float baseDuration = 3f;

		public static float laserMaxWidth = 0.2f;

		public static GameObject effectPrefab;

		public static GameObject laserPrefab;

		public static string attackSoundString;

		private float duration;

		private uint chargePlayID;

		private GameObject chargeEffect;

		private GameObject laserEffect;

		private LineRenderer laserLineComponent;

		private UnityEngine.Vector3 laserDirection;

		private UnityEngine.Vector3 visualEndPosition;

		private float flashTimer;

		private bool laserOn;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("FullBody Override", "TriLaserEnter", "TriLaser.playbackRate", duration, 0.1f);
			Transform modelTransform = GetModelTransform();
			chargePlayID = Util.PlayAttackSpeedSound("Play_halcyonite_skill2_chargeup", base.gameObject, attackSpeedStat);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleLaser");
					if ((bool)transform)
					{
						if ((bool)effectPrefab)
						{
							chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
							chargeEffect.transform.parent = transform;
							ScaleParticleSystemDuration component2 = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
							if ((bool)component2)
							{
								component2.newDuration = duration;
							}
						}
						if ((bool)laserPrefab)
						{
							laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation);
							laserEffect.transform.parent = transform;
							laserLineComponent = laserEffect.GetComponent<LineRenderer>();
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
			flashTimer = 0f;
			laserOn = true;
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(chargePlayID);
			base.OnExit();
			if ((bool)chargeEffect)
			{
				EntityState.Destroy(chargeEffect);
			}
			if ((bool)laserEffect)
			{
				EntityState.Destroy(laserEffect);
			}
			PlayAnimation("FullBody Override", "BufferEmpty");
		}

		public override void Update()
		{
			base.Update();
			if (!laserEffect || !laserLineComponent)
			{
				return;
			}
			float num = 1000f;
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 position = laserEffect.transform.parent.position;
			UnityEngine.Vector3 point = aimRay.GetPoint(num);
			laserDirection = point - position;
			if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask))
			{
				point = hitInfo.point;
			}
			laserLineComponent.SetPosition(0, position);
			laserLineComponent.SetPosition(1, point);
			float num2;
			if (duration - base.age > 0.5f)
			{
				num2 = base.age / duration;
			}
			else
			{
				flashTimer -= Time.deltaTime;
				if (flashTimer <= 0f)
				{
					laserOn = !laserOn;
					flashTimer = 1f / 30f;
				}
				num2 = (laserOn ? 1f : 0f);
			}
			num2 *= laserMaxWidth;
			laserLineComponent.startWidth = num2;
			laserLineComponent.endWidth = num2;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				TriLaser triLaser = new TriLaser();
				triLaser.laserDirection = laserDirection;
				outer.SetNextState(triLaser);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public override void OnEnter()
		{
			base.OnEnter();
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				component.FindChild("ChestGlow").transform.gameObject.GetComponent<ParticleSystem>().Stop();
			}
		}
	}
	public class GoldenSlash : BasicMeleeAttack
	{
		[SerializeField]
		public GameObject swordPrefab;

		protected override void PlayAnimation()
		{
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component && (bool)swordPrefab)
			{
				int childIndex = component.FindChildIndex("SwordPoint");
				EffectData effectData = new EffectData();
				effectData.origin = base.characterBody.transform.position;
				effectData.rotation = Util.QuaternionSafeLookRotation(base.characterBody.transform.forward);
				effectData.SetChildLocatorTransformReference(base.characterBody.transform.gameObject, childIndex);
				EffectManager.SpawnEffect(swordPrefab, effectData, transmit: true);
			}
			PlayCrossfade("FullBody Override", "GoldenSlash", "GoldenSlash.playbackRate", duration, 0.1f);
		}

		public override void OnExit()
		{
			PlayAnimation("FullBody Override", "BufferEmpty");
			base.OnExit();
		}
	}
	public class GoldenSwipe : BasicMeleeAttack
	{
		[SerializeField]
		public GameObject swordPrefab;

		protected override void PlayAnimation()
		{
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component && (bool)swordPrefab)
			{
				int childIndex = component.FindChildIndex("SwordPoint");
				EffectData effectData = new EffectData();
				effectData.origin = base.characterBody.transform.position;
				effectData.rotation = Util.QuaternionSafeLookRotation(base.characterBody.transform.forward);
				effectData.SetChildLocatorTransformReference(base.characterBody.transform.gameObject, childIndex);
				EffectManager.SpawnEffect(swordPrefab, effectData, transmit: true);
			}
			PlayCrossfade("FullBody Override", "GoldenSwipe", "GoldenSwipe.playbackRate", duration, 0.1f);
		}

		public override void OnExit()
		{
			PlayAnimation("FullBody Override", "BufferEmpty");
			base.OnExit();
		}
	}
	public class SpawnState : EntityState
	{
		public static float duration = 2f;

		public static float startingPrintHeight;

		public static float maxPrintHeight;

		public static float startingPrintBias;

		public static float maxPrintBias;

		public static string spawnSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			base.gameObject.GetComponent<CharacterBody>();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", "Spawn", "Spawn.playbackRate", duration);
			PrintController printController = GetModelTransform().gameObject.AddComponent<PrintController>();
			printController.printTime = duration;
			printController.enabled = true;
			printController.startingPrintHeight = startingPrintHeight;
			printController.maxPrintHeight = maxPrintHeight;
			printController.startingPrintBias = startingPrintBias;
			printController.maxPrintBias = maxPrintBias;
			printController.disableWhenFinished = true;
			printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class TriLaser : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float blastRadius;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public static string attackSoundString;

		public UnityEngine.Vector3 laserDirection;

		private float duration;

		private Ray modifiedAimRay;

		public float fireBeamTimer = 0.5f;

		private int timesFired;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireBeamTimer += Time.deltaTime;
			if (timesFired < 3 && fireBeamTimer > 0.5f)
			{
				FireTriLaser();
				fireBeamTimer = 0f;
				timesFired++;
			}
			if (base.fixedAge >= duration && timesFired > 2 && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireTriLaser()
		{
			duration = baseDuration / attackSpeedStat;
			modifiedAimRay = GetAimRay();
			modifiedAimRay.direction = laserDirection;
			GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			Util.PlaySound(attackSoundString, base.gameObject);
			string text = "MuzzleLaser";
			Util.PlaySound("Play_halcyonite_skill2_shoot", base.gameObject);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
			PlayCrossfade("FullBody Override", "TriLaserFire", "TriLaser.playbackRate", duration * 0.5f, 0.1f);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false);
			}
			if (!base.isAuthority)
			{
				return;
			}
			float num = 1000f;
			UnityEngine.Vector3 vector = modifiedAimRay.origin + modifiedAimRay.direction * num;
			if (Physics.Raycast(modifiedAimRay, out var hitInfo, num, LayerIndex.CommonMasks.laser))
			{
				vector = hitInfo.point;
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.inflictor = base.gameObject;
			blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
			blastAttack.baseDamage = damageStat * damageCoefficient;
			blastAttack.baseForce = force * 0.2f;
			blastAttack.position = vector;
			blastAttack.radius = blastRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot;
			blastAttack.bonusForce = force * modifiedAimRay.direction;
			blastAttack.Fire();
			_ = modifiedAimRay.origin;
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				int childIndex = component.FindChildIndex(text);
				if ((bool)tracerEffectPrefab)
				{
					EffectData effectData = new EffectData
					{
						origin = vector,
						start = modifiedAimRay.origin
					};
					effectData.SetChildLocatorTransformReference(base.gameObject, childIndex);
					EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
					EffectManager.SpawnEffect(hitEffectPrefab, effectData, transmit: true);
				}
			}
		}

		public override void OnExit()
		{
			PlayCrossfade("FullBody Override", "TriLaserExit", "TriLaser.playbackRate", duration, 0.1f);
			base.OnExit();
		}
	}
	public class WhirlwindRush : BaseState
	{
		public static float chargeMovementSpeedCoefficient;

		public static float turnSpeed;

		public static float turnSmoothTime;

		public static float damageCoefficient;

		public static GameObject hitEffectPrefab;

		private Animator animator;

		private UnityEngine.Vector3 targetMoveVector;

		private UnityEngine.Vector3 targetMoveVectorVelocity;

		private HitBoxGroup hitboxGroup;

		private ChildLocator childLocator;

		[SerializeField]
		public float spinUpDuration = 1f;

		[SerializeField]
		public float duration = 2f;

		[SerializeField]
		public float endSpinDuration = 1f;

		[SerializeField]
		public GameObject projectilePrefab;

		private bool firedWhirlWind;

		private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed");

		private float originalMoveSpeed = 6.6f;

		private float originalAccSpeed = 40f;

		[SerializeField]
		public float rushingMoveSpeed = 13.5f;

		[SerializeField]
		public float rushingAccSpeed = 200f;

		private UnityEngine.Vector3 safePosition;

		private float ageStartedWhirlwind;

		private float intervalToCheckForSafePath = 1f;

		public override void OnEnter()
		{
			originalMoveSpeed = base.characterBody.baseMoveSpeed;
			originalAccSpeed = base.characterBody.baseAcceleration;
			base.characterBody.baseMoveSpeed = 0.5f;
			base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
			safePosition = base.characterBody.corePosition;
			animator = GetModelAnimator();
			childLocator = animator.GetComponent<ChildLocator>();
			PlayCrossfade("FullBody Override", "WhirlwindRushEnter", "WhirlwindRush.playbackRate", duration, 0.1f);
			Util.PlaySound("Play_halcyonite_skill3_start", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			bool stopWhirlwind = base.fixedAge > duration + spinUpDuration + endSpinDuration;
			if (base.fixedAge > spinUpDuration * 0.5f && !firedWhirlWind)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
				firedWhirlWind = true;
				Util.PlaySound("Play_halcyonite_skill3_loop", base.gameObject);
			}
			if (firedWhirlWind && !stopWhirlwind)
			{
				if (base.fixedAge - ageStartedWhirlwind > intervalToCheckForSafePath)
				{
					HandleIdentifySafePathForward(ref stopWhirlwind);
				}
				else
				{
					HandleProceedAlongPath(ref stopWhirlwind);
				}
			}
			if (base.fixedAge > duration + spinUpDuration && !stopWhirlwind)
			{
				base.characterBody.baseMoveSpeed = 0f;
				if ((bool)base.characterMotor)
				{
					base.characterMotor.walkSpeedPenaltyCoefficient = 0f;
				}
				if ((bool)base.characterBody)
				{
					base.characterBody.isSprinting = false;
				}
				if ((bool)base.characterDirection)
				{
					base.characterDirection.moveVector = base.characterDirection.forward;
				}
				if ((bool)base.rigidbodyMotor)
				{
					base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
				}
			}
			if (stopWhirlwind)
			{
				base.characterBody.baseMoveSpeed = originalMoveSpeed;
				base.characterBody.baseAcceleration = originalAccSpeed;
				if ((bool)base.characterMotor)
				{
					base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
				}
				if ((bool)base.characterBody)
				{
					base.characterBody.isSprinting = false;
				}
				if ((bool)base.characterDirection)
				{
					base.characterDirection.moveVector = base.characterDirection.forward;
				}
				if ((bool)base.rigidbodyMotor)
				{
					base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
				}
				Util.PlaySound("Stop_halcyonite_skill3_loop", base.gameObject);
				outer.SetNextStateToMain();
			}
		}

		private void HandleIdentifySafePathForward(ref bool stopWhirlwind)
		{
			UnityEngine.Vector3 vector = base.inputBank.aimDirection * rushingMoveSpeed * GetDeltaTime();
			vector.y = 0f;
			vector += base.characterBody.aimOrigin;
			UnityEngine.Debug.DrawLine(base.characterBody.aimOrigin, base.characterBody.aimOrigin + UnityEngine.Vector3.right, UnityEngine.Color.grey, 10f);
			UnityEngine.Debug.DrawRay(vector + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down, UnityEngine.Color.green, 10f);
			UnityEngine.Debug.DrawLine(vector + UnityEngine.Vector3.up * 2f, vector + UnityEngine.Vector3.up * 2f + UnityEngine.Vector3.up * -10f, UnityEngine.Color.yellow, 10f);
			if (!Physics.Raycast(new Ray(vector + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down), out var _, 10f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault, QueryTriggerInteraction.Ignore))
			{
				stopWhirlwind = true;
			}
			else
			{
				ageStartedWhirlwind = base.fixedAge;
			}
		}

		private void HandleProceedAlongPath(ref bool stopWhirlwind)
		{
			if (!base.characterMotor.isGrounded)
			{
				TeleportHelper.TeleportBody(base.characterBody, safePosition);
				stopWhirlwind = true;
			}
			else
			{
				safePosition = base.characterBody.footPosition;
			}
			targetMoveVector = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Vector3.SmoothDamp(targetMoveVector, base.inputBank.aimDirection, ref targetMoveVectorVelocity, turnSmoothTime, turnSpeed), UnityEngine.Vector3.up).normalized;
			base.characterDirection.moveVector = targetMoveVector;
			UnityEngine.Vector3 forward = base.characterDirection.forward;
			float value = moveSpeedStat * chargeMovementSpeedCoefficient;
			base.characterMotor.moveDirection = forward * chargeMovementSpeedCoefficient;
			animator.SetFloat(forwardSpeedParamHash, value);
			base.characterBody.baseMoveSpeed = rushingMoveSpeed;
			base.characterBody.baseAcceleration = rushingAccSpeed;
		}

		public override void OnExit()
		{
			base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
			PlayCrossfade("FullBody Override", "WhirlwindRushExit", "WhirlwindRush.playbackRate", duration, 0.1f);
			Util.PlaySound("Play_halcyonite_skill3_end", base.gameObject);
			Util.PlaySound("Stop_halcyonite_skill3_loop", base.gameObject);
			base.characterBody.RecalculateStats();
			base.OnExit();
		}
	}
}
namespace EntityStates.Gup
{
	public class GupSpikesState : BasicMeleeAttack
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string playbackRateParam;

		[SerializeField]
		public float crossfadeDuration;

		[SerializeField]
		public string initialHitboxActiveParameter;

		[SerializeField]
		public string initialHitboxName;

		private HitBox initialHitBox;

		public override void OnEnter()
		{
			base.OnEnter();
			StartAimMode(0f);
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
			if (!hitBoxGroup)
			{
				return;
			}
			HitBox[] hitBoxes = hitBoxGroup.hitBoxes;
			foreach (HitBox hitBox in hitBoxes)
			{
				if (hitBox.gameObject.name == initialHitboxName)
				{
					initialHitBox = hitBox;
					break;
				}
			}
		}

		protected override void PlayAnimation()
		{
			PlayCrossfade(animationLayerName, animationStateName, playbackRateParam, duration, crossfadeDuration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)initialHitBox)
			{
				initialHitBox.enabled = animator.GetFloat(initialHitboxActiveParameter) > 0.5f;
			}
		}
	}
	internal class SpawnState : GenericCharacterSpawnState
	{
		public static GameObject spawnEffectPrefab;

		public static string spawnEffectMuzzle;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData
				{
					origin = FindModelChild(spawnEffectMuzzle).position,
					scale = base.characterBody.radius
				}, transmit: true);
			}
		}
	}
	public class BaseSplitDeath : GenericCharacterDeath
	{
		[SerializeField]
		public CharacterSpawnCard characterSpawnCard;

		[SerializeField]
		public int spawnCount;

		[SerializeField]
		public float deathDelay;

		[SerializeField]
		public float moneyMultiplier;

		public static float spawnRadiusCoefficient = 0.5f;

		public static GameObject deathEffectPrefab;

		private bool hasDied;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!(base.fixedAge > deathDelay) || hasDied)
			{
				return;
			}
			hasDied = true;
			if (NetworkServer.active)
			{
				EffectManager.SpawnEffect(deathEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = base.characterBody.radius
				}, transmit: true);
				if ((bool)characterSpawnCard && spawnCount > 0 && (ulong)(base.healthComponent.killingDamageType & (DamageType.VoidDeath | DamageType.OutOfBounds)) == 0L)
				{
					BodySplitter bodySplitter = new BodySplitter();
					bodySplitter.body = base.characterBody;
					bodySplitter.masterSummon.masterPrefab = characterSpawnCard.prefab;
					bodySplitter.count = spawnCount;
					bodySplitter.splinterInitialVelocityLocal = new UnityEngine.Vector3(0f, 20f, 10f);
					bodySplitter.minSpawnCircleRadius = base.characterBody.radius * spawnRadiusCoefficient;
					bodySplitter.moneyMultiplier = moneyMultiplier;
					bodySplitter.Perform();
				}
				DestroyBodyAsapServer();
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class GupDeath : BaseSplitDeath
	{
	}
	public class GeepDeath : BaseSplitDeath
	{
	}
	public class GipDeath : BaseSplitDeath
	{
	}
}
namespace EntityStates.GummyClone
{
	public class GummyCloneDeathState : BaseState
	{
		[SerializeField]
		public string soundString;

		[SerializeField]
		public GameObject effectPrefab;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(soundString, base.gameObject);
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if (base.isAuthority && (bool)effectPrefab)
			{
				EffectManager.SimpleImpactEffect(effectPrefab, base.transform.position, UnityEngine.Vector3.up, transmit: true);
			}
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class GummyCloneSpawnState : BaseState
	{
		[SerializeField]
		public float duration = 4f;

		[SerializeField]
		public string soundString;

		[SerializeField]
		public float initialDelay;

		[SerializeField]
		public GameObject effectPrefab;

		private bool hasFinished;

		private Animator modelAnimator;

		private CharacterModel characterModel;

		private CameraTargetParams.AimRequest aimRequest;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			if ((bool)modelAnimator)
			{
				GameObject gameObject = modelAnimator.gameObject;
				characterModel = gameObject.GetComponent<CharacterModel>();
				characterModel.invisibilityCount++;
			}
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (!hasFinished)
			{
				characterModel.invisibilityCount--;
			}
			aimRequest?.Dispose();
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
				base.characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 3f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= initialDelay && !hasFinished)
			{
				hasFinished = true;
				characterModel.invisibilityCount--;
				duration = initialDelay;
				if ((bool)effectPrefab)
				{
					EffectManager.SimpleEffect(effectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: false);
				}
				Util.PlaySound(soundString, base.gameObject);
			}
			if (base.fixedAge >= duration && hasFinished && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.ArchWispMonster
{
	public class ChargeCannons : EntityStates.GreaterWispMonster.ChargeCannons
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireCannons nextState = new FireCannons();
				outer.SetNextState(nextState);
			}
		}
	}
	public class FireCannons : EntityStates.GreaterWispMonster.FireCannons
	{
	}
	public class DeathState : EntityStates.GreaterWispMonster.DeathState
	{
	}
}
namespace EntityStates.GreaterWispMonster
{
	public class ChargeCannons : BaseState
	{
		[SerializeField]
		public float baseDuration = 3f;

		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public string attackString;

		protected float duration;

		private GameObject chargeEffectLeft;

		private GameObject chargeEffectRight;

		private const float soundDuration = 2f;

		private uint soundID;

		private EffectManagerHelper _emh_chargeEffectLeft;

		private EffectManagerHelper _emh_chargeEffectRight;

		private static int ChargeCannonsStateHash = Animator.StringToHash("ChargeCannons");

		private static int ChargeCannonsParamHash = Animator.StringToHash("ChargeCannons.playbackRate");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffectLeft = null;
			chargeEffectRight = null;
			_emh_chargeEffectLeft = null;
			_emh_chargeEffectRight = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			soundID = Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat * (2f / baseDuration));
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			GetModelAnimator();
			PlayAnimation("Gesture", ChargeCannonsStateHash, ChargeCannonsParamHash, duration);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component && (bool)effectPrefab)
				{
					Transform transform = component.FindChild("MuzzleLeft");
					Transform transform2 = component.FindChild("MuzzleRight");
					if ((bool)transform)
					{
						if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
						{
							chargeEffectLeft = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeEffectLeft = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation);
							chargeEffectLeft = _emh_chargeEffectLeft.gameObject;
						}
						chargeEffectLeft.transform.parent = transform;
						ScaleParticleSystemDuration component2 = chargeEffectLeft.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = duration;
						}
					}
					if ((bool)transform2)
					{
						if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
						{
							chargeEffectRight = UnityEngine.Object.Instantiate(effectPrefab, transform2.position, transform2.rotation);
						}
						else
						{
							_emh_chargeEffectRight = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform2.position, transform2.rotation);
							chargeEffectRight = _emh_chargeEffectRight.gameObject;
						}
						chargeEffectRight.transform.parent = transform2;
						ScaleParticleSystemDuration component3 = chargeEffectRight.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component3)
						{
							component3.newDuration = duration;
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void OnExit()
		{
			if (base.fixedAge < duration - 0.1f)
			{
				AkSoundEngine.StopPlayingID(soundID);
			}
			PlayAnimation("Gesture", EmptyStateHash);
			if (_emh_chargeEffectLeft != null && _emh_chargeEffectLeft.OwningPool != null)
			{
				_emh_chargeEffectLeft.OwningPool.ReturnObject(_emh_chargeEffectLeft);
			}
			else
			{
				EntityState.Destroy(chargeEffectLeft);
			}
			chargeEffectLeft = null;
			_emh_chargeEffectLeft = null;
			if (_emh_chargeEffectRight != null && _emh_chargeEffectRight.OwningPool != null)
			{
				_emh_chargeEffectRight.OwningPool.ReturnObject(_emh_chargeEffectRight);
			}
			else
			{
				EntityState.Destroy(chargeEffectRight);
			}
			chargeEffectRight = null;
			_emh_chargeEffectRight = null;
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireCannons nextState = new FireCannons();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireCannons : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject effectPrefab;

		public static float baseDuration = 2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		private float duration;

		private static int FireCannonsStateHash = Animator.StringToHash("FireCannons");

		private static int FireCannonsParamHash = Animator.StringToHash("FireCannons.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Ray aimRay = GetAimRay();
			string text = "MuzzleLeft";
			string text2 = "MuzzleRight";
			duration = baseDuration / attackSpeedStat;
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false);
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text2, transmit: false);
			}
			PlayAnimation("Gesture", FireCannonsStateHash, FireCannonsParamHash, duration);
			if (!base.isAuthority || !base.modelLocator || !base.modelLocator.modelTransform)
			{
				return;
			}
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				int childIndex = component.FindChildIndex(text);
				int childIndex2 = component.FindChildIndex(text2);
				Transform transform = component.FindChild(childIndex);
				Transform transform2 = component.FindChild(childIndex2);
				if ((bool)transform)
				{
					ProjectileManager.instance.FireProjectile(projectilePrefab, transform.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
				}
				if ((bool)transform2)
				{
					ProjectileManager.instance.FireProjectile(projectilePrefab, transform2.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		[SerializeField]
		public GameObject initialEffect;

		[SerializeField]
		public GameObject deathEffect;

		private static float duration = 2f;

		private GameObject initialEffectInstance;

		private bool spawnedEffect;

		private EffectData _effectData;

		protected EffectManagerHelper _efh_initializeEffectInstance;

		public override void Reset()
		{
			base.Reset();
			initialEffectInstance = null;
			spawnedEffect = false;
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			_efh_initializeEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.modelLocator)
			{
				return;
			}
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("Mask");
			transform.gameObject.SetActive(value: true);
			transform.GetComponent<AnimateShaderAlpha>().timeMax = duration;
			if ((bool)initialEffect)
			{
				if (!EffectManager.ShouldUsePooledEffect(initialEffect))
				{
					initialEffectInstance = UnityEngine.Object.Instantiate(initialEffect, transform.position, transform.rotation, transform);
					return;
				}
				_efh_initializeEffectInstance = EffectManager.GetAndActivatePooledEffect(initialEffect, transform.position, transform.rotation);
				initialEffectInstance = _efh_initializeEffectInstance.gameObject;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && NetworkServer.active && (bool)deathEffect && !spawnedEffect)
			{
				spawnedEffect = true;
				if (_effectData == null)
				{
					_effectData = new EffectData();
				}
				_effectData.origin = base.transform.position;
				EffectManager.SpawnEffect(deathEffect, _effectData, transmit: true);
				if (base.isAuthority)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			UnityEngine.Debug.LogError("gwisp death onexit");
			EntityState.Destroy(base.gameObject);
			if (!initialEffectInstance)
			{
				return;
			}
			if (!EffectManager.UsePools)
			{
				EntityState.Destroy(initialEffectInstance);
				return;
			}
			if (_efh_initializeEffectInstance != null && _efh_initializeEffectInstance.OwningPool != null)
			{
				_efh_initializeEffectInstance.OwningPool.ReturnObject(_efh_initializeEffectInstance);
			}
			else
			{
				if (_efh_initializeEffectInstance != null)
				{
					UnityEngine.Debug.LogFormat("GreaterWispDeathState has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID());
				}
				EntityState.Destroy(initialEffectInstance);
			}
			initialEffectInstance = null;
			_efh_initializeEffectInstance = null;
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.GravekeeperMonster.Weapon
{
	public class GravekeeperBarrage : BaseState
	{
		private float stopwatch;

		private float missileStopwatch;

		public static float baseDuration;

		public static string muzzleString;

		public static float missileSpawnFrequency;

		public static float missileSpawnDelay;

		public static float missileForce;

		public static float damageCoefficient;

		public static float maxSpread;

		public static GameObject projectilePrefab;

		public static GameObject muzzleflashPrefab;

		public static string jarEffectChildLocatorString;

		public static string jarOpenSoundString;

		public static string jarCloseSoundString;

		public static GameObject jarOpenEffectPrefab;

		public static GameObject jarCloseEffectPrefab;

		private ChildLocator childLocator;

		private static int BeginGravekeeperBarrageStateHash = Animator.StringToHash("BeginGravekeeperBarrage");

		private static int EndGravekeeperBarrageStateHash = Animator.StringToHash("EndGravekeeperBarrage");

		public override void OnEnter()
		{
			base.OnEnter();
			missileStopwatch -= missileSpawnDelay;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				if ((bool)childLocator)
				{
					childLocator.FindChild("JarEffectLoop").gameObject.SetActive(value: true);
				}
			}
			PlayAnimation("Jar, Override", BeginGravekeeperBarrageStateHash);
			EffectManager.SimpleMuzzleFlash(jarOpenEffectPrefab, base.gameObject, jarEffectChildLocatorString, transmit: false);
			Util.PlaySound(jarOpenSoundString, base.gameObject);
			base.characterBody.SetAimTimer(baseDuration + 2f);
		}

		private void FireBlob(Ray projectileRay, float bonusPitch, float bonusYaw)
		{
			projectileRay.direction = Util.ApplySpread(projectileRay.direction, 0f, maxSpread, 1f, 1f, bonusYaw, bonusPitch);
			EffectManager.SimpleMuzzleFlash(muzzleflashPrefab, base.gameObject, muzzleString, transmit: false);
			if (NetworkServer.active)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, projectileRay.origin, Util.QuaternionSafeLookRotation(projectileRay.direction), base.gameObject, damageStat * damageCoefficient, missileForce, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			PlayCrossfade("Jar, Override", EndGravekeeperBarrageStateHash, 0.06f);
			EffectManager.SimpleMuzzleFlash(jarCloseEffectPrefab, base.gameObject, jarEffectChildLocatorString, transmit: false);
			Util.PlaySound(jarCloseSoundString, base.gameObject);
			if ((bool)childLocator)
			{
				childLocator.FindChild("JarEffectLoop").gameObject.SetActive(value: false);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			stopwatch += deltaTime;
			missileStopwatch += deltaTime;
			if (missileStopwatch >= 1f / missileSpawnFrequency)
			{
				missileStopwatch -= 1f / missileSpawnFrequency;
				Transform transform = childLocator.FindChild(muzzleString);
				if ((bool)transform)
				{
					Ray projectileRay = default(Ray);
					projectileRay.origin = transform.position;
					projectileRay.direction = GetAimRay().direction;
					float maxDistance = 1000f;
					if (Physics.Raycast(GetAimRay(), out var hitInfo, maxDistance, LayerIndex.world.mask))
					{
						projectileRay.direction = hitInfo.point - transform.position;
					}
					FireBlob(projectileRay, 0f, 0f);
				}
			}
			if (stopwatch >= baseDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.GravekeeperBoss
{
	public class FireHook : BaseState
	{
		public static float baseDuration = 3f;

		public static string soundString;

		public static string muzzleString;

		public static float projectileDamageCoefficient;

		public static GameObject muzzleflashEffectPrefab;

		public static GameObject projectilePrefab;

		public static float spread;

		public static int projectileCount;

		public static float projectileForce;

		private float duration;

		private Animator modelAnimator;

		public override void OnEnter()
		{
			base.OnEnter();
			base.fixedAge = 0f;
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayCrossfade("Body", "FireHook", "FireHook.playbackRate", duration, 0.03f);
			}
			ChildLocator component = modelAnimator.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				component.FindChild(muzzleString);
			}
			Util.PlayAttackSpeedSound(soundString, base.gameObject, attackSpeedStat);
			EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
			Ray aimRay = GetAimRay();
			if (NetworkServer.active)
			{
				FireSingleHook(aimRay, 0f, 0f);
				for (int i = 0; i < projectileCount; i++)
				{
					float bonusPitch = UnityEngine.Random.Range(0f - spread, spread) / 2f;
					float bonusYaw = UnityEngine.Random.Range(0f - spread, spread) / 2f;
					FireSingleHook(aimRay, bonusPitch, bonusYaw);
				}
			}
		}

		private void FireSingleHook(Ray aimRay, float bonusPitch, float bonusYaw)
		{
			UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, bonusYaw, bonusPitch);
			ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * projectileDamageCoefficient, projectileForce, Util.CheckRoll(critStat, base.characterBody.master));
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class PrepHook : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargeEffectPrefab;

		public static string muzzleString;

		public static string attackString;

		private float duration;

		private GameObject chargeInstance;

		private Animator modelAnimator;

		private EffectManagerHelper _emh_chargeInstance;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeInstance = null;
			modelAnimator = null;
			_emh_chargeInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			base.fixedAge = 0f;
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayCrossfade("Body", "PrepHook", "PrepHook.playbackRate", duration, 0.5f);
				modelAnimator.GetComponent<AimAnimator>().enabled = true;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.inputBank.aimDirection;
			}
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(muzzleString);
					if ((bool)transform && (bool)chargeEffectPrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
						{
							chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
							chargeInstance = _emh_chargeInstance.gameObject;
						}
						chargeInstance.transform.parent = transform;
						ScaleParticleSystemDuration component2 = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = duration;
						}
					}
				}
			}
			Util.PlayAttackSpeedSound(attackString, base.gameObject, attackSpeedStat);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireHook());
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeInstance)
			{
				if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null)
				{
					_emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance);
				}
				else
				{
					EntityState.Destroy(chargeInstance);
				}
				chargeInstance = null;
				_emh_chargeInstance = null;
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "Root", transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.GrandParentSun
{
	public abstract class GrandParentSunBase : BaseState
	{
		[SerializeField]
		public GameObject enterEffectPrefab;

		protected GrandParentSunController sunController { get; private set; }

		protected Transform vfxRoot { get; private set; }

		protected virtual bool shouldEnableSunController => false;

		protected abstract float desiredVfxScale { get; }

		public override void OnEnter()
		{
			base.OnEnter();
			sunController = GetComponent<GrandParentSunController>();
			sunController.enabled = shouldEnableSunController;
			vfxRoot = base.transform.Find("VfxRoot");
			if ((bool)enterEffectPrefab)
			{
				EffectManager.SimpleImpactEffect(enterEffectPrefab, vfxRoot.position, UnityEngine.Vector3.up, transmit: false);
			}
			SetVfxScale(desiredVfxScale);
		}

		public override void Update()
		{
			base.Update();
			SetVfxScale(desiredVfxScale);
		}

		private void SetVfxScale(float newScale)
		{
			newScale = Mathf.Max(newScale, 0.01f);
			if ((bool)vfxRoot && vfxRoot.transform.localScale.x != newScale)
			{
				vfxRoot.transform.localScale = new UnityEngine.Vector3(newScale, newScale, newScale);
			}
		}
	}
	public class GrandParentSunDeath : GrandParentSunBase
	{
		public static float baseDuration;

		private float duration;

		protected override float desiredVfxScale => 1f - Mathf.Clamp01(base.age / duration);

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				NetworkServer.Destroy(base.gameObject);
			}
		}
	}
	public class GrandParentSunMain : GrandParentSunBase
	{
		private GenericOwnership ownership;

		protected override bool shouldEnableSunController => true;

		protected override float desiredVfxScale => 1f;

		public override void OnEnter()
		{
			base.OnEnter();
			ownership = GetComponent<GenericOwnership>();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && !ownership.ownerObject)
			{
				outer.SetNextState(new GrandParentSunDeath());
			}
		}
	}
	public class GrandParentSunSpawn : GrandParentSunBase
	{
		public static float baseDuration;

		private float duration;

		protected override float desiredVfxScale => Mathf.Clamp01(base.age / duration);

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new GrandParentSunMain());
			}
		}
	}
}
namespace EntityStates.GrandParentBoss
{
	public class DeathState : EntityStates.ParentMonster.DeathState
	{
	}
	public class FireSecondaryProjectile : BaseState
	{
		[SerializeField]
		public float baseDuration = 3f;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleEffectPrefab;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public string muzzleName = "SecondaryProjectileMuzzle";

		[SerializeField]
		public string animationStateName = "FireSecondaryProjectile";

		[SerializeField]
		public string playbackRateParam = "FireSecondaryProjectile.playbackRate";

		[SerializeField]
		public string animationLayerName = "Body";

		[SerializeField]
		public float baseFireDelay;

		private float duration;

		private float fireDelay;

		private bool hasFired;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			fireDelay = baseFireDelay / attackSpeedStat;
			if (fireDelay <= Time.fixedDeltaTime * 2f)
			{
				Fire();
			}
			PlayCrossfade(animationLayerName, animationStateName, playbackRateParam, duration, 0.2f);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!hasFired && base.fixedAge >= fireDelay)
			{
				Fire();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void Fire()
		{
			hasFired = true;
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (!base.isAuthority || !projectilePrefab)
			{
				return;
			}
			Ray aimRay = GetAimRay();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					aimRay.origin = component.FindChild(muzzleName).transform.position;
				}
			}
			ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
		}
	}
	public class GroundSwipe : BasicMeleeAttack, SteppedSkillDef.IStepSetter
	{
		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float baseChargeStartDelay;

		[SerializeField]
		public float baseFireProjectileDelay;

		[SerializeField]
		public float projectileDamageCoefficient;

		[SerializeField]
		public float projectileForce;

		[SerializeField]
		public float maxBullseyeDistance;

		[SerializeField]
		public float maxBullseyeAngle;

		[SerializeField]
		public float minProjectileDistance;

		[SerializeField]
		public float maxProjectileDistance;

		[SerializeField]
		public float projectileHorizontalSpeed;

		[SerializeField]
		public string chargeSoundName;

		[SerializeField]
		public string hitBoxGroupNameLeft;

		[SerializeField]
		public string animationLayerName = "Body";

		[SerializeField]
		public string muzzleNameLeft = "SecondaryProjectileMuzzle";

		[SerializeField]
		public string muzzleNameRight = "SecondaryProjectileMuzzle";

		[SerializeField]
		public string animationStateNameLeft = "FireSecondaryProjectile";

		[SerializeField]
		public string animationStateNameRight = "FireSecondaryProjectile";

		[SerializeField]
		public string playbackRateParam = "GroundSwipe.playbackRate";

		private GameObject chargeEffectInstance;

		private bool hasFired;

		private float chargeStartDelay;

		private float fireProjectileDelay;

		private int step;

		protected ChildLocator childLocator { get; private set; }

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			step = i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			hasFired = false;
			chargeStartDelay = baseChargeStartDelay / attackSpeedStat;
			fireProjectileDelay = baseFireProjectileDelay / attackSpeedStat;
			childLocator = GetModelChildLocator();
		}

		public override void OnExit()
		{
			EntityState.Destroy(chargeEffectInstance);
			base.OnExit();
		}

		protected override void PlayAnimation()
		{
			PlayCrossfade(animationLayerName, GetAnimationStateName(), playbackRateParam, duration, 1f);
		}

		public string GetMuzzleName()
		{
			if (step % 2 == 0)
			{
				return muzzleNameLeft;
			}
			return muzzleNameRight;
		}

		public string GetAnimationStateName()
		{
			if (step % 2 == 0)
			{
				return animationStateNameLeft;
			}
			return animationStateNameRight;
		}

		public override string GetHitBoxGroupName()
		{
			if (step % 2 == 0)
			{
				return hitBoxGroupNameLeft;
			}
			return hitBoxGroupName;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!chargeEffectInstance && (bool)childLocator && base.fixedAge >= chargeStartDelay)
			{
				Transform transform = childLocator.FindChild(GetMuzzleName()) ?? base.characterBody.coreTransform;
				if ((bool)transform)
				{
					if ((bool)chargeEffectPrefab)
					{
						chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
						chargeEffectInstance.transform.parent = transform;
						ScaleParticleSystemDuration component = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
						ObjectScaleCurve component2 = chargeEffectInstance.GetComponent<ObjectScaleCurve>();
						if ((bool)component)
						{
							component.newDuration = duration;
						}
						if ((bool)component2)
						{
							component2.timeMax = duration;
						}
					}
					if (chargeSoundName != null)
					{
						Util.PlaySound(chargeSoundName, base.gameObject);
					}
				}
			}
			if (base.isAuthority && !hasFired && (bool)projectilePrefab && base.fixedAge >= fireProjectileDelay)
			{
				hasFired = true;
				Ray aimRay = GetAimRay();
				Ray ray = aimRay;
				Transform transform2 = childLocator.FindChild(GetMuzzleName());
				if ((bool)transform2)
				{
					ray.origin = transform2.position;
				}
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.viewer = base.characterBody;
				bullseyeSearch.searchOrigin = base.characterBody.corePosition;
				bullseyeSearch.searchDirection = base.characterBody.corePosition;
				bullseyeSearch.maxDistanceFilter = maxBullseyeDistance;
				bullseyeSearch.maxAngleFilter = maxBullseyeAngle;
				bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam());
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
				bullseyeSearch.RefreshCandidates();
				HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
				UnityEngine.Vector3? vector = null;
				RaycastHit hitInfo;
				if ((bool)hurtBox)
				{
					vector = hurtBox.transform.position;
				}
				else if (Physics.Raycast(aimRay, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					vector = hitInfo.point;
				}
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = ray.origin;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * projectileDamageCoefficient;
				fireProjectileInfo.force = projectileForce;
				fireProjectileInfo.crit = RollCrit();
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				if (vector.HasValue)
				{
					UnityEngine.Vector3 vector2 = vector.Value - ray.origin;
					UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z);
					float magnitude = vector3.magnitude;
					UnityEngine.Vector2 vector4 = vector3 / magnitude;
					magnitude = Mathf.Clamp(magnitude, minProjectileDistance, maxProjectileDistance);
					float y = Trajectory.CalculateInitialYSpeed(magnitude / projectileHorizontalSpeed, vector2.y);
					UnityEngine.Vector3 direction = new UnityEngine.Vector3(vector4.x * projectileHorizontalSpeed, y, vector4.y * projectileHorizontalSpeed);
					fireProjectileInfo2.speedOverride = direction.magnitude;
					ray.direction = direction;
				}
				else
				{
					fireProjectileInfo2.speedOverride = projectileHorizontalSpeed;
				}
				fireProjectileInfo2.rotation = Util.QuaternionSafeLookRotation(ray.direction);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
		}
	}
	public class Offspring : BaseState
	{
		[SerializeField]
		public GameObject SpawnerPodsPrefab;

		public static float randomRadius = 8f;

		public static float maxRange = 9999f;

		private Animator animator;

		private ChildLocator childLocator;

		private Transform modelTransform;

		private float duration;

		public static float baseDuration = 3.5f;

		public static string attackSoundString;

		private float summonInterval;

		private static float summonDuration = 3.26f;

		public static int maxSummonCount = 5;

		private float summonTimer;

		private bool isSummoning;

		private int summonCount;

		public static GameObject spawnEffect;

		private static int SpawnPodWarnStateHash = Animator.StringToHash("SpawnPodWarn");

		private static int SpawnPodWarnParamHash = Animator.StringToHash("spawnPodWarn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			duration = baseDuration;
			Util.PlaySound(attackSoundString, base.gameObject);
			summonInterval = summonDuration / (float)maxSummonCount;
			isSummoning = true;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (isSummoning)
			{
				summonTimer += GetDeltaTime();
				if (NetworkServer.active && summonTimer > 0f && summonCount < maxSummonCount)
				{
					summonCount++;
					summonTimer -= summonInterval;
					SpawnPods();
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void SpawnPods()
		{
			UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
			Ray aimRay = GetAimRay();
			aimRay.origin += UnityEngine.Random.insideUnitSphere * randomRadius;
			if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask))
			{
				zero = hitInfo.point;
			}
			zero = base.transform.position;
			Transform transform = FindTargetFarthest(zero, GetTeam());
			if ((bool)transform)
			{
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/CharacterSpawnCards/cscParentPod"), new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Approximate,
					minDistance = 3f,
					maxDistance = 20f,
					spawnOnTarget = transform
				}, RoR2Application.rng);
				directorSpawnRequest.summonerBodyObject = base.gameObject;
				directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult spawnResult)
				{
					RoR2.Inventory inventory = spawnResult.spawnedInstance.GetComponent<CharacterMaster>().inventory;
					RoR2.Inventory inventory2 = base.characterBody.inventory;
					inventory.CopyEquipmentFrom(inventory2);
				});
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
				PlayAnimation("Body", SpawnPodWarnStateHash, SpawnPodWarnParamHash, duration);
			}
		}

		private Transform FindTargetFarthest(UnityEngine.Vector3 point, TeamIndex myTeam)
		{
			float num = 0f;
			Transform result = null;
			TeamMask enemyTeams = TeamMask.GetEnemyTeams(myTeam);
			for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
			{
				if (!enemyTeams.HasTeam(teamIndex))
				{
					ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
					for (int i = 0; i < teamMembers.Count; i++)
					{
						float num2 = UnityEngine.Vector3.Magnitude(teamMembers[i].transform.position - point);
						if (num2 > num && num2 < maxRange)
						{
							num = num2;
							result = teamMembers[i].transform;
						}
					}
				}
			}
			return result;
		}
	}
	public class PortalFist : BaseState
	{
		public static float baseDuration;

		public static GameObject portalInEffectPrefab;

		public static GameObject portalOutEffectPrefab;

		public static string portalMuzzleString;

		public static string fistMeshChildLocatorString;

		public static string fistBoneChildLocatorString;

		public static string mecanimFistVisibilityString;

		public static float fistOverlayDuration;

		public static Material fistOverlayMaterial;

		public static float targetSearchMaxDistance;

		private GameObject fistMeshGameObject;

		private GameObject fistBoneGameObject;

		private GameObject fistTargetGameObject;

		private string fistTargetMuzzleString;

		private Animator modelAnimator;

		private CharacterModel characterModel;

		private float duration;

		private bool fistWasOutOfPortal = true;

		public override void OnEnter()
		{
			base.OnEnter();
			fistMeshGameObject = FindModelChild(fistMeshChildLocatorString).gameObject;
			fistBoneGameObject = FindModelChild(fistBoneChildLocatorString).gameObject;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				characterModel = modelTransform.GetComponent<CharacterModel>();
			}
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "PortalFist", "PortalFist.playbackRate", duration, 0.3f);
			Transform transform = FindModelChild("PortalFistTargetRig");
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.viewer = base.characterBody;
			bullseyeSearch.searchOrigin = base.characterBody.corePosition;
			bullseyeSearch.searchDirection = base.characterBody.corePosition;
			bullseyeSearch.maxDistanceFilter = targetSearchMaxDistance;
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam());
			bullseyeSearch.teamMaskFilter.RemoveTeam(TeamIndex.Neutral);
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
			bullseyeSearch.RefreshCandidates();
			HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
			if ((bool)hurtBox)
			{
				transform.position = hurtBox.transform.position;
				fistTargetMuzzleString = $"PortalFistTargetPosition{UnityEngine.Random.Range(1, 5).ToString()}";
				fistTargetGameObject = FindModelChild(fistTargetMuzzleString).gameObject;
			}
		}

		public override void Update()
		{
			base.Update();
			bool flag = modelAnimator.GetFloat(mecanimFistVisibilityString) > 0.5f;
			if (flag != fistWasOutOfPortal)
			{
				fistWasOutOfPortal = flag;
				EffectManager.SimpleMuzzleFlash(flag ? portalOutEffectPrefab : portalInEffectPrefab, base.gameObject, portalMuzzleString, transmit: false);
				EffectManager.SimpleMuzzleFlash(flag ? portalOutEffectPrefab : portalInEffectPrefab, base.gameObject, fistTargetMuzzleString, transmit: false);
				if ((bool)characterModel && (bool)fistOverlayMaterial)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(characterModel.gameObject);
					temporaryOverlayInstance.duration = fistOverlayDuration;
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = fistOverlayMaterial;
					temporaryOverlayInstance.inspectorCharacterModel = characterModel;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.animateShaderAlpha = true;
				}
			}
			if ((bool)fistTargetGameObject && !flag)
			{
				fistBoneGameObject.transform.SetPositionAndRotation(fistTargetGameObject.transform.position, fistTargetGameObject.transform.rotation);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class PortalJump : BaseState
	{
		private BullseyeSearch enemyFinder;

		public static float duration = 3f;

		public static float retreatDuration = 2.433f;

		public static float emergeDuration = 2.933f;

		public static float portalScaleDuration = 2f;

		public static float effectsDuration = 2f;

		private bool retreatDone;

		private bool teleported;

		private bool canMoveDuringTeleport;

		private bool hasEmerged;

		private HurtBox foundBullseye;

		public static float telezoneRadius;

		public static float skillDistance = 2000f;

		private float stopwatch;

		private UnityEngine.Vector3 destinationPressence = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 startPressence = UnityEngine.Vector3.zero;

		private Transform modelTransform;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		public static GameObject jumpInEffectPrefab;

		public static GameObject jumpOutEffectPrefab;

		public static UnityEngine.Vector3 teleportOffset;

		private GrandparentEnergyFXController FXController;

		private static int RetreatStateHash = Animator.StringToHash("Retreat");

		private static int RetreatParamHash = Animator.StringToHash("retreat.playbackRate");

		private static int EmergeStateHash = Animator.StringToHash("Emerge");

		private static int EmergeParamHash = Animator.StringToHash("emerge.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
				PlayAnimation("Body", RetreatStateHash, RetreatParamHash, retreatDuration);
				EffectData effectData = new EffectData
				{
					origin = base.characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("Portal").position
				};
				EffectManager.SpawnEffect(jumpInEffectPrefab, effectData, transmit: true);
			}
			FXController = base.characterBody.GetComponent<GrandparentEnergyFXController>();
			if ((bool)FXController)
			{
				FXController.portalObject = base.characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("Portal").GetComponentInChildren<EffectComponent>()
					.gameObject;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= retreatDuration && !retreatDone)
			{
				retreatDone = true;
				if ((bool)FXController)
				{
					ScaleObject(FXController.portalObject, scaleUp: false);
				}
			}
			if (stopwatch >= retreatDuration + portalScaleDuration && !teleported)
			{
				teleported = true;
				canMoveDuringTeleport = true;
				if ((bool)FXController)
				{
					FXController.portalObject.GetComponent<ObjectScaleCurve>().enabled = false;
				}
				DoTeleport();
			}
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			if (canMoveDuringTeleport)
			{
				SetPosition(UnityEngine.Vector3.Lerp(startPressence, destinationPressence, stopwatch / duration));
			}
			if (stopwatch >= retreatDuration + portalScaleDuration + duration && canMoveDuringTeleport)
			{
				canMoveDuringTeleport = false;
				if ((bool)FXController)
				{
					FXController.portalObject.transform.position = base.characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("Portal").position;
					ScaleObject(FXController.portalObject, scaleUp: true);
				}
			}
			if (stopwatch >= retreatDuration + portalScaleDuration * 2f + duration && !hasEmerged)
			{
				hasEmerged = true;
				if ((bool)FXController)
				{
					FXController.portalObject.GetComponent<ObjectScaleCurve>().enabled = false;
				}
				modelTransform = GetModelTransform();
				if ((bool)modelTransform)
				{
					PlayAnimation("Body", EmergeStateHash, EmergeParamHash, duration);
					EffectData effectData = new EffectData
					{
						origin = base.characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("Portal").position
					};
					EffectManager.SpawnEffect(jumpOutEffectPrefab, effectData, transmit: true);
					if ((bool)characterModel)
					{
						characterModel.invisibilityCount--;
					}
					if ((bool)hurtboxGroup)
					{
						HurtBoxGroup hurtBoxGroup = hurtboxGroup;
						int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
						hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
					}
					if ((bool)base.characterMotor)
					{
						base.characterMotor.enabled = true;
					}
				}
			}
			if (stopwatch >= retreatDuration + portalScaleDuration * 2f + duration + emergeDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void DoTeleport()
		{
			Ray aimRay = GetAimRay();
			enemyFinder = new BullseyeSearch();
			enemyFinder.maxDistanceFilter = skillDistance;
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.filterByLoS = false;
			enemyFinder.sortMode = BullseyeSearch.SortMode.Distance;
			enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			enemyFinder.RefreshCandidates();
			foundBullseye = enemyFinder.GetResults().LastOrDefault();
			modelTransform = GetModelTransform();
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
			UnityEngine.Vector3 vector = base.inputBank.moveVector * skillDistance;
			destinationPressence = base.transform.position;
			startPressence = base.transform.position;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			UnityEngine.Vector3 position = startPressence + vector;
			if ((bool)foundBullseye)
			{
				position = foundBullseye.transform.position;
			}
			NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(position, base.characterBody.hullClassification);
			groundNodes.GetNodePosition(nodeIndex, out destinationPressence);
			destinationPressence += base.transform.position - base.characterBody.footPosition;
		}

		private void SetPosition(UnityEngine.Vector3 newPosition)
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity);
			}
		}

		private void ScaleObject(GameObject objectToScaleDown, bool scaleUp)
		{
			float valueEnd = (scaleUp ? 1f : 0f);
			float valueStart = (scaleUp ? 0f : 1f);
			ObjectScaleCurve component = objectToScaleDown.GetComponent<ObjectScaleCurve>();
			component.timeMax = portalScaleDuration;
			component.curveX = AnimationCurve.Linear(0f, valueStart, 1f, valueEnd);
			component.curveY = AnimationCurve.Linear(0f, valueStart, 1f, valueEnd);
			component.curveZ = AnimationCurve.Linear(0f, valueStart, 1f, valueEnd);
			component.overallCurve = AnimationCurve.EaseInOut(0f, valueStart, 1f, valueEnd);
			component.enabled = true;
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
		public static GameObject preSpawnEffect;

		public static string preSpawnEffectMuzzle;

		public static float preSpawnDuration;

		public static GameObject spawnEffect;

		public static string spawnEffectMuzzle;

		public static Material spawnOverlayMaterial;

		public static float spawnOverlayDuration;

		public static float blastAttackRadius;

		public static float blastAttackForce;

		public static float blastAttackBonusForce;

		private bool hasSpawned;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private bool preSpawnIsDone;

		private static int Spawn1StateHash = Animator.StringToHash("Spawn1");

		private static int Spawn1ParamHash = Animator.StringToHash("Spawn1.playbackRate");

		private bool isInvisible;

		public override void OnEnter()
		{
			base.OnEnter();
			characterModel = base.modelLocator.modelTransform.GetComponent<CharacterModel>();
			hurtboxGroup = base.modelLocator.modelTransform.GetComponent<HurtBoxGroup>();
			ToggleInvisibility(newInvisible: true);
			if ((bool)preSpawnEffect)
			{
				EffectManager.SimpleMuzzleFlash(preSpawnEffect, base.gameObject, preSpawnEffectMuzzle, transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!preSpawnIsDone && base.fixedAge > preSpawnDuration)
			{
				preSpawnIsDone = true;
				ToggleInvisibility(newInvisible: false);
				PlayAnimation("Body", Spawn1StateHash, Spawn1ParamHash, duration - preSpawnDuration);
				if ((bool)spawnEffect)
				{
					EffectManager.SimpleMuzzleFlash(spawnEffect, base.gameObject, spawnEffectMuzzle, transmit: false);
				}
				if (base.isAuthority)
				{
					BlastAttack obj = new BlastAttack
					{
						attacker = base.gameObject,
						inflictor = base.gameObject
					};
					obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
					obj.position = base.characterBody.corePosition;
					obj.procCoefficient = 1f;
					obj.radius = blastAttackRadius;
					obj.baseForce = blastAttackForce;
					obj.bonusForce = UnityEngine.Vector3.up * blastAttackBonusForce;
					obj.baseDamage = 0f;
					obj.falloffModel = BlastAttack.FalloffModel.Linear;
					obj.damageColorIndex = DamageColorIndex.Item;
					obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
					obj.Fire();
				}
				if ((bool)characterModel && (bool)spawnOverlayMaterial)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(characterModel.gameObject);
					temporaryOverlayInstance.duration = spawnOverlayDuration;
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = spawnOverlayMaterial;
					temporaryOverlayInstance.inspectorCharacterModel = characterModel;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.animateShaderAlpha = true;
				}
			}
		}

		private void ToggleInvisibility(bool newInvisible)
		{
			if (isInvisible != newInvisible)
			{
				isInvisible = newInvisible;
				if ((bool)characterModel)
				{
					characterModel.invisibilityCount += (isInvisible ? 1 : (-1));
				}
				if ((bool)hurtboxGroup)
				{
					hurtboxGroup.hurtBoxesDeactivatorCounter += (isInvisible ? 1 : (-1));
				}
			}
		}

		public override void OnExit()
		{
			ToggleInvisibility(newInvisible: false);
			base.OnExit();
		}
	}
	public class SpiritPull : BaseState
	{
		private BullseyeSearch enemyFinder;

		public static float lockOnAngle;

		private UnityEngine.Vector3 teleporterIndicatorInstance;

		private Transform modelTransform;

		public static float pullTimer;

		public static float zoneRadius;

		public static float initialDelay;

		private float duration = 4f;

		public static float maxRange;

		public static string teleportZoneString;

		public static GameObject teleportZoneEffect;

		public static GameObject playerTeleportEffect;

		public static float effectsDuration = 2f;

		public static float playerTeleportEffectsDuration = 1f;

		private bool effectsDone;

		private bool gatheredVictims;

		private bool teleported;

		private float stopwatch;

		private List<UnityEngine.Vector3> Startpositions;

		private List<UnityEngine.Vector3> Endpositions;

		public static int stacks;

		private List<HurtBox> results = new List<HurtBox>();

		private HurtBox foundBullseye;

		private BullseyeSearch search;

		private GameObject spiritPullLocationObject;

		public static string indicatorOnPlayerSoundLoop;

		public static string indicatorOnPlayerSoundStop;

		public static string teleportedPlayerSound;

		public override void OnEnter()
		{
			base.OnEnter();
			Startpositions = new List<UnityEngine.Vector3>();
			Endpositions = new List<UnityEngine.Vector3>();
			Ray aimRay = GetAimRay();
			modelTransform = GetModelTransform();
			enemyFinder = new BullseyeSearch();
			enemyFinder.maxDistanceFilter = 2000f;
			enemyFinder.maxAngleFilter = lockOnAngle;
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.filterByLoS = false;
			enemyFinder.sortMode = BullseyeSearch.SortMode.Distance;
			enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			enemyFinder.RefreshCandidates();
			foundBullseye = enemyFinder.GetResults().LastOrDefault();
			_ = UnityEngine.Vector3.zero;
			if ((bool)foundBullseye)
			{
				teleporterIndicatorInstance = foundBullseye.transform.position;
				if (Physics.Raycast(teleporterIndicatorInstance, UnityEngine.Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask))
				{
					teleporterIndicatorInstance = hitInfo.point;
					_ = teleporterIndicatorInstance;
				}
				EffectData effectData = new EffectData
				{
					origin = teleporterIndicatorInstance,
					rotation = teleportZoneEffect.transform.rotation,
					scale = zoneRadius * 2f
				};
				EffectManager.SpawnEffect(teleportZoneEffect, effectData, transmit: true);
				if (spiritPullLocationObject == null)
				{
					spiritPullLocationObject = new GameObject();
				}
				spiritPullLocationObject.transform.position = effectData.origin;
				Util.PlaySound(indicatorOnPlayerSoundLoop, spiritPullLocationObject);
			}
		}

		private Transform FindTargetFarthest(UnityEngine.Vector3 point, TeamIndex enemyTeam)
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(enemyTeam);
			float num = 0f;
			Transform result = null;
			for (int i = 0; i < teamMembers.Count; i++)
			{
				float num2 = UnityEngine.Vector3.SqrMagnitude(teamMembers[i].transform.position - point);
				if (num2 > num && num2 < maxRange)
				{
					num = num2;
					result = teamMembers[i].transform;
				}
			}
			return result;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			pullTimer -= Time.deltaTime;
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= effectsDuration && !gatheredVictims)
			{
				effectsDone = true;
				gatheredVictims = true;
				GetPlayersInsideTeleportZone();
			}
			if (stopwatch >= effectsDuration + playerTeleportEffectsDuration && !teleported)
			{
				teleported = true;
				TeleportPlayers();
			}
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
			if (effectsDone)
			{
				SetPositions();
			}
			if (stopwatch >= effectsDuration + playerTeleportEffectsDuration + duration && base.isAuthority)
			{
				effectsDone = false;
				outer.SetNextStateToMain();
			}
		}

		private void GetPlayersInsideTeleportZone()
		{
			Startpositions.Clear();
			Endpositions.Clear();
			if (!foundBullseye)
			{
				return;
			}
			for (int i = 0; i < stacks; i++)
			{
				search = new BullseyeSearch();
				search.filterByLoS = false;
				search.maxDistanceFilter = zoneRadius;
				search.searchOrigin = new UnityEngine.Vector3(teleporterIndicatorInstance.x, teleporterIndicatorInstance.y + zoneRadius * (float)i, teleporterIndicatorInstance.z);
				search.sortMode = BullseyeSearch.SortMode.Distance;
				search.teamMaskFilter = TeamMask.allButNeutral;
				search.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
				search.RefreshCandidates();
				search.queryTriggerInteraction = QueryTriggerInteraction.Collide;
				for (int j = 0; j < search.GetResults().ToList().Count; j++)
				{
					if (!results.Contains(search.GetResults().ToList()[j]))
					{
						results.Add(search.GetResults().ToList()[j]);
					}
				}
			}
			if (results.Count <= 0)
			{
				return;
			}
			for (int k = 0; k < results.Count; k++)
			{
				HurtBox hurtBox = results[k];
				Transform transform = hurtBox.healthComponent.body.modelLocator.modelTransform;
				EffectData effectData = new EffectData
				{
					origin = hurtBox.healthComponent.body.footPosition
				};
				EffectManager.SpawnEffect(playerTeleportEffect, effectData, transmit: true);
				if ((bool)transform)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(transform.gameObject);
					temporaryOverlayInstance.duration = 0.6f;
					temporaryOverlayInstance.animateShaderAlpha = true;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matGrandparentTeleportFlash");
					temporaryOverlayInstance.AddToCharacterModel(transform.GetComponent<CharacterModel>());
				}
			}
		}

		private void TeleportPlayers()
		{
			if (results.Count <= 0)
			{
				return;
			}
			for (int i = 0; i < results.Count; i++)
			{
				HurtBox hurtBox = results[i];
				CharacterModel component = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent<CharacterModel>();
				HurtBoxGroup component2 = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent<HurtBoxGroup>();
				Startpositions.Add(hurtBox.transform.position);
				if ((bool)component2)
				{
					int hurtBoxesDeactivatorCounter = component2.hurtBoxesDeactivatorCounter + 1;
					component2.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
				if ((bool)component)
				{
					component.invisibilityCount++;
				}
				CharacterMotor component3 = hurtBox.healthComponent.gameObject.GetComponent<CharacterMotor>();
				if ((bool)component3)
				{
					component3.enabled = false;
				}
				duration = initialDelay;
				GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(base.gameObject);
				if ((bool)teleportEffectPrefab)
				{
					UnityEngine.Object.Instantiate(teleportEffectPrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity);
				}
				Util.PlaySound(teleportedPlayerSound, hurtBox.gameObject);
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				UnityEngine.Vector3 position = base.characterBody.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild(teleportZoneString).position;
				NodeGraph groundNodes = SceneInfo.instance.groundNodes;
				NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(position, base.characterBody.hullClassification);
				groundNodes.GetNodePosition(nodeIndex, out position);
				position += hurtBox.healthComponent.body.transform.position - hurtBox.healthComponent.body.footPosition;
				position = new UnityEngine.Vector3(position.x, position.y + 0.1f, position.z);
				Endpositions.Add(position);
			}
		}

		private void SetPositions()
		{
			if (results.Count <= 0)
			{
				return;
			}
			for (int i = 0; i < results.Count; i++)
			{
				CharacterMotor component = results[i].healthComponent.gameObject.GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					UnityEngine.Vector3 position = UnityEngine.Vector3.Lerp(Startpositions[i], Endpositions[i], stopwatch / duration);
					component.Motor.SetPositionAndRotation(position, UnityEngine.Quaternion.identity);
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			Util.PlaySound(indicatorOnPlayerSoundStop, spiritPullLocationObject);
			if (results.Count <= 0)
			{
				return;
			}
			for (int i = 0; i < results.Count; i++)
			{
				HurtBox hurtBox = results[i];
				CharacterModel component = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent<CharacterModel>();
				HurtBoxGroup component2 = hurtBox.healthComponent.body.modelLocator.modelTransform.GetComponent<HurtBoxGroup>();
				Transform transform = hurtBox.healthComponent.body.modelLocator.modelTransform;
				if ((bool)transform)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(transform.gameObject);
					temporaryOverlayInstance.duration = 0.6f;
					temporaryOverlayInstance.animateShaderAlpha = true;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matGrandparentTeleportFlash");
					temporaryOverlayInstance.AddToCharacterModel(transform.GetComponent<CharacterModel>());
				}
				EffectData effectData = new EffectData
				{
					origin = hurtBox.healthComponent.body.footPosition
				};
				EffectManager.SpawnEffect(playerTeleportEffect, effectData, transmit: true);
				if ((bool)component2)
				{
					int hurtBoxesDeactivatorCounter = component2.hurtBoxesDeactivatorCounter - 1;
					component2.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
				if ((bool)component)
				{
					component.invisibilityCount--;
				}
				CharacterMotor component3 = hurtBox.healthComponent.gameObject.GetComponent<CharacterMotor>();
				if ((bool)component3)
				{
					component3.enabled = true;
				}
			}
		}
	}
}
namespace EntityStates.GrandParent
{
	public class ChannelSun : ChannelSunBase
	{
		public static string animLayerName;

		public static string animStateName;

		public static GameObject sunPrefab;

		public static float sunPrefabDiameter = 10f;

		public static float sunPlacementMinDistance = 100f;

		public static float sunPlacementIdealAltitudeBonus = 200f;

		private GameObject sunInstance;

		public UnityEngine.Vector3? sunSpawnPosition;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation(animLayerName, animStateName);
			if (NetworkServer.active)
			{
				sunSpawnPosition = sunSpawnPosition ?? FindSunSpawnPosition(base.transform.position);
				if (sunSpawnPosition.HasValue)
				{
					sunInstance = CreateSun(sunSpawnPosition.Value);
				}
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active && (bool)sunInstance)
			{
				sunInstance.GetComponent<GenericOwnership>().ownerObject = null;
				sunInstance = null;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && !IsKeyDownAuthority())
			{
				outer.SetNextState(new ChannelSunEnd());
			}
		}

		private GameObject CreateSun(UnityEngine.Vector3 sunSpawnPosition)
		{
			GameObject obj = UnityEngine.Object.Instantiate(sunPrefab, sunSpawnPosition, UnityEngine.Quaternion.identity);
			obj.GetComponent<GenericOwnership>().ownerObject = base.gameObject;
			NetworkServer.Spawn(obj);
			return obj;
		}

		private static UnityEngine.Vector3? FindSunNodePosition(UnityEngine.Vector3 searchOrigin)
		{
			NodeGraph airNodes = SceneInfo.instance.airNodes;
			NodeGraph.NodeIndex nodeIndex = airNodes.FindClosestNodeWithFlagConditions(searchOrigin, HullClassification.Golem, NodeFlags.None, NodeFlags.None, preventOverhead: false);
			if (nodeIndex == NodeGraph.NodeIndex.invalid)
			{
				return null;
			}
			float num = sunPlacementMinDistance;
			float num2 = num * num;
			_ = NodeGraph.NodeIndex.invalid;
			float num3 = 0f;
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(airNodes, HullMask.Golem);
			nodeGraphSpider.AddNodeForNextStep(nodeIndex);
			int num4 = 0;
			int i = 0;
			while (nodeGraphSpider.PerformStep())
			{
				num4++;
				for (; i < nodeGraphSpider.collectedSteps.Count; i++)
				{
					NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[i];
					airNodes.GetNodePosition(stepInfo.node, out var position);
					float sqrMagnitude = (position - searchOrigin).sqrMagnitude;
					if (sqrMagnitude > num3)
					{
						num3 = sqrMagnitude;
						_ = stepInfo.node;
						if (num3 >= num2)
						{
							return position;
						}
					}
				}
			}
			return null;
		}

		public static UnityEngine.Vector3? FindSunSpawnPosition(UnityEngine.Vector3 searchOrigin)
		{
			UnityEngine.Vector3? vector = FindSunNodePosition(searchOrigin);
			if (vector.HasValue)
			{
				UnityEngine.Vector3 value = vector.Value;
				float num = sunPlacementIdealAltitudeBonus;
				float num2 = sunPrefabDiameter * 0.5f;
				if (Physics.Raycast(value, UnityEngine.Vector3.up, out var hitInfo, sunPlacementIdealAltitudeBonus + num2, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					num = Mathf.Clamp(hitInfo.distance - num2, 0f, num);
				}
				value.y += num;
				return value;
			}
			return null;
		}
	}
	public abstract class ChannelSunBase : BaseSkillState
	{
		[SerializeField]
		public GameObject handVfxPrefab;

		public static string leftHandVfxTargetNameInChildLocator;

		public static string rightHandVfxTargetNameInChildLocator;

		private GameObject leftHandVfxInstance;

		private GameObject rightHandVfxInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)handVfxPrefab)
			{
				ChildLocator modelChildLocator = GetModelChildLocator();
				if ((bool)modelChildLocator)
				{
					CreateVfxInstanceForHand(modelChildLocator, leftHandVfxTargetNameInChildLocator, ref leftHandVfxInstance);
					CreateVfxInstanceForHand(modelChildLocator, rightHandVfxTargetNameInChildLocator, ref rightHandVfxInstance);
				}
			}
		}

		public override void OnExit()
		{
			DestroyVfxInstance(ref leftHandVfxInstance);
			DestroyVfxInstance(ref rightHandVfxInstance);
			base.OnExit();
		}

		protected void CreateVfxInstanceForHand(ChildLocator childLocator, string nameInChildLocator, ref GameObject dest)
		{
			Transform transform = childLocator.FindChild(nameInChildLocator);
			if ((bool)transform)
			{
				dest = UnityEngine.Object.Instantiate(handVfxPrefab, transform);
			}
			else
			{
				dest = null;
			}
		}

		protected void DestroyVfxInstance(ref GameObject vfxInstance)
		{
			EntityState.Destroy(vfxInstance);
			vfxInstance = null;
		}
	}
	public class ChannelSunEnd : ChannelSunBase
	{
		public static string animLayerName;

		public static string animStateName;

		public static string animPlaybackRateParam;

		public static float baseDuration;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animLayerName, animStateName, animPlaybackRateParam, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class ChannelSunStart : ChannelSunBase
	{
		public static string animLayerName;

		public static string animStateName;

		public static string animPlaybackRateParam;

		public static string beginSoundName;

		public static float baseDuration;

		public static GameObject beamVfxPrefab;

		private float duration;

		private UnityEngine.Vector3? sunSpawnPosition;

		private ParticleSystem leftHandBeamParticleSystem;

		private ParticleSystem rightHandBeamParticleSystem;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation(animLayerName, animStateName, animPlaybackRateParam, duration);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = true;
				}
			}
			if (base.isAuthority)
			{
				sunSpawnPosition = sunSpawnPosition ?? ChannelSun.FindSunSpawnPosition(base.transform.position);
			}
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator && sunSpawnPosition.HasValue)
			{
				CreateBeamEffect(modelChildLocator, ChannelSunBase.leftHandVfxTargetNameInChildLocator, sunSpawnPosition.Value, ref leftHandBeamParticleSystem);
				CreateBeamEffect(modelChildLocator, ChannelSunBase.rightHandVfxTargetNameInChildLocator, sunSpawnPosition.Value, ref rightHandBeamParticleSystem);
			}
			if (beginSoundName != null)
			{
				Util.PlaySound(beginSoundName, base.gameObject);
			}
		}

		public override void OnExit()
		{
			EndBeamEffect(ref leftHandBeamParticleSystem);
			EndBeamEffect(ref rightHandBeamParticleSystem);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new ChannelSun
				{
					activatorSkillSlot = base.activatorSkillSlot,
					sunSpawnPosition = sunSpawnPosition
				});
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(sunSpawnPosition.HasValue);
			if (sunSpawnPosition.HasValue)
			{
				writer.Write(sunSpawnPosition.Value);
			}
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			sunSpawnPosition = null;
			if (reader.ReadBoolean())
			{
				sunSpawnPosition = reader.ReadVector3();
			}
		}

		private void CreateBeamEffect(ChildLocator childLocator, string nameInChildLocator, UnityEngine.Vector3 targetPosition, ref ParticleSystem dest)
		{
			Transform transform = childLocator.FindChild(nameInChildLocator);
			if ((bool)transform)
			{
				ChildLocator component = UnityEngine.Object.Instantiate(beamVfxPrefab, transform).GetComponent<ChildLocator>();
				component.FindChild("EndPoint").SetPositionAndRotation(targetPosition, UnityEngine.Quaternion.identity);
				Transform transform2 = component.FindChild("BeamParticles");
				dest = transform2.GetComponent<ParticleSystem>();
			}
			else
			{
				dest = null;
			}
		}

		private void EndBeamEffect(ref ParticleSystem particleSystem)
		{
			if ((bool)particleSystem)
			{
				ParticleSystem.MainModule main = particleSystem.main;
				main.loop = false;
				particleSystem.Stop();
			}
			particleSystem = null;
		}
	}
}
namespace EntityStates.TitanMonster
{
	public class ChargeGoldMegaLaser : ChargeMegaLaser
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireGoldMegaLaser nextState = new FireGoldMegaLaser();
				outer.SetNextState(nextState);
			}
		}
	}
	public class ChargeMegaLaser : BaseState
	{
		public static float baseDuration = 3f;

		public static float laserMaxWidth = 0.2f;

		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject laserPrefab;

		public static string chargeAttackSoundString;

		public static float lockOnAngle;

		private HurtBox lockedOnHurtBox;

		public float duration;

		private GameObject chargeEffect;

		private GameObject laserEffect;

		private LineRenderer laserLineComponent;

		private UnityEngine.Vector3 visualEndPosition;

		private float flashTimer;

		private bool laserOn;

		private BullseyeSearch enemyFinder;

		private const float originalSoundDuration = 2.1f;

		private EffectManagerHelper _emh_chargeEffect;

		private EffectManagerHelper _emh_laserEffect;

		public override void Reset()
		{
			base.Reset();
			lockedOnHurtBox = null;
			duration = 0f;
			chargeEffect = null;
			laserEffect = null;
			laserLineComponent = null;
			visualEndPosition = UnityEngine.Vector3.zero;
			flashTimer = 0f;
			laserOn = false;
			if (enemyFinder != null)
			{
				enemyFinder.Reset();
			}
			_emh_chargeEffect = null;
			_emh_laserEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(chargeAttackSoundString, base.gameObject, 2.1f / duration);
			Ray aimRay = GetAimRay();
			enemyFinder = new BullseyeSearch();
			enemyFinder.maxDistanceFilter = 2000f;
			enemyFinder.maxAngleFilter = lockOnAngle;
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.filterByLoS = false;
			enemyFinder.sortMode = BullseyeSearch.SortMode.Angle;
			enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleLaser");
					if ((bool)transform)
					{
						if ((bool)effectPrefab)
						{
							if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
							{
								chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
							}
							else
							{
								_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation);
								chargeEffect = _emh_chargeEffect.gameObject;
							}
							chargeEffect.transform.parent = transform;
							ScaleParticleSystemDuration component2 = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
							if ((bool)component2)
							{
								component2.newDuration = duration;
							}
						}
						if ((bool)laserPrefab)
						{
							if (!EffectManager.ShouldUsePooledEffect(laserPrefab))
							{
								laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation);
							}
							else
							{
								_emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserPrefab, transform.position, transform.rotation);
								laserEffect = _emh_laserEffect.gameObject;
							}
							laserEffect.transform.parent = transform;
							laserLineComponent = laserEffect.GetComponent<LineRenderer>();
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
			flashTimer = 0f;
			laserOn = true;
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeEffect)
			{
				if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffect);
				}
				_emh_chargeEffect = null;
				chargeEffect = null;
			}
			if ((bool)laserEffect)
			{
				if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null)
				{
					_emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect);
				}
				else
				{
					EntityState.Destroy(laserEffect);
				}
				_emh_laserEffect = null;
				laserEffect = null;
			}
		}

		public override void Update()
		{
			base.Update();
			if (!laserEffect || !laserLineComponent)
			{
				return;
			}
			float num = 1000f;
			Ray aimRay = GetAimRay();
			enemyFinder.RefreshCandidates();
			lockedOnHurtBox = enemyFinder.GetResults().FirstOrDefault();
			if ((bool)lockedOnHurtBox)
			{
				aimRay.direction = lockedOnHurtBox.transform.position - aimRay.origin;
			}
			UnityEngine.Vector3 position = laserEffect.transform.parent.position;
			UnityEngine.Vector3 point = aimRay.GetPoint(num);
			if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault))
			{
				point = hitInfo.point;
			}
			laserLineComponent.SetPosition(0, position);
			laserLineComponent.SetPosition(1, point);
			float num2;
			if (duration - base.age > 0.5f)
			{
				num2 = base.age / duration;
			}
			else
			{
				flashTimer -= Time.deltaTime;
				if (flashTimer <= 0f)
				{
					laserOn = !laserOn;
					flashTimer = 1f / 30f;
				}
				num2 = (laserOn ? 1f : 0f);
			}
			num2 *= laserMaxWidth;
			laserLineComponent.startWidth = num2;
			laserLineComponent.endWidth = num2;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireMegaLaser nextState = new FireMegaLaser();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialEffect;

		[SerializeField]
		public GameObject deathEffect;

		public static float duration = 2f;

		private float stopwatch;

		private Transform centerTransform;

		private Transform modelBaseTransform;

		private bool attemptedDeathBehavior;

		private EffectData _effectData;

		public override void Reset()
		{
			base.Reset();
			centerTransform = null;
			modelBaseTransform = null;
			attemptedDeathBehavior = false;
			if (_effectData != null)
			{
				_effectData.Reset();
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.modelLocator)
			{
				return;
			}
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				centerTransform = component.FindChild("Center");
				if ((bool)initialEffect)
				{
					if (!EffectManager.ShouldUsePooledEffect(initialEffect))
					{
						GameObject obj = UnityEngine.Object.Instantiate(initialEffect, centerTransform.position, centerTransform.rotation);
						obj.GetComponent<ScaleParticleSystemDuration>().newDuration = duration + 2f;
						obj.transform.parent = centerTransform;
					}
					else
					{
						EffectManager.GetAndActivatePooledEffect(initialEffect, centerTransform.position, centerTransform.rotation, centerTransform).gameObject.GetComponent<ScaleParticleSystemDuration>().newDuration = duration + 2f;
					}
				}
			}
			modelBaseTransform = base.modelLocator.modelBaseTransform;
		}

		private void AttemptDeathBehavior()
		{
			if (attemptedDeathBehavior)
			{
				return;
			}
			attemptedDeathBehavior = true;
			if ((bool)deathEffect && NetworkServer.active)
			{
				if (_effectData == null)
				{
					_effectData = new EffectData();
				}
				_effectData.origin = centerTransform.position;
				EffectManager.SpawnEffect(deathEffect, _effectData, transmit: true);
			}
			if ((bool)modelBaseTransform)
			{
				EntityState.Destroy(modelBaseTransform.gameObject);
				modelBaseTransform = null;
			}
			if (NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration)
			{
				AttemptDeathBehavior();
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				AttemptDeathBehavior();
			}
			base.OnExit();
		}
	}
	public class DeathStateGold : DeathState
	{
	}
	public class FireFist : BaseState
	{
		private enum SubState
		{
			Prep,
			FireFist,
			Exit
		}

		private class Predictor
		{
			private enum ExtrapolationType
			{
				None,
				Linear,
				Polar
			}

			private Transform bodyTransform;

			private Transform targetTransform;

			private UnityEngine.Vector3 targetPosition0;

			private UnityEngine.Vector3 targetPosition1;

			private UnityEngine.Vector3 targetPosition2;

			private int collectedPositions;

			public bool hasTargetTransform => targetTransform;

			public bool isPredictionReady => collectedPositions > 2;

			public Predictor(Transform bodyTransform)
			{
				this.bodyTransform = bodyTransform;
			}

			private void PushTargetPosition(UnityEngine.Vector3 newTargetPosition)
			{
				targetPosition2 = targetPosition1;
				targetPosition1 = targetPosition0;
				targetPosition0 = newTargetPosition;
				collectedPositions++;
			}

			public void SetTargetTransform(Transform newTargetTransform)
			{
				targetTransform = newTargetTransform;
				targetPosition2 = (targetPosition1 = (targetPosition0 = newTargetTransform.position));
				collectedPositions = 1;
			}

			public void Update()
			{
				if ((bool)targetTransform)
				{
					PushTargetPosition(targetTransform.position);
				}
			}

			public bool GetPredictedTargetPosition(float time, out UnityEngine.Vector3 predictedPosition)
			{
				UnityEngine.Vector3 vector = targetPosition1 - targetPosition2;
				UnityEngine.Vector3 vector2 = targetPosition0 - targetPosition1;
				vector.y = 0f;
				vector2.y = 0f;
				ExtrapolationType extrapolationType;
				if (vector == UnityEngine.Vector3.zero || vector2 == UnityEngine.Vector3.zero)
				{
					extrapolationType = ExtrapolationType.None;
				}
				else
				{
					UnityEngine.Vector3 normalized = vector.normalized;
					UnityEngine.Vector3 normalized2 = vector2.normalized;
					extrapolationType = ((UnityEngine.Vector3.Dot(normalized, normalized2) > 0.98f) ? ExtrapolationType.Linear : ExtrapolationType.Polar);
				}
				float num = 1f / Time.deltaTime;
				predictedPosition = targetPosition0;
				switch (extrapolationType)
				{
				case ExtrapolationType.Linear:
					predictedPosition = targetPosition0 + vector2 * (time * num);
					break;
				case ExtrapolationType.Polar:
				{
					UnityEngine.Vector3 position = bodyTransform.position;
					UnityEngine.Vector3 vector3 = Util.Vector3XZToVector2XY(targetPosition2 - position);
					UnityEngine.Vector3 vector4 = Util.Vector3XZToVector2XY(targetPosition1 - position);
					UnityEngine.Vector3 vector5 = Util.Vector3XZToVector2XY(targetPosition0 - position);
					float magnitude = vector3.magnitude;
					float magnitude2 = vector4.magnitude;
					float magnitude3 = vector5.magnitude;
					float num2 = UnityEngine.Vector2.SignedAngle(vector3, vector4) * num;
					float num3 = UnityEngine.Vector2.SignedAngle(vector4, vector5) * num;
					float num4 = (magnitude2 - magnitude) * num;
					float num5 = (magnitude3 - magnitude2) * num;
					float num6 = (num2 + num3) * 0.5f;
					float num7 = (num4 + num5) * 0.5f;
					float num8 = magnitude3 + num7 * time;
					if (num8 < 0f)
					{
						num8 = 0f;
					}
					UnityEngine.Vector2 vector6 = Util.RotateVector2(vector5, num6 * time);
					vector6 *= num8 * magnitude3;
					predictedPosition = position;
					predictedPosition.x += vector6.x;
					predictedPosition.z += vector6.y;
					break;
				}
				}
				if (Physics.Raycast(new Ray(predictedPosition + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down), out var hitInfo, 200f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					predictedPosition = hitInfo.point;
					return true;
				}
				return false;
			}
		}

		public static float entryDuration = 1f;

		public static float fireDuration = 2f;

		public static float exitDuration = 1f;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public GameObject fistEffectPrefab;

		[SerializeField]
		public GameObject fireEffectPrefab;

		[SerializeField]
		public GameObject fistProjectilePrefab;

		public static float maxDistance = 40f;

		public static float trackingDuration = 0.5f;

		public static float fistDamageCoefficient = 2f;

		public static float fistForce = 2000f;

		public static string chargeFistAttackSoundString;

		private bool hasShownPrediction;

		private bool predictionOk;

		protected UnityEngine.Vector3 predictedTargetPosition;

		private AimAnimator aimAnimator;

		private GameObject chargeEffect;

		private Transform fistTransform;

		private float stopwatch;

		private EffectData _effectData;

		protected BullseyeSearch enemyFinder;

		private EffectManagerHelper _emh_chargeEffect;

		private SubState subState;

		private Predictor predictor;

		private GameObject predictorDebug;

		private static int FireFistStateHash = Animator.StringToHash("FireFist");

		public override void Reset()
		{
			base.Reset();
			hasShownPrediction = false;
			predictionOk = false;
			predictedTargetPosition = UnityEngine.Vector3.zero;
			aimAnimator = null;
			chargeEffect = null;
			fistTransform = null;
			stopwatch = 0f;
			subState = SubState.Prep;
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			if (enemyFinder != null)
			{
				enemyFinder.Reset();
			}
			predictor = null;
			predictorDebug = null;
			_emh_chargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			if ((bool)base.modelLocator)
			{
				ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
				aimAnimator = base.modelLocator.modelTransform.GetComponent<AimAnimator>();
				if ((bool)aimAnimator)
				{
					aimAnimator.enabled = true;
				}
				if ((bool)component)
				{
					fistTransform = component.FindChild("RightFist");
					if ((bool)fistTransform)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
						{
							chargeEffect = UnityEngine.Object.Instantiate(chargeEffectPrefab, fistTransform);
						}
						else
						{
							_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, fistTransform, inResetLocal: true);
							chargeEffect = _emh_chargeEffect.gameObject;
						}
					}
				}
			}
			subState = SubState.Prep;
			PlayCrossfade("Body", "PrepFist", "PrepFist.playbackRate", entryDuration, 0.1f);
			Util.PlayAttackSpeedSound(chargeFistAttackSoundString, base.gameObject, attackSpeedStat);
			if (NetworkServer.active)
			{
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
				if ((bool)base.teamComponent)
				{
					bullseyeSearch.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
				}
				bullseyeSearch.maxDistanceFilter = maxDistance;
				bullseyeSearch.maxAngleFilter = 90f;
				Ray aimRay = GetAimRay();
				bullseyeSearch.searchOrigin = aimRay.origin;
				bullseyeSearch.searchDirection = aimRay.direction;
				bullseyeSearch.filterByLoS = false;
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
				bullseyeSearch.RefreshCandidates();
				HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
				if ((bool)hurtBox)
				{
					predictor = new Predictor(base.transform);
					predictor.SetTargetTransform(hurtBox.transform);
				}
			}
		}

		protected void DestroyChargeEffect()
		{
			if ((bool)chargeEffect)
			{
				if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffect);
				}
				chargeEffect = null;
				_emh_chargeEffect = null;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			DestroyChargeEffect();
			EntityState.Destroy(predictorDebug);
			predictorDebug = null;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			switch (subState)
			{
			case SubState.Prep:
				if (predictor != null)
				{
					predictor.Update();
				}
				if (stopwatch <= trackingDuration)
				{
					if (predictor != null)
					{
						predictionOk = predictor.GetPredictedTargetPosition(entryDuration - trackingDuration, out predictedTargetPosition);
						if (predictionOk && (bool)predictorDebug)
						{
							predictorDebug.transform.position = predictedTargetPosition;
						}
					}
				}
				else if (!hasShownPrediction)
				{
					hasShownPrediction = true;
					PlacePredictedAttack();
				}
				if (stopwatch >= entryDuration)
				{
					predictor = null;
					subState = SubState.FireFist;
					stopwatch = 0f;
					PlayAnimation("Body", FireFistStateHash);
					DestroyChargeEffect();
					if (!EffectManager.ShouldUsePooledEffect(fireEffectPrefab))
					{
						UnityEngine.Object.Instantiate(fireEffectPrefab, fistTransform.position, UnityEngine.Quaternion.identity, fistTransform);
					}
					else
					{
						EffectManager.GetAndActivatePooledEffect(fireEffectPrefab, fistTransform.position, UnityEngine.Quaternion.identity, fistTransform);
					}
				}
				break;
			case SubState.FireFist:
				if (stopwatch >= fireDuration)
				{
					subState = SubState.Exit;
					stopwatch = 0f;
					PlayCrossfade("Body", "ExitFist", "ExitFist.playbackRate", exitDuration, 0.3f);
				}
				break;
			case SubState.Exit:
				if (stopwatch >= exitDuration && base.isAuthority)
				{
					outer.SetNextStateToMain();
				}
				break;
			}
		}

		protected virtual void PlacePredictedAttack()
		{
			PlaceSingleDelayBlast(predictedTargetPosition, 0f);
		}

		protected void PlaceSingleDelayBlast(UnityEngine.Vector3 position, float delay)
		{
			if (base.isAuthority)
			{
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = fistProjectilePrefab;
				fireProjectileInfo.position = position;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * fistDamageCoefficient;
				fireProjectileInfo.force = fistForce;
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				fireProjectileInfo.fuseOverride = entryDuration - trackingDuration + delay;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}
	}
	public class FireGoldFist : FireFist
	{
		public static int fistCount;

		public static float distanceBetweenFists;

		public static float delayBetweenFists;

		protected override void PlacePredictedAttack()
		{
			int num = 0;
			UnityEngine.Vector3 vector = predictedTargetPosition;
			UnityEngine.Vector3 vector2 = UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f) * UnityEngine.Vector3.forward;
			for (int i = -(fistCount / 2); i < fistCount / 2; i++)
			{
				UnityEngine.Vector3 vector3 = vector + vector2 * distanceBetweenFists * i;
				float num2 = 60f;
				if (Physics.Raycast(new Ray(vector3 + UnityEngine.Vector3.up * (num2 / 2f), UnityEngine.Vector3.down), out var hitInfo, num2, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					vector3 = hitInfo.point;
				}
				PlaceSingleDelayBlast(vector3, delayBetweenFists * (float)num);
				num++;
			}
		}
	}
	public class FireGoldMegaLaser : FireMegaLaser
	{
		public static GameObject projectilePrefab;

		public static float projectileFireFrequency;

		public static float projectileDamageCoefficient;

		public static float projectileMinSpread;

		public static float projectileMaxSpread;

		private float projectileStopwatch;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			projectileStopwatch += GetDeltaTime() * attackSpeedStat;
			if (projectileStopwatch >= 1f / projectileFireFrequency)
			{
				Ray ray = GetAimRay();
				if ((bool)muzzleTransform)
				{
					ray.origin = muzzleTransform.transform.position;
				}
				ray.direction = Util.ApplySpread(ray.direction, projectileMinSpread, projectileMaxSpread, 1f, 1f);
				projectileStopwatch -= 1f / projectileFireFrequency;
				ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageStat * FireMegaLaser.damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}
	}
	public class FireMegaLaser : BaseState
	{
		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject laserPrefab;

		public static string playAttackSoundString;

		public static string playLoopSoundString;

		public static string stopLoopSoundString;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float fireFrequency;

		public static float maxDistance;

		public static float minimumDuration;

		public static float maximumDuration;

		public static float lockOnAngle;

		public static float procCoefficientPerTick;

		private HurtBox lockedOnHurtBox;

		private float fireStopwatch;

		private float stopwatch;

		private Ray aimRay;

		private Transform modelTransform;

		private GameObject laserEffect;

		private ChildLocator laserChildLocator;

		private Transform laserEffectEnd;

		protected Transform muzzleTransform;

		private BulletAttack bulletAttack;

		private EffectManagerHelper _emh_laserEffect;

		private BullseyeSearch enemyFinder;

		private bool foundAnyTarget;

		public override void Reset()
		{
			base.Reset();
			lockedOnHurtBox = null;
			modelTransform = null;
			laserEffect = null;
			laserChildLocator = null;
			laserEffectEnd = null;
			muzzleTransform = null;
			if (bulletAttack != null)
			{
				bulletAttack.Reset();
			}
			if (enemyFinder != null)
			{
				enemyFinder.Reset();
			}
			foundAnyTarget = false;
			_emh_laserEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterBody.SetAimTimer(maximumDuration);
			Util.PlaySound(playAttackSoundString, base.gameObject);
			Util.PlaySound(playLoopSoundString, base.gameObject);
			PlayCrossfade("Gesture, Additive", "FireLaserLoop", 0.25f);
			enemyFinder = new BullseyeSearch();
			enemyFinder.viewer = base.characterBody;
			enemyFinder.maxDistanceFilter = maxDistance;
			enemyFinder.maxAngleFilter = lockOnAngle;
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.filterByLoS = false;
			enemyFinder.sortMode = BullseyeSearch.SortMode.Angle;
			enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			aimRay = GetAimRay();
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					muzzleTransform = component.FindChild("MuzzleLaser");
					if ((bool)muzzleTransform && (bool)laserPrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(laserPrefab))
						{
							laserEffect = UnityEngine.Object.Instantiate(laserPrefab, muzzleTransform.position, muzzleTransform.rotation);
						}
						else
						{
							_emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserPrefab, muzzleTransform.position, muzzleTransform.rotation);
							laserEffect = _emh_laserEffect.gameObject;
						}
						laserEffect.transform.parent = muzzleTransform;
						laserChildLocator = laserEffect.GetComponent<ChildLocator>();
						laserEffectEnd = laserChildLocator.FindChild("LaserEnd");
					}
				}
			}
			UpdateLockOn();
		}

		public override void OnExit()
		{
			if ((bool)laserEffect)
			{
				if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null)
				{
					_emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect);
				}
				else
				{
					EntityState.Destroy(laserEffect);
				}
				_emh_laserEffect = null;
				laserEffect = null;
			}
			base.characterBody.SetAimTimer(2f);
			Util.PlaySound(stopLoopSoundString, base.gameObject);
			PlayCrossfade("Gesture, Additive", "FireLaserEnd", 0.25f);
			base.OnExit();
		}

		private void UpdateLockOn()
		{
			if (base.isAuthority)
			{
				enemyFinder.searchOrigin = aimRay.origin;
				enemyFinder.searchDirection = aimRay.direction;
				enemyFinder.RefreshCandidates();
				foundAnyTarget = (lockedOnHurtBox = enemyFinder.GetResults().FirstOrDefault());
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			fireStopwatch += deltaTime;
			stopwatch += deltaTime;
			aimRay = GetAimRay();
			UnityEngine.Vector3 vector = aimRay.origin;
			if ((bool)muzzleTransform)
			{
				vector = muzzleTransform.position;
			}
			RaycastHit hitInfo;
			UnityEngine.Vector3 vector2 = (lockedOnHurtBox ? lockedOnHurtBox.transform.position : ((!Util.CharacterRaycast(base.gameObject, aimRay, out hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) ? aimRay.GetPoint(maxDistance) : hitInfo.point));
			Ray ray = new Ray(vector, vector2 - vector);
			bool flag = false;
			if ((bool)laserEffect && (bool)laserChildLocator)
			{
				if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo2, (vector2 - vector).magnitude, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
				{
					vector2 = hitInfo2.point;
					if (Util.CharacterRaycast(base.gameObject, new Ray(vector2 - ray.direction * 0.1f, -ray.direction), out var _, hitInfo2.distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
					{
						vector2 = ray.GetPoint(0.1f);
						flag = true;
					}
				}
				laserEffect.transform.rotation = Util.QuaternionSafeLookRotation(vector2 - vector);
				laserEffectEnd.transform.position = vector2;
			}
			if (fireStopwatch > 1f / fireFrequency)
			{
				string targetMuzzle = "MuzzleLaser";
				if (!flag)
				{
					FireBullet(modelTransform, ray, targetMuzzle, (vector2 - ray.origin).magnitude + 0.1f);
				}
				UpdateLockOn();
				fireStopwatch -= 1f / fireFrequency;
			}
			if (base.isAuthority && (((!base.inputBank || !base.inputBank.skill4.down) && stopwatch > minimumDuration) || stopwatch > maximumDuration))
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		private void FireBullet(Transform modelTransform, Ray aimRay, string targetMuzzle, float maxDistance)
		{
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				if (bulletAttack == null)
				{
					bulletAttack = new BulletAttack();
				}
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = 1u;
				bulletAttack.damage = damageCoefficient * damageStat / fireFrequency;
				bulletAttack.force = force;
				bulletAttack.muzzleName = targetMuzzle;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.procCoefficient = procCoefficientPerTick;
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = 0f;
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.Fire();
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(HurtBoxReference.FromHurtBox(lockedOnHurtBox));
			writer.Write(stopwatch);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			HurtBoxReference hurtBoxReference = reader.ReadHurtBoxReference();
			stopwatch = reader.ReadSingle();
			lockedOnHurtBox = hurtBoxReference.ResolveGameObject()?.GetComponent<HurtBox>();
		}
	}
	public class RechargeRocks : BaseState
	{
		public static float baseDuration = 3f;

		public static float baseRechargeDuration = 2f;

		public static GameObject effectPrefab;

		public static string attackSoundString;

		public static GameObject rockControllerPrefab;

		private int rocksFired;

		private float duration;

		private float stopwatch;

		private float rechargeStopwatch;

		private GameObject chargeEffect;

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			Util.PlaySound(attackSoundString, base.gameObject);
			PlayCrossfade("Body", "RechargeRocks", "RechargeRocks.playbackRate", duration, 0.2f);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("LeftFist");
					if ((bool)transform && (bool)effectPrefab)
					{
						chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
						chargeEffect.transform.parent = transform;
						ScaleParticleSystemDuration component2 = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = duration;
						}
					}
				}
			}
			if (NetworkServer.active)
			{
				GameObject obj = UnityEngine.Object.Instantiate(rockControllerPrefab);
				obj.GetComponent<TitanRockController>().SetOwner(base.gameObject);
				NetworkServer.Spawn(obj);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeEffect)
			{
				EntityState.Destroy(chargeEffect);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static GameObject burrowPrefab;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Transform transform = component.FindChild("BurrowCenter");
			if ((bool)transform)
			{
				if (!EffectManager.ShouldUsePooledEffect(burrowPrefab))
				{
					UnityEngine.Object.Instantiate(burrowPrefab, transform.position, UnityEngine.Quaternion.identity);
				}
				else
				{
					EffectManager.GetAndActivatePooledEffect(burrowPrefab, transform.position, UnityEngine.Quaternion.identity);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.GolemMonster
{
	public class ChargeLaser : BaseState
	{
		public static float baseDuration = 3f;

		public static float laserMaxWidth = 0.2f;

		public static GameObject effectPrefab;

		public static GameObject laserPrefab;

		public static string attackSoundString;

		private float duration;

		private uint chargePlayID;

		private GameObject chargeEffect;

		private GameObject laserEffect;

		private LineRenderer laserLineComponent;

		private UnityEngine.Vector3 laserDirection;

		private UnityEngine.Vector3 visualEndPosition;

		private float flashTimer;

		private bool laserOn;

		protected EffectManagerHelper _efh_Charge;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargePlayID = 0u;
			chargeEffect = null;
			laserLineComponent = null;
			laserDirection = UnityEngine.Vector3.zero;
			visualEndPosition = UnityEngine.Vector3.zero;
			flashTimer = 0f;
			laserOn = false;
			_efh_Charge = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			SetAIUpdateFrequency(alwaysUpdate: true);
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			chargePlayID = Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleLaser");
					if ((bool)transform)
					{
						if ((bool)effectPrefab)
						{
							if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
							{
								chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
							}
							else
							{
								_efh_Charge = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation);
								chargeEffect = _efh_Charge.gameObject;
							}
							chargeEffect.transform.parent = transform;
							ScaleParticleSystemDuration component2 = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
							if ((bool)component2)
							{
								component2.newDuration = duration;
							}
						}
						if ((bool)laserPrefab && laserEffect == null)
						{
							laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation);
						}
						if (laserEffect != null)
						{
							if (!laserEffect.activeInHierarchy)
							{
								laserEffect.SetActive(value: true);
							}
							if (laserEffect.transform.parent != transform)
							{
								laserEffect.transform.parent = transform;
							}
							laserLineComponent = laserEffect.GetComponent<LineRenderer>();
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
			flashTimer = 0f;
			laserOn = true;
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(chargePlayID);
			base.OnExit();
			SetAIUpdateFrequency(alwaysUpdate: false);
			if ((bool)chargeEffect)
			{
				if (!EffectManager.UsePools)
				{
					EntityState.Destroy(chargeEffect);
				}
				else if (_efh_Charge != null && _efh_Charge.OwningPool != null)
				{
					if (!_efh_Charge.OwningPool.IsObjectInPool(_efh_Charge))
					{
						_efh_Charge.OwningPool.ReturnObject(_efh_Charge);
					}
				}
				else
				{
					if (_efh_Charge != null)
					{
						UnityEngine.Debug.LogFormat("ChargeLaser has no owning pool {0} {1}", base.gameObject.name, base.gameObject.GetInstanceID());
					}
					EntityState.Destroy(chargeEffect);
				}
			}
			if ((bool)laserEffect && laserEffect.activeInHierarchy)
			{
				laserEffect.SetActive(value: false);
			}
		}

		public override void Update()
		{
			base.Update();
			if (!laserEffect || !laserLineComponent)
			{
				return;
			}
			float num = 1000f;
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 position = laserEffect.transform.parent.position;
			UnityEngine.Vector3 point = aimRay.GetPoint(num);
			laserDirection = point - position;
			if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask))
			{
				point = hitInfo.point;
			}
			laserLineComponent.SetPosition(0, position);
			laserLineComponent.SetPosition(1, point);
			float num2;
			if (duration - base.age > 0.5f)
			{
				num2 = base.age / duration;
			}
			else
			{
				flashTimer -= Time.deltaTime;
				if (flashTimer <= 0f)
				{
					laserOn = !laserOn;
					flashTimer = 1f / 30f;
				}
				num2 = (laserOn ? 1f : 0f);
			}
			num2 *= laserMaxWidth;
			laserLineComponent.startWidth = num2;
			laserLineComponent.endWidth = num2;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireLaser fireLaser = new FireLaser();
				fireLaser.laserDirection = laserDirection;
				outer.SetNextState(fireLaser);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ClapState : BaseState
	{
		public static float duration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float radius = 3f;

		private BlastAttack attack;

		public static string attackSoundString;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasAttacked;

		private GameObject leftHandChargeEffect;

		private GameObject rightHandChargeEffect;

		private EffectManagerHelper _emh_leftHandChargeEffect;

		private EffectManagerHelper _emh_rightHandChargeEffect;

		public override void Reset()
		{
			base.Reset();
			modelAnimator = null;
			modelTransform = null;
			hasAttacked = false;
			leftHandChargeEffect = null;
			rightHandChargeEffect = null;
			if (attack != null)
			{
				attack.Reset();
			}
			_emh_leftHandChargeEffect = null;
			_emh_rightHandChargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			PlayCrossfade("Body", "Clap", "Clap.playbackRate", duration, 0.1f);
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/GolemClapCharge");
			Transform transform = component.FindChild("HandL");
			Transform transform2 = component.FindChild("HandR");
			if ((bool)transform)
			{
				if (!EffectManager.ShouldUsePooledEffect(gameObject))
				{
					leftHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform);
				}
				else
				{
					_emh_leftHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform, inResetLocal: true);
					leftHandChargeEffect = _emh_leftHandChargeEffect.gameObject;
				}
			}
			if ((bool)transform2)
			{
				if (!EffectManager.ShouldUsePooledEffect(gameObject))
				{
					rightHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform2);
					return;
				}
				_emh_rightHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform2, inResetLocal: true);
				rightHandChargeEffect = _emh_rightHandChargeEffect.gameObject;
			}
		}

		protected void DestroyChargeEffects()
		{
			if (_emh_leftHandChargeEffect != null && _emh_leftHandChargeEffect.OwningPool != null)
			{
				_emh_leftHandChargeEffect.OwningPool.ReturnObject(_emh_leftHandChargeEffect);
			}
			else
			{
				EntityState.Destroy(leftHandChargeEffect);
			}
			leftHandChargeEffect = null;
			_emh_leftHandChargeEffect = null;
			if (_emh_rightHandChargeEffect != null && _emh_rightHandChargeEffect.OwningPool != null)
			{
				_emh_rightHandChargeEffect.OwningPool.ReturnObject(_emh_rightHandChargeEffect);
			}
			else
			{
				EntityState.Destroy(rightHandChargeEffect);
			}
			rightHandChargeEffect = null;
			_emh_rightHandChargeEffect = null;
		}

		public override void OnExit()
		{
			DestroyChargeEffects();
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && modelAnimator.GetFloat("Clap.hitBoxActive") > 0.5f && !hasAttacked)
			{
				if (base.isAuthority && (bool)modelTransform)
				{
					ChildLocator component = modelTransform.GetComponent<ChildLocator>();
					if ((bool)component)
					{
						Transform transform = component.FindChild("ClapZone");
						if ((bool)transform)
						{
							attack = new BlastAttack();
							attack.attacker = base.gameObject;
							attack.inflictor = base.gameObject;
							attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
							attack.baseDamage = damageStat * damageCoefficient;
							attack.baseForce = forceMagnitude;
							attack.position = transform.position;
							attack.radius = radius;
							attack.attackerFiltering = AttackerFiltering.NeverHitSelf;
							attack.Fire();
						}
					}
				}
				hasAttacked = true;
				DestroyChargeEffects();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialDeathExplosionPrefab;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("Head");
			if ((bool)transform && (bool)initialDeathExplosionPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(initialDeathExplosionPrefab))
				{
					UnityEngine.Object.Instantiate(initialDeathExplosionPrefab, transform.position, UnityEngine.Quaternion.identity).transform.parent = transform;
				}
				else
				{
					EffectManager.GetAndActivatePooledEffect(initialDeathExplosionPrefab, transform.position, UnityEngine.Quaternion.identity, transform);
				}
			}
		}
	}
	public class FireLaser : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float blastRadius;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public static string attackSoundString;

		public UnityEngine.Vector3 laserDirection;

		private float duration;

		private Ray modifiedAimRay;

		private static int FireLaserStateHash = Animator.StringToHash("FireLaser");

		private static int FireLaserParamHash = Animator.StringToHash("FireLaser.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modifiedAimRay = GetAimRay();
			modifiedAimRay.direction = laserDirection;
			GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			Util.PlaySound(attackSoundString, base.gameObject);
			string text = "MuzzleLaser";
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
			PlayAnimation("Gesture", FireLaserStateHash, FireLaserParamHash, duration);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false);
			}
			if (!base.isAuthority)
			{
				return;
			}
			float num = 1000f;
			UnityEngine.Vector3 vector = modifiedAimRay.origin + modifiedAimRay.direction * num;
			if (Physics.Raycast(modifiedAimRay, out var hitInfo, num, LayerIndex.CommonMasks.laser))
			{
				vector = hitInfo.point;
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.inflictor = base.gameObject;
			blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
			blastAttack.baseDamage = damageStat * damageCoefficient;
			blastAttack.baseForce = force * 0.2f;
			blastAttack.position = vector;
			blastAttack.radius = blastRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot;
			blastAttack.bonusForce = force * modifiedAimRay.direction;
			blastAttack.Fire();
			_ = modifiedAimRay.origin;
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				int childIndex = component.FindChildIndex(text);
				if ((bool)tracerEffectPrefab)
				{
					EffectData effectData = new EffectData
					{
						origin = vector,
						start = modifiedAimRay.origin
					};
					effectData.SetChildLocatorTransformReference(base.gameObject, childIndex);
					EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
					EffectManager.SpawnEffect(hitEffectPrefab, effectData, transmit: true);
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
		private GameObject eyeGameObject;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				modelTransform.GetComponent<PrintController>().enabled = true;
			}
			eyeGameObject = FindModelChild("Eye")?.gameObject;
			if ((bool)eyeGameObject)
			{
				eyeGameObject.SetActive(value: false);
			}
			if (base.characterBody.HasBuff(DLC2Content.Buffs.EliteAurelionite))
			{
				PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent<PrintController>();
				component.enabled = false;
				component.printTime = duration;
				component.startingPrintHeight = -101.78f;
				component.maxPrintHeight = -93f;
				component.startingPrintBias = 2f;
				component.maxPrintBias = 0.95f;
				component.disableWhenFinished = true;
				component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
				component.enabled = true;
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying && (bool)eyeGameObject)
			{
				eyeGameObject.SetActive(value: true);
			}
		}
	}
}
namespace EntityStates.GoldGat
{
	public class BaseGoldGatState : EntityState
	{
		protected NetworkedBodyAttachment networkedBodyAttachment;

		protected GameObject bodyGameObject;

		protected CharacterBody body;

		protected ChildLocator gunChildLocator;

		protected Animator gunAnimator;

		protected Transform gunTransform;

		protected CharacterMaster bodyMaster;

		protected EquipmentSlot bodyEquipmentSlot;

		protected InputBankTest bodyInputBank;

		protected AimAnimator bodyAimAnimator;

		public bool shouldFire;

		private bool linkedToDisplay;

		public override void OnEnter()
		{
			base.OnEnter();
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
			if (!networkedBodyAttachment)
			{
				return;
			}
			bodyGameObject = networkedBodyAttachment.attachedBodyObject;
			body = networkedBodyAttachment.attachedBody;
			if ((bool)bodyGameObject)
			{
				bodyMaster = body.master;
				bodyInputBank = bodyGameObject.GetComponent<InputBankTest>();
				bodyEquipmentSlot = body.equipmentSlot;
				ModelLocator component = body.GetComponent<ModelLocator>();
				if ((bool)component)
				{
					bodyAimAnimator = component.modelTransform.GetComponent<AimAnimator>();
				}
				LinkToDisplay();
			}
		}

		private void LinkToDisplay()
		{
			if (linkedToDisplay || !bodyEquipmentSlot)
			{
				return;
			}
			gunTransform = bodyEquipmentSlot.FindActiveEquipmentDisplay();
			if ((bool)gunTransform)
			{
				gunChildLocator = gunTransform.GetComponentInChildren<ChildLocator>();
				if ((bool)gunChildLocator && (bool)base.modelLocator)
				{
					base.modelLocator.modelTransform = gunChildLocator.transform;
					gunAnimator = GetModelAnimator();
					linkedToDisplay = true;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.Update();
			if (base.isAuthority && (bool)bodyInputBank)
			{
				if (bodyInputBank.activateEquipment.justPressed)
				{
					shouldFire = !shouldFire;
				}
				if (body.inventory.GetItemCount(RoR2Content.Items.AutoCastEquipment) > 0)
				{
					shouldFire = true;
				}
			}
			LinkToDisplay();
			if ((bool)bodyAimAnimator && (bool)gunAnimator)
			{
				bodyAimAnimator.UpdateAnimatorParameters(gunAnimator, -45f, 45f, 0f, 0f);
			}
		}

		protected bool CheckReturnToIdle()
		{
			if (!base.isAuthority)
			{
				return false;
			}
			if (((bool)bodyMaster && bodyMaster.money == 0) || !shouldFire)
			{
				outer.SetNextState(new GoldGatIdle
				{
					shouldFire = shouldFire
				});
				return true;
			}
			return false;
		}
	}
	public class GoldGatIdle : BaseGoldGatState
	{
		public static string windDownSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(windDownSoundString, base.gameObject);
		}

		public override void Update()
		{
			base.Update();
			if ((bool)gunAnimator)
			{
				gunAnimator.SetFloat("Crank.playbackRate", 0f, 1f, GetDeltaTime());
			}
			if (base.isAuthority && shouldFire && bodyMaster.money != 0 && bodyEquipmentSlot.stock > 0)
			{
				outer.SetNextState(new GoldGatFire
				{
					shouldFire = shouldFire
				});
			}
		}
	}
	public class GoldGatFire : BaseGoldGatState
	{
		public static float minFireFrequency;

		public static float maxFireFrequency;

		public static float minSpread;

		public static float maxSpread;

		public static float windUpDuration;

		public static float force;

		public static float damageCoefficient;

		public static float procCoefficient;

		public static string attackSoundString;

		public static GameObject tracerEffectPrefab;

		public static GameObject impactEffectPrefab;

		public static GameObject muzzleFlashEffectPrefab;

		public static int baseMoneyCostPerBullet;

		public static string windUpSoundString;

		public static string windUpRTPC;

		public float totalStopwatch;

		private float stopwatch;

		private float fireFrequency;

		private uint loopSoundID;

		private static int CrankplaybackRateParamHash = Animator.StringToHash("Crank.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			loopSoundID = Util.PlaySound(windUpSoundString, base.gameObject);
			FireBullet();
		}

		private void FireBullet()
		{
			body.SetAimTimer(2f);
			float t = Mathf.Clamp01(totalStopwatch / windUpDuration);
			fireFrequency = Mathf.Lerp(minFireFrequency, maxFireFrequency, t);
			float num = Mathf.Lerp(minSpread, maxSpread, t);
			Util.PlaySound(attackSoundString, base.gameObject);
			int num2 = (int)((float)baseMoneyCostPerBullet * (1f + ((float)TeamManager.instance.GetTeamLevel(bodyMaster.teamIndex) - 1f) * 0.25f));
			if (base.isAuthority)
			{
				Transform aimOriginTransform = body.aimOriginTransform;
				if ((bool)gunChildLocator)
				{
					gunChildLocator.FindChild("Muzzle");
				}
				if ((bool)aimOriginTransform)
				{
					BulletAttack bulletAttack = new BulletAttack();
					bulletAttack.owner = networkedBodyAttachment.attachedBodyObject;
					bulletAttack.aimVector = bodyInputBank.aimDirection;
					bulletAttack.origin = bodyInputBank.aimOrigin;
					bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet;
					bulletAttack.force = force;
					bulletAttack.damage = body.damage * damageCoefficient;
					bulletAttack.damageColorIndex = DamageColorIndex.Item;
					bulletAttack.bulletCount = 1u;
					bulletAttack.minSpread = 0f;
					bulletAttack.maxSpread = num;
					bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
					bulletAttack.isCrit = Util.CheckRoll(body.crit, bodyMaster);
					bulletAttack.procCoefficient = procCoefficient;
					bulletAttack.muzzleName = "Muzzle";
					bulletAttack.weapon = base.gameObject;
					bulletAttack.Fire();
					gunAnimator?.Play("Fire");
				}
			}
			if (NetworkServer.active)
			{
				bodyMaster.money = (uint)Mathf.Max(0f, bodyMaster.money - num2);
			}
			gunAnimator?.SetFloat(CrankplaybackRateParamHash, fireFrequency);
			EffectManager.SimpleMuzzleFlash(muzzleFlashEffectPrefab, base.gameObject, "Muzzle", transmit: false);
		}

		public override void Update()
		{
			base.Update();
			float deltaTime = Time.deltaTime;
			totalStopwatch += deltaTime;
			stopwatch += deltaTime;
			AkSoundEngine.SetRTPCValueByPlayingID(windUpRTPC, Mathf.InverseLerp(minFireFrequency, maxFireFrequency, fireFrequency) * 100f, loopSoundID);
			if (!CheckReturnToIdle() && stopwatch > 1f / fireFrequency)
			{
				stopwatch = 0f;
				FireBullet();
			}
		}

		public override void OnExit()
		{
			AkSoundEngine.StopPlayingID(loopSoundID);
			base.OnExit();
		}
	}
}
namespace EntityStates.GlobalSkills.WoundSlash
{
	public class WoundSlash : BaseSkillState
	{
		public static float blastRadius;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static float blastProcCoefficient;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject slashEffectPrefab;

		public static float slashEffectOffset;

		public static float baseDuration;

		public static string soundString;

		public static float shortHopVelocity;

		private float duration => baseDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 vector = base.characterBody.corePosition + aimRay.direction * slashEffectOffset;
			Util.PlaySound(soundString, base.gameObject);
			EffectData effectData = new EffectData
			{
				origin = vector,
				rotation = Util.QuaternionSafeLookRotation(aimRay.direction)
			};
			EffectManager.SpawnEffect(slashEffectPrefab, effectData, transmit: true);
			if (NetworkServer.active)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.gameObject;
				blastAttack.baseDamage = blastDamageCoefficient * damageStat;
				blastAttack.baseForce = blastForce;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.crit = RollCrit();
				blastAttack.damageType = DamageType.Generic;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.inflictor = base.gameObject;
				blastAttack.position = vector;
				blastAttack.procChainMask = default(ProcChainMask);
				blastAttack.procCoefficient = blastProcCoefficient;
				blastAttack.radius = blastRadius;
				blastAttack.teamIndex = base.teamComponent.teamIndex;
				blastAttack.impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab);
				blastAttack.Fire();
			}
			if (base.isAuthority && (bool)base.characterMotor)
			{
				base.characterMotor.velocity.y = Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
}
namespace EntityStates.GlobalSkills.LunarNeedle
{
	public class ChargeLunarSecondary : BaseChargeBombState
	{
		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string playbackRateParam;

		protected override BaseThrowBombState GetNextState()
		{
			return new ThrowLunarSecondary();
		}

		protected override void PlayChargeAnimation()
		{
			PlayAnimation(animationLayerName, animationStateName, playbackRateParam, base.duration);
		}
	}
	public class FireLunarNeedle : BaseSkillState
	{
		public static float baseDuration;

		public static float damageCoefficient;

		public static GameObject projectilePrefab;

		public static float recoilAmplitude;

		public static float spreadBloomValue;

		public static GameObject muzzleFlashEffectPrefab;

		public static string fireSound;

		public static float maxSpread;

		private float duration;

		[SerializeField]
		public string animationLayerName = "Gesture, Override";

		[SerializeField]
		public string animationStateName = "FireLunarNeedle";

		[SerializeField]
		public string playbackRateParam = "FireLunarNeedle.playbackRate";

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, maxSpread, 1f, 1f);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.position = aimRay.origin;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction);
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				fireProjectileInfo.damage = base.characterBody.damage * damageCoefficient;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.useFuseOverride = false;
				fireProjectileInfo.useSpeedOverride = false;
				fireProjectileInfo.target = null;
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
			AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(spreadBloomValue);
			StartAimMode();
			EffectManager.SimpleMuzzleFlash(muzzleFlashEffectPrefab, base.gameObject, "Head", transmit: false);
			Util.PlaySound(fireSound, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ThrowLunarSecondary : BaseThrowBombState
	{
		[SerializeField]
		public float minSpeed;

		[SerializeField]
		public float maxSpeed;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string playbackRateParam;

		protected override void PlayThrowAnimation()
		{
			PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration);
		}

		protected override void ModifyProjectile(ref FireProjectileInfo projectileInfo)
		{
			projectileInfo.speedOverride = Util.Remap(charge, 0f, 1f, minSpeed, maxSpeed);
			projectileInfo.useSpeedOverride = true;
		}
	}
}
namespace EntityStates.GlobalSkills.LunarDetonator
{
	public class Detonate : BaseState
	{
		private class DetonationController
		{
			public HurtBox[] detonationTargets;

			public CharacterBody characterBody;

			public float damageStat;

			public bool isCrit;

			public float interval;

			private int i;

			private float timer;

			private bool _active;

			public bool active
			{
				get
				{
					return _active;
				}
				set
				{
					if (_active != value)
					{
						_active = value;
						if (_active)
						{
							RoR2Application.onFixedUpdate += FixedUpdate;
						}
						else
						{
							RoR2Application.onFixedUpdate -= FixedUpdate;
						}
					}
				}
			}

			private void FixedUpdate()
			{
				if (!characterBody || !characterBody.healthComponent || !characterBody.healthComponent.alive)
				{
					active = false;
					return;
				}
				timer -= Time.deltaTime;
				if (!(timer <= 0f))
				{
					return;
				}
				for (timer = interval; i < detonationTargets.Length; i++)
				{
					try
					{
						HurtBox a = null;
						Util.Swap(ref a, ref detonationTargets[i]);
						if (DoDetonation(a))
						{
							break;
						}
					}
					catch (Exception message)
					{
						UnityEngine.Debug.LogError(message);
					}
				}
				if (i >= detonationTargets.Length)
				{
					active = false;
				}
			}

			private bool DoDetonation(HurtBox targetHurtBox)
			{
				if (!targetHurtBox)
				{
					return false;
				}
				HealthComponent healthComponent = targetHurtBox.healthComponent;
				if (!healthComponent)
				{
					return false;
				}
				CharacterBody body = healthComponent.body;
				if (!body)
				{
					return false;
				}
				if (body.GetBuffCount(RoR2Content.Buffs.LunarDetonationCharge) <= 0)
				{
					return false;
				}
				LunarDetonatorOrb lunarDetonatorOrb = new LunarDetonatorOrb();
				lunarDetonatorOrb.origin = characterBody.corePosition;
				lunarDetonatorOrb.target = targetHurtBox;
				lunarDetonatorOrb.attacker = characterBody.gameObject;
				lunarDetonatorOrb.baseDamage = damageStat * baseDamageCoefficient;
				lunarDetonatorOrb.damagePerStack = damageStat * damageCoefficientPerStack;
				lunarDetonatorOrb.damageColorIndex = DamageColorIndex.Default;
				lunarDetonatorOrb.isCrit = isCrit;
				lunarDetonatorOrb.procChainMask = default(ProcChainMask);
				lunarDetonatorOrb.procCoefficient = 1f;
				lunarDetonatorOrb.detonationEffectPrefab = detonationEffectPrefab;
				lunarDetonatorOrb.travelSpeed = 120f;
				lunarDetonatorOrb.orbEffectPrefab = orbEffectPrefab;
				OrbManager.instance.AddOrb(lunarDetonatorOrb);
				return true;
			}
		}

		public static float baseDuration;

		public static float baseDamageCoefficient;

		public static float damageCoefficientPerStack;

		public static float procCoefficient;

		public static float detonationInterval;

		public static GameObject detonationEffectPrefab;

		public static GameObject orbEffectPrefab;

		public static GameObject enterEffectPrefab;

		public static string enterSoundString;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string playbackRateParam;

		private float duration;

		private HurtBox[] detonationTargets;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			EffectManager.SimpleImpactEffect(enterEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false);
			Util.PlaySound(enterSoundString, base.gameObject);
			if (NetworkServer.active)
			{
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.filterByDistinctEntity = true;
				bullseyeSearch.filterByLoS = false;
				bullseyeSearch.maxDistanceFilter = float.PositiveInfinity;
				bullseyeSearch.minDistanceFilter = 0f;
				bullseyeSearch.minAngleFilter = 0f;
				bullseyeSearch.maxAngleFilter = 180f;
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
				bullseyeSearch.teamMaskFilter = TeamMask.GetUnprotectedTeams(GetTeam());
				bullseyeSearch.searchOrigin = base.characterBody.corePosition;
				bullseyeSearch.viewer = null;
				bullseyeSearch.RefreshCandidates();
				bullseyeSearch.FilterOutGameObject(base.gameObject);
				IEnumerable<HurtBox> results = bullseyeSearch.GetResults();
				detonationTargets = results.ToArray();
				new DetonationController
				{
					characterBody = base.characterBody,
					interval = detonationInterval,
					detonationTargets = detonationTargets,
					damageStat = damageStat,
					isCrit = RollCrit(),
					active = true
				};
			}
			PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.Geode
{
	public class GeodeEntityStates : EntityState
	{
		protected GeodeController geodeController;

		protected GameObject cleansingIndicator;

		protected GameObject geodeModel;

		protected Renderer geodeTrunkRenderer;

		protected GameObject geodeBase;

		protected GameObject geodeIdleVFX;

		protected int sliceHeightNameId;

		public override void OnEnter()
		{
			base.OnEnter();
			geodeController = base.gameObject.GetComponent<GeodeController>();
			ChildLocator component = base.gameObject.GetComponent<ChildLocator>();
			cleansingIndicator = component.FindChildGameObject(0);
			geodeModel = component.FindChildGameObject(1);
			geodeBase = component.FindChildGameObject(2);
			geodeIdleVFX = component.FindChildGameObject(3);
			geodeTrunkRenderer = geodeModel.GetComponent<Renderer>();
			geodeTrunkRenderer.material.EnableKeyword("_SLICEHEIGHT");
			int propertyIndex = geodeTrunkRenderer.material.shader.FindPropertyIndex("_SliceHeight");
			sliceHeightNameId = geodeTrunkRenderer.material.shader.GetPropertyNameId(propertyIndex);
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class GeodeShatter : GeodeEntityStates
	{
		private SphereSearch sphereSearch;

		private List<HurtBox> hitHurtBoxes;

		private bool cleansingActive = true;

		private float stopWatch;

		protected bool rewardGiven;

		[Tooltip("The prefab to use for the reward pickup.")]
		[SerializeField]
		public GameObject rewardPickupPrefab;

		[SerializeField]
		public PickupDropTable rewardDropTable;

		[SerializeField]
		public int rewardOptionCount = 1;

		[SerializeField]
		public ItemTier rewardDisplayTier;

		[SerializeField]
		public UnityEngine.Vector3 rewardOffset;

		[SerializeField]
		public float cleansingDuration = 6f;

		[SerializeField]
		public float cleansingTicksPerSecond = 1.5f;

		protected Xoroshiro128Plus rng;

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/GeodeShatterVFX"), new EffectData
			{
				origin = base.gameObject.transform.position
			}, transmit: false);
			Util.PlaySound("Play_env_meridian_geode_activate", base.gameObject);
			Util.PlaySound("Play_env_meridian_geode_active_loop", base.gameObject);
			cleansingIndicator.SetActive(value: true);
			sphereSearch = new SphereSearch();
			CharacterBody characterBody = geodeController.lastInteractor?.GetComponent<CharacterBody>();
			if (!geodeController.ShouldRegenerate)
			{
				geodeBase.SetActive(value: false);
			}
			geodeTrunkRenderer.material.SetFloat(sliceHeightNameId, geodeController.startingPrintHeight);
			geodeIdleVFX.SetActive(value: false);
			geodeModel.SetActive(value: false);
			if (!NetworkServer.active)
			{
				return;
			}
			if ((bool)characterBody && characterBody.HasBuff(DLC2Content.Buffs.GeodeBuff) && geodeController.ShouldDropReward)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
				RemoveGeodeBuffFromAllPlayers();
				int participatingPlayerCount = Run.instance.participatingPlayerCount;
				if (!(base.gameObject == null) && !(rewardDropTable == null) && participatingPlayerCount != 0 && participatingPlayerCount > 0 && (bool)base.gameObject && (bool)rewardDropTable && !rewardGiven)
				{
					rewardGiven = true;
					int num = participatingPlayerCount;
					float angle = 360f / (float)num;
					UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
					UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
					UnityEngine.Vector3 position = base.gameObject.transform.position + rewardOffset;
					int num2 = 0;
					while (num2 < num)
					{
						GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo);
						pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier);
						pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, rewardDropTable, rng);
						pickupInfo.rotation = UnityEngine.Quaternion.identity;
						pickupInfo.prefabOverride = rewardPickupPrefab;
						PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector);
						num2++;
						vector = quaternion * vector;
					}
				}
			}
			else
			{
				RemoveGeodeBuffFromAllPlayers();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= cleansingDuration)
			{
				cleansingActive = false;
				Util.PlaySound("Stop_env_meridian_geode_active_loop", base.gameObject);
				outer.SetNextState(new GeodeInert());
			}
			else
			{
				if (!cleansingActive)
				{
					return;
				}
				stopWatch += Time.deltaTime;
				if (stopWatch > 1f / cleansingTicksPerSecond && sphereSearch != null)
				{
					stopWatch -= 1f / cleansingTicksPerSecond;
					if (NetworkServer.active)
					{
						HandleCleanseNearbyPlayers();
					}
				}
			}
		}

		private void HandleCleanseNearbyPlayers()
		{
			hitHurtBoxes = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			SearchForPlayers(hitHurtBoxes);
			for (int i = 0; i < hitHurtBoxes.Count; i++)
			{
				HurtBox hurtBox = hitHurtBoxes[i];
				CharacterBody body = hurtBox.healthComponent.body;
				bool isPlayerControlled = body.isPlayerControlled;
				if ((bool)hurtBox && hurtBox.healthComponent.alive && isPlayerControlled && !body.HasBuff(DLC2Content.Buffs.GeodeBuff))
				{
					Util.PlaySound("Play_env_meridian_geode_cleanse_debuff", body.gameObject);
					Util.CleanseBody(body, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: true, removeDots: true, removeStun: true, removeNearbyProjectiles: true);
					hurtBox.healthComponent.AddBarrier(hurtBox.healthComponent.fullHealth * geodeController.barrierToHealthPercentage);
					body.AddBuff(DLC2Content.Buffs.GeodeBuff);
				}
			}
		}

		protected void RemoveGeodeBuffFromAllPlayers()
		{
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterBody currentBody = instance.networkUser.GetCurrentBody();
				if (currentBody.HasBuff(DLC2Content.Buffs.GeodeBuff))
				{
					currentBody.RemoveBuff(DLC2Content.Buffs.GeodeBuff);
				}
			}
		}

		protected void SearchForPlayers(List<HurtBox> dest)
		{
			TeamMask mask = default(TeamMask);
			mask.AddTeam(TeamIndex.Player);
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.origin = base.gameObject.transform.position;
			sphereSearch.radius = geodeController.geodeBuffRadius;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByHurtBoxTeam(mask);
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			sphereSearch.GetHurtBoxes(dest);
			sphereSearch.ClearCandidates();
		}
	}
	public class GeodeInert : GeodeEntityStates
	{
		[SerializeField]
		public float reactivationDuration;

		public override void OnEnter()
		{
			base.OnEnter();
			cleansingIndicator.SetActive(value: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= reactivationDuration && geodeController.ShouldRegenerate)
			{
				outer.SetNextState(new GeodeRegenerate());
			}
			else if (!geodeController.ShouldRegenerate)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
	public class GeodeRegenerate : GeodeEntityStates
	{
		private new float age;

		public override void OnEnter()
		{
			base.OnEnter();
			geodeModel.SetActive(value: true);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			age += Time.deltaTime;
			float printThreshold = geodeController.printCurve.Evaluate(age / geodeController.printTime);
			SetPrintThreshold(printThreshold);
			if (age >= geodeController.idleVFXRegenerationTimer && !geodeIdleVFX.activeInHierarchy)
			{
				geodeIdleVFX.SetActive(value: true);
			}
			if (age >= geodeController.printTime)
			{
				if (NetworkServer.active)
				{
					geodeController.SetAvailable(activeState: true);
				}
				outer.SetNextState(new GeodeEntityStates());
			}
		}

		private void SetPrintThreshold(float sample)
		{
			float num = 1f - sample;
			float value = sample * geodeController.maxPrintHeight + num * geodeController.startingPrintHeight;
			geodeTrunkRenderer.material.SetFloat(sliceHeightNameId, value);
		}

		public override void OnExit()
		{
			base.OnExit();
			age = 0f;
		}
	}
}
namespace EntityStates.GameOver
{
	public class BaseGameOverControllerState : BaseState
	{
		protected GameOverController gameOverController { get; private set; }

		protected GameEndingDef gameEnding { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			gameOverController = GetComponent<GameOverController>();
			gameEnding = gameOverController.runReport.gameEnding;
		}
	}
	public class RoR2MainEndingStart : BaseGameOverControllerState
	{
		public static float duration = 6f;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				outer.SetNextState(new RoR2MainEndingSetSceneAndWaitForPlayers());
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class RoR2MainEndingSetSceneAndWaitForPlayers : BaseGameOverControllerState
	{
		private SceneDef desiredSceneDef;

		public override void OnEnter()
		{
			base.OnEnter();
			FadeToBlackManager.ForceFullBlack();
			FadeToBlackManager.fadeCount++;
			desiredSceneDef = SceneCatalog.GetSceneDefFromSceneName("outro");
			if (NetworkServer.active)
			{
				Run.instance.AdvanceStage(desiredSceneDef);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && NetworkUser.AllParticipatingNetworkUsersReady() && SceneCatalog.mostRecentSceneDef == desiredSceneDef)
			{
				outer.SetNextState(new RoR2MainEndingPlayCutscene());
			}
		}

		public override void OnExit()
		{
			FadeToBlackManager.fadeCount--;
			base.OnExit();
		}
	}
	public class RoR2MainEndingPlayCutscene : BaseGameOverControllerState
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (!OutroCutsceneController.instance || OutroCutsceneController.instance.cutsceneIsFinished))
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)OutroCutsceneController.instance && (bool)OutroCutsceneController.instance.playableDirector)
			{
				OutroCutsceneController.instance.playableDirector.time = OutroCutsceneController.instance.playableDirector.duration;
			}
			base.OnExit();
		}
	}
	public class LingerShort : BaseGameOverControllerState
	{
		private static readonly float duration = 3f;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class FinishEndingContent : BaseGameOverControllerState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				outer.SetNextState(base.gameEnding.showCredits ? ((BaseGameOverControllerState)new ShowCredits()) : ((BaseGameOverControllerState)new ShowReport()));
			}
		}
	}
	public class ShowCredits : BaseGameOverControllerState
	{
		private GameObject creditsControllerInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				creditsControllerInstance = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/CreditsController"));
				NetworkServer.Spawn(creditsControllerInstance);
			}
		}

		public override void OnExit()
		{
			if (NetworkServer.active && (bool)creditsControllerInstance)
			{
				EntityState.Destroy(creditsControllerInstance);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && !creditsControllerInstance)
			{
				outer.SetNextState(new ShowReport());
			}
		}
	}
	public class ShowReport : BaseGameOverControllerState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkClient.active)
			{
				base.gameOverController.shouldDisplayGameEndReportPanels = true;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class RebirthEndingFadeToBlack : BaseGameOverControllerState
	{
		[SerializeField]
		public float delay;

		[SerializeField]
		public float duration;

		[SerializeField]
		public GameObject screenPrefab;

		private Run.TimeStamp startTime;

		private UnityEngine.UI.Image image;

		private GameObject screenInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				startTime = Run.TimeStamp.now + delay;
			}
			screenInstance = UnityEngine.Object.Instantiate(screenPrefab, RoR2Application.instance.mainCanvas.transform);
			image = screenInstance.GetComponentInChildren<UnityEngine.UI.Image>();
			image.raycastTarget = false;
			UpdateImageAlpha(0f);
		}

		public override void OnExit()
		{
			FadeToBlackManager.ForceFullBlack();
			EntityState.Destroy(screenInstance);
			screenInstance = null;
			image = null;
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(startTime);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			startTime = reader.ReadTimeStamp();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			UpdateImageAlpha(Mathf.Max(0f, Mathf.Min(1f, startTime.timeSince / duration)));
			if (NetworkServer.active && (startTime + duration).hasPassed)
			{
				outer.SetNextStateToMain();
			}
		}

		private void UpdateImageAlpha(float finalAlpha)
		{
			UnityEngine.Color color = image.color;
			color.a = finalAlpha;
			image.color = color;
		}
	}
	public class RebirthEndingStart : BaseGameOverControllerState
	{
		[SerializeField]
		public float duration;

		private bool hasSceneExited;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration && hasSceneExited)
			{
				outer.SetNextState(new RebirthEndingFadeToBlack());
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			SceneExitController.onFinishExit += OnFinishSceneExit;
		}

		public override void OnExit()
		{
			SceneExitController.onFinishExit -= OnFinishSceneExit;
			base.OnExit();
		}

		private void OnFinishSceneExit(SceneExitController obj)
		{
			hasSceneExited = true;
		}
	}
	public class VoidEndingFadeToBlack : BaseGameOverControllerState
	{
		[SerializeField]
		public float delay;

		[SerializeField]
		public float duration;

		[SerializeField]
		public GameObject screenPrefab;

		private Run.TimeStamp startTime;

		private UnityEngine.UI.Image image;

		private GameObject screenInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				startTime = Run.TimeStamp.now + delay;
			}
			screenInstance = UnityEngine.Object.Instantiate(screenPrefab, RoR2Application.instance.mainCanvas.transform);
			image = screenInstance.GetComponentInChildren<UnityEngine.UI.Image>();
			image.raycastTarget = false;
			UpdateImageAlpha(0f);
		}

		public override void OnExit()
		{
			FadeToBlackManager.ForceFullBlack();
			EntityState.Destroy(screenInstance);
			screenInstance = null;
			image = null;
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(startTime);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			startTime = reader.ReadTimeStamp();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			UpdateImageAlpha(Mathf.Max(0f, Mathf.Min(1f, startTime.timeSince / duration)));
			if (NetworkServer.active && (startTime + duration).hasPassed)
			{
				outer.SetNextStateToMain();
			}
		}

		private void UpdateImageAlpha(float finalAlpha)
		{
			UnityEngine.Color color = image.color;
			color.a = finalAlpha;
			image.color = color;
		}
	}
	public class VoidEndingPlayCutscene : BaseGameOverControllerState
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (!OutroCutsceneController.instance || OutroCutsceneController.instance.cutsceneIsFinished))
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)OutroCutsceneController.instance && (bool)OutroCutsceneController.instance.playableDirector)
			{
				OutroCutsceneController.instance.playableDirector.time = OutroCutsceneController.instance.playableDirector.duration;
			}
			base.OnExit();
		}
	}
	public class VoidEndingSetSceneAndWaitForPlayers : BaseGameOverControllerState
	{
		[SerializeField]
		public SceneDef desiredSceneDef;

		public override void OnEnter()
		{
			base.OnEnter();
			FadeToBlackManager.ForceFullBlack();
			FadeToBlackManager.fadeCount++;
			if (NetworkServer.active)
			{
				Run.instance.AdvanceStage(desiredSceneDef);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && NetworkUser.AllParticipatingNetworkUsersReady() && SceneCatalog.mostRecentSceneDef == desiredSceneDef)
			{
				outer.SetNextState(new VoidEndingPlayCutscene());
			}
		}

		public override void OnExit()
		{
			FadeToBlackManager.fadeCount--;
			base.OnExit();
		}
	}
	public class VoidEndingStart : BaseGameOverControllerState
	{
		[SerializeField]
		public float duration;

		private bool hasSceneExited;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration && hasSceneExited)
			{
				outer.SetNextState(new VoidEndingFadeToBlack());
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			SceneExitController.onFinishExit += OnFinishSceneExit;
		}

		public override void OnExit()
		{
			SceneExitController.onFinishExit -= OnFinishSceneExit;
			base.OnExit();
		}

		private void OnFinishSceneExit(SceneExitController obj)
		{
			hasSceneExited = true;
		}
	}
}
namespace EntityStates.FlyingVermin
{
	public class FallingDeath : GenericCharacterDeath
	{
		public static float initialVerticalVelocity;

		public static float deathDelay;

		public static GameObject deathEffectPrefab;

		private bool hasDied;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity.y = initialVerticalVelocity;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > deathDelay && NetworkServer.active && !hasDied)
			{
				hasDied = true;
				EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: true);
				DestroyBodyAsapServer();
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
	}
}
namespace EntityStates.FlyingVermin.Weapon
{
	public class Spit : GenericProjectileBaseState
	{
		private static int SpitStateHash = Animator.StringToHash("Spit");

		private static int SpitParamHash = Animator.StringToHash("Spit.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(5f);
			}
		}

		protected override void PlayAnimation(float duration)
		{
			base.PlayAnimation(duration);
			PlayAnimation("Gesture, Additive", SpitStateHash, SpitParamHash, duration);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		protected override void FireProjectile()
		{
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				aimRay = ModifyProjectileAimRay(aimRay);
				aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, 0f, projectilePitchBonus);
				float damage = damageStat * damageCoefficient;
				BaseAI component = outer.commonComponents.characterBody.master.GetComponent<BaseAI>();
				if ((object)component != null && component.shouldMissFirstOffScreenShot && component.currentEnemy.characterBody.teamComponent.teamIndex == TeamIndex.Player)
				{
					component.shouldMissFirstOffScreenShot = false;
					aimRay.direction = OffScreenMissHelper.ApplyRandomTrajectoryOffset(aimRay.direction);
					damage = 0f;
				}
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damage, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}
	}
}
namespace EntityStates.FlyingVermin.Mode
{
	public class GrantFlight : BaseState
	{
		protected ICharacterGravityParameterProvider characterGravityParameterProvider;

		protected ICharacterFlightParameterProvider characterFlightParameterProvider;

		public override void OnEnter()
		{
			base.OnEnter();
			characterGravityParameterProvider = base.gameObject.GetComponent<ICharacterGravityParameterProvider>();
			characterFlightParameterProvider = base.gameObject.GetComponent<ICharacterFlightParameterProvider>();
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount++;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount++;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
		}

		public override void OnExit()
		{
			if (characterFlightParameterProvider != null)
			{
				CharacterFlightParameters flightParameters = characterFlightParameterProvider.flightParameters;
				flightParameters.channeledFlightGranterCount--;
				characterFlightParameterProvider.flightParameters = flightParameters;
			}
			if (characterGravityParameterProvider != null)
			{
				CharacterGravityParameters gravityParameters = characterGravityParameterProvider.gravityParameters;
				gravityParameters.channeledAntiGravityGranterCount--;
				characterGravityParameterProvider.gravityParameters = gravityParameters;
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.Fauna
{
	public class BirdsharkDeathState : BaseState
	{
		[SerializeField]
		public GameObject initialExplosion;

		[SerializeField]
		public string deathSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(deathSoundString, base.gameObject);
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if ((bool)initialExplosion && NetworkServer.active)
			{
				EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true);
			}
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class VultureEggDeathState : BirdsharkDeathState
	{
		public static int healPackCount;

		public static float healPackMaxVelocity;

		public static float fractionalHealing;

		public static float scale;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				for (int i = 0; i < healPackCount; i++)
				{
					GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/HealPack"), base.transform.position, UnityEngine.Random.rotation);
					obj.GetComponent<TeamFilter>().teamIndex = TeamIndex.Player;
					obj.GetComponentInChildren<HealthPickup>().fractionalHealing = fractionalHealing;
					obj.transform.localScale = new UnityEngine.Vector3(scale, scale, scale);
					obj.GetComponent<Rigidbody>().AddForce(UnityEngine.Random.insideUnitSphere * healPackMaxVelocity, ForceMode.VelocityChange);
					NetworkServer.Spawn(obj);
				}
			}
		}
	}
	public class HabitatFruitDeathState : BaseState
	{
		[SerializeField]
		public static GameObject initialExplosion;

		[SerializeField]
		public static string deathSoundString;

		public static int healPackCount;

		public static float healPackMaxVelocity;

		public static float fractionalHealing;

		public static float scale;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(deathSoundString, base.gameObject);
			if ((bool)initialExplosion && NetworkServer.active)
			{
				EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true);
			}
			if (NetworkServer.active)
			{
				for (int i = 0; i < healPackCount; i++)
				{
					GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/HealPack"), base.transform.position, UnityEngine.Random.rotation);
					obj.GetComponent<TeamFilter>().teamIndex = TeamIndex.Player;
					obj.GetComponentInChildren<HealthPickup>().fractionalHealing = fractionalHealing;
					obj.transform.localScale = new UnityEngine.Vector3(scale, scale, scale);
					obj.GetComponent<Rigidbody>().AddForce(UnityEngine.Random.insideUnitSphere * healPackMaxVelocity, ForceMode.VelocityChange);
					NetworkServer.Spawn(obj);
				}
			}
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.FalseSonBoss
{
	public class ClubForsakenBoss : BaseSkillState
	{
		[SerializeField]
		public float baseChargeDuration = 1f;

		public static float minChargeForChargedAttack;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private Transform chargeVfxInstanceTransform;

		private int gauntlet;

		private uint soundID;

		private bool chargeAnimPlayed;

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = baseChargeDuration;
			Util.PlaySound(enterSFXString, base.gameObject);
			soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnExit()
		{
			if ((bool)chargeVfxInstanceTransform)
			{
				EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
				PlayAnimation("Gesture, Additive", "Empty");
				PlayAnimation("Gesture, Override", "Empty");
				crosshairOverrideRequest?.Dispose();
				chargeVfxInstanceTransform = null;
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			Util.PlaySound(endChargeLoopSFXString, base.gameObject);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			AkSoundEngine.SetRTPCValueByPlayingID("loaderShift_chargeAmount", charge * 100f, soundID);
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab)
			{
				if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
				}
				Transform transform = FindModelChild(chargeVfxChildLocatorName);
				if ((bool)transform)
				{
					chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform;
					ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration;
					}
				}
				if (!chargeAnimPlayed)
				{
					PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					chargeAnimPlayed = true;
				}
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		public override void Update()
		{
			base.Update();
			Mathf.Clamp01(base.age / chargeDuration);
		}

		private void AuthorityFixedUpdate()
		{
			ShouldKeepChargingAuthority();
		}

		protected virtual bool ShouldKeepChargingAuthority()
		{
			return IsKeyDownAuthority();
		}
	}
	public class CorruptedPaths : BaseCharacterMain
	{
		[SerializeField]
		public float baseDuration;

		public float charge;

		public static float minimumDuration;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static string enterSoundString;

		public static UnityEngine.Vector3 blastBonusForce;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static GameObject fistEffectPrefab;

		public static GameObject swingEffectPrefab;

		private GameObject leftFistEffectInstance;

		private GameObject rightFistEffectInstance;

		private GameObject swingEffectInstance;

		private bool detonateNextFrame;

		public override void OnEnter()
		{
			base.OnEnter();
			baseDuration /= attackSpeedStat;
			PlayAnimation("FullBody, Override", "ChargeSwing", "ChargeSwing.playbackRate", baseDuration);
			Util.PlaySound(enterSoundString, base.gameObject);
			swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, FindModelChild("OverHeadSwingPoint"));
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= minimumDuration)
			{
				DetonateAuthority();
				if (base.characterBody.GetBuffCount(DLC2Content.Buffs.CorruptionFesters) == 0)
				{
					outer.SetNextState(new CorruptedPathsDash());
				}
				else
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = position,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * (blastDamageCoefficient * charge) + (base.characterBody.maxHealth - (base.characterBody.baseMaxHealth + base.characterBody.levelMaxHealth * (float)((int)base.characterBody.level - 1))) * 0.01f,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = position,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class CorruptedPathsDash : BaseState
	{
		private Transform modelTransform;

		public static GameObject dashPrefab;

		public static float smallHopVelocity = 0.35f;

		public static float dashPrepDuration = 0.8f;

		public static float dashDuration = 0.05f;

		public static float speedCoefficient = 15f;

		public static float gapToEnemy = 0f;

		public static string beginSoundString;

		public static string endSoundString;

		public static float damageCoefficient = 2f;

		public static float procCoefficient;

		public static GameObject hitEffectPrefab;

		public static float hitPauseDuration;

		private float stopwatch;

		private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private OverlapAttack overlapAttack;

		private ChildLocator childLocator;

		private bool isDashing;

		private bool inHitPause;

		private float hitPauseTimer;

		private CameraTargetParams.AimRequest aimRequest;

		private CharacterBody survivorBody;

		public static GameObject explosionEffect;

		public BlastAttack explosionAttack;

		private float maxHealth;

		private int originalLayer;

		public bool hasHit { get; private set; }

		public int dashIndex { private get; set; }

		public override void OnEnter()
		{
			base.OnEnter();
			dashDuration = UnityEngine.Vector3.Distance(base.characterBody.master.GetComponent<BaseAI>().currentEnemy.characterBody.transform.position, base.transform.position) * 0.1f / speedCoefficient - gapToEnemy;
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			survivorBody = base.gameObject.GetComponent<CharacterBody>();
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
				childLocator = modelTransform.GetComponent<ChildLocator>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
				_ = (bool)childLocator;
			}
			SmallHop(base.characterMotor, smallHopVelocity);
			PlayAnimation("FullBody, Override", "StepBrothersPrep", "StepBrothersPrep.playbackRate", dashPrepDuration);
			dashVector = base.inputBank.aimDirection;
			overlapAttack = InitMeleeOverlap(0f, hitEffectPrefab, modelTransform, "StepBrothers");
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
		}

		private void CreateDashEffect()
		{
			Transform transform = childLocator.FindChild("DashCenter");
			if ((bool)transform && (bool)dashPrefab)
			{
				UnityEngine.Object.Instantiate(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterDirection.forward = dashVector;
			if (stopwatch > dashPrepDuration && !isDashing)
			{
				isDashing = true;
				dashVector = base.inputBank.aimDirection;
				CreateDashEffect();
				PlayCrossfade("FullBody, Override", "StepBrothersLoop", 0.1f);
				originalLayer = base.gameObject.layer;
				base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
				base.characterMotor.Motor.RebuildCollidableLayers();
			}
			if (!isDashing)
			{
				stopwatch += GetDeltaTime();
			}
			else if (base.isAuthority)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				if (!inHitPause)
				{
					bool num = overlapAttack.Fire();
					stopwatch += GetDeltaTime();
					if (num)
					{
						UnityEngine.Vector3 position = base.gameObject.transform.position;
						EffectManager.SpawnEffect(explosionEffect, new EffectData
						{
							origin = position,
							scale = 1f
						}, transmit: true);
						explosionAttack = new BlastAttack();
						explosionAttack.attacker = base.gameObject;
						explosionAttack.inflictor = base.gameObject;
						explosionAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
						explosionAttack.baseDamage = damageStat * damageCoefficient;
						explosionAttack.position = position;
						explosionAttack.radius = 20f;
						explosionAttack.Fire();
						if (!hasHit)
						{
							hasHit = true;
						}
						inHitPause = true;
						hitPauseTimer = hitPauseDuration / attackSpeedStat;
					}
					base.characterMotor.rootMotion += dashVector * moveSpeedStat * speedCoefficient * GetDeltaTime();
				}
				else
				{
					hitPauseTimer -= GetDeltaTime();
					if (hitPauseTimer < 0f)
					{
						inHitPause = false;
					}
				}
			}
			if (stopwatch >= dashDuration + dashPrepDuration && base.isAuthority)
			{
				outer.SetNextState(GetNextStateAuthority());
			}
		}

		public override void OnExit()
		{
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			Util.PlaySound(endSoundString, base.gameObject);
			if (base.isAuthority)
			{
				base.characterMotor.velocity *= -0.3f;
				SmallHop(base.characterMotor, smallHopVelocity);
			}
			aimRequest?.Dispose();
			_ = (bool)childLocator;
			PlayAnimation("FullBody, Override", "StepBrothersLoopExit");
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)dashIndex);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			dashIndex = reader.ReadByte();
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			return new FissureSlam();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class CrystalDeathState : GenericCharacterDeath
	{
		public static GameObject deathEffectPrefab;

		public static float duration = 3f;

		public float vfxSize = 8f;

		private bool playedSFX;

		private bool _shouldAutoDestroy;

		protected override bool shouldAutoDestroy => _shouldAutoDestroy;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayAnimation("FullBody, Override", "Phase1Death", "StepBrothersPrep.playbackRate", duration);
			MeridianEventTriggerInteraction.instance.musicPhaseOne.SetActive(value: false);
			MeridianEventTriggerInteraction.instance.musicPhaseTwo.SetActive(value: true);
		}

		public override void FixedUpdate()
		{
			if (base.fixedAge >= 2f && !playedSFX)
			{
				Util.PlaySound("Play_boss_falseson_phaseTransition_kneel", base.characterBody.gameObject);
				Util.PlaySound("Play_boss_falseson_VO_groan", base.gameObject);
				playedSFX = true;
			}
			if (!_shouldAutoDestroy && NetworkServer.active && base.fixedAge >= duration + 0.5f)
			{
				EffectManager.SpawnEffect(deathEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = vfxSize
				}, transmit: true);
				_shouldAutoDestroy = true;
			}
			base.FixedUpdate();
		}

		public override void OnExit()
		{
			DestroyBodyAsapServer();
			DestroyModel();
			base.OnExit();
			MeridianEventTriggerInteraction.FSBFPhaseBaseState.readyToSpawnNextBossBody = true;
			DestroyBodyServer();
		}

		private void DestroyBodyServer()
		{
			if (NetworkServer.active)
			{
				OnPreDestroyBodyServer();
				EntityState.Destroy(base.gameObject);
			}
		}
	}
	public class BrokenCrystalDeathState : GenericCharacterDeath
	{
		public static float duration = 3f;

		public static GameObject deathEffectPrefab;

		public float vfxSize = 8f;

		private bool playedSFX;

		private bool _shouldAutoDestroy;

		protected override bool shouldAutoDestroy => _shouldAutoDestroy;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			MeridianEventTriggerInteraction.instance.musicPhaseTwo.SetActive(value: false);
			MeridianEventTriggerInteraction.instance.musicPhaseThree.SetActive(value: true);
			PlayAnimation("FullBody, Override", "Phase2Death", "StepBrothersPrep.playbackRate", duration);
		}

		public override void FixedUpdate()
		{
			if (base.fixedAge >= 2f && !playedSFX)
			{
				Util.PlaySound("Play_boss_falseson_phaseTransition_kneel", base.characterBody.gameObject);
				Util.PlaySound("Play_boss_falseson_VO_anger", base.characterBody.gameObject);
				playedSFX = true;
			}
			if (!_shouldAutoDestroy && NetworkServer.active && (double)base.fixedAge >= (double)duration + 0.5)
			{
				_shouldAutoDestroy = true;
				EffectManager.SpawnEffect(deathEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = vfxSize
				}, transmit: true);
			}
			base.FixedUpdate();
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
			MeridianEventTriggerInteraction.FSBFPhaseBaseState.readyToSpawnNextBossBody = true;
			DestroyBodyServer();
		}

		private void DestroyBodyServer()
		{
			if (NetworkServer.active)
			{
				OnPreDestroyBodyServer();
				EntityState.Destroy(base.gameObject);
			}
		}
	}
	public class SkyJumpDeathState : GenericCharacterDeath
	{
		[SerializeField]
		public float duration = 4.5f;

		public GameObject deathEffectPrefab;

		public float vfxSize = 8f;

		private float beginUpwardMovementTime = 0.96086955f;

		private bool startedFlying;

		private UnityEngine.Vector3 cachedDeathPosition;

		private bool _shouldAutoDestroy;

		[SerializeField]
		public GameObject falseSonJumpAwayVFX;

		[SerializeField]
		public ItemTier rewardDisplayTier;

		[Tooltip("The prefab to use for the reward pickup.")]
		[SerializeField]
		public GameObject rewardPickupPrefab;

		[SerializeField]
		public UnityEngine.Vector3 rewardOffset;

		[SerializeField]
		public string falseSonSurvivorAchievement;

		private PickupIndex halcyonSeed;

		[SerializeField]
		public int rewardOptionCount = 1;

		[SerializeField]
		public PickupDropTable dtColossusBuffDropTable;

		public bool rewardGiven;

		private bool playedSFX;

		protected override bool shouldAutoDestroy => _shouldAutoDestroy;

		public static event Action falseSonDeathEvent;

		public static event Action falseSonUnlockEvent;

		public override void OnEnter()
		{
			base.OnEnter();
			SkyJumpDeathState.falseSonDeathEvent?.Invoke();
			beginUpwardMovementTime *= duration;
			cachedDeathPosition = base.gameObject.transform.position;
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("FalseSonBoss/FalseSonBossLightningStreakDeath"), new EffectData
			{
				origin = base.characterBody.corePosition,
				scale = vfxSize
			}, transmit: true);
			halcyonSeed = PickupCatalog.FindPickupIndex("TitanGoldDuringTP");
			GiveColossusItem();
		}

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayAnimation("FullBody, Override", "Phase3Death", "StepBrothersPrep.playbackRate", duration);
			Util.PlaySound("Play_boss_falseson_VO_defeat", base.gameObject);
			MeridianEventTriggerInteraction.instance.musicPhaseThree.SetActive(value: false);
			MeridianEventTriggerInteraction.instance.musicPhaseBossDead.SetActive(value: true);
		}

		public override void FixedUpdate()
		{
			if (base.fixedAge >= 0.35f && !playedSFX)
			{
				Util.PlaySound("Play_boss_falseson_phaseTransition_kneel", base.characterBody.gameObject);
				Util.PlaySound("Play_boss_falseson_VO_groan", base.characterBody.gameObject);
				playedSFX = true;
			}
			if (base.fixedAge > beginUpwardMovementTime)
			{
				if (!startedFlying)
				{
					if (NetworkServer.active)
					{
						LightningStormController.SetStormActive(b: false);
					}
					startedFlying = true;
					EffectManager.SpawnEffect(falseSonJumpAwayVFX, new EffectData
					{
						origin = cachedDeathPosition
					}, transmit: false);
				}
				base.characterMotor.rootMotion += UnityEngine.Vector3.up * moveSpeedStat;
			}
			if (!_shouldAutoDestroy && NetworkServer.active && base.fixedAge >= duration + 0.5f)
			{
				_shouldAutoDestroy = true;
			}
			base.FixedUpdate();
		}

		public override void OnExit()
		{
			DestroyBodyAsapServer();
			DestroyModel();
			base.OnExit();
			MeridianEventTriggerInteraction.FSBFPhaseBaseState.readyToSpawnNextBossBody = true;
			DestroyBodyServer();
		}

		private void DestroyBodyServer()
		{
			if (NetworkServer.active)
			{
				OnPreDestroyBodyServer();
				EntityState.Destroy(base.gameObject);
			}
		}

		private void GiveColossusItem()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (dtColossusBuffDropTable == null || participatingPlayerCount == 0)
			{
				return;
			}
			if (FalseSonUnlockStateMet())
			{
				SkyJumpDeathState.falseSonUnlockEvent?.Invoke();
				dtColossusBuffDropTable = LegacyResourcesAPI.Load<PickupDropTable>("DropTables/dtAurelioniteHeartPickupDropTable");
			}
			Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			if (participatingPlayerCount > 0 && (bool)base.gameObject && (bool)dtColossusBuffDropTable && !rewardGiven)
			{
				rewardGiven = true;
				int num = participatingPlayerCount;
				float angle = 360f / (float)num;
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				UnityEngine.Vector3 position = cachedDeathPosition + rewardOffset;
				int num2 = 0;
				while (num2 < num)
				{
					GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo);
					pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier);
					pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, dtColossusBuffDropTable, rng);
					pickupInfo.rotation = UnityEngine.Quaternion.identity;
					pickupInfo.prefabOverride = rewardPickupPrefab;
					PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector);
					num2++;
					vector = quaternion * vector;
				}
			}
		}

		private bool FalseSonUnlockStateMet()
		{
			bool result = false;
			if (MeridianEventTriggerInteraction.instance.isGoldTitanSpawned)
			{
				return true;
			}
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (!(instance == null) && instance.master.inventory.GetItemCount(RoR2Content.Items.TitanGoldDuringTP) > 0)
				{
					result = true;
					GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/DelusionItemDissolveVFX");
					EffectData effectData = new EffectData
					{
						origin = instance.master.GetBody().transform.position,
						genericFloat = 1.5f,
						genericUInt = (uint)(halcyonSeed.itemIndex + 1)
					};
					effectData.SetNetworkedObjectReference(base.gameObject);
					EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
					instance.master.inventory.RemoveItem(halcyonSeed.itemIndex);
				}
			}
			return result;
		}
	}
	public class FalseSonBossGenericStateWithSwing : GenericCharacterMain
	{
		private bool transitioningToMeleeSwingState;

		public override void OnEnter()
		{
			base.OnEnter();
			transitioningToMeleeSwingState = false;
		}

		public override void Update()
		{
			if (base.characterBody == null || base.characterBody.coreTransform == null)
			{
				if (outer != null)
				{
					outer.SetNextStateToMain();
				}
				return;
			}
			base.Update();
			if (!transitioningToMeleeSwingState)
			{
				FalseSonBossStateHelper.TrySwitchToMeleeSwing(ref transitioningToMeleeSwingState, base.characterBody.coreTransform, base.characterDirection.forward, null, outer);
			}
		}

		public override void FixedUpdate()
		{
			if (!transitioningToMeleeSwingState)
			{
				base.FixedUpdate();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (transitioningToMeleeSwingState)
			{
				return InterruptPriority.Frozen;
			}
			return InterruptPriority.Any;
		}
	}
	public static class FalseSonBossStateHelper
	{
		private static int hitLimit = 2;

		private static float coolDownDuration = 2f;

		private static int hitCount = 0;

		private static float coolDownTimeStamp = -3f;

		private static float maxDistanceSquared = 225f;

		private static bool CheckPlayerOrMinionsForProximity(PlayerCharacterMasterController playerController, UnityEngine.Vector3 playerPosition, UnityEngine.Vector3 aimDirection, UnityEngine.Vector3 bossPosition)
		{
			UnityEngine.Vector3 vectorToCharacter;
			if (CharacterIsInFrontOfUs(playerPosition))
			{
				return true;
			}
			MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(playerController.master.netId);
			if (minionGroup == null || minionGroup.memberCount < 1)
			{
				return false;
			}
			MinionOwnership[] members = minionGroup.members;
			foreach (MinionOwnership minionOwnership in members)
			{
				if (!(minionOwnership == null))
				{
					UnityEngine.Vector3 value = (minionOwnership.GetComponent<CharacterMaster>()?.GetBody()?.corePosition).Value;
					if (value != UnityEngine.Vector3.zero && CharacterIsInFrontOfUs(value))
					{
						return true;
					}
				}
			}
			return false;
			bool CharacterIsInFrontOfUs(UnityEngine.Vector3 position)
			{
				vectorToCharacter = position - bossPosition;
				if (UnityEngine.Vector3.SqrMagnitude(vectorToCharacter) > maxDistanceSquared)
				{
					return false;
				}
				if (UnityEngine.Vector3.Dot(vectorToCharacter.normalized, aimDirection) <= 0f)
				{
					return false;
				}
				return true;
			}
		}

		public static bool TrySwitchToMeleeSwing(ref bool stateAborted, Transform bossTransform, UnityEngine.Vector3 aimDirection, GenericSkill previousSkill, EntityStateMachine outer)
		{
			if (bossTransform == null)
			{
				return false;
			}
			if (PlatformSystems.networkManager.serverFixedTime - coolDownTimeStamp < coolDownDuration)
			{
				return false;
			}
			stateAborted = false;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (!(instance == null))
				{
					CharacterBody body = instance.master.GetBody();
					if (!(body == null) && CheckPlayerOrMinionsForProximity(instance, body.corePosition, aimDirection, bossTransform.position))
					{
						stateAborted = true;
						break;
					}
				}
			}
			if (stateAborted)
			{
				outer.SetNextState(new SwatAwayPlayersWindup());
				if ((bool)previousSkill)
				{
					previousSkill.Reset();
				}
				hitCount++;
				if (hitCount >= hitLimit)
				{
					coolDownTimeStamp = PlatformSystems.networkManager.serverFixedTime;
					hitCount = 0;
				}
			}
			return stateAborted;
		}
	}
	public class FissureSlam : BaseCharacterMain
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public int totalFissures = 5;

		[SerializeField]
		public float delayBetweenFissures = 0.001f;

		public float charge;

		public static float minimumDuration;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static string enterSoundString;

		public static UnityEngine.Vector3 blastBonusForce;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static GameObject fistEffectPrefab;

		public static GameObject swingEffectPrefab;

		public static GameObject fissureSlamObject;

		private GameObject leftFistEffectInstance;

		private GameObject rightFistEffectInstance;

		private GameObject swingEffectInstance;

		private bool detonateNextFrame;

		private bool amServer;

		private bool slamComplete;

		private float fissureExplosionDelay = 0.7f;

		private float fissureExplosionTimer;

		private NodeGraph nodeGraph;

		private List<NodeGraph.NodeIndex> possibleNodesToTarget;

		private List<GameObject> playersToTarget;

		private List<UnityEngine.Vector3> fissurePositions;

		private int totalFissuresFired;

		private float timeToGenerateNextFissure;

		public static GameObject crackWarningEffectPrefab;

		public static GameObject fissureExplosionEffectPrefab;

		public static GameObject pillarProjectilePrefab;

		private bool stateAborted;

		public override void OnEnter()
		{
			base.OnEnter();
			amServer = NetworkServer.active;
			baseDuration /= attackSpeedStat;
			PlayAnimation("FullBody, Override", "ChargeSwing", "ChargeSwing.playbackRate", baseDuration);
			Util.PlaySound(enterSoundString, base.gameObject);
			leftFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("HandR"));
			rightFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("HandL"));
			swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, FindModelChild("OverHeadSwingPoint"));
			nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			possibleNodesToTarget = nodeGraph.FindNodesInRange(base.characterBody.corePosition, 0f, 30f, HullMask.Human);
			playersToTarget = new List<GameObject>();
			fissurePositions = new List<UnityEngine.Vector3>();
			totalFissuresFired = 0;
			timeToGenerateNextFissure = 0f;
			if (!amServer)
			{
				return;
			}
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (!(instance == null) && !(instance.master.GetBodyObject() == null))
				{
					playersToTarget.Add(instance.master.GetBodyObject());
				}
			}
			Util.ShuffleList(playersToTarget);
			RaycastToFindGroundPointOfNextPlayer();
		}

		private void RaycastToFindGroundPointOfNextPlayer()
		{
			if (fissurePositions.Count >= totalFissures)
			{
				return;
			}
			if (fissurePositions.Count < playersToTarget.Count && playersToTarget.Count > 0)
			{
				if (Physics.Raycast(new Ray(playersToTarget[fissurePositions.Count].transform.position + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down), out var hitInfo, 200f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					fissurePositions.Add(hitInfo.point);
				}
				else
				{
					if (possibleNodesToTarget.Count < 1)
					{
						return;
					}
					int index = UnityEngine.Random.Range(0, possibleNodesToTarget.Count);
					nodeGraph.GetNodePosition(possibleNodesToTarget[index], out var position);
					fissurePositions.Add(position);
					possibleNodesToTarget.RemoveAt(index);
				}
			}
			if (fissurePositions.Count >= playersToTarget.Count)
			{
				FillRemainingFissurePositions();
			}
		}

		private void FillRemainingFissurePositions()
		{
			if (fissurePositions.Count >= totalFissures)
			{
				return;
			}
			int num = Mathf.Max(totalFissures - fissurePositions.Count, 0);
			for (int i = 0; i < num; i++)
			{
				if (possibleNodesToTarget.Count < 1)
				{
					break;
				}
				int index = UnityEngine.Random.Range(0, possibleNodesToTarget.Count);
				nodeGraph.GetNodePosition(possibleNodesToTarget[index], out var position);
				fissurePositions.Add(position);
				possibleNodesToTarget.RemoveAt(index);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (stateAborted)
			{
				return;
			}
			RaycastToFindGroundPointOfNextPlayer();
			if (!slamComplete && base.fixedAge >= baseDuration - baseDuration * 0.8f && amServer)
			{
				DetonateAuthority();
				slamComplete = true;
				FillRemainingFissurePositions();
				int num = Mathf.Min(totalFissures, fissurePositions.Count);
				for (int i = 0; i < num; i++)
				{
					EffectManager.SpawnEffect(crackWarningEffectPrefab, new EffectData
					{
						origin = fissurePositions[i] + UnityEngine.Vector3.up * 0.01f
					}, transmit: true);
				}
			}
			if (!slamComplete || !amServer)
			{
				return;
			}
			fissureExplosionTimer += Time.deltaTime;
			if (fissureExplosionTimer > fissureExplosionDelay)
			{
				int num2 = Mathf.Min(totalFissures, fissurePositions.Count);
				for (int j = 0; j < num2; j++)
				{
					ProjectileManager.instance.FireProjectile(pillarProjectilePrefab, fissurePositions[j], UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * (blastDamageCoefficient * 0.2f), 0f, Util.CheckRoll(base.characterBody.crit, base.characterBody.master));
				}
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (!stateAborted)
			{
				EntityState.Destroy(leftFistEffectInstance);
				EntityState.Destroy(rightFistEffectInstance);
				base.OnExit();
			}
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = position,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius + 3f,
				position = position,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	internal class List
	{
	}
	public class FissureSlamWindup : BaseSkillState
	{
		[SerializeField]
		public float baseChargeDuration = 1f;

		[SerializeField]
		public float chargeThreshold = 3f;

		public static float minChargeForChargedAttack;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private int gauntlet;

		private uint soundID;

		private Transform chargeVfxInstanceTransform;

		private bool chargeAnimPlayed;

		private bool stateAborted;

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = 0.5f;
			Util.PlaySound(enterSFXString, base.gameObject);
			soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject);
			if (base.characterBody.GetBuffCount(DLC2Content.Buffs.WeakenedBeating) > 0)
			{
				charge = 0.5f;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnExit()
		{
			if (!stateAborted)
			{
				if ((bool)chargeVfxInstanceTransform)
				{
					EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
					PlayAnimation("Gesture, Additive", "Empty");
					PlayAnimation("Gesture, Override", "Empty");
					chargeVfxInstanceTransform = null;
				}
				base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
				Util.PlaySound(endChargeLoopSFXString, base.gameObject);
				base.OnExit();
			}
		}

		public override void FixedUpdate()
		{
			if (stateAborted)
			{
				return;
			}
			base.FixedUpdate();
			charge += Time.deltaTime;
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge <= 3f && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab)
			{
				Transform transform = FindModelChild(chargeVfxChildLocatorName);
				if ((bool)transform)
				{
					chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform;
					ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration;
					}
				}
				if (!chargeAnimPlayed)
				{
					PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f);
					PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f);
					chargeAnimPlayed = true;
				}
			}
			else if (charge > baseChargeDuration)
			{
				outer.SetNextState(GetNextStateAuthority());
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			}
		}

		public override void Update()
		{
			if (!stateAborted)
			{
				base.Update();
				Mathf.Clamp01(base.age / chargeDuration);
			}
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			return new FissureSlam();
		}
	}
	public class HeroRelicSwing : BasicMeleeAttack
	{
		private float swingTimer;

		protected override void PlayAnimation()
		{
			string animationStateName = "SwingClubRight";
			float num = Mathf.Max(duration, 0.2f);
			PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", num, 0.1f);
			PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", num, 0.1f);
		}

		protected override void BeginMeleeAttackEffect()
		{
			swingEffectMuzzleString = "SwingRight";
			base.BeginMeleeAttackEffect();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			swingTimer += Time.deltaTime;
			if (swingTimer > baseDuration)
			{
				outer.SetNextState(GetNextStateAuthority());
			}
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			return new HeroRelicSwingLeft();
		}
	}
	public class HeroRelicSwingLeft : BasicMeleeAttack
	{
		private float swingTimer;

		protected override void PlayAnimation()
		{
			string animationStateName = "SwingClubLeft";
			float num = Mathf.Max(duration, 0.2f);
			PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", num, 0.1f);
			PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", num, 0.1f);
		}

		protected override void BeginMeleeAttackEffect()
		{
			swingEffectMuzzleString = "SwingLeft";
			base.BeginMeleeAttackEffect();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			swingTimer += Time.deltaTime;
			if (swingTimer > baseDuration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class LunarGazeCharge : BaseState
	{
		public static float baseDuration = 3f;

		public static float laserMaxWidth = 0.2f;

		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject laserPrefab;

		public static string chargeAttackSoundString;

		public static float lockOnAngle;

		private HurtBox lockedOnHurtBox;

		public float duration;

		private GameObject chargeEffect;

		private GameObject laserEffect;

		private LineRenderer laserLineComponent;

		private UnityEngine.Vector3 visualEndPosition;

		private float flashTimer;

		private bool laserOn;

		private BullseyeSearch enemyFinder;

		private const float originalSoundDuration = 2.1f;

		protected EntityState fireState;

		public override void OnEnter()
		{
			base.OnEnter();
			fireState = new LunarGazeFire();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", "LaserBlastStart", "LaserBlast.playbackRate", duration);
			PlayAnimation("Gesture, Override", "LaserBlastStart", "LaserBlast.playbackRate", duration);
			Transform modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(chargeAttackSoundString, base.gameObject, 2.1f / duration);
			Ray aimRay = GetAimRay();
			enemyFinder = new BullseyeSearch();
			if ((bool)base.characterBody)
			{
				enemyFinder.viewer = base.characterBody;
			}
			enemyFinder.maxDistanceFilter = 2000f;
			enemyFinder.maxAngleFilter = lockOnAngle;
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.filterByLoS = false;
			enemyFinder.sortMode = BullseyeSearch.SortMode.Angle;
			enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleLaser");
					if ((bool)transform)
					{
						if ((bool)effectPrefab)
						{
							chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
							chargeEffect.transform.parent = transform;
							ScaleParticleSystemDuration component2 = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
							if ((bool)component2)
							{
								component2.newDuration = duration;
							}
						}
						if ((bool)laserPrefab)
						{
							laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation);
							laserEffect.transform.parent = transform;
							laserLineComponent = laserEffect.GetComponent<LineRenderer>();
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
			flashTimer = 0f;
			laserOn = true;
		}

		public override void OnExit()
		{
			PlayAnimation("FullBody, Override", "Empty");
			base.OnExit();
			if ((bool)chargeEffect)
			{
				EntityState.Destroy(chargeEffect);
			}
			if ((bool)laserEffect)
			{
				EntityState.Destroy(laserEffect);
			}
		}

		public override void Update()
		{
			base.Update();
			if (!laserEffect || !laserLineComponent)
			{
				return;
			}
			float num = 1000f;
			Ray aimRay = GetAimRay();
			enemyFinder.RefreshCandidates();
			lockedOnHurtBox = enemyFinder.GetResults().FirstOrDefault();
			if ((bool)lockedOnHurtBox)
			{
				aimRay.direction = lockedOnHurtBox.transform.position - aimRay.origin;
			}
			UnityEngine.Vector3 position = laserEffect.transform.parent.position;
			UnityEngine.Vector3 point = aimRay.GetPoint(num);
			if (Physics.Raycast(aimRay, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault))
			{
				point = hitInfo.point;
			}
			laserLineComponent.SetPosition(0, position);
			laserLineComponent.SetPosition(1, point);
			float num2;
			if (duration - base.age > 0.5f)
			{
				num2 = base.age / duration;
			}
			else
			{
				flashTimer -= Time.deltaTime;
				if (flashTimer <= 0f)
				{
					laserOn = !laserOn;
					flashTimer = 1f / 30f;
				}
				num2 = (laserOn ? 1f : 0f);
			}
			num2 *= laserMaxWidth;
			laserLineComponent.startWidth = num2;
			laserLineComponent.endWidth = num2;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				EntityState nextState = fireState;
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class LunarGazeChargePlus : LunarGazeCharge
	{
		public override void OnEnter()
		{
			base.OnEnter();
			fireState = new LunarGazeFirePlus();
		}
	}
	public class LunarGazeFire : BaseState
	{
		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject laserPrefab;

		public static string playAttackSoundString;

		public static string playLoopSoundString;

		public static string stopLoopSoundString;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float fireFrequency;

		public static float maxDistance;

		public static float minimumDuration;

		public static float maximumDuration;

		public static float lockOnAngle;

		public static float procCoefficientPerTick;

		public static DamageType lunarGazeDamageType;

		public static bool isLunarGazePlusPlus;

		private HurtBox lockedOnHurtBox;

		private float fireStopwatch;

		private float stopwatch;

		private Ray aimRay;

		private Transform modelTransform;

		private GameObject laserEffect;

		private ChildLocator laserChildLocator;

		private Transform laserEffectEnd;

		protected Transform muzzleTransform;

		private BullseyeSearch enemyFinder;

		private bool foundAnyTarget;

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterBody.SetAimTimer(maximumDuration);
			Util.PlaySound(playAttackSoundString, base.gameObject);
			Util.PlaySound(playLoopSoundString, base.gameObject);
			PlayCrossfade("Gesture, Additive", "LaserBlastLoop", 0.25f);
			PlayCrossfade("Gesture, Override", "LaserBlastLoop", 0.25f);
			enemyFinder = new BullseyeSearch();
			enemyFinder.viewer = base.characterBody;
			enemyFinder.maxDistanceFilter = maxDistance;
			enemyFinder.maxAngleFilter = lockOnAngle;
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.filterByLoS = false;
			enemyFinder.sortMode = BullseyeSearch.SortMode.Angle;
			enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
			if ((bool)base.teamComponent)
			{
				enemyFinder.teamMaskFilter.RemoveTeam(base.teamComponent.teamIndex);
			}
			aimRay = GetAimRay();
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					muzzleTransform = component.FindChild("MuzzleLaser");
					if ((bool)muzzleTransform && (bool)laserPrefab)
					{
						laserEffect = UnityEngine.Object.Instantiate(laserPrefab, muzzleTransform.position, muzzleTransform.rotation);
						laserEffect.transform.parent = muzzleTransform;
						laserChildLocator = laserEffect.GetComponent<ChildLocator>();
						laserEffectEnd = laserChildLocator.FindChild("LaserEnd");
					}
				}
			}
			UpdateLockOn();
		}

		public override void OnExit()
		{
			PlayCrossfade("Gesture, Additive", "Empty", 0.25f);
			PlayCrossfade("Gesture, Override", "Empty", 0.25f);
			if ((bool)laserEffect)
			{
				EntityState.Destroy(laserEffect);
			}
			base.characterBody.SetAimTimer(2f);
			Util.PlaySound(stopLoopSoundString, base.gameObject);
			base.OnExit();
		}

		private void UpdateLockOn()
		{
			if (base.isAuthority)
			{
				enemyFinder.searchOrigin = aimRay.origin;
				enemyFinder.searchDirection = aimRay.direction;
				enemyFinder.RefreshCandidates();
				HurtBox hurtBox = enemyFinder.GetResults().FirstOrDefault();
				if (!(lockedOnHurtBox != null) || !(hurtBox == null) || !enemyFinder.CheckVisible(lockedOnHurtBox.healthComponent.gameObject))
				{
					lockedOnHurtBox = hurtBox;
					foundAnyTarget = hurtBox;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireStopwatch += GetDeltaTime();
			stopwatch += GetDeltaTime();
			aimRay = GetAimRay();
			UnityEngine.Vector3 vector = aimRay.origin;
			if ((bool)muzzleTransform)
			{
				vector = muzzleTransform.position;
			}
			RaycastHit hitInfo;
			UnityEngine.Vector3 vector2 = (lockedOnHurtBox ? lockedOnHurtBox.transform.position : ((!Util.CharacterRaycast(base.gameObject, aimRay, out hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) ? aimRay.GetPoint(maxDistance) : hitInfo.point));
			Ray ray = new Ray(vector, vector2 - vector);
			bool flag = false;
			if ((bool)laserEffect && (bool)laserChildLocator)
			{
				if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo2, (vector2 - vector).magnitude, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
				{
					vector2 = hitInfo2.point;
					if (Util.CharacterRaycast(base.gameObject, new Ray(vector2 - ray.direction * 0.1f, -ray.direction), out var _, hitInfo2.distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
					{
						vector2 = ray.GetPoint(0.1f);
						flag = true;
					}
				}
				laserEffect.transform.rotation = Util.QuaternionSafeLookRotation(vector2 - vector);
				laserEffectEnd.transform.position = vector2;
			}
			if (fireStopwatch > 1f / fireFrequency)
			{
				string targetMuzzle = "MuzzleLaser";
				if (!flag)
				{
					FireBullet(modelTransform, ray, targetMuzzle, (vector2 - ray.origin).magnitude + 0.1f);
				}
				UpdateLockOn();
				fireStopwatch -= 1f / fireFrequency;
			}
			if (base.isAuthority && (((!base.inputBank || !base.inputBank.skill4.down) && stopwatch > minimumDuration) || stopwatch > maximumDuration))
			{
				Util.PlaySound("Play_boss_falseson_skill3_lunarGaze_end", base.gameObject);
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		private void FireBullet(Transform modelTransform, Ray aimRay, string targetMuzzle, float maxDistance)
		{
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (!base.isAuthority)
			{
				return;
			}
			if (isLunarGazePlusPlus)
			{
				if (Util.CheckRoll(10f))
				{
					lunarGazeDamageType = DamageType.LunarRuin;
				}
				else
				{
					lunarGazeDamageType = DamageType.Generic;
				}
			}
			BulletAttack bulletAttack = new BulletAttack();
			bulletAttack.owner = base.gameObject;
			bulletAttack.weapon = base.gameObject;
			bulletAttack.origin = aimRay.origin;
			bulletAttack.aimVector = aimRay.direction;
			bulletAttack.minSpread = minSpread;
			bulletAttack.maxSpread = maxSpread;
			bulletAttack.bulletCount = 1u;
			bulletAttack.damage = damageCoefficient * damageStat / fireFrequency;
			bulletAttack.force = force;
			bulletAttack.damageType = lunarGazeDamageType;
			bulletAttack.muzzleName = targetMuzzle;
			bulletAttack.hitEffectPrefab = hitEffectPrefab;
			bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			bulletAttack.procCoefficient = procCoefficientPerTick;
			bulletAttack.HitEffectNormal = false;
			bulletAttack.radius = 0f;
			bulletAttack.maxDistance = maxDistance;
			bulletAttack.Fire();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(HurtBoxReference.FromHurtBox(lockedOnHurtBox));
			writer.Write(stopwatch);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			HurtBoxReference hurtBoxReference = reader.ReadHurtBoxReference();
			stopwatch = reader.ReadSingle();
			lockedOnHurtBox = hurtBoxReference.ResolveGameObject()?.GetComponent<HurtBox>();
		}
	}
	public class LunarGazeFirePlus : LunarGazeFire
	{
		public static float plusDamageCoefficient;

		public override void OnEnter()
		{
			LunarGazeFire.playAttackSoundString = "Play_boss_falseson_skill3plus_lunarGaze_start";
			LunarGazeFire.playLoopSoundString = "Play_boss_falseson_skill3plus_lunarGaze_active_loop";
			LunarGazeFire.stopLoopSoundString = "Stop_boss_falseson_skill3plus_lunarGaze_active_loop";
			LunarGazeFire.isLunarGazePlusPlus = true;
			LunarGazeFire.damageCoefficient += plusDamageCoefficient;
			base.OnEnter();
		}

		public override void OnExit()
		{
			Util.PlaySound("Play_boss_falseson_skill3plus_lunarGaze_end", base.gameObject);
			base.OnExit();
		}
	}
	public class LunarRain : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public float warningDuration;

		[SerializeField]
		public float delayBetweenDrops = 0.2f;

		[SerializeField]
		public float lunarRadius;

		[SerializeField]
		public int totalLunarDrops = 7;

		[SerializeField]
		public float percentVarianceRotation = 0.25f;

		[SerializeField]
		public float percentVarianceInRadius = 0.2f;

		public static GameObject warningFXPrefab;

		public static GameObject rainCrashEffectPrefab;

		public static GameObject lunarRainPrefab;

		public static GameObject blastImpactEffectPrefab;

		[SerializeField]
		public GameObject blastEffectPrefab;

		[SerializeField]
		public float blastRadius = 2f;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static UnityEngine.Vector3 blastBonusForce;

		private NodeGraph nodeGraph;

		private List<NodeGraph.NodeIndex> nodesToTeleportTo;

		private List<NodeGraph.NodeIndex> fissureLocs;

		private UnityEngine.Vector3 fissureLocation;

		private bool lunarRainStarted;

		private float lunarRainStartTime;

		private int totalWarned;

		private int totalFired;

		private int totalLunarDropsToFire;

		private float nextDropTime;

		public override void OnEnter()
		{
			base.OnEnter();
			new System.Random();
			nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			fissureLocs = new List<NodeGraph.NodeIndex>();
			totalLunarDrops = ((totalLunarDrops > 0) ? totalLunarDrops : 7);
			float num = ((lunarRadius > 0f) ? lunarRadius : 30f);
			Transform transform = base.characterBody.transform;
			UnityEngine.Vector3 position = transform.position;
			UnityEngine.Vector3 angleOffset2 = UnityEngine.Quaternion.AngleAxis(-90f, UnityEngine.Vector3.up) * transform.forward;
			angleOffset2.y = 0f;
			NodeGraph.NodeIndex nodeIndex = nodeGraph.FindClosestNode(position, HullClassification.Human);
			for (int j = 0; j < totalLunarDrops; j++)
			{
				UnityEngine.Vector3 position2 = GeneratePositionAroundCircle(j, totalLunarDrops, position, num * UnityEngine.Random.Range(0.7f, 1.3f), angleOffset2);
				NodeGraph.NodeIndex nodeIndex2 = SceneInfo.instance.groundNodes.FindClosestNode(position2, HullClassification.Human);
				if (!fissureLocs.Contains(nodeIndex2) && nodeIndex2 != nodeIndex)
				{
					fissureLocs.Add(nodeIndex2);
				}
				else
				{
					num *= 1.5f;
				}
			}
			Util.ShuffleList(fissureLocs);
			totalFired = 0;
			nextDropTime = base.fixedAge + delayBetweenDrops;
			totalLunarDropsToFire = Mathf.Min(totalLunarDrops, fissureLocs.Count);
			PlayAnimation("FullBody, Override", "LunarRain", "LunarRain.playbackRate", duration);
			UnityEngine.Vector3 GeneratePositionAroundCircle(int i, int total, UnityEngine.Vector3 center, float radius, UnityEngine.Vector3 angleOffset)
			{
				float num2 = MathF.PI * 2f / (float)total;
				float f = num2 * (float)i + num2 * UnityEngine.Random.Range(1f - percentVarianceRotation, 1f + percentVarianceRotation);
				float x = Mathf.Cos(f);
				float z = Mathf.Sin(f);
				UnityEngine.Vector3 vector = new UnityEngine.Vector3(x, 0f, z);
				radius *= UnityEngine.Random.Range(1f - percentVarianceInRadius, 1f + percentVarianceInRadius);
				return vector * radius + center;
			}
		}

		private void SpawnRainWarning(NodeGraph.NodeIndex node)
		{
			nodeGraph.GetNodePosition(node, out fissureLocation);
			EffectManager.SpawnEffect(warningFXPrefab, new EffectData
			{
				origin = fissureLocation
			}, transmit: true);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (totalWarned < totalLunarDropsToFire)
			{
				SpawnRainWarning(fissureLocs[totalWarned++]);
				if (totalWarned >= totalLunarDropsToFire)
				{
					lunarRainStartTime = base.fixedAge + warningDuration + duration * 0.7f;
				}
				return;
			}
			if (!lunarRainStarted && base.fixedAge > lunarRainStartTime)
			{
				lunarRainStarted = true;
				DetonateAuthority();
			}
			if (!lunarRainStarted || base.fixedAge < nextDropTime)
			{
				return;
			}
			if (totalFired >= totalLunarDropsToFire)
			{
				outer.SetNextStateToMain();
				return;
			}
			FireRain(fissureLocs[totalFired++]);
			if (totalFired < totalLunarDropsToFire)
			{
				FireRain(fissureLocs[totalFired++]);
			}
		}

		private void FireRain(NodeGraph.NodeIndex node)
		{
			if (NetworkServer.active)
			{
				nodeGraph.GetNodePosition(node, out fissureLocation);
				nextDropTime = base.fixedAge + delayBetweenDrops;
				EffectManager.SpawnEffect(rainCrashEffectPrefab, new EffectData
				{
					origin = fissureLocation
				}, transmit: true);
				NetworkServer.Spawn(UnityEngine.Object.Instantiate(lunarRainPrefab, fissureLocation, UnityEngine.Quaternion.identity));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			UnityEngine.Vector3 position = FindModelChild("Root").transform.position;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = position,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = base.gameObject.transform.position,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class OverloadSpike : BaseState
	{
		[SerializeField]
		public float duration;

		public static GameObject rainCrashEffectPrefab;

		public static GameObject lunarRainPrefab;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static UnityEngine.Vector3 blastBonusForce;

		private bool firedSpike;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.characterBody.GetComponent<FalseSonBossController>().firedLunarSpike)
			{
				PlayAnimation("FullBody, Override", "OverloadErruption", "OverloadErruption.playbackRate", duration);
			}
			else
			{
				outer.SetNextStateToMain();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration - duration * 0.3f && !firedSpike && !base.characterBody.GetComponent<FalseSonBossController>().firedLunarSpike)
			{
				DetonateAuthority();
				base.characterBody.GetComponent<FalseSonBossController>().SpawnLunarSpike();
				firedSpike = true;
			}
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			outer.SetNextStateToMain();
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = base.gameObject.transform.position,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = base.gameObject.transform.position,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}
	}
	public class PrimeDevastator : BaseState
	{
		[SerializeField]
		private float duration = 4f;

		[SerializeField]
		private float damageCoefficient = 2f;

		public static float slamEffectDelay;

		public static float playerLightningDelay;

		public static GameObject projectilePrefab;

		private Transform modelTransform;

		protected Transform muzzleTransform;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static GameObject disablingLightningPrefab;

		public static GameObject lightningEffectPrefab;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static UnityEngine.Vector3 blastBonusForce;

		private Ray projectileRay;

		public static float arcAngle = 7f;

		public static float spreadBloomValue = 0.3f;

		public static GameObject chargeEffectPrefab;

		private bool chargeEffectSpawned;

		private bool slamEffectSpawned;

		private bool playerLightningSpawned;

		private bool orbsSpawned;

		private float orbSpawnTimer;

		private int orbNumber;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("FullBody, Override", "PrimeDevastator", "PrimeDevastator.playbackRate", duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!chargeEffectSpawned && base.fixedAge > duration * 0.3f)
			{
				chargeEffectSpawned = true;
				EffectManager.SpawnEffect(chargeEffectPrefab, new EffectData
				{
					origin = base.gameObject.transform.position,
					scale = 10f
				}, transmit: true);
			}
			if (!slamEffectSpawned && base.fixedAge > slamEffectDelay)
			{
				slamEffectSpawned = true;
				DetonateAuthority();
			}
			if (!playerLightningSpawned && base.isAuthority && base.fixedAge > playerLightningDelay)
			{
				playerLightningSpawned = true;
				if ((bool)disablingLightningPrefab)
				{
					foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
					{
						if (!(instance == null))
						{
							CharacterBody body = instance.master.GetBody();
							if (!(body == null))
							{
								body.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 420f);
								EffectManager.SpawnEffect(lightningEffectPrefab, new EffectData
								{
									origin = body.corePosition,
									scale = blastRadius
								}, transmit: true);
							}
						}
					}
				}
			}
			if (!orbsSpawned && base.isAuthority && base.fixedAge > playerLightningDelay)
			{
				orbSpawnTimer += Time.deltaTime;
				if (orbSpawnTimer > 0.5f)
				{
					FireDevastator("MuzzleOrb1");
					orbNumber++;
					orbSpawnTimer = 0f;
				}
				if (orbNumber >= 4)
				{
					orbsSpawned = true;
				}
			}
			if (base.fixedAge >= duration + 1f && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireDevastator(string targetMuzzle)
		{
			projectileRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						projectileRay.origin = transform.position;
					}
				}
			}
			if (base.isAuthority)
			{
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = base.gameObject.transform.position + new UnityEngine.Vector3(7f, 0f, 0f);
				fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = base.gameObject.transform.position,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = base.gameObject.transform.position,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class HeartSpawnState : BaseState
	{
		[SerializeField]
		private float baseAnimDuration = 2f;

		[SerializeField]
		private float baseSpawnDuration = 4f;

		[SerializeField]
		private GameObject spawnEffect;

		[SerializeField]
		private float vfxSize = 6f;

		private bool playedSFX;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound("Play_boss_falseson_spawn", base.gameObject);
			Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject);
			PlayAnimation("Body", "Phase1Spawn", "StepBrothersPrep.playbackRate", baseAnimDuration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > 1f && !playedSFX)
			{
				Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject);
				playedSFX = true;
			}
			if (base.fixedAge > baseSpawnDuration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class Lightning1SpawnState : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject spawnEffect;

		public static float vfxSize = 6f;

		private bool playedSFX;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound("Play_boss_falseson_spawn", base.gameObject);
			PlayAnimation("Body", "Phase2Spawn", "StepBrothersPrep.playbackRate", baseDuration);
			PlayAnimation("FullBody, Override", "BufferEmpty");
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("FalseSonBoss/FalseSonBossLightningNovaSpawn"), new EffectData
			{
				origin = base.transform.position,
				scale = vfxSize
			}, transmit: true);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > 1f && !playedSFX)
			{
				Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject);
				playedSFX = true;
			}
			if (base.fixedAge > baseDuration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class Lightning2SpawnState : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject spawnEffect;

		public static float vfxSize = 6f;

		private bool playedSFX;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound("Play_boss_falseson_spawn", base.gameObject);
			Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject);
			PlayAnimation("Body", "Phase3Spawn", "StepBrothersPrep.playbackRate", baseDuration);
			PlayAnimation("FullBody, Override", "BufferEmpty");
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("FalseSonBoss/FalseSonBossLightningNovaSpawn"), new EffectData
			{
				origin = base.transform.position,
				scale = vfxSize
			}, transmit: true);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > 1f && !playedSFX)
			{
				Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject);
				playedSFX = true;
			}
			if (base.fixedAge > baseDuration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class SwatAwayPlayersSlam : BaseCharacterMain
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public string hitBoxGroupName;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float pushAwayForce;

		[SerializeField]
		public UnityEngine.Vector3 forceVector;

		[SerializeField]
		public NetworkSoundEventDef impactSound;

		public float charge;

		public static float minimumDuration;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static string enterSoundString;

		public static UnityEngine.Vector3 blastBonusForce;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static GameObject fistEffectPrefab;

		public static GameObject swingEffectPrefab;

		public static GameObject fissureSlamObject;

		private GameObject swingEffectInstance;

		private bool detonateNextFrame;

		private bool slamComplete;

		protected HitBoxGroup hitBoxGroup;

		private OverlapAttack overlapAttack;

		public override void OnEnter()
		{
			base.OnEnter();
			baseDuration /= attackSpeedStat;
			PlayAnimation("FullBody, Override", "ChargeSwing", "ChargeSwing.playbackRate", baseDuration);
			Util.PlaySound(enterSoundString, base.gameObject);
			swingEffectInstance = UnityEngine.Object.Instantiate(swingEffectPrefab, FindModelChild("OverHeadSwingPoint"));
			if (base.isAuthority)
			{
				hitBoxGroup = FindHitBoxGroup(GetHitBoxGroupName());
				if ((bool)hitBoxGroup)
				{
					overlapAttack = new OverlapAttack
					{
						attacker = base.gameObject,
						damage = damageCoefficient * damageStat,
						damageColorIndex = DamageColorIndex.Default,
						damageType = DamageType.Generic,
						forceVector = forceVector,
						hitBoxGroup = hitBoxGroup,
						hitEffectPrefab = hitEffectPrefab,
						impactSound = (impactSound?.index ?? NetworkSoundEventIndex.Invalid),
						inflictor = base.gameObject,
						isCrit = RollCrit(),
						procChainMask = default(ProcChainMask),
						pushAwayForce = pushAwayForce,
						procCoefficient = procCoefficient,
						teamIndex = GetTeam()
					};
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!slamComplete && base.fixedAge >= baseDuration - baseDuration * 0.8f)
			{
				BeginMeleeAttack();
				slamComplete = true;
			}
			if (slamComplete)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected void BeginMeleeAttack()
		{
			UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = position,
				scale = blastRadius
			}, transmit: true);
			if (base.isAuthority && overlapAttack != null)
			{
				overlapAttack.Fire();
			}
		}

		public virtual string GetHitBoxGroupName()
		{
			return hitBoxGroupName;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class SwatAwayPlayersWindup : BaseSkillState
	{
		[SerializeField]
		public float baseChargeDuration = 1f;

		[SerializeField]
		public float chargeThreshold = 3f;

		public static float minChargeForChargedAttack;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private int gauntlet;

		private uint soundID;

		private Transform chargeVfxInstanceTransform;

		private bool chargeAnimPlayed;

		private bool stateAborted;

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = 0.5f;
			Util.PlaySound(enterSFXString, base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		public override void OnExit()
		{
			if (!stateAborted)
			{
				if ((bool)chargeVfxInstanceTransform)
				{
					EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
					PlayAnimation("Gesture, Additive", "Empty");
					PlayAnimation("Gesture, Override", "Empty");
					chargeVfxInstanceTransform = null;
				}
				base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
				Util.PlaySound(endChargeLoopSFXString, base.gameObject);
				base.OnExit();
			}
		}

		public override void FixedUpdate()
		{
			if (stateAborted)
			{
				return;
			}
			base.FixedUpdate();
			charge += Time.deltaTime;
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge <= 3f && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab)
			{
				Transform transform = FindModelChild(chargeVfxChildLocatorName);
				if ((bool)transform)
				{
					chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform;
					ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration;
					}
				}
				if (!chargeAnimPlayed)
				{
					PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f);
					PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", chargeDuration, 0.1f);
					chargeAnimPlayed = true;
				}
			}
			else if (charge > baseChargeDuration)
			{
				outer.SetNextState(GetNextStateAuthority());
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			}
		}

		public override void Update()
		{
			if (!stateAborted)
			{
				base.Update();
				Mathf.Clamp01(base.age / chargeDuration);
			}
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			return new SwatAwayPlayersSlam();
		}
	}
	public class TaintedOffering : GenericProjectileBaseState
	{
		[SerializeField]
		public float projectileYawBonus;

		[SerializeField]
		public float additionalShots = 8f;

		private BaseAI ai;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterBody)
			{
				if (base.characterBody.master.TryGetComponent<BaseAI>(out var component))
				{
					ai = component;
				}
				base.characterBody.SetAimTimer(1f);
			}
		}

		public override void FixedUpdate()
		{
			stopwatch += GetDeltaTime();
			if (stopwatch >= delayBeforeFiringProjectile && !firedProjectile)
			{
				firedProjectile = true;
				for (int num = 9; num > 0; num--)
				{
					switch (num)
					{
					case 9:
						projectileYawBonus = 0f;
						projectilePitchBonus = 0f;
						break;
					case 8:
						projectileYawBonus = -4f;
						projectilePitchBonus = -4f;
						break;
					case 7:
						projectileYawBonus = 4f;
						projectilePitchBonus = 4f;
						break;
					case 6:
						projectileYawBonus = 4f;
						projectilePitchBonus = -4f;
						break;
					case 5:
						projectileYawBonus = -4f;
						projectilePitchBonus = 4f;
						break;
					case 4:
						projectileYawBonus = 0f;
						projectilePitchBonus = 8f;
						break;
					case 3:
						projectileYawBonus = 0f;
						projectilePitchBonus = -8f;
						break;
					case 2:
						projectileYawBonus = 8f;
						projectilePitchBonus = 0f;
						break;
					case 1:
						projectileYawBonus = -8f;
						projectilePitchBonus = 0f;
						break;
					}
					FireProjectile();
				}
				DoFireEffects();
			}
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		protected override void PlayAnimation(float duration)
		{
			base.PlayAnimation(duration);
			PlayAnimation("Gesture, Additive", "FireLunarSpike", "LunarSpike.playbackRate", duration);
			PlayAnimation("Gesture, Override", "HoldGauntletsUp", "LunarSpike.playbackRate", duration);
		}

		protected override Ray ModifyProjectileAimRay(Ray aimRay)
		{
			aimRay.origin = base.modelLocator.modelTransform.GetComponent<ChildLocator>().FindChild("MuzzleRight").position;
			if (ai != null && ai.currentEnemy != null && ai.currentEnemy.GetBullseyePosition(out var position))
			{
				aimRay.direction = position - aimRay.origin;
			}
			return aimRay;
		}

		protected override void FireProjectile()
		{
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				aimRay = ModifyProjectileAimRay(aimRay);
				aimRay.direction = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, projectileYawBonus, projectilePitchBonus);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
}
namespace EntityStates.FalseSon
{
	public class AurelioniteCore : BaseState
	{
		public override void OnEnter()
		{
		}
	}
	public class ChargedClubSwing : BaseState
	{
		[SerializeField]
		public float baseDuration;

		public float charge;

		public bool chargeMetMinimumHold;

		public static float playerWalkSpeedCoefficient;

		public static float minimumDuration;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static string enterSoundString;

		public static UnityEngine.Vector3 blastBonusForce;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static GameObject swingEffectPrefab;

		public static float percentOfDurationToFireSwingEffect;

		public static float unchargedBlastRadius;

		public static float unchargedBlastProcCoefficient;

		public static float unchargedBlastDamageCoefficient;

		public static float unchargedBlastForce;

		public static UnityEngine.Vector3 unchargedBlastBonusForce;

		public static GameObject unchargedSwingVFX;

		public static float percentOfAnimationToHoldPlayer;

		private GameObject swingEffectInstance;

		private bool wasSprinting;

		private bool authorityDetonated;

		private bool detonateNextFrame;

		private bool firedSwingVFX;

		public override void OnEnter()
		{
			base.OnEnter();
			baseDuration /= attackSpeedStat;
			PlayAnimation("FullBody, Override", "OverheadSwing", "ChargeSwing.playbackRate", baseDuration);
			wasSprinting = base.characterBody.isSprinting;
			base.characterMotor.walkSpeedPenaltyCoefficient = playerWalkSpeedCoefficient;
			if (chargeMetMinimumHold && base.isAuthority)
			{
				EffectData effectData = new EffectData();
				ChildLocator modelChildLocator = GetModelChildLocator();
				effectData.SetChildLocatorTransformReference(base.gameObject, modelChildLocator.FindChildIndex("OverHeadSwingPoint"));
				EffectManager.SpawnEffect(swingEffectPrefab, effectData, transmit: false);
			}
			base.characterBody.GetComponent<FalseSonController>()?.SetClubSwingAltSecondaryTimestamp();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				if (!chargeMetMinimumHold && !firedSwingVFX && base.fixedAge >= minimumDuration * percentOfDurationToFireSwingEffect)
				{
					SpawnSwingEffect();
					firedSwingVFX = true;
				}
				if (!authorityDetonated && base.fixedAge >= minimumDuration)
				{
					DetonateAuthority();
					authorityDetonated = true;
				}
				if (base.fixedAge >= baseDuration * percentOfAnimationToHoldPlayer)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		private void SpawnSwingEffect()
		{
			EffectData effectData = new EffectData();
			ChildLocator modelChildLocator = GetModelChildLocator();
			effectData.SetChildLocatorTransformReference(base.gameObject, modelChildLocator.FindChildIndex("SwingVertical"));
			EffectManager.SpawnEffect(unchargedSwingVFX, effectData, transmit: true);
		}

		public override void OnExit()
		{
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			base.characterBody.isSprinting = wasSprinting;
			base.characterBody.SetSpreadBloom(0f, canOnlyIncreaseBloom: false);
			base.OnExit();
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			BlastAttack blast = new BlastAttack();
			if (chargeMetMinimumHold)
			{
				InitializeBlastAttackAsCharged(ref blast);
			}
			else
			{
				InitializeBlastAttackNormal(ref blast);
			}
			return blast.Fire();
		}

		private void InitializeBlastAttackAsCharged(ref BlastAttack blast)
		{
			UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = position,
				scale = blastRadius * (charge + 1.25f)
			}, transmit: true);
			blast.attacker = base.gameObject;
			blast.baseDamage = damageStat * (blastDamageCoefficient * charge) + (base.characterBody.maxHealth - (base.characterBody.baseMaxHealth + base.characterBody.levelMaxHealth * (float)((int)base.characterBody.level - 1))) * 0.01f;
			blast.baseForce = blastForce;
			blast.bonusForce = blastBonusForce;
			blast.crit = RollCrit();
			blast.falloffModel = BlastAttack.FalloffModel.None;
			blast.procCoefficient = blastProcCoefficient;
			blast.radius = blastRadius * (charge + 1.55f);
			blast.position = position;
			blast.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blast.impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab);
			blast.teamIndex = base.teamComponent.teamIndex;
		}

		private void InitializeBlastAttackNormal(ref BlastAttack blast)
		{
			UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position;
			blast.attacker = base.gameObject;
			blast.baseDamage = damageStat * (unchargedBlastDamageCoefficient * charge);
			blast.baseForce = unchargedBlastForce;
			blast.bonusForce = unchargedBlastBonusForce;
			blast.crit = RollCrit();
			blast.falloffModel = BlastAttack.FalloffModel.None;
			blast.procCoefficient = unchargedBlastProcCoefficient;
			blast.radius = unchargedBlastRadius;
			blast.position = position;
			blast.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blast.impactEffect = EffectIndex.Invalid;
			blast.teamIndex = base.teamComponent.teamIndex;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class ClubForsaken : BaseSkillState, SteppedSkillDef.IStepSetter
	{
		private class ArcVisualizer : IDisposable
		{
			private readonly UnityEngine.Vector3[] points;

			private readonly float duration;

			private readonly GameObject arcVisualizerInstance;

			private readonly LineRenderer lineRenderer;

			public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount)
			{
				arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab);
				lineRenderer = arcVisualizerInstance.GetComponent<LineRenderer>();
				lineRenderer.positionCount = vertexCount;
				points = new UnityEngine.Vector3[vertexCount];
				this.duration = duration;
			}

			public void Dispose()
			{
				EntityState.Destroy(arcVisualizerInstance);
			}

			public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration)
			{
				arcVisualizerInstance.transform.position = origin;
				if (!lineRenderer.useWorldSpace)
				{
					UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles;
					eulerAngles.x = 0f;
					eulerAngles.z = 0f;
					UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles);
					arcVisualizerInstance.transform.rotation = rotation;
					origin = UnityEngine.Vector3.zero;
					initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity;
				}
				else
				{
					arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up));
				}
				float y = Physics.gravity.y;
				float num = duration / (float)points.Length;
				UnityEngine.Vector3 vector = origin;
				UnityEngine.Vector3 vector2 = initialVelocity;
				float num2 = num;
				float num3 = y * num2;
				float maxDistanceDelta = characterAcceleration * num2;
				for (int i = 0; i < points.Length; i++)
				{
					points[i] = vector;
					UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2);
					current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta);
					vector2.x = current.x;
					vector2.z = current.y;
					vector2.y += num3;
					vector += vector2 * num2;
				}
				lineRenderer.SetPositions(points);
			}
		}

		public int clubState;

		public static GameObject arcVisualizerPrefab;

		public static float arcVisualizerSimulationLength;

		public static int arcVisualizerVertexCount;

		[SerializeField]
		public float baseChargeDuration = 1f;

		public static float minChargeForChargedAttack;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private Transform chargeVfxInstanceTransform;

		private int gauntlet;

		private uint soundID;

		private bool chargeAnimPlayed;

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			clubState = i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = baseChargeDuration / attackSpeedStat;
			Util.PlaySound(enterSFXString, base.gameObject);
			soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnExit()
		{
			if ((bool)chargeVfxInstanceTransform)
			{
				EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
				PlayAnimation("Gesture, Additive", "Empty");
				PlayAnimation("Gesture, Override", "Empty");
				crosshairOverrideRequest?.Dispose();
				chargeVfxInstanceTransform = null;
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			Util.PlaySound(endChargeLoopSFXString, base.gameObject);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill1_chargeAmount", charge * 100f, soundID);
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab)
			{
				if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
				}
				Transform transform = FindModelChild(chargeVfxChildLocatorName);
				if ((bool)transform)
				{
					chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform;
					ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration;
					}
				}
				if (!chargeAnimPlayed)
				{
					PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					chargeAnimPlayed = true;
				}
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		public override void Update()
		{
			base.Update();
			Mathf.Clamp01(base.age / chargeDuration);
		}

		private void AuthorityFixedUpdate()
		{
			if (!ShouldKeepChargingAuthority())
			{
				outer.SetNextState(GetNextStateAuthority());
			}
		}

		protected virtual bool ShouldKeepChargingAuthority()
		{
			return IsKeyDownAuthority();
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			if (charge > minChargeForChargedAttack)
			{
				if (!base.isGrounded)
				{
					return new PreClubGroundSlam
					{
						charge = charge
					};
				}
				return new ChargedClubSwing
				{
					charge = charge
				};
			}
			return new ClubSwing2
			{
				club = clubState
			};
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)clubState);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			clubState = reader.ReadByte();
		}
	}
	public class ClubForsaken2 : BaseSkillState
	{
		private class ArcVisualizer : IDisposable
		{
			private readonly UnityEngine.Vector3[] points;

			private readonly float duration;

			private readonly GameObject arcVisualizerInstance;

			private readonly LineRenderer lineRenderer;

			public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount)
			{
				arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab);
				lineRenderer = arcVisualizerInstance.GetComponent<LineRenderer>();
				lineRenderer.positionCount = vertexCount;
				points = new UnityEngine.Vector3[vertexCount];
				this.duration = duration;
			}

			public void Dispose()
			{
				EntityState.Destroy(arcVisualizerInstance);
			}

			public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration)
			{
				arcVisualizerInstance.transform.position = origin;
				if (!lineRenderer.useWorldSpace)
				{
					UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles;
					eulerAngles.x = 0f;
					eulerAngles.z = 0f;
					UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles);
					arcVisualizerInstance.transform.rotation = rotation;
					origin = UnityEngine.Vector3.zero;
					initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity;
				}
				else
				{
					arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up));
				}
				float y = Physics.gravity.y;
				float num = duration / (float)points.Length;
				UnityEngine.Vector3 vector = origin;
				UnityEngine.Vector3 vector2 = initialVelocity;
				float num2 = num;
				float num3 = y * num2;
				float maxDistanceDelta = characterAcceleration * num2;
				for (int i = 0; i < points.Length; i++)
				{
					points[i] = vector;
					UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2);
					current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta);
					vector2.x = current.x;
					vector2.z = current.y;
					vector2.y += num3;
					vector += vector2 * num2;
				}
				lineRenderer.SetPositions(points);
			}
		}

		public static GameObject arcVisualizerPrefab;

		public static float arcVisualizerSimulationLength;

		public static int arcVisualizerVertexCount;

		[SerializeField]
		public float baseChargeDuration = 1f;

		public static float minChargeForChargedAttack;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private Transform chargeVfxInstanceTransform;

		private int gauntlet;

		private uint soundID;

		private bool chargeAnimPlayed;

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = baseChargeDuration / attackSpeedStat;
			Util.PlaySound(enterSFXString, base.gameObject);
			soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnExit()
		{
			if ((bool)chargeVfxInstanceTransform)
			{
				EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
				PlayAnimation("Gesture, Additive", "Empty");
				PlayAnimation("Gesture, Override", "Empty");
				crosshairOverrideRequest?.Dispose();
				chargeVfxInstanceTransform = null;
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			Util.PlaySound(endChargeLoopSFXString, base.gameObject);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill1_chargeAmount", charge * 100f, soundID);
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge >= minChargeForChargedAttack && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab)
			{
				if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
				}
				Transform transform = FindModelChild(chargeVfxChildLocatorName);
				if ((bool)transform)
				{
					chargeVfxInstanceTransform = UnityEngine.Object.Instantiate(chargeVfxPrefab, transform).transform;
					ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = (1f - minChargeForChargedAttack) * chargeDuration;
					}
				}
				if (!chargeAnimPlayed)
				{
					PlayCrossfade("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					PlayCrossfade("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					chargeAnimPlayed = true;
				}
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		public override void Update()
		{
			base.Update();
			Mathf.Clamp01(base.age / chargeDuration);
		}

		private void AuthorityFixedUpdate()
		{
			if (!ShouldKeepChargingAuthority())
			{
				outer.SetNextState(GetNextStateAuthority());
			}
		}

		protected virtual bool ShouldKeepChargingAuthority()
		{
			return IsKeyDownAuthority();
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			if (!base.isGrounded)
			{
				return new PreClubGroundSlam
				{
					charge = charge
				};
			}
			return new ChargedClubSwing
			{
				charge = charge
			};
		}
	}
	public class PreClubGroundSlam : BaseState
	{
		public float charge;

		public static float baseDuration;

		public static string enterSoundString;

		public static float upwardVelocity;

		private float duration;

		private bool forceAnimWrapUp = true;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Body", "PreGroundSlam", "GroundSlam.playbackRate", duration);
			Util.PlaySound(enterSoundString, base.gameObject);
			base.characterMotor.Motor.ForceUnground();
			base.characterMotor.disableAirControlUntilCollision = false;
			base.characterMotor.velocity.y = upwardVelocity;
			base.characterBody.bodyFlags |= CharacterBody.BodyFlags.IgnoreFallDamage;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterMotor.moveDirection = base.inputBank.moveVector;
			base.characterBody.SetSpreadBloom(charge);
			if (base.fixedAge > duration)
			{
				forceAnimWrapUp = false;
				outer.SetNextState(new ClubGroundSlam
				{
					charge = charge
				});
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}

		public override void ModifyNextState(EntityState nextState)
		{
			ClubGroundSlam clubGroundSlam = nextState as ClubGroundSlam;
			forceAnimWrapUp = clubGroundSlam == null;
		}

		public override void OnExit()
		{
			base.OnExit();
			if (forceAnimWrapUp)
			{
				PlayAnimation("Gesture, Override", "Empty");
				PlayAnimation("Gesture, Additive", "Empty");
				PlayAnimation("Body", "Idle");
				base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.IgnoreFallDamage;
			}
		}
	}
	public class ClubGroundSlam : BaseState
	{
		public float charge;

		public static float airControl;

		public static float minimumDuration;

		public static float blastRadius;

		public static float blastProcCoefficient;

		public static float blastDamageCoefficient;

		public static float blastForce;

		public static string enterSoundString;

		public static float initialVerticalVelocity;

		public static float exitVerticalVelocity;

		public static float verticalAcceleration;

		public static float exitSlowdownCoefficient;

		public static UnityEngine.Vector3 blastBonusForce;

		public static GameObject blastImpactEffectPrefab;

		public static GameObject blastEffectPrefab;

		public static float normalizedVFXPositionBetweenFootAndClub;

		public static float normalizedBlastPositionBetweenFootAndClub;

		public static float smallHopVelocity;

		public static float heightInfluencePercent;

		private float previousAirControl;

		private float timeInAir;

		private float airClubTimer;

		private bool hitTheGround;

		private float delayBeforeExit;

		private bool detonateNextFrame;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", "GroundSlam", 0.2f);
			if (base.isAuthority)
			{
				base.characterMotor.onHitGroundAuthority += OnHitGroundAuthority;
				base.characterMotor.velocity.y = initialVerticalVelocity;
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			previousAirControl = base.characterMotor.airControl;
			base.characterMotor.airControl = airControl;
			base.characterBody.bodyFlags |= CharacterBody.BodyFlags.IgnoreFallDamage;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			airClubTimer += deltaTime;
			timeInAir = 0f;
			if (airClubTimer > 0.5f)
			{
				timeInAir = airClubTimer;
			}
			if (base.isAuthority && (bool)base.characterMotor)
			{
				base.characterMotor.moveDirection = base.inputBank.moveVector;
				base.characterDirection.moveVector = base.characterMotor.moveDirection;
				base.characterMotor.velocity.y += verticalAcceleration * deltaTime;
				if (!hitTheGround && base.fixedAge >= minimumDuration && (detonateNextFrame || (base.characterMotor.Motor.GroundingStatus.IsStableOnGround && !base.characterMotor.Motor.LastGroundingStatus.IsStableOnGround)))
				{
					PlayAnimation("Body", "GroundSlamExit");
					DetonateAuthority();
					hitTheGround = true;
					delayBeforeExit = base.fixedAge;
				}
				else if (hitTheGround && base.fixedAge >= delayBeforeExit + 0.1f)
				{
					outer.SetNextStateToMain();
				}
				else
				{
					base.characterBody.SetSpreadBloom(charge);
				}
			}
		}

		public override void OnExit()
		{
			if (!base.isAuthority)
			{
				PlayAnimation("Body", "GroundSlamExit");
			}
			base.characterBody.SetSpreadBloom(0f, canOnlyIncreaseBloom: false);
			if (base.isAuthority)
			{
				base.characterMotor.onHitGroundAuthority -= OnHitGroundAuthority;
				base.characterMotor.velocity *= exitSlowdownCoefficient;
				base.characterMotor.velocity.y = exitVerticalVelocity;
				if (!hitTheGround)
				{
					PlayAnimation("Body", "Idle");
				}
			}
			base.characterMotor.airControl = previousAirControl;
			base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.IgnoreFallDamage;
			SmallHop(base.characterMotor, smallHopVelocity + airClubTimer * heightInfluencePercent);
			base.OnExit();
		}

		private void OnHitGroundAuthority(ref CharacterMotor.HitGroundInfo hitGroundInfo)
		{
			detonateNextFrame = true;
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			UnityEngine.Vector3 position = FindModelChild("ClubExplosionPoint").transform.position;
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			UnityEngine.Vector3 origin = footPosition + (position - footPosition) * normalizedVFXPositionBetweenFootAndClub;
			UnityEngine.Vector3 position2 = footPosition + (position - footPosition) * normalizedBlastPositionBetweenFootAndClub;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = origin,
				scale = blastRadius * (charge + 1.25f + timeInAir * 2f)
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * (blastDamageCoefficient * charge) + (base.characterBody.maxHealth - (base.characterBody.baseMaxHealth + base.characterBody.levelMaxHealth * (float)((int)base.characterBody.level - 1))) * 0.01f,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = RollCrit(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius * (charge + 1.25f + timeInAir * 2f),
				position = position2,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class ClubSwing : BasicMeleeAttack, SteppedSkillDef.IStepSetter, ISkillOverrideHandoff
	{
		public int club;

		public static GameObject secondarySwingEffectPrefab;

		[SerializeField]
		public SkillDef secondaryOverrideSkill;

		[SerializeField]
		public SkillDef specialOverrideSkill;

		[SerializeField]
		public float secondaryAltCooldownDuration = 0.7f;

		private SkillStateOverrideData skillOverrideData;

		private float startTimeStamp;

		private bool resetClubSwing;

		private bool clearOverrides = true;

		private FalseSonController falseSonController;

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			club = i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			falseSonController = base.characterBody.GetComponent<FalseSonController>();
			if (CheckReadyForSecondaryAlt())
			{
				GenerateSkillOverrideData();
			}
			else
			{
				EnsureSkillOverrideState(readyToFire: false);
			}
			clearOverrides = true;
			startTimeStamp = Time.time;
		}

		void ISkillOverrideHandoff.TransferSkillOverride(SkillStateOverrideData skillOverrideData)
		{
			this.skillOverrideData = skillOverrideData;
		}

		private bool CheckReadyForSecondaryAlt()
		{
			if (base.inputBank.skill1.down)
			{
				return Time.time - falseSonController.GetClubSwingAltSecondaryTimestamp() > secondaryAltCooldownDuration;
			}
			return false;
		}

		private void EnsureSkillOverrideState(bool readyToFire)
		{
			if (readyToFire ^ (skillOverrideData != null))
			{
				if (readyToFire)
				{
					GenerateSkillOverrideData();
				}
				else
				{
					ClearSkillOverrideData();
				}
			}
		}

		private void GenerateSkillOverrideData()
		{
			if (skillOverrideData == null)
			{
				skillOverrideData = new SkillStateOverrideData(base.characterBody);
				skillOverrideData.secondarySkillOverride = secondaryOverrideSkill;
				skillOverrideData.overrideFullReloadOnAssign = true;
				skillOverrideData.simulateRestockForOverridenSkills = false;
				skillOverrideData.OverrideSkills(base.skillLocator);
			}
		}

		private void ClearSkillOverrideData()
		{
			if (skillOverrideData != null)
			{
				skillOverrideData.ClearOverrides();
			}
			skillOverrideData = null;
		}

		public override void FixedUpdate()
		{
			if (skillOverrideData != null)
			{
				skillOverrideData.StepRestock();
			}
			bool flag = CheckReadyForSecondaryAlt();
			EnsureSkillOverrideState(flag);
			if (flag && base.inputBank.skill2.justPressed)
			{
				ResetClubSwing();
				outer.SetNextState(GetNextStateAuthority());
			}
			base.FixedUpdate();
		}

		private void ResetClubSwing()
		{
			SteppedSkillDef.InstanceData instanceData = (SteppedSkillDef.InstanceData)(base.skillLocator.GetSkill(SkillSlot.Primary)?.skillInstanceData);
			if (instanceData != null)
			{
				instanceData.step = 0;
				club = 0;
				resetClubSwing = true;
			}
		}

		protected override void PlayAnimation()
		{
			string animationStateName = ((club == 0) ? "SwingClubRight" : "SwingClubLeft");
			float num = Mathf.Max(duration, 0.2f);
			PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", num, 0.1f);
			PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", num, 0.1f);
		}

		protected override void BeginMeleeAttackEffect()
		{
			swingEffectPrefab = ((club == 0) ? swingEffectPrefab : secondarySwingEffectPrefab);
			swingEffectMuzzleString = ((club == 0) ? "SwingRight" : "SwingLeft");
			base.BeginMeleeAttackEffect();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)club);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			club = reader.ReadByte();
		}

		public override void OnExit()
		{
			base.OnExit();
			if (clearOverrides && skillOverrideData != null)
			{
				skillOverrideData.ClearOverrides();
			}
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (nextState is ISkillOverrideHandoff skillOverrideHandoff && skillOverrideData != null)
			{
				skillOverrideHandoff.TransferSkillOverride(skillOverrideData);
				clearOverrides = false;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			return new ClubSwing3();
		}
	}
	public class ClubSwing2 : BasicMeleeAttack, SteppedSkillDef.IStepSetter
	{
		public int club;

		public static float recoilAmplitude;

		public static float baseDurationBeforeInterruptable;

		[SerializeField]
		public float bloom;

		public static float comboFinisherBaseDuration;

		public static GameObject comboFinisherSwingEffectPrefab;

		public static float comboFinisherhitPauseDuration;

		public static float comboFinisherDamageCoefficient;

		public static float comboFinisherBloom;

		public static float comboFinisherBaseDurationBeforeInterruptable;

		public static string slash1Sound;

		public static string slash3Sound;

		private string animationStateName;

		private string meleeStreakStateName;

		private float durationBeforeInterruptable;

		private bool isComboFinisher => club == 1;

		protected override bool allowExitFire
		{
			get
			{
				if ((bool)base.characterBody)
				{
					return !base.characterBody.isSprinting;
				}
				return false;
			}
		}

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			club = i;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if (isComboFinisher)
			{
				swingEffectPrefab = comboFinisherSwingEffectPrefab;
				hitPauseDuration = comboFinisherhitPauseDuration;
				damageCoefficient = comboFinisherDamageCoefficient;
				bloom = comboFinisherBloom;
				hitBoxGroupName = "SwordLarge";
				baseDuration = comboFinisherBaseDuration;
			}
			base.OnEnter();
			base.characterDirection.forward = GetAimRay().direction;
			durationBeforeInterruptable = (isComboFinisher ? (comboFinisherBaseDurationBeforeInterruptable / attackSpeedStat) : (baseDurationBeforeInterruptable / attackSpeedStat));
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			_ = isComboFinisher;
		}

		protected override void PlayAnimation()
		{
			animationStateName = "";
			string soundString = null;
			switch (club)
			{
			case 0:
				animationStateName = "SwingClubRight";
				meleeStreakStateName = "SwingRight";
				soundString = slash1Sound;
				break;
			case 1:
				animationStateName = "SwingClubLeft";
				meleeStreakStateName = "SwingLeft";
				soundString = slash1Sound;
				break;
			}
			bool @bool = animator.GetBool("isMoving");
			bool bool2 = animator.GetBool("isGrounded");
			if (!@bool && bool2)
			{
				PlayCrossfade("FullBody, Override", animationStateName, "SwingClub.playbackRate", duration, 0.05f);
			}
			else
			{
				PlayCrossfade("Gesture, Additive", animationStateName, "SwingClub.playbackRate", duration, 0.05f);
				PlayCrossfade("Gesture, Override", animationStateName, "SwingClub.playbackRate", duration, 0.05f);
			}
			Util.PlaySound(soundString, base.gameObject);
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			base.characterBody.AddSpreadBloom(bloom);
		}

		protected override void BeginMeleeAttackEffect()
		{
			swingEffectMuzzleString = meleeStreakStateName;
			AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			base.BeginMeleeAttackEffect();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)club);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			club = reader.ReadByte();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public class ClubSwing3 : BaseSkillState, ISkillOverrideHandoff
	{
		private class ArcVisualizer : IDisposable
		{
			private readonly UnityEngine.Vector3[] points;

			private readonly float duration;

			private readonly GameObject arcVisualizerInstance;

			private readonly LineRenderer lineRenderer;

			public ArcVisualizer(GameObject arcVisualizerPrefab, float duration, int vertexCount)
			{
				arcVisualizerInstance = UnityEngine.Object.Instantiate(arcVisualizerPrefab);
				lineRenderer = arcVisualizerInstance.GetComponent<LineRenderer>();
				lineRenderer.positionCount = vertexCount;
				points = new UnityEngine.Vector3[vertexCount];
				this.duration = duration;
			}

			public void Dispose()
			{
				EntityState.Destroy(arcVisualizerInstance);
			}

			public void SetParameters(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float characterMaxSpeed, float characterAcceleration)
			{
				arcVisualizerInstance.transform.position = origin;
				if (!lineRenderer.useWorldSpace)
				{
					UnityEngine.Vector3 eulerAngles = UnityEngine.Quaternion.LookRotation(initialVelocity).eulerAngles;
					eulerAngles.x = 0f;
					eulerAngles.z = 0f;
					UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(eulerAngles);
					arcVisualizerInstance.transform.rotation = rotation;
					origin = UnityEngine.Vector3.zero;
					initialVelocity = UnityEngine.Quaternion.Inverse(rotation) * initialVelocity;
				}
				else
				{
					arcVisualizerInstance.transform.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.Cross(initialVelocity, UnityEngine.Vector3.up));
				}
				float y = Physics.gravity.y;
				float num = duration / (float)points.Length;
				UnityEngine.Vector3 vector = origin;
				UnityEngine.Vector3 vector2 = initialVelocity;
				float num2 = num;
				float num3 = y * num2;
				float maxDistanceDelta = characterAcceleration * num2;
				for (int i = 0; i < points.Length; i++)
				{
					points[i] = vector;
					UnityEngine.Vector2 current = Util.Vector3XZToVector2XY(vector2);
					current = UnityEngine.Vector2.MoveTowards(current, UnityEngine.Vector3.zero, maxDistanceDelta);
					vector2.x = current.x;
					vector2.z = current.y;
					vector2.y += num3;
					vector += vector2 * num2;
				}
				lineRenderer.SetPositions(points);
			}
		}

		public static GameObject arcVisualizerPrefab;

		public static float arcVisualizerSimulationLength;

		public static int arcVisualizerVertexCount;

		[SerializeField]
		public float baseChargeDuration = 1f;

		[SerializeField]
		public float minChargeToDisplayAttackCharging;

		[SerializeField]
		public float minChargeToChargeAttack;

		[SerializeField]
		public float cooldownOnCancelDuration = 1f;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private Transform chargeVfxInstanceTransform;

		private int gauntlet;

		private uint soundID;

		private bool chargeAnimPlayed;

		private SkillStateOverrideData skillOverrideData;

		private bool clearOverrides = true;

		private bool nonAuthority_AllowEarlyCancelAnimationToFinish;

		private float cooldownTimestamp = -1f;

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = baseChargeDuration / attackSpeedStat;
			Util.PlaySound(enterSFXString, base.gameObject);
			soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject);
			clearOverrides = true;
			ResetPrimarySwingCount();
		}

		private void ResetPrimarySwingCount()
		{
			SteppedSkillDef.InstanceData instanceData = (SteppedSkillDef.InstanceData)(base.skillLocator.GetSkill(SkillSlot.Primary)?.skillInstanceData);
			if (instanceData != null)
			{
				instanceData.step = 0;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void FixedUpdate()
		{
			if (skillOverrideData != null)
			{
				skillOverrideData.StepRestock();
			}
			if (cooldownTimestamp != -1f)
			{
				if (!(Time.time - cooldownTimestamp < cooldownOnCancelDuration))
				{
					outer.SetNextStateToMain();
				}
				return;
			}
			base.FixedUpdate();
			charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill1_chargeAmount", charge * 100f, soundID);
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge >= minChargeToDisplayAttackCharging && !chargeVfxInstanceTransform && (bool)chargeVfxPrefab)
			{
				if ((bool)crosshairOverridePrefab && crosshairOverrideRequest == null)
				{
					crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
				}
				Transform transform = FindModelChild(chargeVfxChildLocatorName);
				if ((bool)transform && charge > minChargeToChargeAttack)
				{
					chargeVfxInstanceTransform = EffectManager.GetAndActivatePooledEffect(chargeVfxPrefab, transform, inResetLocal: true)?.transform;
					ScaleParticleSystemDuration component = chargeVfxInstanceTransform.GetComponent<ScaleParticleSystemDuration>();
					if ((bool)component)
					{
						component.newDuration = (1f - minChargeToDisplayAttackCharging) * chargeDuration;
					}
				}
				if (!chargeAnimPlayed)
				{
					PlayAnimation("Gesture, Additive", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					PlayAnimation("Gesture, Override", "ChargeSwingIntro", "ChargeSwingIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
					chargeAnimPlayed = true;
				}
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		public override void Update()
		{
			base.Update();
			Mathf.Clamp01(base.age / chargeDuration);
		}

		private void AuthorityFixedUpdate()
		{
			if (!base.inputBank.skill1.down && !base.inputBank.skill2.down)
			{
				if ((base.inputBank.skill2.justReleased || base.inputBank.skill1.justReleased) && CanOverheadSwing())
				{
					outer.SetNextState(GetNextStateAuthority());
				}
				else
				{
					HandleEarlyCancel();
				}
			}
		}

		private void HandleEarlyCancel()
		{
			if (cooldownTimestamp == -1f)
			{
				PlayAnimation("Gesture, Additive", "ChargeSwingExit");
				PlayAnimation("Gesture, Override", "ChargeSwingExit");
				cooldownTimestamp = Time.time;
			}
		}

		private bool CanOverheadSwing()
		{
			if (!(charge > minChargeToChargeAttack))
			{
				return base.isGrounded;
			}
			return true;
		}

		protected virtual bool ShouldKeepChargingAuthority()
		{
			return IsKeyDownAuthority();
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			if (!base.isGrounded)
			{
				return new PreClubGroundSlam
				{
					charge = charge
				};
			}
			if (charge > minChargeToChargeAttack)
			{
				return new ChargedClubSwing
				{
					charge = charge,
					chargeMetMinimumHold = (charge > minChargeToChargeAttack)
				};
			}
			return new OverheadClubSwing();
		}

		public override void OnExit()
		{
			if (clearOverrides)
			{
				skillOverrideData?.ClearOverrides();
			}
			if ((bool)chargeVfxInstanceTransform)
			{
				EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
				crosshairOverrideRequest?.Dispose();
				chargeVfxInstanceTransform = null;
			}
			if (!nonAuthority_AllowEarlyCancelAnimationToFinish)
			{
				PlayAnimation("Gesture, Additive", "Empty");
				PlayAnimation("Gesture, Override", "Empty");
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			Util.PlaySound(endChargeLoopSFXString, base.gameObject);
			base.OnExit();
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			if (nextState is ISkillOverrideHandoff skillOverrideHandoff)
			{
				skillOverrideHandoff.TransferSkillOverride(skillOverrideData);
				clearOverrides = false;
				if (!base.isAuthority && nextState is IdleSkillOverrideHandoff)
				{
					HandleEarlyCancel();
					nonAuthority_AllowEarlyCancelAnimationToFinish = true;
				}
			}
		}

		public void TransferSkillOverride(SkillStateOverrideData skillOverrideData)
		{
			this.skillOverrideData = skillOverrideData;
		}
	}
	public class LaserFather : BaseSkillState
	{
		[SerializeField]
		public float baseChargeDuration = 1f;

		[SerializeField]
		public GameObject chargeCompletePrefab;

		public static float minChargeForChargedAttack;

		public static GameObject chargeVfxPrefab;

		public static string chargeVfxChildLocatorName;

		public static GameObject crosshairOverridePrefab;

		public static float walkSpeedCoefficient;

		public static string startChargeLoopSFXString;

		public static string endChargeLoopSFXString;

		public static string enterSFXString;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private Transform chargeVfxInstanceTransform;

		private int gauntlet;

		private uint soundID;

		public static float baseDuration = 3f;

		public static float laserMaxWidth = 0.2f;

		public static GameObject effectPrefab;

		public static GameObject laserPrefab;

		public static string attackSoundString;

		private float duration;

		private uint chargePlayID;

		private GameObject chargeEffect;

		private GameObject laserEffect;

		private LineRenderer laserLineComponent;

		private UnityEngine.Vector3 laserDirection;

		private UnityEngine.Vector3 visualEndPosition;

		private float flashTimer;

		private bool laserOn;

		private bool chargeAnimPlayed;

		private bool chargeFinished;

		private bool chargeStarted;

		private bool cancellingAttack;

		protected float chargeDuration { get; private set; }

		protected float charge { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			chargeDuration = baseChargeDuration / attackSpeedStat;
			soundID = Util.PlaySound(startChargeLoopSFXString, base.gameObject);
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			chargePlayID = Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("MuzzleLaser");
					if ((bool)transform)
					{
						if ((bool)effectPrefab)
						{
							chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
							chargeEffect.transform.parent = transform;
							ScaleParticleSystemDuration component2 = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
							if ((bool)component2)
							{
								component2.newDuration = duration;
							}
						}
						if ((bool)laserPrefab)
						{
							laserEffect = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation);
							laserEffect.transform.parent = transform;
							laserLineComponent = laserEffect.GetComponent<LineRenderer>();
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
			flashTimer = 0f;
			laserOn = true;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void ModifyNextState(EntityState nextState)
		{
			base.ModifyNextState(nextState);
			LaserFatherCharged laserFatherCharged = nextState as LaserFatherCharged;
			cancellingAttack = laserFatherCharged == null;
		}

		public override void OnExit()
		{
			if ((bool)chargeVfxInstanceTransform)
			{
				EntityState.Destroy(chargeVfxInstanceTransform.gameObject);
				crosshairOverrideRequest?.Dispose();
				chargeVfxInstanceTransform = null;
			}
			PlayAnimation("Gesture, Additive", "Empty");
			PlayAnimation("Gesture, Override", "Empty");
			if (cancellingAttack)
			{
				PlayAnimation("Gesture, Head, Additive", "Empty");
				PlayAnimation("Gesture, Head, Override", "Buffer Empty");
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			Util.PlaySound(endChargeLoopSFXString, base.gameObject);
			AkSoundEngine.StopPlayingID(chargePlayID);
			Util.PlaySound("Stop_falseson_skill4_laser_loop", base.gameObject);
			Util.PlaySound("Stop_falseson_skill4_laser_charge_loop", base.gameObject);
			base.OnExit();
			if ((bool)chargeEffect)
			{
				EntityState.Destroy(chargeEffect);
			}
			if ((bool)laserEffect)
			{
				EntityState.Destroy(laserEffect);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			AkSoundEngine.SetRTPCValueByPlayingID("charFalseSon_skill4_chargeAmount", charge * 100f, soundID);
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge >= minChargeForChargedAttack && !chargeStarted)
			{
				chargeStarted = true;
				base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
				PlayCrossfade("Gesture, Head, Additive", "LaserChargeIntro", "LaserChargeIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
				PlayCrossfade("Gesture, Head, Override", "LaserChargeIntro", "LaserChargeIntro.playbackRate", 0.2f * chargeDuration, 0.1f);
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
			if (!(charge > 0.85f) || chargeFinished)
			{
				return;
			}
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("MuzzleLaser");
				if ((bool)transform)
				{
					chargeCompletePrefab = LegacyResourcesAPI.Load<GameObject>("FalseSon/FalseSonLaserChargeComplete");
					EffectManager.SpawnEffect(chargeCompletePrefab, new EffectData
					{
						origin = transform.transform.position,
						scale = 1f
					}, transmit: true);
					chargeFinished = true;
				}
			}
		}

		public override void Update()
		{
			base.Update();
			Mathf.Clamp01(base.age / chargeDuration);
		}

		private void AuthorityFixedUpdate()
		{
			if (!ShouldKeepChargingAuthority())
			{
				outer.SetNextState(GetNextStateAuthority());
			}
		}

		protected virtual bool ShouldKeepChargingAuthority()
		{
			return IsKeyDownAuthority();
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			if (charge < 0.175f)
			{
				charge = 0.175f;
			}
			return new LaserFatherCharged
			{
				charge = charge,
				walkSpeedCoefficient = walkSpeedCoefficient
			};
		}
	}
	public class LaserFatherBurst : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float blastRadius;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public static string attackSoundString;

		public static float laserTimerPercent = 0.12f;

		public UnityEngine.Vector3 laserDirection;

		private float duration;

		private Ray modifiedAimRay;

		public float charge;

		private float maxSecondaryStock;

		private float secondaryStock;

		private Transform modelTransform;

		protected Transform muzzleTransform;

		private string targetMuzzle;

		private float rayDistance;

		private bool firedLaser;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Gesture, Override", "FireLaser", "FireLaser.playbackRate", duration, 0.1f);
			PlayCrossfade("Gesture, Additive", "FireLaser", "FireLaser.playbackRate", duration, 0.1f);
			maxSecondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock;
			secondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).stock;
			int num = (int)(maxSecondaryStock * 0.3f);
			int num2 = (int)maxSecondaryStock - (int)secondaryStock;
			if (num2 > 0)
			{
				if (num2 < num)
				{
					base.skillLocator.GetSkill(SkillSlot.Secondary).stock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock;
				}
				else
				{
					base.skillLocator.GetSkill(SkillSlot.Secondary).stock = base.skillLocator.GetSkill(SkillSlot.Secondary).stock + num;
				}
			}
		}

		public void FireBurstLaser()
		{
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					muzzleTransform = component.FindChild("MuzzleLaser");
				}
			}
			rayDistance = 1000f;
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 position = muzzleTransform.transform.parent.position;
			UnityEngine.Vector3 point = aimRay.GetPoint(rayDistance);
			laserDirection = point - position;
			modifiedAimRay = GetAimRay();
			modifiedAimRay.direction = laserDirection;
			TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref modifiedAimRay, rayDistance, base.gameObject);
			GetModelAnimator();
			Util.PlaySound(attackSoundString, base.gameObject);
			targetMuzzle = "MuzzleLaser";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (!base.isAuthority)
			{
				return;
			}
			rayDistance = 200f;
			UnityEngine.Vector3 vector = modifiedAimRay.origin + modifiedAimRay.direction * rayDistance;
			if (Physics.Raycast(modifiedAimRay, out var hitInfo, rayDistance, LayerIndex.CommonMasks.laser))
			{
				vector = hitInfo.point;
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.inflictor = base.gameObject;
			blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
			blastAttack.baseDamage = damageStat * damageCoefficient;
			blastAttack.baseForce = force * 0.2f;
			blastAttack.position = vector;
			blastAttack.radius = blastRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.SweetSpot;
			blastAttack.bonusForce = force * modifiedAimRay.direction;
			blastAttack.Fire();
			_ = modifiedAimRay.origin;
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component2 = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component2)
			{
				int childIndex = component2.FindChildIndex(targetMuzzle);
				if ((bool)tracerEffectPrefab)
				{
					EffectData effectData = new EffectData
					{
						origin = vector,
						start = modifiedAimRay.origin
					};
					effectData.SetChildLocatorTransformReference(base.gameObject, childIndex);
					EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
					EffectManager.SpawnEffect(hitEffectPrefab, effectData, transmit: true);
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration * laserTimerPercent && !firedLaser)
			{
				firedLaser = true;
				FireBurstLaser();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class LaserFatherCharged : BaseState
	{
		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject laserPrefab;

		public static string playAttackSoundString;

		public static string playLoopSoundString;

		public static string stopLoopSoundString;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float fireFrequency;

		public static float maxDistance;

		public static float minimumDuration;

		public static float maximumDuration;

		public static float lockOnAngle;

		public static float procCoefficientPerTick;

		private HurtBox lockedOnHurtBox;

		private float fireStopwatch;

		private float stopwatch;

		private float refillSecondaryStopwatch;

		private float maxSecondaryStock;

		private float secondaryStock;

		private Ray aimRay;

		private Transform modelTransform;

		private GameObject laserEffect;

		private ChildLocator laserChildLocator;

		private Transform laserEffectEnd;

		public float charge;

		protected Transform muzzleTransform;

		private float bonusDuration;

		protected CameraTargetParams.AimRequest aimRequest;

		public static int abilityAimType;

		private float duration;

		public float walkSpeedCoefficient = 1f;

		private int lunarSpikeCount;

		public static event Action<float> laserTracking;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = maximumDuration;
			aimRequest = base.cameraTargetParams.RequestAimType((CameraTargetParams.AimType)abilityAimType);
			base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			FalseSonController component = GetComponent<FalseSonController>();
			if ((bool)component)
			{
				lunarSpikeCount = component.GetTotalSpikeCount();
			}
			else
			{
				lunarSpikeCount = 0;
			}
			Util.PlaySound("Play_falseson_skill4_laser_start", base.gameObject);
			PlayCrossfade("Gesture, Head, Override", "FireLaserLoop", 0.25f);
			PlayCrossfade("Gesture, Head, Additive", "FireLaserLoop", 0.25f);
			aimRay = GetAimRay();
			TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, maxDistance, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component2 = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component2)
				{
					muzzleTransform = component2.FindChild("MuzzleLaser");
					if ((bool)muzzleTransform && (bool)laserPrefab)
					{
						laserEffect = UnityEngine.Object.Instantiate(laserPrefab, muzzleTransform.position, muzzleTransform.rotation);
						laserEffect.transform.parent = muzzleTransform;
						laserChildLocator = laserEffect.GetComponent<ChildLocator>();
						laserEffectEnd = laserChildLocator.FindChild("LaserEnd");
					}
				}
			}
			bonusDuration = 0f;
			for (int i = 1; i <= lunarSpikeCount; i++)
			{
				bonusDuration += 1f / (0.5f * (float)i + 1f);
			}
			if (bonusDuration < 0f)
			{
				bonusDuration = 0f;
			}
			duration += bonusDuration;
			base.characterBody.SetAimTimer(duration);
			float num = base.characterBody.attackSpeed - base.characterBody.baseAttackSpeed;
			fireFrequency += num * 0.3f;
			maxSecondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock;
			secondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock;
			LaserFatherCharged.laserTracking?.Invoke(duration);
		}

		public override void OnExit()
		{
			aimRequest?.Dispose();
			if ((bool)laserEffect)
			{
				LaserFatherCharged.laserTracking?.Invoke(0f);
				EntityState.Destroy(laserEffect);
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			base.characterBody.SetAimTimer(2f);
			Util.PlaySound("Stop_falseson_skill4_laser_loop", base.gameObject);
			Util.PlaySound("Stop_falseson_skill4_laser_charge_loop", base.gameObject);
			Util.PlaySound("Play_falseson_skill4_laser_end", base.gameObject);
			PlayAnimation("Gesture, Head, Override", "FireLaserLoopEnd");
			PlayAnimation("Gesture, Head, Additive", "FireLaserLoopEnd");
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			fireStopwatch += deltaTime;
			stopwatch += deltaTime;
			refillSecondaryStopwatch += deltaTime;
			if (refillSecondaryStopwatch > 1f)
			{
				maxSecondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).maxStock;
				secondaryStock = base.skillLocator.GetSkill(SkillSlot.Secondary).stock;
				if (secondaryStock < maxSecondaryStock)
				{
					base.skillLocator.GetSkill(SkillSlot.Secondary).stock++;
					refillSecondaryStopwatch = 0f;
				}
			}
			aimRay = GetAimRay();
			UnityEngine.Vector3 vector = aimRay.origin;
			if ((bool)muzzleTransform)
			{
				vector = muzzleTransform.position;
			}
			UnityEngine.Vector3 vector2;
			if ((bool)lockedOnHurtBox)
			{
				vector2 = lockedOnHurtBox.transform.position;
			}
			else
			{
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, maxDistance, base.gameObject);
				vector2 = ((!Util.CharacterRaycast(base.gameObject, aimRay, out var hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore)) ? aimRay.GetPoint(maxDistance) : hitInfo.point);
			}
			Ray ray = new Ray(vector, vector2 - vector);
			bool flag = false;
			if ((bool)laserEffect && (bool)laserChildLocator)
			{
				if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo2, (vector2 - vector).magnitude, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
				{
					vector2 = hitInfo2.point;
					if (Util.CharacterRaycast(base.gameObject, new Ray(vector2 - ray.direction * 0.1f, -ray.direction), out var _, hitInfo2.distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
					{
						vector2 = ray.GetPoint(0.1f);
						flag = true;
					}
				}
				laserEffect.transform.rotation = Util.QuaternionSafeLookRotation(vector2 - vector);
				laserEffectEnd.transform.position = vector2;
			}
			if (fireStopwatch > 1f / fireFrequency)
			{
				string targetMuzzle = "MuzzleLaser";
				if (!flag)
				{
					FireBullet(modelTransform, ray, targetMuzzle, (vector2 - ray.origin).magnitude + 0.1f);
				}
				fireStopwatch -= 1f / fireFrequency;
			}
			if (base.isAuthority && stopwatch > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		private void FireBullet(Transform modelTransform, Ray aimRay, string targetMuzzle, float maxDistance)
		{
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				if (charge > 0.85f)
				{
					charge = 1f;
				}
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = 1u;
				bulletAttack.damage = damageCoefficient * damageStat * charge;
				bulletAttack.force = force;
				bulletAttack.muzzleName = targetMuzzle;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.procCoefficient = procCoefficientPerTick;
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = 1f;
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.Fire();
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(HurtBoxReference.FromHurtBox(lockedOnHurtBox));
			writer.Write(stopwatch);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			HurtBoxReference hurtBoxReference = reader.ReadHurtBoxReference();
			stopwatch = reader.ReadSingle();
			lockedOnHurtBox = hurtBoxReference.ResolveGameObject()?.GetComponent<HurtBox>();
		}
	}
	public class LunarSpikes : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force = 20f;

		public static float attackSpeedAltAnimationThreshold;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float attackSoundPitch;

		public static float bloom;

		private float duration;

		private bool hasFiredSpike;

		private string muzzleString;

		private Transform muzzleTransform;

		private Animator animator;

		private ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch);
			base.characterBody.SetAimTimer(2f);
			animator = GetModelAnimator();
			if ((bool)animator)
			{
				childLocator = animator.GetComponent<ChildLocator>();
			}
			muzzleString = "MuzzleRight";
			if (attackSpeedStat < attackSpeedAltAnimationThreshold)
			{
				PlayCrossfade("Gesture, Additive", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f);
				PlayCrossfade("Gesture, Override", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f);
				FireLunarSpike();
			}
			else
			{
				PlayAnimation("Gesture, Override", "HoldGauntletsUp", "LunarSpike.playbackRate", duration);
				FireLunarSpike();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireLunarSpike()
		{
			if (!hasFiredSpike)
			{
				base.characterBody.AddSpreadBloom(bloom);
				hasFiredSpike = true;
				Ray ray = GetAimRay();
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
				if ((bool)childLocator)
				{
					muzzleTransform = childLocator.FindChild(muzzleString);
				}
				if ((bool)muzzleflashEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
				}
				if (base.isAuthority)
				{
					ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageCoefficient * damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Void);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class LunarSpikesShotgun : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject muzzleflashEffectPrefab;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force = 20f;

		public static float attackSpeedAltAnimationThreshold;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float attackSoundPitch;

		public static float bloom;

		private float duration;

		private bool hasFiredSpike;

		private string muzzleString;

		private Transform muzzleTransform;

		private Animator animator;

		private ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPitch);
			base.characterBody.SetAimTimer(2f);
			animator = GetModelAnimator();
			if ((bool)animator)
			{
				childLocator = animator.GetComponent<ChildLocator>();
			}
			muzzleString = "MuzzleRight";
			if (attackSpeedStat < attackSpeedAltAnimationThreshold)
			{
				PlayCrossfade("Gesture, Additive", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f);
				PlayCrossfade("Gesture, Override", "FireLunarSpike", "LunarSpike.playbackRate", duration, 0.1f);
				FireLunarSpike();
			}
			else
			{
				PlayAnimation("Gesture, Override", "HoldGauntletsUp", "LunarSpike.playbackRate", duration);
				FireLunarSpike();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireLunarSpike()
		{
			if (!hasFiredSpike)
			{
				base.characterBody.AddSpreadBloom(bloom);
				hasFiredSpike = true;
				Ray ray = GetAimRay();
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
				if ((bool)childLocator)
				{
					muzzleTransform = childLocator.FindChild(muzzleString);
				}
				if ((bool)muzzleflashEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: false);
				}
				if (base.isAuthority)
				{
					ProjectileManager.instance.FireProjectile(projectilePrefab, ray.origin, Util.QuaternionSafeLookRotation(ray.direction), base.gameObject, damageCoefficient * damageStat, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Void);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class OverheadClubSwing : BasicMeleeAttack
	{
		protected override void PlayAnimation()
		{
			PlayAnimation("FullBody, Override", "OverheadSwing", "ChargeSwing.playbackRate", duration);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class StepBrothers : BaseState
	{
		private Transform modelTransform;

		public static GameObject dashPrefab;

		public static float smallHopVelocity;

		public static float dashPrepDuration;

		public static float dashDuration = 0.3f;

		public static float speedCoefficient = 25f;

		public static string beginSoundString;

		public static float damageCoefficient;

		public static float procCoefficient;

		public static GameObject hitEffectPrefab;

		public static float hitPauseDuration;

		private float stopwatch;

		private UnityEngine.Vector3 dashVector = UnityEngine.Vector3.zero;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private OverlapAttack overlapAttack;

		private ChildLocator childLocator;

		private bool isDashing;

		private bool inHitPause;

		private float hitPauseTimer;

		private CameraTargetParams.AimRequest aimRequest;

		private CharacterBody survivorBody;

		public static GameObject explosionEffect;

		public BlastAttack explosionAttack;

		private int originalLayer;

		public bool hasHit { get; private set; }

		public int dashIndex { private get; set; }

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			survivorBody = base.gameObject.GetComponent<CharacterBody>();
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
				childLocator = modelTransform.GetComponent<ChildLocator>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
				_ = (bool)childLocator;
			}
			PlayAnimation("FullBody, Override", "StepBrothersPrep", "StepBrothersPrep.playbackRate", dashPrepDuration);
			dashVector = base.inputBank.aimDirection;
			overlapAttack = InitMeleeOverlap(0f, hitEffectPrefab, modelTransform, "StepBrothers");
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
		}

		private void CreateDashEffect()
		{
			Transform transform = childLocator.FindChild("DashCenter");
			if ((bool)transform && (bool)dashPrefab)
			{
				UnityEngine.Object.Instantiate(dashPrefab, transform.position, Util.QuaternionSafeLookRotation(dashVector), transform);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterDirection.forward = dashVector;
			if (stopwatch > dashPrepDuration / attackSpeedStat && !isDashing)
			{
				isDashing = true;
				dashVector = base.inputBank.aimDirection;
				CreateDashEffect();
				PlayCrossfade("FullBody, Override", "StepBrothersLoop", 0.1f);
				originalLayer = base.gameObject.layer;
				base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
				base.characterMotor.Motor.RebuildCollidableLayers();
			}
			if (!isDashing)
			{
				stopwatch += GetDeltaTime();
			}
			else if (base.isAuthority)
			{
				base.characterMotor.velocity = UnityEngine.Vector3.zero;
				if (!inHitPause)
				{
					bool num = overlapAttack.Fire();
					stopwatch += GetDeltaTime();
					if (num)
					{
						UnityEngine.Vector3 position = base.gameObject.transform.position;
						UnityEngine.Object.Instantiate(explosionEffect, position, UnityEngine.Quaternion.identity);
						explosionAttack = new BlastAttack();
						explosionAttack.attacker = base.gameObject;
						explosionAttack.inflictor = base.gameObject;
						explosionAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
						explosionAttack.baseDamage = damageStat * damageCoefficient;
						explosionAttack.position = position;
						explosionAttack.radius = 20f;
						explosionAttack.Fire();
						if (!hasHit)
						{
							hasHit = true;
						}
						inHitPause = true;
						hitPauseTimer = hitPauseDuration / attackSpeedStat;
					}
					base.characterMotor.rootMotion += dashVector * moveSpeedStat * speedCoefficient * GetDeltaTime();
				}
				else
				{
					hitPauseTimer -= GetDeltaTime();
					if (hitPauseTimer < 0f)
					{
						inHitPause = false;
					}
				}
			}
			if (stopwatch >= dashDuration + dashPrepDuration / attackSpeedStat && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			_ = base.isAuthority;
			aimRequest?.Dispose();
			_ = (bool)childLocator;
			PlayAnimation("FullBody, Override", "StepBrothersLoopExit");
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)dashIndex);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			dashIndex = reader.ReadByte();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class TheTamperedHeart : BaseState
	{
		public override void OnEnter()
		{
		}
	}
}
namespace EntityStates.EngiTurret
{
	public class DeathState : GenericCharacterDeath
	{
		[SerializeField]
		public GameObject initialExplosion;

		[SerializeField]
		public GameObject deathExplosion;

		private float deathDuration;

		protected override bool shouldAutoDestroy => false;

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				modelAnimator.PlayInFixedTime("Death", layerIndex);
				modelAnimator.Update(0f);
				deathDuration = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length;
				if ((bool)initialExplosion)
				{
					UnityEngine.Object.Instantiate(initialExplosion, base.transform.position, base.transform.rotation, base.transform);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > deathDuration && NetworkServer.active && (bool)deathExplosion)
			{
				EffectManager.SpawnEffect(deathExplosion, new EffectData
				{
					origin = base.transform.position,
					scale = 2f
				}, transmit: true);
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
}
namespace EntityStates.EngiTurret.EngiTurretWeapon
{
	public class FireBeam : BaseState
	{
		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject laserPrefab;

		[SerializeField]
		public string muzzleString;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public float minSpread;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public int bulletCount;

		[SerializeField]
		public float fireFrequency;

		[SerializeField]
		public float maxDistance;

		private float fireTimer;

		private Ray laserRay;

		private Transform modelTransform;

		private GameObject laserEffectInstance;

		private Transform laserEffectInstanceEndTransform;

		private UnityEngine.Vector3 laserEndPoint;

		private float prevLaserDistance;

		private bool forceCast;

		private BulletAttack bulletAttack;

		private EffectManagerHelper _emh_laserEffect;

		public override void Reset()
		{
			base.Reset();
			fireTimer = 0f;
			laserEndPoint = UnityEngine.Vector3.zero;
			modelTransform = null;
			laserEffectInstance = null;
			laserEffectInstanceEndTransform = null;
			forceCast = true;
			if (bulletAttack != null)
			{
				bulletAttack.Reset();
			}
			_emh_laserEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(attackSoundString, base.gameObject);
			fireTimer = 0f;
			forceCast = true;
			modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild(muzzleString);
			if ((bool)transform && (bool)laserPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(laserPrefab))
				{
					laserEffectInstance = UnityEngine.Object.Instantiate(laserPrefab, transform.position, transform.rotation);
				}
				else
				{
					_emh_laserEffect = EffectManager.GetAndActivatePooledEffect(laserPrefab, transform.position, transform.rotation);
					laserEffectInstance = _emh_laserEffect.gameObject;
				}
				if ((bool)laserEffectInstance)
				{
					ChildLocator component2 = laserEffectInstance.GetComponent<ChildLocator>();
					laserEffectInstanceEndTransform = component2.FindChild("LaserEnd");
				}
				laserEffectInstance.transform.parent = transform;
			}
		}

		public override void OnExit()
		{
			if ((bool)laserEffectInstance)
			{
				if (_emh_laserEffect != null && _emh_laserEffect.OwningPool != null)
				{
					_emh_laserEffect.OwningPool.ReturnObject(_emh_laserEffect);
				}
				else
				{
					EntityState.Destroy(laserEffectInstance);
				}
				laserEffectInstance = null;
				_emh_laserEffect = null;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!(Time.deltaTime > 0f))
			{
				return;
			}
			laserRay = GetLaserRay();
			fireTimer += Time.deltaTime;
			float num = fireFrequency * base.characterBody.attackSpeed;
			float num2 = 1f / num;
			if (fireTimer > num2)
			{
				if (base.isAuthority)
				{
					laserEndPoint = FireBullet(laserRay, muzzleString);
					prevLaserDistance = (laserEndPoint - laserRay.origin).magnitude;
				}
				else
				{
					forceCast = true;
				}
				fireTimer = 0f;
			}
			else if (!forceCast && prevLaserDistance > float.Epsilon)
			{
				laserEndPoint = laserRay.origin + laserRay.direction * prevLaserDistance;
			}
			if (forceCast)
			{
				forceCast = false;
				if ((bool)laserEffectInstance && (bool)laserEffectInstanceEndTransform)
				{
					float distance = maxDistance;
					_ = laserEffectInstance.transform.parent.position;
					laserEndPoint = laserRay.GetPoint(distance);
					if (Util.CharacterRaycast(base.gameObject, laserRay, out var hitInfo, distance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
					{
						laserEndPoint = hitInfo.point;
						prevLaserDistance = (laserEndPoint - laserRay.origin).magnitude;
					}
				}
			}
			if ((bool)laserEffectInstance && (bool)laserEffectInstanceEndTransform)
			{
				laserEffectInstanceEndTransform.position = laserEndPoint;
			}
			if (base.isAuthority && !ShouldFireLaser())
			{
				outer.SetNextStateToMain();
			}
		}

		protected UnityEngine.Vector3 GetBeamEndPoint()
		{
			UnityEngine.Vector3 point = laserRay.GetPoint(maxDistance);
			if (Util.CharacterRaycast(base.gameObject, laserRay, out var hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
			{
				point = hitInfo.point;
			}
			return point;
		}

		protected virtual EntityState GetNextState()
		{
			return EntityStateCatalog.InstantiateState(ref outer.mainStateType);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}

		public virtual void ModifyBullet(BulletAttack bulletAttack)
		{
			bulletAttack.damageType |= (DamageTypeCombo)DamageType.SlowOnHit;
		}

		public virtual bool ShouldFireLaser()
		{
			if ((bool)base.inputBank)
			{
				return base.inputBank.skill1.down;
			}
			return false;
		}

		public virtual Ray GetLaserRay()
		{
			return GetAimRay();
		}

		private UnityEngine.Vector3 FireBullet(Ray laserRay, string targetMuzzle)
		{
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				if (bulletAttack == null)
				{
					bulletAttack = new BulletAttack();
				}
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = laserRay.origin;
				bulletAttack.aimVector = laserRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = 1u;
				bulletAttack.damage = damageCoefficient * damageStat / fireFrequency;
				bulletAttack.procCoefficient = procCoefficient / fireFrequency;
				bulletAttack.force = force;
				bulletAttack.muzzleName = targetMuzzle;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = 0f;
				bulletAttack.maxDistance = maxDistance;
				ModifyBullet(bulletAttack);
				return bulletAttack.Fire_ReturnHit();
			}
			return UnityEngine.Vector3.zero;
		}
	}
	public class FireGauss : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static string attackSoundString;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public int bulletCountCurrent = 1;

		private float duration;

		private static int FireGaussStateHash = Animator.StringToHash("FireGauss");

		private static int FireGaussParamHash = Animator.StringToHash("FireGauss.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(attackSoundString, base.gameObject);
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			PlayAnimation("Gesture", FireGaussStateHash, FireGaussParamHash, duration);
			string muzzleName = "Muzzle";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = 1u;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = 0.15f;
				bulletAttack.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Engi.SpiderMine
{
	public class BaseSpiderMineState : BaseState
	{
		protected static int IdleToArmedStateHash = Animator.StringToHash("IdleToArmed");

		protected static int IdleToArmedParamHash = Animator.StringToHash("IdleToArmed.playbackRate");

		protected static int ArmedToChaseStateHash = Animator.StringToHash("ArmedToChase");

		protected static int ArmedToChaseParamHash = Animator.StringToHash("ArmedToChase.playbackRate");

		protected static int ChaseStateHash = Animator.StringToHash("Chase");

		[SerializeField]
		public string enterSoundString;

		[SerializeField]
		public string childLocatorStringToEnable;

		protected ProjectileStickOnImpact projectileStickOnImpact { get; private set; }

		protected ProjectileTargetComponent projectileTargetComponent { get; private set; }

		protected ProjectileGhostController projectileGhostController { get; private set; }

		protected virtual bool shouldStick => false;

		public override void OnEnter()
		{
			base.OnEnter();
			projectileStickOnImpact = GetComponent<ProjectileStickOnImpact>();
			projectileTargetComponent = GetComponent<ProjectileTargetComponent>();
			projectileGhostController = base.projectileController.ghost;
			if ((bool)base.modelLocator && (bool)projectileGhostController)
			{
				base.modelLocator.modelBaseTransform = projectileGhostController.transform;
				base.modelLocator.modelTransform = base.modelLocator.modelBaseTransform.Find("mdlEngiSpiderMine");
				base.modelLocator.preserveModel = true;
				base.modelLocator.noCorpse = true;
			}
			if (projectileStickOnImpact.enabled != shouldStick)
			{
				projectileStickOnImpact.enabled = shouldStick;
			}
			Transform transform = FindModelChild(childLocatorStringToEnable);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: true);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		protected void EmitDustEffect()
		{
			if ((bool)projectileGhostController)
			{
				projectileGhostController.transform.Find("Ring").GetComponent<ParticleSystem>().Play();
			}
		}
	}
	public class WaitForStick : BaseSpiderMineState
	{
		private static int IdleStateHash = Animator.StringToHash("Idle");

		protected override bool shouldStick => true;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", IdleStateHash);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.projectileStickOnImpact.stuck)
			{
				outer.SetNextState(new Burrow());
			}
		}
	}
	public class Burrow : BaseSpiderMineState
	{
		public static float baseDuration;

		private float duration;

		protected override bool shouldStick => true;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			PlayAnimation("Base", BaseSpiderMineState.IdleToArmedStateHash, BaseSpiderMineState.IdleToArmedParamHash, duration);
			EmitDustEffect();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				EntityState entityState = null;
				if (!base.projectileStickOnImpact.stuck)
				{
					entityState = new WaitForStick();
				}
				else if (duration <= base.fixedAge)
				{
					entityState = new WaitForTarget();
				}
				if (entityState != null)
				{
					outer.SetNextState(entityState);
				}
			}
		}
	}
	public class WaitForTarget : BaseSpiderMineState
	{
		private static int ArmedStateHash = Animator.StringToHash("Armed");

		protected ProjectileSphereTargetFinder targetFinder { get; private set; }

		protected override bool shouldStick => true;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				targetFinder = GetComponent<ProjectileSphereTargetFinder>();
				targetFinder.enabled = true;
			}
			PlayAnimation("Base", ArmedStateHash);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				EntityState entityState = null;
				if (!base.projectileStickOnImpact.stuck)
				{
					entityState = new WaitForStick();
				}
				else if ((bool)base.projectileTargetComponent.target)
				{
					entityState = new Unburrow();
				}
				if (entityState != null)
				{
					outer.SetNextState(entityState);
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)targetFinder)
			{
				targetFinder.enabled = false;
			}
			base.OnExit();
		}
	}
	public class Unburrow : BaseSpiderMineState
	{
		public static float baseDuration;

		public static int betterTargetSearchLimit;

		private float duration;

		protected override bool shouldStick => true;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			Util.PlaySound("Play_beetle_worker_idle", base.gameObject);
			PlayAnimation("Base", BaseSpiderMineState.ArmedToChaseStateHash, BaseSpiderMineState.ArmedToChaseParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			EntityState entityState = null;
			if (!base.projectileStickOnImpact.stuck)
			{
				entityState = new WaitForStick();
			}
			else if ((bool)base.projectileTargetComponent.target)
			{
				if (duration <= base.fixedAge)
				{
					FindBetterTarget(base.projectileTargetComponent.target);
					entityState = new ChaseTarget();
				}
			}
			else
			{
				entityState = new Burrow();
			}
			if (entityState != null)
			{
				outer.SetNextState(entityState);
			}
		}

		private BullseyeSearch CreateBullseyeSearch(UnityEngine.Vector3 origin)
		{
			return new BullseyeSearch
			{
				searchOrigin = origin,
				filterByDistinctEntity = true,
				maxDistanceFilter = Detonate.blastRadius,
				sortMode = BullseyeSearch.SortMode.Distance,
				maxAngleFilter = 360f,
				teamMaskFilter = TeamMask.GetEnemyTeams(base.projectileController.teamFilter.teamIndex)
			};
		}

		private void FindBetterTarget(Transform initialTarget)
		{
			BullseyeSearch bullseyeSearch = CreateBullseyeSearch(initialTarget.position);
			bullseyeSearch.RefreshCandidates();
			HurtBox[] array = bullseyeSearch.GetResults().ToArray();
			int num = array.Length;
			int num2 = -1;
			int i = 0;
			for (int num3 = Math.Min(array.Length, betterTargetSearchLimit); i < num3; i++)
			{
				HurtBox hurtBox = array[i];
				int num4 = CountTargets(hurtBox.transform.position);
				if (num < num4)
				{
					num = num4;
					num2 = i;
				}
			}
			if (num2 != -1)
			{
				base.projectileTargetComponent.target = array[num2].transform;
			}
		}

		private int CountTargets(UnityEngine.Vector3 origin)
		{
			BullseyeSearch bullseyeSearch = CreateBullseyeSearch(origin);
			bullseyeSearch.RefreshCandidates();
			return bullseyeSearch.GetResults().Count();
		}
	}
	public class ChaseTarget : BaseSpiderMineState
	{
		private class OrientationHelper : MonoBehaviour
		{
			private Rigidbody rigidbody;

			private void Awake()
			{
				rigidbody = GetComponent<Rigidbody>();
			}

			private void OnCollisionStay(Collision collision)
			{
				int contactCount = collision.contactCount;
				if (contactCount == 0)
				{
					return;
				}
				UnityEngine.Vector3 forward = collision.GetContact(0).normal;
				for (int i = 1; i < contactCount; i++)
				{
					UnityEngine.Vector3 normal = collision.GetContact(i).normal;
					if (forward.y < normal.y)
					{
						forward = normal;
					}
				}
				rigidbody.MoveRotation(UnityEngine.Quaternion.LookRotation(forward));
			}
		}

		public static float speed;

		public static float triggerRadius;

		private bool passedDetonationRadius;

		private float bestDistance;

		private OrientationHelper orientationHelper;

		private Transform target => base.projectileTargetComponent.target;

		protected override bool shouldStick => false;

		public override void OnEnter()
		{
			base.OnEnter();
			passedDetonationRadius = false;
			bestDistance = float.PositiveInfinity;
			PlayAnimation("Base", BaseSpiderMineState.ChaseStateHash);
			if (base.isAuthority)
			{
				orientationHelper = base.gameObject.AddComponent<OrientationHelper>();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			if (!target)
			{
				base.rigidbody.AddForce(UnityEngine.Vector3.up, ForceMode.VelocityChange);
				outer.SetNextState(new WaitForStick());
				return;
			}
			UnityEngine.Vector3 position = target.position;
			UnityEngine.Vector3 position2 = base.transform.position;
			UnityEngine.Vector3 vector = position - position2;
			float magnitude = vector.magnitude;
			float y = base.rigidbody.velocity.y;
			UnityEngine.Vector3 velocity = vector * (speed / magnitude);
			velocity.y = y;
			base.rigidbody.velocity = velocity;
			if (!passedDetonationRadius && magnitude <= triggerRadius)
			{
				passedDetonationRadius = true;
			}
			if (magnitude < bestDistance)
			{
				bestDistance = magnitude;
			}
			else if (passedDetonationRadius)
			{
				outer.SetNextState(new PreDetonate());
			}
		}

		public override void OnExit()
		{
			Transform transform = FindModelChild(childLocatorStringToEnable);
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: false);
			}
			if ((object)orientationHelper != null)
			{
				EntityState.Destroy(orientationHelper);
				orientationHelper = null;
			}
			base.OnExit();
		}
	}
	public class PreDetonate : BaseSpiderMineState
	{
		public static float baseDuration;

		private float duration;

		protected override bool shouldStick => false;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			base.rigidbody.isKinematic = true;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && duration <= base.fixedAge)
			{
				outer.SetNextState(new Detonate());
			}
		}
	}
	public class Detonate : BaseSpiderMineState
	{
		public static float blastRadius;

		public static GameObject blastEffectPrefab;

		[SerializeField]
		private List<string> childLocatorStringToDisable = new List<string> { "Armed", "Chase", "PreDetonate" };

		protected override bool shouldStick => false;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!NetworkServer.active)
			{
				return;
			}
			ProjectileDamage component = GetComponent<ProjectileDamage>();
			UnityEngine.Vector3 position = base.transform.position;
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.position = position;
			blastAttack.attacker = base.projectileController.owner;
			blastAttack.baseDamage = component.damage;
			blastAttack.baseForce = component.force;
			blastAttack.bonusForce = UnityEngine.Vector3.zero;
			blastAttack.crit = component.crit;
			blastAttack.damageColorIndex = component.damageColorIndex;
			blastAttack.damageType = component.damageType;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.inflictor = base.gameObject;
			blastAttack.procChainMask = base.projectileController.procChainMask;
			blastAttack.radius = blastRadius;
			blastAttack.teamIndex = base.projectileController.teamFilter.teamIndex;
			blastAttack.procCoefficient = base.projectileController.procCoefficient;
			blastAttack.Fire();
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = position,
				scale = blastRadius
			}, transmit: true);
			float duration = 0.25f;
			PlayAnimation("Base", BaseSpiderMineState.IdleToArmedStateHash, BaseSpiderMineState.IdleToArmedParamHash, duration);
			foreach (string item in childLocatorStringToDisable)
			{
				Transform transform = FindModelChild(item);
				if ((bool)transform)
				{
					transform.gameObject.SetActive(value: false);
				}
			}
			EntityState.Destroy(base.gameObject);
		}
	}
}
namespace EntityStates.Engi.MineDeployer
{
	public class BaseMineDeployerState : BaseState
	{
		public static List<BaseMineDeployerState> instancesList = new List<BaseMineDeployerState>();

		public GameObject owner { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			owner = base.projectileController?.owner;
			instancesList.Add(this);
		}

		public override void OnExit()
		{
			instancesList.Remove(this);
			base.OnExit();
		}
	}
	public class FireMine : BaseMineDeployerState
	{
		public static float duration;

		public static float launchApex;

		public static float patternRadius;

		public static GameObject projectilePrefab;

		private int fireIndex;

		private static UnityEngine.Vector3[] velocities;

		private static bool velocitiesResolved;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				ResolveVelocities();
				Transform transform = base.transform.Find("FirePoint");
				ProjectileDamage component = GetComponent<ProjectileDamage>();
				UnityEngine.Vector3 forward = transform.TransformVector(velocities[fireIndex]);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.crit = component.crit;
				fireProjectileInfo.damage = component.damage;
				fireProjectileInfo.damageColorIndex = component.damageColorIndex;
				fireProjectileInfo.force = component.force;
				fireProjectileInfo.owner = base.owner;
				fireProjectileInfo.position = transform.position;
				fireProjectileInfo.procChainMask = base.projectileController.procChainMask;
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(forward);
				fireProjectileInfo.fuseOverride = -1f;
				fireProjectileInfo.useFuseOverride = false;
				fireProjectileInfo.speedOverride = forward.magnitude;
				fireProjectileInfo.useSpeedOverride = true;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && duration <= base.fixedAge)
			{
				int num = fireIndex + 1;
				if (num < velocities.Length)
				{
					outer.SetNextState(new FireMine
					{
						fireIndex = num
					});
				}
				else
				{
					outer.SetNextState(new WaitForDeath());
				}
			}
		}

		private static UnityEngine.Vector3[] GeneratePoints(float radius)
		{
			UnityEngine.Vector3[] array = new UnityEngine.Vector3[9];
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(60f, UnityEngine.Vector3.up);
			UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(120f, UnityEngine.Vector3.up);
			UnityEngine.Vector3 forward = UnityEngine.Vector3.forward;
			array[0] = forward;
			array[1] = quaternion2 * array[0];
			array[2] = quaternion2 * array[1];
			float num = 1f;
			float num2 = UnityEngine.Vector3.Distance(array[0], array[1]);
			float num3 = Mathf.Sqrt(num * num + num2 * num2) / num;
			array[3] = quaternion * (array[2] * num3);
			array[4] = quaternion2 * array[3];
			array[5] = quaternion2 * array[4];
			num3 = 1f;
			array[6] = quaternion * (array[5] * num3);
			array[7] = quaternion2 * array[6];
			array[8] = quaternion2 * array[7];
			float num4 = radius / array[8].magnitude;
			for (int i = 0; i < array.Length; i++)
			{
				array[i] *= num4;
			}
			return array;
		}

		private static UnityEngine.Vector3[] GenerateHexPoints(float radius)
		{
			UnityEngine.Vector3[] array = new UnityEngine.Vector3[6];
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(60f, UnityEngine.Vector3.up);
			ref UnityEngine.Vector3 reference = ref array[0];
			reference = UnityEngine.Vector3.forward * radius;
			for (int i = 1; i < array.Length; i++)
			{
				ref UnityEngine.Vector3 reference2 = ref array[i];
				reference2 = quaternion * reference;
				reference = ref reference2;
			}
			return array;
		}

		private static UnityEngine.Vector3[] GeneratePointsFromPattern(GameObject patternObject)
		{
			Transform transform = patternObject.transform;
			UnityEngine.Vector3 position = transform.position;
			List<UnityEngine.Vector3> list = new List<UnityEngine.Vector3>();
			for (int i = 0; i < transform.childCount; i++)
			{
				Transform child = transform.GetChild(i);
				if (child.gameObject.activeInHierarchy)
				{
					list.Add(child.position - position);
				}
			}
			return list.ToArray();
		}

		private static UnityEngine.Vector3[] GenerateVelocitiesFromPoints(UnityEngine.Vector3[] points, float apex)
		{
			UnityEngine.Vector3[] array = new UnityEngine.Vector3[points.Length];
			float num = Trajectory.CalculateInitialYSpeedForHeight(apex);
			for (int i = 0; i < points.Length; i++)
			{
				UnityEngine.Vector3 normalized = points[i].normalized;
				float num2 = Trajectory.CalculateGroundSpeedToClearDistance(num, points[i].magnitude);
				UnityEngine.Vector3 vector = normalized * num2;
				vector.y = num;
				array[i] = vector;
			}
			return array;
		}

		private static void ResolveVelocities()
		{
			if (!velocitiesResolved)
			{
				velocities = GenerateVelocitiesFromPoints(GeneratePoints(patternRadius), launchApex);
				if (!Application.isEditor)
				{
					velocitiesResolved = true;
				}
			}
		}
	}
	public class WaitForDeath : BaseMineDeployerState
	{
		public static float duration;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && duration <= base.fixedAge)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
	public class WaitForStick : BaseMineDeployerState
	{
		private ProjectileStickOnImpact projectileStickOnImpact;

		public override void OnEnter()
		{
			base.OnEnter();
			projectileStickOnImpact = GetComponent<ProjectileStickOnImpact>();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && projectileStickOnImpact.stuck)
			{
				outer.SetNextState(new FireMine());
			}
		}
	}
}
namespace EntityStates.Engi.Mine
{
	public class BaseMineArmingState : BaseState
	{
		[SerializeField]
		public float damageScale;

		[SerializeField]
		public float forceScale;

		[SerializeField]
		public float blastRadiusScale;

		[SerializeField]
		public float triggerRadius;

		[SerializeField]
		public string onEnterSfx;

		[SerializeField]
		public float onEnterSfxPlaybackRate;

		[SerializeField]
		public string pathToChildToEnable;

		private Transform enabledChild;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlayAttackSpeedSound(onEnterSfx, base.gameObject, onEnterSfxPlaybackRate);
			if (!string.IsNullOrEmpty(pathToChildToEnable))
			{
				enabledChild = base.transform.Find(pathToChildToEnable);
				if ((bool)enabledChild)
				{
					enabledChild.gameObject.SetActive(value: true);
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)enabledChild)
			{
				enabledChild.gameObject.SetActive(value: false);
			}
			base.OnExit();
		}
	}
	public class MineArmingUnarmed : BaseMineArmingState
	{
	}
	public class MineArmingWeak : BaseMineArmingState
	{
		public static float duration;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && duration <= base.fixedAge)
			{
				outer.SetNextState(new MineArmingFull());
			}
		}
	}
	public class MineArmingFull : BaseMineArmingState
	{
	}
	public class BaseMineState : BaseState
	{
		[SerializeField]
		public string enterSoundString;

		protected ProjectileStickOnImpact projectileStickOnImpact { get; private set; }

		protected EntityStateMachine armingStateMachine { get; private set; }

		protected virtual bool shouldStick => false;

		protected virtual bool shouldRevertToWaitForStickOnSurfaceLost => false;

		public override void OnEnter()
		{
			base.OnEnter();
			projectileStickOnImpact = GetComponent<ProjectileStickOnImpact>();
			armingStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Arming");
			if (projectileStickOnImpact.enabled != shouldStick)
			{
				projectileStickOnImpact.enabled = shouldStick;
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && shouldRevertToWaitForStickOnSurfaceLost && !projectileStickOnImpact.stuck)
			{
				outer.SetNextState(new WaitForStick());
			}
		}
	}
	public class WaitForStick : BaseMineState
	{
		protected override bool shouldStick => true;

		protected override bool shouldRevertToWaitForStickOnSurfaceLost => false;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				base.armingStateMachine.SetNextState(new MineArmingUnarmed());
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.projectileStickOnImpact.stuck)
			{
				outer.SetNextState(new Arm());
			}
		}
	}
	public class Arm : BaseMineState
	{
		public static float duration;

		protected override bool shouldStick => true;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && duration <= base.fixedAge)
			{
				outer.SetNextState(new WaitForTarget());
			}
		}
	}
	public class WaitForTarget : BaseMineState
	{
		private ProjectileSphereTargetFinder targetFinder;

		private ProjectileTargetComponent projectileTargetComponent;

		private ProjectileImpactExplosion projectileImpactExplosion;

		protected override bool shouldStick => true;

		public override void OnEnter()
		{
			base.OnEnter();
			projectileTargetComponent = GetComponent<ProjectileTargetComponent>();
			targetFinder = GetComponent<ProjectileSphereTargetFinder>();
			if (NetworkServer.active)
			{
				targetFinder.enabled = true;
				base.armingStateMachine.SetNextState(new MineArmingWeak());
			}
		}

		public override void OnExit()
		{
			if ((bool)targetFinder)
			{
				targetFinder.enabled = false;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)targetFinder)
			{
				if ((bool)projectileTargetComponent.target)
				{
					outer.SetNextState(new PreDetonate());
				}
				if (base.armingStateMachine?.state is BaseMineArmingState baseMineArmingState)
				{
					targetFinder.enabled = baseMineArmingState.triggerRadius != 0f;
					targetFinder.lookRange = baseMineArmingState.triggerRadius;
				}
			}
		}
	}
	public class PreDetonate : BaseMineState
	{
		public static float duration;

		public static string pathToPrepForExplosionChildEffect;

		public static float detachForce;

		protected override bool shouldStick => false;

		protected override bool shouldRevertToWaitForStickOnSurfaceLost => false;

		public override void OnEnter()
		{
			base.OnEnter();
			base.transform.Find(pathToPrepForExplosionChildEffect).gameObject.SetActive(value: true);
			base.rigidbody.AddForce(base.transform.forward * detachForce);
			base.rigidbody.AddTorque(UnityEngine.Random.onUnitSphere * 200f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && duration <= base.fixedAge)
			{
				outer.SetNextState(new Detonate());
			}
		}
	}
	public class Detonate : BaseMineState
	{
		public static float blastRadius;

		public static GameObject explosionEffectPrefab;

		protected override bool shouldStick => false;

		protected override bool shouldRevertToWaitForStickOnSurfaceLost => false;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				Explode();
			}
		}

		private void Explode()
		{
			ProjectileDamage component = GetComponent<ProjectileDamage>();
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			if (base.armingStateMachine?.state is BaseMineArmingState baseMineArmingState)
			{
				num = baseMineArmingState.damageScale;
				num2 = baseMineArmingState.forceScale;
				num3 = baseMineArmingState.blastRadiusScale;
			}
			float num4 = blastRadius * num3;
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.procChainMask = base.projectileController.procChainMask;
			blastAttack.procCoefficient = base.projectileController.procCoefficient;
			blastAttack.attacker = base.projectileController.owner;
			blastAttack.inflictor = base.gameObject;
			blastAttack.teamIndex = base.projectileController.teamFilter.teamIndex;
			blastAttack.procCoefficient = base.projectileController.procCoefficient;
			blastAttack.baseDamage = component.damage * num;
			blastAttack.baseForce = component.force * num2;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.crit = component.crit;
			blastAttack.radius = num4;
			blastAttack.position = base.transform.position;
			blastAttack.damageColorIndex = component.damageColorIndex;
			blastAttack.Fire();
			if ((bool)explosionEffectPrefab)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					rotation = base.transform.rotation,
					scale = num4
				}, transmit: true);
			}
			EntityState.Destroy(base.gameObject);
		}
	}
}
namespace EntityStates.Engi.EngiWeapon
{
	public class ChargeGrenades : BaseState
	{
		public static float baseTotalDuration;

		public static float baseMaxChargeTime;

		public static int maxCharges;

		public static GameObject chargeEffectPrefab;

		public static string chargeStockSoundString;

		public static string chargeLoopStartSoundString;

		public static string chargeLoopStopSoundString;

		public static int minGrenadeCount;

		public static int maxGrenadeCount;

		public static float minBonusBloom;

		public static float maxBonusBloom;

		private GameObject chargeLeftInstance;

		private GameObject chargeRightInstance;

		private int charge;

		private int lastCharge;

		private float totalDuration;

		private float maxChargeTime;

		private EffectManagerHelper _emh_chargeLeftInstance;

		private EffectManagerHelper _emh_chargeRightInstance;

		private static int ChargeGrenadesStateHash = Animator.StringToHash("ChargeGrenades");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		public override void Reset()
		{
			base.Reset();
			chargeLeftInstance = null;
			chargeRightInstance = null;
			charge = 0;
			lastCharge = 0;
			totalDuration = 0f;
			maxChargeTime = 0f;
			_emh_chargeLeftInstance = null;
			_emh_chargeRightInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			totalDuration = baseTotalDuration / attackSpeedStat;
			maxChargeTime = baseMaxChargeTime / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayAnimation("Gesture, Additive", ChargeGrenadesStateHash);
			Util.PlaySound(chargeLoopStartSoundString, base.gameObject);
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("MuzzleLeft");
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
				{
					chargeLeftInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				}
				else
				{
					_emh_chargeLeftInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
					chargeLeftInstance = _emh_chargeLeftInstance.gameObject;
				}
				chargeLeftInstance.transform.parent = transform;
				ScaleParticleSystemDuration component2 = chargeLeftInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component2)
				{
					component2.newDuration = totalDuration;
				}
			}
			Transform transform2 = component.FindChild("MuzzleRight");
			if ((bool)transform2 && (bool)chargeEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
				{
					chargeRightInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform2.position, transform2.rotation);
				}
				else
				{
					_emh_chargeRightInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform2.position, transform2.rotation);
					chargeRightInstance = _emh_chargeRightInstance.gameObject;
				}
				chargeRightInstance.transform.parent = transform2;
				ScaleParticleSystemDuration component3 = chargeRightInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component3)
				{
					component3.newDuration = totalDuration;
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			PlayAnimation("Gesture, Additive", EmptyStateHash);
			Util.PlaySound(chargeLoopStopSoundString, base.gameObject);
			if (chargeLeftInstance != null)
			{
				if (_emh_chargeLeftInstance != null && _emh_chargeLeftInstance.OwningPool != null)
				{
					_emh_chargeLeftInstance.OwningPool.ReturnObject(_emh_chargeLeftInstance);
				}
				else
				{
					EntityState.Destroy(chargeLeftInstance);
				}
				chargeLeftInstance = null;
				_emh_chargeLeftInstance = null;
			}
			if (chargeRightInstance != null)
			{
				if (_emh_chargeRightInstance != null && _emh_chargeRightInstance.OwningPool != null)
				{
					_emh_chargeRightInstance.OwningPool.ReturnObject(_emh_chargeRightInstance);
				}
				else
				{
					EntityState.Destroy(chargeRightInstance);
				}
				chargeRightInstance = null;
				_emh_chargeRightInstance = null;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			lastCharge = charge;
			charge = Mathf.Min((int)(base.fixedAge / maxChargeTime * (float)maxCharges), maxCharges);
			float t = (float)charge / (float)maxCharges;
			float value = Mathf.Lerp(minBonusBloom, maxBonusBloom, t);
			base.characterBody.SetSpreadBloom(value);
			int num = Mathf.FloorToInt(Mathf.Lerp(minGrenadeCount, maxGrenadeCount, t));
			if (lastCharge < charge)
			{
				Util.PlaySound(chargeStockSoundString, base.gameObject, "engiM1_chargePercent", 100f * ((float)(num - 1) / (float)maxGrenadeCount));
			}
			if ((base.fixedAge >= totalDuration || !base.inputBank || !base.inputBank.skill1.down) && base.isAuthority)
			{
				FireGrenades fireGrenades = new FireGrenades();
				fireGrenades.grenadeCountMax = num;
				outer.SetNextState(fireGrenades);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class EngiOtherShield : BaseState
	{
		public CharacterBody target;

		public float minimumDuration;

		private Indicator indicator;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)target)
			{
				indicator = new Indicator(base.gameObject, LegacyResourcesAPI.Load<GameObject>("Prefabs/EngiShieldRetractIndicator"));
				indicator.active = true;
				indicator.targetTransform = Util.GetCoreTransform(target.gameObject);
				target.AddBuff(RoR2Content.Buffs.EngiShield);
				target.RecalculateStats();
				HealthComponent component = target.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					component.RechargeShieldFull();
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!target || !base.characterBody.healthComponent.alive)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.skillLocator.utility = base.skillLocator.FindSkill("GiveShield");
			if (NetworkServer.active && (bool)target)
			{
				target.RemoveBuff(RoR2Content.Buffs.EngiShield);
			}
			if (base.isAuthority)
			{
				base.skillLocator.utility.RemoveAllStocks();
			}
			if (indicator != null)
			{
				indicator.active = false;
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge >= minimumDuration))
			{
				return InterruptPriority.PrioritySkill;
			}
			return InterruptPriority.Skill;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(target.gameObject);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			GameObject gameObject = reader.ReadGameObject();
			if ((bool)gameObject)
			{
				target = gameObject.GetComponent<CharacterBody>();
			}
		}
	}
	public class EngiSelfShield : BaseState
	{
		public static float transferDelay = 0.1f;

		private HurtBox transferTarget;

		private BullseyeSearch friendLocator;

		private Indicator indicator;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.EngiShield);
				base.characterBody.RecalculateStats();
				if ((bool)base.healthComponent)
				{
					base.healthComponent.RechargeShieldFull();
				}
			}
			friendLocator = new BullseyeSearch();
			friendLocator.teamMaskFilter = TeamMask.none;
			if ((bool)base.teamComponent)
			{
				friendLocator.teamMaskFilter.AddTeam(base.teamComponent.teamIndex);
			}
			friendLocator.maxDistanceFilter = 80f;
			friendLocator.maxAngleFilter = 20f;
			friendLocator.sortMode = BullseyeSearch.SortMode.Angle;
			friendLocator.filterByLoS = false;
			indicator = new Indicator(base.gameObject, LegacyResourcesAPI.Load<GameObject>("Prefabs/ShieldTransferIndicator"));
		}

		public override void OnExit()
		{
			base.skillLocator.utility = base.skillLocator.FindSkill("RetractShield");
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.EngiShield);
			}
			if (base.isAuthority)
			{
				base.skillLocator.utility.RemoveAllStocks();
			}
			indicator.active = false;
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority || !(base.fixedAge >= transferDelay) || !base.skillLocator.utility.IsReady())
			{
				return;
			}
			if ((bool)base.characterBody)
			{
				float extraRaycastDistance = 0f;
				Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance);
				friendLocator.searchOrigin = ray.origin;
				friendLocator.searchDirection = ray.direction;
				friendLocator.maxDistanceFilter += extraRaycastDistance;
				friendLocator.RefreshCandidates();
				friendLocator.FilterOutGameObject(base.gameObject);
				transferTarget = friendLocator.GetResults().FirstOrDefault();
			}
			HealthComponent healthComponent = (transferTarget ? transferTarget.healthComponent : null);
			if ((bool)healthComponent)
			{
				indicator.targetTransform = Util.GetCoreTransform(healthComponent.gameObject);
				if ((bool)base.inputBank && base.inputBank.skill3.justPressed)
				{
					EngiOtherShield engiOtherShield = new EngiOtherShield();
					engiOtherShield.target = healthComponent.gameObject.GetComponent<CharacterBody>();
					outer.SetNextState(engiOtherShield);
					return;
				}
			}
			else
			{
				indicator.targetTransform = null;
			}
			indicator.active = indicator.targetTransform;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class EngiTeamShield : BaseState
	{
		public static float duration = 3f;

		public static float radius;

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.teamComponent || !NetworkServer.active)
			{
				return;
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(base.teamComponent.teamIndex);
			float num = radius * radius;
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < teamMembers.Count; i++)
			{
				if (!((teamMembers[i].transform.position - position).sqrMagnitude <= num))
				{
					continue;
				}
				CharacterBody component = teamMembers[i].GetComponent<CharacterBody>();
				if ((bool)component)
				{
					component.AddTimedBuff(JunkContent.Buffs.EngiTeamShield, duration);
					HealthComponent component2 = component.GetComponent<HealthComponent>();
					if ((bool)component2)
					{
						component2.RechargeShieldFull();
					}
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireConcussionBlast : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static int grenadeCountMax = 3;

		public static float damageCoefficient;

		public static float fireDuration = 1f;

		public static float baseDuration = 2f;

		public static float minSpread = 0f;

		public static float maxSpread = 5f;

		public static float recoilAmplitude = 1f;

		public static string attackSoundString;

		public static float force;

		public static float maxDistance;

		public static float radius;

		public static GameObject tracerEffectPrefab;

		private Ray aimRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		private void FireGrenade(string targetMuzzle)
		{
			Util.PlaySound(attackSoundString, base.gameObject);
			aimRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						aimRay.origin = transform.position;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = targetMuzzle;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.radius = radius;
				bulletAttack.stopperMask = 0;
				bulletAttack.Fire();
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			aimRay = GetAimRay();
			StartAimMode(aimRay);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			fireTimer -= GetDeltaTime();
			float num = fireDuration / attackSpeedStat / (float)grenadeCountMax;
			if (fireTimer <= 0f && grenadeCount < grenadeCountMax)
			{
				fireTimer += num;
				if (grenadeCount % 2 == 0)
				{
					FireGrenade("MuzzleLeft");
					PlayCrossfade("Gesture, Left Cannon", "FireGrenadeLeft", 0.1f);
				}
				else
				{
					FireGrenade("MuzzleRight");
					PlayCrossfade("Gesture, Right Cannon", "FireGrenadeRight", 0.1f);
				}
				grenadeCount++;
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireGrenades : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public int grenadeCountMax = 3;

		public static float damageCoefficient;

		public static float fireDuration = 1f;

		public static float baseDuration = 2f;

		public static float arcAngle = 5f;

		public static float recoilAmplitude = 1f;

		public static string attackSoundString;

		public static float spreadBloomValue = 0.3f;

		private Ray projectileRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		private void FireGrenade(string targetMuzzle)
		{
			Util.PlaySound(attackSoundString, base.gameObject);
			projectileRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						projectileRay.origin = transform.position;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, projectileRay.direction);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle;
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * projectileRay.direction);
				ProjectileManager.instance.FireProjectile(projectilePrefab, projectileRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			StartAimMode();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			float num = fireDuration / attackSpeedStat / (float)grenadeCountMax;
			if (fireTimer <= 0f && grenadeCount < grenadeCountMax)
			{
				fireTimer += num;
				if (grenadeCount % 2 == 0)
				{
					FireGrenade("MuzzleLeft");
					PlayCrossfade("Gesture Left Cannon, Additive", "FireGrenadeLeft", 0.1f);
				}
				else
				{
					FireGrenade("MuzzleRight");
					PlayCrossfade("Gesture Right Cannon, Additive", "FireGrenadeRight", 0.1f);
				}
				grenadeCount++;
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireMines : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		public static float baseDuration = 2f;

		public static string throwMineSoundString;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(throwMineSoundString, base.gameObject);
			duration = baseDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			if ((bool)GetModelAnimator())
			{
				float num = duration * 0.3f;
				PlayCrossfade("Gesture, Additive", "FireMineRight", "FireMine.playbackRate", duration + num, 0.05f);
			}
			string muzzleName = "MuzzleCenter";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireBubbleShield : FireMines
	{
	}
	public class FireWallShield : FireMines
	{
	}
	public class FireSeekerGrenades : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject projectilePrefab;

		public static int grenadeCountMax = 3;

		public static float damageCoefficient;

		public static float fireDuration = 1f;

		public static float baseDuration = 2f;

		public static float minSpread = 0f;

		public static float maxSpread = 5f;

		public static float arcAngle = 5f;

		public static float recoilAmplitude = 1f;

		public static string attackSoundString;

		private Ray aimRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		private void FireGrenade(string targetMuzzle)
		{
			Util.PlaySound(attackSoundString, base.gameObject);
			aimRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						aimRay.origin = transform.position;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				float x = UnityEngine.Random.Range(minSpread, maxSpread);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle;
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			aimRay = GetAimRay();
			StartAimMode(aimRay);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			fireTimer -= GetDeltaTime();
			float num = fireDuration / attackSpeedStat / (float)grenadeCountMax;
			if (fireTimer <= 0f && grenadeCount < grenadeCountMax)
			{
				fireTimer += num;
				if (grenadeCount % 2 == 0)
				{
					FireGrenade("MuzzleLeft");
					PlayCrossfade("Gesture, Left Cannon", "FireGrenadeLeft", 0.1f);
				}
				else
				{
					FireGrenade("MuzzleRight");
					PlayCrossfade("Gesture, Right Cannon", "FireGrenadeRight", 0.1f);
				}
				grenadeCount++;
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireSpiderMine : FireMines
	{
	}
	public class PlaceTurret : BaseState
	{
		private struct PlacementInfo
		{
			public bool ok;

			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;
		}

		[SerializeField]
		public GameObject wristDisplayPrefab;

		[SerializeField]
		public string placeSoundString;

		[SerializeField]
		public GameObject blueprintPrefab;

		[SerializeField]
		public GameObject turretMasterPrefab;

		private const float placementMaxUp = 1f;

		private const float placementMaxDown = 3f;

		private const float placementForwardDistance = 2f;

		private const float entryDelay = 0.1f;

		private const float exitDelay = 0.25f;

		private const float turretRadius = 0.5f;

		private const float turretHeight = 1.82f;

		private const float turretCenter = 0f;

		private const float turretModelYOffset = -0.75f;

		private GameObject wristDisplayObject;

		private BlueprintController blueprints;

		private float exitCountdown;

		private bool exitPending;

		private float entryCountdown;

		private static int PrepTurretStateHash = Animator.StringToHash("PrepTurret");

		private static int PlaceTurretStateHash = Animator.StringToHash("PlaceTurret");

		private PlacementInfo currentPlacementInfo;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				currentPlacementInfo = GetPlacementInfo();
				blueprints = UnityEngine.Object.Instantiate(blueprintPrefab, currentPlacementInfo.position, currentPlacementInfo.rotation).GetComponent<BlueprintController>();
			}
			PlayAnimation("Gesture", PrepTurretStateHash);
			entryCountdown = 0.1f;
			exitCountdown = 0.25f;
			exitPending = false;
			if (!base.modelLocator)
			{
				return;
			}
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("WristDisplay");
				if ((bool)transform)
				{
					wristDisplayObject = UnityEngine.Object.Instantiate(wristDisplayPrefab, transform);
				}
			}
		}

		private PlacementInfo GetPlacementInfo()
		{
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 direction = aimRay.direction;
			direction.y = 0f;
			direction.Normalize();
			aimRay.direction = direction;
			PlacementInfo result = default(PlacementInfo);
			result.ok = false;
			result.rotation = Util.QuaternionSafeLookRotation(-direction);
			Ray ray = new Ray(aimRay.GetPoint(2f) + UnityEngine.Vector3.up * 1f, UnityEngine.Vector3.down);
			float num = 4f;
			float num2 = num;
			if (Physics.SphereCast(ray, 0.5f, out var hitInfo, num, LayerIndex.world.mask) && hitInfo.normal.y > 0.5f)
			{
				num2 = hitInfo.distance;
				result.ok = true;
			}
			UnityEngine.Vector3 point = ray.GetPoint(num2 + 0.5f);
			result.position = point;
			if (result.ok)
			{
				float num3 = Mathf.Max(1.82f, 0f);
				if (Physics.CheckCapsule(result.position + UnityEngine.Vector3.up * (num3 - 0.5f), result.position + UnityEngine.Vector3.up * 0.5f, 0.45f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault))
				{
					result.ok = false;
				}
			}
			return result;
		}

		private void DestroyBlueprints()
		{
			if ((bool)blueprints)
			{
				EntityState.Destroy(blueprints.gameObject);
				blueprints = null;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			PlayAnimation("Gesture", PlaceTurretStateHash);
			if ((bool)wristDisplayObject)
			{
				EntityState.Destroy(wristDisplayObject);
			}
			DestroyBlueprints();
		}

		public override void Update()
		{
			base.Update();
			currentPlacementInfo = GetPlacementInfo();
			if ((bool)blueprints)
			{
				blueprints.PushState(currentPlacementInfo.position, currentPlacementInfo.rotation, currentPlacementInfo.ok);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			entryCountdown -= GetDeltaTime();
			if (exitPending)
			{
				exitCountdown -= GetDeltaTime();
				if (exitCountdown <= 0f)
				{
					outer.SetNextStateToMain();
				}
			}
			else
			{
				if (!base.inputBank || !(entryCountdown <= 0f))
				{
					return;
				}
				if ((base.inputBank.skill1.down || base.inputBank.skill4.justPressed) && currentPlacementInfo.ok)
				{
					if ((bool)base.characterBody)
					{
						base.characterBody.SendConstructTurret(base.characterBody, currentPlacementInfo.position, currentPlacementInfo.rotation, MasterCatalog.FindMasterIndex(turretMasterPrefab));
						if ((bool)base.skillLocator)
						{
							GenericSkill skill = base.skillLocator.GetSkill(SkillSlot.Special);
							if ((bool)skill)
							{
								skill.DeductStock(1);
							}
						}
					}
					Util.PlaySound(placeSoundString, base.gameObject);
					DestroyBlueprints();
					exitPending = true;
				}
				if (base.inputBank.skill2.justPressed)
				{
					DestroyBlueprints();
					exitPending = true;
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class PlaceWalkerTurret : PlaceTurret
	{
	}
	public class ThrowMineDeployer : AimThrowableBase
	{
	}
}
namespace EntityStates.Engi.EngiMissilePainter
{
	public class BaseEngiMissilePainterState : BaseSkillState
	{
		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class Startup : BaseEngiMissilePainterState
	{
		public static float baseDuration;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && duration <= base.fixedAge)
			{
				outer.SetNextState(new Paint());
			}
		}
	}
	public class Paint : BaseEngiMissilePainterState
	{
		private struct IndicatorInfo
		{
			public int refCount;

			public EngiMissileIndicator indicator;
		}

		private class EngiMissileIndicator : Indicator
		{
			public int missileCount;

			public override void UpdateVisualizer()
			{
				base.UpdateVisualizer();
				Transform transform = base.visualizerTransform.Find("DotOrigin");
				for (int num = transform.childCount - 1; num >= missileCount; num--)
				{
					EntityState.Destroy(transform.GetChild(num));
				}
				for (int i = transform.childCount; i < missileCount; i++)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(base.visualizerPrefab.transform.Find("DotOrigin/DotTemplate").gameObject, transform);
					FindRenderers(gameObject.transform);
				}
				if (transform.childCount > 0)
				{
					float num2 = 360f / (float)transform.childCount;
					float num3 = (float)(transform.childCount - 1) * 90f;
					for (int j = 0; j < transform.childCount; j++)
					{
						Transform child = transform.GetChild(j);
						child.gameObject.SetActive(value: true);
						child.localRotation = UnityEngine.Quaternion.Euler(0f, 0f, num3 + (float)j * num2);
					}
				}
			}

			public EngiMissileIndicator(GameObject owner, GameObject visualizerPrefab)
				: base(owner, visualizerPrefab)
			{
			}
		}

		public static GameObject crosshairOverridePrefab;

		public static GameObject stickyTargetIndicatorPrefab;

		public static float stackInterval;

		public static string enterSoundString;

		public static string exitSoundString;

		public static string loopSoundString;

		public static string lockOnSoundString;

		public static string stopLoopSoundString;

		public static float maxAngle;

		public static float maxDistance;

		private List<HurtBox> targetsList;

		private Dictionary<HurtBox, IndicatorInfo> targetIndicators;

		private Indicator stickyTargetIndicator;

		private SkillDef engiConfirmTargetDummySkillDef;

		private SkillDef engiCancelTargetingDummySkillDef;

		private bool releasedKeyOnce;

		private float stackStopwatch;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private BullseyeSearch search;

		private bool queuedFiringState;

		private uint loopSoundID;

		private HealthComponent previousHighlightTargetHealthComponent;

		private HurtBox previousHighlightTargetHurtBox;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				targetsList = new List<HurtBox>();
				targetIndicators = new Dictionary<HurtBox, IndicatorInfo>();
				stickyTargetIndicator = new Indicator(base.gameObject, stickyTargetIndicatorPrefab);
				search = new BullseyeSearch();
			}
			PlayCrossfade("Gesture, Additive", "PrepHarpoons", 0.1f);
			Util.PlaySound(enterSoundString, base.gameObject);
			loopSoundID = Util.PlaySound(loopSoundString, base.gameObject);
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			engiConfirmTargetDummySkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("EngiConfirmTargetDummy"));
			engiCancelTargetingDummySkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("EngiCancelTargetingDummy"));
			base.skillLocator.primary.SetSkillOverride(this, engiConfirmTargetDummySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			base.skillLocator.secondary.SetSkillOverride(this, engiCancelTargetingDummySkillDef, GenericSkill.SkillOverridePriority.Contextual);
		}

		public override void OnExit()
		{
			if (base.isAuthority && !outer.destroying && !queuedFiringState)
			{
				for (int i = 0; i < targetsList.Count; i++)
				{
					base.activatorSkillSlot.AddOneStock();
				}
			}
			base.skillLocator.secondary.UnsetSkillOverride(this, engiCancelTargetingDummySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			base.skillLocator.primary.UnsetSkillOverride(this, engiConfirmTargetDummySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			if (targetIndicators != null)
			{
				foreach (KeyValuePair<HurtBox, IndicatorInfo> targetIndicator in targetIndicators)
				{
					targetIndicator.Value.indicator.active = false;
				}
			}
			if (stickyTargetIndicator != null)
			{
				stickyTargetIndicator.active = false;
			}
			crosshairOverrideRequest?.Dispose();
			PlayCrossfade("Gesture, Additive", "ExitHarpoons", 0.1f);
			Util.PlaySound(exitSoundString, base.gameObject);
			Util.PlaySound(stopLoopSoundString, base.gameObject);
			base.OnExit();
		}

		private void AddTargetAuthority(HurtBox hurtBox)
		{
			if (base.activatorSkillSlot.stock != 0)
			{
				Util.PlaySound(lockOnSoundString, base.gameObject);
				targetsList.Add(hurtBox);
				if (!targetIndicators.TryGetValue(hurtBox, out var value))
				{
					IndicatorInfo indicatorInfo = default(IndicatorInfo);
					indicatorInfo.refCount = 0;
					indicatorInfo.indicator = new EngiMissileIndicator(base.gameObject, LegacyResourcesAPI.Load<GameObject>("Prefabs/EngiMissileTrackingIndicator"));
					value = indicatorInfo;
					value.indicator.targetTransform = hurtBox.transform;
					value.indicator.active = true;
				}
				value.refCount++;
				value.indicator.missileCount = value.refCount;
				targetIndicators[hurtBox] = value;
				base.activatorSkillSlot.DeductStock(1);
			}
		}

		private void RemoveTargetAtAuthority(int i)
		{
			HurtBox key = targetsList[i];
			targetsList.RemoveAt(i);
			if (targetIndicators.TryGetValue(key, out var value))
			{
				value.refCount--;
				value.indicator.missileCount = value.refCount;
				targetIndicators[key] = value;
				if (value.refCount == 0)
				{
					value.indicator.active = false;
					targetIndicators.Remove(key);
				}
			}
		}

		private void CleanTargetsList()
		{
			for (int num = targetsList.Count - 1; num >= 0; num--)
			{
				HurtBox hurtBox = targetsList[num];
				if (!hurtBox.healthComponent || !hurtBox.healthComponent.alive)
				{
					RemoveTargetAtAuthority(num);
					base.activatorSkillSlot.AddOneStock();
				}
			}
			for (int num2 = targetsList.Count - 1; num2 >= base.activatorSkillSlot.maxStock; num2--)
			{
				RemoveTargetAtAuthority(num2);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterBody.SetAimTimer(3f);
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		private void GetCurrentTargetInfo(out HurtBox currentTargetHurtBox, out HealthComponent currentTargetHealthComponent)
		{
			Ray aimRay = GetAimRay();
			search.filterByDistinctEntity = true;
			search.filterByLoS = true;
			search.minDistanceFilter = 0f;
			search.maxDistanceFilter = maxDistance;
			search.minAngleFilter = 0f;
			search.maxAngleFilter = maxAngle;
			search.viewer = base.characterBody;
			search.searchOrigin = aimRay.origin;
			search.searchDirection = aimRay.direction;
			search.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
			search.teamMaskFilter = TeamMask.GetUnprotectedTeams(GetTeam());
			search.RefreshCandidates();
			search.FilterOutGameObject(base.gameObject);
			foreach (HurtBox result in search.GetResults())
			{
				if ((bool)result.healthComponent && result.healthComponent.alive)
				{
					currentTargetHurtBox = result;
					currentTargetHealthComponent = result.healthComponent;
					return;
				}
			}
			currentTargetHurtBox = null;
			currentTargetHealthComponent = null;
		}

		private void AuthorityFixedUpdate()
		{
			CleanTargetsList();
			bool flag = false;
			GetCurrentTargetInfo(out var currentTargetHurtBox, out var currentTargetHealthComponent);
			if ((bool)currentTargetHurtBox)
			{
				stackStopwatch += GetDeltaTime();
				if (base.inputBank.skill1.down && (previousHighlightTargetHealthComponent != currentTargetHealthComponent || stackStopwatch > stackInterval / attackSpeedStat || base.inputBank.skill1.justPressed))
				{
					stackStopwatch = 0f;
					AddTargetAuthority(currentTargetHurtBox);
				}
			}
			if (base.inputBank.skill1.justReleased)
			{
				flag = true;
			}
			if (base.inputBank.skill2.justReleased)
			{
				outer.SetNextStateToMain();
				return;
			}
			if (base.inputBank.skill3.justReleased)
			{
				if (releasedKeyOnce)
				{
					flag = true;
				}
				releasedKeyOnce = true;
			}
			if ((object)currentTargetHurtBox != previousHighlightTargetHurtBox)
			{
				previousHighlightTargetHurtBox = currentTargetHurtBox;
				previousHighlightTargetHealthComponent = currentTargetHealthComponent;
				stickyTargetIndicator.targetTransform = (((bool)currentTargetHurtBox && base.activatorSkillSlot.stock != 0) ? currentTargetHurtBox.transform : null);
				stackStopwatch = 0f;
			}
			stickyTargetIndicator.active = stickyTargetIndicator.targetTransform;
			if (flag)
			{
				queuedFiringState = true;
				outer.SetNextState(new Fire
				{
					targetsList = targetsList,
					activatorSkillSlot = base.activatorSkillSlot
				});
			}
		}
	}
	public class Fire : BaseEngiMissilePainterState
	{
		public static float baseDurationPerMissile;

		public static float damageCoefficient;

		public static GameObject projectilePrefab;

		public static GameObject muzzleflashEffectPrefab;

		public List<HurtBox> targetsList;

		private int fireIndex;

		private float durationPerMissile;

		private float stopwatch;

		private static int IdleHarpoonsStateHash = Animator.StringToHash("IdleHarpoons");

		private static int FireHarpoonStateHash = Animator.StringToHash("FireHarpoon");

		public override void OnEnter()
		{
			base.OnEnter();
			durationPerMissile = baseDurationPerMissile / attackSpeedStat;
			PlayAnimation("Gesture, Additive", IdleHarpoonsStateHash);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			bool flag = false;
			if (base.isAuthority)
			{
				stopwatch += GetDeltaTime();
				if (stopwatch >= durationPerMissile)
				{
					stopwatch -= durationPerMissile;
					while (fireIndex < targetsList.Count)
					{
						HurtBox hurtBox = targetsList[fireIndex++];
						if (!hurtBox.healthComponent || !hurtBox.healthComponent.alive)
						{
							base.activatorSkillSlot.AddOneStock();
							continue;
						}
						string text = ((fireIndex % 2 == 0) ? "MuzzleLeft" : "MuzzleRight");
						UnityEngine.Vector3 position = base.inputBank.aimOrigin;
						Transform transform = FindModelChild(text);
						if (transform != null)
						{
							position = transform.position;
						}
						EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, text, transmit: true);
						FireMissile(hurtBox, position);
						flag = true;
						break;
					}
					if (fireIndex >= targetsList.Count)
					{
						outer.SetNextState(new Finish());
					}
				}
			}
			if (flag)
			{
				PlayAnimation((fireIndex % 2 == 0) ? "Gesture Left Cannon, Additive" : "Gesture Right Cannon, Additive", FireHarpoonStateHash);
			}
		}

		private void FireMissile(HurtBox target, UnityEngine.Vector3 position)
		{
			MissileUtils.FireMissile(base.inputBank.aimOrigin, base.characterBody, default(ProcChainMask), target.gameObject, damageStat * damageCoefficient, RollCrit(), projectilePrefab, DamageColorIndex.Default, UnityEngine.Vector3.up, 0f, addMissileProc: false);
		}

		public override void OnExit()
		{
			base.OnExit();
			PlayCrossfade("Gesture, Additive", "ExitHarpoons", 0.1f);
		}
	}
	public class Finish : BaseEngiMissilePainterState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				outer.SetNextState(new Idle());
			}
		}
	}
}
namespace EntityStates.Engi.EngiWallShield
{
	public class Undeployed : EntityStates.Engi.EngiBubbleShield.Undeployed
	{
		public override void OnEnter()
		{
			base.OnEnter();
		}

		protected override void SetNextState()
		{
			UnityEngine.Vector3 forward = base.transform.forward;
			UnityEngine.Vector3 forward2 = new UnityEngine.Vector3(forward.x, 0f, forward.z);
			base.transform.forward = forward2;
			outer.SetNextState(new Deployed());
		}
	}
	public class Deployed : EntityStates.Engi.EngiBubbleShield.Deployed
	{
	}
}
namespace EntityStates.Engi.EngiBubbleShield
{
	public class Undeployed : EntityState
	{
		private ProjectileStickOnImpact projectileStickOnImpact;

		public override void OnEnter()
		{
			base.OnEnter();
			ProjectileController component = GetComponent<ProjectileController>();
			projectileStickOnImpact = GetComponent<ProjectileStickOnImpact>();
			if (!NetworkServer.active || !component.owner)
			{
				return;
			}
			CharacterBody component2 = component.owner.GetComponent<CharacterBody>();
			if ((bool)component2)
			{
				CharacterMaster master = component2.master;
				if ((bool)master)
				{
					master.AddDeployable(GetComponent<Deployable>(), DeployableSlot.EngiBubbleShield);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (projectileStickOnImpact.stuck && NetworkServer.active)
			{
				SetNextState();
			}
		}

		protected virtual void SetNextState()
		{
			outer.SetNextState(new Deployed());
		}
	}
	public class Deployed : EntityState
	{
		public static string childLocatorString;

		public static string initialSoundString;

		public static string destroySoundString;

		public static float delayToDeploy;

		public static float lifetime;

		[SerializeField]
		public GameObject destroyEffectPrefab;

		[SerializeField]
		public float destroyEffectRadius;

		private bool hasDeployed;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(initialSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!hasDeployed && base.fixedAge >= delayToDeploy)
			{
				ChildLocator component = GetComponent<ChildLocator>();
				if ((bool)component)
				{
					component.FindChild(childLocatorString).gameObject.SetActive(value: true);
					hasDeployed = true;
				}
			}
			if (base.fixedAge >= lifetime && NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			EffectManager.SpawnEffect(destroyEffectPrefab, new EffectData
			{
				origin = base.transform.position,
				rotation = base.transform.rotation,
				scale = destroyEffectRadius
			}, transmit: false);
			Util.PlaySound(destroySoundString, base.gameObject);
		}
	}
}
namespace EntityStates.Duplicator
{
	public class Duplicating : BaseState
	{
		public static float initialDelayDuration = 1f;

		public static float timeBetweenStartAndDropDroplet = 3f;

		public static string muzzleString;

		public static GameObject bakeEffectPrefab;

		public static GameObject releaseEffectPrefab;

		private GameObject bakeEffectInstance;

		private bool hasStartedCooking;

		private bool hasDroppedDroplet;

		private Transform muzzleTransform;

		private EffectManagerHelper _emh_bakeEffectInstance;

		private static int CookStateHash = Animator.StringToHash("Cook");

		public override void Reset()
		{
			base.Reset();
			bakeEffectInstance = null;
			hasStartedCooking = false;
			hasDroppedDroplet = false;
			muzzleTransform = null;
			_emh_bakeEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component)
			{
				muzzleTransform = component.FindChild(muzzleString);
			}
		}

		private void BeginCooking()
		{
			if (hasStartedCooking)
			{
				return;
			}
			hasStartedCooking = true;
			PlayAnimation("Body", CookStateHash);
			if ((bool)base.sfxLocator)
			{
				Util.PlaySound(base.sfxLocator.openSound, base.gameObject);
			}
			if ((bool)muzzleTransform)
			{
				if (!EffectManager.ShouldUsePooledEffect(bakeEffectPrefab))
				{
					bakeEffectInstance = UnityEngine.Object.Instantiate(bakeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
					return;
				}
				_emh_bakeEffectInstance = EffectManager.GetAndActivatePooledEffect(bakeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
				bakeEffectInstance = _emh_bakeEffectInstance.gameObject;
			}
		}

		private void DropDroplet()
		{
			if (hasDroppedDroplet)
			{
				return;
			}
			hasDroppedDroplet = true;
			GetComponent<ShopTerminalBehavior>().DropPickup();
			if (!muzzleTransform)
			{
				return;
			}
			if ((bool)bakeEffectInstance)
			{
				if (_emh_bakeEffectInstance != null && _emh_bakeEffectInstance.OwningPool != null)
				{
					_emh_bakeEffectInstance.OwningPool.ReturnObject(_emh_bakeEffectInstance);
				}
				else
				{
					EntityState.Destroy(bakeEffectInstance);
				}
				_emh_bakeEffectInstance = null;
				bakeEffectInstance = null;
			}
			if ((bool)releaseEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(releaseEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= initialDelayDuration)
			{
				BeginCooking();
			}
			if (base.fixedAge >= initialDelayDuration + timeBetweenStartAndDropDroplet)
			{
				DropDroplet();
			}
		}
	}
}
namespace EntityStates.DroneWeaponsChainGun
{
	public class AimChainGun : BaseDroneWeaponChainGunState
	{
		[SerializeField]
		public float minDuration;

		[SerializeField]
		public float maxEnemyDistanceToStartFiring;

		[SerializeField]
		public float searchRefreshSeconds;

		private BullseyeSearch enemyFinder;

		private float searchRefreshTimer;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				enemyFinder = new BullseyeSearch();
				enemyFinder.teamMaskFilter = TeamMask.allButNeutral;
				enemyFinder.maxDistanceFilter = maxEnemyDistanceToStartFiring;
				enemyFinder.maxAngleFilter = float.MaxValue;
				enemyFinder.filterByLoS = true;
				enemyFinder.sortMode = BullseyeSearch.SortMode.Angle;
				if ((bool)bodyTeamComponent)
				{
					enemyFinder.teamMaskFilter.RemoveTeam(bodyTeamComponent.teamIndex);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority || !(base.fixedAge > minDuration))
			{
				return;
			}
			searchRefreshTimer -= GetDeltaTime();
			if (!(searchRefreshTimer < 0f))
			{
				return;
			}
			searchRefreshTimer = searchRefreshSeconds;
			Ray aimRay = GetAimRay();
			enemyFinder.searchOrigin = aimRay.origin;
			enemyFinder.searchDirection = aimRay.direction;
			enemyFinder.RefreshCandidates();
			using IEnumerator<HurtBox> enumerator = enemyFinder.GetResults().GetEnumerator();
			if (enumerator.MoveNext())
			{
				HurtBox current = enumerator.Current;
				outer.SetNextState(new FireChainGun(current));
			}
		}
	}
	public abstract class BaseDroneWeaponChainGunState : EntityState
	{
		private const string aimAnimatorChildName = "AimAnimator";

		[SerializeField]
		public float pitchRangeMin;

		[SerializeField]
		public float pitchRangeMax;

		[SerializeField]
		public float yawRangeMin;

		[SerializeField]
		public float yawRangeMax;

		protected NetworkedBodyAttachment networkedBodyAttachment;

		protected GameObject bodyGameObject;

		protected CharacterBody body;

		protected List<ChildLocator> gunChildLocators;

		protected List<Animator> gunAnimators;

		protected AimAnimator bodyAimAnimator;

		protected TeamComponent bodyTeamComponent;

		private bool linkedToDisplay;

		public override void OnEnter()
		{
			base.OnEnter();
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
			if ((bool)networkedBodyAttachment)
			{
				bodyGameObject = networkedBodyAttachment.attachedBodyObject;
				body = networkedBodyAttachment.attachedBody;
				if ((bool)bodyGameObject && (bool)body)
				{
					ModelLocator component = body.GetComponent<ModelLocator>();
					if ((bool)component)
					{
						bodyAimAnimator = component.modelTransform.GetComponent<AimAnimator>();
						bodyTeamComponent = body.GetComponent<TeamComponent>();
					}
				}
			}
			LinkToDisplay();
		}

		private void LinkToDisplay()
		{
			if (linkedToDisplay)
			{
				return;
			}
			gunAnimators = new List<Animator>();
			gunChildLocators = new List<ChildLocator>();
			if (!networkedBodyAttachment)
			{
				return;
			}
			bodyGameObject = networkedBodyAttachment.attachedBodyObject;
			body = networkedBodyAttachment.attachedBody;
			if (!bodyGameObject || !body)
			{
				return;
			}
			ModelLocator component = body.GetComponent<ModelLocator>();
			if (!component || !component.modelTransform)
			{
				return;
			}
			bodyAimAnimator = component.modelTransform.GetComponent<AimAnimator>();
			bodyTeamComponent = body.GetComponent<TeamComponent>();
			CharacterModel component2 = component.modelTransform.GetComponent<CharacterModel>();
			if (!component2)
			{
				return;
			}
			List<GameObject> itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay1.itemIndex);
			itemDisplayObjects.AddRange(component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay2.itemIndex));
			foreach (GameObject item in itemDisplayObjects)
			{
				ChildLocator component3 = item.GetComponent<ChildLocator>();
				if ((bool)component3)
				{
					gunChildLocators.Add(component3);
					Animator animator = component3.FindChildComponent<Animator>("AimAnimator");
					if ((bool)animator)
					{
						gunAnimators.Add(animator);
					}
				}
			}
		}

		public void PassDisplayLinks(List<ChildLocator> gunChildLocators, List<Animator> gunAnimators)
		{
			if (!linkedToDisplay)
			{
				linkedToDisplay = true;
				this.gunAnimators = gunAnimators;
				this.gunChildLocators = gunChildLocators;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			LinkToDisplay();
			if (!bodyAimAnimator)
			{
				return;
			}
			foreach (Animator gunAnimator in gunAnimators)
			{
				bodyAimAnimator.UpdateAnimatorParameters(gunAnimator, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax);
			}
		}

		protected Transform FindChild(string childName)
		{
			foreach (ChildLocator gunChildLocator in gunChildLocators)
			{
				Transform transform = gunChildLocator.FindChild(childName);
				if ((bool)transform)
				{
					return transform;
				}
			}
			return null;
		}

		protected Ray GetAimRay()
		{
			if ((bool)body.inputBank)
			{
				return new Ray(body.inputBank.aimOrigin, body.inputBank.aimDirection);
			}
			return new Ray(base.transform.position, base.transform.forward);
		}
	}
	public class FireChainGun : BaseDroneWeaponChainGunState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject orbEffectObject;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float orbSpeed;

		[SerializeField]
		public int shotCount;

		[SerializeField]
		public float procCoefficient;

		[SerializeField]
		public int additionalBounces;

		[SerializeField]
		public float bounceRange;

		[SerializeField]
		public float damageCoefficientPerBounce;

		[SerializeField]
		public int targetsToFindPerBounce;

		[SerializeField]
		public bool canBounceOnSameTarget;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public GameObject muzzleFlashPrefab;

		[SerializeField]
		public string fireSoundString;

		private HurtBox targetHurtBox;

		private float duration;

		private int stepIndex;

		public FireChainGun()
		{
		}

		public FireChainGun(HurtBox targetHurtBox)
		{
			this.targetHurtBox = targetHurtBox;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Transform transform = FindChild(muzzleName);
			if (!transform)
			{
				transform = body.coreTransform;
			}
			if (base.isAuthority)
			{
				duration = baseDuration / body.attackSpeed;
				ChainGunOrb chainGunOrb = new ChainGunOrb(orbEffectObject);
				chainGunOrb.damageValue = body.damage * damageCoefficient;
				chainGunOrb.isCrit = Util.CheckRoll(body.crit, body.master);
				chainGunOrb.teamIndex = TeamComponent.GetObjectTeam(body.gameObject);
				chainGunOrb.attacker = body.gameObject;
				chainGunOrb.procCoefficient = procCoefficient;
				chainGunOrb.procChainMask = default(ProcChainMask);
				chainGunOrb.origin = transform.position;
				chainGunOrb.target = targetHurtBox;
				chainGunOrb.speed = orbSpeed;
				chainGunOrb.bouncesRemaining = additionalBounces;
				chainGunOrb.bounceRange = bounceRange;
				chainGunOrb.damageCoefficientPerBounce = damageCoefficientPerBounce;
				chainGunOrb.targetsToFindPerBounce = targetsToFindPerBounce;
				chainGunOrb.canBounceOnSameTarget = canBounceOnSameTarget;
				chainGunOrb.damageColorIndex = DamageColorIndex.Item;
				OrbManager.instance.AddOrb(chainGunOrb);
			}
			if ((bool)transform)
			{
				EffectData effectData = new EffectData
				{
					origin = transform.position
				};
				EffectManager.SpawnEffect(muzzleFlashPrefab, effectData, transmit: true);
			}
			Util.PlaySound(fireSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				BaseDroneWeaponChainGunState baseDroneWeaponChainGunState;
				if (stepIndex < shotCount)
				{
					baseDroneWeaponChainGunState = new FireChainGun(targetHurtBox);
					(baseDroneWeaponChainGunState as FireChainGun).stepIndex = stepIndex + 1;
				}
				else
				{
					baseDroneWeaponChainGunState = new AimChainGun();
				}
				baseDroneWeaponChainGunState.PassDisplayLinks(gunChildLocators, gunAnimators);
				outer.SetNextState(baseDroneWeaponChainGunState);
			}
		}
	}
}
namespace EntityStates.Turret1
{
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)GetModelAnimator())
			{
				PlayAnimation("Body", SpawnStateHash, SpawnParamHash, 1.5f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class DeathState : EntityStates.EngiTurret.DeathState
	{
	}
}
namespace EntityStates.Drone
{
	public class DeathState : GenericCharacterDeath
	{
		public class RigidbodyCollisionListener : MonoBehaviour
		{
			public DeathState deathState;

			private void OnCollisionEnter(Collision collision)
			{
				deathState.OnImpactServer(collision.GetContact(0).point);
				deathState.Explode();
			}
		}

		[SerializeField]
		public GameObject initialExplosionEffect;

		[SerializeField]
		public GameObject deathExplosionEffect;

		[SerializeField]
		public string initialSoundString;

		[SerializeField]
		public string deathSoundString;

		[SerializeField]
		public float deathEffectRadius;

		[SerializeField]
		public float forceAmount = 20f;

		[SerializeField]
		public float deathDuration = 2f;

		[SerializeField]
		public bool destroyOnImpact;

		private RigidbodyCollisionListener rigidbodyCollisionListener;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(initialSoundString, base.gameObject);
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.forcePID.enabled = false;
				base.rigidbodyMotor.rigid.useGravity = true;
				base.rigidbodyMotor.rigid.AddForce(UnityEngine.Vector3.up * forceAmount, ForceMode.Force);
				base.rigidbodyMotor.rigid.collisionDetectionMode = CollisionDetectionMode.Continuous;
			}
			if ((bool)base.rigidbodyDirection)
			{
				base.rigidbodyDirection.enabled = false;
			}
			if ((bool)initialExplosionEffect)
			{
				EffectManager.SpawnEffect(deathExplosionEffect, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = base.characterBody.radius + deathEffectRadius
				}, transmit: false);
			}
			if (base.isAuthority && destroyOnImpact)
			{
				rigidbodyCollisionListener = base.gameObject.AddComponent<RigidbodyCollisionListener>();
				rigidbodyCollisionListener.deathState = this;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge > deathDuration)
			{
				Explode();
			}
		}

		public void Explode()
		{
			EntityState.Destroy(base.gameObject);
		}

		public virtual void OnImpactServer(UnityEngine.Vector3 contactPoint)
		{
			string bodyName = BodyCatalog.GetBodyName(base.characterBody.bodyIndex);
			bodyName = bodyName.Replace("Body", "");
			bodyName = "iscBroken" + bodyName;
			SpawnCard spawnCard = LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/" + bodyName);
			if (!(spawnCard != null))
			{
				return;
			}
			DirectorPlacementRule placementRule = new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Direct,
				position = contactPoint
			};
			GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, new Xoroshiro128Plus(0uL)));
			if ((bool)gameObject)
			{
				PurchaseInteraction component = gameObject.GetComponent<PurchaseInteraction>();
				if ((bool)component && component.costType == CostTypeIndex.Money)
				{
					component.Networkcost = Run.instance.GetDifficultyScaledCost(component.cost);
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)deathExplosionEffect)
			{
				EffectManager.SpawnEffect(deathExplosionEffect, new EffectData
				{
					origin = base.characterBody.corePosition,
					scale = base.characterBody.radius + deathEffectRadius
				}, transmit: false);
			}
			if ((bool)rigidbodyCollisionListener)
			{
				EntityState.Destroy(rigidbodyCollisionListener);
			}
			Util.PlaySound(deathSoundString, base.gameObject);
			base.OnExit();
		}
	}
	public class MegaDroneDeathState : GenericCharacterDeath
	{
		public static string initialSoundString;

		public static GameObject initialEffect;

		public static float initialEffectScale;

		public static float velocityMagnitude;

		public static float explosionForce;

		public override void OnEnter()
		{
			if (NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			Util.PlaySound(initialSoundString, base.gameObject);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform && NetworkServer.active)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					component.FindChild("LeftJet").gameObject.SetActive(value: false);
					component.FindChild("RightJet").gameObject.SetActive(value: false);
					if ((bool)initialEffect)
					{
						EffectManager.SpawnEffect(initialEffect, new EffectData
						{
							origin = base.transform.position,
							scale = initialEffectScale
						}, transmit: true);
					}
				}
			}
			Rigidbody component2 = GetComponent<Rigidbody>();
			RagdollController component3 = modelTransform.GetComponent<RagdollController>();
			if ((bool)component3 && (bool)component2)
			{
				component3.BeginRagdoll(component2.velocity * velocityMagnitude);
			}
			ExplodeRigidbodiesOnStart component4 = modelTransform.GetComponent<ExplodeRigidbodiesOnStart>();
			if ((bool)component4)
			{
				component4.force = explosionForce;
				component4.enabled = true;
			}
		}
	}
}
namespace EntityStates.Drone.DroneWeapon
{
	public class FireGatling : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static float baseDuration = 2f;

		public static string fireGatlingSoundString;

		public int bulletCountCurrent = 1;

		private float duration;

		private static int FireGatlingStateHash = Animator.StringToHash("FireGatling");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			string muzzleName = "Muzzle";
			Util.PlaySound(fireGatlingSoundString, base.gameObject);
			PlayAnimation("Gesture", FireGatlingStateHash);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireMegaTurret : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static string attackSoundString;

		public static float attackSoundPlaybackCoefficient;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int maxBulletCount;

		public static float baseTotalDuration;

		private Transform modelTransform;

		private ChildLocator childLocator;

		private float fireStopwatch;

		private float stopwatch;

		private float durationBetweenShots;

		private float totalDuration;

		private int bulletCount;

		private static int FireGatStateHash = Animator.StringToHash("FireGat");

		public override void OnEnter()
		{
			base.OnEnter();
			fireStopwatch = 0f;
			totalDuration = baseTotalDuration / attackSpeedStat;
			durationBetweenShots = totalDuration / (float)maxBulletCount;
			GetAimRay();
			Transform transform = GetModelTransform();
			if ((bool)transform)
			{
				childLocator = transform.GetComponent<ChildLocator>();
			}
		}

		private void FireBullet(string muzzleString)
		{
			Ray aimRay = GetAimRay();
			_ = aimRay.origin;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSoundPlaybackCoefficient);
			PlayAnimation("Gesture, Additive", FireGatStateHash);
			if ((bool)childLocator)
			{
				Transform transform = childLocator.FindChild(muzzleString);
				if ((bool)transform)
				{
					_ = transform.position;
				}
			}
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleString;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			fireStopwatch += deltaTime;
			stopwatch += deltaTime;
			if (fireStopwatch >= durationBetweenShots)
			{
				bulletCount++;
				fireStopwatch -= durationBetweenShots;
				FireBullet((bulletCount % 2 == 0) ? "GatLeft" : "GatRight");
			}
			if (stopwatch >= totalDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireMissileBarrage : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public static float damageCoefficient = 1f;

		public static float baseFireInterval = 0.1f;

		public static float minSpread = 0f;

		public static float maxSpread = 5f;

		public static int maxMissileCount;

		private float fireTimer;

		private float fireInterval;

		private Transform modelTransform;

		private AimAnimator aimAnimator;

		private int missileCount;

		private static int FireMissileStateHash = Animator.StringToHash("FireMissile");

		private void FireMissile(string targetMuzzle)
		{
			missileCount++;
			PlayAnimation("Gesture, Additive", FireMissileStateHash);
			Ray aimRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						aimRay.origin = transform.position;
					}
				}
			}
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
			if (base.isAuthority)
			{
				float x = UnityEngine.Random.Range(minSpread, maxSpread);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f;
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			modelTransform = GetModelTransform();
			fireInterval = baseFireInterval / attackSpeedStat;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			if (fireTimer <= 0f)
			{
				FireMissile("Muzzle");
				fireTimer += fireInterval;
			}
			if (missileCount >= maxMissileCount && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireTurret : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static string attackSoundString;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float durationBetweenShots = 1f;

		public static float baseDuration = 2f;

		public int bulletCountCurrent = 1;

		private float duration = 2f;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			string muzzleName = "Muzzle";
			Util.PlaySound(attackSoundString, base.gameObject);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= durationBetweenShots / attackSpeedStat && bulletCountCurrent < bulletCount && base.isAuthority)
			{
				FireTurret fireTurret = new FireTurret();
				fireTurret.bulletCountCurrent = bulletCountCurrent + 1;
				outer.SetNextState(fireTurret);
			}
			else if (base.fixedAge >= duration && bulletCountCurrent >= bulletCount && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireTwinRocket : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject muzzleEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float baseDuration = 2f;

		private ChildLocator childLocator;

		private float stopwatch;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			GetAimRay();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
			}
			FireProjectile("GatLeft");
			FireProjectile("GatRight");
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void FireProjectile(string muzzleString)
		{
			GetAimRay();
			Transform transform = childLocator.FindChild(muzzleString);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if (!base.isAuthority || !(projectilePrefab != null))
			{
				return;
			}
			float maxDistance = 1000f;
			Ray aimRay = GetAimRay();
			UnityEngine.Vector3 forward = aimRay.direction;
			UnityEngine.Vector3 position = aimRay.origin;
			if ((bool)transform)
			{
				position = transform.position;
				if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask))
				{
					forward = hitInfo.point - transform.position;
				}
			}
			ProjectileManager.instance.FireProjectile(projectilePrefab, position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration / attackSpeedStat && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class HealBeam : BaseState
	{
		public static float baseDuration;

		public static float healCoefficient = 5f;

		public static GameObject healBeamPrefab;

		public HurtBox target;

		private HealBeamController healBeamController;

		private float duration;

		private float lineWidthRefVelocity;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Gesture", "Heal", 0.2f);
			duration = baseDuration / attackSpeedStat;
			float healRate = healCoefficient * damageStat / duration;
			Ray aimRay = GetAimRay();
			Transform transform = FindModelChild("Muzzle");
			if (NetworkServer.active)
			{
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.teamMaskFilter = TeamMask.none;
				if ((bool)base.teamComponent)
				{
					bullseyeSearch.teamMaskFilter.AddTeam(base.teamComponent.teamIndex);
				}
				bullseyeSearch.filterByLoS = false;
				bullseyeSearch.maxDistanceFilter = 50f;
				bullseyeSearch.maxAngleFilter = 180f;
				bullseyeSearch.searchOrigin = aimRay.origin;
				bullseyeSearch.searchDirection = aimRay.direction;
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
				bullseyeSearch.RefreshCandidates();
				bullseyeSearch.FilterOutGameObject(base.gameObject);
				target = bullseyeSearch.GetResults().FirstOrDefault();
				if ((bool)transform && (bool)target)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(healBeamPrefab, transform);
					healBeamController = gameObject.GetComponent<HealBeamController>();
					healBeamController.healRate = healRate;
					healBeamController.target = target;
					healBeamController.ownership.ownerObject = base.gameObject;
					NetworkServer.Spawn(gameObject);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((base.fixedAge >= duration || !target) && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			PlayCrossfade("Gesture", "Empty", 0.2f);
			if ((bool)healBeamController)
			{
				healBeamController.BreakServer();
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			HurtBoxReference.FromHurtBox(target).Write(writer);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			HurtBoxReference hurtBoxReference = default(HurtBoxReference);
			hurtBoxReference.Read(reader);
			target = hurtBoxReference.ResolveGameObject()?.GetComponent<HurtBox>();
		}
	}
	public class StartHealBeam : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float targetSelectionRange;

		[SerializeField]
		public float healRateCoefficient;

		[SerializeField]
		public GameObject healBeamPrefab;

		[SerializeField]
		public string muzzleName;

		[SerializeField]
		public int maxSimultaneousBeams;

		private HurtBox targetHurtBox;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				targetHurtBox = FindTarget(aimRay);
			}
			if (NetworkServer.active && HealBeamController.GetHealBeamCountForOwner(base.gameObject) < maxSimultaneousBeams && (bool)targetHurtBox)
			{
				Transform transform = FindModelChild(muzzleName);
				if ((bool)transform)
				{
					GameObject obj = UnityEngine.Object.Instantiate(healBeamPrefab, transform);
					HealBeamController component = obj.GetComponent<HealBeamController>();
					component.healRate = healRateCoefficient * damageStat * attackSpeedStat;
					component.target = targetHurtBox;
					component.ownership.ownerObject = base.gameObject;
					obj.AddComponent<DestroyOnTimer>().duration = duration;
					NetworkServer.Spawn(obj);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private HurtBox FindTarget(Ray aimRay)
		{
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.none;
			if ((bool)base.teamComponent)
			{
				bullseyeSearch.teamMaskFilter.AddTeam(base.teamComponent.teamIndex);
			}
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.maxDistanceFilter = targetSelectionRange;
			bullseyeSearch.maxAngleFilter = 180f;
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.RefreshCandidates();
			bullseyeSearch.FilterOutGameObject(base.gameObject);
			return bullseyeSearch.GetResults().Where(NotAlreadyHealingTarget).Where(IsHurt)
				.FirstOrDefault();
		}

		private bool NotAlreadyHealingTarget(HurtBox hurtBox)
		{
			return !HealBeamController.HealBeamAlreadyExists(base.gameObject, hurtBox);
		}

		private static bool IsHurt(HurtBox hurtBox)
		{
			if (hurtBox.healthComponent.alive)
			{
				return hurtBox.healthComponent.health < hurtBox.healthComponent.fullHealth;
			}
			return false;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(HurtBoxReference.FromHurtBox(targetHurtBox));
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			targetHurtBox = reader.ReadHurtBoxReference().ResolveHurtBox();
		}
	}
	public class Flamethrower : EntityStates.Mage.Weapon.Flamethrower
	{
	}
}
namespace EntityStates.Destructible
{
	public class AltarSkeletonDeath : BaseState
	{
		public static GameObject explosionEffectPrefab;

		public static float explosionRadius;

		public static string deathSoundString;

		private float stopwatch;

		public static event Action onDeath;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(deathSoundString, base.gameObject);
			Explode();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}

		private void Explode()
		{
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if ((bool)explosionEffectPrefab && NetworkServer.active)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = explosionRadius,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: false);
			}
			AltarSkeletonDeath.onDeath?.Invoke();
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class ExplosivePotDeath : BaseState
	{
		public static GameObject chargePrefab;

		[Tooltip("How long the object will wait before exploding")]
		public static float chargeDuration;

		public static GameObject explosionEffectPrefab;

		public static float explosionRadius;

		public static float explosionDamageCoefficient;

		public static float explosionProcCoefficient;

		public static float explosionForce;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)chargePrefab)
			{
				UnityEngine.Object.Instantiate(chargePrefab, base.transform);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= chargeDuration)
			{
				Explode();
			}
		}

		public virtual void Explode()
		{
			if ((bool)explosionEffectPrefab)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = explosionRadius,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: true);
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient;
			blastAttack.radius = explosionRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.procCoefficient = explosionProcCoefficient;
			blastAttack.teamIndex = TeamIndex.None;
			blastAttack.damageType = DamageType.ClayGoo;
			blastAttack.position = base.transform.position;
			blastAttack.baseForce = explosionForce;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.Fire();
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class FusionCellDeath : BaseState
	{
		public static string chargeChildEffectName;

		public static float chargeDuration;

		public static GameObject explosionEffectPrefab;

		public static float explosionRadius;

		public static float explosionDamageCoefficient;

		public static float explosionProcCoefficient;

		public static float explosionForce;

		private float stopwatch;

		public override void OnEnter()
		{
			base.OnEnter();
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild(chargeChildEffectName);
				if ((bool)transform)
				{
					transform.gameObject.SetActive(value: true);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch > chargeDuration)
			{
				Explode();
			}
		}

		private void Explode()
		{
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if ((bool)explosionEffectPrefab && NetworkServer.active)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = explosionRadius,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: true);
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient;
			blastAttack.radius = explosionRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.procCoefficient = explosionProcCoefficient;
			blastAttack.teamIndex = TeamIndex.None;
			blastAttack.position = base.transform.position;
			blastAttack.baseForce = explosionForce;
			blastAttack.bonusForce = explosionForce * 0.5f * UnityEngine.Vector3.up;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.Fire();
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class GauntletShardDeath : BaseState
	{
		public static GameObject explosionEffectPrefab;

		public static float explosionRadius;

		public static float explosionDamageCoefficient;

		public static float explosionProcCoefficient;

		public static float explosionForce;

		private float stopwatch;

		public override void OnEnter()
		{
			base.OnEnter();
			Explode();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
		}

		private void Explode()
		{
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if ((bool)explosionEffectPrefab && NetworkServer.active)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = explosionRadius,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: true);
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient;
			blastAttack.radius = explosionRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.procCoefficient = explosionProcCoefficient;
			blastAttack.teamIndex = TeamIndex.None;
			blastAttack.position = base.transform.position;
			blastAttack.baseForce = explosionForce;
			blastAttack.bonusForce = explosionForce * 0.5f * UnityEngine.Vector3.up;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.Fire();
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class SulfurPodDeath : GenericCharacterDeath
	{
		public static GameObject chargePrefab;

		public static float chargeDuration;

		public static GameObject explosionEffectPrefab;

		public static float explosionRadius;

		public static float explosionDamageCoefficient;

		public static float explosionProcCoefficient;

		public static float explosionForce;

		private bool hasExploded;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)chargePrefab)
			{
				UnityEngine.Object.Instantiate(chargePrefab, base.transform);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= chargeDuration)
			{
				Explode();
			}
		}

		private void Explode()
		{
			if (!hasExploded)
			{
				hasExploded = true;
				if ((bool)explosionEffectPrefab)
				{
					EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
					{
						origin = base.transform.position,
						scale = explosionRadius,
						rotation = UnityEngine.Quaternion.identity
					}, transmit: true);
				}
				DestroyModel();
				if (NetworkServer.active)
				{
					BlastAttack blastAttack = new BlastAttack();
					blastAttack.attacker = base.gameObject;
					blastAttack.damageColorIndex = DamageColorIndex.Poison;
					blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient;
					blastAttack.radius = explosionRadius;
					blastAttack.falloffModel = BlastAttack.FalloffModel.None;
					blastAttack.procCoefficient = explosionProcCoefficient;
					blastAttack.teamIndex = TeamIndex.None;
					blastAttack.damageType = DamageType.PoisonOnHit;
					blastAttack.position = base.transform.position;
					blastAttack.baseForce = explosionForce;
					blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
					blastAttack.Fire();
					DestroyBodyAsapServer();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class TimeCrystalDeath : BaseState
	{
		public static GameObject explosionEffectPrefab;

		public static float explosionRadius;

		public static float explosionDamageCoefficient;

		public static float explosionProcCoefficient;

		public static float explosionForce;

		private float stopwatch;

		public override void OnEnter()
		{
			base.OnEnter();
			Explode();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
		}

		private void Explode()
		{
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if ((bool)explosionEffectPrefab && NetworkServer.active)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = explosionRadius,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: true);
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.baseDamage = damageStat * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient;
			blastAttack.radius = explosionRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.procCoefficient = explosionProcCoefficient;
			blastAttack.teamIndex = TeamIndex.None;
			blastAttack.position = base.transform.position;
			blastAttack.baseForce = explosionForce;
			blastAttack.bonusForce = explosionForce * 0.5f * UnityEngine.Vector3.up;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.Fire();
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class CorruptedSpikeDeath : BaseState
	{
		public static GameObject chargePrefab;

		public static float chargeDuration;

		public static GameObject explosionEffectPrefab;

		public static float explosionRadius;

		public static float explosionDamageCoefficient;

		public static float explosionProcCoefficient;

		public static float explosionForce;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)chargePrefab)
			{
				UnityEngine.Object.Instantiate(chargePrefab, base.transform);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= chargeDuration)
			{
				Explode();
			}
		}

		private void Explode()
		{
			if ((bool)explosionEffectPrefab)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = explosionRadius,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: true);
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.baseDamage = 1f;
			blastAttack.radius = explosionRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.procCoefficient = explosionProcCoefficient;
			blastAttack.teamIndex = TeamIndex.None;
			blastAttack.position = base.transform.position;
			blastAttack.baseForce = explosionForce;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.Fire();
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class LunarRainDeathState : BaseState
	{
		public static GameObject chargePrefab;

		[Tooltip("How long the object will wait before exploding")]
		public static float chargeDuration;

		public static GameObject explosionEffectPrefab;

		public static float baseDamage;

		public static float explosionRadius;

		public static float explosionDamageCoefficient;

		public static float explosionProcCoefficient;

		public static float explosionForce;

		public static float vfxScale;

		public static bool canRejectForce;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.teamComponent != null)
			{
				base.teamComponent.teamIndex = TeamIndex.Monster;
			}
			if ((bool)chargePrefab)
			{
				EffectData effectData = new EffectData
				{
					scale = explosionRadius,
					origin = base.transform.position
				};
				EffectManager.SpawnEffect(chargePrefab, effectData, transmit: false);
			}
			FlashEmission component = base.modelLocator.modelTransform.GetComponent<FlashEmission>();
			if ((bool)component)
			{
				component.StartFlash();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= chargeDuration && NetworkServer.active)
			{
				Explode();
			}
		}

		public virtual void Explode()
		{
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if ((bool)explosionEffectPrefab)
			{
				EffectManager.SpawnEffect(explosionEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = vfxScale,
					rotation = base.transform.rotation
				}, transmit: true);
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.gameObject;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.baseDamage = baseDamage * explosionDamageCoefficient * Run.instance.teamlessDamageCoefficient;
			blastAttack.radius = explosionRadius;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.procCoefficient = explosionProcCoefficient;
			blastAttack.teamIndex = TeamIndex.Monster;
			blastAttack.damageType = DamageType.LunarRuin;
			blastAttack.position = base.transform.position;
			blastAttack.baseForce = explosionForce;
			blastAttack.canRejectForce = canRejectForce;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.Fire();
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.DeepVoidPortalBattery
{
	public class BaseDeepVoidPortalBatteryState : BaseState
	{
		[SerializeField]
		public string onEnterSoundString;

		[SerializeField]
		public string onEnterChildToEnable;

		[SerializeField]
		public string animationStateName;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(onEnterSoundString, base.gameObject);
			GameObject gameObject = FindModelChildGameObject(onEnterChildToEnable);
			if ((bool)gameObject)
			{
				gameObject.SetActive(value: true);
			}
			PlayAnimation("Base", animationStateName);
		}

		public override void OnExit()
		{
			GameObject gameObject = FindModelChildGameObject(onEnterChildToEnable);
			if ((bool)gameObject)
			{
				gameObject.SetActive(value: false);
			}
			base.OnExit();
		}
	}
	public class Idle : BaseDeepVoidPortalBatteryState
	{
	}
	public class Charging : BaseDeepVoidPortalBatteryState
	{
		[SerializeField]
		public GameObject chargingPositionIndicator;

		private CombatDirector combatDirector;

		private HoldoutZoneController holdoutZoneController;

		private VoidStageMissionController.FogRequest fogRequest;

		private ChargeIndicatorController chargeIndicatorController;

		public override void OnEnter()
		{
			base.OnEnter();
			holdoutZoneController = GetComponent<HoldoutZoneController>();
			if ((bool)holdoutZoneController)
			{
				holdoutZoneController.enabled = true;
			}
			Transform targetTransform = FindModelChild("PositionIndicatorPosition").transform;
			PositionIndicator component = UnityEngine.Object.Instantiate(chargingPositionIndicator, base.transform.position, UnityEngine.Quaternion.identity).GetComponent<PositionIndicator>();
			component.targetTransform = targetTransform;
			chargeIndicatorController = component.GetComponent<ChargeIndicatorController>();
			chargeIndicatorController.holdoutZoneController = holdoutZoneController;
			if (NetworkServer.active)
			{
				combatDirector = GetComponent<CombatDirector>();
				if ((bool)combatDirector)
				{
					combatDirector.enabled = true;
					combatDirector.SetNextSpawnAsBoss();
				}
				if ((bool)holdoutZoneController && (bool)VoidStageMissionController.instance)
				{
					fogRequest = VoidStageMissionController.instance.RequestFog(holdoutZoneController);
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeIndicatorController)
			{
				EntityState.Destroy(chargeIndicatorController.gameObject);
			}
			if ((bool)holdoutZoneController)
			{
				holdoutZoneController.enabled = false;
			}
			if (NetworkServer.active)
			{
				if ((bool)combatDirector)
				{
					combatDirector.enabled = false;
				}
				fogRequest?.Dispose();
				fogRequest = null;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && holdoutZoneController.charge >= 1f)
			{
				outer.SetNextState(new Charged());
			}
		}
	}
	public class Charged : BaseDeepVoidPortalBatteryState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)VoidStageMissionController.instance && NetworkServer.active)
			{
				VoidStageMissionController.instance.OnBatteryActivated();
			}
		}
	}
}
namespace EntityStates.Croco
{
	public class Bite : BasicMeleeAttack
	{
		public static float recoilAmplitude;

		public static float baseDurationBeforeInterruptable;

		[SerializeField]
		public float bloom;

		public static string biteSound;

		private string animationStateName;

		private float durationBeforeInterruptable;

		private CrocoDamageTypeController crocoDamageTypeController;

		private bool hasGrantedBuff;

		protected override bool allowExitFire
		{
			get
			{
				if ((bool)base.characterBody)
				{
					return !base.characterBody.isSprinting;
				}
				return false;
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterDirection.forward = GetAimRay().direction;
			durationBeforeInterruptable = baseDurationBeforeInterruptable / attackSpeedStat;
			crocoDamageTypeController = GetComponent<CrocoDamageTypeController>();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			DamageTypeCombo damageTypeCombo = (crocoDamageTypeController ? crocoDamageTypeController.GetDamageType() : DamageTypeCombo.Generic);
			overlapAttack.damageType = damageTypeCombo | DamageType.BonusToLowHealth;
		}

		protected override void PlayAnimation()
		{
			float num = Mathf.Max(duration, 0.2f);
			PlayCrossfade("Gesture, Additive", "Bite", "Bite.playbackRate", num, 0.05f);
			PlayCrossfade("Gesture, Override", "Bite", "Bite.playbackRate", num, 0.05f);
			Util.PlaySound(biteSound, base.gameObject);
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			base.characterBody.AddSpreadBloom(bloom);
			if (!hasGrantedBuff)
			{
				hasGrantedBuff = true;
				base.characterBody.AddTimedBuffAuthority(RoR2Content.Buffs.CrocoRegen.buffIndex, 0.5f);
			}
		}

		protected override void BeginMeleeAttackEffect()
		{
			AddRecoil(0.9f * recoilAmplitude, 1.1f * recoilAmplitude, -0.1f * recoilAmplitude, 0.1f * recoilAmplitude);
			base.BeginMeleeAttackEffect();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge < durationBeforeInterruptable))
			{
				return InterruptPriority.Skill;
			}
			return InterruptPriority.Pain;
		}
	}
	public class Disease : BaseState
	{
		public static GameObject muzzleflashEffectPrefab;

		public static string muzzleString;

		public static float orbRange;

		public static float baseDuration;

		public static float damageCoefficient;

		public static int maxBounces;

		public static float bounceRange;

		public static float procCoefficient;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			Transform transform = FindModelChild(muzzleString);
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.maxDistanceFilter = orbRange;
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			bullseyeSearch.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject));
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
			bullseyeSearch.RefreshCandidates();
			EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
			List<HurtBox> list = bullseyeSearch.GetResults().ToList();
			if (list.Count > 0)
			{
				UnityEngine.Debug.LogFormat("Shooting at {0}", list[0]);
				HurtBox target = list.FirstOrDefault();
				LightningOrb lightningOrb = new LightningOrb();
				lightningOrb.attacker = base.gameObject;
				lightningOrb.bouncedObjects = new List<HealthComponent>();
				lightningOrb.lightningType = LightningOrb.LightningType.CrocoDisease;
				lightningOrb.damageType = DamageType.PoisonOnHit;
				lightningOrb.damageValue = damageStat * damageCoefficient;
				lightningOrb.isCrit = RollCrit();
				lightningOrb.procCoefficient = procCoefficient;
				lightningOrb.bouncesRemaining = maxBounces;
				lightningOrb.origin = transform.position;
				lightningOrb.target = target;
				lightningOrb.teamIndex = GetTeam();
				lightningOrb.range = bounceRange;
				OrbManager.instance.AddOrb(lightningOrb);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class FireSpit : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		[SerializeField]
		public string attackString;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		private float duration;

		private CrocoDamageTypeController crocoDamageTypeController;

		private static int FireSpitStateHash = Animator.StringToHash("FireSpit");

		private static int FireSpitParamHash = Animator.StringToHash("FireSpit.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			crocoDamageTypeController = GetComponent<CrocoDamageTypeController>();
			Ray ray = GetAimRay();
			TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
			duration = baseDuration / attackSpeedStat;
			StartAimMode(duration + 2f);
			PlayAnimation("Gesture, Mouth", FireSpitStateHash, FireSpitParamHash, duration);
			Util.PlaySound(attackString, base.gameObject);
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(bloom);
			string muzzleName = "MouthMuzzle";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				DamageTypeCombo value = (crocoDamageTypeController ? crocoDamageTypeController.GetDamageType() : DamageTypeCombo.Generic);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = ray.origin;
				fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction);
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.damageTypeOverride = value;
				fireProjectileInfo.force = force;
				fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireDiseaseProjectile : FireSpit
	{
	}
	public class BaseLeap : BaseCharacterMain
	{
		public static float minimumDuration;

		public static float blastRadius;

		public static float blastProcCoefficient;

		[SerializeField]
		public float blastDamageCoefficient;

		[SerializeField]
		public float blastForce;

		public static string leapSoundString;

		public static GameObject projectilePrefab;

		[SerializeField]
		public UnityEngine.Vector3 blastBonusForce;

		[SerializeField]
		public GameObject blastImpactEffectPrefab;

		[SerializeField]
		public GameObject blastEffectPrefab;

		public static float airControl;

		public static float aimVelocity;

		public static float upwardVelocity;

		public static float forwardVelocity;

		public static float minimumY;

		public static float minYVelocityForAnim;

		public static float maxYVelocityForAnim;

		public static float knockbackForce;

		[SerializeField]
		public GameObject fistEffectPrefab;

		public static string soundLoopStartEvent;

		public static string soundLoopStopEvent;

		public static NetworkSoundEventDef landingSound;

		private float previousAirControl;

		private GameObject leftFistEffectInstance;

		private GameObject rightFistEffectInstance;

		protected bool isCritAuthority;

		protected CrocoDamageTypeController crocoDamageTypeController;

		private bool detonateNextFrame;

		private static int LightImpactStateHash = Animator.StringToHash("LightImpact");

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		protected virtual DamageTypeCombo GetBlastDamageType()
		{
			return DamageType.Generic;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			crocoDamageTypeController = GetComponent<CrocoDamageTypeController>();
			previousAirControl = base.characterMotor.airControl;
			base.characterMotor.airControl = airControl;
			UnityEngine.Vector3 direction = GetAimRay().direction;
			if (base.isAuthority)
			{
				base.characterBody.isSprinting = true;
				direction.y = Mathf.Max(direction.y, minimumY);
				UnityEngine.Vector3 vector = direction.normalized * aimVelocity * moveSpeedStat;
				UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up * upwardVelocity;
				UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(direction.x, 0f, direction.z).normalized * forwardVelocity;
				base.characterMotor.Motor.ForceUnground();
				base.characterMotor.velocity = vector + vector2 + vector3;
				isCritAuthority = RollCrit();
			}
			base.characterBody.bodyFlags |= CharacterBody.BodyFlags.IgnoreFallDamage;
			GetModelTransform().GetComponent<AimAnimator>().enabled = true;
			PlayCrossfade("Gesture, Override", "Leap", 0.1f);
			PlayCrossfade("Gesture, AdditiveHigh", "Leap", 0.1f);
			PlayCrossfade("Gesture, Override", "Leap", 0.1f);
			Util.PlaySound(leapSoundString, base.gameObject);
			base.characterDirection.moveVector = direction;
			leftFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MuzzleHandL"));
			rightFistEffectInstance = UnityEngine.Object.Instantiate(fistEffectPrefab, FindModelChild("MuzzleHandR"));
			if (base.isAuthority)
			{
				base.characterMotor.onMovementHit += OnMovementHit;
			}
			Util.PlaySound(soundLoopStartEvent, base.gameObject);
		}

		private void OnMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo)
		{
			detonateNextFrame = true;
		}

		private void onHitGroundServer(ref CharacterMotor.HitGroundInfo hitGroundInfo)
		{
			detonateNextFrame = true;
		}

		protected override void UpdateAnimationParameters()
		{
			base.UpdateAnimationParameters();
			float value = Mathf.Clamp01(Util.Remap(base.estimatedVelocity.y, minYVelocityForAnim, maxYVelocityForAnim, 0f, 1f)) * 0.97f;
			base.modelAnimator.SetFloat("LeapCycle", value, 0.1f, Time.deltaTime);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (bool)base.characterMotor)
			{
				base.characterMotor.moveDirection = base.inputBank.moveVector;
				if (base.fixedAge >= minimumDuration && (detonateNextFrame || (base.characterMotor.Motor.GroundingStatus.IsStableOnGround && !base.characterMotor.Motor.LastGroundingStatus.IsStableOnGround)))
				{
					DoImpactAuthority();
					outer.SetNextStateToMain();
				}
			}
		}

		protected virtual void DoImpactAuthority()
		{
			if ((bool)landingSound)
			{
				EffectManager.SimpleSoundEffect(landingSound.index, base.characterBody.footPosition, transmit: true);
			}
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = footPosition,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = isCritAuthority,
				damageType = GetBlastDamageType(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = footPosition,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		protected void DropAcidPoolAuthority()
		{
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.crit = isCritAuthority;
			fireProjectileInfo.force = 0f;
			fireProjectileInfo.damage = damageStat;
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
			fireProjectileInfo.position = footPosition;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
		}

		public override void OnExit()
		{
			Util.PlaySound(soundLoopStopEvent, base.gameObject);
			if (base.isAuthority)
			{
				base.characterMotor.onMovementHit -= OnMovementHit;
			}
			base.characterBody.bodyFlags &= ~CharacterBody.BodyFlags.IgnoreFallDamage;
			base.characterMotor.airControl = previousAirControl;
			base.characterBody.isSprinting = false;
			int layerIndex = base.modelAnimator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				base.modelAnimator.SetLayerWeight(layerIndex, 2f);
				PlayAnimation("Impact", LightImpactStateHash);
			}
			PlayCrossfade("Gesture, Override", BufferEmptyStateHash, 0.1f);
			PlayCrossfade("Gesture, AdditiveHigh", BufferEmptyStateHash, 0.1f);
			EntityState.Destroy(leftFistEffectInstance);
			EntityState.Destroy(rightFistEffectInstance);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class Leap : BaseLeap
	{
		protected override DamageTypeCombo GetBlastDamageType()
		{
			return (crocoDamageTypeController ? crocoDamageTypeController.GetDamageType() : DamageTypeCombo.Generic) | DamageType.Stun1s;
		}

		protected override void DoImpactAuthority()
		{
			base.DoImpactAuthority();
			DetonateAuthority();
			DropAcidPoolAuthority();
		}
	}
	public class ChainableLeap : BaseLeap
	{
		public static float refundPerHit;

		protected override DamageTypeCombo GetBlastDamageType()
		{
			return DamageType.Stun1s;
		}

		protected override void DoImpactAuthority()
		{
			base.DoImpactAuthority();
			BlastAttack.Result result = DetonateAuthority();
			base.skillLocator.utility.RunRecharge((float)result.hitCount * refundPerHit);
		}
	}
	public class Slash : BasicMeleeAttack, SteppedSkillDef.IStepSetter
	{
		public int step;

		public static float recoilAmplitude;

		public static float baseDurationBeforeInterruptable;

		[SerializeField]
		public float bloom;

		public static GameObject comboFinisherSwingEffectPrefab;

		public static float comboFinisherhitPauseDuration;

		public static float comboFinisherDamageCoefficient;

		public static float comboFinisherBloom;

		public static float comboFinisherBaseDurationBeforeInterruptable;

		public static string slash1Sound;

		public static string slash3Sound;

		private string animationStateName;

		private float durationBeforeInterruptable;

		private bool hasGrantedBuff;

		private bool isComboFinisher => step == 2;

		protected override bool allowExitFire
		{
			get
			{
				if ((bool)base.characterBody)
				{
					return !base.characterBody.isSprinting;
				}
				return false;
			}
		}

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			step = i;
		}

		public override void OnEnter()
		{
			if (isComboFinisher)
			{
				swingEffectPrefab = comboFinisherSwingEffectPrefab;
				hitPauseDuration = comboFinisherhitPauseDuration;
				damageCoefficient = comboFinisherDamageCoefficient;
				bloom = comboFinisherBloom;
			}
			base.OnEnter();
			base.characterDirection.forward = GetAimRay().direction;
			durationBeforeInterruptable = (isComboFinisher ? (comboFinisherBaseDurationBeforeInterruptable / attackSpeedStat) : (baseDurationBeforeInterruptable / attackSpeedStat));
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
		}

		protected override void PlayAnimation()
		{
			animationStateName = "";
			string soundString = null;
			switch (step)
			{
			case 0:
				animationStateName = "Slash1";
				soundString = slash1Sound;
				break;
			case 1:
				animationStateName = "Slash2";
				soundString = slash1Sound;
				break;
			case 2:
				animationStateName = "Slash3";
				soundString = slash3Sound;
				break;
			}
			float num = Mathf.Max(duration, 0.2f);
			PlayCrossfade("Gesture, Additive", animationStateName, "Slash.playbackRate", num, 0.05f);
			PlayCrossfade("Gesture, Override", animationStateName, "Slash.playbackRate", num, 0.05f);
			Util.PlaySound(soundString, base.gameObject);
		}

		protected override void OnMeleeHitAuthority()
		{
			base.OnMeleeHitAuthority();
			base.characterBody.AddSpreadBloom(bloom);
			if (!hasGrantedBuff && isComboFinisher)
			{
				hasGrantedBuff = true;
				base.characterBody.AddTimedBuffAuthority(RoR2Content.Buffs.CrocoRegen.buffIndex, 0.5f);
			}
		}

		protected override void BeginMeleeAttackEffect()
		{
			swingEffectMuzzleString = animationStateName;
			AddRecoil(-0.1f * recoilAmplitude, 0.1f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			base.BeginMeleeAttackEffect();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write((byte)step);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			step = reader.ReadByte();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge < durationBeforeInterruptable))
			{
				return InterruptPriority.Skill;
			}
			return InterruptPriority.PrioritySkill;
		}
	}
	public class Spawn : BaseState
	{
		public static float minimumSleepDuration;

		public static GameObject spawnEffectPrefab;

		private Animator modelAnimator;

		private static int SleepLoopStateHash = Animator.StringToHash("SleepLoop");

		public override void OnEnter()
		{
			base.OnEnter();
			base.modelLocator.normalizeToFloor = true;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat(AnimationParameters.aimWeight, 0f);
			}
			PlayAnimation("Body", SleepLoopStateHash);
			EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData
			{
				origin = base.characterBody.footPosition
			}, transmit: false);
		}

		public override void OnExit()
		{
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat(AnimationParameters.aimWeight, 1f);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= minimumSleepDuration && (base.inputBank.moveVector.sqrMagnitude >= Mathf.Epsilon || base.inputBank.CheckAnyButtonDown()))
			{
				outer.SetNextState(new WakeUp());
			}
		}
	}
	public class WakeUp : BaseState
	{
		public static float duration;

		public static float delayBeforeAimAnimatorWeight;

		private Animator modelAnimator;

		private static int SleepToIdleStateHash = Animator.StringToHash("SleepToIdle");

		private static int SleepToIdleParamHash = Animator.StringToHash("SleepToIdle.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			base.modelLocator.normalizeToFloor = true;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat(AnimationParameters.aimWeight, 0f);
			}
			PlayAnimation("Body", SleepToIdleStateHash, SleepToIdleParamHash, duration);
		}

		public override void Update()
		{
			base.Update();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat(AnimationParameters.aimWeight, Mathf.Clamp01((base.age - delayBeforeAimAnimatorWeight) / duration));
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat(AnimationParameters.aimWeight, 1f);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.Commando
{
	public class DeathState : GenericCharacterDeath
	{
		private UnityEngine.Vector3 previousPosition;

		private float upSpeedVelocity;

		private float upSpeed;

		private Animator modelAnimator;

		protected override bool shouldAutoDestroy => false;

		public override void OnEnter()
		{
			base.OnEnter();
			UnityEngine.Vector3 force = UnityEngine.Vector3.up * 3f;
			if ((bool)base.characterMotor)
			{
				force += base.characterMotor.velocity;
				base.characterMotor.enabled = false;
			}
			if ((bool)base.cachedModelTransform)
			{
				RagdollController component = base.cachedModelTransform.GetComponent<RagdollController>();
				if ((bool)component)
				{
					component.BeginRagdoll(force);
				}
			}
		}

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge > 4f)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class DodgeState : BaseState
	{
		[SerializeField]
		public float duration = 0.9f;

		[SerializeField]
		public float initialSpeedCoefficient;

		[SerializeField]
		public float finalSpeedCoefficient;

		public static string dodgeSoundString;

		public static GameObject jetEffect;

		public static float dodgeFOV;

		public static int primaryReloadStockCount;

		private float rollSpeed;

		private UnityEngine.Vector3 forwardDirection;

		private Animator animator;

		private UnityEngine.Vector3 previousPosition;

		private static int DodgeForwardStateHash = Animator.StringToHash("DodgeForward");

		private static int DodgeBackwardStateHash = Animator.StringToHash("DodgeBackward");

		private static int DodgeRightStateHash = Animator.StringToHash("DodgeRight");

		private static int DodgeLeftStateHash = Animator.StringToHash("DodgeLeft");

		private static int DodgeParamHash = Animator.StringToHash("Dodge.playbackRate");

		public override void Reset()
		{
			base.Reset();
			rollSpeed = 0f;
			forwardDirection = UnityEngine.Vector3.zero;
			animator = null;
			previousPosition = UnityEngine.Vector3.zero;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(dodgeSoundString, base.gameObject);
			animator = GetModelAnimator();
			ChildLocator component = animator.GetComponent<ChildLocator>();
			if (base.isAuthority)
			{
				if ((bool)base.inputBank && (bool)base.characterDirection)
				{
					forwardDirection = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized;
				}
				if ((bool)base.skillLocator.primary)
				{
					base.skillLocator.primary.Reset();
					base.skillLocator.primary.stock = primaryReloadStockCount;
				}
			}
			UnityEngine.Vector3 rhs = (base.characterDirection ? base.characterDirection.forward : forwardDirection);
			UnityEngine.Vector3 rhs2 = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, rhs);
			float num = UnityEngine.Vector3.Dot(forwardDirection, rhs);
			float num2 = UnityEngine.Vector3.Dot(forwardDirection, rhs2);
			animator.SetFloat("forwardSpeed", num, 0.1f, GetDeltaTime());
			animator.SetFloat("rightSpeed", num2, 0.1f, GetDeltaTime());
			if (Mathf.Abs(num) > Mathf.Abs(num2))
			{
				PlayAnimation("Body", (num > 0f) ? DodgeForwardStateHash : DodgeBackwardStateHash, DodgeParamHash, duration);
			}
			else
			{
				PlayAnimation("Body", (num2 > 0f) ? DodgeRightStateHash : DodgeLeftStateHash, DodgeParamHash, duration);
			}
			if ((bool)jetEffect)
			{
				Transform transform = component.FindChild("LeftJet");
				Transform transform2 = component.FindChild("RightJet");
				bool flag = EffectManager.ShouldUsePooledEffect(jetEffect);
				if ((bool)transform)
				{
					if (!flag)
					{
						UnityEngine.Object.Instantiate(jetEffect, transform);
					}
					else
					{
						EffectManager.GetAndActivatePooledEffect(jetEffect, transform, inResetLocal: true);
					}
				}
				if ((bool)transform2)
				{
					if (!flag)
					{
						UnityEngine.Object.Instantiate(jetEffect, transform2);
					}
					else
					{
						EffectManager.GetAndActivatePooledEffect(jetEffect, transform2, inResetLocal: true);
					}
				}
			}
			RecalculateRollSpeed();
			if ((bool)base.characterMotor && (bool)base.characterDirection)
			{
				base.characterMotor.velocity.y = 0f;
				base.characterMotor.velocity = forwardDirection * rollSpeed;
			}
			UnityEngine.Vector3 vector = (base.characterMotor ? base.characterMotor.velocity : UnityEngine.Vector3.zero);
			previousPosition = base.transform.position - vector;
		}

		private void RecalculateRollSpeed()
		{
			rollSpeed = moveSpeedStat * Mathf.Lerp(initialSpeedCoefficient, finalSpeedCoefficient, base.fixedAge / duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			RecalculateRollSpeed();
			if ((bool)base.cameraTargetParams)
			{
				base.cameraTargetParams.fovOverride = Mathf.Lerp(dodgeFOV, 60f, base.fixedAge / duration);
			}
			UnityEngine.Vector3 normalized = (base.transform.position - previousPosition).normalized;
			if ((bool)base.characterMotor && (bool)base.characterDirection && normalized != UnityEngine.Vector3.zero)
			{
				UnityEngine.Vector3 lhs = normalized * rollSpeed;
				float y = lhs.y;
				lhs.y = 0f;
				float num = Mathf.Max(UnityEngine.Vector3.Dot(lhs, forwardDirection), 0f);
				lhs = forwardDirection * num;
				lhs.y += Mathf.Max(y, 0f);
				base.characterMotor.velocity = lhs;
			}
			previousPosition = base.transform.position;
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)base.cameraTargetParams)
			{
				base.cameraTargetParams.fovOverride = -1f;
			}
			base.OnExit();
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(forwardDirection);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			forwardDirection = reader.ReadVector3();
		}
	}
	public class CombatDodge : DodgeState
	{
		public static float durationToFire;

		public static int bulletCount;

		public static GameObject muzzleEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static string firePistolSoundString;

		public static float recoilAmplitude = 1f;

		public static float range;

		private int bulletsFired;

		private BullseyeSearch search;

		private static int FirePistolLeftStateHash = Animator.StringToHash("FirePistol, Left");

		private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right");

		public override void OnEnter()
		{
			base.OnEnter();
			search = new BullseyeSearch();
			search.searchDirection = UnityEngine.Vector3.zero;
			search.teamMaskFilter = TeamMask.allButNeutral;
			search.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex);
			search.filterByLoS = true;
			search.sortMode = BullseyeSearch.SortMode.Distance;
			search.maxDistanceFilter = range;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float num = base.fixedAge / durationToFire;
			if (bulletsFired < bulletCount && num > (float)bulletsFired / (float)bulletCount)
			{
				if (bulletsFired % 2 == 0)
				{
					PlayAnimation("Gesture Additive, Left", FirePistolLeftStateHash);
					FireBullet("MuzzleLeft");
				}
				else
				{
					PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash);
					FireBullet("MuzzleRight");
				}
			}
		}

		private HurtBox PickNextTarget()
		{
			search.searchOrigin = GetAimRay().origin;
			search.RefreshCandidates();
			List<HurtBox> list = search.GetResults().ToList();
			if (list.Count <= 0)
			{
				return null;
			}
			return list[UnityEngine.Random.Range(0, list.Count)];
		}

		private void FireBullet(string targetMuzzle)
		{
			bulletsFired++;
			AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude);
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				aimRay.direction = UnityEngine.Random.onUnitSphere;
				HurtBox hurtBox = PickNextTarget();
				if ((bool)hurtBox)
				{
					aimRay.direction = hurtBox.transform.position - aimRay.origin;
				}
				Util.PlaySound(firePistolSoundString, base.gameObject);
				if ((bool)muzzleEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, targetMuzzle, transmit: false);
				}
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = base.characterBody.spreadBloomAngle;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = targetMuzzle;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.radius = 0.1f;
				bulletAttack.smartCollision = true;
				bulletAttack.Fire();
			}
		}
	}
	public class MainState : BaseState
	{
		private Animator modelAnimator;

		private GenericSkill skill1;

		private GenericSkill skill2;

		private GenericSkill skill3;

		private GenericSkill skill4;

		private bool skill1InputRecieved;

		private bool skill2InputRecieved;

		private bool skill3InputRecieved;

		private bool skill4InputRecieved;

		private UnityEngine.Vector3 previousPosition;

		private UnityEngine.Vector3 estimatedVelocity;

		private static int isMovingParamHash = Animator.StringToHash("isMoving");

		private static int walkSpeedParamHash = Animator.StringToHash("walkSpeed");

		private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed");

		private static int rightSpeedParamHash = Animator.StringToHash("rightSpeed");

		public override void OnEnter()
		{
			base.OnEnter();
			GenericSkill[] components = base.gameObject.GetComponents<GenericSkill>();
			for (int i = 0; i < components.Length; i++)
			{
				if (components[i].skillName == "FirePistol")
				{
					skill1 = components[i];
				}
				else if (components[i].skillName == "FireFMJ")
				{
					skill2 = components[i];
				}
				else if (components[i].skillName == "Roll")
				{
					skill3 = components[i];
				}
				else if (components[i].skillName == "FireBarrage")
				{
					skill4 = components[i];
				}
			}
			modelAnimator = GetModelAnimator();
			previousPosition = base.transform.position;
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Body");
				modelAnimator.CrossFadeInFixedTime("Walk", 0.1f, layerIndex);
				modelAnimator.Update(0f);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = true;
				}
			}
		}

		public override void OnExit()
		{
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = false;
				}
			}
			if (base.isAuthority && (bool)base.characterMotor)
			{
				base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
			}
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			if (base.inputBank.skill1.down)
			{
				skill1InputRecieved = true;
			}
			if (base.inputBank.skill2.down)
			{
				skill2InputRecieved = true;
			}
			if (base.inputBank.skill3.down)
			{
				skill3InputRecieved = true;
			}
			if (base.inputBank.skill4.down)
			{
				skill4InputRecieved = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			UnityEngine.Vector3 position = base.transform.position;
			float deltaTime = GetDeltaTime();
			if (deltaTime != 0f)
			{
				estimatedVelocity = (position - previousPosition) / deltaTime;
			}
			if (base.isAuthority)
			{
				UnityEngine.Vector3 moveVector = base.inputBank.moveVector;
				if ((bool)base.characterMotor)
				{
					base.characterMotor.moveDirection = moveVector;
					if (skill3InputRecieved)
					{
						if ((bool)skill3)
						{
							skill3.ExecuteIfReady();
						}
						skill3InputRecieved = false;
					}
				}
				if ((bool)base.characterDirection)
				{
					if ((bool)base.characterBody && base.characterBody.shouldAim)
					{
						base.characterDirection.moveVector = base.inputBank.aimDirection;
					}
					else
					{
						base.characterDirection.moveVector = moveVector;
					}
				}
				if (skill1InputRecieved)
				{
					if ((bool)skill1)
					{
						skill1.ExecuteIfReady();
					}
					skill1InputRecieved = false;
				}
				if (skill2InputRecieved)
				{
					if ((bool)skill2)
					{
						skill2.ExecuteIfReady();
					}
					skill2InputRecieved = false;
				}
				if (skill4InputRecieved)
				{
					if ((bool)skill4)
					{
						skill4.ExecuteIfReady();
					}
					skill4InputRecieved = false;
				}
			}
			if ((bool)modelAnimator && (bool)base.characterDirection)
			{
				UnityEngine.Vector3 lhs = estimatedVelocity;
				lhs.y = 0f;
				UnityEngine.Vector3 forward = base.characterDirection.forward;
				UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward);
				float magnitude = lhs.magnitude;
				float value = UnityEngine.Vector3.Dot(lhs, forward);
				float value2 = UnityEngine.Vector3.Dot(lhs, rhs);
				modelAnimator.SetBool(isMovingParamHash, magnitude != 0f);
				modelAnimator.SetFloat(walkSpeedParamHash, magnitude);
				modelAnimator.SetFloat(forwardSpeedParamHash, value, 0.2f, GetDeltaTime());
				modelAnimator.SetFloat(rightSpeedParamHash, value2, 0.2f, GetDeltaTime());
			}
			previousPosition = position;
		}
	}
	public class SlideState : BaseState
	{
		public static float slideDuration;

		public static float jumpDuration;

		public static AnimationCurve forwardSpeedCoefficientCurve;

		public static AnimationCurve jumpforwardSpeedCoefficientCurve;

		public static string soundString;

		public static GameObject jetEffectPrefab;

		public static GameObject slideEffectPrefab;

		private UnityEngine.Vector3 forwardDirection;

		private GameObject slideEffectInstance;

		private bool startedStateGrounded;

		private static int JumpStateHash = Animator.StringToHash("Jump");

		private static int SlideForwardStateHash = Animator.StringToHash("SlideForward");

		private static int SlideForwardParamHash = Animator.StringToHash("SlideForward.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(soundString, base.gameObject);
			if ((bool)base.inputBank && (bool)base.characterDirection)
			{
				base.characterDirection.forward = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized;
			}
			if ((bool)base.characterMotor)
			{
				startedStateGrounded = base.characterMotor.isGrounded;
			}
			if ((bool)jetEffectPrefab)
			{
				Transform transform = FindModelChild("LeftJet");
				Transform transform2 = FindModelChild("RightJet");
				if ((bool)transform)
				{
					UnityEngine.Object.Instantiate(jetEffectPrefab, transform);
				}
				if ((bool)transform2)
				{
					UnityEngine.Object.Instantiate(jetEffectPrefab, transform2);
				}
			}
			base.characterBody.SetSpreadBloom(0f, canOnlyIncreaseBloom: false);
			if (!startedStateGrounded)
			{
				PlayAnimation("Body", JumpStateHash);
				UnityEngine.Vector3 velocity = base.characterMotor.velocity;
				velocity.y = base.characterBody.jumpPower;
				base.characterMotor.velocity = velocity;
				return;
			}
			PlayAnimation("Body", SlideForwardStateHash, SlideForwardParamHash, slideDuration);
			if ((bool)slideEffectPrefab)
			{
				Transform parent = FindModelChild("Base");
				slideEffectInstance = UnityEngine.Object.Instantiate(slideEffectPrefab, parent);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				float num = (startedStateGrounded ? slideDuration : jumpDuration);
				if ((bool)base.inputBank && (bool)base.characterDirection)
				{
					base.characterDirection.moveVector = base.inputBank.moveVector;
					forwardDirection = base.characterDirection.forward;
				}
				if ((bool)base.characterMotor)
				{
					float num2 = 0f;
					num2 = ((!startedStateGrounded) ? jumpforwardSpeedCoefficientCurve.Evaluate(base.fixedAge / num) : forwardSpeedCoefficientCurve.Evaluate(base.fixedAge / num));
					base.characterMotor.rootMotion += num2 * moveSpeedStat * forwardDirection * GetDeltaTime();
				}
				if (base.fixedAge >= num)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			PlayImpactAnimation();
			if ((bool)slideEffectInstance)
			{
				EntityState.Destroy(slideEffectInstance);
			}
			base.OnExit();
		}

		private void PlayImpactAnimation()
		{
			Animator modelAnimator = GetModelAnimator();
			int layerIndex = modelAnimator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				modelAnimator.SetLayerWeight(layerIndex, 1f);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.Commando.CommandoWeapon
{
	public class CastSmokescreen : BaseState
	{
		public static float baseDuration;

		public static float stealthDuration = 3f;

		public static string jumpSoundString;

		public static string startCloakSoundString;

		public static string stopCloakSoundString;

		public static GameObject initialEffectPrefab;

		public static GameObject smokescreenEffectPrefab;

		public static float damageCoefficient = 1.3f;

		public static float radius = 4f;

		public static float forceMagnitude = 100f;

		private float duration;

		private float totalDuration;

		private bool hasCastSmoke;

		private Animator animator;

		private void CastSmoke()
		{
			if (!hasCastSmoke)
			{
				Util.PlaySound(startCloakSoundString, base.gameObject);
			}
			else
			{
				Util.PlaySound(stopCloakSoundString, base.gameObject);
			}
			EffectManager.SpawnEffect(smokescreenEffectPrefab, new EffectData
			{
				origin = base.transform.position
			}, transmit: false);
			int layerIndex = animator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, 2f);
				animator.PlayInFixedTime("LightImpact", layerIndex, 0f);
			}
			if (NetworkServer.active)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.gameObject;
				blastAttack.inflictor = base.gameObject;
				blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				blastAttack.baseDamage = damageStat * damageCoefficient;
				blastAttack.baseForce = forceMagnitude;
				blastAttack.position = base.transform.position;
				blastAttack.radius = radius;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.damageType = DamageType.Stun1s;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.Fire();
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			totalDuration = stealthDuration + totalDuration;
			PlayCrossfade("Gesture, Smokescreen", "CastSmokescreen", "CastSmokescreen.playbackRate", duration, 0.2f);
			animator = GetModelAnimator();
			Util.PlaySound(jumpSoundString, base.gameObject);
			EffectManager.SpawnEffect(initialEffectPrefab, new EffectData
			{
				origin = base.transform.position
			}, transmit: true);
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed.buffIndex);
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterBody && NetworkServer.active)
			{
				if (base.characterBody.HasBuff(RoR2Content.Buffs.Cloak))
				{
					base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak);
				}
				if (base.characterBody.HasBuff(RoR2Content.Buffs.CloakSpeed))
				{
					base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed);
				}
			}
			if (!outer.destroying)
			{
				CastSmoke();
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && !hasCastSmoke)
			{
				CastSmoke();
				if ((bool)base.characterBody && NetworkServer.active)
				{
					base.characterBody.AddBuff(RoR2Content.Buffs.Cloak.buffIndex);
				}
				hasCastSmoke = true;
			}
			if (base.fixedAge >= totalDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!hasCastSmoke)
			{
				return InterruptPriority.PrioritySkill;
			}
			return InterruptPriority.Any;
		}
	}
	public class CastSmokescreenNoDelay : BaseState
	{
		public static float duration;

		public static float minimumStateDuration = 3f;

		public static string startCloakSoundString;

		public static string stopCloakSoundString;

		public static GameObject smokescreenEffectPrefab;

		public static Material destealthMaterial;

		public static float damageCoefficient = 1.3f;

		public static float radius = 4f;

		public static float forceMagnitude = 100f;

		private float stopwatch;

		private bool hasCastSmoke;

		private Animator animator;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			CastSmoke();
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.Cloak);
				base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed);
			}
		}

		public override void OnExit()
		{
			if ((bool)base.characterBody && NetworkServer.active)
			{
				if (base.characterBody.HasBuff(RoR2Content.Buffs.Cloak))
				{
					base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak);
				}
				if (base.characterBody.HasBuff(RoR2Content.Buffs.CloakSpeed))
				{
					base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed);
				}
			}
			if (!outer.destroying)
			{
				CastSmoke();
			}
			if ((bool)destealthMaterial)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject);
				temporaryOverlayInstance.duration = 1f;
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = destealthMaterial;
				temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent<CharacterModel>();
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.animateShaderAlpha = true;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void CastSmoke()
		{
			if (!hasCastSmoke)
			{
				Util.PlaySound(startCloakSoundString, base.gameObject);
				hasCastSmoke = true;
			}
			else
			{
				Util.PlaySound(stopCloakSoundString, base.gameObject);
			}
			EffectManager.SpawnEffect(smokescreenEffectPrefab, new EffectData
			{
				origin = base.transform.position
			}, transmit: false);
			int layerIndex = animator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, 1f);
				animator.PlayInFixedTime("LightImpact", layerIndex, 0f);
			}
			if (NetworkServer.active)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.gameObject;
				blastAttack.inflictor = base.gameObject;
				blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
				blastAttack.baseDamage = damageStat * damageCoefficient;
				blastAttack.baseForce = forceMagnitude;
				blastAttack.position = base.transform.position;
				blastAttack.radius = radius;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.damageType = DamageType.Stun1s;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.Fire();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(stopwatch > minimumStateDuration))
			{
				return InterruptPriority.PrioritySkill;
			}
			return InterruptPriority.Any;
		}
	}
	public class FireBarrage : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static float baseDurationBetweenShots = 1f;

		public static float totalDuration = 2f;

		public static float bulletRadius = 1.5f;

		public static int baseBulletCount = 1;

		public static string fireBarrageSoundString;

		public static float recoilAmplitude;

		public static float spreadBloomValue;

		private int totalBulletsFired;

		private int bulletCount;

		public float stopwatchBetweenShots;

		private Animator modelAnimator;

		private Transform modelTransform;

		private float duration;

		private float durationBetweenShots;

		private static int FireBarrageStateHash = Animator.StringToHash("FireBarrage");

		private static int FireBarrageParamHash = Animator.StringToHash("FireBarrage.playbackRate");

		private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right");

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterBody.SetSpreadBloom(0.2f, canOnlyIncreaseBloom: false);
			duration = totalDuration;
			durationBetweenShots = baseDurationBetweenShots / attackSpeedStat;
			bulletCount = (int)((float)baseBulletCount * attackSpeedStat);
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			PlayCrossfade("Gesture, Additive", FireBarrageStateHash, FireBarrageParamHash, duration, 0.2f);
			PlayCrossfade("Gesture, Override", FireBarrageStateHash, FireBarrageParamHash, duration, 0.2f);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
			FireBullet();
		}

		private void FireBullet()
		{
			Ray aimRay = GetAimRay();
			string muzzleName = "MuzzleRight";
			if ((bool)modelAnimator)
			{
				if ((bool)effectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
				}
				PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash);
			}
			AddRecoil(-0.8f * recoilAmplitude, -1f * recoilAmplitude, -0.1f * recoilAmplitude, 0.15f * recoilAmplitude);
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = 1u;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.radius = bulletRadius;
				bulletAttack.smartCollision = true;
				bulletAttack.damageType = DamageType.Stun1s;
				bulletAttack.Fire();
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
			totalBulletsFired++;
			Util.PlaySound(fireBarrageSoundString, base.gameObject);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatchBetweenShots += GetDeltaTime();
			if (stopwatchBetweenShots >= durationBetweenShots && totalBulletsFired < bulletCount)
			{
				stopwatchBetweenShots -= durationBetweenShots;
				FireBullet();
			}
			if (base.fixedAge >= duration && totalBulletsFired == bulletCount && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireFMJ : GenericProjectileBaseState
	{
		private static int FireFMJStateHash = Animator.StringToHash("FireFMJ");

		private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate");

		protected override void PlayAnimation(float duration)
		{
			base.PlayAnimation(duration);
			if ((bool)GetModelAnimator())
			{
				PlayAnimation("Gesture, Additive", FireFMJStateHash, FireFMJParamHash, duration);
				PlayAnimation("Gesture, Override", FireFMJStateHash, FireFMJParamHash, duration);
			}
		}

		protected override Ray ModifyProjectileAimRay(Ray aimRay)
		{
			TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, projectilePrefab, base.gameObject);
			return aimRay;
		}
	}
	public class FireLightsOut : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public static string attackSoundString;

		public static float recoilAmplitude;

		private ChildLocator childLocator;

		public int bulletCountCurrent = 1;

		private float duration;

		private static int FireRevolverStateHash = Animator.StringToHash("FireRevolver");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			AddRecoil(-3f * recoilAmplitude, -4f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude);
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			string muzzleName = "MuzzlePistol";
			Util.PlaySound(attackSoundString, base.gameObject);
			PlayAnimation("Gesture, Additive", FireRevolverStateHash);
			PlayAnimation("Gesture, Override", FireRevolverStateHash);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack obj = new BulletAttack
				{
					owner = base.gameObject,
					weapon = base.gameObject,
					origin = aimRay.origin,
					aimVector = aimRay.direction,
					minSpread = minSpread,
					maxSpread = maxSpread,
					bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u),
					damage = damageCoefficient * damageStat,
					force = force,
					falloffModel = BulletAttack.FalloffModel.None,
					tracerEffectPrefab = tracerEffectPrefab,
					muzzleName = muzzleName,
					hitEffectPrefab = hitEffectPrefab,
					isCrit = Util.CheckRoll(critStat, base.characterBody.master),
					HitEffectNormal = false,
					radius = 0.5f
				};
				obj.damageType |= (DamageTypeCombo)DamageType.ResetCooldownsOnKill;
				obj.smartCollision = true;
				obj.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public class FirePistol2 : BaseSkillState, SteppedSkillDef.IStepSetter
	{
		public static GameObject muzzleEffectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float baseDuration = 2f;

		public static string firePistolSoundString;

		public static float recoilAmplitude = 1f;

		public static float spreadBloomValue = 0.3f;

		public static float commandoBoostBuffCoefficient = 0.4f;

		public static float trajectoryAimAssistMultiplier = 0.75f;

		private int pistol;

		private Ray aimRay;

		private float duration;

		private static int FirePistolLeftStateHash = Animator.StringToHash("FirePistol, Left");

		private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right");

		void SteppedSkillDef.IStepSetter.SetStep(int i)
		{
			pistol = i;
		}

		private void FireBullet(string targetMuzzle)
		{
			Util.PlaySound(firePistolSoundString, base.gameObject);
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude);
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = base.characterBody.spreadBloomAngle;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = targetMuzzle;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.radius = 0.1f;
				bulletAttack.smartCollision = true;
				bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier;
				bulletAttack.Fire();
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			aimRay = GetAimRay();
			StartAimMode(aimRay, 3f);
			if (pistol % 2 == 0)
			{
				PlayAnimation("Gesture Additive, Left", FirePistolLeftStateHash);
				FireBullet("MuzzleLeft");
			}
			else
			{
				PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash);
				FireBullet("MuzzleRight");
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				if (base.activatorSkillSlot.stock <= 0)
				{
					outer.SetNextState(new ReloadPistols());
				}
				else
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireRocket : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float baseDuration = 2f;

		private float duration;

		public int bulletCountCurrent = 1;

		private static int FireFMJStateHash = Animator.StringToHash("FireFMJ");

		private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			string muzzleName = "MuzzleCenter";
			PlayAnimation("Gesture", FireFMJStateHash, FireFMJParamHash, duration);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireShotgun : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float force;

		public static int bulletCount;

		public static float baseMaxDuration = 2f;

		public static float baseMinDuration = 0.5f;

		public static string attackSoundString;

		public static float recoilAmplitude;

		public static float spreadBloomValue = 0.3f;

		private float maxDuration;

		private float minDuration;

		private static int FireShotgunStateHash = Animator.StringToHash("FireShotgun");

		private static int FireShotgunParamHash = Animator.StringToHash("FireShotgun.playbackRate");

		private bool buttonReleased;

		public override void OnEnter()
		{
			base.OnEnter();
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude);
			maxDuration = baseMaxDuration / attackSpeedStat;
			minDuration = baseMinDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			Util.PlaySound(attackSoundString, base.gameObject);
			PlayAnimation("Gesture, Additive", FireShotgunStateHash, FireShotgunParamHash, maxDuration * 1.1f);
			PlayAnimation("Gesture, Override", FireShotgunStateHash, FireShotgunParamHash, maxDuration * 1.1f);
			string muzzleName = "MuzzleShotgun";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = base.characterBody.spreadBloomAngle;
				bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u);
				bulletAttack.procCoefficient = 1f / (float)bulletCount;
				bulletAttack.damage = damageCoefficient * damageStat / (float)bulletCount;
				bulletAttack.force = force;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = 0f;
				bulletAttack.Fire();
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			buttonReleased |= !base.inputBank.skill1.down;
			if (base.fixedAge >= maxDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (buttonReleased && base.fixedAge >= minDuration)
			{
				return InterruptPriority.Any;
			}
			return InterruptPriority.Skill;
		}
	}
	public class FireShotgunBlast : GenericBulletBaseState
	{
		public static float delayBetweenShotgunBlasts;

		private bool hasFiredSecondBlast;

		private static int FirePistolLeftStateHash = Animator.StringToHash("FirePistol, Left");

		private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right");

		public override void OnEnter()
		{
			muzzleName = "MuzzleLeft";
			base.OnEnter();
			PlayAnimation("Gesture Additive, Left", FirePistolLeftStateHash);
			PlayAnimation("Gesture Override, Left", FirePistolLeftStateHash);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!hasFiredSecondBlast && delayBetweenShotgunBlasts / attackSpeedStat < base.fixedAge)
			{
				hasFiredSecondBlast = true;
				PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash);
				PlayAnimation("Gesture Override, Right", FirePistolRightStateHash);
				muzzleName = "MuzzleRight";
				FireBullet(GetAimRay());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireShrapnel : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject hitEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float damageCoefficient;

		public static float blastRadius;

		public static float force;

		public static float minSpread;

		public static float maxSpread;

		public static int bulletCount;

		public static float baseDuration = 2f;

		public static string attackSoundString;

		public static float maxDistance;

		private float duration;

		private Ray modifiedAimRay;

		private static int FireLaserStateHash = Animator.StringToHash("FireLaser");

		private static int FireLaserParamHash = Animator.StringToHash("FireLaser.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modifiedAimRay = GetAimRay();
			Util.PlaySound(attackSoundString, base.gameObject);
			string muzzleName = "MuzzleLaser";
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
			PlayAnimation("Gesture", FireLaserStateHash, FireLaserParamHash, duration);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				if (Physics.Raycast(modifiedAimRay, out var hitInfo, 1000f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault))
				{
					BlastAttack blastAttack = new BlastAttack();
					blastAttack.attacker = base.gameObject;
					blastAttack.inflictor = base.gameObject;
					blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
					blastAttack.baseDamage = damageStat * damageCoefficient;
					blastAttack.baseForce = force * 0.2f;
					blastAttack.position = hitInfo.point;
					blastAttack.radius = blastRadius;
					blastAttack.Fire();
				}
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = modifiedAimRay.origin;
				bulletAttack.aimVector = modifiedAimRay.direction;
				bulletAttack.radius = 0.25f;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = ((bulletCount > 0) ? ((uint)bulletCount) : 0u);
				bulletAttack.damage = 0f;
				bulletAttack.procCoefficient = 0f;
				bulletAttack.force = force;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
				bulletAttack.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireSweepBarrage : BaseState
	{
		public static string enterSound;

		public static string muzzle;

		public static string fireSoundString;

		public static GameObject muzzleEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float baseTotalDuration;

		public static float baseFiringDuration;

		public static float fieldOfView;

		public static float maxDistance;

		public static float damageCoefficient;

		public static float procCoefficient;

		public static float force;

		public static int minimumFireCount;

		public static GameObject impactEffectPrefab;

		private float totalDuration;

		private float firingDuration;

		private int totalBulletsToFire;

		private int totalBulletsFired;

		private int targetHurtboxIndex;

		private float timeBetweenBullets;

		private List<HurtBox> targetHurtboxes = new List<HurtBox>();

		private float fireTimer;

		private ChildLocator childLocator;

		private int muzzleIndex;

		private Transform muzzleTransform;

		private static int FireSweepBarrageStateHash = Animator.StringToHash("FireSweepBarrage");

		private static int FireSweepBarrageParamHash = Animator.StringToHash("FireSweepBarrage.playbackRate");

		private static int FirePistolRightStateHash = Animator.StringToHash("FirePistol, Right");

		public override void OnEnter()
		{
			base.OnEnter();
			totalDuration = baseTotalDuration / attackSpeedStat;
			firingDuration = baseFiringDuration / attackSpeedStat;
			base.characterBody.SetAimTimer(3f);
			PlayAnimation("Gesture, Additive", FireSweepBarrageStateHash, FireSweepBarrageParamHash, totalDuration);
			PlayAnimation("Gesture, Override", FireSweepBarrageStateHash, FireSweepBarrageParamHash, totalDuration);
			Util.PlaySound(enterSound, base.gameObject);
			Ray aimRay = GetAimRay();
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam());
			bullseyeSearch.maxAngleFilter = fieldOfView * 0.5f;
			bullseyeSearch.maxDistanceFilter = maxDistance;
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
			bullseyeSearch.filterByLoS = true;
			bullseyeSearch.RefreshCandidates();
			targetHurtboxes = bullseyeSearch.GetResults().Where(Util.IsValid).Distinct(default(HurtBox.EntityEqualityComparer))
				.ToList();
			totalBulletsToFire = Mathf.Max(targetHurtboxes.Count, minimumFireCount);
			timeBetweenBullets = firingDuration / (float)totalBulletsToFire;
			childLocator = GetModelTransform().GetComponent<ChildLocator>();
			muzzleIndex = childLocator.FindChildIndex(muzzle);
			muzzleTransform = childLocator.FindChild(muzzleIndex);
		}

		private void Fire()
		{
			if (totalBulletsFired >= totalBulletsToFire)
			{
				return;
			}
			if (!string.IsNullOrEmpty(muzzle))
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzle, transmit: false);
			}
			Util.PlaySound(fireSoundString, base.gameObject);
			PlayAnimation("Gesture Additive, Right", FirePistolRightStateHash);
			if (NetworkServer.active && targetHurtboxes.Count > 0)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = damageStat * damageCoefficient;
				damageInfo.attacker = base.gameObject;
				damageInfo.procCoefficient = procCoefficient;
				damageInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				if (targetHurtboxIndex >= targetHurtboxes.Count)
				{
					targetHurtboxIndex = 0;
				}
				HurtBox hurtBox = targetHurtboxes[targetHurtboxIndex];
				if ((bool)hurtBox)
				{
					HealthComponent healthComponent = hurtBox.healthComponent;
					if ((bool)healthComponent)
					{
						targetHurtboxIndex++;
						UnityEngine.Vector3 normalized = (hurtBox.transform.position - base.characterBody.corePosition).normalized;
						damageInfo.force = force * normalized;
						damageInfo.position = hurtBox.transform.position;
						EffectManager.SimpleImpactEffect(impactEffectPrefab, hurtBox.transform.position, normalized, transmit: true);
						healthComponent.TakeDamage(damageInfo);
						GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
					}
					if ((bool)tracerEffectPrefab && (bool)childLocator)
					{
						int childIndex = childLocator.FindChildIndex(muzzle);
						childLocator.FindChild(childIndex);
						EffectData effectData = new EffectData
						{
							origin = hurtBox.transform.position,
							start = muzzleTransform.position
						};
						effectData.SetChildLocatorTransformReference(base.gameObject, childIndex);
						EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
					}
				}
			}
			totalBulletsFired++;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			if (fireTimer <= 0f)
			{
				Fire();
				fireTimer += timeBetweenBullets;
			}
			if (base.fixedAge >= totalDuration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireThermite : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public static float damageCoefficient;

		public static float force;

		public static float selfForce;

		public static float baseDuration = 2f;

		private float duration;

		public int bulletCountCurrent = 1;

		private static int FireFMJStateHash = Animator.StringToHash("FireFMJ");

		private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			PlayAnimation("Gesture", FireFMJStateHash, FireFMJParamHash, duration);
			string muzzleName = "MuzzleCenter";
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
			if ((bool)base.characterMotor && !base.characterMotor.isGrounded)
			{
				UnityEngine.Vector3 vector = -aimRay.direction * selfForce;
				vector.y *= 0.5f;
				base.characterMotor.ApplyForce(vector, alwaysApply: true);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class PrepBarrage : BaseState
	{
		public static float baseDuration = 3f;

		public static string prepBarrageSoundString;

		private float duration;

		private Animator modelAnimator;

		private static int PrepBarrageStateHash = Animator.StringToHash("PrepBarrage");

		private static int PrepBarrageParamHash = Animator.StringToHash("PrepBarrage.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", PrepBarrageStateHash, PrepBarrageParamHash, duration);
			}
			Util.PlaySound(prepBarrageSoundString, base.gameObject);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireBarrage nextState = new FireBarrage();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class PrepLightsOut : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargePrefab;

		public static GameObject specialCrosshairPrefab;

		public static string prepSoundString;

		private GameObject chargeEffect;

		private float duration;

		private ChildLocator childLocator;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private EffectManagerHelper _emh_chargeEffect;

		private static int PrepRevolverStateHash = Animator.StringToHash("PrepRevolver");

		private static int PrepRevolverParamHash = Animator.StringToHash("PrepRevolver.playbackRate");

		public override void Reset()
		{
			base.Reset();
			chargeEffect = null;
			duration = 0f;
			childLocator = null;
			_emh_chargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Additive", PrepRevolverStateHash, PrepRevolverParamHash, duration);
			PlayAnimation("Gesture, Override", PrepRevolverStateHash, PrepRevolverParamHash, duration);
			Util.PlaySound(prepSoundString, base.gameObject);
			if ((bool)specialCrosshairPrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, specialCrosshairPrefab, CrosshairUtils.OverridePriority.Skill);
			}
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				if ((bool)childLocator)
				{
					Transform transform = childLocator.FindChild("MuzzlePistol");
					if ((bool)transform && (bool)chargePrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargePrefab))
						{
							chargeEffect = UnityEngine.Object.Instantiate(chargePrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(chargePrefab, transform.position, transform.rotation);
							chargeEffect = _emh_chargeEffect.gameObject;
						}
						chargeEffect.transform.parent = transform;
						ScaleParticleSystemDuration component = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component)
						{
							component.newDuration = duration;
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireLightsOut());
			}
		}

		public override void OnExit()
		{
			if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
			{
				_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
			}
			else
			{
				EntityState.Destroy(chargeEffect);
			}
			chargeEffect = null;
			_emh_chargeEffect = null;
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ReloadPistols : GenericReload
	{
		private static int ReloadPistolsStateHash = Animator.StringToHash("ReloadPistols");

		private static int ReloadPistolsParamHash = Animator.StringToHash("ReloadPistols.playbackRate");

		private static int ReloadPistolsExitStateHash = Animator.StringToHash("ReloadPistolsExit");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Gesture, Override", ReloadPistolsStateHash, ReloadPistolsParamHash, duration);
			PlayAnimation("Gesture, Additive", ReloadPistolsStateHash, ReloadPistolsParamHash, duration);
			FindModelChild("GunMeshL")?.gameObject.SetActive(value: false);
			FindModelChild("GunMeshR")?.gameObject.SetActive(value: false);
		}

		public override void OnExit()
		{
			FindModelChild("ReloadFXL")?.gameObject.SetActive(value: false);
			FindModelChild("ReloadFXR")?.gameObject.SetActive(value: false);
			FindModelChild("GunMeshL")?.gameObject.SetActive(value: true);
			FindModelChild("GunMeshR")?.gameObject.SetActive(value: true);
			PlayAnimation("Gesture, Override", ReloadPistolsExitStateHash);
			PlayAnimation("Gesture, Additive", ReloadPistolsExitStateHash);
			base.OnExit();
		}
	}
	public class ThrowGrenade : GenericProjectileBaseState
	{
		private static int ThrowGrenadeStateHash = Animator.StringToHash("ThrowGrenade");

		private static int FireFMJParamHash = Animator.StringToHash("FireFMJ.playbackRate");

		protected override void PlayAnimation(float duration)
		{
			if ((bool)GetModelAnimator())
			{
				PlayAnimation("Gesture, Additive", ThrowGrenadeStateHash, FireFMJParamHash, duration * 2f);
				PlayAnimation("Gesture, Override", ThrowGrenadeStateHash, FireFMJParamHash, duration * 2f);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class ThrowStickyGrenade : ThrowGrenade
	{
	}
}
namespace EntityStates.ClaymanMonster
{
	public class Leap : BaseState
	{
		public static string leapSoundString;

		public static float minimumDuration;

		public static float verticalJumpSpeed;

		public static float horizontalJumpSpeedCoefficient;

		private UnityEngine.Vector3 forwardDirection;

		private Animator animator;

		private float stopwatch;

		private bool playedImpact;

		private static int LeapcycleParamHash = Animator.StringToHash("Leap.cycle");

		private static int LightImpactStateHash = Animator.StringToHash("LightImpact");

		private static int IdleStateHash = Animator.StringToHash("Idle");

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			Util.PlaySound(leapSoundString, base.gameObject);
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity.y = verticalJumpSpeed;
			}
			forwardDirection = UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up);
			base.characterDirection.moveVector = forwardDirection;
			PlayCrossfade("Body", "LeapAirLoop", 0.15f);
		}

		public override void FixedUpdate()
		{
			stopwatch += GetDeltaTime();
			animator.SetFloat(LeapcycleParamHash, Mathf.Clamp01(Util.Remap(base.characterMotor.velocity.y, 0f - verticalJumpSpeed, verticalJumpSpeed, 1f, 0f)));
			UnityEngine.Vector3 velocity = forwardDirection * base.characterBody.moveSpeed * horizontalJumpSpeedCoefficient;
			velocity.y = base.characterMotor.velocity.y;
			base.characterMotor.velocity = velocity;
			base.FixedUpdate();
			if (base.characterMotor.isGrounded && stopwatch > minimumDuration && !playedImpact)
			{
				playedImpact = true;
				int layerIndex = animator.GetLayerIndex("Impact");
				if (layerIndex >= 0)
				{
					animator.SetLayerWeight(layerIndex, 1.5f);
					animator.PlayInFixedTime(LightImpactStateHash, layerIndex, 0f);
				}
				if (base.isAuthority)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			PlayAnimation("Body", IdleStateHash);
			base.OnExit();
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		public static string spawnEffectChildString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild(spawnEffectChildString);
				if ((bool)transform)
				{
					UnityEngine.Object.Instantiate(spawnEffectPrefab, transform.position, UnityEngine.Quaternion.identity);
				}
			}
			if (spawnSoundString.Length > 0)
			{
				Util.PlaySound(spawnSoundString, base.gameObject);
			}
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class SwipeForward : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float selfForceMagnitude;

		public static float radius = 3f;

		public static GameObject hitEffectPrefab;

		public static GameObject swingEffectPrefab;

		public static string attackString;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private bool hasSlashed;

		private static int SwipeForwardStateHash = Animator.StringToHash("SwipeForward");

		private static int SwipeForwardParamHash = Animator.StringToHash("SwipeForward.playbackRate");

		private static int SwipeForwardHitboxActiveParamHash = Animator.StringToHash("SwipeForward.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			Util.PlaySound(attackString, base.gameObject);
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Sword");
			}
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture, Override", SwipeForwardStateHash, SwipeForwardParamHash, duration);
				PlayAnimation("Gesture, Additive", SwipeForwardStateHash, SwipeForwardParamHash, duration);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat(SwipeForwardHitboxActiveParamHash) > 0.1f)
			{
				if (!hasSlashed)
				{
					EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true);
					HealthComponent healthComponent = base.characterBody.healthComponent;
					CharacterDirection component = base.characterBody.GetComponent<CharacterDirection>();
					if ((bool)healthComponent)
					{
						healthComponent.TakeDamageForce(selfForceMagnitude * component.forward, alwaysApply: true);
					}
					hasSlashed = true;
				}
				attack.forceVector = base.transform.forward * forceMagnitude;
				attack.Fire();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.ClayGrenadier
{
	public class FaceSlam : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float baseDurationBeforeBlast = 1.5f;

		public static string animationLayerName = "Body";

		public static string animationStateName = "FaceSlam";

		public static string playbackRateParam = "FaceSlam.playbackRate";

		private static int FaceSlamStateHash = Animator.StringToHash("FaceSlam");

		private static int FaceSlamParamHash = Animator.StringToHash("FaceSlam.playbackRate");

		public static GameObject chargeEffectPrefab;

		public static string chargeEffectMuzzleString;

		public static GameObject blastImpactEffect;

		public static float blastDamageCoefficient = 4f;

		public static float blastForceMagnitude = 16f;

		public static float blastUpwardForce;

		public static float blastRadius = 3f;

		public static string attackSoundString;

		public static string blastMuzzleString;

		public static GameObject projectilePrefab;

		public static float projectileDamageCoefficient;

		public static float projectileForce;

		public static float projectileSnapOnAngle;

		public static float healthCostFraction;

		private BlastAttack attack;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasFiredBlast;

		private float duration;

		private float durationBeforeBlast;

		private GameObject chargeInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			duration = baseDuration / attackSpeedStat;
			durationBeforeBlast = baseDurationBeforeBlast / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			PlayAnimation(animationLayerName, FaceSlamStateHash, FaceSlamParamHash, duration);
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
			Transform transform = FindModelChild(chargeEffectMuzzleString);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeInstance.transform.parent = transform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = durationBeforeBlast;
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > durationBeforeBlast && !hasFiredBlast)
			{
				hasFiredBlast = true;
				if ((bool)chargeInstance)
				{
					EntityState.Destroy(chargeInstance);
				}
				UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
				EffectManager.SpawnEffect(blastImpactEffect, new EffectData
				{
					origin = footPosition,
					scale = blastRadius
				}, transmit: true);
				if (NetworkServer.active && (bool)base.healthComponent)
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction;
					damageInfo.position = base.characterBody.corePosition;
					damageInfo.force = UnityEngine.Vector3.zero;
					damageInfo.damageColorIndex = DamageColorIndex.Default;
					damageInfo.crit = false;
					damageInfo.attacker = null;
					damageInfo.inflictor = null;
					damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor;
					damageInfo.procCoefficient = 0f;
					damageInfo.procChainMask = default(ProcChainMask);
					base.healthComponent.TakeDamage(damageInfo);
				}
				if (base.isAuthority)
				{
					if ((bool)modelTransform)
					{
						Transform transform = FindModelChild(blastMuzzleString);
						if ((bool)transform)
						{
							attack = new BlastAttack();
							attack.attacker = base.gameObject;
							attack.inflictor = base.gameObject;
							attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
							attack.baseDamage = damageStat * blastDamageCoefficient;
							attack.baseForce = blastForceMagnitude;
							attack.position = transform.position;
							attack.radius = blastRadius;
							attack.bonusForce = new UnityEngine.Vector3(0f, blastUpwardForce, 0f);
							attack.damageType = DamageType.ClayGoo;
							attack.Fire();
						}
					}
					UnityEngine.Vector3 position = footPosition;
					_ = UnityEngine.Vector3.up;
					if (Physics.Raycast(GetAimRay(), out var hitInfo, 1000f, LayerIndex.world.mask))
					{
						position = hitInfo.point;
					}
					BullseyeSearch bullseyeSearch = new BullseyeSearch();
					bullseyeSearch.viewer = base.characterBody;
					bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
					bullseyeSearch.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex);
					bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
					bullseyeSearch.minDistanceFilter = 0f;
					bullseyeSearch.maxDistanceFilter = 1000f;
					bullseyeSearch.searchOrigin = base.inputBank.aimOrigin;
					bullseyeSearch.searchDirection = base.inputBank.aimDirection;
					bullseyeSearch.maxAngleFilter = projectileSnapOnAngle;
					bullseyeSearch.filterByLoS = false;
					bullseyeSearch.RefreshCandidates();
					HurtBox hurtBox = bullseyeSearch.GetResults().FirstOrDefault();
					if ((bool)hurtBox && (bool)hurtBox.healthComponent)
					{
						position = hurtBox.healthComponent.body.footPosition;
					}
					ProjectileManager.instance.FireProjectile(projectilePrefab, position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * projectileDamageCoefficient, projectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master));
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class SpawnState : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string spawnSoundString;

		[SerializeField]
		public GameObject spawnEffectPrefab;

		[SerializeField]
		public string spawnEffectChildString;

		[SerializeField]
		public float startingPrintBias;

		[SerializeField]
		public float maxPrintBias;

		[SerializeField]
		public float printDuration;

		[SerializeField]
		public float startingPrintHeight = 0.3f;

		[SerializeField]
		public float maxPrintHeight = 0.3f;

		[SerializeField]
		public string animationLayerName = "Body";

		[SerializeField]
		public string animationStateName = "Spawn";

		[SerializeField]
		public string playbackRateParam = "Spawn.playbackRate";

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectChildString, transmit: false);
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation(animationLayerName, animationStateName, playbackRateParam, duration);
			PrintController printController = GetModelTransform().gameObject.AddComponent<PrintController>();
			printController.printTime = printDuration;
			printController.enabled = true;
			printController.startingPrintHeight = startingPrintHeight;
			printController.maxPrintHeight = maxPrintHeight;
			printController.startingPrintBias = startingPrintBias;
			printController.maxPrintBias = maxPrintBias;
			printController.disableWhenFinished = true;
			printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class ThrowBarrel : GenericProjectileBaseState
	{
		[SerializeField]
		public float aimCalculationRaycastDistance;

		[SerializeField]
		public string animationLayerName = "Body";

		[SerializeField]
		public string animationStateName = "FaceSlam";

		[SerializeField]
		public string playbackRateParam = "FaceSlam.playbackRate";

		[SerializeField]
		public int projectileCount;

		[SerializeField]
		public float projectilePitchBonusPerProjectile;

		[SerializeField]
		public float projectileYawBonusPerProjectile;

		[SerializeField]
		public GameObject chargeEffectPrefab;

		[SerializeField]
		public string chargeEffectMuzzleString;

		[SerializeField]
		public string enterSoundString;

		private GameObject chargeInstance;

		private int currentProjectileCount;

		protected override void PlayAnimation(float duration)
		{
			base.PlayAnimation(duration);
			PlayCrossfade(animationLayerName, animationStateName, playbackRateParam, duration, 0.2f);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			base.characterBody.SetAimTimer(0f);
			Transform transform = FindModelChild(chargeEffectMuzzleString);
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeInstance.transform.parent = transform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = delayBeforeFiringProjectile;
				}
			}
		}

		protected override Ray ModifyProjectileAimRay(Ray aimRay)
		{
			RaycastHit hitInfo = default(RaycastHit);
			Ray ray = aimRay;
			float desiredForwardSpeed = projectilePrefab.GetComponent<ProjectileSimple>().desiredForwardSpeed;
			ray.origin = aimRay.origin;
			if (Util.CharacterRaycast(base.gameObject, ray, out hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
			{
				float num = desiredForwardSpeed;
				UnityEngine.Vector3 vector = hitInfo.point - aimRay.origin;
				UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z);
				float magnitude = vector2.magnitude;
				float y = Trajectory.CalculateInitialYSpeed(magnitude / num, vector.y);
				UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude * num, y, vector2.y / magnitude * num);
				desiredForwardSpeed = vector3.magnitude;
				aimRay.direction = vector3 / desiredForwardSpeed;
			}
			aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, 0f, 1f, 1f, projectileYawBonusPerProjectile * (float)currentProjectileCount, projectilePitchBonusPerProjectile * (float)currentProjectileCount);
			return aimRay;
		}

		protected override void FireProjectile()
		{
			for (int i = 0; i < projectileCount; i++)
			{
				base.FireProjectile();
				currentProjectileCount++;
			}
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.ClayBruiser.Weapon
{
	public class MinigunState : BaseState
	{
		public static string muzzleName;

		private static readonly BuffDef slowBuff = RoR2Content.Buffs.Slow50;

		protected Transform muzzleTransform;

		protected ref InputBankTest.ButtonState skillButtonState => ref base.inputBank.skill1;

		public override void OnEnter()
		{
			base.OnEnter();
			muzzleTransform = FindModelChild(muzzleName);
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.AddBuff(slowBuff);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			StartAimMode();
		}

		public override void OnExit()
		{
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.RemoveBuff(slowBuff);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class MinigunSpinUp : MinigunState
	{
		public static float baseDuration;

		public static string sound;

		public static GameObject chargeEffectPrefab;

		private GameObject chargeInstance;

		private float duration;

		private static int WeaponIsReadyParamHash = Animator.StringToHash("WeaponIsReady");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(sound, base.gameObject);
			GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: true);
			if ((bool)muzzleTransform && (bool)chargeEffectPrefab)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, muzzleTransform.position, muzzleTransform.rotation);
				chargeInstance.transform.parent = muzzleTransform;
				ScaleParticleSystemDuration component = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = duration;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new MinigunFire());
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
		}
	}
	public class MinigunSpinDown : MinigunState
	{
		public static float baseDuration;

		public static string sound;

		private float duration;

		private static int WeaponIsReadyParamHash = Animator.StringToHash("WeaponIsReady");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(sound, base.gameObject, attackSpeedStat);
			GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class MinigunFire : MinigunState
	{
		public static GameObject muzzleVfxPrefab;

		public static float baseFireInterval;

		public static int baseBulletCount;

		public static float baseDamagePerSecondCoefficient;

		public static float baseForcePerSecond;

		public static float baseProcCoefficientPerSecond;

		public static float bulletMinSpread;

		public static float bulletMaxSpread;

		public static GameObject bulletTracerEffectPrefab;

		public static GameObject bulletHitEffectPrefab;

		public static bool bulletHitEffectNormal;

		public static float bulletMaxDistance;

		public static string fireSound;

		public static string startSound;

		public static string endSound;

		private float fireTimer;

		private Transform muzzleVfxTransform;

		private float baseFireRate;

		private float baseBulletsPerSecond;

		private Run.FixedTimeStamp critEndTime;

		private Run.FixedTimeStamp lastCritCheck;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)muzzleTransform && (bool)muzzleVfxPrefab)
			{
				muzzleVfxTransform = UnityEngine.Object.Instantiate(muzzleVfxPrefab, muzzleTransform).transform;
			}
			baseFireRate = 1f / baseFireInterval;
			baseBulletsPerSecond = (float)baseBulletCount * baseFireRate;
			critEndTime = Run.FixedTimeStamp.negativeInfinity;
			lastCritCheck = Run.FixedTimeStamp.negativeInfinity;
			Util.PlaySound(startSound, base.gameObject);
			PlayCrossfade("Gesture, Additive", "FireMinigun", 0.2f);
		}

		private void UpdateCrits()
		{
			if (lastCritCheck.timeSince >= 1f)
			{
				lastCritCheck = Run.FixedTimeStamp.now;
				if (RollCrit())
				{
					critEndTime = Run.FixedTimeStamp.now + 2f;
				}
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(endSound, base.gameObject);
			if ((bool)muzzleVfxTransform)
			{
				EntityState.Destroy(muzzleVfxTransform.gameObject);
				muzzleVfxTransform = null;
			}
			PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.2f);
			base.OnExit();
		}

		private void OnFireShared()
		{
			Util.PlaySound(fireSound, base.gameObject);
			if (base.isAuthority)
			{
				OnFireAuthority();
			}
		}

		private void OnFireAuthority()
		{
			UpdateCrits();
			bool isCrit = !critEndTime.hasPassed;
			float damage = baseDamagePerSecondCoefficient / baseBulletsPerSecond * damageStat;
			float force = baseForcePerSecond / baseBulletsPerSecond;
			float procCoefficient = baseProcCoefficientPerSecond / baseBulletsPerSecond;
			Ray aimRay = GetAimRay();
			BulletAttack bulletAttack = new BulletAttack();
			bulletAttack.bulletCount = (uint)baseBulletCount;
			bulletAttack.aimVector = aimRay.direction;
			bulletAttack.origin = aimRay.origin;
			bulletAttack.damage = damage;
			bulletAttack.damageColorIndex = DamageColorIndex.Default;
			bulletAttack.damageType = DamageType.Generic;
			bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
			bulletAttack.maxDistance = bulletMaxDistance;
			bulletAttack.force = force;
			bulletAttack.hitMask = LayerIndex.CommonMasks.bullet;
			bulletAttack.minSpread = bulletMinSpread;
			bulletAttack.maxSpread = bulletMaxSpread;
			bulletAttack.isCrit = isCrit;
			bulletAttack.owner = base.gameObject;
			bulletAttack.muzzleName = MinigunState.muzzleName;
			bulletAttack.smartCollision = false;
			bulletAttack.procChainMask = default(ProcChainMask);
			bulletAttack.procCoefficient = procCoefficient;
			bulletAttack.radius = 0f;
			bulletAttack.sniper = false;
			bulletAttack.stopperMask = LayerIndex.CommonMasks.bullet;
			bulletAttack.weapon = null;
			bulletAttack.tracerEffectPrefab = bulletTracerEffectPrefab;
			bulletAttack.spreadPitchScale = 1f;
			bulletAttack.spreadYawScale = 1f;
			bulletAttack.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			bulletAttack.hitEffectPrefab = bulletHitEffectPrefab;
			bulletAttack.HitEffectNormal = bulletHitEffectNormal;
			bulletAttack.Fire();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			if (fireTimer <= 0f)
			{
				float num = baseFireInterval / attackSpeedStat;
				fireTimer += num;
				OnFireShared();
			}
			if (base.isAuthority && !base.skillButtonState.down)
			{
				outer.SetNextState(new MinigunSpinDown());
			}
		}
	}
	public class FireSonicBoom : EntityStates.Treebot.Weapon.FireSonicBoom
	{
		private static int WeaponIsReadyParamHash = Animator.StringToHash("WeaponIsReady");

		public override void OnEnter()
		{
			base.OnEnter();
			GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: true);
		}

		protected override void AddDebuff(CharacterBody body)
		{
			body.AddTimedBuff(RoR2Content.Buffs.ClayGoo, slowDuration);
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				GetModelAnimator().SetBool(WeaponIsReadyParamHash, value: false);
			}
			base.OnExit();
		}
	}
}
namespace EntityStates.ClayBruiserMonster
{
	public class SpawnState : BaseState
	{
		public static float duration;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		public static string spawnEffectChildString;

		public static float startingPrintBias;

		public static float maxPrintBias;

		public static float printDuration;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectChildString, transmit: false);
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			PrintController printController = GetModelTransform().gameObject.AddComponent<PrintController>();
			printController.printTime = printDuration;
			printController.enabled = true;
			printController.startingPrintHeight = 0.3f;
			printController.maxPrintHeight = 0.3f;
			printController.startingPrintBias = startingPrintBias;
			printController.maxPrintBias = maxPrintBias;
			printController.disableWhenFinished = true;
			printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.ClayBoss
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialEffect;

		public static GameObject deathEffect;

		public static float duration = 2f;

		private float stopwatch;

		private Transform modelBaseTransform;

		private Transform centerTransform;

		private EffectData _effectData;

		private EffectManagerHelper _emh_initialEffect;

		private bool attemptedDeathBehavior;

		public override void Reset()
		{
			base.Reset();
			stopwatch = 0f;
			modelBaseTransform = null;
			centerTransform = null;
			attemptedDeathBehavior = false;
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			_emh_initialEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.modelLocator)
			{
				return;
			}
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				centerTransform = component.FindChild("Center");
				if ((bool)initialEffect)
				{
					if (!EffectManager.ShouldUsePooledEffect(initialEffect))
					{
						GameObject obj = UnityEngine.Object.Instantiate(initialEffect, centerTransform.position, centerTransform.rotation);
						obj.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
						obj.transform.parent = centerTransform;
					}
					else
					{
						_emh_initialEffect = EffectManager.GetAndActivatePooledEffect(initialEffect, centerTransform.position, centerTransform.rotation, centerTransform);
						_emh_initialEffect.gameObject.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
					}
				}
			}
			modelBaseTransform = base.modelLocator.modelBaseTransform;
		}

		private void AttemptDeathBehavior()
		{
			if (attemptedDeathBehavior)
			{
				return;
			}
			attemptedDeathBehavior = true;
			CleanupInitialEffect();
			if ((bool)deathEffect && NetworkServer.active)
			{
				if (_effectData == null)
				{
					_effectData = new EffectData();
				}
				_effectData.origin = centerTransform.position;
				EffectManager.SpawnEffect(deathEffect, _effectData, transmit: true);
			}
			if ((bool)modelBaseTransform)
			{
				EntityState.Destroy(modelBaseTransform.gameObject);
				modelBaseTransform = null;
			}
			if (NetworkServer.active)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration)
			{
				AttemptDeathBehavior();
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				AttemptDeathBehavior();
			}
			else
			{
				CleanupInitialEffect();
			}
			base.OnExit();
		}

		public void CleanupInitialEffect()
		{
			if (_emh_initialEffect != null && _emh_initialEffect.OwningPool != null)
			{
				_emh_initialEffect.OwningPool.ReturnObject(_emh_initialEffect);
				_emh_initialEffect = null;
			}
		}
	}
	public class FireTarball : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public static int tarballCountMax = 3;

		public static float damageCoefficient;

		public static float baseTimeBetweenShots = 1f;

		public static float cooldownDuration = 2f;

		public static float recoilAmplitude = 1f;

		public static string attackSoundString;

		public static float spreadBloomValue = 0.3f;

		private int tarballCount;

		private Ray aimRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private float timeBetweenShots;

		private void FireSingleTarball(string targetMuzzle)
		{
			PlayCrossfade("Body", "FireTarBall", 0.1f);
			Util.PlaySound(attackSoundString, base.gameObject);
			aimRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						aimRay.origin = transform.position;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: true);
			}
			if (base.isAuthority)
			{
				UnityEngine.Vector3 forward = UnityEngine.Vector3.ProjectOnPlane(aimRay.direction, UnityEngine.Vector3.up);
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			timeBetweenShots = baseTimeBetweenShots / attackSpeedStat;
			duration = (baseTimeBetweenShots * (float)tarballCountMax + cooldownDuration) / attackSpeedStat;
			modelTransform = GetModelTransform();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			fireTimer -= GetDeltaTime();
			if (fireTimer <= 0f)
			{
				if (tarballCount < tarballCountMax)
				{
					fireTimer += timeBetweenShots;
					FireSingleTarball("BottomMuzzle");
					tarballCount++;
				}
				else
				{
					fireTimer += 9999f;
					PlayCrossfade("Body", "ExitTarBall", "ExitTarBall.playbackRate", (cooldownDuration - baseTimeBetweenShots) / attackSpeedStat, 0.1f);
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class PrepTarBall : BaseState
	{
		public static float baseDuration = 3f;

		public static string prepTarBallSoundString;

		private float duration;

		private float stopwatch;

		private Animator modelAnimator;

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayCrossfade("Body", "PrepTarBall", "PrepTarBall.playbackRate", duration, 0.5f);
			}
			if (!string.IsNullOrEmpty(prepTarBallSoundString))
			{
				Util.PlayAttackSpeedSound(prepTarBallSoundString, base.gameObject, attackSpeedStat);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireTarball());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Recover : BaseState
	{
		private enum SubState
		{
			Entry,
			Tethers
		}

		public static float duration = 15f;

		public static float maxTetherDistance = 40f;

		public static float tetherMulchDistance = 5f;

		public static float tetherMulchDamageScale = 2f;

		public static float tetherMulchTickIntervalScale = 0.5f;

		public static float damagePerSecond = 2f;

		public static float damageTickFrequency = 3f;

		public static float entryDuration = 1f;

		public static GameObject mulchEffectPrefab;

		public static string enterSoundString;

		public static string beginMulchSoundString;

		public static string stopMulchSoundString;

		private GameObject mulchEffect;

		private Transform muzzleTransform;

		private List<TarTetherController> tetherControllers;

		private List<GameObject> victimsList;

		private BullseyeSearch search;

		private float stopwatch;

		private uint soundID;

		private EffectManagerHelper _emh_mulchEffect;

		private SubState subState;

		private static int ChannelSiphonStateHash = Animator.StringToHash("ChannelSiphon");

		public override void Reset()
		{
			base.Reset();
			mulchEffect = null;
			muzzleTransform = null;
			if (tetherControllers != null)
			{
				tetherControllers.Clear();
			}
			if (victimsList != null)
			{
				victimsList.Clear();
			}
			if (search != null)
			{
				search.Reset();
			}
			soundID = 0u;
			subState = SubState.Entry;
			_emh_mulchEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost);
			}
			if ((bool)base.modelLocator)
			{
				ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					muzzleTransform = component.FindChild("MuzzleMulch");
				}
			}
			subState = SubState.Entry;
			PlayCrossfade("Body", "PrepSiphon", "PrepSiphon.playbackRate", entryDuration, 0.1f);
			soundID = Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
		}

		private void FireTethers()
		{
			UnityEngine.Vector3 position = muzzleTransform.position;
			float breakDistanceSqr = maxTetherDistance * maxTetherDistance;
			if (victimsList == null)
			{
				victimsList = new List<GameObject>();
			}
			tetherControllers = new List<TarTetherController>();
			if (search == null)
			{
				search = new BullseyeSearch();
			}
			search.searchOrigin = position;
			search.maxDistanceFilter = maxTetherDistance;
			search.teamMaskFilter = TeamMask.allButNeutral;
			search.sortMode = BullseyeSearch.SortMode.Distance;
			search.filterByLoS = true;
			search.searchDirection = UnityEngine.Vector3.up;
			search.RefreshCandidates();
			search.FilterOutGameObject(base.gameObject);
			List<HurtBox> list = search.GetResults().ToList();
			for (int i = 0; i < list.Count; i++)
			{
				GameObject gameObject = list[i].healthComponent.gameObject;
				if ((bool)gameObject)
				{
					victimsList.Add(gameObject);
				}
			}
			float tickInterval = 1f / damageTickFrequency;
			float damageCoefficientPerTick = damagePerSecond / damageTickFrequency;
			float mulchDistanceSqr = tetherMulchDistance * tetherMulchDistance;
			GameObject original = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/TarTether");
			for (int j = 0; j < victimsList.Count; j++)
			{
				GameObject obj = UnityEngine.Object.Instantiate(original, position, UnityEngine.Quaternion.identity);
				TarTetherController component = obj.GetComponent<TarTetherController>();
				component.NetworkownerRoot = base.gameObject;
				component.NetworktargetRoot = victimsList[j];
				component.breakDistanceSqr = breakDistanceSqr;
				component.damageCoefficientPerTick = damageCoefficientPerTick;
				component.tickInterval = tickInterval;
				component.tickTimer = (float)j * 0.1f;
				component.mulchDistanceSqr = mulchDistanceSqr;
				component.mulchDamageScale = tetherMulchDamageScale;
				component.mulchTickIntervalScale = tetherMulchTickIntervalScale;
				tetherControllers.Add(component);
				NetworkServer.Spawn(obj);
			}
		}

		private void DestroyTethers()
		{
			if (tetherControllers == null)
			{
				return;
			}
			for (int num = tetherControllers.Count - 1; num >= 0; num--)
			{
				if ((bool)tetherControllers[num])
				{
					EntityState.Destroy(tetherControllers[num].gameObject);
				}
			}
		}

		public override void OnExit()
		{
			DestroyTethers();
			if ((bool)mulchEffect)
			{
				if ((bool)_emh_mulchEffect && _emh_mulchEffect.OwningPool != null)
				{
					_emh_mulchEffect.ReturnToPool();
					_emh_mulchEffect = null;
				}
				else
				{
					EntityState.Destroy(mulchEffect);
				}
			}
			AkSoundEngine.StopPlayingID(soundID);
			Util.PlaySound(stopMulchSoundString, base.gameObject);
			if (NetworkServer.active && (bool)base.characterBody)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost);
			}
			base.OnExit();
		}

		private static void RemoveDeadTethersFromList(List<TarTetherController> tethersList)
		{
			for (int num = tethersList.Count - 1; num >= 0; num--)
			{
				if (!tethersList[num])
				{
					tethersList.RemoveAt(num);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (subState == SubState.Entry)
			{
				if (stopwatch >= entryDuration)
				{
					subState = SubState.Tethers;
					stopwatch = 0f;
					PlayAnimation("Body", ChannelSiphonStateHash);
					Util.PlaySound(beginMulchSoundString, base.gameObject);
					SpawnMulcherEffect();
					if (NetworkServer.active)
					{
						FireTethers();
					}
				}
			}
			else if (subState == SubState.Tethers && NetworkServer.active)
			{
				RemoveDeadTethersFromList(tetherControllers);
				if ((stopwatch >= duration || tetherControllers.Count == 0) && base.isAuthority)
				{
					outer.SetNextState(new RecoverExit());
				}
			}
		}

		private void SpawnMulcherEffect()
		{
			if (!EffectManager.ShouldUsePooledEffect(mulchEffectPrefab))
			{
				mulchEffect = UnityEngine.Object.Instantiate(mulchEffectPrefab, muzzleTransform.position, UnityEngine.Quaternion.identity);
			}
			else
			{
				_emh_mulchEffect = EffectManager.GetAndActivatePooledEffect(mulchEffectPrefab, muzzleTransform.position, UnityEngine.Quaternion.identity);
				mulchEffect = _emh_mulchEffect.gameObject;
			}
			ChildLocator component = mulchEffect.gameObject.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("AreaIndicator");
				if ((bool)transform)
				{
					transform.localScale = new UnityEngine.Vector3(maxTetherDistance * 2f, maxTetherDistance * 2f, maxTetherDistance * 2f);
				}
			}
			mulchEffect.transform.parent = muzzleTransform;
		}
	}
	public class RecoverExit : BaseState
	{
		public static float exitDuration = 1f;

		private float stopwatch;

		private static int ExitSiphonStateHash = Animator.StringToHash("ExitSiphon");

		private static int ExitSiphonParamHash = Animator.StringToHash("ExitSiphon.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			PlayAnimation("Body", ExitSiphonStateHash, ExitSiphonParamHash, exitDuration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= exitDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		public static string spawnEffectChildString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			ChildLocator component = GetModelTransform().GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild(spawnEffectChildString);
				if ((bool)transform)
				{
					UnityEngine.Object.Instantiate(spawnEffectPrefab, transform.position, UnityEngine.Quaternion.identity);
				}
			}
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.ClayBoss.ClayBossWeapon
{
	public class ChargeBombardment : BaseState
	{
		public static float baseTotalDuration;

		public static float baseMaxChargeTime;

		public static int maxCharges;

		public static GameObject chargeEffectPrefab;

		public static string chargeLoopStartSoundString;

		public static string chargeLoopStopSoundString;

		public static int minGrenadeCount;

		public static int maxGrenadeCount;

		public static float minBonusBloom;

		public static float maxBonusBloom;

		private float stopwatch;

		private GameObject chargeInstance;

		private int charge;

		private float totalDuration;

		private float maxChargeTime;

		private EffectManagerHelper _emh_chargeInstance;

		private static int ChargeBombardmentStateHash = Animator.StringToHash("ChargeBombardment");

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		public override void Reset()
		{
			base.Reset();
			stopwatch = 0f;
			chargeInstance = null;
			charge = 0;
			totalDuration = 0f;
			maxChargeTime = 0f;
			_emh_chargeInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			totalDuration = baseTotalDuration / attackSpeedStat;
			maxChargeTime = baseMaxChargeTime / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayAnimation("Gesture, Additive", ChargeBombardmentStateHash);
			Util.PlaySound(chargeLoopStartSoundString, base.gameObject);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild("Muzzle");
					if ((bool)transform && (bool)chargeEffectPrefab)
					{
						if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
						{
							chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
							chargeInstance = _emh_chargeInstance.gameObject;
						}
						chargeInstance.transform.parent = transform;
						ScaleParticleSystemDuration component2 = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = totalDuration;
						}
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(totalDuration);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			PlayAnimation("Gesture, Additive", EmptyStateHash);
			Util.PlaySound(chargeLoopStopSoundString, base.gameObject);
			if (_emh_chargeInstance != null && _emh_chargeInstance.OwningPool != null)
			{
				_emh_chargeInstance.OwningPool.ReturnObject(_emh_chargeInstance);
			}
			else
			{
				EntityState.Destroy(chargeInstance);
			}
			_emh_chargeInstance = null;
			chargeInstance = null;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			charge = Mathf.Min((int)(stopwatch / maxChargeTime * (float)maxCharges), maxCharges);
			float t = (float)charge / (float)maxCharges;
			float value = Mathf.Lerp(minBonusBloom, maxBonusBloom, t);
			base.characterBody.SetSpreadBloom(value);
			int grenadeCountMax = Mathf.FloorToInt(Mathf.Lerp(minGrenadeCount, maxGrenadeCount, t));
			if ((stopwatch >= totalDuration || !base.inputBank || !base.inputBank.skill1.down) && base.isAuthority)
			{
				FireBombardment fireBombardment = new FireBombardment();
				fireBombardment.grenadeCountMax = grenadeCountMax;
				outer.SetNextState(fireBombardment);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireBombardment : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public int grenadeCountMax = 3;

		public static float damageCoefficient;

		public static float baseTimeBetweenShots = 1f;

		public static float cooldownDuration = 2f;

		public static float arcAngle = 5f;

		public static float recoilAmplitude = 1f;

		public static string shootSoundString;

		public static float spreadBloomValue = 0.3f;

		private Ray aimRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		private float timeBetweenShots;

		private void FireGrenade(string targetMuzzle)
		{
			PlayCrossfade("Gesture, Bombardment", "FireBombardment", 0.1f);
			Util.PlaySound(shootSoundString, base.gameObject);
			aimRay = GetAimRay();
			UnityEngine.Vector3 vector = aimRay.origin;
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						vector = transform.position;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: true);
			}
			if (base.isAuthority)
			{
				float num = -1f;
				if (Util.CharacterRaycast(base.gameObject, aimRay, out var hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
				{
					UnityEngine.Vector3 point = hitInfo.point;
					float velocity = projectilePrefab.GetComponent<ProjectileSimple>().velocity;
					UnityEngine.Vector3 vector2 = point - vector;
					UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(vector2.x, vector2.z);
					float magnitude = vector3.magnitude;
					float y = Trajectory.CalculateInitialYSpeed(magnitude / velocity, vector2.y);
					UnityEngine.Vector3 vector4 = new UnityEngine.Vector3(vector3.x / magnitude * velocity, y, vector3.y / magnitude * velocity);
					num = vector4.magnitude;
					aimRay.direction = vector4 / num;
				}
				float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimRay.direction);
				UnityEngine.Vector3 vector5 = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y2 = vector5.y;
				vector5.y = 0f;
				float angle = Mathf.Atan2(vector5.z, vector5.x) * 57.29578f - 90f;
				float angle2 = Mathf.Atan2(y2, vector5.magnitude) * 57.29578f;
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimRay.direction);
				ProjectileManager.instance.FireProjectile(projectilePrefab, vector, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, num);
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			timeBetweenShots = baseTimeBetweenShots / attackSpeedStat;
			duration = (baseTimeBetweenShots * (float)grenadeCount + cooldownDuration) / attackSpeedStat;
			PlayCrossfade("Gesture, Additive", "BeginBombardment", 0.1f);
			modelTransform = GetModelTransform();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void OnExit()
		{
			PlayCrossfade("Gesture, Additive", "EndBombardment", 0.1f);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				fireTimer -= GetDeltaTime();
				if (fireTimer <= 0f && grenadeCount < grenadeCountMax)
				{
					fireTimer += timeBetweenShots;
					FireGrenade("Muzzle");
					grenadeCount++;
				}
				if (base.fixedAge >= duration && base.isAuthority)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.ChildMonster
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathEffectPrefab;

		public float smallHopVelocity = 0.35f;

		private bool blewUp;

		public float duration = 0.2f;

		public static string deathSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			SmallHop(base.characterMotor, smallHopVelocity);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && !blewUp && base.fixedAge > duration)
			{
				EffectManager.SpawnEffect(deathEffectPrefab, new EffectData
				{
					origin = base.characterBody.corePosition
				}, transmit: true);
				Util.PlaySound(deathSoundString, base.gameObject);
				blewUp = true;
			}
			if (base.fixedAge > duration * 2f)
			{
				DestroyBodyAsapServer();
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class Frolic : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static GameObject tpEffectPrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string attackString;

		public static float tpDuration = 0.5f;

		public static float fireFrolicDuration = 0.3f;

		public static float frolicCooldownDuration = 18f;

		private float duration;

		private bool frolicFireFired;

		private bool tpFired;

		private bool cantFrolic;

		public override void OnEnter()
		{
			base.OnEnter();
			ChildMonsterController component = base.characterBody.GetComponent<ChildMonsterController>();
			cantFrolic = !component.CheckTeleportAvailable();
			if (!cantFrolic)
			{
				component.RegisterTeleport();
				fireFrolicDuration += tpDuration;
				duration = baseDuration / attackSpeedStat;
				PlayAnimation("Gesture, Override", "FrolicEnter", "FrolicEnter.playbackRate", 1f);
				Util.PlaySound(attackString, base.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (cantFrolic)
			{
				outer.SetNextStateToMain();
				return;
			}
			if (base.fixedAge > tpDuration && !tpFired)
			{
				FireTPEffect();
				tpFired = true;
				TeleportAroundPlayer();
			}
			if (base.fixedAge > fireFrolicDuration && !frolicFireFired)
			{
				frolicFireFired = true;
				FireTPEffect();
				Transform transform = base.characterBody.master.GetComponent<BaseAI>().currentEnemy.characterBody.transform;
				base.characterBody.transform.LookAt(transform.position);
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public void TeleportAroundPlayer()
		{
			GetComponent<ModelLocator>().modelTransform.GetComponent<CharacterModel>();
			_ = base.characterBody.corePosition;
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			UnityEngine.Vector3 position = base.characterBody.master.GetComponent<BaseAI>().currentEnemy.characterBody.coreTransform.position;
			List<NodeGraph.NodeIndex> list = nodeGraph.FindNodesInRange(position, 25f, 37f, HullMask.Human);
			UnityEngine.Vector3 position2 = default(UnityEngine.Vector3);
			bool flag = false;
			int num = 35;
			while (!flag)
			{
				NodeGraph.NodeIndex nodeIndex = list.ElementAt(UnityEngine.Random.Range(1, list.Count));
				nodeGraph.GetNodePosition(nodeIndex, out position2);
				float num2 = UnityEngine.Vector3.Distance(base.characterBody.coreTransform.position, position2);
				num--;
				if (num2 > 35f || num < 0)
				{
					flag = true;
				}
			}
			if (num < 0)
			{
				UnityEngine.Debug.LogWarning("Child.Frolic state entered a loop where it ran more than 35 times without getting out - check what it's doing");
			}
			position2 += UnityEngine.Vector3.up * 1.5f;
			TeleportHelper.TeleportBody(base.characterBody, position2);
		}

		public void FireTPEffect()
		{
			UnityEngine.Vector3 position = FindModelChild("Chest").transform.position;
			EffectManager.SpawnEffect(tpEffectPrefab, new EffectData
			{
				origin = position,
				scale = 1f
			}, transmit: true);
			Util.PlaySound("Play_child_attack2_reappear", base.gameObject);
		}
	}
	public class FrolicAway : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static GameObject tpEffectPrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string attackString;

		public static float tpDuration = 0.5f;

		public static float fireFrolicDuration = 0.3f;

		private float duration;

		private bool frolicFireFired;

		private bool tpFired;

		public override void OnEnter()
		{
			base.OnEnter();
			fireFrolicDuration += tpDuration;
			base.characterBody.GetComponent<ChildMonsterController>()?.RegisterTeleport();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Override", "FrolicEnter", "FrolicEnter.playbackRate", 1f);
			Util.PlaySound(attackString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > tpDuration && !tpFired)
			{
				FireTPEffect();
				tpFired = true;
				TeleportAway();
			}
			if (base.fixedAge > fireFrolicDuration && !frolicFireFired)
			{
				frolicFireFired = true;
				FireTPEffect();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public void TeleportAway()
		{
			CharacterModel component = GetComponent<ModelLocator>().modelTransform.GetComponent<CharacterModel>();
			_ = base.characterBody.corePosition;
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			List<NodeGraph.NodeIndex> source = nodeGraph.FindNodesInRange(base.characterBody.corePosition, 100f, 200f, HullMask.Human);
			nodeGraph.GetNodePosition(source.First(), out var position);
			TeleportHelper.TeleportBody(base.characterBody, position);
			TeleportOutController.AddTPOutEffect(component, 1f, 0f, 1f);
			if ((bool)tpEffectPrefab)
			{
				FireTPEffect();
			}
		}

		public void FireTPEffect()
		{
			UnityEngine.Vector3 position = FindModelChild("Chest").transform.position;
			EffectManager.SpawnEffect(tpEffectPrefab, new EffectData
			{
				origin = position,
				scale = 1f
			}, transmit: true);
			Util.PlaySound("Play_child_attack2_reappear", base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class SparkBallCharge : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject chargingEffectPrefab;

		public static string chargingSoundString;

		private float duration;

		private float stopwatch;

		private GameObject chargeEffectInstance;

		private uint soundID;

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayCrossfade("Gesture, Override", "SparkEnter", "SparkEnter.playbackRate", duration, 0.3f);
			soundID = Util.PlayAttackSpeedSound(chargingSoundString, base.gameObject, attackSpeedStat);
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("MuzzleFire");
				if ((bool)transform && (bool)chargingEffectPrefab)
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargingEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance.transform.parent = transform;
					chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = duration;
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			AkSoundEngine.StopPlayingID(soundID);
			if ((bool)chargeEffectInstance)
			{
				EntityState.Destroy(chargeEffectInstance);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextState(new SparkBallFire());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class SparkBallFire : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject projectilePrefab;

		public static GameObject muzzleEffectPrefab;

		public static string fireBombSoundString;

		public static float bombDamageCoefficient;

		public static float bombForce;

		public float novaRadius;

		private float duration;

		private float stopwatch;

		public override void OnEnter()
		{
			base.OnEnter();
			stopwatch = 0f;
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture, Override", "SparkLaunch", "SparkLaunch.playbackRate", duration);
			FireBomb();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireBomb()
		{
			Ray aimRay = GetAimRay();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					aimRay.origin = component.FindChild("MuzzleFire").transform.position;
				}
			}
			EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, "MuzzleFire", transmit: false);
			if (base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * bombDamageCoefficient, bombForce, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}
	}
	public class SpawnState : EntityState
	{
		public static float duration = 1f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private ParentEnergyFXController FXController;

		public override void OnEnter()
		{
			base.OnEnter();
			GetModelAnimator();
			PlayAnimation("Gesture, Override", "FrolicEnter", "FrolicEnter.playbackRate", duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData
				{
					origin = base.gameObject.transform.position
				}, transmit: true);
			}
			PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent<PrintController>();
			component.enabled = false;
			component.printTime = duration;
			component.startingPrintHeight = 4f;
			component.maxPrintHeight = -1f;
			component.startingPrintBias = 2f;
			component.maxPrintBias = 0.95f;
			component.disableWhenFinished = true;
			component.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
			component.enabled = true;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Chef
{
	public class ChargeRolyPoly : BaseSkillState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float baseChargeDuration = 1f;

		[SerializeField]
		public float minChargeForChargedAttack = 0.1f;

		[SerializeField]
		public float walkSpeedCoefficient;

		[SerializeField]
		public GameObject skiddingVFX1;

		[SerializeField]
		public string chargeLevelSFX1;

		[SerializeField]
		public string chargeLevelSFX2;

		[SerializeField]
		public string chargeLevelSFX3;

		[SerializeField]
		public float explosionDmgCoefficient;

		[SerializeField]
		public float dmgIncreasePercent;

		[SerializeField]
		public float explosionForce;

		[SerializeField]
		public UnityEngine.Vector3 extraExplosionForce;

		[SerializeField]
		public float explosionRadius;

		[SerializeField]
		public GameObject explosionPrefab1;

		[SerializeField]
		public GameObject explosionPrefab2;

		[SerializeField]
		public GameObject explosionPrefab3;

		[SerializeField]
		public float explodeRadiusVFX;

		private float duration;

		private GameObject explosionPrefab;

		private int gearShifLevel;

		private GameObject chargeLevelVFXBase;

		private bool chargeAnimPlayed;

		private float gearToChargeProgress = 0.3f;

		private bool obtainedGear1;

		private bool obtainedGear2;

		private bool obtainedGear3;

		private Transform modelTransform;

		private EffectManagerHelper rolyPolyChargeFXReference;

		private bool hasBoost;

		private bool useRootMotion;

		private bool hasCharacterMotor;

		private bool hasRailMotor;

		private bool hasCharacterDirection;

		private bool hasAimAnimator;

		private AimAnimator aimAnimator;

		private UnityEngine.Vector3 moveVector = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 aimDirection = UnityEngine.Vector3.forward;

		private ChefController chefController;

		protected float charge { get; private set; }

		protected float chargeDuration { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				chefController = base.characterBody.GetComponent<ChefController>();
				if (chefController != null)
				{
					chefController.blockOtherSkills = true;
				}
				EntityStateMachine.FindByCustomName(base.gameObject, "Weapon").SetNextState(new RolyPolyWeaponBlockingState());
			}
			bool active = NetworkServer.active;
			chargeDuration = baseChargeDuration / attackSpeedStat;
			if (base.characterBody.HasBuff(DLC2Content.Buffs.Boosted))
			{
				hasBoost = true;
				if (active)
				{
					base.characterBody.RemoveBuff(DLC2Content.Buffs.Boosted);
				}
			}
			if (active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.ArmorBoost);
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = walkSpeedCoefficient;
			PlayAnimation("Body", "ChargeRolyPoly", "ChargeRolyPoly.playbackRate", 1f);
			new EffectData
			{
				origin = base.transform.position,
				scale = 1f
			};
			modelTransform = GetModelTransform();
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform inTransform = component.FindChild("Base");
				rolyPolyChargeFXReference = EffectManager.GetAndActivatePooledEffect(skiddingVFX1, inTransform, inResetLocal: true);
			}
			useRootMotion = ((bool)base.characterBody && base.characterBody.rootMotionInMainState && base.isGrounded) || (bool)base.railMotor;
			hasCharacterMotor = base.characterMotor;
			hasRailMotor = base.railMotor;
			hasCharacterDirection = base.characterDirection;
			Util.PlaySound("Play_chef_skill3_charge_start", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			charge = Mathf.Clamp01(base.fixedAge / chargeDuration);
			base.characterBody.SetSpreadBloom(charge);
			base.characterBody.SetAimTimer(3f);
			if (charge >= minChargeForChargedAttack && charge != 1f && charge >= gearToChargeProgress)
			{
				gearToChargeProgress += 0.3f;
				explosionDmgCoefficient += explosionDmgCoefficient * dmgIncreasePercent;
				GearShift();
			}
			if (base.isAuthority)
			{
				AuthorityFixedUpdate();
			}
		}

		private void GearShift()
		{
			switch (gearShifLevel)
			{
			case 0:
				explosionPrefab = explosionPrefab1;
				Util.PlaySound(chargeLevelSFX1, base.gameObject);
				break;
			case 1:
				explosionPrefab = explosionPrefab2;
				Util.PlaySound(chargeLevelSFX2, base.gameObject);
				break;
			case 2:
				explosionPrefab = explosionPrefab3;
				Util.PlaySound(chargeLevelSFX3, base.gameObject);
				break;
			}
			EffectManager.SpawnEffect(explosionPrefab, new EffectData
			{
				origin = base.characterBody.footPosition,
				scale = explosionRadius * explodeRadiusVFX
			}, transmit: true);
			gearShifLevel++;
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = base.characterBody.gameObject;
			blastAttack.baseDamage = explosionDmgCoefficient * base.characterBody.damage;
			blastAttack.baseForce = explosionForce;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.crit = base.characterBody.RollCrit();
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.damageType = DamageType.SlowOnHit;
			blastAttack.inflictor = base.gameObject;
			blastAttack.position = base.transform.position;
			blastAttack.procChainMask = default(ProcChainMask);
			blastAttack.procCoefficient = 1f;
			blastAttack.radius = explosionRadius;
			blastAttack.teamIndex = base.characterBody.teamComponent.teamIndex;
			blastAttack.bonusForce = extraExplosionForce;
			blastAttack.Fire();
		}

		private void AuthorityFixedUpdate()
		{
			if (base.inputBank.skill3.justReleased || charge > 0.9f)
			{
				if (charge >= 0.9f)
				{
					charge = 3f;
				}
				else if (charge >= 0.6f)
				{
					charge = 2f;
				}
				else if (charge >= 0.3f)
				{
					charge = 1f;
				}
				else
				{
					charge = 0f;
				}
				outer.SetNextState(GetNextStateAuthority());
			}
			else
			{
				HandleRotation();
			}
		}

		private void HandleRotation()
		{
			moveVector = base.inputBank.moveVector;
			aimDirection = base.inputBank.aimDirection;
			if (useRootMotion)
			{
				if (hasCharacterMotor)
				{
					base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
				}
				if (hasRailMotor)
				{
					base.railMotor.inputMoveVector = moveVector;
				}
			}
			else
			{
				if (hasCharacterMotor)
				{
					base.characterMotor.moveDirection = moveVector;
				}
				if (hasRailMotor)
				{
					base.railMotor.inputMoveVector = moveVector;
				}
			}
			if (!hasRailMotor && hasCharacterDirection)
			{
				if (hasAimAnimator && aimAnimator.aimType == AimAnimator.AimType.Smart)
				{
					UnityEngine.Vector3 vector = ((moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : moveVector);
					float num = UnityEngine.Vector3.Angle(aimDirection, vector);
					float num2 = Mathf.Max(aimAnimator.pitchRangeMax + aimAnimator.pitchGiveupRange, aimAnimator.yawRangeMax + aimAnimator.yawGiveupRange);
					base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim && num > num2) ? aimDirection : vector);
				}
				else
				{
					base.characterDirection.moveVector = (((bool)base.characterBody && base.characterBody.shouldAim) ? aimDirection : moveVector);
				}
			}
		}

		public override void OnExit()
		{
			if (rolyPolyChargeFXReference != null)
			{
				rolyPolyChargeFXReference.ReturnToPool();
				rolyPolyChargeFXReference = null;
			}
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost);
			}
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			if (base.isAuthority && chefController != null)
			{
				chefController.blockOtherSkills = hasBoost;
			}
			Util.PlaySound("Stop_chef_skill3_charge_loop", base.gameObject);
			base.OnExit();
		}

		protected virtual EntityState GetNextStateAuthority()
		{
			return new RolyPoly
			{
				charge = charge,
				hasBoost = hasBoost
			};
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class RolyPolyWeaponBlockingState : BaseSkillState
	{
		private ChefController chefController;

		public override void OnEnter()
		{
			base.OnEnter();
			chefController = base.characterBody.GetComponent<ChefController>();
		}

		public override void Update()
		{
			base.Update();
			if (base.isAuthority && !chefController.blockOtherSkills)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class ChefsKiss : BaseState
	{
		public override void OnEnter()
		{
		}
	}
	public class Dice : BaseState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject projectileEnhancedPrefab;

		[SerializeField]
		public GameObject effectEnhancedPrefab;

		[SerializeField]
		public float baseDuration = 2f;

		[SerializeField]
		public float damageCoefficient = 1.2f;

		[SerializeField]
		public float boostedDamageCoefficient = 1.2f;

		[SerializeField]
		public float force = 20f;

		[SerializeField]
		public string attackString;

		[SerializeField]
		public string returnString;

		[SerializeField]
		public string yesChefAttackString;

		[SerializeField]
		public string yesChefReturnString;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bloom;

		[SerializeField]
		public float recallAnimationTransitionTime = 0.2f;

		[SerializeField]
		public float approximateCleaverDistance = 80f;

		private float duration;

		private ChefController chefController;

		private bool hasBoost;

		private bool recallInputPressed;

		private const float recallBackupCountdown_Duration = 3f;

		private float recallBackupCountdown = 3f;

		public override void OnEnter()
		{
			base.OnEnter();
			recallBackupCountdown = 3f;
			if (!chefController)
			{
				chefController = GetComponent<ChefController>();
			}
			chefController.characterBody = base.characterBody;
			chefController.spreadBloom = bloom;
			hasBoost = base.characterBody.HasBuff(DLC2Content.Buffs.Boosted);
			if (hasBoost)
			{
				damageCoefficient = boostedDamageCoefficient;
				if (NetworkServer.active)
				{
					base.characterBody.RemoveBuff(DLC2Content.Buffs.Boosted);
				}
			}
			chefController.NetworkcatchDirtied = false;
			chefController.recallCleaver = false;
			Ray ray = GetAimRay();
			TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, approximateCleaverDistance, base.gameObject);
			duration = baseDuration;
			StartAimMode(duration + 2f);
			if (hasBoost)
			{
				PlayAnimation("Gesture, Override", "FireSliceAndDice", "FireSliceAndDice.playbackRate", duration);
				PlayAnimation("Gesture, Additive", "FireSliceAndDice", "FireSliceAndDice.playbackRate", duration);
				Util.PlaySound(yesChefAttackString, base.gameObject);
			}
			else
			{
				PlayAnimation("Gesture, Override", "FireDice", "FireDice.playbackRate", duration);
				PlayAnimation("Gesture, Additive", "FireDice", "FireDice.playbackRate", duration);
				Util.PlaySound(attackString, base.gameObject);
			}
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			string muzzleName = "MouthMuzzle";
			GameObject gameObject = (hasBoost ? effectEnhancedPrefab : effectPrefab);
			if ((bool)gameObject)
			{
				EffectManager.SimpleMuzzleFlash(gameObject, base.characterBody.aimOriginTransform.gameObject, muzzleName, transmit: false);
			}
			chefController.cleaverAway = true;
			if (!base.isAuthority)
			{
				return;
			}
			GameObject gameObject2 = (hasBoost ? projectileEnhancedPrefab : projectilePrefab);
			int[] array = ((!hasBoost) ? new int[1] { 1 } : new int[3] { 8, 4, 4 });
			int num = array.Length;
			for (int i = 0; i < num; i++)
			{
				int num2 = array[i];
				float num3 = (float)(i % 2) * (0.5f / (float)num2);
				for (int j = 0; j < num2; j++)
				{
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.projectilePrefab = gameObject2;
					fireProjectileInfo.position = ray.origin;
					float f = (num3 + (float)j / (float)num2) * MathF.PI * 2f;
					float f2 = Mathf.Acos(0.02f + (float)i / (float)num);
					float x = Mathf.Sin(f2) * Mathf.Sin(f);
					float y = Mathf.Cos(f2);
					float z = Mathf.Sin(f2) * Mathf.Cos(f);
					UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.LookRotation(new UnityEngine.Vector3(x, y, z));
					fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction) * quaternion;
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.damage = damageStat * damageCoefficient;
					fireProjectileInfo.damageTypeOverride = DamageType.Generic;
					fireProjectileInfo.force = force;
					fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
					if (!NetworkServer.active && (bool)chefController)
					{
						chefController.CacheCleaverProjectileFireInfo(fireProjectileInfo);
					}
					ProjectileManager.instance.FireProjectile(fireProjectileInfo);
				}
			}
		}

		public override void OnExit()
		{
			chefController.SetYesChefHeatState(newYesChefHeatState: false);
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(DLC2Content.Buffs.boostedFireEffect);
				if (!hasBoost)
				{
					chefController.DestroyCleavers();
				}
			}
			if (base.isAuthority)
			{
				chefController.ClearSkillOverrides();
			}
			if (chefController.cleaverAway)
			{
				chefController.recallCleaver = true;
			}
			if (chefController.catchDirtied)
			{
				chefController.NetworkcatchDirtied = false;
				PlayAnimation("Gesture, Override", "DiceReturnCatch", "DiceReturnCatch.playbackRate", duration);
				PlayAnimation("Gesture, Additive", "DiceReturnCatch", "DiceReturnCatch.playbackRate", duration);
			}
			else
			{
				PlayAnimation("Gesture, Override", "BufferEmpty", null, duration);
				PlayAnimation("Gesture, Additive", "BufferEmpty", null, duration);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			bool flag = base.fixedAge > 0f;
			base.FixedUpdate();
			bool flag2 = base.isAuthority;
			if (flag)
			{
				recallInputPressed = base.inputBank.skill1.justPressed;
			}
			if (recallInputPressed)
			{
				recallInputPressed = false;
				if (chefController.cleaverAway && flag)
				{
					if (chefController.recallCleaver)
					{
						chefController.recallCleaver = true;
					}
					else
					{
						chefController.recallCleaver = true;
						recallBackupCountdown = 3f;
						PlayAnimation("Gesture, Override", "DiceReturnHold", null, duration, recallAnimationTransitionTime);
						PlayAnimation("Gesture, Additive", "DiceReturnHold", null, duration, recallAnimationTransitionTime);
					}
				}
			}
			bool flag3 = false;
			if (flag2 && chefController.recallCleaver)
			{
				recallBackupCountdown -= Time.deltaTime;
				if (recallBackupCountdown <= 0f)
				{
					flag3 = true;
				}
			}
			if (chefController.catchDirtied)
			{
				if (hasBoost)
				{
					Util.PlaySound(yesChefReturnString, base.gameObject);
				}
				else
				{
					Util.PlaySound(returnString, base.gameObject);
				}
				if (flag2)
				{
					outer.SetNextStateToMain();
				}
			}
			else if (flag3 || (!chefController.cleaverAway && flag))
			{
				chefController.NetworkcatchDirtied = true;
				if (flag2)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Glaze : BaseState
	{
		public static GameObject effectPrefab;

		public static GameObject projectilePrefab;

		public static int grenadeCountMax = 3;

		public static float damageCoefficient;

		public static float fireDuration = 3f;

		public static float baseDuration = 2f;

		public static float arcAngle = 7f;

		public static float recoilAmplitude = 1f;

		public static string attackSoundString;

		public static float spreadBloomValue = 0.3f;

		public static float minimumTimeBetweenShots = 0.025f;

		public static float maximumTimeBetweenShots = 0.1f;

		public static float xDeviationSpread = 1f;

		private Ray projectileRay;

		private Transform modelTransform;

		private float duration;

		private float fireTimer;

		private int grenadeCount;

		private int muzzleStringEndNum = 1;

		private void FireGrenade(string targetMuzzle)
		{
			Util.PlaySound(attackSoundString, base.gameObject);
			projectileRay = GetAimRay();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					Transform transform = component.FindChild(targetMuzzle);
					if ((bool)transform)
					{
						projectileRay.origin = transform.position;
					}
				}
			}
			AddRecoil(-1f * recoilAmplitude, -2f * recoilAmplitude, -1f * recoilAmplitude, 1f * recoilAmplitude);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				float x = UnityEngine.Random.Range(0f, base.characterBody.spreadBloomAngle + xDeviationSpread);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, projectileRay.direction);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f + arcAngle;
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * projectileRay.direction);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = projectileRay.origin;
				fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(forward);
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				fireProjectileInfo.damageTypeOverride = DamageType.WeakOnHit;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
			base.characterBody.AddSpreadBloom(spreadBloomValue);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelTransform = GetModelTransform();
			PlayAnimation("Gesture, Override", "ChefGlazeStart", "ChefGlazeStart.playbackRate", duration);
			StartAimMode();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				fireTimer -= GetDeltaTime();
				float num = UnityEngine.Random.Range(minimumTimeBetweenShots, maximumTimeBetweenShots) + fireDuration / attackSpeedStat / (float)grenadeCountMax;
				if (fireTimer <= 0f && grenadeCount < grenadeCountMax)
				{
					fireTimer += num;
					arcAngle = UnityEngine.Random.Range(-6, -12);
					PlayCrossfade("Gesture, Additive", "ChefGlazeRecoil", 0.2f);
					FireGrenade("MuzzleGlaze" + muzzleStringEndNum);
					muzzleStringEndNum++;
					if (muzzleStringEndNum > 5)
					{
						muzzleStringEndNum = 1;
					}
					grenadeCount++;
				}
			}
			if (base.isAuthority && grenadeCount >= grenadeCountMax)
			{
				PlayCrossfade("Gesture, Override", "ChefGlazeExit", 0.2f);
				PlayCrossfade("Gesture, Additive", "ChefGlazeExit", 0.2f);
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class RolyPoly : GenericCharacterMain
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float speedMultiplier;

		[SerializeField]
		public float speedMultiplierLvlUp;

		[SerializeField]
		public float baseDurationLvlUp;

		public static float chargeDamageCoefficient;

		public static float chargeDamageCoefficientLvlUp;

		public static float awayForceMagnitude;

		public static float upwardForceMagnitude;

		public static GameObject impactEffectPrefab;

		public static GameObject impactEffectBoostedPrefab;

		public static float hitPauseDuration;

		public static string impactSoundString;

		public static float recoilAmplitude;

		public static string startSoundString;

		public static string endSoundString;

		public static GameObject knockbackEffectPrefab;

		public static float knockbackDamageCoefficient;

		public static float massThresholdForKnockback;

		public static float knockbackForce;

		public static float knockbackForceLvlUp;

		[SerializeField]
		public GameObject startEffectPrefab;

		[SerializeField]
		public GameObject midEffectPrefab;

		[SerializeField]
		public GameObject endEffectPrefab;

		private uint soundID;

		private float duration;

		private float hitPauseTimer;

		private UnityEngine.Vector3 idealDirection;

		private OverlapAttack attack;

		private bool inHitPause;

		private int chestIndex = -1;

		private GameObject temporaryInstantiationTransform;

		private GameObject midEffectInstance;

		private float chargeDamageCoefficientTemp;

		private float speedMultiplierTemp;

		private float knockBackForceTemp;

		private float baseDurationTemp;

		private ChefController chefController;

		[SerializeField]
		public bool hasBoost;

		[SerializeField]
		public float charge;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float whirlwindDamageCo;

		private int originalLayer;

		[SerializeField]
		public GameObject rollerSpikePrefab;

		private GameObject rollerSpikeInstance;

		public override void OnEnter()
		{
			base.OnEnter();
			chefController = base.characterBody.GetComponent<ChefController>();
			chefController.rolyPolyActive = true;
			originalLayer = base.gameObject.layer;
			base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
			base.characterMotor?.Motor.RebuildCollidableLayers();
			chargeDamageCoefficientTemp = chargeDamageCoefficient;
			knockBackForceTemp = knockbackForce;
			speedMultiplierTemp = speedMultiplier;
			baseDurationTemp = baseDuration;
			float num = charge;
			if (num <= 1f)
			{
				if (num != 0f && num == 1f)
				{
					chargeDamageCoefficientTemp += chargeDamageCoefficientTemp * chargeDamageCoefficientLvlUp;
					speedMultiplierTemp += speedMultiplierTemp * speedMultiplierLvlUp;
					knockBackForceTemp += knockBackForceTemp * knockbackForceLvlUp;
					baseDurationTemp += baseDurationLvlUp;
				}
			}
			else if (num != 2f)
			{
				if (num == 3f)
				{
					chargeDamageCoefficientTemp += chargeDamageCoefficientTemp * (chargeDamageCoefficientLvlUp * 3f);
					speedMultiplierTemp += speedMultiplierTemp * (speedMultiplierLvlUp * 3f);
					knockBackForceTemp += knockBackForceTemp * (knockbackForceLvlUp * 3f);
					baseDurationTemp += baseDurationLvlUp * 3f;
				}
			}
			else
			{
				chargeDamageCoefficientTemp += chargeDamageCoefficientTemp * (chargeDamageCoefficientLvlUp * 2f);
				speedMultiplierTemp += speedMultiplierTemp * (speedMultiplierLvlUp * 2f);
				knockBackForceTemp += knockBackForceTemp * (knockbackForceLvlUp * 2f);
				baseDurationTemp += baseDurationLvlUp * 2f;
			}
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(DLC2Content.Buffs.CookingRolling);
			}
			if (hasBoost)
			{
				Util.PlaySound("Play_chef_skill3_start", base.gameObject);
				Util.PlaySound("Play_chef_skill3_boosted_active_loop", base.gameObject);
				ProjectileManager.instance.FireProjectile(projectilePrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * whirlwindDamageCo, 0f, Util.CheckRoll(critStat, base.characterBody.master));
				PlayAnimation("Body", "BoostedRolyPoly", "BoostedRolyPoly.playbackRate", 1f);
				GetModelAnimator().SetBool("isInBoostedRolyPoly", value: true);
			}
			else
			{
				Util.PlaySound("Play_chef_skill3_start", base.gameObject);
				GetModelAnimator().SetBool("isInRolyPoly", value: true);
				PlayAnimation("Body", "FireRolyPoly", "FireRolyPoly.playbackRate", 1f);
			}
			duration = baseDurationTemp;
			if (base.isAuthority)
			{
				if ((bool)base.inputBank)
				{
					idealDirection = base.inputBank.aimDirection;
					idealDirection.y = 0f;
				}
				UpdateDirection();
			}
			temporaryInstantiationTransform = GetModelTransform().gameObject;
			if ((bool)base.modelLocator)
			{
				base.modelLocator.normalizeToFloor = true;
			}
			if ((bool)base.characterBody)
			{
				if ((bool)startEffectPrefab)
				{
					EffectManager.SpawnEffect(startEffectPrefab, new EffectData
					{
						origin = base.characterBody.corePosition
					}, transmit: false);
				}
				if ((bool)midEffectPrefab && (bool)temporaryInstantiationTransform)
				{
					midEffectInstance = UnityEngine.Object.Instantiate(midEffectPrefab, temporaryInstantiationTransform.transform);
				}
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.forward = idealDirection;
			}
			Util.PlaySound("Stop_chef_skill3_charge_loop", base.gameObject);
			HitBoxGroup hitBoxGroup = null;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Charge");
			}
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = GetTeam();
			attack.damage = chargeDamageCoefficientTemp * damageStat;
			attack.hitEffectPrefab = (hasBoost ? impactEffectBoostedPrefab : impactEffectPrefab);
			attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude;
			attack.pushAwayForce = knockBackForceTemp;
			attack.hitBoxGroup = hitBoxGroup;
			attack.isCrit = RollCrit();
			attack.damageType = DamageType.Stun1s;
			attack.retriggerTimeout = 0.5f;
		}

		private void HandleSpawnRollerspikes()
		{
			if (!rollerSpikePrefab)
			{
				return;
			}
			ChildLocator modelChildLocator = GetModelChildLocator();
			if ((bool)modelChildLocator)
			{
				GameObject gameObject = modelChildLocator.FindChildGameObject("Wheel");
				if ((bool)gameObject)
				{
					rollerSpikeInstance = UnityEngine.Object.Instantiate(rollerSpikePrefab, gameObject.transform);
				}
			}
		}

		private void HandleCleanupRollerSpikes()
		{
			if ((bool)rollerSpikeInstance)
			{
				EntityState.Destroy(rollerSpikeInstance);
			}
		}

		public override void OnExit()
		{
			chefController.rolyPolyActive = false;
			chefController.SetYesChefHeatState(newYesChefHeatState: false);
			chefController.blockOtherSkills = false;
			if (hasBoost)
			{
				if (NetworkServer.active && base.characterBody.HasBuff(DLC2Content.Buffs.boostedFireEffect))
				{
					base.characterBody.RemoveBuff(DLC2Content.Buffs.boostedFireEffect);
				}
				if (base.isAuthority)
				{
					chefController.ClearSkillOverrides();
				}
			}
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(DLC2Content.Buffs.CookingRolling);
			}
			base.gameObject.layer = originalLayer;
			base.characterMotor?.Motor.RebuildCollidableLayers();
			HandleCleanupRollerSpikes();
			if (!outer.destroying && (bool)base.characterBody)
			{
				if ((bool)endEffectPrefab)
				{
					EffectManager.SpawnEffect(endEffectPrefab, new EffectData
					{
						origin = base.characterBody.corePosition
					}, transmit: false);
				}
				if ((bool)midEffectInstance)
				{
					EntityState.Destroy(midEffectInstance);
				}
				base.characterBody.isSprinting = false;
				if (NetworkServer.active)
				{
					base.characterBody.RemoveBuff(RoR2Content.Buffs.ArmorBoost);
				}
			}
			if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision)
			{
				base.characterMotor.velocity += GetIdealVelocity();
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.normalizeToFloor = false;
			}
			GetModelAnimator().SetBool("isInRolyPoly", value: false);
			GetModelAnimator().SetBool("isInBoostedRolyPoly", value: false);
			PlayCrossfade("Body", "ExitRolyPoly", 0.1f);
			AkSoundEngine.StopPlayingID(soundID);
			if (hasBoost)
			{
				Util.PlaySound("Stop_chef_skill3_boosted_active_loop", base.gameObject);
			}
			Util.PlaySound(endSoundString, base.gameObject);
			Util.PlaySound("Stop_chef_skill3_active_loop", base.gameObject);
			Util.PlaySound("Stop_chef_skill3_charge_loop", base.gameObject);
			base.OnExit();
		}

		private float GetDamageBoostFromSpeed()
		{
			return Mathf.Max(1f, base.characterBody.moveSpeed / base.characterBody.baseMoveSpeed);
		}

		private void UpdateDirection()
		{
			if ((bool)base.inputBank)
			{
				UnityEngine.Vector3 vector = base.inputBank.moveVector;
				UnityEngine.Vector2 vector2 = ((!(vector == UnityEngine.Vector3.zero)) ? Util.Vector3XZToVector2XY(vector.normalized) : Util.Vector3XZToVector2XY(base.characterDirection.forward));
				if (vector2 != UnityEngine.Vector2.zero)
				{
					vector2.Normalize();
					idealDirection = new UnityEngine.Vector3(vector2.x, 0f, vector2.y).normalized;
				}
			}
		}

		private UnityEngine.Vector3 GetIdealVelocity()
		{
			return base.characterDirection.forward.normalized * base.characterBody.moveSpeed * speedMultiplier;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
			else
			{
				if (!base.isAuthority)
				{
					return;
				}
				if ((bool)base.characterBody)
				{
					base.characterBody.isSprinting = true;
				}
				if ((bool)base.skillLocator.special && base.inputBank.skill4.down)
				{
					base.skillLocator.special.ExecuteIfReady();
				}
				UpdateDirection();
				if (!inHitPause)
				{
					if ((bool)base.characterDirection)
					{
						base.characterMotor.moveDirection = idealDirection;
						base.characterDirection.moveVector = idealDirection;
						if ((bool)base.characterMotor && !base.characterMotor.disableAirControlUntilCollision)
						{
							base.characterMotor.rootMotion += GetIdealVelocity() * GetDeltaTime();
						}
					}
					if (attack.Fire())
					{
						inHitPause = true;
						hitPauseTimer = hitPauseDuration;
						AddRecoil(-0.25f * recoilAmplitude, -0.25f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
					}
				}
				else
				{
					base.characterMotor.velocity = UnityEngine.Vector3.zero;
					hitPauseTimer -= GetDeltaTime();
					if (hitPauseTimer < 0f)
					{
						inHitPause = false;
					}
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class Sear : BaseState
	{
		public static GameObject flamethrowerEffectPrefab;

		public static GameObject ovenBlueEffectPrefab;

		public static GameObject initialOvenBlueEffectPrefab;

		public static GameObject boostedSearProjectilePrefab;

		public static GameObject impactEffectPrefab;

		public static GameObject tracerEffectPrefab;

		public static float maxDistance;

		public static float radius;

		public static float baseEntryDuration = 1f;

		public static float baseExitDuration = 0.5f;

		public static float baseFlamethrowerDuration = 2f;

		public static float totalDamageCoefficient = 1.2f;

		public static float procCoefficientPerTick;

		public static float tickFrequency;

		public static float force = 20f;

		public static GameObject muzzleflashEffectPrefab;

		public static float boostedProjectileDmgCoefficient = 1f;

		public static float boostedProjectileCount = 1f;

		public static float boostedProjectileTimer;

		public static float boostedProjectileInBetweenShotTime;

		public static string startAttackSoundString;

		public static string endAttackSoundString;

		public static string endLoopSoundString;

		public static string boostedStartAttackSoundString;

		public static string boostedEndAttackSoundString;

		public static string boostedEndLoopSoundString;

		public static string boostedFireBallSoundString;

		public static float ignitePercentChance;

		public static float maxSpread;

		private float tickDamageCoefficient;

		private float primaryAttackStopwatch;

		private float stopwatch;

		private float entryDuration;

		private float exitDuration;

		private float flamethrowerDuration;

		private bool flamethrowerStarted;

		private bool flamethrowerEnded;

		private ChildLocator childLocator;

		private Transform flamethrowerEffectInstance;

		private Transform muzzleTransform;

		private bool isCrit;

		private bool hasBoost;

		private float boostedDamage;

		private int boostedProjectilesFired;

		private bool allBoostProjectilesFired;

		private ChefController chefController;

		private const float flamethrowerEffectBaseDistance = 16f;

		private float flamethrowerTimestamp;

		public override void OnEnter()
		{
			base.OnEnter();
			chefController = GetComponent<ChefController>();
			if (NetworkServer.active)
			{
				base.characterBody.AddBuff(DLC2Content.Buffs.CookingSearing);
			}
			if (base.characterBody.HasBuff(DLC2Content.Buffs.Boosted))
			{
				hasBoost = true;
				base.characterBody.RemoveBuff(DLC2Content.Buffs.Boosted);
			}
			stopwatch = 0f;
			entryDuration = baseEntryDuration / attackSpeedStat;
			exitDuration = baseExitDuration / attackSpeedStat;
			flamethrowerDuration = baseFlamethrowerDuration + exitDuration;
			Transform modelTransform = GetModelTransform();
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(entryDuration + flamethrowerDuration + 1f);
			}
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
				modelTransform.GetComponent<AimAnimator>().enabled = true;
				muzzleTransform = childLocator.FindChild("MuzzleCenter");
			}
			float num = flamethrowerDuration * tickFrequency;
			if (hasBoost)
			{
				boostedDamage = 1.5f;
			}
			else
			{
				boostedDamage = 1f;
			}
			tickDamageCoefficient = totalDamageCoefficient * boostedDamage / num;
			if (base.isAuthority && (bool)base.characterBody)
			{
				isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			}
			boostedProjectileTimer = boostedProjectileInBetweenShotTime;
			PlayAnimation("Gesture, Additive", "PrepSear", "PrepSear.playbackRate", entryDuration);
			PlayAnimation("Gesture, Override", "PrepSear", "PrepSear.playbackRate", entryDuration);
		}

		public override void Update()
		{
			base.Update();
			float deltaTime = Time.deltaTime;
			stopwatch += deltaTime;
			if (stopwatch < entryDuration)
			{
				return;
			}
			if (hasBoost && !allBoostProjectilesFired)
			{
				HandleBoostProjectiles(deltaTime);
				return;
			}
			if (!flamethrowerStarted && stopwatch >= entryDuration)
			{
				StartPrimaryFlameVFX();
			}
			else if (!flamethrowerEnded)
			{
				if (base.isAuthority)
				{
					HandlePrimaryAttack(deltaTime);
				}
				if (stopwatch >= entryDuration + flamethrowerDuration)
				{
					EndPrimaryFlameVFX();
				}
			}
			if (flamethrowerEnded && stopwatch >= flamethrowerDuration + entryDuration + exitDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void HandleBoostProjectiles(float deltaTime)
		{
			boostedProjectileTimer += deltaTime;
			if (!(boostedProjectileTimer < boostedProjectileInBetweenShotTime))
			{
				if ((float)boostedProjectilesFired < boostedProjectileCount)
				{
					boostedProjectileTimer = 0f;
					boostedProjectilesFired++;
					FireBoostedFireball("MuzzleCenter");
				}
				else
				{
					allBoostProjectilesFired = true;
					stopwatch = entryDuration;
				}
			}
		}

		private void FirePrimaryAttack(string muzzleString)
		{
			GetAimRay();
			if (base.isAuthority && (bool)muzzleTransform)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = muzzleTransform.position;
				bulletAttack.aimVector = muzzleTransform.forward;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.damage = tickDamageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.muzzleName = muzzleString;
				bulletAttack.hitEffectPrefab = impactEffectPrefab;
				bulletAttack.isCrit = isCrit;
				bulletAttack.radius = radius;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.stopperMask = LayerIndex.world.mask;
				bulletAttack.procCoefficient = procCoefficientPerTick;
				bulletAttack.maxDistance = maxDistance;
				bulletAttack.smartCollision = true;
				bulletAttack.damageType = new DamageTypeCombo(DamageType.IgniteOnHit, DamageTypeExtended.ChefSearDamage);
				bulletAttack.Fire();
			}
		}

		private void FireBoostedFireball(string muzzleString)
		{
			if (base.isAuthority && (bool)muzzleTransform)
			{
				if ((bool)muzzleflashEffectPrefab)
				{
					EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
				}
				Ray aimRay = GetAimRay();
				Util.PlaySound(boostedFireBallSoundString, base.gameObject);
				ProjectileManager.instance.FireProjectile(boostedSearProjectilePrefab, muzzleTransform.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, base.characterBody.damage * boostedProjectileDmgCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		private void StartPrimaryFlameVFX()
		{
			flamethrowerStarted = true;
			PlayAnimation("Gesture, Override", "FireSear", "FireSear.playbackRate", flamethrowerDuration);
			PlayAnimation("Gesture, Additive", "FireSear", "FireSear.playbackRate", flamethrowerDuration);
			if (hasBoost)
			{
				flamethrowerEffectInstance = UnityEngine.Object.Instantiate(ovenBlueEffectPrefab, muzzleTransform).transform;
				Util.PlaySound(boostedStartAttackSoundString, base.gameObject);
			}
			else
			{
				flamethrowerEffectInstance = UnityEngine.Object.Instantiate(flamethrowerEffectPrefab, muzzleTransform).transform;
				Util.PlaySound(startAttackSoundString, base.gameObject);
			}
			flamethrowerTimestamp = Time.time;
			flamethrowerEffectInstance.transform.localPosition = UnityEngine.Vector3.zero;
			flamethrowerEffectInstance.GetComponent<ScaleParticleSystemDuration>().newDuration = flamethrowerDuration;
		}

		private void EndPrimaryFlameVFX()
		{
			flamethrowerEnded = true;
			PlayCrossfade("Gesture, Override", "ExitSear", "ExitSear.playbackRate", exitDuration, 0.1f);
			PlayCrossfade("Gesture, Additive", "ExitSear", "ExitSear.playbackRate", exitDuration, 0.1f);
			if ((bool)flamethrowerEffectInstance)
			{
				if (hasBoost)
				{
					Util.PlaySound(boostedEndLoopSoundString, base.gameObject);
					Util.PlaySound(boostedEndAttackSoundString, base.gameObject);
				}
				else
				{
					Util.PlaySound(endLoopSoundString, base.gameObject);
					Util.PlaySound(endAttackSoundString, base.gameObject);
				}
				EntityState.Destroy(flamethrowerEffectInstance.gameObject);
			}
		}

		private void HandlePrimaryAttack(float deltaTime)
		{
			primaryAttackStopwatch += deltaTime;
			if (primaryAttackStopwatch > 1f / tickFrequency)
			{
				primaryAttackStopwatch -= 1f / tickFrequency;
				FirePrimaryAttack("MuzzleCenter");
			}
		}

		public override void OnExit()
		{
			chefController.SetYesChefHeatState(newYesChefHeatState: false);
			if (NetworkServer.active)
			{
				base.characterBody.RemoveBuff(DLC2Content.Buffs.CookingSearing);
				if (base.characterBody.HasBuff(DLC2Content.Buffs.boostedFireEffect))
				{
					base.characterBody.RemoveBuff(DLC2Content.Buffs.boostedFireEffect);
				}
			}
			if (base.isAuthority)
			{
				chefController.ClearSkillOverrides();
			}
			PlayCrossfade("Gesture, Override", "BufferEmpty", 0.1f);
			PlayCrossfade("Gesture, Additive", "BufferEmpty", 0.1f);
			if ((bool)flamethrowerEffectInstance)
			{
				if (hasBoost)
				{
					Util.PlaySound(boostedEndLoopSoundString, base.gameObject);
					Util.PlaySound(boostedEndAttackSoundString, base.gameObject);
				}
				else
				{
					Util.PlaySound(endLoopSoundString, base.gameObject);
					Util.PlaySound(endAttackSoundString, base.gameObject);
				}
				EntityState.Destroy(flamethrowerEffectInstance.gameObject);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class YesChef : BaseState
	{
		[SerializeField]
		public float duration = 1f;

		[SerializeField]
		public GameObject playerRespawnEffectPrefab;

		[SerializeField]
		public string startSoundString;

		[SerializeField]
		public int buffStockToAdd = 3;

		[SerializeField]
		public float heatDamageCo = 1f;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public GameObject blastEffectPrefab;

		[SerializeField]
		public float blastDamageCoefficient;

		[SerializeField]
		public float blastRadius;

		[SerializeField]
		public float blastProcCoefficient;

		[SerializeField]
		public float blastForce;

		[SerializeField]
		[Tooltip("Set This to the child transform you want the blast effect to parent to")]
		public string blastEffectTransformChild;

		[SerializeField]
		public float exitDelay;

		[SerializeField]
		public SkillDef primarySkillOverrideDef;

		[SerializeField]
		public SkillDef secondarySkillOverrideDef;

		[SerializeField]
		public SkillDef utilitySkillOverrideDef;

		[SerializeField]
		public SkillDef specialSkillOverrideDef;

		private bool alreadyRan;

		private ChildLocator childLocator;

		private ChefController chefController;

		private bool playedYesChefSFX;

		public override void OnEnter()
		{
			base.OnEnter();
			chefController = base.characterBody.GetComponent<ChefController>();
			if ((bool)chefController)
			{
				chefController.SetYesChefHeatState(newYesChefHeatState: true);
			}
			if (base.isAuthority && (bool)chefController)
			{
				chefController.ClearSkillOverrides();
				SkillStateOverrideData skillStateOverrideData = new SkillStateOverrideData(base.characterBody, _duplicateStock: true);
				skillStateOverrideData.simulateRestockForOverridenSkills = false;
				skillStateOverrideData.primarySkillOverride = primarySkillOverrideDef;
				skillStateOverrideData.secondarySkillOverride = secondarySkillOverrideDef;
				skillStateOverrideData.utilitySkillOverride = utilitySkillOverrideDef;
				skillStateOverrideData.specialSkillOverride = specialSkillOverrideDef;
				skillStateOverrideData.OverrideSkills(base.skillLocator);
				EnsureMinStock(ref base.skillLocator.primary);
				EnsureMinStock(ref base.skillLocator.secondary);
				EnsureMinStock(ref base.skillLocator.utility);
				chefController.TransferSkillOverrides(skillStateOverrideData);
			}
			childLocator = GetModelChildLocator();
			PlayAnimation("Gesture, Additive", "FireYesChef", "FireYesChef.playbackRate", duration);
			PlayAnimation("Gesture, Override", "FireYesChef", "FireYesChef.playbackRate", duration);
			EffectData effectData = new EffectData
			{
				origin = base.transform.position,
				scale = blastRadius
			};
			if ((bool)childLocator)
			{
				int num = childLocator.FindChildIndex(blastEffectTransformChild);
				if (num != -1)
				{
					effectData.SetChildLocatorTransformReference(base.gameObject, num);
				}
			}
			EffectManager.SpawnEffect(blastEffectPrefab, effectData, transmit: true);
			chefController.ActivateServoStrainSfxForDuration(3f);
			static void EnsureMinStock(ref GenericSkill skill)
			{
				if (skill.stock < 1)
				{
					skill.stock = 1;
					skill.rechargeStopwatch = 0f;
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		public override void OnExit()
		{
			base.OnExit();
			if (NetworkServer.active)
			{
				if (!base.characterBody.HasBuff(DLC2Content.Buffs.Boosted))
				{
					base.characterBody.AddBuff(DLC2Content.Buffs.Boosted);
				}
				if (!base.characterBody.HasBuff(DLC2Content.Buffs.boostedFireEffect))
				{
					base.characterBody.AddBuff(DLC2Content.Buffs.boostedFireEffect);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > 0.5f && !playedYesChefSFX)
			{
				Util.PlaySound(startSoundString, base.gameObject);
				playedYesChefSFX = true;
			}
			if ((bool)chefController && base.fixedAge > duration && base.isAuthority)
			{
				ProjectileManager.instance.FireProjectile(projectilePrefab, base.gameObject.transform.position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * heatDamageCo, 0f, Util.CheckRoll(critStat, base.characterBody.master));
				Util.PlaySound("Play_chef_skill4_flame_aoe_on", base.gameObject);
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.characterBody.gameObject;
				blastAttack.baseDamage = blastDamageCoefficient * base.characterBody.damage;
				blastAttack.baseForce = blastForce;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.crit = base.characterBody.RollCrit();
				blastAttack.damageColorIndex = DamageColorIndex.Item;
				blastAttack.inflictor = base.gameObject;
				blastAttack.position = base.characterBody.corePosition;
				blastAttack.procChainMask = default(ProcChainMask);
				blastAttack.procCoefficient = blastProcCoefficient;
				blastAttack.radius = blastRadius;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.teamIndex = base.teamComponent.teamIndex;
				blastAttack.Fire();
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.CaptainSupplyDrop
{
	public class BaseCaptainSupplyDropState : BaseState
	{
		private ProxyInteraction interactionComponent;

		protected GenericEnergyComponent energyComponent;

		protected TeamFilter teamFilter;

		private UnityEngine.UI.Image energyIndicator;

		private GameObject energyIndicatorContainer;

		protected virtual bool shouldShowModel => true;

		protected virtual bool shouldShowEnergy => false;

		protected virtual string GetContextString(Interactor activator)
		{
			return null;
		}

		protected virtual Interactability GetInteractability(Interactor activator)
		{
			return Interactability.Disabled;
		}

		protected virtual void OnInteractionBegin(Interactor activator)
		{
		}

		protected virtual bool ShouldShowOnScanner()
		{
			return false;
		}

		protected virtual bool ShouldIgnoreSpherecastForInteractability(Interactor activator)
		{
			return false;
		}

		private string GetContextStringInternal(ProxyInteraction proxyInteraction, Interactor activator)
		{
			return GetContextString(activator);
		}

		private Interactability GetInteractabilityInternal(ProxyInteraction proxyInteraction, Interactor activator)
		{
			return GetInteractability(activator);
		}

		private void OnInteractionBeginInternal(ProxyInteraction proxyInteraction, Interactor activator)
		{
			OnInteractionBegin(activator);
		}

		private bool ShouldIgnoreSpherecastForInteractabilityInternal(ProxyInteraction proxyInteraction, Interactor activator)
		{
			return ShouldIgnoreSpherecastForInteractability(activator);
		}

		private bool ShouldShowOnScannerInternal(ProxyInteraction proxyInteraction)
		{
			return ShouldShowOnScanner();
		}

		public override void OnEnter()
		{
			base.OnEnter();
			energyComponent = GetComponent<GenericEnergyComponent>();
			teamFilter = GetComponent<TeamFilter>();
			interactionComponent = GetComponent<ProxyInteraction>();
			interactionComponent.getContextString = GetContextStringInternal;
			interactionComponent.getInteractability = GetInteractabilityInternal;
			interactionComponent.onInteractionBegin = OnInteractionBeginInternal;
			interactionComponent.shouldShowOnScanner = ShouldShowOnScannerInternal;
			interactionComponent.shouldIgnoreSpherecastForInteractability = ShouldIgnoreSpherecastForInteractabilityInternal;
			GetModelTransform().gameObject.SetActive(shouldShowModel);
			energyIndicatorContainer = FindModelChild("EnergyIndicatorContainer").gameObject;
			energyIndicator = FindModelChild("EnergyIndicator").GetComponent<UnityEngine.UI.Image>();
		}

		public override void OnExit()
		{
			interactionComponent.getContextString = null;
			interactionComponent.getInteractability = null;
			interactionComponent.onInteractionBegin = null;
			interactionComponent.shouldShowOnScanner = null;
			interactionComponent.shouldIgnoreSpherecastForInteractability = null;
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			UpdateEnergyIndicator();
		}

		private void UpdateEnergyIndicator()
		{
			energyIndicatorContainer.SetActive(shouldShowEnergy);
			energyIndicator.fillAmount = energyComponent.normalizedEnergy;
		}
	}
	public class EntryState : BaseCaptainSupplyDropState
	{
		public static float baseDuration;

		private float duration;

		protected override bool shouldShowModel => false;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new HitGroundState());
			}
		}
	}
	public class HitGroundState : BaseCaptainSupplyDropState
	{
		public static float baseDuration;

		public static GameObject effectPrefab;

		public static float impactBulletDistance;

		public static float impactBulletRadius;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			if (NetworkServer.active)
			{
				GameObject ownerObject = GetComponent<GenericOwnership>().ownerObject;
				ProjectileDamage component = GetComponent<ProjectileDamage>();
				UnityEngine.Vector3 position = base.transform.position;
				UnityEngine.Vector3 vector = -base.transform.up;
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.origin = position - vector * impactBulletDistance;
				bulletAttack.aimVector = vector;
				bulletAttack.maxDistance = impactBulletDistance + 1f;
				bulletAttack.stopperMask = default(LayerMask);
				bulletAttack.hitMask = LayerIndex.CommonMasks.bullet;
				bulletAttack.damage = component.damage;
				bulletAttack.damageColorIndex = component.damageColorIndex;
				bulletAttack.damageType = component.damageType;
				bulletAttack.bulletCount = 1u;
				bulletAttack.minSpread = 0f;
				bulletAttack.maxSpread = 0f;
				bulletAttack.owner = ownerObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.procCoefficient = 0f;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.isCrit = RollCrit();
				bulletAttack.smartCollision = false;
				bulletAttack.sniper = false;
				bulletAttack.force = component.force;
				bulletAttack.radius = impactBulletRadius;
				bulletAttack.hitEffectPrefab = effectPrefab;
				bulletAttack.Fire();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextState(new DeployState());
			}
		}
	}
	public class DeployState : BaseCaptainSupplyDropState
	{
		public static float baseDuration;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public abstract class BaseMainState : BaseCaptainSupplyDropState
	{
	}
	public class PreDepletionState : BaseCaptainSupplyDropState
	{
	}
	public class DepletionState : BaseCaptainSupplyDropState
	{
	}
	public class PlatingBuffMainState : BaseMainState
	{
		public static int maximumBuffStack;

		public static int buffCountToGrant;

		[SerializeField]
		public float activationCost;

		private static BuffIndex buff => JunkContent.Buffs.BodyArmor.buffIndex;

		protected override bool shouldShowEnergy => true;

		protected override string GetContextString(Interactor activator)
		{
			return Language.GetString("CAPTAIN_SUPPLY_DEFENSE_RESTOCK_INTERACTION");
		}

		protected override Interactability GetInteractability(Interactor activator)
		{
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if (!component)
			{
				return Interactability.Disabled;
			}
			if (energyComponent.energy < activationCost)
			{
				return Interactability.ConditionsNotMet;
			}
			if (component.GetBuffCount(buff) >= maximumBuffStack)
			{
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Available;
		}

		protected override void OnInteractionBegin(Interactor activator)
		{
			CharacterBody component = activator.GetComponent<CharacterBody>();
			for (int i = 0; i < buffCountToGrant; i++)
			{
				if (component.GetBuffCount(buff) >= maximumBuffStack)
				{
					break;
				}
				if (!energyComponent.TakeEnergy(activationCost))
				{
					break;
				}
				component.AddBuff(buff);
			}
		}
	}
	public class EquipmentRestockMainState : BaseMainState
	{
		[SerializeField]
		public float activationCost;

		protected override bool shouldShowEnergy => true;

		protected override string GetContextString(Interactor activator)
		{
			return Language.GetString("CAPTAIN_SUPPLY_EQUIPMENT_RESTOCK_INTERACTION");
		}

		protected override Interactability GetInteractability(Interactor activator)
		{
			CharacterBody component = activator.GetComponent<CharacterBody>();
			RoR2.Inventory inventory;
			if (!component || !(inventory = component.inventory))
			{
				return Interactability.Disabled;
			}
			if (activationCost >= energyComponent.energy)
			{
				return Interactability.ConditionsNotMet;
			}
			if (inventory.GetEquipmentRestockableChargeCount(inventory.activeEquipmentSlot) <= 0)
			{
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Available;
		}

		protected override void OnInteractionBegin(Interactor activator)
		{
			energyComponent.TakeEnergy(activationCost);
			RoR2.Inventory inventory = activator.GetComponent<CharacterBody>().inventory;
			inventory.RestockEquipmentCharges(inventory.activeEquipmentSlot, 1);
		}
	}
	public class HealZoneMainState : BaseMainState
	{
		public static GameObject healZonePrefab;

		private GameObject healZoneInstance;

		protected override Interactability GetInteractability(Interactor activator)
		{
			return Interactability.Disabled;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				healZoneInstance = UnityEngine.Object.Instantiate(healZonePrefab, base.transform.position, base.transform.rotation);
				healZoneInstance.GetComponent<TeamFilter>().teamIndex = teamFilter.teamIndex;
				NetworkServer.Spawn(healZoneInstance);
			}
		}

		public override void OnExit()
		{
			if ((bool)healZoneInstance)
			{
				EntityState.Destroy(healZoneInstance);
			}
			base.OnExit();
		}
	}
	public class ShockZoneMainState : BaseMainState
	{
		public static GameObject shockEffectPrefab;

		public static float shockRadius;

		public static float shockDamageCoefficient;

		public static float shockFrequency;

		private float shockTimer;

		protected override Interactability GetInteractability(Interactor activator)
		{
			return Interactability.Disabled;
		}

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			shockTimer += GetDeltaTime();
			if (shockTimer > 1f / shockFrequency)
			{
				shockTimer -= 1f / shockFrequency;
				Shock();
			}
		}

		private void Shock()
		{
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.radius = shockRadius;
			blastAttack.baseDamage = 0f;
			blastAttack.damageType = DamageType.Silent | DamageType.Shock5s;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.attacker = null;
			blastAttack.teamIndex = teamFilter.teamIndex;
			blastAttack.position = base.transform.position;
			blastAttack.Fire();
			if ((bool)shockEffectPrefab)
			{
				EffectManager.SpawnEffect(shockEffectPrefab, new EffectData
				{
					origin = base.transform.position,
					scale = shockRadius
				}, transmit: false);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class HackingMainState : BaseMainState
	{
		public static float baseRadius = 7f;

		public static float scanInterval = 5f;

		private float radius;

		private float scanTimer;

		private SphereSearch sphereSearch;

		public override void OnEnter()
		{
			base.OnEnter();
			radius = baseRadius;
			if (base.isAuthority)
			{
				sphereSearch = new SphereSearch();
				sphereSearch.origin = base.transform.position;
				sphereSearch.mask = LayerIndex.CommonMasks.interactable;
				sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.Collide;
				sphereSearch.radius = radius;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private PurchaseInteraction ScanForTarget()
		{
			List<Collider> list = CollectionPool<Collider, List<Collider>>.RentCollection();
			sphereSearch.ClearCandidates();
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByColliderEntities();
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctColliderEntities();
			sphereSearch.GetColliders(list);
			PurchaseInteraction result = null;
			int i = 0;
			for (int count = list.Count; i < count; i++)
			{
				PurchaseInteraction component = list[i].GetComponent<EntityLocator>().entity.GetComponent<PurchaseInteraction>();
				if (PurchaseInteractionIsValidTarget(component))
				{
					result = component;
					break;
				}
			}
			CollectionPool<Collider, List<Collider>>.ReturnCollection(list);
			return result;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority)
			{
				return;
			}
			scanTimer -= GetDeltaTime();
			if (scanTimer <= 0f)
			{
				scanTimer = scanInterval;
				PurchaseInteraction purchaseInteraction = ScanForTarget();
				if ((bool)purchaseInteraction)
				{
					outer.SetNextState(new HackingInProgressState
					{
						target = purchaseInteraction
					});
				}
			}
		}

		public static bool PurchaseInteractionIsValidTarget(PurchaseInteraction purchaseInteraction)
		{
			if ((bool)purchaseInteraction)
			{
				if (purchaseInteraction.costType == CostTypeIndex.Money && purchaseInteraction.cost > 0)
				{
					return purchaseInteraction.available;
				}
				return false;
			}
			return false;
		}
	}
	public class HackingInProgressState : BaseMainState
	{
		public static int baseGoldForBaseDuration = 25;

		public static float baseDuration = 15f;

		public static GameObject targetIndicatorVfxPrefab;

		public PurchaseInteraction target;

		private GameObject targetIndicatorVfxInstance;

		private Run.FixedTimeStamp startTime;

		private Run.FixedTimeStamp endTime;

		protected override bool shouldShowEnergy => true;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				int difficultyScaledCost = Run.instance.GetDifficultyScaledCost(baseGoldForBaseDuration, Stage.instance.entryDifficultyCoefficient);
				float num = (float)((double)target.cost / (double)difficultyScaledCost * (double)baseDuration);
				startTime = Run.FixedTimeStamp.now;
				endTime = startTime + num;
			}
			energyComponent.normalizedChargeRate = 1f / (endTime - startTime);
			if (NetworkServer.active)
			{
				energyComponent.energy = 0f;
			}
			if (!targetIndicatorVfxPrefab || !target)
			{
				return;
			}
			targetIndicatorVfxInstance = UnityEngine.Object.Instantiate(targetIndicatorVfxPrefab, target.transform.position, UnityEngine.Quaternion.identity);
			ChildLocator component = targetIndicatorVfxInstance.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("LineEnd");
				if ((bool)transform)
				{
					transform.position = FindModelChild("ShaftTip").position;
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)targetIndicatorVfxInstance)
			{
				EntityState.Destroy(targetIndicatorVfxInstance);
				targetIndicatorVfxInstance = null;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				if (energyComponent.normalizedEnergy >= 1f)
				{
					outer.SetNextState(new UnlockTargetState
					{
						target = target
					});
				}
				else if (!HackingMainState.PurchaseInteractionIsValidTarget(target))
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(target ? target.gameObject : null);
			writer.Write(startTime);
			writer.Write(endTime);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			GameObject gameObject = reader.ReadGameObject();
			target = (gameObject ? gameObject.GetComponent<PurchaseInteraction>() : null);
			startTime = reader.ReadFixedTimeStamp();
			endTime = reader.ReadFixedTimeStamp();
		}
	}
	public class UnlockTargetState : BaseMainState
	{
		public static GameObject unlockEffectPrefab;

		public static float baseDuration;

		public static string soundString;

		public PurchaseInteraction target;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active && (bool)target && target.available)
			{
				target.Networkcost = 0;
				GameObject ownerObject = GetComponent<GenericOwnership>().ownerObject;
				if ((bool)ownerObject)
				{
					Interactor component = ownerObject.GetComponent<Interactor>();
					if ((bool)component)
					{
						component.AttemptInteraction(target.gameObject);
					}
				}
				EffectManager.SpawnEffect(unlockEffectPrefab, new EffectData
				{
					origin = target.transform.position
				}, transmit: true);
			}
			Util.PlaySound(soundString, base.gameObject);
			duration = baseDuration;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			writer.Write(target ? target.gameObject : null);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			GameObject gameObject = reader.ReadGameObject();
			target = (gameObject ? gameObject.GetComponent<PurchaseInteraction>() : null);
		}
	}
}
namespace EntityStates.Captain.Weapon
{
	public class SetupAirstrike : BaseState
	{
		public static SkillDef primarySkillDef;

		public static GameObject crosshairOverridePrefab;

		public static string enterSoundString;

		public static string exitSoundString;

		public static GameObject effectMuzzlePrefab;

		public static string effectMuzzleString;

		public static float baseExitDuration;

		private GenericSkill primarySkillSlot;

		private GameObject effectMuzzleInstance;

		private Animator modelAnimator;

		private float timerSinceComplete;

		private bool beginExit;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private static int PrepAirstrikeHash = Animator.StringToHash("PrepAirstrike");

		private float exitDuration => baseExitDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			primarySkillSlot = (base.skillLocator ? base.skillLocator.primary : null);
			if ((bool)primarySkillSlot)
			{
				primarySkillSlot.SetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(PrepAirstrikeHash, value: true);
			}
			PlayCrossfade("Gesture, Override", PrepAirstrikeHash, 0.1f);
			PlayCrossfade("Gesture, Additive", PrepAirstrikeHash, 0.1f);
			Transform transform = FindModelChild(effectMuzzleString);
			if ((bool)transform)
			{
				effectMuzzleInstance = UnityEngine.Object.Instantiate(effectMuzzlePrefab, transform);
			}
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			Util.PlaySound("Play_captain_shift_active_loop", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if (!primarySkillSlot || primarySkillSlot.stock == 0)
			{
				beginExit = true;
			}
			if (beginExit)
			{
				timerSinceComplete += GetDeltaTime();
				if (timerSinceComplete > exitDuration)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)primarySkillSlot)
			{
				primarySkillSlot.UnsetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			Util.PlaySound(exitSoundString, base.gameObject);
			Util.PlaySound("Stop_captain_shift_active_loop", base.gameObject);
			if ((bool)effectMuzzleInstance)
			{
				EntityState.Destroy(effectMuzzleInstance);
			}
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(PrepAirstrikeHash, value: false);
			}
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}
	}
	public class SetupAirstrikeAlt : BaseState
	{
		public static SkillDef primarySkillDef;

		public static GameObject crosshairOverridePrefab;

		public static string enterSoundString;

		public static string exitSoundString;

		public static GameObject effectMuzzlePrefab;

		public static string effectMuzzleString;

		public static float baseExitDuration;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private GenericSkill primarySkillSlot;

		private GameObject effectMuzzleInstance;

		private Animator modelAnimator;

		private float timerSinceComplete;

		private bool beginExit;

		private static int PrepAirstrikeHash = Animator.StringToHash("PrepAirstrike");

		private float exitDuration => baseExitDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			primarySkillSlot = (base.skillLocator ? base.skillLocator.primary : null);
			if ((bool)primarySkillSlot)
			{
				primarySkillSlot.SetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(PrepAirstrikeHash, value: true);
			}
			PlayCrossfade("Gesture, Override", PrepAirstrikeHash, 0.1f);
			PlayCrossfade("Gesture, Additive", PrepAirstrikeHash, 0.1f);
			Transform transform = FindModelChild(effectMuzzleString);
			if ((bool)transform)
			{
				effectMuzzleInstance = UnityEngine.Object.Instantiate(effectMuzzlePrefab, transform);
			}
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			Util.PlaySound("Play_captain_shift_active_loop", base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if (!primarySkillSlot || primarySkillSlot.stock == 0)
			{
				beginExit = true;
			}
			if (beginExit)
			{
				timerSinceComplete += GetDeltaTime();
				if (timerSinceComplete > exitDuration)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)primarySkillSlot)
			{
				primarySkillSlot.UnsetSkillOverride(this, primarySkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			Util.PlaySound(exitSoundString, base.gameObject);
			Util.PlaySound("Stop_captain_shift_active_loop", base.gameObject);
			if ((bool)effectMuzzleInstance)
			{
				EntityState.Destroy(effectMuzzleInstance);
			}
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(PrepAirstrikeHash, value: false);
			}
			crosshairOverrideRequest?.Dispose();
			base.OnExit();
		}
	}
	public class CallAirstrikeEnter : BaseSkillState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				switch (base.activatorSkillSlot.stock)
				{
				case 2:
					outer.SetNextState(new CallAirstrike1());
					break;
				case 1:
					outer.SetNextState(new CallAirstrike2());
					break;
				case 0:
					outer.SetNextState(new CallAirstrike3());
					break;
				default:
					outer.SetNextState(new CallAirstrike1());
					break;
				}
			}
		}
	}
	public class CallAirstrikeAltEnter : BaseSkillState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				outer.SetNextState(new CallAirstrikeAlt());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class CallAirstrike1 : CallAirstrikeBase
	{
		private static int CallAirstrike1StateHash = Animator.StringToHash("CallAirstrike1");

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void OnExit()
		{
			PlayAnimation("Gesture, Override", CallAirstrike1StateHash);
			PlayAnimation("Gesture, Additive", CallAirstrike1StateHash);
			AddRecoil(0f, 0f, -1f, -1f);
			base.OnExit();
		}
	}
	public class CallAirstrike2 : CallAirstrikeBase
	{
		private static int CallAirstrike2StateHash = Animator.StringToHash("CallAirstrike2");

		public override void OnExit()
		{
			PlayAnimation("Gesture, Override", CallAirstrike2StateHash);
			PlayAnimation("Gesture, Additive", CallAirstrike2StateHash);
			AddRecoil(0f, 0f, 1f, 1f);
			base.OnExit();
		}
	}
	public class CallAirstrike3 : CallAirstrikeBase
	{
		private static int CallAirstrike3StateHash = Animator.StringToHash("CallAirstrike3");

		public override void OnExit()
		{
			PlayAnimation("Gesture, Override", CallAirstrike3StateHash);
			AddRecoil(-2f, -2f, -0.5f, 0.5f);
			base.OnExit();
		}
	}
	public class CallAirstrikeAlt : CallAirstrikeBase
	{
		[SerializeField]
		public float projectileForce;

		private static int CallAirstrike3StateHash = Animator.StringToHash("CallAirstrike3");

		public override void OnExit()
		{
			PlayAnimation("Gesture, Override", CallAirstrike3StateHash);
			PlayAnimation("Gesture, Additive", CallAirstrike3StateHash);
			AddRecoil(-2f, -2f, -0.5f, 0.5f);
			base.OnExit();
		}

		protected override void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo)
		{
			base.ModifyProjectile(ref fireProjectileInfo);
			fireProjectileInfo.force = projectileForce;
		}
	}
	public class CallAirstrikeBase : AimThrowableBase
	{
		[SerializeField]
		public float airstrikeRadius;

		[SerializeField]
		public float bloom;

		public static GameObject muzzleFlashEffect;

		public static string muzzleString;

		public static string fireAirstrikeSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			base.characterBody.SetSpreadBloom(bloom);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterBody.SetAimTimer(4f);
		}

		public override void OnExit()
		{
			Util.PlaySound(fireAirstrikeSoundString, base.gameObject);
			base.OnExit();
		}

		protected override void ModifyProjectile(ref FireProjectileInfo fireProjectileInfo)
		{
			base.ModifyProjectile(ref fireProjectileInfo);
			fireProjectileInfo.position = currentTrajectoryInfo.hitPoint;
			fireProjectileInfo.rotation = UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f);
			fireProjectileInfo.speedOverride = 0f;
		}

		protected override bool KeyIsDown()
		{
			return base.inputBank.skill1.down;
		}

		protected override EntityState PickNextState()
		{
			return new Idle();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SetupSupplyDrop : BaseState
	{
		public struct PlacementInfo
		{
			public bool ok;

			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;

			public void Serialize(NetworkWriter writer)
			{
				writer.Write(ok);
				writer.Write(position);
				writer.Write(rotation);
			}

			public void Deserialize(NetworkReader reader)
			{
				ok = reader.ReadBoolean();
				position = reader.ReadVector3();
				rotation = reader.ReadQuaternion();
			}
		}

		public static GameObject crosshairOverridePrefab;

		public static string enterSoundString;

		public static string exitSoundString;

		public static GameObject effectMuzzlePrefab;

		public static string effectMuzzleString;

		public static float baseExitDuration;

		public static float maxPlacementDistance;

		public static GameObject blueprintPrefab;

		public static float normalYThreshold;

		private PlacementInfo currentPlacementInfo;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		private GenericSkill primarySkillSlot;

		private AimAnimator modelAimAnimator;

		private GameObject effectMuzzleInstance;

		private Animator modelAnimator;

		private float timerSinceComplete;

		private bool beginExit;

		private GenericSkill originalPrimarySkill;

		private GenericSkill originalSecondarySkill;

		private BlueprintController blueprints;

		private CameraTargetParams.AimRequest aimRequest;

		private static int PrepSupplyDropStateHash = Animator.StringToHash("PrepSupplyDrop");

		private float exitDuration => baseExitDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			PlayAnimation("Gesture, Override", PrepSupplyDropStateHash);
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(PrepSupplyDropStateHash, value: true);
			}
			Transform transform = FindModelChild(effectMuzzleString);
			if ((bool)transform)
			{
				effectMuzzleInstance = UnityEngine.Object.Instantiate(effectMuzzlePrefab, transform);
			}
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			Util.PlaySound(enterSoundString, base.gameObject);
			blueprints = UnityEngine.Object.Instantiate(blueprintPrefab, currentPlacementInfo.position, currentPlacementInfo.rotation).GetComponent<BlueprintController>();
			if ((bool)base.cameraTargetParams)
			{
				aimRequest = base.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			originalPrimarySkill = base.skillLocator.primary;
			originalSecondarySkill = base.skillLocator.secondary;
			base.skillLocator.primary = base.skillLocator.FindSkill("SupplyDrop1");
			base.skillLocator.secondary = base.skillLocator.FindSkill("SupplyDrop2");
		}

		public override void Update()
		{
			base.Update();
			currentPlacementInfo = GetPlacementInfo(GetAimRay(), base.gameObject);
			if ((bool)blueprints)
			{
				blueprints.PushState(currentPlacementInfo.position, currentPlacementInfo.rotation, currentPlacementInfo.ok);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if (base.isAuthority && beginExit)
			{
				timerSinceComplete += GetDeltaTime();
				if (timerSinceComplete > exitDuration)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				Util.PlaySound(exitSoundString, base.gameObject);
			}
			if ((bool)effectMuzzleInstance)
			{
				EntityState.Destroy(effectMuzzleInstance);
			}
			crosshairOverrideRequest?.Dispose();
			base.skillLocator.primary = originalPrimarySkill;
			base.skillLocator.secondary = originalSecondarySkill;
			if ((bool)modelAnimator)
			{
				modelAnimator.SetBool(PrepSupplyDropStateHash, value: false);
			}
			if ((bool)blueprints)
			{
				EntityState.Destroy(blueprints.gameObject);
				blueprints = null;
			}
			aimRequest?.Dispose();
			base.OnExit();
		}

		public static PlacementInfo GetPlacementInfo(Ray aimRay, GameObject gameObject)
		{
			float extraRaycastDistance = 0f;
			CameraRigController.ModifyAimRayIfApplicable(aimRay, gameObject, out extraRaycastDistance);
			UnityEngine.Vector3 vector = -aimRay.direction;
			UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up;
			UnityEngine.Vector3 lhs = UnityEngine.Vector3.Cross(vector2, vector);
			PlacementInfo result = default(PlacementInfo);
			result.ok = false;
			if (Physics.Raycast(aimRay, out var hitInfo, maxPlacementDistance, LayerIndex.world.mask) && hitInfo.normal.y > normalYThreshold)
			{
				vector2 = hitInfo.normal;
				vector = UnityEngine.Vector3.Cross(lhs, vector2);
				result.ok = true;
			}
			result.rotation = Util.QuaternionSafeLookRotation(vector, vector2);
			UnityEngine.Vector3 point = hitInfo.point;
			result.position = point;
			return result;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class CallSupplyDropBase : BaseSkillState
	{
		[SerializeField]
		public GameObject muzzleflashEffect;

		[SerializeField]
		public GameObject supplyDropPrefab;

		public static string muzzleString;

		public static float baseDuration;

		public static float impactDamageCoefficient;

		public static float impactDamageForce;

		public SetupSupplyDrop.PlacementInfo placementInfo;

		private static int CallSupplyDropStateHash = Animator.StringToHash("CallSupplyDrop");

		private static int CallSupplyDropParamHash = Animator.StringToHash("CallSupplyDrop.playbackRate");

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		private float duration => baseDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.isAuthority)
			{
				placementInfo = SetupSupplyDrop.GetPlacementInfo(GetAimRay(), base.gameObject);
				if (placementInfo.ok)
				{
					base.activatorSkillSlot.DeductStock(1);
				}
			}
			if (placementInfo.ok)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffect, base.gameObject, muzzleString, transmit: false);
				base.characterBody.SetAimTimer(3f);
				PlayAnimation("Gesture, Additive", CallSupplyDropStateHash, CallSupplyDropParamHash, duration);
				PlayAnimation("Gesture, Override", CallSupplyDropStateHash, CallSupplyDropParamHash, duration);
				if (NetworkServer.active)
				{
					GameObject obj = UnityEngine.Object.Instantiate(supplyDropPrefab, placementInfo.position, placementInfo.rotation);
					obj.GetComponent<TeamFilter>().teamIndex = base.teamComponent.teamIndex;
					obj.GetComponent<GenericOwnership>().ownerObject = base.gameObject;
					Deployable component = obj.GetComponent<Deployable>();
					if ((bool)component && (bool)base.characterBody.master)
					{
						base.characterBody.master.AddDeployable(component, DeployableSlot.CaptainSupplyDrop);
					}
					ProjectileDamage component2 = obj.GetComponent<ProjectileDamage>();
					component2.crit = RollCrit();
					component2.damage = damageStat * impactDamageCoefficient;
					component2.damageColorIndex = DamageColorIndex.Default;
					component2.force = impactDamageForce;
					component2.damageType = DamageType.Generic;
					NetworkServer.Spawn(obj);
				}
			}
			else
			{
				PlayCrossfade("Gesture, Additive", BufferEmptyStateHash, 0.1f);
				PlayCrossfade("Gesture, Additive", BufferEmptyStateHash, 0.1f);
			}
			EntityStateMachine entityStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Skillswap");
			if ((bool)entityStateMachine)
			{
				entityStateMachine.SetNextStateToMain();
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			placementInfo.Serialize(writer);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			placementInfo.Deserialize(reader);
		}
	}
	public class CallSupplyDropHealing : CallSupplyDropBase
	{
	}
	public class CallSupplyDropPlating : CallSupplyDropBase
	{
	}
	public class CallSupplyDropEquipmentRestock : CallSupplyDropBase
	{
	}
	public class CallSupplyDropForce : CallSupplyDropBase
	{
	}
	public class CallSupplyDropHacking : CallSupplyDropBase
	{
	}
	public class CallSupplyDropShocking : CallSupplyDropBase
	{
	}
	public class ChargeCaptainShotgun : BaseState
	{
		public static float baseMinChargeDuration;

		public static float baseChargeDuration;

		public static string muzzleName;

		public static GameObject chargeupVfxPrefab;

		public static GameObject holdChargeVfxPrefab;

		public static string enterSoundString;

		public static string playChargeSoundString;

		public static string stopChargeSoundString;

		private float minChargeDuration;

		private float chargeDuration;

		private bool released;

		private GameObject chargeupVfxGameObject;

		private GameObject holdChargeVfxGameObject;

		private Transform muzzleTransform;

		private uint enterSoundID;

		public override void OnEnter()
		{
			base.OnEnter();
			minChargeDuration = baseMinChargeDuration / attackSpeedStat;
			chargeDuration = baseChargeDuration / attackSpeedStat;
			PlayCrossfade("Gesture, Override", "ChargeCaptainShotgun", "ChargeCaptainShotgun.playbackRate", chargeDuration, 0.1f);
			PlayCrossfade("Gesture, Additive", "ChargeCaptainShotgun", "ChargeCaptainShotgun.playbackRate", chargeDuration, 0.1f);
			muzzleTransform = FindModelChild(muzzleName);
			if ((bool)muzzleTransform)
			{
				chargeupVfxGameObject = UnityEngine.Object.Instantiate(chargeupVfxPrefab, muzzleTransform);
				chargeupVfxGameObject.GetComponent<ScaleParticleSystemDuration>().newDuration = chargeDuration;
			}
			enterSoundID = Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
			Util.PlaySound(playChargeSoundString, base.gameObject);
		}

		public override void OnExit()
		{
			if ((bool)chargeupVfxGameObject)
			{
				EntityState.Destroy(chargeupVfxGameObject);
				chargeupVfxGameObject = null;
			}
			if ((bool)holdChargeVfxGameObject)
			{
				EntityState.Destroy(holdChargeVfxGameObject);
				holdChargeVfxGameObject = null;
			}
			AkSoundEngine.StopPlayingID(enterSoundID);
			Util.PlaySound(stopChargeSoundString, base.gameObject);
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
			base.characterBody.SetSpreadBloom(base.age / chargeDuration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.characterBody.SetAimTimer(1f);
			Mathf.Clamp01(base.fixedAge / chargeDuration);
			if (base.fixedAge >= chargeDuration)
			{
				if ((bool)chargeupVfxGameObject)
				{
					EntityState.Destroy(chargeupVfxGameObject);
					chargeupVfxGameObject = null;
				}
				if (!holdChargeVfxGameObject && (bool)muzzleTransform)
				{
					holdChargeVfxGameObject = UnityEngine.Object.Instantiate(holdChargeVfxPrefab, muzzleTransform);
				}
			}
			if (base.isAuthority)
			{
				if (!released && (!base.inputBank || !base.inputBank.skill1.down))
				{
					released = true;
				}
				if (released)
				{
					outer.SetNextState(new FireCaptainShotgun());
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireCaptainShotgun : GenericBulletBaseState
	{
		public static float tightSoundSwitchThreshold;

		public static string wideSoundString;

		public static string tightSoundString;

		private static int FireCaptainShotgunStateHash = Animator.StringToHash("FireCaptainShotgun");

		public override void OnEnter()
		{
			fireSoundString = ((base.characterBody.spreadBloomAngle <= tightSoundSwitchThreshold) ? tightSoundString : wideSoundString);
			base.OnEnter();
			PlayAnimation("Gesture, Additive", FireCaptainShotgunStateHash);
			PlayAnimation("Gesture, Override", FireCaptainShotgunStateHash);
		}

		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireTazer : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject muzzleflashEffectPrefab;

		public static GameObject chargeEffectPrefab;

		public static float baseDelay = 0.1f;

		public static float baseDuration = 2f;

		public static float baseDurationUntilPriorityLowers = 1f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static string enterSoundString;

		public static string attackString;

		public static float recoilAmplitude;

		public static float bloom;

		public static string targetMuzzle;

		private float duration;

		private float delay;

		private float durationUntilPriorityLowers;

		private static int FireTazerStateHash = Animator.StringToHash("FireTazer");

		private static int FireTazerParamHash = Animator.StringToHash("FireTazer.playbackRate");

		private bool hasFired;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			durationUntilPriorityLowers = baseDurationUntilPriorityLowers / attackSpeedStat;
			delay = baseDelay / attackSpeedStat;
			StartAimMode(duration + 2f);
			if ((bool)chargeEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(chargeEffectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
			PlayAnimation("Gesture, Additive", FireTazerStateHash, FireTazerParamHash, duration);
			PlayAnimation("Gesture, Override", FireTazerStateHash, FireTazerParamHash, duration);
		}

		private void Fire()
		{
			hasFired = true;
			Util.PlaySound(attackString, base.gameObject);
			AddRecoil(-1f * recoilAmplitude, -1.5f * recoilAmplitude, -0.25f * recoilAmplitude, 0.25f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(bloom);
			Ray ray = GetAimRay();
			if ((bool)muzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, targetMuzzle, transmit: false);
			}
			if (base.isAuthority)
			{
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.position = ray.origin;
				fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction);
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.damage = damageStat * damageCoefficient;
				fireProjectileInfo.force = force;
				fireProjectileInfo.crit = Util.CheckRoll(critStat, base.characterBody.master);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= delay && !hasFired)
			{
				Fire();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge > durationUntilPriorityLowers))
			{
				return InterruptPriority.PrioritySkill;
			}
			return InterruptPriority.Any;
		}
	}
}
namespace EntityStates.CaptainDefenseMatrixItem
{
	public class DefenseMatrixOn : BaseBodyAttachmentState
	{
		public static float projectileEraserRadius;

		public static float minimumFireFrequency;

		public static float baseRechargeFrequency;

		public static GameObject tracerEffectPrefab;

		private float rechargeTimer;

		private float rechargeFrequency => baseRechargeFrequency * (base.attachedBody ? base.attachedBody.attackSpeed : 1f);

		private float fireFrequency => Mathf.Max(minimumFireFrequency, rechargeFrequency);

		private float timeBetweenFiring => 1f / fireFrequency;

		private bool isReadyToFire => rechargeTimer <= 0f;

		protected int GetItemStack()
		{
			if (!base.attachedBody || !base.attachedBody.inventory)
			{
				return 1;
			}
			return base.attachedBody.inventory.GetItemCount(RoR2Content.Items.CaptainDefenseMatrix);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if (!base.attachedBody)
			{
				return;
			}
			PlayerCharacterMasterController component = base.attachedBody.master.GetComponent<PlayerCharacterMasterController>();
			if ((bool)component)
			{
				NetworkUser networkUser = component.networkUser;
				if ((bool)networkUser)
				{
					PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(RoR2Content.Items.CaptainDefenseMatrix.itemIndex);
					networkUser.localUser?.userProfile.DiscoverPickup(pickupIndex);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!NetworkServer.active)
			{
				return;
			}
			rechargeTimer -= GetDeltaTime();
			if (base.fixedAge > timeBetweenFiring)
			{
				base.fixedAge -= timeBetweenFiring;
				if (isReadyToFire && DeleteNearbyProjectile())
				{
					rechargeTimer = 1f / rechargeFrequency;
				}
			}
		}

		private bool DeleteNearbyProjectile()
		{
			UnityEngine.Vector3 vector = (base.attachedBody ? base.attachedBody.corePosition : UnityEngine.Vector3.zero);
			TeamIndex teamIndex = (base.attachedBody ? base.attachedBody.teamComponent.teamIndex : TeamIndex.None);
			float num = projectileEraserRadius * projectileEraserRadius;
			int num2 = 0;
			int itemStack = GetItemStack();
			bool result = false;
			List<ProjectileController> instancesList = InstanceTracker.GetInstancesList<ProjectileController>();
			List<ProjectileController> list = new List<ProjectileController>();
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				if (num2 >= itemStack)
				{
					break;
				}
				ProjectileController projectileController = instancesList[i];
				if (!projectileController.cannotBeDeleted && projectileController.teamFilter.teamIndex != teamIndex && (projectileController.transform.position - vector).sqrMagnitude < num)
				{
					list.Add(projectileController);
					num2++;
				}
			}
			int j = 0;
			for (int count2 = list.Count; j < count2; j++)
			{
				ProjectileController projectileController2 = list[j];
				if ((bool)projectileController2)
				{
					result = true;
					UnityEngine.Vector3 position = projectileController2.transform.position;
					UnityEngine.Vector3 start = vector;
					if ((bool)tracerEffectPrefab)
					{
						EffectData effectData = new EffectData
						{
							origin = position,
							start = start
						};
						EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
					}
					EntityState.Destroy(projectileController2.gameObject);
				}
			}
			return result;
		}
	}
}
namespace EntityStates.BrotherMonster
{
	public class SkyLeapDeathState : GenericCharacterDeath
	{
		public static float baseDuration;

		private float duration;

		private static int SkyLeapStateHash = Animator.StringToHash("EnterSkyLeap");

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate");

		protected override bool shouldAutoDestroy => false;

		public override void OnEnter()
		{
			duration = baseDuration / attackSpeedStat;
			base.OnEnter();
		}

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayAnimation("Body", SkyLeapStateHash, SkyLeapParamHash, duration);
			PlayAnimation("FullBody Override", BufferEmptyStateHash);
			base.characterDirection.moveVector = base.characterDirection.forward;
			AimAnimator aimAnimator = GetAimAnimator();
			if ((bool)aimAnimator)
			{
				aimAnimator.enabled = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				DestroyBodyAsapServer();
			}
		}
	}
	public class InstantDeathState : GenericCharacterDeath
	{
		public static GameObject deathEffectPrefab;

		protected override bool shouldAutoDestroy => false;

		public override void OnEnter()
		{
			base.OnEnter();
			DestroyModel();
			if (NetworkServer.active)
			{
				DestroyBodyAsapServer();
			}
		}

		protected override void CreateDeathEffects()
		{
			base.CreateDeathEffects();
			EffectManager.SimpleMuzzleFlash(deathEffectPrefab, base.gameObject, "MuzzleCenter", transmit: false);
		}
	}
	public class TrueDeathState : GenericCharacterDeath
	{
		public static float durationBeforeDissolving;

		public static float dissolveDuration;

		public static GameObject deathEffectPrefab;

		private static int TrueDeathStateHash = Animator.StringToHash("TrueDeath");

		private bool dissolving;

		protected override bool shouldAutoDestroy => base.fixedAge > durationBeforeDissolving + dissolveDuration + 1f;

		public override void OnEnter()
		{
			base.OnEnter();
			if (NetworkServer.active)
			{
				Util.CleanseBody(base.characterBody, removeDebuffs: true, removeBuffs: true, removeCooldownBuffs: true, removeDots: true, removeStun: false, removeNearbyProjectiles: false);
				ReturnStolenItemsOnGettingHit component = GetComponent<ReturnStolenItemsOnGettingHit>();
				if ((bool)component && (bool)component.itemStealController)
				{
					EntityState.Destroy(component.itemStealController.gameObject);
				}
			}
		}

		protected override void PlayDeathAnimation(float crossfadeDuration = 0.1f)
		{
			PlayAnimation("FullBody Override", TrueDeathStateHash);
			base.characterDirection.moveVector = base.characterDirection.forward;
			EffectManager.SimpleMuzzleFlash(deathEffectPrefab, base.gameObject, "MuzzleCenter", transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= durationBeforeDissolving)
			{
				Dissolve();
			}
		}

		private void Dissolve()
		{
			if (!dissolving)
			{
				dissolving = true;
				Transform modelTransform = GetModelTransform();
				if ((bool)modelTransform)
				{
					modelTransform.gameObject.GetComponent<CharacterModel>();
					PrintController component = base.modelLocator.modelTransform.gameObject.GetComponent<PrintController>();
					component.enabled = false;
					component.printTime = dissolveDuration;
					component.enabled = true;
				}
				Transform transform = FindModelChild("TrueDeathEffect");
				if ((bool)transform)
				{
					transform.gameObject.SetActive(value: true);
					transform.GetComponent<ScaleParticleSystemDuration>().newDuration = dissolveDuration;
				}
			}
		}
	}
	public class FistSlam : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float upwardForce;

		public static float radius = 3f;

		public static string attackSoundString;

		public static string muzzleString;

		public static float healthCostFraction;

		public static GameObject chargeEffectPrefab;

		public static GameObject slamImpactEffect;

		public static GameObject waveProjectilePrefab;

		public static int waveProjectileCount;

		public static float waveProjectileDamageCoefficient;

		public static float waveProjectileForce;

		private BlastAttack attack;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasAttacked;

		private float duration;

		private GameObject chargeInstance;

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			PlayCrossfade("FullBody Override", "FistSlam", "FistSlam.playbackRate", duration, 0.1f);
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = true;
				}
			}
			Transform transform = FindModelChild("MuzzleRight");
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				chargeInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				chargeInstance.transform.parent = transform;
				ScaleParticleSystemDuration component2 = chargeInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component2)
				{
					component2.newDuration = duration / 2.8f;
				}
			}
		}

		public override void OnExit()
		{
			if ((bool)chargeInstance)
			{
				EntityState.Destroy(chargeInstance);
			}
			PlayAnimation("FullBody Override", BufferEmptyStateHash);
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && modelAnimator.GetFloat("fist.hitBoxActive") > 0.5f && !hasAttacked)
			{
				if ((bool)chargeInstance)
				{
					EntityState.Destroy(chargeInstance);
				}
				EffectManager.SimpleMuzzleFlash(slamImpactEffect, base.gameObject, muzzleString, transmit: false);
				if (NetworkServer.active && (bool)base.healthComponent)
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = base.healthComponent.combinedHealth * healthCostFraction;
					damageInfo.position = base.characterBody.corePosition;
					damageInfo.force = UnityEngine.Vector3.zero;
					damageInfo.damageColorIndex = DamageColorIndex.Default;
					damageInfo.crit = false;
					damageInfo.attacker = null;
					damageInfo.inflictor = null;
					damageInfo.damageType = DamageType.NonLethal | DamageType.BypassArmor;
					damageInfo.procCoefficient = 0f;
					damageInfo.procChainMask = default(ProcChainMask);
					base.healthComponent.TakeDamage(damageInfo);
				}
				if (base.isAuthority)
				{
					if ((bool)modelTransform)
					{
						Transform transform = FindModelChild(muzzleString);
						if ((bool)transform)
						{
							attack = new BlastAttack();
							attack.attacker = base.gameObject;
							attack.inflictor = base.gameObject;
							attack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
							attack.baseDamage = damageStat * damageCoefficient;
							attack.baseForce = forceMagnitude;
							attack.position = transform.position;
							attack.radius = radius;
							attack.bonusForce = new UnityEngine.Vector3(0f, upwardForce, 0f);
							attack.Fire();
						}
					}
					float num = 360f / (float)waveProjectileCount;
					UnityEngine.Vector3 vector = UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up);
					UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
					for (int i = 0; i < waveProjectileCount; i++)
					{
						UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * vector;
						ProjectileManager.instance.FireProjectile(waveProjectilePrefab, footPosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master));
					}
				}
				hasAttacked = true;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class EnterSkyLeap : BaseState
	{
		public static float baseDuration;

		public static string soundString;

		private float duration;

		private static int EnterSkyLeapStateHash = Animator.StringToHash("EnterSkyLeap");

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(soundString, base.gameObject);
			PlayAnimation("Body", EnterSkyLeapStateHash, SkyLeapParamHash, duration);
			PlayAnimation("FullBody Override", BufferEmptyStateHash);
			base.characterDirection.moveVector = base.characterDirection.forward;
			base.characterBody.AddTimedBuff(RoR2Content.Buffs.ArmorBoost, baseDuration);
			AimAnimator aimAnimator = GetAimAnimator();
			if ((bool)aimAnimator)
			{
				aimAnimator.enabled = true;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextState(new HoldSkyLeap());
			}
		}
	}
	public class ExitSkyLeap : BaseState
	{
		public static float baseDuration;

		public static float baseDurationUntilRecastInterrupt;

		public static string soundString;

		public static GameObject waveProjectilePrefab;

		public static int waveProjectileCount;

		public static float waveProjectileDamageCoefficient;

		public static float waveProjectileForce;

		public static float recastChance;

		public static int cloneCount;

		public static int cloneDuration;

		public static SkillDef replacementSkillDef;

		private float duration;

		private float durationUntilRecastInterrupt;

		private bool recast;

		private static int ExitSkyLeapStateHash = Animator.StringToHash("ExitSkyLeap");

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Util.PlaySound(soundString, base.gameObject);
			PlayAnimation("Body", ExitSkyLeapStateHash, SkyLeapParamHash, duration);
			PlayAnimation("FullBody Override", BufferEmptyStateHash);
			base.characterBody.AddTimedBuff(RoR2Content.Buffs.ArmorBoost, baseDuration);
			AimAnimator aimAnimator = GetAimAnimator();
			if ((bool)aimAnimator)
			{
				aimAnimator.enabled = true;
			}
			if (base.isAuthority)
			{
				FireRingAuthority();
			}
			if (!PhaseCounter.instance || PhaseCounter.instance.phase != 3)
			{
				return;
			}
			if (UnityEngine.Random.value < recastChance)
			{
				recast = true;
			}
			for (int i = 0; i < cloneCount; i++)
			{
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/CharacterSpawnCards/cscBrotherGlass"), new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Approximate,
					minDistance = 3f,
					maxDistance = 20f,
					spawnOnTarget = base.gameObject.transform
				}, RoR2Application.rng);
				directorSpawnRequest.summonerBodyObject = base.gameObject;
				directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult spawnResult)
				{
					spawnResult.spawnedInstance.GetComponent<RoR2.Inventory>().GiveItem(RoR2Content.Items.HealthDecay, cloneDuration);
				});
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			}
			GenericSkill genericSkill = (base.skillLocator ? base.skillLocator.special : null);
			if ((bool)genericSkill)
			{
				genericSkill.SetSkillOverride(outer, UltChannelState.replacementSkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
		}

		private void FireRingAuthority()
		{
			float num = 360f / (float)waveProjectileCount;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.ProjectOnPlane(base.inputBank.aimDirection, UnityEngine.Vector3.up);
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			for (int i = 0; i < waveProjectileCount; i++)
			{
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * vector;
				if (base.isAuthority)
				{
					ProjectileManager.instance.FireProjectile(waveProjectilePrefab, footPosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master));
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				if (recast && base.fixedAge > baseDurationUntilRecastInterrupt)
				{
					outer.SetNextState(new EnterSkyLeap());
				}
				if (base.fixedAge > duration)
				{
					outer.SetNextStateToMain();
				}
			}
		}
	}
	public class HoldSkyLeap : BaseState
	{
		public static float duration;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private int originalLayer;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
			}
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount++;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			base.characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			Util.PlaySound("Play_moonBrother_phaseJump_land_preWhoosh", base.gameObject);
			originalLayer = base.gameObject.layer;
			base.gameObject.layer = LayerIndex.GetAppropriateFakeLayerForTeam(base.teamComponent.teamIndex).intVal;
			base.characterMotor.Motor.RebuildCollidableLayers();
			if (!SceneInfo.instance)
			{
				return;
			}
			ChildLocator component = SceneInfo.instance.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("CenterOfArena");
				if ((bool)transform)
				{
					base.characterMotor.Motor.SetPositionAndRotation(transform.position, UnityEngine.Quaternion.identity);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextState(new ExitSkyLeap());
			}
		}

		public override void OnExit()
		{
			if ((bool)characterModel)
			{
				characterModel.invisibilityCount--;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			base.characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
			base.gameObject.layer = originalLayer;
			base.characterMotor.Motor.RebuildCollidableLayers();
			base.OnExit();
		}
	}
	public class BaseSlideState : BaseState
	{
		public static float duration;

		public static AnimationCurve speedCoefficientCurve;

		public static AnimationCurve jumpforwardSpeedCoefficientCurve;

		public static string soundString;

		public static GameObject slideEffectPrefab;

		public static string slideEffectMuzzlestring;

		protected UnityEngine.Vector3 slideVector;

		protected UnityEngine.Quaternion slideRotation;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(soundString, base.gameObject);
			if ((bool)base.inputBank)
			{
				_ = (bool)base.characterDirection;
			}
			if (NetworkServer.active)
			{
				Util.CleanseBody(base.characterBody, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: false, removeDots: false, removeStun: false, removeNearbyProjectiles: false);
			}
			if ((bool)slideEffectPrefab && (bool)base.characterBody)
			{
				UnityEngine.Vector3 position = base.characterBody.corePosition;
				UnityEngine.Quaternion rotation = UnityEngine.Quaternion.identity;
				Transform transform = FindModelChild(slideEffectMuzzlestring);
				if ((bool)transform)
				{
					position = transform.position;
				}
				if ((bool)base.characterDirection)
				{
					rotation = Util.QuaternionSafeLookRotation(slideRotation * base.characterDirection.forward, UnityEngine.Vector3.up);
				}
				EffectManager.SimpleEffect(slideEffectPrefab, position, rotation, transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
				if ((bool)base.inputBank && (bool)base.characterDirection)
				{
					vector = base.characterDirection.forward;
				}
				if ((bool)base.characterMotor)
				{
					float num = speedCoefficientCurve.Evaluate(base.fixedAge / duration);
					base.characterMotor.rootMotion += slideRotation * (num * moveSpeedStat * vector * GetDeltaTime());
				}
				if (base.fixedAge >= duration)
				{
					outer.SetNextStateToMain();
				}
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				PlayImpactAnimation();
			}
			base.OnExit();
		}

		private void PlayImpactAnimation()
		{
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SlideIntroState : BaseState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			bool flag = false;
			if ((bool)base.inputBank && base.isAuthority)
			{
				UnityEngine.Vector3 normalized = ((base.inputBank.moveVector == UnityEngine.Vector3.zero) ? base.characterDirection.forward : base.inputBank.moveVector).normalized;
				UnityEngine.Vector3 forward = base.characterDirection.forward;
				UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward);
				float num = UnityEngine.Vector3.Dot(normalized, forward);
				float num2 = UnityEngine.Vector3.Dot(normalized, rhs);
				if ((bool)base.characterDirection)
				{
					base.characterDirection.moveVector = base.inputBank.aimDirection;
				}
				if (Mathf.Abs(num2) > Mathf.Abs(num))
				{
					if (num2 <= 0f)
					{
						flag = true;
						outer.SetNextState(new SlideLeftState());
					}
					else
					{
						flag = true;
						outer.SetNextState(new SlideRightState());
					}
				}
				else if (num <= 0f)
				{
					flag = true;
					outer.SetNextState(new SlideBackwardState());
				}
				else
				{
					flag = true;
					outer.SetNextState(new SlideForwardState());
				}
			}
			if (!flag)
			{
				outer.SetNextState(new SlideForwardState());
			}
		}
	}
	public class SlideLeftState : BaseSlideState
	{
		public override void OnEnter()
		{
			slideRotation = UnityEngine.Quaternion.AngleAxis(-90f, UnityEngine.Vector3.up);
			base.OnEnter();
			PlayCrossfade("FullBody Override", "SlideLeft", "Slide.playbackRate", BaseSlideState.duration, 0.05f);
		}
	}
	public class SlideRightState : BaseSlideState
	{
		public override void OnEnter()
		{
			slideRotation = UnityEngine.Quaternion.AngleAxis(90f, UnityEngine.Vector3.up);
			base.OnEnter();
			PlayCrossfade("FullBody Override", "SlideRight", "Slide.playbackRate", BaseSlideState.duration, 0.05f);
		}
	}
	public class SlideForwardState : BaseSlideState
	{
		public override void OnEnter()
		{
			slideRotation = UnityEngine.Quaternion.identity;
			base.OnEnter();
			PlayCrossfade("FullBody Override", "SlideForward", "Slide.playbackRate", BaseSlideState.duration, 0.05f);
			PlayCrossfade("Body", "Run", 0.05f);
		}

		public override void OnExit()
		{
			base.OnExit();
		}
	}
	public class SlideBackwardState : BaseSlideState
	{
		public override void OnEnter()
		{
			slideRotation = UnityEngine.Quaternion.AngleAxis(-180f, UnityEngine.Vector3.up);
			base.OnEnter();
			PlayCrossfade("FullBody Override", "SlideBackward", "Slide.playbackRate", BaseSlideState.duration, 0.05f);
		}
	}
	public class SkySpawnState : BaseState
	{
		public static float duration;

		public static string soundString;

		private static int ExitSkyLeapStateHash = Animator.StringToHash("ExitSkyLeap");

		private static int BufferEmptyLeapStateHash = Animator.StringToHash("BufferEmpty");

		private static int SkyLeapParamHash = Animator.StringToHash("SkyLeap.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", ExitSkyLeapStateHash, SkyLeapParamHash, duration);
			PlayAnimation("FullBody Override", BufferEmptyLeapStateHash);
			Util.PlaySound(soundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class ThroneSpawnState : BaseState
	{
		public static GameObject spawnEffectPrefab;

		public static string muzzleString;

		public static float initialDelay;

		public static float duration;

		private bool hasPlayedAnimation;

		private static int ThroneStateHash = Animator.StringToHash("Throne");

		private static int ThroneToIdleStateHash = Animator.StringToHash("ThroneToIdle");

		private static int BufferEmptyStateHash = Animator.StringToHash("BufferEmpty");

		private static int ThroneToIdleParamHash = Animator.StringToHash("ThroneToIdle.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", ThroneStateHash);
			PlayAnimation("FullBody Override", BufferEmptyStateHash);
			EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, muzzleString, transmit: false);
		}

		private void PlayAnimation()
		{
			hasPlayedAnimation = true;
			PlayAnimation("Body", ThroneToIdleStateHash, ThroneToIdleParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > initialDelay && !hasPlayedAnimation)
			{
				PlayAnimation();
			}
			if (base.fixedAge > initialDelay + duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
	public class SpellBaseState : BaseState
	{
		protected ItemStealController itemStealController;

		protected GameObject hammerRendererObject;

		protected virtual bool DisplayWeapon => false;

		public override void OnEnter()
		{
			base.OnEnter();
			FindItemStealer();
			if (NetworkServer.active && !itemStealController)
			{
				InitItemStealer();
			}
			hammerRendererObject = FindModelChild("HammerRenderer").gameObject;
			if ((bool)hammerRendererObject)
			{
				hammerRendererObject.SetActive(DisplayWeapon);
			}
		}

		public override void OnExit()
		{
			if ((bool)hammerRendererObject)
			{
				hammerRendererObject.SetActive(value: false);
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			FindItemStealer();
		}

		private void FindItemStealer()
		{
			if ((bool)itemStealController)
			{
				return;
			}
			List<NetworkedBodyAttachment> list = new List<NetworkedBodyAttachment>();
			NetworkedBodyAttachment.FindBodyAttachments(base.characterBody, list);
			foreach (NetworkedBodyAttachment item in list)
			{
				itemStealController = item.GetComponent<ItemStealController>();
				if ((bool)itemStealController)
				{
					break;
				}
			}
		}

		private void InitItemStealer()
		{
			if (NetworkServer.active && itemStealController == null)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/ItemStealController"), base.transform.position, UnityEngine.Quaternion.identity);
				itemStealController = gameObject.GetComponent<ItemStealController>();
				itemStealController.itemLendFilter = ItemStealController.BrotherItemFilter;
				gameObject.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.gameObject);
				base.gameObject.GetComponent<ReturnStolenItemsOnGettingHit>().itemStealController = itemStealController;
				NetworkServer.Spawn(gameObject);
			}
		}
	}
	public class SpellChannelEnterState : SpellBaseState
	{
		public static GameObject channelBeginEffectPrefab;

		public static float duration;

		private Transform trueDeathEffect;

		private static int SpellChannerEnterStateHash = Animator.StringToHash("SpellChannelEnter");

		private static int SpellChannelEnterParamHash = Animator.StringToHash("SpellChannelEnter.playbackRate");

		protected override bool DisplayWeapon => false;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpellChannerEnterStateHash, SpellChannelEnterParamHash, duration);
			Util.PlaySound("Play_moonBrother_phase4_transition", base.gameObject);
			trueDeathEffect = FindModelChild("TrueDeathEffect");
			if ((bool)trueDeathEffect)
			{
				trueDeathEffect.gameObject.SetActive(value: true);
				trueDeathEffect.GetComponent<ScaleParticleSystemDuration>().newDuration = 10f;
			}
			HurtBoxGroup component = GetModelTransform().GetComponent<HurtBoxGroup>();
			if ((bool)component)
			{
				int hurtBoxesDeactivatorCounter = component.hurtBoxesDeactivatorCounter + 1;
				component.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextState(new SpellChannelState());
			}
		}

		public override void OnExit()
		{
			HurtBoxGroup component = GetModelTransform().GetComponent<HurtBoxGroup>();
			if ((bool)component)
			{
				int hurtBoxesDeactivatorCounter = component.hurtBoxesDeactivatorCounter - 1;
				component.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)channelBeginEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(channelBeginEffectPrefab, base.gameObject, "SpellChannel", transmit: false);
			}
			if ((bool)trueDeathEffect)
			{
				trueDeathEffect.gameObject.SetActive(value: false);
			}
			base.OnExit();
		}
	}
	public class SpellChannelState : SpellBaseState
	{
		public static float stealInterval;

		public static float delayBeforeBeginningSteal;

		public static float maxDuration;

		public static GameObject channelEffectPrefab;

		private bool hasBegunSteal;

		private GameObject channelEffectInstance;

		private Transform spellChannelChildTransform;

		private bool hasSubscribedToStealFinish;

		private static int SpellChannelStateHash = Animator.StringToHash("SpellChannel");

		protected override bool DisplayWeapon => false;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpellChannelStateHash);
			Util.PlaySound("Play_moonBrother_phase4_itemSuck_start", base.gameObject);
			spellChannelChildTransform = FindModelChild("SpellChannel");
			if ((bool)spellChannelChildTransform)
			{
				channelEffectInstance = UnityEngine.Object.Instantiate(channelEffectPrefab, spellChannelChildTransform.position, UnityEngine.Quaternion.identity, spellChannelChildTransform);
			}
			base.characterBody.AddBuff(RoR2Content.Buffs.Immune);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!itemStealController)
			{
				return;
			}
			if (!hasSubscribedToStealFinish && base.isAuthority)
			{
				hasSubscribedToStealFinish = true;
				if (NetworkServer.active)
				{
					itemStealController.onStealFinishServer.AddListener(OnStealEndAuthority);
				}
				else
				{
					itemStealController.onStealFinishClient += OnStealEndAuthority;
				}
			}
			if (NetworkServer.active && base.fixedAge > delayBeforeBeginningSteal && !hasBegunSteal)
			{
				hasBegunSteal = true;
				itemStealController.stealInterval = stealInterval;
				TeamIndex teamIndex = GetTeam();
				itemStealController.StartSteal((CharacterMaster characterMaster) => characterMaster.teamIndex != teamIndex && characterMaster.hasBody);
			}
			if (base.isAuthority && base.fixedAge > delayBeforeBeginningSteal + maxDuration)
			{
				outer.SetNextState(new SpellChannelExitState());
			}
			if ((bool)spellChannelChildTransform)
			{
				itemStealController.transform.position = spellChannelChildTransform.position;
			}
		}

		public override void OnExit()
		{
			if ((bool)itemStealController && hasSubscribedToStealFinish)
			{
				itemStealController.onStealFinishServer.RemoveListener(OnStealEndAuthority);
				itemStealController.onStealFinishClient -= OnStealEndAuthority;
			}
			if ((bool)channelEffectInstance)
			{
				EntityState.Destroy(channelEffectInstance);
			}
			Util.PlaySound("Play_moonBrother_phase4_itemSuck_end", base.gameObject);
			base.characterBody.RemoveBuff(RoR2Content.Buffs.Immune);
			base.OnExit();
		}

		private void OnStealEndAuthority()
		{
			outer.SetNextState(new SpellChannelExitState());
		}
	}
	public class SpellChannelExitState : SpellBaseState
	{
		public static float lendInterval;

		public static float duration;

		public static GameObject channelFinishEffectPrefab;

		private static int SpellChannelExitStateHash = Animator.StringToHash("SpellChannelExit");

		private static int SpellChannelExitParamHash = Animator.StringToHash("SpellChannelExit.playbackRate");

		protected override bool DisplayWeapon => false;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpellChannelExitStateHash, SpellChannelExitParamHash, duration);
			if (NetworkServer.active && (bool)itemStealController)
			{
				itemStealController.stealInterval = lendInterval;
				itemStealController.LendImmediately(base.characterBody.inventory);
			}
			if ((bool)channelFinishEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(channelFinishEffectPrefab, base.gameObject, "SpellChannel", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			SetStateOnHurt component = GetComponent<SetStateOnHurt>();
			if ((bool)component)
			{
				component.canBeFrozen = true;
			}
			base.OnExit();
		}
	}
	public class SprintBash : BasicMeleeAttack
	{
		public static float durationBeforePriorityReduces;

		protected override void PlayAnimation()
		{
			PlayCrossfade("FullBody Override", "SprintBash", "SprintBash.playbackRate", duration, 0.05f);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			AimAnimator aimAnimator = GetAimAnimator();
			if ((bool)aimAnimator)
			{
				aimAnimator.enabled = true;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.forward = base.inputBank.aimDirection;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (bool)base.inputBank && (bool)base.skillLocator && base.skillLocator.utility.IsReady() && base.inputBank.skill3.justPressed)
			{
				base.skillLocator.utility.ExecuteIfReady();
			}
		}

		public override void OnExit()
		{
			Transform transform = FindModelChild("SpinnyFX");
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: false);
			}
			PlayCrossfade("FullBody Override", "BufferEmpty", 0.1f);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge > durationBeforePriorityReduces))
			{
				return InterruptPriority.PrioritySkill;
			}
			return InterruptPriority.Skill;
		}
	}
	public class StaggerBaseState : BaseState
	{
		[SerializeField]
		public float duration;

		public virtual EntityState nextState => null;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class StaggerEnter : StaggerBaseState
	{
		public static GameObject effectPrefab;

		public static string effectMuzzleString;

		private static int StaggerEnterStateHash = Animator.StringToHash("StaggerEnter");

		private static int StaggerParamHash = Animator.StringToHash("Stagger.playbackRate");

		public override EntityState nextState => new StaggerLoop();

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", StaggerEnterStateHash, StaggerParamHash, duration);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, effectMuzzleString, transmit: false);
			}
		}
	}
	public class StaggerLoop : StaggerBaseState
	{
		private static int StaggerLoopStateHash = Animator.StringToHash("StaggerLoop");

		public override EntityState nextState => new StaggerExit();

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", "StaggerLoop", 0.2f);
			PlayCrossfade("Body", StaggerLoopStateHash, 0.2f);
		}
	}
	public class StaggerExit : StaggerBaseState
	{
		private static int StaggerExitStateHash = Animator.StringToHash("StaggerExit");

		private static int StaggerParamHash = Animator.StringToHash("Stagger.playbackRate");

		public override EntityState nextState => new GenericCharacterMain();

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", StaggerExitStateHash, StaggerParamHash, duration, 0.1f);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
	public class UltEnterState : BaseState
	{
		public static string soundString;

		public static float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Body", "UltEnter", "Ult.playbackRate", duration, 0.1f);
			Util.PlaySound(soundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextState(new UltChannelState());
			}
		}
	}
	public class UltChannelState : BaseState
	{
		public static GameObject waveProjectileLeftPrefab;

		public static GameObject waveProjectileRightPrefab;

		public static int waveProjectileCount;

		public static float waveProjectileDamageCoefficient;

		public static float waveProjectileForce;

		public static int totalWaves;

		public static float maxDuration;

		public static GameObject channelBeginMuzzleflashEffectPrefab;

		public static GameObject channelEffectPrefab;

		public static string enterSoundString;

		public static string exitSoundString;

		private GameObject channelEffectInstance;

		public static SkillDef replacementSkillDef;

		private int wavesFired;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			Transform transform = FindModelChild("MuzzleUlt");
			if ((bool)transform && (bool)channelEffectPrefab)
			{
				channelEffectInstance = UnityEngine.Object.Instantiate(channelEffectPrefab, transform.position, UnityEngine.Quaternion.identity, transform);
			}
			if ((bool)channelBeginMuzzleflashEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(channelBeginMuzzleflashEffectPrefab, base.gameObject, "MuzzleUlt", transmit: false);
			}
		}

		private void FireWave()
		{
			wavesFired++;
			float num = 360f / (float)waveProjectileCount;
			UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Random.onUnitSphere, UnityEngine.Vector3.up).normalized;
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			GameObject prefab = waveProjectileLeftPrefab;
			if (UnityEngine.Random.value <= 0.5f)
			{
				prefab = waveProjectileRightPrefab;
			}
			for (int i = 0; i < waveProjectileCount; i++)
			{
				UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * normalized;
				ProjectileManager.instance.FireProjectile(prefab, footPosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master));
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				if (Mathf.CeilToInt(base.fixedAge / maxDuration * (float)totalWaves) > wavesFired)
				{
					FireWave();
				}
				if (base.fixedAge > maxDuration)
				{
					outer.SetNextState(new UltExitState());
				}
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(exitSoundString, base.gameObject);
			if ((bool)channelEffectInstance)
			{
				EntityState.Destroy(channelEffectInstance);
			}
			base.OnExit();
		}
	}
	public class UltExitState : BaseState
	{
		public static float lendInterval;

		public static float duration;

		public static string soundString;

		public static GameObject channelFinishEffectPrefab;

		private static int UltExitStateHash = Animator.StringToHash("UltExit");

		private static int UltParamHash = Animator.StringToHash("Ult.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", UltExitStateHash, UltParamHash, duration);
			Util.PlaySound(soundString, base.gameObject);
			if ((bool)channelFinishEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(channelFinishEffectPrefab, base.gameObject, "MuzzleUlt", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			GenericSkill genericSkill = (base.skillLocator ? base.skillLocator.special : null);
			if ((bool)genericSkill)
			{
				genericSkill.UnsetSkillOverride(outer, UltChannelState.replacementSkillDef, GenericSkill.SkillOverridePriority.Contextual);
			}
			base.OnExit();
		}
	}
	public class WeaponSlam : BaseState
	{
		public static float duration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float upwardForce;

		public static float radius = 3f;

		public static string attackSoundString;

		public static string muzzleString;

		public static GameObject slamImpactEffect;

		public static float durationBeforePriorityReduces;

		public static GameObject waveProjectilePrefab;

		public static float waveProjectileArc;

		public static int waveProjectileCount;

		public static float waveProjectileDamageCoefficient;

		public static float waveProjectileForce;

		public static float weaponDamageCoefficient;

		public static float weaponForce;

		public static GameObject pillarProjectilePrefab;

		public static float pillarDamageCoefficient;

		public static GameObject weaponHitEffectPrefab;

		public static NetworkSoundEventDef weaponImpactSound;

		private BlastAttack blastAttack;

		private OverlapAttack weaponAttack;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasDoneBlastAttack;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			PlayCrossfade("FullBody Override", "WeaponSlam", "WeaponSlam.playbackRate", duration, 0.1f);
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = true;
				}
			}
			if (base.isAuthority)
			{
				weaponAttack = new OverlapAttack
				{
					attacker = base.gameObject,
					damage = damageCoefficient * damageStat,
					damageColorIndex = DamageColorIndex.Default,
					damageType = DamageType.Generic,
					hitEffectPrefab = weaponHitEffectPrefab,
					hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "WeaponBig"),
					impactSound = weaponImpactSound.index,
					inflictor = base.gameObject,
					procChainMask = default(ProcChainMask),
					pushAwayForce = weaponForce,
					procCoefficient = 1f,
					teamIndex = GetTeam()
				};
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && (bool)base.inputBank && (bool)base.skillLocator && base.skillLocator.utility.IsReady() && base.inputBank.skill3.justPressed)
			{
				base.skillLocator.utility.ExecuteIfReady();
				return;
			}
			if ((bool)modelAnimator)
			{
				if (base.isAuthority && modelAnimator.GetFloat("weapon.hitBoxActive") > 0.5f)
				{
					weaponAttack.Fire();
				}
				if (modelAnimator.GetFloat("blast.hitBoxActive") > 0.5f && !hasDoneBlastAttack)
				{
					hasDoneBlastAttack = true;
					EffectManager.SimpleMuzzleFlash(slamImpactEffect, base.gameObject, muzzleString, transmit: false);
					if (base.isAuthority)
					{
						if ((bool)base.characterDirection)
						{
							base.characterDirection.moveVector = base.characterDirection.forward;
						}
						if ((bool)modelTransform)
						{
							Transform transform = FindModelChild(muzzleString);
							if ((bool)transform)
							{
								blastAttack = new BlastAttack();
								blastAttack.attacker = base.gameObject;
								blastAttack.inflictor = base.gameObject;
								blastAttack.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
								blastAttack.baseDamage = damageStat * damageCoefficient;
								blastAttack.baseForce = forceMagnitude;
								blastAttack.position = transform.position;
								blastAttack.radius = radius;
								blastAttack.bonusForce = new UnityEngine.Vector3(0f, upwardForce, 0f);
								blastAttack.Fire();
							}
						}
						if ((bool)PhaseCounter.instance && PhaseCounter.instance.phase == 3)
						{
							Transform transform2 = FindModelChild(muzzleString);
							float num = waveProjectileArc / (float)waveProjectileCount;
							UnityEngine.Vector3 vector = UnityEngine.Vector3.ProjectOnPlane(base.characterDirection.forward, UnityEngine.Vector3.up);
							UnityEngine.Vector3 position = base.characterBody.footPosition;
							if ((bool)transform2)
							{
								position = transform2.position;
							}
							for (int i = 0; i < waveProjectileCount; i++)
							{
								UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num * ((float)i - (float)waveProjectileCount / 2f), UnityEngine.Vector3.up) * vector;
								ProjectileManager.instance.FireProjectile(waveProjectilePrefab, position, Util.QuaternionSafeLookRotation(forward), base.gameObject, base.characterBody.damage * waveProjectileDamageCoefficient, waveProjectileForce, Util.CheckRoll(base.characterBody.crit, base.characterBody.master));
							}
							ProjectileManager.instance.FireProjectile(pillarProjectilePrefab, position, UnityEngine.Quaternion.identity, base.gameObject, base.characterBody.damage * pillarDamageCoefficient, 0f, Util.CheckRoll(base.characterBody.crit, base.characterBody.master));
						}
					}
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge > durationBeforePriorityReduces))
			{
				return InterruptPriority.PrioritySkill;
			}
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.BrotherMonster.Weapon
{
	public class FireLunarShards : BaseSkillState
	{
		public static float baseDuration;

		[SerializeField]
		public float damageCoefficient;

		public static GameObject projectilePrefab;

		public static float recoilAmplitude;

		public static float spreadBloomValue;

		public static string muzzleString;

		public static GameObject muzzleFlashEffectPrefab;

		public static string fireSound;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public float spreadYawScale;

		[SerializeField]
		public float spreadPitchScale;

		private float duration;

		private static int FireLunarShardsStateHash = Animator.StringToHash("FireLunarShards");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if (base.isAuthority)
			{
				Ray aimRay = GetAimRay();
				Transform transform = FindModelChild(muzzleString);
				if ((bool)transform)
				{
					aimRay.origin = transform.position;
				}
				aimRay.direction = Util.ApplySpread(aimRay.direction, 0f, maxSpread, spreadYawScale, spreadPitchScale);
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.position = aimRay.origin;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction);
				fireProjectileInfo.crit = base.characterBody.RollCrit();
				fireProjectileInfo.damage = base.characterBody.damage * damageCoefficient;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.useFuseOverride = false;
				fireProjectileInfo.useSpeedOverride = false;
				fireProjectileInfo.target = null;
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo);
			}
			PlayAnimation("Gesture, Additive", FireLunarShardsStateHash);
			PlayAnimation("Gesture, Override", FireLunarShardsStateHash);
			AddRecoil(-0.4f * recoilAmplitude, -0.8f * recoilAmplitude, -0.3f * recoilAmplitude, 0.3f * recoilAmplitude);
			base.characterBody.AddSpreadBloom(spreadBloomValue);
			EffectManager.SimpleMuzzleFlash(muzzleFlashEffectPrefab, base.gameObject, muzzleString, transmit: false);
			Util.PlaySound(fireSound, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge >= duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireLunarShardsHurt : FireLunarShards
	{
	}
}
namespace EntityStates.Bison
{
	public class Charge : BaseState
	{
		public static float chargeDuration;

		public static float chargeMovementSpeedCoefficient;

		public static float turnSpeed;

		public static float turnSmoothTime;

		public static float impactDamageCoefficient;

		public static float impactForce;

		public static float damageCoefficient;

		public static float upwardForceMagnitude;

		public static float awayForceMagnitude;

		public static GameObject hitEffectPrefab;

		public static float overlapResetFrequency;

		public static float overlapSphereRadius;

		public static float selfStunDuration;

		public static float selfStunForce;

		public static string startSoundString;

		public static string endSoundString;

		public static string footstepOverrideSoundString;

		public static string headbuttImpactSound;

		private float stopwatch;

		private float overlapResetStopwatch;

		private Animator animator;

		private UnityEngine.Vector3 targetMoveVector;

		private UnityEngine.Vector3 targetMoveVectorVelocity;

		private ContactDamage contactDamage;

		private OverlapAttack attack;

		private HitBoxGroup hitboxGroup;

		private ChildLocator childLocator;

		private Transform sphereCheckTransform;

		private string baseFootstepString;

		private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed");

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			childLocator = animator.GetComponent<ChildLocator>();
			FootstepHandler component = animator.GetComponent<FootstepHandler>();
			if ((bool)component)
			{
				baseFootstepString = component.baseFootstepString;
				component.baseFootstepString = footstepOverrideSoundString;
			}
			Util.PlaySound(startSoundString, base.gameObject);
			PlayCrossfade("Body", "ChargeForward", 0.2f);
			ResetOverlapAttack();
			SetSprintEffectActive(active: true);
			if ((bool)childLocator)
			{
				sphereCheckTransform = childLocator.FindChild("SphereCheckTransform");
			}
			if (!sphereCheckTransform && (bool)base.characterBody)
			{
				sphereCheckTransform = base.characterBody.coreTransform;
			}
			if (!sphereCheckTransform)
			{
				sphereCheckTransform = base.transform;
			}
		}

		private void SetSprintEffectActive(bool active)
		{
			if ((bool)childLocator)
			{
				childLocator.FindChild("SprintEffect")?.gameObject.SetActive(active);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
			Util.PlaySound(endSoundString, base.gameObject);
			Util.PlaySound("stop_bison_charge_attack_loop", base.gameObject);
			SetSprintEffectActive(active: false);
			FootstepHandler component = animator.GetComponent<FootstepHandler>();
			if ((bool)component)
			{
				component.baseFootstepString = baseFootstepString;
			}
		}

		public override void FixedUpdate()
		{
			targetMoveVector = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Vector3.SmoothDamp(targetMoveVector, base.inputBank.aimDirection, ref targetMoveVectorVelocity, turnSmoothTime, turnSpeed), UnityEngine.Vector3.up).normalized;
			base.characterDirection.moveVector = targetMoveVector;
			UnityEngine.Vector3 forward = base.characterDirection.forward;
			float value = moveSpeedStat * chargeMovementSpeedCoefficient;
			base.characterMotor.moveDirection = forward * chargeMovementSpeedCoefficient;
			animator.SetFloat(forwardSpeedParamHash, value);
			if (base.isAuthority && attack.Fire())
			{
				Util.PlaySound(headbuttImpactSound, base.gameObject);
			}
			if (overlapResetStopwatch >= 1f / overlapResetFrequency)
			{
				overlapResetStopwatch -= 1f / overlapResetFrequency;
			}
			if (base.isAuthority && HGPhysics.DoesOverlapSphere(sphereCheckTransform.position, overlapSphereRadius, LayerIndex.world.mask))
			{
				Util.PlaySound(headbuttImpactSound, base.gameObject);
				EffectManager.SimpleMuzzleFlash(hitEffectPrefab, base.gameObject, "SphereCheckTransform", transmit: true);
				base.healthComponent.TakeDamageForce(forward * selfStunForce, alwaysApply: true);
				StunState stunState = new StunState();
				stunState.stunDuration = selfStunDuration;
				outer.SetNextState(stunState);
				return;
			}
			float deltaTime = GetDeltaTime();
			stopwatch += deltaTime;
			overlapResetStopwatch += deltaTime;
			if (stopwatch > chargeDuration)
			{
				outer.SetNextStateToMain();
			}
			base.FixedUpdate();
		}

		private void ResetOverlapAttack()
		{
			if (!hitboxGroup)
			{
				Transform modelTransform = GetModelTransform();
				if ((bool)modelTransform)
				{
					hitboxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Charge");
				}
			}
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude;
			attack.pushAwayForce = awayForceMagnitude;
			attack.hitBoxGroup = hitboxGroup;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Headbutt : BaseState
	{
		public static float baseHeadbuttDuration;

		public static float damageCoefficient;

		public static string attackSoundString;

		public static GameObject hitEffectPrefab;

		public static float upwardForceMagnitude;

		public static float awayForceMagnitude;

		private float headbuttDuration;

		private float stopwatch;

		private OverlapAttack attack;

		private Animator animator;

		private bool hasAttacked;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			animator = modelTransform.GetComponent<Animator>();
			headbuttDuration = baseHeadbuttDuration / attackSpeedStat;
			Util.PlaySound(attackSoundString, base.gameObject);
			PlayCrossfade("Body", "Headbutt", "Headbutt.playbackRate", headbuttDuration, 0.2f);
			base.characterMotor.moveDirection = UnityEngine.Vector3.zero;
			base.characterDirection.moveVector = base.characterDirection.forward;
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.forceVector = UnityEngine.Vector3.up * upwardForceMagnitude;
			attack.pushAwayForce = awayForceMagnitude;
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Headbutt");
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)animator && animator.GetFloat("Headbutt.hitBoxActive") > 0.5f)
			{
				if (NetworkServer.active)
				{
					attack.Fire();
				}
				if (base.isAuthority && !hasAttacked)
				{
					hasAttacked = true;
				}
			}
			stopwatch += GetDeltaTime();
			if (stopwatch > headbuttDuration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class PrepCharge : BaseState
	{
		public static float basePrepDuration;

		public static string enterSoundString;

		public static GameObject chargeEffectPrefab;

		private float stopwatch;

		private float prepDuration;

		private GameObject chargeEffectInstance;

		private EffectManagerHelper _emh_chargeEffectInstance;

		public override void Reset()
		{
			base.Reset();
			prepDuration = 0f;
			chargeEffectInstance = null;
			_emh_chargeEffectInstance = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			prepDuration = basePrepDuration / attackSpeedStat;
			base.characterBody.SetAimTimer(prepDuration);
			PlayCrossfade("Body", "PrepCharge", "PrepCharge.playbackRate", prepDuration, 0.2f);
			Util.PlaySound(enterSoundString, base.gameObject);
			Transform modelTransform = GetModelTransform();
			AimAnimator component = modelTransform.GetComponent<AimAnimator>();
			if ((bool)component)
			{
				component.enabled = true;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component2 = modelTransform.GetComponent<ChildLocator>();
			if (!component2)
			{
				return;
			}
			Transform transform = component2.FindChild("ChargeIndicator");
			if ((bool)transform && (bool)chargeEffectPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(chargeEffectPrefab))
				{
					chargeEffectInstance = UnityEngine.Object.Instantiate(chargeEffectPrefab, transform.position, transform.rotation);
				}
				else
				{
					_emh_chargeEffectInstance = EffectManager.GetAndActivatePooledEffect(chargeEffectPrefab, transform.position, transform.rotation);
					chargeEffectInstance = _emh_chargeEffectInstance.gameObject;
				}
				chargeEffectInstance.transform.parent = transform;
				ScaleParticleSystemDuration component3 = chargeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component3)
				{
					component3.newDuration = prepDuration;
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)chargeEffectInstance)
			{
				if (_emh_chargeEffectInstance != null && _emh_chargeEffectInstance.OwningPool != null)
				{
					_emh_chargeEffectInstance.OwningPool.ReturnObject(_emh_chargeEffectInstance);
				}
				else
				{
					EntityState.Destroy(chargeEffectInstance);
				}
				chargeEffectInstance = null;
				_emh_chargeEffectInstance = null;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch > prepDuration && base.isAuthority)
			{
				outer.SetNextState(new Charge());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : BaseState
	{
		public static GameObject spawnEffectPrefab;

		public static string spawnEffectMuzzle;

		public static float duration;

		public static float snowyOverlayDuration;

		public static Material snowyMaterial;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, spawnEffectMuzzle, transmit: false);
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound("Play_bison_idle_graze", base.gameObject);
			Util.PlaySound("Play_bison_charge_attack_collide", base.gameObject);
			if ((bool)modelTransform)
			{
				CharacterModel component = modelTransform.GetComponent<CharacterModel>();
				if ((bool)component && (bool)snowyMaterial)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(component.gameObject);
					temporaryOverlayInstance.duration = snowyOverlayDuration;
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = snowyMaterial;
					temporaryOverlayInstance.inspectorCharacterModel = component;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.animateShaderAlpha = true;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}
	}
}
namespace EntityStates.Bell
{
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialEffect;

		public static float initialEffectScale;

		public static float velocityMagnitude;

		public static float explosionForce;

		protected override bool shouldAutoDestroy => false;

		public override void OnEnter()
		{
			base.OnEnter();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				if ((bool)modelTransform.GetComponent<ChildLocator>() && (bool)initialEffect)
				{
					EffectManager.SpawnEffect(initialEffect, new EffectData
					{
						origin = base.transform.position,
						scale = initialEffectScale
					}, transmit: false);
				}
				RagdollController component = modelTransform.GetComponent<RagdollController>();
				Rigidbody component2 = GetComponent<Rigidbody>();
				if ((bool)component && (bool)component2)
				{
					component.BeginRagdoll(component2.velocity * velocityMagnitude);
				}
				ExplodeRigidbodiesOnStart component3 = modelTransform.GetComponent<ExplodeRigidbodiesOnStart>();
				if ((bool)component3)
				{
					component3.force = explosionForce;
					component3.enabled = true;
				}
			}
			if ((bool)base.modelLocator)
			{
				base.modelLocator.autoUpdateModelTransform = false;
			}
			DestroyBodyAsapServer();
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			Util.PlaySound(spawnSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Bell.BellWeapon
{
	public class BuffBeam : BaseState
	{
		public static float duration;

		public static GameObject buffBeamPrefab;

		public static AnimationCurve beamWidthCurve;

		public static string playBeamSoundString;

		public static string stopBeamSoundString;

		public HurtBox target;

		private float healTimer;

		private float healInterval;

		private float healChunk;

		private CharacterBody targetBody;

		private GameObject buffBeamInstance;

		private BezierCurveLine healBeamCurve;

		private Transform muzzleTransform;

		private Transform beamTipTransform;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(playBeamSoundString, base.gameObject);
			Ray aimRay = GetAimRay();
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.teamMaskFilter = TeamMask.none;
			if ((bool)base.teamComponent)
			{
				bullseyeSearch.teamMaskFilter.AddTeam(base.teamComponent.teamIndex);
			}
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.maxDistanceFilter = 50f;
			bullseyeSearch.maxAngleFilter = 180f;
			bullseyeSearch.searchOrigin = aimRay.origin;
			bullseyeSearch.searchDirection = aimRay.direction;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Angle;
			bullseyeSearch.RefreshCandidates();
			bullseyeSearch.FilterOutGameObject(base.gameObject);
			target = bullseyeSearch.GetResults().FirstOrDefault();
			UnityEngine.Debug.LogFormat("Buffing target {0}", target);
			if ((bool)target)
			{
				targetBody = target.healthComponent.body;
				targetBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
			string childName = "Muzzle";
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				muzzleTransform = component.FindChild(childName);
				buffBeamInstance = UnityEngine.Object.Instantiate(buffBeamPrefab);
				ChildLocator component2 = buffBeamInstance.GetComponent<ChildLocator>();
				if ((bool)component2)
				{
					beamTipTransform = component2.FindChild("BeamTip");
				}
				healBeamCurve = buffBeamInstance.GetComponentInChildren<BezierCurveLine>();
			}
		}

		private void UpdateHealBeamVisuals()
		{
			float widthMultiplier = beamWidthCurve.Evaluate(base.age / duration);
			healBeamCurve.lineRenderer.widthMultiplier = widthMultiplier;
			healBeamCurve.v0 = muzzleTransform.forward * 3f;
			healBeamCurve.transform.position = muzzleTransform.position;
			if ((bool)target)
			{
				beamTipTransform.position = targetBody.mainHurtBox.transform.position;
			}
		}

		public override void Update()
		{
			base.Update();
			UpdateHealBeamVisuals();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((base.fixedAge >= duration || target == null) && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(stopBeamSoundString, base.gameObject);
			EntityState.Destroy(buffBeamInstance);
			if ((bool)targetBody)
			{
				targetBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility.buffIndex);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}

		public override void OnSerialize(NetworkWriter writer)
		{
			base.OnSerialize(writer);
			HurtBoxReference.FromHurtBox(target).Write(writer);
		}

		public override void OnDeserialize(NetworkReader reader)
		{
			base.OnDeserialize(reader);
			HurtBoxReference hurtBoxReference = default(HurtBoxReference);
			hurtBoxReference.Read(reader);
			target = hurtBoxReference.ResolveGameObject()?.GetComponent<HurtBox>();
		}
	}
	public class ChargeTrioBomb : BaseState
	{
		public static float basePrepDuration;

		public static float baseTimeBetweenPreps;

		public static GameObject preppedBombPrefab;

		public static float baseBarrageDuration;

		public static float baseTimeBetweenBarrages;

		public static GameObject bombProjectilePrefab;

		public static GameObject muzzleflashPrefab;

		public static float damageCoefficient;

		public static float force;

		public static float selfForce;

		private float prepDuration;

		private float timeBetweenPreps;

		private float barrageDuration;

		private float timeBetweenBarrages;

		private ChildLocator childLocator;

		private List<GameObject> preppedBombInstances = new List<GameObject>();

		private int currentBombIndex;

		private float perProjectileStopwatch;

		public override void OnEnter()
		{
			base.OnEnter();
			prepDuration = basePrepDuration / attackSpeedStat;
			timeBetweenPreps = baseTimeBetweenPreps / attackSpeedStat;
			barrageDuration = baseBarrageDuration / attackSpeedStat;
			timeBetweenBarrages = baseTimeBetweenBarrages / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				childLocator = modelTransform.GetComponent<ChildLocator>();
			}
		}

		private string FindTargetChildStringFromBombIndex()
		{
			return string.Format(CultureInfo.InvariantCulture, "ProjectilePosition{0}", currentBombIndex);
		}

		private Transform FindTargetChildTransformFromBombIndex()
		{
			string childName = FindTargetChildStringFromBombIndex();
			return childLocator.FindChild(childName);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			perProjectileStopwatch += GetDeltaTime();
			if (base.fixedAge < prepDuration)
			{
				if (perProjectileStopwatch > timeBetweenPreps && currentBombIndex < 3)
				{
					currentBombIndex++;
					perProjectileStopwatch = 0f;
					Transform transform = FindTargetChildTransformFromBombIndex();
					if ((bool)transform)
					{
						GameObject item = UnityEngine.Object.Instantiate(preppedBombPrefab, transform);
						preppedBombInstances.Add(item);
					}
				}
			}
			else if (base.fixedAge < prepDuration + barrageDuration)
			{
				if (!(perProjectileStopwatch > timeBetweenBarrages) || currentBombIndex <= 0)
				{
					return;
				}
				perProjectileStopwatch = 0f;
				Ray aimRay = GetAimRay();
				Transform transform2 = FindTargetChildTransformFromBombIndex();
				if ((bool)transform2)
				{
					if (base.isAuthority)
					{
						float damage = damageStat * damageCoefficient;
						BaseAI component = outer.commonComponents.characterBody.master.GetComponent<BaseAI>();
						if ((object)component != null && component.shouldMissFirstOffScreenShot && component.currentEnemy.characterBody.teamComponent.teamIndex == TeamIndex.Player)
						{
							aimRay.direction = OffScreenMissHelper.ApplyRandomTrajectoryOffset(aimRay.direction);
							damage = 0f;
							if (currentBombIndex <= 1)
							{
								component.shouldMissFirstOffScreenShot = false;
							}
						}
						ProjectileManager.instance.FireProjectile(bombProjectilePrefab, transform2.position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damage, force, Util.CheckRoll(critStat, base.characterBody.master));
						Rigidbody component2 = GetComponent<Rigidbody>();
						if ((bool)component2)
						{
							component2.AddForceAtPosition((0f - selfForce) * transform2.forward, transform2.position);
						}
					}
					EffectManager.SimpleMuzzleFlash(muzzleflashPrefab, base.gameObject, FindTargetChildStringFromBombIndex(), transmit: false);
				}
				currentBombIndex--;
				EntityState.Destroy(preppedBombInstances[currentBombIndex]);
			}
			else if (base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			foreach (GameObject preppedBombInstance in preppedBombInstances)
			{
				EntityState.Destroy(preppedBombInstance);
			}
		}
	}
}
namespace EntityStates.BeetleMonster
{
	public class HeadbuttState : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient;

		public static float forceMagnitude = 16f;

		public static GameObject hitEffectPrefab;

		public static string attackSoundString;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private RootMotionAccumulator rootMotionAccumulator;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			rootMotionAccumulator = GetModelRootMotionAccumulator();
			modelAnimator = GetModelAnimator();
			duration = baseDuration / attackSpeedStat;
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Headbutt");
			}
			Util.PlaySound(attackSoundString, base.gameObject);
			PlayCrossfade("Body", "Headbutt", "Headbutt.playbackRate", duration, 0.1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)rootMotionAccumulator)
			{
				UnityEngine.Vector3 vector = rootMotionAccumulator.ExtractRootMotion();
				if (vector != UnityEngine.Vector3.zero && base.isAuthority && (bool)base.characterMotor)
				{
					base.characterMotor.rootMotion += vector;
				}
			}
			if (base.isAuthority)
			{
				attack.forceVector = (base.characterDirection ? (base.characterDirection.forward * forceMagnitude) : UnityEngine.Vector3.zero);
				if ((bool)base.characterDirection && (bool)base.inputBank)
				{
					base.characterDirection.moveVector = base.inputBank.aimDirection;
				}
				if ((bool)modelAnimator && modelAnimator.GetFloat("Headbutt.hitBoxActive") > 0.5f)
				{
					attack.Fire();
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class MainState : EntityState
	{
		private Animator modelAnimator;

		private static int walkToRunBlendParamHash = Animator.StringToHash("walkToRunBlend");

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				modelAnimator.CrossFadeInFixedTime("Walk", 0.1f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator)
			{
				modelAnimator.SetFloat(walkToRunBlendParamHash, 1f);
			}
		}
	}
	public class MeleeState : EntityState
	{
		public static float duration = 3.5f;

		public static float damage = 10f;

		public static float forceMagnitude = 10f;

		private OverlapAttack attack;

		private Animator modelAnimator;

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = 10f;
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "Melee1");
			}
			PlayCrossfade("Body", "Melee1", "Melee1.playbackRate", duration, 0.1f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				attack.forceVector = (base.characterDirection ? (base.characterDirection.forward * forceMagnitude) : UnityEngine.Vector3.zero);
				if ((bool)modelAnimator && modelAnimator.GetFloat("Melee1.hitBoxActive") > 0.5f)
				{
					attack.Fire();
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
	}
}
namespace EntityStates.BeetleQueenMonster
{
	public class BeetleWardDeath : BaseState
	{
		public static GameObject initialExplosion;

		public static string deathString;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(deathString, base.gameObject);
			if ((bool)base.modelLocator)
			{
				if ((bool)base.modelLocator.modelBaseTransform)
				{
					EntityState.Destroy(base.modelLocator.modelBaseTransform.gameObject);
				}
				if ((bool)base.modelLocator.modelTransform)
				{
					EntityState.Destroy(base.modelLocator.modelTransform.gameObject);
				}
			}
			if ((bool)initialExplosion && NetworkServer.active)
			{
				EffectManager.SimpleImpactEffect(initialExplosion, base.transform.position, UnityEngine.Vector3.up, transmit: true);
			}
			EntityState.Destroy(base.gameObject);
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class BeginBurrow : BaseState
	{
		public static GameObject burrowPrefab;

		public static float duration;

		private bool isBurrowing;

		private Animator animator;

		private Transform modelTransform;

		private ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			PlayCrossfade("Body", "BeginBurrow", "BeginBurrow.playbackRate", duration, 0.5f);
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			bool flag = animator.GetFloat("BeginBurrow.active") > 0.9f;
			if (flag && !isBurrowing)
			{
				string childName = "BurrowCenter";
				Transform transform = childLocator.FindChild(childName);
				if ((bool)transform)
				{
					UnityEngine.Object.Instantiate(burrowPrefab, transform.position, UnityEngine.Quaternion.identity);
				}
			}
			isBurrowing = flag;
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeSpit : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject effectPrefab;

		public static string attackSoundString;

		private float duration;

		private GameObject chargeEffect;

		private EffectManagerHelper _emh_chargeEffect;

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffect = null;
			_emh_chargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayCrossfade("Gesture", "ChargeSpit", "ChargeSpit.playbackRate", duration, 0.2f);
			Util.PlaySound(attackSoundString, base.gameObject);
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component || !effectPrefab)
			{
				return;
			}
			Transform transform = component.FindChild("Mouth");
			if ((bool)transform)
			{
				if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
				{
					chargeEffect = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
				}
				else
				{
					_emh_chargeEffect = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation);
					chargeEffect = _emh_chargeEffect.gameObject;
				}
				chargeEffect.transform.parent = transform;
				ScaleParticleSystemDuration component2 = chargeEffect.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component2)
				{
					component2.newDuration = duration;
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (chargeEffect != null)
			{
				if (_emh_chargeEffect != null && _emh_chargeEffect.OwningPool != null)
				{
					_emh_chargeEffect.OwningPool.ReturnObject(_emh_chargeEffect);
				}
				else
				{
					EntityState.Destroy(chargeEffect);
				}
				chargeEffect = null;
				_emh_chargeEffect = null;
			}
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireSpit nextState = new FireSpit();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class FireSpit : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float baseDuration = 2f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static int projectileCount = 3;

		public static float yawSpread = 5f;

		public static float minSpread = 0f;

		public static float maxSpread = 5f;

		public static float arcAngle = 5f;

		public static float projectileHSpeed = 50f;

		private Ray aimRay;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			string muzzleName = "Mouth";
			duration = baseDuration / attackSpeedStat;
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			PlayCrossfade("Gesture", "FireSpit", "FireSpit.playbackRate", duration, 0.1f);
			aimRay = GetAimRay();
			float magnitude = projectileHSpeed;
			Ray ray = aimRay;
			ray.origin = aimRay.GetPoint(6f);
			if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
			{
				float num = magnitude;
				UnityEngine.Vector3 vector = hitInfo.point - aimRay.origin;
				UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(vector.x, vector.z);
				float magnitude2 = vector2.magnitude;
				float y = Trajectory.CalculateInitialYSpeed(magnitude2 / num, vector.y);
				UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(vector2.x / magnitude2 * num, y, vector2.y / magnitude2 * num);
				magnitude = vector3.magnitude;
				aimRay.direction = vector3 / magnitude;
			}
			EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			if (base.isAuthority)
			{
				for (int i = 0; i < projectileCount; i++)
				{
					FireBlob(aimRay, 0f, ((float)projectileCount / 2f - (float)i) * yawSpread, magnitude);
				}
			}
		}

		private void FireBlob(Ray aimRay, float bonusPitch, float bonusYaw, float speed)
		{
			UnityEngine.Vector3 forward = Util.ApplySpread(aimRay.direction, minSpread, maxSpread, 1f, 1f, bonusYaw, bonusPitch);
			ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, 0f, Util.CheckRoll(critStat, base.characterBody.master), DamageColorIndex.Default, null, speed);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static GameObject burrowPrefab;

		public static string spawnSoundString;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		private static int SpawnParamHash = Animator.StringToHash("Spawn.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			GetModelTransform().GetComponent<ChildLocator>();
			PlayAnimation("Body", SpawnStateHash, SpawnParamHash, duration);
			string muzzleName = "BurrowCenter";
			EffectManager.SimpleMuzzleFlash(burrowPrefab, base.gameObject, muzzleName, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class SpawnWards : BaseState
	{
		public static string muzzleString;

		public static string attackSoundString;

		public static GameObject muzzleflashEffectPrefab;

		public static float baseDuration = 0.9f;

		public static float orbRange;

		public static float orbTravelSpeed;

		public static int orbCountMax;

		private float stopwatch;

		private int orbCount;

		private float duration;

		private bool hasFiredOrbs;

		private Animator animator;

		private ChildLocator childLocator;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			childLocator = animator.GetComponent<ChildLocator>();
			duration = baseDuration / attackSpeedStat;
			Util.PlayAttackSpeedSound(attackSoundString, base.gameObject, attackSpeedStat);
			PlayCrossfade("Gesture", "SpawnWards", "SpawnWards.playbackRate", duration, 0.5f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (!hasFiredOrbs && animator.GetFloat("SpawnWards.active") > 0.5f)
			{
				hasFiredOrbs = true;
				FireOrbs();
			}
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireOrbs()
		{
			if (NetworkServer.active)
			{
				Transform transform = childLocator.FindChild(muzzleString).transform;
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.searchOrigin = transform.position;
				bullseyeSearch.searchDirection = transform.forward;
				bullseyeSearch.maxDistanceFilter = orbRange;
				bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
				bullseyeSearch.teamMaskFilter.RemoveTeam(TeamComponent.GetObjectTeam(base.gameObject));
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
				bullseyeSearch.RefreshCandidates();
				EffectManager.SimpleMuzzleFlash(muzzleflashEffectPrefab, base.gameObject, muzzleString, transmit: true);
				List<HurtBox> list = bullseyeSearch.GetResults().ToList();
				for (int i = 0; i < list.Count; i++)
				{
					HurtBox target = list[i];
					BeetleWardOrb beetleWardOrb = new BeetleWardOrb();
					beetleWardOrb.origin = transform.position;
					beetleWardOrb.target = target;
					beetleWardOrb.speed = orbTravelSpeed;
					OrbManager.instance.AddOrb(beetleWardOrb);
				}
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if ((bool)base.cameraTargetParams)
			{
				base.cameraTargetParams.fovOverride = -1f;
			}
			int layerIndex = animator.GetLayerIndex("Impact");
			if (layerIndex >= 0)
			{
				animator.SetLayerWeight(layerIndex, 1.5f);
				animator.PlayInFixedTime("LightImpact", layerIndex, 0f);
			}
		}
	}
	public class SummonEggs : BaseState
	{
		public static float baseDuration = 3.5f;

		public static string attackSoundString;

		public static float randomRadius = 8f;

		public static GameObject spitPrefab;

		public static int maxSummonCount = 5;

		public static float summonInterval = 1f;

		private static float summonDuration = 3.26f;

		public static SpawnCard spawnCard;

		private Animator animator;

		private Transform modelTransform;

		private ChildLocator childLocator;

		private float duration;

		private float summonTimer;

		private int summonCount;

		private bool isSummoning;

		private BullseyeSearch enemySearch;

		public override void Reset()
		{
			base.Reset();
			animator = null;
			modelTransform = null;
			childLocator = null;
			duration = 0f;
			summonInterval = 0f;
			summonTimer = 0f;
			summonCount = 0;
			isSummoning = false;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			modelTransform = GetModelTransform();
			childLocator = modelTransform.GetComponent<ChildLocator>();
			duration = baseDuration;
			PlayCrossfade("Gesture", "SummonEggs", 0.5f);
			Util.PlaySound(attackSoundString, base.gameObject);
			if (NetworkServer.active)
			{
				enemySearch = new BullseyeSearch();
				enemySearch.filterByDistinctEntity = false;
				enemySearch.filterByLoS = false;
				enemySearch.maxDistanceFilter = float.PositiveInfinity;
				enemySearch.minDistanceFilter = 0f;
				enemySearch.minAngleFilter = 0f;
				enemySearch.maxAngleFilter = 180f;
				enemySearch.teamMaskFilter = TeamMask.GetEnemyTeams(GetTeam());
				enemySearch.sortMode = BullseyeSearch.SortMode.Distance;
				enemySearch.viewer = base.characterBody;
			}
		}

		private void SummonEgg()
		{
			UnityEngine.Vector3 searchOrigin = GetAimRay().origin;
			if ((bool)base.inputBank && base.inputBank.GetAimRaycast(float.PositiveInfinity, out var hitInfo))
			{
				searchOrigin = hitInfo.point;
			}
			if (enemySearch == null)
			{
				return;
			}
			enemySearch.searchOrigin = searchOrigin;
			enemySearch.RefreshCandidates();
			HurtBox hurtBox = enemySearch.GetResults().FirstOrDefault();
			Transform transform = (((bool)hurtBox && (bool)hurtBox.healthComponent) ? hurtBox.healthComponent.body.coreTransform : base.characterBody.coreTransform);
			if (!transform)
			{
				return;
			}
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Approximate,
				minDistance = 3f,
				maxDistance = 20f,
				spawnOnTarget = transform
			}, RoR2Application.rng);
			directorSpawnRequest.summonerBodyObject = base.gameObject;
			directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult spawnResult)
			{
				if (spawnResult.success && (bool)spawnResult.spawnedInstance && (bool)base.characterBody)
				{
					RoR2.Inventory component = spawnResult.spawnedInstance.GetComponent<RoR2.Inventory>();
					if ((bool)component)
					{
						component.CopyEquipmentFrom(base.characterBody.inventory);
						if (base.characterBody.inventory.GetItemCount(RoR2Content.Items.Ghost) > 0)
						{
							component.GiveItem(RoR2Content.Items.Ghost);
							component.GiveItem(RoR2Content.Items.HealthDecay, 30);
							component.GiveItem(RoR2Content.Items.BoostDamage, 150);
						}
					}
				}
			});
			DirectorCore.instance?.TrySpawnObject(directorSpawnRequest);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			bool flag = animator.GetFloat("SummonEggs.active") > 0.9f;
			if (flag && !isSummoning)
			{
				string childName = "Mouth";
				Transform transform = childLocator.FindChild(childName);
				if ((bool)transform)
				{
					if (!EffectManager.ShouldUsePooledEffect(spitPrefab))
					{
						UnityEngine.Object.Instantiate(spitPrefab, transform);
					}
					else
					{
						EffectManager.GetAndActivatePooledEffect(spitPrefab, transform, inResetLocal: true);
					}
				}
			}
			if (isSummoning)
			{
				summonTimer += GetDeltaTime();
				if (NetworkServer.active && summonTimer > 0f && summonCount < maxSummonCount)
				{
					summonCount++;
					summonTimer -= summonInterval;
					SummonEgg();
				}
			}
			isSummoning = flag;
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class WeakState : BaseState
	{
		private float stopwatch;

		private float grubStopwatch;

		public static float weakDuration;

		public static float weakToIdleTransitionDuration;

		public static string weakPointChildString;

		public static int maxGrubCount;

		public static float grubSpawnFrequency;

		public static float grubSpawnDelay;

		private int grubCount;

		private bool beginExitTransition;

		private ChildLocator childLocator;

		private static int WeakEnterStateHash = Animator.StringToHash("WeakEnter");

		public override void OnEnter()
		{
			base.OnEnter();
			grubStopwatch -= grubSpawnDelay;
			if ((bool)base.sfxLocator && base.sfxLocator.barkSound != "")
			{
				Util.PlaySound(base.sfxLocator.barkSound, base.gameObject);
			}
			PlayAnimation("Body", WeakEnterStateHash);
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			childLocator = modelTransform.GetComponent<ChildLocator>();
			if ((bool)childLocator)
			{
				Transform transform = childLocator.FindChild(weakPointChildString);
				if ((bool)transform)
				{
					UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/WeakPointProcEffect"), transform.position, transform.rotation);
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float deltaTime = GetDeltaTime();
			stopwatch += deltaTime;
			grubStopwatch += deltaTime;
			if (grubStopwatch >= 1f / grubSpawnFrequency && grubCount < maxGrubCount)
			{
				grubCount++;
				grubStopwatch -= 1f / grubSpawnFrequency;
				if (NetworkServer.active)
				{
					Transform transform = childLocator.FindChild("GrubSpawnPoint" + UnityEngine.Random.Range(1, 10));
					if ((bool)transform)
					{
						NetworkServer.Spawn(UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/GrubPack"), transform.transform.position, UnityEngine.Random.rotation));
						transform.gameObject.SetActive(value: false);
					}
				}
			}
			if (stopwatch >= weakDuration - weakToIdleTransitionDuration && !beginExitTransition)
			{
				beginExitTransition = true;
				PlayCrossfade("Body", "WeakExit", "WeakExit.playbackRate", weakToIdleTransitionDuration, 0.5f);
			}
			if (stopwatch >= weakDuration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Pain;
		}
	}
}
namespace EntityStates.BeetleGuardMonster
{
	public class DefenseUp : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float buffDuration = 8f;

		public static GameObject defenseUpPrefab;

		private Animator modelAnimator;

		private float duration;

		private bool hasCastBuff;

		private EffectManagerHelper _emh_defenseUp;

		public override void Reset()
		{
			base.Reset();
			modelAnimator = null;
			duration = 0f;
			hasCastBuff = false;
			_emh_defenseUp = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayCrossfade("Body", "DefenseUp", "DefenseUp.playbackRate", duration, 0.2f);
			}
		}

		public override void OnExit()
		{
			if (_emh_defenseUp != null && _emh_defenseUp.OwningPool != null)
			{
				_emh_defenseUp.OwningPool.ReturnObject(_emh_defenseUp);
				_emh_defenseUp = null;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && modelAnimator.GetFloat("DefenseUp.activate") > 0.5f && !hasCastBuff)
			{
				GameObject gameObject = null;
				if (!EffectManager.ShouldUsePooledEffect(defenseUpPrefab))
				{
					gameObject = UnityEngine.Object.Instantiate(defenseUpPrefab, base.transform.position, UnityEngine.Quaternion.identity, base.transform);
				}
				else
				{
					_emh_defenseUp = EffectManager.GetAndActivatePooledEffect(defenseUpPrefab, base.transform.position, UnityEngine.Quaternion.identity, base.transform);
					gameObject = _emh_defenseUp.gameObject;
				}
				ScaleParticleSystemDuration component = gameObject.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = buffDuration;
				}
				hasCastBuff = true;
				if (NetworkServer.active)
				{
					base.characterBody.AddTimedBuff(JunkContent.Buffs.EnrageAncientWisp, buffDuration);
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireSunder : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static string initialAttackSoundString;

		public static GameObject chargeEffectPrefab;

		public static GameObject projectilePrefab;

		public static GameObject hitEffectPrefab;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasAttacked;

		private float duration;

		private GameObject rightHandChargeEffect;

		private ChildLocator modelChildLocator;

		private Transform handRTransform;

		private EffectManagerHelper _emh_rightHandChargeEffect;

		public override void Reset()
		{
			base.Reset();
			modelAnimator = null;
			modelTransform = null;
			hasAttacked = false;
			duration = 0f;
			rightHandChargeEffect = null;
			modelChildLocator = null;
			handRTransform = null;
			_emh_rightHandChargeEffect = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			Util.PlaySound(initialAttackSoundString, base.gameObject);
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "FireSunder", "FireSunder.playbackRate", duration, 0.2f);
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration + 2f);
			}
			if (!modelTransform)
			{
				return;
			}
			AimAnimator component = modelTransform.GetComponent<AimAnimator>();
			if ((bool)component)
			{
				component.enabled = true;
			}
			modelChildLocator = modelTransform.GetComponent<ChildLocator>();
			if (!modelChildLocator)
			{
				return;
			}
			GameObject gameObject = chargeEffectPrefab;
			handRTransform = modelChildLocator.FindChild("HandR");
			if ((bool)handRTransform)
			{
				if (!EffectManager.ShouldUsePooledEffect(gameObject))
				{
					rightHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, handRTransform);
					return;
				}
				_emh_rightHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, handRTransform, inResetLocal: true);
				rightHandChargeEffect = _emh_rightHandChargeEffect.gameObject;
			}
		}

		public override void OnExit()
		{
			DestroyRightHandCharge();
			if ((bool)modelTransform)
			{
				AimAnimator component = modelTransform.GetComponent<AimAnimator>();
				if ((bool)component)
				{
					component.enabled = true;
				}
			}
			base.OnExit();
		}

		public void DestroyRightHandCharge()
		{
			if (_emh_rightHandChargeEffect != null && _emh_rightHandChargeEffect.OwningPool != null)
			{
				_emh_rightHandChargeEffect.OwningPool.ReturnObject(_emh_rightHandChargeEffect);
			}
			else
			{
				EntityState.Destroy(rightHandChargeEffect);
			}
			rightHandChargeEffect = null;
			_emh_rightHandChargeEffect = null;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && modelAnimator.GetFloat("FireSunder.activate") > 0.5f && !hasAttacked)
			{
				if (base.isAuthority && (bool)modelTransform)
				{
					Ray aimRay = GetAimRay();
					aimRay.origin = handRTransform.position;
					ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, damageStat * damageCoefficient, forceMagnitude, Util.CheckRoll(critStat, base.characterBody.master));
				}
				hasAttacked = true;
				DestroyRightHandCharge();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class GroundSlam : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		private OverlapAttack attack;

		public static string initialAttackSoundString;

		public static GameObject chargeEffectPrefab;

		public static GameObject slamEffectPrefab;

		public static GameObject hitEffectPrefab;

		private Animator modelAnimator;

		private Transform modelTransform;

		private bool hasAttacked;

		private float duration;

		private GameObject leftHandChargeEffect;

		private GameObject rightHandChargeEffect;

		private ChildLocator modelChildLocator;

		private EffectManagerHelper _emh_leftHandChargeEffect;

		private EffectManagerHelper _emh_rightHandChargeEffect;

		private Transform groundSlamIndicatorInstance;

		public override void Reset()
		{
			base.Reset();
			if (attack != null)
			{
				attack.Reset();
			}
			modelAnimator = null;
			modelTransform = null;
			hasAttacked = false;
			duration = 0f;
			leftHandChargeEffect = null;
			rightHandChargeEffect = null;
			modelChildLocator = null;
			_emh_leftHandChargeEffect = null;
			_emh_rightHandChargeEffect = null;
			groundSlamIndicatorInstance = null;
		}

		private void EnableIndicator(Transform indicator)
		{
			if ((bool)indicator)
			{
				indicator.gameObject.SetActive(value: true);
				ObjectScaleCurve component = indicator.gameObject.GetComponent<ObjectScaleCurve>();
				if ((bool)component)
				{
					component.time = 0f;
				}
			}
		}

		private void DisableIndicator(Transform indicator)
		{
			if ((bool)indicator)
			{
				indicator.gameObject.SetActive(value: false);
			}
		}

		public override void OnEnter()
		{
			base.OnEnter();
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			Util.PlaySound(initialAttackSoundString, base.gameObject);
			_ = (bool)base.characterDirection;
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.forceVector = UnityEngine.Vector3.up * forceMagnitude;
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == "GroundSlam");
			}
			duration = baseDuration / attackSpeedStat;
			PlayCrossfade("Body", "GroundSlam", "GroundSlam.playbackRate", duration, 0.2f);
			if (!modelTransform)
			{
				return;
			}
			modelChildLocator = modelTransform.GetComponent<ChildLocator>();
			if (!modelChildLocator)
			{
				return;
			}
			GameObject gameObject = chargeEffectPrefab;
			Transform transform = modelChildLocator.FindChild("HandL");
			Transform transform2 = modelChildLocator.FindChild("HandR");
			if ((bool)transform)
			{
				if (!EffectManager.ShouldUsePooledEffect(gameObject))
				{
					leftHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform);
				}
				else
				{
					_emh_leftHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform, inResetLocal: true);
					leftHandChargeEffect = _emh_leftHandChargeEffect.gameObject;
				}
			}
			if ((bool)transform2)
			{
				if (!EffectManager.ShouldUsePooledEffect(gameObject))
				{
					rightHandChargeEffect = UnityEngine.Object.Instantiate(gameObject, transform2);
				}
				else
				{
					_emh_rightHandChargeEffect = EffectManager.GetAndActivatePooledEffect(gameObject, transform2, inResetLocal: true);
					rightHandChargeEffect = _emh_rightHandChargeEffect.gameObject;
				}
			}
			groundSlamIndicatorInstance = modelChildLocator.FindChild("GroundSlamIndicator");
			EnableIndicator(groundSlamIndicatorInstance);
		}

		protected void DestroyChargeEffects()
		{
			if (_emh_leftHandChargeEffect != null && _emh_leftHandChargeEffect.OwningPool != null)
			{
				_emh_leftHandChargeEffect.OwningPool.ReturnObject(_emh_leftHandChargeEffect);
			}
			else
			{
				EntityState.Destroy(leftHandChargeEffect);
			}
			leftHandChargeEffect = null;
			_emh_leftHandChargeEffect = null;
			if (_emh_rightHandChargeEffect != null && _emh_rightHandChargeEffect.OwningPool != null)
			{
				_emh_rightHandChargeEffect.OwningPool.ReturnObject(_emh_rightHandChargeEffect);
			}
			else
			{
				EntityState.Destroy(rightHandChargeEffect);
			}
			rightHandChargeEffect = null;
			_emh_rightHandChargeEffect = null;
		}

		public override void OnExit()
		{
			DestroyChargeEffects();
			DisableIndicator(groundSlamIndicatorInstance);
			_ = (bool)base.characterDirection;
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)modelAnimator && modelAnimator.GetFloat("GroundSlam.hitBoxActive") > 0.5f && !hasAttacked)
			{
				if (NetworkServer.active)
				{
					attack.Fire();
				}
				if (base.isAuthority && (bool)modelTransform)
				{
					DisableIndicator(groundSlamIndicatorInstance);
					EffectManager.SimpleMuzzleFlash(slamEffectPrefab, base.gameObject, "SlamZone", transmit: true);
				}
				hasAttacked = true;
				DestroyChargeEffects();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : BaseState
	{
		public static float duration = 4f;

		public static string spawnSoundString;

		private static int Spawn1StateHash = Animator.StringToHash("Spawn1");

		private static int Spawn1ParamHash = Animator.StringToHash("Spawn1.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(spawnSoundString, base.gameObject);
			PlayAnimation("Body", Spawn1StateHash, Spawn1ParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.Barrel
{
	public class ActivateFan : EntityState
	{
		private static int IdleToActiveStateHash = Animator.StringToHash("IdleToActive");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Base", IdleToActiveStateHash);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					component.FindChild("JumpVolume").gameObject.SetActive(value: true);
					component.FindChild("LightBack").gameObject.SetActive(value: true);
					component.FindChild("LightFront").gameObject.SetActive(value: true);
				}
			}
			if ((bool)base.sfxLocator)
			{
				Util.PlaySound(base.sfxLocator.openSound, base.gameObject);
			}
		}
	}
	public class Closed : EntityState
	{
		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", "Closed");
		}
	}
	public class Closing : EntityState
	{
		public static float duration = 1f;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", "Closing", "Closing.playbackRate", duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new Closed());
			}
		}
	}
	public class Opened : EntityState
	{
		private static int OpenedStateHash = Animator.StringToHash("Opened");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", OpenedStateHash);
			SetPingable(value: false);
		}
	}
	public class Opening : EntityState
	{
		public static float duration = 1f;

		private static int OpeningStateHash = Animator.StringToHash("Opening");

		private static int OpeningParamHash = Animator.StringToHash("Opening.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", OpeningStateHash, OpeningParamHash, duration);
			if ((bool)base.sfxLocator)
			{
				Util.PlaySound(base.sfxLocator.openSound, base.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new Opened());
			}
		}
	}
	public class OpeningLunar : BaseState
	{
		public static float duration = 1f;

		private static int OpeningStateHash = Animator.StringToHash("Opening");

		private static int OpeningParamHash = Animator.StringToHash("Opening.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", OpeningStateHash, OpeningParamHash, duration);
			if ((bool)base.sfxLocator)
			{
				Util.PlaySound(base.sfxLocator.openSound, base.gameObject);
			}
			StopSteamEffect();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new Opened());
			}
		}

		private void StopSteamEffect()
		{
			Transform modelTransform = GetModelTransform();
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("SteamEffect");
			if ((bool)transform)
			{
				ParticleSystem component2 = transform.GetComponent<ParticleSystem>();
				if ((bool)component2)
				{
					ParticleSystem.MainModule main = component2.main;
					main.loop = false;
				}
			}
		}
	}
}
namespace EntityStates.Bandit2
{
	public class ThrowSmokebomb : BaseState
	{
		public static float duration;

		private static int throwSmokeBombStateHash = Animator.StringToHash("ThrowSmokebomb");

		private static int throwSmokeBombParamHash = Animator.StringToHash("ThrowSmokebomb.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Gesture, Additive", throwSmokeBombStateHash, throwSmokeBombParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new StealthMode());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class StealthMode : BaseState
	{
		public static float duration;

		public static string enterStealthSound;

		public static string exitStealthSound;

		public static float blastAttackRadius;

		public static float blastAttackDamageCoefficient;

		public static float blastAttackProcCoefficient;

		public static float blastAttackForce;

		public static GameObject smokeBombEffectPrefab;

		public static string smokeBombMuzzleString;

		public static float shortHopVelocity;

		private Animator animator;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			_ = (bool)animator;
			if ((bool)base.characterBody)
			{
				if (NetworkServer.active)
				{
					base.characterBody.AddBuff(RoR2Content.Buffs.Cloak);
					base.characterBody.AddBuff(RoR2Content.Buffs.CloakSpeed);
				}
				base.characterBody.onSkillActivatedAuthority += OnSkillActivatedAuthority;
			}
			FireSmokebomb();
			Util.PlaySound(enterStealthSound, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if (!outer.destroying)
			{
				FireSmokebomb();
			}
			Util.PlaySound(exitStealthSound, base.gameObject);
			if ((bool)base.characterBody)
			{
				base.characterBody.onSkillActivatedAuthority -= OnSkillActivatedAuthority;
				if (NetworkServer.active)
				{
					base.characterBody.RemoveBuff(RoR2Content.Buffs.CloakSpeed);
					base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak);
				}
			}
			if ((bool)animator)
			{
				animator.SetLayerWeight(animator.GetLayerIndex("Body, StealthWeapon"), 0f);
			}
			base.OnExit();
		}

		private void OnSkillActivatedAuthority(GenericSkill skill)
		{
			if (skill.skillDef.isCombatSkill)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireSmokebomb()
		{
			if (base.isAuthority)
			{
				BlastAttack obj = new BlastAttack
				{
					radius = blastAttackRadius,
					procCoefficient = blastAttackProcCoefficient,
					position = base.transform.position,
					attacker = base.gameObject,
					crit = Util.CheckRoll(base.characterBody.crit, base.characterBody.master),
					baseDamage = base.characterBody.damage * blastAttackDamageCoefficient,
					falloffModel = BlastAttack.FalloffModel.None,
					damageType = DamageType.Stun1s,
					baseForce = blastAttackForce
				};
				obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
				obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
				obj.Fire();
			}
			if ((bool)smokeBombEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(smokeBombEffectPrefab, base.gameObject, smokeBombMuzzleString, transmit: false);
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, shortHopVelocity, base.characterMotor.velocity.z);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Bandit2.Weapon
{
	public abstract class Bandit2FirePrimaryBase : GenericBulletBaseState
	{
		[SerializeField]
		public float minimumBaseDuration;

		protected float minimumDuration;

		private static int FireMainWeaponStateHash = Animator.StringToHash("FireMainWeapon");

		private static int FireMainWeaponParamHash = Animator.StringToHash("FireMainWeapon.playbackRate");

		public override void OnEnter()
		{
			minimumDuration = minimumBaseDuration / attackSpeedStat;
			base.OnEnter();
			PlayAnimation("Gesture, Additive", FireMainWeaponStateHash, FireMainWeaponParamHash, duration);
		}

		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.falloffModel = BulletAttack.FalloffModel.DefaultBullet;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if (!(base.fixedAge > minimumDuration))
			{
				return InterruptPriority.Skill;
			}
			return InterruptPriority.Any;
		}
	}
	public class Bandit2FireRifle : Bandit2FirePrimaryBase
	{
		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
		}
	}
	public class Bandit2FireShiv : BaseSkillState
	{
		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public int maxShivCount;

		public static float baseDelayBetweenShivs;

		public static float shortHopVelocity;

		public static GameObject muzzleEffectPrefab;

		public static string muzzleString;

		private float duration;

		private float delayBetweenShivs;

		private float countdownSinceLastShiv;

		private int shivCount;

		private static int SlashBladeStateHash = Animator.StringToHash("SlashBlade");

		private static int SlashBladeParamHash = Animator.StringToHash("SlashBlade.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			delayBetweenShivs = baseDelayBetweenShivs / attackSpeedStat;
			PlayAnimation("Gesture, Additive", SlashBladeStateHash, SlashBladeParamHash, duration);
			StartAimMode();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity), base.characterMotor.velocity.z);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			countdownSinceLastShiv -= GetDeltaTime();
			if (shivCount < maxShivCount && countdownSinceLastShiv <= 0f)
			{
				shivCount++;
				countdownSinceLastShiv += delayBetweenShivs;
				FireShiv();
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		private void FireShiv()
		{
			if ((bool)muzzleEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(muzzleEffectPrefab, base.gameObject, muzzleString, transmit: false);
			}
			if (base.isAuthority)
			{
				Ray ray = GetAimRay();
				if (projectilePrefab != null)
				{
					TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref ray, projectilePrefab, base.gameObject);
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.projectilePrefab = projectilePrefab;
					fireProjectileInfo.position = ray.origin;
					fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(ray.direction);
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.damage = damageStat * damageCoefficient;
					fireProjectileInfo.force = force;
					fireProjectileInfo.crit = RollCrit();
					fireProjectileInfo.damageTypeOverride = DamageType.SuperBleedOnCrit;
					FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
					ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class FireShotgun2 : Bandit2FirePrimaryBase
	{
		[SerializeField]
		public float minFixedSpreadYaw;

		[SerializeField]
		public float maxFixedSpreadYaw;

		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.bulletCount = 1u;
			bulletAttack.allowTrajectoryAimAssist = false;
		}

		protected override void FireBullet(Ray aimRay)
		{
			StartAimMode(aimRay, 3f);
			DoFireEffects();
			PlayFireAnimation();
			AddRecoil(-1f * recoilAmplitudeY, -1.5f * recoilAmplitudeY, -1f * recoilAmplitudeX, 1f * recoilAmplitudeX);
			if (base.isAuthority)
			{
				UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, aimRay.direction);
				UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(aimRay.direction, rhs);
				float num = 0f;
				if ((bool)base.characterBody)
				{
					num = base.characterBody.spreadBloomAngle;
				}
				float angle = 0f;
				float num2 = 0f;
				if (bulletCount > 1)
				{
					num2 = UnityEngine.Random.Range(minFixedSpreadYaw + num, maxFixedSpreadYaw + num) * 2f;
					angle = num2 / (float)(bulletCount - 1);
				}
				TrajectoryAimAssist.ApplyTrajectoryAimAssist(ref aimRay, maxDistance, base.gameObject);
				UnityEngine.Vector3 direction = UnityEngine.Quaternion.AngleAxis((0f - num2) * 0.5f, axis) * aimRay.direction;
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, axis);
				Ray aimRay2 = new Ray(aimRay.origin, direction);
				for (int i = 0; i < bulletCount; i++)
				{
					BulletAttack bulletAttack = GenerateBulletAttack(aimRay2);
					ModifyBullet(bulletAttack);
					bulletAttack.Fire();
					aimRay2.direction = quaternion * aimRay2.direction;
				}
			}
		}
	}
	public class EnterReload : BaseState
	{
		public static string enterSoundString;

		public static float baseDuration;

		private float duration => baseDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade("Gesture, Additive", "EnterReload", "Reload.playbackRate", duration, 0.1f);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.fixedAge > duration)
			{
				outer.SetNextState(new Reload());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Reload : BaseState
	{
		public static float enterSoundPitch;

		public static float exitSoundPitch;

		public static string enterSoundString;

		public static string exitSoundString;

		public static GameObject reloadEffectPrefab;

		public static string reloadEffectMuzzleString;

		public static float baseDuration;

		private bool hasGivenStock;

		private static int ReloadSimpleStateHash = Animator.StringToHash("ReloadSimple");

		private static int ReloadStateHash = Animator.StringToHash("Reload");

		private static int ReloadParamHash = Animator.StringToHash("Reload.playbackRate");

		private float duration => baseDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Gesture, Additive", (base.characterBody.isSprinting && (bool)base.characterMotor && base.characterMotor.isGrounded) ? ReloadSimpleStateHash : ReloadStateHash, ReloadParamHash, duration);
			Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, enterSoundPitch);
			EffectManager.SimpleMuzzleFlash(reloadEffectPrefab, base.gameObject, reloadEffectMuzzleString, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration / 2f)
			{
				GiveStock();
			}
			if (base.isAuthority && base.fixedAge >= duration)
			{
				if (base.skillLocator.primary.stock < base.skillLocator.primary.maxStock)
				{
					outer.SetNextState(new Reload());
					return;
				}
				Util.PlayAttackSpeedSound(exitSoundString, base.gameObject, exitSoundPitch);
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		private void GiveStock()
		{
			if (!hasGivenStock)
			{
				base.skillLocator.primary.AddOneStock();
				hasGivenStock = true;
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class BaseSidearmState : BaseState
	{
		[SerializeField]
		public float baseDuration;

		[SerializeField]
		public GameObject crosshairOverridePrefab;

		protected float duration;

		private Animator animator;

		private int bodySideWeaponLayerIndex;

		private CrosshairUtils.OverrideRequest crosshairOverrideRequest;

		public virtual string exitAnimationStateName => "BufferEmpty";

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			duration = baseDuration / attackSpeedStat;
			if ((bool)animator)
			{
				bodySideWeaponLayerIndex = animator.GetLayerIndex("Body, SideWeapon");
				animator.SetLayerWeight(bodySideWeaponLayerIndex, 1f);
			}
			if ((bool)crosshairOverridePrefab)
			{
				crosshairOverrideRequest = CrosshairUtils.RequestOverrideForBody(base.characterBody, crosshairOverridePrefab, CrosshairUtils.OverridePriority.Skill);
			}
			base.characterBody.SetAimTimer(3f);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority && base.characterBody.isSprinting)
			{
				outer.SetNextStateToMain();
			}
		}

		public override void OnExit()
		{
			if ((bool)animator)
			{
				animator.SetLayerWeight(bodySideWeaponLayerIndex, 0f);
			}
			PlayAnimation("Gesture, Additive", exitAnimationStateName);
			crosshairOverrideRequest?.Dispose();
			Transform transform = FindModelChild("SpinningPistolFX");
			if ((bool)transform)
			{
				transform.gameObject.SetActive(value: false);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public abstract class BasePrepSidearmRevolverState : BaseSidearmState
	{
		[SerializeField]
		public string enterSoundString;

		private Animator animator;

		private static int MainToSideStateHash = Animator.StringToHash("MainToSide");

		private static int MainToSideParamHash = Animator.StringToHash("MainToSide.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Gesture, Additive", MainToSideStateHash, MainToSideParamHash, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(GetNextState());
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		protected abstract EntityState GetNextState();
	}
	public class ExitSidearmRevolver : BaseSidearmState
	{
		public override string exitAnimationStateName => "SideToMain";

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}
	}
	public abstract class BaseFireSidearmRevolverState : BaseSidearmState
	{
		[SerializeField]
		public GameObject effectPrefab;

		[SerializeField]
		public GameObject hitEffectPrefab;

		[SerializeField]
		public GameObject tracerEffectPrefab;

		[SerializeField]
		public float damageCoefficient;

		[SerializeField]
		public float force;

		[SerializeField]
		public float minSpread;

		[SerializeField]
		public float maxSpread;

		[SerializeField]
		public string attackSoundString;

		[SerializeField]
		public float recoilAmplitude;

		[SerializeField]
		public float bulletRadius;

		[SerializeField]
		public float trajectoryAimAssistMultiplier = 0.75f;

		private static int FireSideWeaponStateHash = Animator.StringToHash("FireSideWeapon");

		private static int FireSideWeaponParamHash = Animator.StringToHash("FireSideWeapon.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			AddRecoil(-3f * recoilAmplitude, -4f * recoilAmplitude, -0.5f * recoilAmplitude, 0.5f * recoilAmplitude);
			Ray aimRay = GetAimRay();
			StartAimMode(aimRay);
			string muzzleName = "MuzzlePistol";
			Util.PlaySound(attackSoundString, base.gameObject);
			PlayAnimation("Gesture, Additive", FireSideWeaponStateHash, FireSideWeaponParamHash, duration);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, muzzleName, transmit: false);
			}
			if (base.isAuthority)
			{
				BulletAttack bulletAttack = new BulletAttack();
				bulletAttack.owner = base.gameObject;
				bulletAttack.weapon = base.gameObject;
				bulletAttack.origin = aimRay.origin;
				bulletAttack.aimVector = aimRay.direction;
				bulletAttack.minSpread = minSpread;
				bulletAttack.maxSpread = maxSpread;
				bulletAttack.bulletCount = 1u;
				bulletAttack.damage = damageCoefficient * damageStat;
				bulletAttack.force = force;
				bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
				bulletAttack.tracerEffectPrefab = tracerEffectPrefab;
				bulletAttack.muzzleName = muzzleName;
				bulletAttack.hitEffectPrefab = hitEffectPrefab;
				bulletAttack.isCrit = RollCrit();
				bulletAttack.HitEffectNormal = false;
				bulletAttack.radius = bulletRadius;
				bulletAttack.damageType |= (DamageTypeCombo)DamageType.BonusToLowHealth;
				bulletAttack.smartCollision = true;
				bulletAttack.trajectoryAimAssistMultiplier = trajectoryAimAssistMultiplier;
				ModifyBullet(bulletAttack);
				bulletAttack.Fire();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new ExitSidearmRevolver());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Any;
		}

		protected virtual void ModifyBullet(BulletAttack bulletAttack)
		{
		}
	}
	public class PrepSidearmResetRevolver : BasePrepSidearmRevolverState
	{
		protected override EntityState GetNextState()
		{
			return new FireSidearmResetRevolver();
		}
	}
	public class FireSidearmResetRevolver : BaseFireSidearmRevolverState
	{
		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			bulletAttack.damageType |= (DamageTypeCombo)DamageType.ResetCooldownsOnKill;
		}
	}
	public class PrepSidearmSkullRevolver : BasePrepSidearmRevolverState
	{
		protected override EntityState GetNextState()
		{
			return new FireSidearmSkullRevolver();
		}
	}
	public class FireSidearmSkullRevolver : BaseFireSidearmRevolverState
	{
		protected override void ModifyBullet(BulletAttack bulletAttack)
		{
			base.ModifyBullet(bulletAttack);
			int num = 0;
			if ((bool)base.characterBody)
			{
				num = base.characterBody.GetBuffCount(RoR2Content.Buffs.BanditSkull);
			}
			bulletAttack.damage *= 1f + 0.1f * (float)num;
			bulletAttack.damageType |= (DamageTypeCombo)DamageType.GiveSkullOnKill;
		}
	}
	public class SlashBlade : BasicMeleeAttack
	{
		public static float shortHopVelocity;

		public static float selfForceStrength;

		public static float minimumBaseDuration;

		public static AnimationCurve bloomCurve;

		private GameObject bladeMeshObject;

		private static int SlashBladeStateHash = Animator.StringToHash("SlashBlade");

		private static int SlashBladeParamHash = Animator.StringToHash("SlashBlade.playbackRate");

		private float minimumDuration => minimumBaseDuration / attackSpeedStat;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Gesture, Additive", SlashBladeStateHash, SlashBladeParamHash, duration);
			bladeMeshObject = FindModelChild("BladeMesh").gameObject;
			if ((bool)bladeMeshObject)
			{
				bladeMeshObject.SetActive(value: true);
			}
			base.characterMotor.ApplyForce(base.inputBank.moveVector * selfForceStrength, alwaysApply: true);
			if ((bool)base.characterMotor)
			{
				base.characterMotor.velocity = new UnityEngine.Vector3(base.characterMotor.velocity.x, Mathf.Max(base.characterMotor.velocity.y, shortHopVelocity), base.characterMotor.velocity.z);
			}
		}

		protected override void AuthorityModifyOverlapAttack(OverlapAttack overlapAttack)
		{
			base.AuthorityModifyOverlapAttack(overlapAttack);
			overlapAttack.damageType = DamageType.SuperBleedOnCrit;
		}

		public override void Update()
		{
			base.Update();
			base.characterBody.SetSpreadBloom(bloomCurve.Evaluate(base.age / duration), canOnlyIncreaseBloom: false);
		}

		public override void OnExit()
		{
			if ((bool)bladeMeshObject)
			{
				bladeMeshObject.SetActive(value: false);
			}
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			if ((bool)base.inputBank)
			{
				if (!(base.fixedAge > minimumDuration))
				{
					return InterruptPriority.PrioritySkill;
				}
				return InterruptPriority.Skill;
			}
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.AurelioniteHeart
{
	public class AurelioniteHeartEntityState : EntityState
	{
		protected AurelioniteHeartController heartController;

		protected Animator animator;

		protected Xoroshiro128Plus rng;

		protected UnityEngine.Vector3 inertPosition;

		protected float heartMovementTimer;

		public static event Action falseSonUnlockEvent;

		public override void OnEnter()
		{
			base.OnEnter();
			heartController = base.gameObject.GetComponent<AurelioniteHeartController>();
			animator = heartController.heartAnimator;
			rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			inertPosition = new UnityEngine.Vector3(base.gameObject.transform.position.x, base.gameObject.transform.position.y - 1f, base.gameObject.transform.position.z);
		}

		public void FalseSonUnlocked()
		{
			AurelioniteHeartEntityState.falseSonUnlockEvent?.Invoke();
		}
	}
	public class AurelioniteHeartIdleState : AurelioniteHeartEntityState
	{
		public override void OnEnter()
		{
			base.OnEnter();
		}
	}
	public class AurelioniteHeartActivationState : AurelioniteHeartEntityState
	{
		public static float expGrantingDuration = 3f;

		[SerializeField]
		public static float itemGrantingDuration = 10f;

		[SerializeField]
		public ItemTier rewardDisplayTier;

		[SerializeField]
		[Tooltip("The prefab to use for the reward pickup.")]
		public GameObject rewardPickupPrefab;

		[SerializeField]
		public UnityEngine.Vector3 rewardOffset;

		[SerializeField]
		public string falseSonSurvivorAchievement;

		[SerializeField]
		public ItemDef halcyonSeed;

		[SerializeField]
		public int rewardOptionCount = 1;

		[SerializeField]
		public PickupDropTable rewardDropTable;

		public bool rewardGiven;

		public override void OnEnter()
		{
			base.OnEnter();
			rewardGiven = false;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!heartController.activated || !(base.fixedAge >= expGrantingDuration))
			{
				return;
			}
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (base.gameObject == null || rewardDropTable == null || participatingPlayerCount == 0)
			{
				return;
			}
			if (participatingPlayerCount > 0 && (bool)base.gameObject && (bool)rewardDropTable && !rewardGiven)
			{
				rewardGiven = true;
				int num = participatingPlayerCount;
				float angle = 360f / (float)num;
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				UnityEngine.Vector3 position = base.gameObject.transform.position + rewardOffset;
				int num2 = 0;
				while (num2 < num)
				{
					GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo);
					pickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier);
					pickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, rewardDropTable, rng);
					pickupInfo.rotation = UnityEngine.Quaternion.identity;
					pickupInfo.prefabOverride = rewardPickupPrefab;
					PickupDropletController.CreatePickupDroplet(pickupInfo, position, vector);
					num2++;
					vector = quaternion * vector;
				}
			}
			if (base.fixedAge >= itemGrantingDuration)
			{
				if (FalseSonUnlockStateMet())
				{
					outer.SetNextState(new AurelioniteHeartFalseSonSurvivorUnlockState());
				}
				else
				{
					outer.SetNextState(new AurelioniteHeartInertState());
				}
			}
		}

		private bool FalseSonUnlockStateMet()
		{
			bool result = false;
			int num = 0;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (!instance.networkUser.localUser.userProfile.HasAchievement("UnlockFalseSon"))
				{
					num++;
				}
			}
			if (num > 0)
			{
				foreach (PlayerCharacterMasterController instance2 in PlayerCharacterMasterController.instances)
				{
					if (instance2.master.inventory.GetItemCount(RoR2Content.Items.TitanGoldDuringTP) > 0 && num > 0)
					{
						result = true;
						GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/DelusionItemDissolveVFX");
						EffectData effectData = new EffectData
						{
							origin = instance2.master.GetBody().transform.position,
							genericFloat = 1.5f,
							genericUInt = (uint)(halcyonSeed.itemIndex + 1)
						};
						effectData.SetNetworkedObjectReference(base.gameObject);
						EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
						instance2.master.inventory.RemoveItem(halcyonSeed);
						FalseSonUnlocked();
					}
				}
			}
			return result;
		}
	}
	public class AurelioniteHeartFalseSonSurvivorUnlockState : AurelioniteHeartEntityState
	{
		[SerializeField]
		public float animationDuration = 4f;

		[SerializeField]
		public float initialDelay = 2f;

		[SerializeField]
		public string falseSonUnlockAnimationState;

		[SerializeField]
		public float upwardMovement = 0.2f;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!(base.fixedAge >= initialDelay))
			{
				return;
			}
			heartMovementTimer -= GetDeltaTime();
			base.gameObject.transform.position += new UnityEngine.Vector3(0f, upwardMovement, 0f);
			if (heartMovementTimer <= 0f)
			{
				heartMovementTimer += 0.02f;
				upwardMovement += upwardMovement / 10f;
				if (base.fixedAge >= animationDuration)
				{
					heartController.rebirthShrine.SetActive(value: true);
					EntityState.Destroy(base.gameObject);
				}
			}
		}
	}
	public class AurelioniteHeartInertState : AurelioniteHeartEntityState
	{
		[SerializeField]
		private float animationDuration = 1f;

		[SerializeField]
		private string heartInertAnimationState;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			heartMovementTimer -= GetDeltaTime();
			if (heartMovementTimer <= 0f)
			{
				heartMovementTimer += 0.02f;
				if (base.gameObject.transform.position != inertPosition)
				{
					base.gameObject.transform.position += new UnityEngine.Vector3(0f, -0.25f, 0f);
					return;
				}
				animator.StopPlayback();
				heartController.rebirthShrine.SetActive(value: true);
				outer.SetNextState(new AurelioniteHeartIdleState());
			}
		}
	}
}
namespace EntityStates.Assassin2
{
	public class ChargeDash : BaseState
	{
		public static float baseDuration = 1.5f;

		public static string enterSoundString;

		private Animator modelAnimator;

		private float duration;

		private int slashCount;

		private Transform modelTransform;

		private UnityEngine.Vector3 oldVelocity;

		private bool dashComplete;

		private static int PreAttackStateHash = Animator.StringToHash("PreAttack");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(enterSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			AimAnimator component = modelTransform.GetComponent<AimAnimator>();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)component)
			{
				component.enabled = true;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = GetAimRay().direction;
			}
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", PreAttackStateHash);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration && base.isAuthority)
			{
				outer.SetNextState(new DashStrike());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class DashStrike : BaseState
	{
		public static float dashDuration = 1f;

		public static float slashDuration = 1.667f;

		public static float damageCoefficient = 4f;

		public static float procCoefficient;

		public static float selfForce;

		public static float forceMagnitude = 16f;

		public static float maxDashSpeedCoefficient = 4f;

		public static float maxSlashDistance = 20f;

		public static GameObject hitEffectPrefab;

		public static GameObject swipeEffectPrefab;

		public static string enterSoundString;

		public static string slashSoundString;

		private UnityEngine.Vector3 targetMoveVector;

		private UnityEngine.Vector3 targetMoveVectorVelocity;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private int slashCount;

		private Transform modelTransform;

		private bool dashComplete;

		private int handParamHash;

		private int swordParamHash;

		private float calculatedDashSpeed;

		private bool startedSlash;

		private static int DashStateHash = Animator.StringToHash("Dash");

		private static int SwordStrikeStateHash = Animator.StringToHash("SwordStrike");

		private static int forwardSpeedParamHash = Animator.StringToHash("forwardSpeed");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = (dashDuration + slashDuration) / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			modelTransform = GetModelTransform();
			base.characterMotor.velocity = UnityEngine.Vector3.zero;
			float sqrMagnitude = (base.characterBody.master.GetComponent<BaseAI>().currentEnemy.characterBody.corePosition - base.characterBody.corePosition).sqrMagnitude;
			calculatedDashSpeed = Util.Remap(sqrMagnitude, 0f, maxSlashDistance * maxSlashDistance, 0f, maxDashSpeedCoefficient);
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			attack.procCoefficient = procCoefficient;
			attack.damageType = DamageType.Generic;
			Util.PlayAttackSpeedSound(enterSoundString, base.gameObject, attackSpeedStat);
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture", DashStateHash);
				handParamHash = Animator.StringToHash("HandStrike");
				swordParamHash = Animator.StringToHash("SwordStrike");
			}
		}

		public override void OnExit()
		{
			base.characterMotor.walkSpeedPenaltyCoefficient = 1f;
			base.OnExit();
		}

		private void HandleSlash(int animatorParamHash, string muzzleName, string hitBoxGroupName)
		{
			bool flag = false;
			if (modelAnimator.GetFloat(animatorParamHash) > 0.1f)
			{
				if (!startedSlash)
				{
					Util.PlaySound(slashSoundString, base.gameObject);
					EffectManager.SimpleMuzzleFlash(swipeEffectPrefab, base.gameObject, muzzleName, transmit: true);
					startedSlash = true;
				}
				if ((bool)modelTransform)
				{
					attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == hitBoxGroupName);
				}
				if ((bool)base.healthComponent)
				{
					base.healthComponent.TakeDamageForce(base.characterDirection.forward * selfForce, alwaysApply: true);
				}
				attack.ResetIgnoredHealthComponents();
				if ((bool)base.characterDirection)
				{
					attack.forceVector = base.characterDirection.forward * forceMagnitude;
				}
				flag = attack.Fire();
			}
			else if (startedSlash || flag)
			{
				slashCount++;
				startedSlash = false;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!dashComplete)
			{
				targetMoveVector = UnityEngine.Vector3.ProjectOnPlane(UnityEngine.Vector3.SmoothDamp(targetMoveVector, base.inputBank.aimDirection, ref targetMoveVectorVelocity, 0f, 0f), UnityEngine.Vector3.up).normalized;
				base.characterDirection.moveVector = targetMoveVector;
				UnityEngine.Vector3 forward = base.characterDirection.forward;
				float value = moveSpeedStat * calculatedDashSpeed;
				base.characterMotor.moveDirection = forward * calculatedDashSpeed;
				modelAnimator.SetFloat(forwardSpeedParamHash, value);
			}
			if (NetworkServer.active)
			{
				if (base.fixedAge > dashDuration && !dashComplete)
				{
					PlayAnimation("Gesture", SwordStrikeStateHash);
					dashComplete = true;
				}
				if ((bool)modelAnimator)
				{
					switch (slashCount)
					{
					case 0:
						HandleSlash(handParamHash, "ShurikenTag", "ShurikenHitbox");
						break;
					case 1:
						HandleSlash(swordParamHash, "Sword", "SwordHitbox");
						break;
					}
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject deathEffectPrefab;

		public static float duration = 1.333f;

		private float stopwatch;

		private Animator animator;

		private bool hasPlayedDeathEffect;

		public override void OnEnter()
		{
			base.OnEnter();
			animator = GetModelAnimator();
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = false;
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if ((bool)animator)
			{
				stopwatch += GetDeltaTime();
				if (!hasPlayedDeathEffect && animator.GetFloat("DeathEffect") > 0.5f)
				{
					hasPlayedDeathEffect = true;
					EffectData effectData = new EffectData();
					effectData.origin = base.transform.position;
					EffectManager.SpawnEffect(deathEffectPrefab, effectData, transmit: false);
				}
				if (stopwatch >= duration)
				{
					DestroyModel();
					EntityState.Destroy(base.gameObject);
				}
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class Hide : BaseState
	{
		private Transform modelTransform;

		public static GameObject hideEfffectPrefab;

		public static GameObject smokeEffectPrefab;

		public static Material destealthMaterial;

		private float stopwatch;

		private UnityEngine.Vector3 blinkDestination = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 blinkStart = UnityEngine.Vector3.zero;

		[Tooltip("the length of time to stay hidden")]
		public static float hiddenDuration = 5f;

		[Tooltip("the entire duration of the hidden state (hidden time + time after)")]
		public static float fullDuration = 10f;

		public static string beginSoundString;

		public static string endSoundString;

		private Animator animator;

		private CharacterModel characterModel;

		private HurtBoxGroup hurtboxGroup;

		private bool hidden;

		private GameObject smokeEffectInstance;

		private static int DisappearStateHash = Animator.StringToHash("Disappear");

		private static int AppearStateHash = Animator.StringToHash("Appear");

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(beginSoundString, base.gameObject);
			modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				animator = modelTransform.GetComponent<Animator>();
				characterModel = modelTransform.GetComponent<CharacterModel>();
				hurtboxGroup = modelTransform.GetComponent<HurtBoxGroup>();
				if ((bool)smokeEffectPrefab)
				{
					Transform transform = modelTransform;
					if ((bool)transform)
					{
						smokeEffectInstance = UnityEngine.Object.Instantiate(smokeEffectPrefab, transform);
						ScaleParticleSystemDuration component = smokeEffectInstance.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component)
						{
							component.newDuration = component.initialDuration;
						}
					}
				}
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter + 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			PlayAnimation("Gesture", DisappearStateHash);
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.AddBuff(RoR2Content.Buffs.Cloak);
			}
			CreateHiddenEffect(Util.GetCorePosition(base.gameObject));
			if ((bool)base.healthComponent)
			{
				base.healthComponent.dontShowHealthbar = true;
			}
			hidden = true;
		}

		private void CreateHiddenEffect(UnityEngine.Vector3 origin)
		{
			EffectData effectData = new EffectData();
			effectData.origin = origin;
			EffectManager.SpawnEffect(hideEfffectPrefab, effectData, transmit: false);
		}

		private void SetPosition(UnityEngine.Vector3 newPosition)
		{
			if ((bool)base.characterMotor)
			{
				base.characterMotor.Motor.SetPositionAndRotation(newPosition, UnityEngine.Quaternion.identity);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= hiddenDuration && hidden)
			{
				Reveal();
			}
			if (base.isAuthority && stopwatch > fullDuration)
			{
				outer.SetNextStateToMain();
			}
		}

		private void Reveal()
		{
			Util.PlaySound(endSoundString, base.gameObject);
			CreateHiddenEffect(Util.GetCorePosition(base.gameObject));
			if ((bool)modelTransform && (bool)destealthMaterial)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(animator.gameObject);
				temporaryOverlayInstance.duration = 1f;
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = destealthMaterial;
				temporaryOverlayInstance.inspectorCharacterModel = animator.gameObject.GetComponent<CharacterModel>();
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.animateShaderAlpha = true;
			}
			if ((bool)hurtboxGroup)
			{
				HurtBoxGroup hurtBoxGroup = hurtboxGroup;
				int hurtBoxesDeactivatorCounter = hurtBoxGroup.hurtBoxesDeactivatorCounter - 1;
				hurtBoxGroup.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
			}
			if ((bool)base.characterMotor)
			{
				base.characterMotor.enabled = true;
			}
			PlayAnimation("Gesture", AppearStateHash);
			if ((bool)base.characterBody && NetworkServer.active)
			{
				base.characterBody.RemoveBuff(RoR2Content.Buffs.Cloak);
			}
			if ((bool)base.healthComponent)
			{
				base.healthComponent.dontShowHealthbar = false;
			}
			if ((bool)smokeEffectInstance)
			{
				EntityState.Destroy(smokeEffectInstance);
			}
			hidden = false;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : BaseState
	{
		private float stopwatch;

		public static float animDuration = 1.5f;

		public static float duration = 4f;

		public static string spawnSoundString;

		public static GameObject spawnEffectPrefab;

		private static int SpawnStateHash = Animator.StringToHash("Spawn");

		public override void OnEnter()
		{
			base.OnEnter();
			PlayAnimation("Body", SpawnStateHash);
			Util.PlaySound(spawnSoundString, base.gameObject);
			if ((bool)spawnEffectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(spawnEffectPrefab, base.gameObject, "Base", transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			stopwatch += GetDeltaTime();
			if (stopwatch >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
	public class ThrowShuriken : GenericProjectileBaseState
	{
		public static string attackString;

		private Transform muzzleTransform;

		private static int ThrowShurikenStateHash = Animator.StringToHash("ThrowShuriken");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture", ThrowShurikenStateHash);
			Util.PlaySound(attackString, base.gameObject);
			GetAimRay();
			string text = "ShurikenTag";
			muzzleTransform = FindModelChild(text);
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false);
			}
			if (base.isAuthority)
			{
				FireProjectile();
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
}
namespace EntityStates.Assassin.Weapon
{
	public class SlashCombo : BaseState
	{
		public enum SlashComboPermutation
		{
			Slash1,
			Slash2,
			Final
		}

		public static float baseDuration = 3.5f;

		public static float mecanimDurationCoefficient;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float selfForceMagnitude;

		public static float radius = 3f;

		public static GameObject hitEffectPrefab;

		public static GameObject swingEffectPrefab;

		public static string attackString;

		private OverlapAttack attack;

		private Animator modelAnimator;

		private float duration;

		private bool hasSlashed;

		public SlashComboPermutation slashComboPermutation;

		private static int SlashP1Hash = Animator.StringToHash("SlashP1");

		private static int SlashP2Hash = Animator.StringToHash("SlashP2");

		private static int SlashP3Hash = Animator.StringToHash("SlashP3");

		private static int SlashComboParamHash = Animator.StringToHash("SlashCombo.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			attack = new OverlapAttack();
			attack.attacker = base.gameObject;
			attack.inflictor = base.gameObject;
			attack.teamIndex = TeamComponent.GetObjectTeam(attack.attacker);
			attack.damage = damageCoefficient * damageStat;
			attack.hitEffectPrefab = hitEffectPrefab;
			attack.isCrit = Util.CheckRoll(critStat, base.characterBody.master);
			Util.PlaySound(attackString, base.gameObject);
			string hitboxGroupName = "";
			int animationStateHash = -1;
			switch (slashComboPermutation)
			{
			case SlashComboPermutation.Slash1:
				hitboxGroupName = "DaggerLeft";
				animationStateHash = SlashP1Hash;
				break;
			case SlashComboPermutation.Slash2:
				hitboxGroupName = "DaggerLeft";
				animationStateHash = SlashP2Hash;
				break;
			case SlashComboPermutation.Final:
				hitboxGroupName = "DaggerLeft";
				animationStateHash = SlashP3Hash;
				break;
			}
			if ((bool)modelTransform)
			{
				attack.hitBoxGroup = Array.Find(modelTransform.GetComponents<HitBoxGroup>(), (HitBoxGroup element) => element.groupName == hitboxGroupName);
			}
			if ((bool)modelAnimator)
			{
				PlayAnimation("Gesture, Override", animationStateHash, SlashComboParamHash, duration * mecanimDurationCoefficient);
				PlayAnimation("Gesture, Additive", animationStateHash, SlashComboParamHash, duration * mecanimDurationCoefficient);
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("SlashCombo.hitBoxActive") > 0.1f)
			{
				if (!hasSlashed)
				{
					EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "SwingCenter", transmit: true);
					HealthComponent healthComponent = base.characterBody.healthComponent;
					CharacterDirection component = base.characterBody.GetComponent<CharacterDirection>();
					if ((bool)healthComponent)
					{
						healthComponent.TakeDamageForce(selfForceMagnitude * component.forward, alwaysApply: true);
					}
					hasSlashed = true;
				}
				attack.forceVector = base.transform.forward * forceMagnitude;
				attack.Fire();
			}
			if (!(base.fixedAge >= duration) || !base.isAuthority)
			{
				return;
			}
			if ((bool)base.inputBank && base.inputBank.skill1.down)
			{
				SlashCombo slashCombo = new SlashCombo();
				switch (slashComboPermutation)
				{
				case SlashComboPermutation.Slash1:
					slashCombo.slashComboPermutation = SlashComboPermutation.Slash2;
					break;
				case SlashComboPermutation.Slash2:
					slashCombo.slashComboPermutation = SlashComboPermutation.Slash1;
					break;
				}
				outer.SetNextState(slashCombo);
			}
			else
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
}
namespace EntityStates.ArtifactShell
{
	public class ArtifactShellBaseState : BaseState
	{
		protected Light light;

		private string stopLoopSound;

		protected PurchaseInteraction purchaseInteraction { get; private set; }

		protected virtual CostTypeIndex interactionCostType => CostTypeIndex.None;

		protected virtual bool interactionAvailable => false;

		protected virtual int interactionCost => 0;

		protected ParticleSystem rayParticleSystem { get; private set; }

		protected PostProcessVolume postProcessVolume { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			if ((object)purchaseInteraction != null)
			{
				purchaseInteraction.costType = interactionCostType;
				purchaseInteraction.Networkcost = interactionCost;
				purchaseInteraction.Networkavailable = interactionAvailable;
				purchaseInteraction.onPurchase.AddListener(DoOnPurchase);
			}
			rayParticleSystem = FindModelChild("RayParticles")?.GetComponent<ParticleSystem>();
			postProcessVolume = FindModelChild("PP")?.GetComponent<PostProcessVolume>();
			light = FindModelChild("Light").GetComponent<Light>();
			CalcLoopSounds(base.healthComponent.combinedHealthFraction, out var startLoopSound, out stopLoopSound);
			Util.PlaySound(startLoopSound, base.gameObject);
		}

		private static void CalcLoopSounds(float currentHealthFraction, out string startLoopSound, out string stopLoopSound)
		{
			startLoopSound = null;
			stopLoopSound = null;
			float num = 0.05f;
			if (currentHealthFraction > 0.75f + num)
			{
				startLoopSound = "Play_artifactBoss_loop_level1";
				stopLoopSound = "Stop_artifactBoss_loop_level1";
			}
			else if (currentHealthFraction > 0.25f + num)
			{
				startLoopSound = "Play_artifactBoss_loop_level2";
				stopLoopSound = "Stop_artifactBoss_loop_level2";
			}
			else if (currentHealthFraction > 0f + num)
			{
				startLoopSound = "Play_artifactBoss_loop_level2";
				stopLoopSound = "Stop_artifactBoss_loop_level2";
			}
		}

		public override void OnExit()
		{
			Util.PlaySound(stopLoopSound, base.gameObject);
			if ((object)purchaseInteraction != null)
			{
				purchaseInteraction.onPurchase.RemoveListener(DoOnPurchase);
				purchaseInteraction = null;
			}
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			UpdateVisuals();
		}

		private void DoOnPurchase(Interactor activator)
		{
			OnPurchase(activator);
		}

		protected virtual void OnPurchase(Interactor activator)
		{
		}

		protected void UpdateVisuals()
		{
			float num = 1f - base.healthComponent.combinedHealthFraction;
			if ((bool)rayParticleSystem)
			{
				ParticleSystem.EmissionModule emission = rayParticleSystem.emission;
				emission.rateOverTime = Util.Remap(num, 0f, 1f, 0f, 10f);
				ParticleSystem.MainModule main = rayParticleSystem.main;
				main.simulationSpeed = Util.Remap(num, 0f, 1f, 1f, 5f);
			}
			if ((bool)postProcessVolume)
			{
				if (!Mathf.Approximately(postProcessVolume.weight, num))
				{
					PostProcessVolume.DispatchVolumeSettingsChangedEvent();
				}
				postProcessVolume.weight = num;
			}
			if ((bool)light)
			{
				light.range = 10f + num * 150f;
			}
		}
	}
	public class StartHurt : ArtifactShellBaseState
	{
		public static float baseDuration = 0.25f;

		public static string firstHurtSound;

		public override void OnEnter()
		{
			base.OnEnter();
			if (base.healthComponent.combinedHealthFraction >= 1f)
			{
				Util.PlaySound(firstHurtSound, base.gameObject);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= baseDuration)
			{
				outer.SetNextState(new Hurt());
			}
		}
	}
	public class Hurt : ArtifactShellBaseState
	{
		public static float baseDuration = 2f;

		public static float blastRadius = 50f;

		public static float knockbackForce = 5000f;

		public static float knockbackLiftForce = 2000f;

		public static float blastOriginOffset = -10f;

		public static GameObject novaEffectPrefab;

		private float duration;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			UnityEngine.Vector3 position = base.transform.position;
			if (NetworkServer.active)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.position = position;
				damageInfo.attacker = null;
				damageInfo.inflictor = null;
				damageInfo.damage = Mathf.Ceil(base.healthComponent.fullCombinedHealth * 0.25f);
				damageInfo.damageType = DamageType.BypassArmor | DamageType.Silent;
				damageInfo.procCoefficient = 0f;
				base.healthComponent.TakeDamage(damageInfo);
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.position = position + blastOriginOffset * UnityEngine.Vector3.up;
				blastAttack.attacker = base.gameObject;
				blastAttack.inflictor = base.gameObject;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.baseDamage = 0f;
				blastAttack.baseForce = knockbackForce;
				blastAttack.bonusForce = UnityEngine.Vector3.up * knockbackLiftForce;
				blastAttack.falloffModel = BlastAttack.FalloffModel.Linear;
				blastAttack.radius = blastRadius;
				blastAttack.procCoefficient = 0f;
				blastAttack.teamIndex = TeamIndex.None;
				blastAttack.Fire();
				ArtifactTrialMissionController.RemoveAllMissionKeys();
			}
			EffectData effectData = new EffectData
			{
				origin = position,
				scale = blastRadius
			};
			EffectManager.SpawnEffect(novaEffectPrefab, effectData, transmit: false);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				outer.SetNextState(new WaitForKey());
			}
		}
	}
	public class WaitForIntro : ArtifactShellBaseState
	{
		public static float baseDuration = 10f;

		private float duration;

		protected override bool interactionAvailable => false;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				outer.SetNextState(new WaitForKey());
			}
		}
	}
	public class WaitForKey : ArtifactShellBaseState
	{
		protected override CostTypeIndex interactionCostType => CostTypeIndex.ArtifactShellKillerItem;

		protected override int interactionCost => 1;

		protected override bool interactionAvailable => true;

		public override void OnEnter()
		{
			base.OnEnter();
		}

		protected override void OnPurchase(Interactor activator)
		{
			base.OnPurchase(activator);
			outer.SetInterruptState(new StartHurt(), InterruptPriority.Pain);
		}
	}
	public class FireSolarFlares : BaseState
	{
		public static GameObject projectilePrefab;

		public static int minimumProjectileCount;

		public static int maximumProjectileCount;

		public static float arc;

		public static float baseDuration;

		public static float radius;

		public static float projectileDamageCoefficient;

		public static float projectileForce;

		public static float projectileFuse;

		public static float projectileSpeed;

		private float duration;

		private int projectileCount;

		private int projectilesFired;

		private UnityEngine.Quaternion currentRotation;

		private UnityEngine.Quaternion deltaRotation;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.healthComponent)
			{
				projectileCount = (int)Util.Remap(base.healthComponent.combinedHealthFraction, 0f, 1f, maximumProjectileCount, minimumProjectileCount);
			}
			if (NetworkServer.active)
			{
				UnityEngine.Vector3 aimDirection = base.inputBank.aimDirection;
				currentRotation = UnityEngine.Quaternion.LookRotation(aimDirection);
				_ = Run.FixedTimeStamp.now.t * 2f % 1f;
				UnityEngine.Vector3 rhs = currentRotation * UnityEngine.Vector3.forward;
				UnityEngine.Vector3 lhs = currentRotation * UnityEngine.Vector3.right;
				_ = currentRotation * UnityEngine.Vector3.up;
				deltaRotation = UnityEngine.Quaternion.AngleAxis(arc / (float)projectileCount, UnityEngine.Vector3.Cross(lhs, rhs));
			}
			duration = baseDuration / attackSpeedStat;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active)
			{
				float num = duration / (float)projectileCount;
				if (base.fixedAge >= (float)projectilesFired * num)
				{
					projectilesFired++;
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.position = base.transform.position + currentRotation * UnityEngine.Vector3.forward * radius;
					fireProjectileInfo.rotation = currentRotation;
					fireProjectileInfo.projectilePrefab = projectilePrefab;
					fireProjectileInfo.fuseOverride = projectileFuse;
					fireProjectileInfo.useFuseOverride = true;
					fireProjectileInfo.speedOverride = projectileSpeed;
					fireProjectileInfo.useSpeedOverride = true;
					fireProjectileInfo.damage = damageStat * projectileDamageCoefficient;
					fireProjectileInfo.force = projectileForce;
					ProjectileManager.instance.FireProjectile(fireProjectileInfo);
					currentRotation *= deltaRotation;
				}
				if (base.fixedAge >= duration)
				{
					outer.SetNextStateToMain();
				}
			}
		}
	}
	public class Death : ArtifactShellBaseState
	{
		public static float duration;

		protected override bool interactionAvailable => false;

		public override void OnEnter()
		{
			base.OnEnter();
			Util.PlaySound(GetComponent<SfxLocator>().deathSound, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Death;
		}
	}
}
namespace EntityStates.AncientWispMonster
{
	public class ChannelRain : BaseState
	{
		private float castTimer;

		public static float baseDuration = 4f;

		public static float explosionDelay = 2f;

		public static int explosionCount = 10;

		public static float damageCoefficient;

		public static float randomRadius;

		public static float radius;

		public static GameObject delayPrefab;

		private float duration;

		private float durationBetweenCast;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration;
			durationBetweenCast = baseDuration / (float)explosionCount / attackSpeedStat;
			PlayCrossfade("Body", "ChannelRain", 0.3f);
		}

		private void PlaceRain()
		{
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			Ray aimRay = GetAimRay();
			aimRay.origin += UnityEngine.Random.insideUnitSphere * randomRadius;
			if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask))
			{
				vector = hitInfo.point;
			}
			if (!(vector != UnityEngine.Vector3.zero))
			{
				return;
			}
			Transform transform = FindTargetClosest(vector, base.characterBody.GetComponent<TeamComponent>().teamIndex switch
			{
				TeamIndex.Monster => TeamIndex.Player, 
				TeamIndex.Player => TeamIndex.Monster, 
				_ => TeamIndex.Neutral, 
			});
			UnityEngine.Vector3 vector2 = vector;
			if ((bool)transform)
			{
				vector2 = transform.transform.position;
			}
			vector2 += UnityEngine.Random.insideUnitSphere * randomRadius;
			Ray ray = default(Ray);
			ray.origin = vector2 + UnityEngine.Vector3.up * randomRadius;
			ray.direction = UnityEngine.Vector3.down;
			if (Physics.Raycast(ray, out hitInfo, 500f, LayerIndex.world.mask))
			{
				UnityEngine.Vector3 point = hitInfo.point;
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(hitInfo.normal);
				GameObject obj = UnityEngine.Object.Instantiate(delayPrefab, point, rotation);
				DelayBlast component = obj.GetComponent<DelayBlast>();
				component.position = point;
				component.baseDamage = base.characterBody.damage * damageCoefficient;
				component.baseForce = 2000f;
				component.bonusForce = UnityEngine.Vector3.up * 1000f;
				component.radius = radius;
				component.attacker = base.gameObject;
				component.inflictor = null;
				component.crit = Util.CheckRoll(critStat, base.characterBody.master);
				component.maxTimer = explosionDelay;
				obj.GetComponent<TeamFilter>().teamIndex = TeamComponent.GetObjectTeam(component.attacker);
				obj.transform.localScale = new UnityEngine.Vector3(radius, radius, 1f);
				ScaleParticleSystemDuration component2 = obj.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component2)
				{
					component2.newDuration = explosionDelay;
				}
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			castTimer += GetDeltaTime();
			if (castTimer >= durationBetweenCast)
			{
				PlaceRain();
				castTimer -= durationBetweenCast;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new EndRain());
			}
		}

		private Transform FindTargetClosest(UnityEngine.Vector3 point, TeamIndex enemyTeam)
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(enemyTeam);
			float num = 99999f;
			Transform result = null;
			for (int i = 0; i < teamMembers.Count; i++)
			{
				float num2 = UnityEngine.Vector3.SqrMagnitude(teamMembers[i].transform.position - point);
				if (num2 < num)
				{
					num = num2;
					result = teamMembers[i].transform;
				}
			}
			return result;
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class ChargeBomb : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject effectPrefab;

		public static GameObject delayPrefab;

		public static float radius = 10f;

		public static float damageCoefficient = 1f;

		private float duration;

		private GameObject chargeEffectLeft;

		private GameObject chargeEffectRight;

		private UnityEngine.Vector3 startLine = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 endLine = UnityEngine.Vector3.zero;

		private bool hasFired;

		private EffectManagerHelper _emh_chargeEffectLeft;

		private EffectManagerHelper _emh_chargeEffectRight;

		private static int chargeBombAnimStateHash = Animator.StringToHash("ChargeBomb");

		private static int chargeBombParamHas = Animator.StringToHash("ChargeBomb.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffectLeft = null;
			chargeEffectRight = null;
			startLine = UnityEngine.Vector3.zero;
			endLine = UnityEngine.Vector3.zero;
			hasFired = false;
			_emh_chargeEffectLeft = null;
			_emh_chargeEffectRight = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture", chargeBombAnimStateHash, chargeBombParamHas, duration);
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component && (bool)effectPrefab)
				{
					Transform transform = component.FindChild("MuzzleLeft");
					Transform transform2 = component.FindChild("MuzzleRight");
					if ((bool)transform)
					{
						if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
						{
							chargeEffectLeft = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeEffectLeft = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation);
							chargeEffectLeft = _emh_chargeEffectLeft.gameObject;
						}
						chargeEffectLeft.transform.parent = transform;
					}
					if ((bool)transform2)
					{
						if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
						{
							chargeEffectRight = UnityEngine.Object.Instantiate(effectPrefab, transform2.position, transform2.rotation);
						}
						else
						{
							_emh_chargeEffectRight = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform2.position, transform2.rotation);
							chargeEffectRight = _emh_chargeEffectRight.gameObject;
						}
						chargeEffectRight.transform.parent = transform2;
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
			if (Physics.Raycast(GetAimRay(), out var hitInfo, (int)LayerIndex.world.mask))
			{
				startLine = hitInfo.point;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (_emh_chargeEffectLeft != null && _emh_chargeEffectLeft.OwningPool != null)
			{
				_emh_chargeEffectLeft.OwningPool.ReturnObject(_emh_chargeEffectLeft);
			}
			else
			{
				EntityState.Destroy(chargeEffectLeft);
			}
			chargeEffectLeft = null;
			_emh_chargeEffectLeft = null;
			if (_emh_chargeEffectRight != null && _emh_chargeEffectRight.OwningPool != null)
			{
				_emh_chargeEffectRight.OwningPool.ReturnObject(_emh_chargeEffectRight);
			}
			else
			{
				EntityState.Destroy(chargeEffectRight);
			}
			chargeEffectRight = null;
			_emh_chargeEffectRight = null;
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			float num = 0f;
			if (base.fixedAge >= num && !hasFired)
			{
				hasFired = true;
				Ray aimRay = GetAimRay();
				if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask))
				{
					endLine = hitInfo.point;
				}
				UnityEngine.Vector3 normalized = (endLine - startLine).normalized;
				normalized.y = 0f;
				normalized.Normalize();
				for (int i = 0; i < 1; i++)
				{
					UnityEngine.Vector3 vector = endLine;
					Ray ray = default(Ray);
					ray.origin = aimRay.origin;
					ray.direction = vector - aimRay.origin;
					UnityEngine.Debug.DrawLine(ray.origin, vector, UnityEngine.Color.red, 5f);
					if (Physics.Raycast(ray, out hitInfo, 500f, LayerIndex.world.mask))
					{
						UnityEngine.Vector3 point = hitInfo.point;
						UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(hitInfo.normal);
						GameObject obj = UnityEngine.Object.Instantiate(delayPrefab, point, rotation);
						DelayBlast component = obj.GetComponent<DelayBlast>();
						component.position = point;
						component.baseDamage = base.characterBody.damage * damageCoefficient;
						component.baseForce = 2000f;
						component.bonusForce = UnityEngine.Vector3.up * 1000f;
						component.radius = radius;
						component.attacker = base.gameObject;
						component.inflictor = null;
						component.crit = Util.CheckRoll(critStat, base.characterBody.master);
						component.maxTimer = duration;
						obj.GetComponent<TeamFilter>().teamIndex = TeamComponent.GetObjectTeam(component.attacker);
						obj.transform.localScale = new UnityEngine.Vector3(radius, radius, 1f);
						ScaleParticleSystemDuration component2 = obj.GetComponent<ScaleParticleSystemDuration>();
						if ((bool)component2)
						{
							component2.newDuration = duration;
						}
					}
				}
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new FireBomb());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeRain : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject effectPrefab;

		public static GameObject delayPrefab;

		private float duration;

		private static int chargeRainStateHash = Animator.StringToHash("ChargeRain");

		private static int chargeRainplaybackRateParamHash = Animator.StringToHash("ChargeRain.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
			PlayAnimation("Body", chargeRainStateHash, chargeRainplaybackRateParamHash, duration);
			if (Physics.Raycast(base.transform.position, UnityEngine.Vector3.down, out var hitInfo, 999f, LayerIndex.world.mask))
			{
				NodeGraph groundNodes = SceneInfo.instance.groundNodes;
				NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(hitInfo.point, HullClassification.BeetleQueen);
				groundNodes.GetNodePosition(nodeIndex, out var position);
				base.transform.position = position + UnityEngine.Vector3.up * 2f;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextState(new ChannelRain());
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class ChargeRHCannon : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject effectPrefab;

		private float duration;

		private GameObject chargeEffectLeft;

		private GameObject chargeEffectRight;

		private EffectManagerHelper _emh_chargeEffectRight;

		private static int chargeRHCannonHash = Animator.StringToHash("ChargeRHCannon");

		private static int chargeRHCannonPlaybackHash = Animator.StringToHash("ChargeRHCannon.playbackRate");

		public override void Reset()
		{
			base.Reset();
			duration = 0f;
			chargeEffectLeft = null;
			chargeEffectRight = null;
			_emh_chargeEffectRight = null;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			Transform modelTransform = GetModelTransform();
			PlayAnimation("Gesture", chargeRHCannonHash, chargeRHCannonPlaybackHash, duration);
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component && (bool)effectPrefab)
				{
					Transform transform = component.FindChild("MuzzleRight");
					if ((bool)transform)
					{
						if (!EffectManager.ShouldUsePooledEffect(effectPrefab))
						{
							chargeEffectRight = UnityEngine.Object.Instantiate(effectPrefab, transform.position, transform.rotation);
						}
						else
						{
							_emh_chargeEffectRight = EffectManager.GetAndActivatePooledEffect(effectPrefab, transform.position, transform.rotation);
							chargeEffectRight = _emh_chargeEffectRight.gameObject;
						}
						chargeEffectRight.transform.parent = transform;
					}
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(duration);
			}
		}

		public override void OnExit()
		{
			base.OnExit();
			if (_emh_chargeEffectRight != null && _emh_chargeEffectRight.OwningPool != null)
			{
				_emh_chargeEffectRight.OwningPool.ReturnObject(_emh_chargeEffectRight);
			}
			else
			{
				EntityState.Destroy(chargeEffectRight);
			}
			chargeEffectRight = null;
			_emh_chargeEffectRight = null;
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				FireRHCannon nextState = new FireRHCannon();
				outer.SetNextState(nextState);
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class EndRain : BaseState
	{
		public static float baseDuration = 3f;

		public static GameObject effectPrefab;

		public static GameObject delayPrefab;

		private float duration;

		private static int endRainHash = Animator.StringToHash("EndRain");

		private static int endRainParamHash = Animator.StringToHash("EndRain.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
			PlayAnimation("Body", endRainHash, endRainParamHash, duration);
			NodeGraph airNodes = SceneInfo.instance.airNodes;
			NodeGraph.NodeIndex nodeIndex = airNodes.FindClosestNode(base.transform.position, base.characterBody.hullClassification);
			airNodes.GetNodePosition(nodeIndex, out var position);
			base.transform.position = position;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void Update()
		{
			base.Update();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Enrage : BaseState
	{
		public static float baseDuration = 3.5f;

		public static GameObject enragePrefab;

		private Animator modelAnimator;

		private float duration;

		private bool hasCastBuff;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayCrossfade("Gesture", "Enrage", "Enrage.playbackRate", duration, 0.2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Enrage.activate") > 0.5f && !hasCastBuff)
			{
				EffectData effectData = new EffectData();
				effectData.origin = base.transform.position;
				effectData.SetNetworkedObjectReference(base.gameObject);
				EffectManager.SpawnEffect(enragePrefab, effectData, transmit: true);
				hasCastBuff = true;
				base.characterBody.AddBuff(JunkContent.Buffs.EnrageAncientWisp);
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		private static void PullEnemies(UnityEngine.Vector3 position, UnityEngine.Vector3 direction, float coneAngle, float maxDistance, float force, TeamIndex excludedTeam)
		{
			float num = Mathf.Cos(coneAngle * 0.5f * (MathF.PI / 180f));
			HGPhysics.OverlapSphere(out var colliders, position, maxDistance);
			foreach (Collider collider in colliders)
			{
				UnityEngine.Vector3 position2 = collider.transform.position;
				UnityEngine.Vector3 normalized = (position - position2).normalized;
				if (!(UnityEngine.Vector3.Dot(-normalized, direction) >= num))
				{
					continue;
				}
				TeamIndex teamIndex = TeamIndex.Neutral;
				TeamComponent component = collider.GetComponent<TeamComponent>();
				if (!component)
				{
					continue;
				}
				teamIndex = component.teamIndex;
				if (teamIndex != excludedTeam)
				{
					CharacterMotor component2 = collider.GetComponent<CharacterMotor>();
					if ((bool)component2)
					{
						component2.ApplyForce(normalized * force);
					}
					Rigidbody component3 = collider.GetComponent<Rigidbody>();
					if ((bool)component3)
					{
						component3.AddForce(normalized * force, ForceMode.Impulse);
					}
				}
			}
			HGPhysics.ReturnResults(colliders);
		}
	}
	public class FireBomb : BaseState
	{
		public static float baseDuration = 4f;

		private float duration;

		private static int fireBombHash = Animator.StringToHash("FireBomb");

		private static int fireBombParamHash = Animator.StringToHash("FireBomb.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			PlayAnimation("Gesture", fireBombHash, fireBombParamHash, duration);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Frozen;
		}
	}
	public class FireRHCannon : BaseState
	{
		public static GameObject projectilePrefab;

		public static GameObject effectPrefab;

		public static float baseDuration = 2f;

		public static float baseDurationBetweenShots = 0.5f;

		public static float damageCoefficient = 1.2f;

		public static float force = 20f;

		public static int bulletCount;

		private float duration;

		private float durationBetweenShots;

		public int bulletCountCurrent = 1;

		private static int fireRHCannonHash = Animator.StringToHash("FireRHCannon");

		private static int fireRHCannonParamHash = Animator.StringToHash("FireRHCannon.playbackRate");

		public override void OnEnter()
		{
			base.OnEnter();
			Ray aimRay = GetAimRay();
			string text = "MuzzleRight";
			duration = baseDuration / attackSpeedStat;
			durationBetweenShots = baseDurationBetweenShots / attackSpeedStat;
			if ((bool)effectPrefab)
			{
				EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, text, transmit: false);
			}
			PlayAnimation("Gesture", fireRHCannonHash, fireRHCannonParamHash, duration);
			if (!base.isAuthority || !base.modelLocator || !base.modelLocator.modelTransform)
			{
				return;
			}
			ChildLocator component = base.modelLocator.modelTransform.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild(text);
			if ((bool)transform)
			{
				UnityEngine.Vector3 forward = aimRay.direction;
				if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask))
				{
					forward = hitInfo.point - transform.position;
				}
				ProjectileManager.instance.FireProjectile(projectilePrefab, transform.position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, force, Util.CheckRoll(critStat, base.characterBody.master));
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.isAuthority)
			{
				if (bulletCountCurrent == bulletCount && base.fixedAge >= duration)
				{
					outer.SetNextStateToMain();
				}
				else if (bulletCountCurrent < bulletCount && base.fixedAge >= durationBetweenShots)
				{
					FireRHCannon fireRHCannon = new FireRHCannon();
					fireRHCannon.bulletCountCurrent = bulletCountCurrent + 1;
					outer.SetNextState(fireRHCannon);
				}
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.Skill;
		}
	}
	public class Throw : BaseState
	{
		public static float baseDuration = 3.5f;

		public static float returnToIdlePercentage;

		public static float damageCoefficient = 4f;

		public static float forceMagnitude = 16f;

		public static float radius = 3f;

		public static GameObject projectilePrefab;

		public static GameObject swingEffectPrefab;

		private Transform rightMuzzleTransform;

		private Animator modelAnimator;

		private float duration;

		private bool hasSwung;

		public override void OnEnter()
		{
			base.OnEnter();
			duration = baseDuration / attackSpeedStat;
			modelAnimator = GetModelAnimator();
			Transform modelTransform = GetModelTransform();
			if ((bool)modelTransform)
			{
				ChildLocator component = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component)
				{
					rightMuzzleTransform = component.FindChild("MuzzleRight");
				}
			}
			if ((bool)modelAnimator)
			{
				int layerIndex = modelAnimator.GetLayerIndex("Gesture");
				if (modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).IsName("Throw1"))
				{
					PlayCrossfade("Gesture", "Throw2", "Throw.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f);
				}
				else
				{
					PlayCrossfade("Gesture", "Throw1", "Throw.playbackRate", duration / (1f - returnToIdlePercentage), 0.2f);
				}
			}
			if ((bool)base.characterBody)
			{
				base.characterBody.SetAimTimer(2f);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)modelAnimator && modelAnimator.GetFloat("Throw.activate") > 0f && !hasSwung)
			{
				Ray aimRay = GetAimRay();
				UnityEngine.Vector3 forward = aimRay.direction;
				if (Physics.Raycast(aimRay, out var hitInfo, (int)LayerIndex.world.mask))
				{
					forward = hitInfo.point - rightMuzzleTransform.position;
				}
				ProjectileManager.instance.FireProjectile(projectilePrefab, rightMuzzleTransform.position, Util.QuaternionSafeLookRotation(forward), base.gameObject, damageStat * damageCoefficient, forceMagnitude, Util.CheckRoll(critStat, base.characterBody.master));
				EffectManager.SimpleMuzzleFlash(swingEffectPrefab, base.gameObject, "RightSwingCenter", transmit: true);
				hasSwung = true;
			}
			if (base.fixedAge >= duration && base.isAuthority)
			{
				outer.SetNextStateToMain();
			}
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}

		private static void PullEnemies(UnityEngine.Vector3 position, UnityEngine.Vector3 direction, float coneAngle, float maxDistance, float force, TeamIndex excludedTeam)
		{
			float num = Mathf.Cos(coneAngle * 0.5f * (MathF.PI / 180f));
			Collider[] colliders;
			int num2 = HGPhysics.OverlapSphere(out colliders, position, maxDistance);
			for (int i = 0; i < num2; i++)
			{
				Collider collider = colliders[i];
				UnityEngine.Vector3 position2 = collider.transform.position;
				UnityEngine.Vector3 normalized = (position - position2).normalized;
				if (!(UnityEngine.Vector3.Dot(-normalized, direction) >= num))
				{
					continue;
				}
				TeamIndex teamIndex = TeamIndex.Neutral;
				TeamComponent component = collider.GetComponent<TeamComponent>();
				if (!component)
				{
					continue;
				}
				teamIndex = component.teamIndex;
				if (teamIndex != excludedTeam)
				{
					CharacterMotor component2 = collider.GetComponent<CharacterMotor>();
					if ((bool)component2)
					{
						component2.ApplyForce(normalized * force);
					}
					Rigidbody component3 = collider.GetComponent<Rigidbody>();
					if ((bool)component3)
					{
						component3.AddForce(normalized * force, ForceMode.Impulse);
					}
				}
			}
			HGPhysics.ReturnResults(colliders);
		}
	}
}
namespace EntityStates.AI
{
	public abstract class BaseAIState : EntityState
	{
		protected static FloatConVar cvAIUpdateInterval = new FloatConVar("ai_update_interval", ConVarFlags.Cheat, "0.2", "Frequency that the local navigator refreshes.");

		protected BaseAI.BodyInputs bodyInputs;

		protected bool isInJump;

		protected UnityEngine.Vector3? jumpLockedMoveVector;

		protected CharacterMaster characterMaster { get; private set; }

		protected BaseAI ai { get; private set; }

		protected CharacterBody body { get; private set; }

		protected Transform bodyTransform { get; private set; }

		protected InputBankTest bodyInputBank { get; private set; }

		protected CharacterMotor bodyCharacterMotor { get; private set; }

		protected SkillLocator bodySkillLocator { get; private set; }

		public override void OnEnter()
		{
			base.OnEnter();
			characterMaster = GetComponent<CharacterMaster>();
			ai = GetComponent<BaseAI>();
			if ((bool)ai)
			{
				body = ai.body;
				bodyTransform = ai.bodyTransform;
				bodyInputBank = ai.bodyInputBank;
				bodyCharacterMotor = ai.bodyCharacterMotor;
				bodySkillLocator = ai.bodySkillLocator;
			}
			bodyInputs = default(BaseAI.BodyInputs);
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
		}

		public virtual BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs)
		{
			return bodyInputs;
		}

		protected void ModifyInputsForJumpIfNeccessary(ref BaseAI.BodyInputs bodyInputs)
		{
			if (!ai)
			{
				return;
			}
			BroadNavigationSystem.AgentOutput output = ai.broadNavigationAgent.output;
			bodyInputs.pressJump = false;
			if (!bodyCharacterMotor)
			{
				return;
			}
			bool isGrounded = bodyCharacterMotor.isGrounded;
			bool flag = isGrounded || bodyCharacterMotor.isFlying || !bodyCharacterMotor.useGravity;
			if (isInJump && flag)
			{
				isInJump = false;
				jumpLockedMoveVector = null;
			}
			if (isGrounded)
			{
				float num = Mathf.Max(output.desiredJumpVelocity, ai.localNavigator.jumpSpeed);
				if (num > 0f && body.jumpPower > 0f)
				{
					bool num2 = output.desiredJumpVelocity >= ai.localNavigator.jumpSpeed;
					num = body.jumpPower;
					bodyInputs.pressJump = true;
					if (num2 && output.nextPosition.HasValue)
					{
						UnityEngine.Vector3 vector = output.nextPosition.Value - bodyTransform.position;
						UnityEngine.Vector3 vector2 = vector;
						vector2.y = 0f;
						float num3 = Trajectory.CalculateFlightDuration(0f, vector.y, num);
						float walkSpeed = bodyCharacterMotor.walkSpeed;
						if (num3 > 0f && walkSpeed > 0f)
						{
							float magnitude = vector2.magnitude;
							float num4 = Mathf.Max(magnitude / num3 / bodyCharacterMotor.walkSpeed, 0f);
							jumpLockedMoveVector = vector2 * (num4 / magnitude);
							bodyCharacterMotor.moveDirection = jumpLockedMoveVector.Value;
						}
					}
					isInJump = true;
				}
			}
			if (jumpLockedMoveVector.HasValue)
			{
				bodyInputs.moveVector = jumpLockedMoveVector.Value;
			}
		}

		protected UnityEngine.Vector3? PickRandomNearbyReachablePosition()
		{
			if (!ai || !body)
			{
				return null;
			}
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground);
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(nodeGraph, (HullMask)(1 << (int)body.hullClassification));
			NodeGraph.NodeIndex nodeIndex = nodeGraph.FindClosestNode(bodyTransform.position, body.hullClassification, 50f);
			nodeGraphSpider.AddNodeForNextStep(nodeIndex);
			nodeGraphSpider.PerformStep();
			nodeGraphSpider.PerformStep();
			List<NodeGraphSpider.StepInfo> collectedSteps = nodeGraphSpider.collectedSteps;
			if (collectedSteps.Count == 0)
			{
				return null;
			}
			int index = UnityEngine.Random.Range(0, collectedSteps.Count);
			NodeGraph.NodeIndex node = collectedSteps[index].node;
			if (nodeGraph.GetNodePosition(node, out var position))
			{
				return position;
			}
			return null;
		}

		protected void AimAt(ref BaseAI.BodyInputs dest, BaseAI.Target aimTarget)
		{
			if (aimTarget != null && aimTarget.GetBullseyePosition(out var position))
			{
				dest.desiredAimDirection = (position - bodyInputBank.aimOrigin).normalized;
			}
		}

		protected void AimInDirection(ref BaseAI.BodyInputs dest, UnityEngine.Vector3 aimDirection)
		{
			if (aimDirection != UnityEngine.Vector3.zero)
			{
				dest.desiredAimDirection = aimDirection;
			}
		}
	}
}
namespace EntityStates.AI.Walker
{
	public class Combat : BaseAIState
	{
		private float strafeDirection;

		private const float strafeDuration = 0.25f;

		private float strafeTimer;

		private float activeSoundTimer;

		private float aiUpdateTimer;

		public float timeChasing;

		private const float minUpdateInterval = 1f / 6f;

		private const float maxUpdateInterval = 0.2f;

		private AISkillDriver dominantSkillDriver;

		protected bool currentSkillMeetsActivationConditions;

		protected SkillSlot currentSkillSlot = SkillSlot.None;

		protected UnityEngine.Vector3 myBodyFootPosition;

		private float lastPathUpdate;

		private float fallbackNodeStartAge;

		private readonly float fallbackNodeDuration = 4f;

		public override void OnEnter()
		{
			base.OnEnter();
			activeSoundTimer = UnityEngine.Random.Range(3f, 8f);
			if ((bool)base.ai)
			{
				lastPathUpdate = base.ai.broadNavigationAgent.output.lastPathUpdate;
				base.ai.broadNavigationAgent.InvalidatePath();
			}
			fallbackNodeStartAge = float.NegativeInfinity;
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.ai || !base.body)
			{
				return;
			}
			float deltaTime = GetDeltaTime();
			aiUpdateTimer -= deltaTime;
			strafeTimer -= deltaTime;
			UpdateFootPosition();
			if (aiUpdateTimer <= 0f)
			{
				aiUpdateTimer = BaseAIState.cvAIUpdateInterval.value;
				UpdateAI(BaseAIState.cvAIUpdateInterval.value);
				if (!dominantSkillDriver)
				{
					outer.SetNextState(new LookBusy());
				}
			}
			UpdateBark();
		}

		protected void UpdateFootPosition()
		{
			myBodyFootPosition = base.body.footPosition;
			BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent;
			broadNavigationAgent.currentPosition = myBodyFootPosition;
		}

		protected void UpdateAI(float deltaTime)
		{
			BaseAI.SkillDriverEvaluation skillDriverEvaluation = base.ai.skillDriverEvaluation;
			dominantSkillDriver = skillDriverEvaluation.dominantSkillDriver;
			currentSkillSlot = SkillSlot.None;
			currentSkillMeetsActivationConditions = false;
			bodyInputs.moveVector = UnityEngine.Vector3.zero;
			AISkillDriver.MovementType movementType = AISkillDriver.MovementType.Stop;
			float num = 1f;
			bool flag = false;
			bool flag2 = false;
			bool flag3 = false;
			if (!base.body || !base.bodyInputBank)
			{
				return;
			}
			if ((bool)dominantSkillDriver)
			{
				movementType = dominantSkillDriver.movementType;
				currentSkillSlot = dominantSkillDriver.skillSlot;
				flag = dominantSkillDriver.activationRequiresTargetLoS;
				flag2 = dominantSkillDriver.activationRequiresAimTargetLoS;
				flag3 = dominantSkillDriver.activationRequiresAimConfirmation;
				num = dominantSkillDriver.moveInputScale;
			}
			UnityEngine.Vector3 position = base.bodyTransform.position;
			_ = base.bodyInputBank.aimOrigin;
			BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent;
			BroadNavigationSystem.AgentOutput output = broadNavigationAgent.output;
			BaseAI.Target target = skillDriverEvaluation.target;
			if ((bool)target?.gameObject)
			{
				target.GetBullseyePosition(out var position2);
				UnityEngine.Vector3 vector = position2;
				if (fallbackNodeStartAge + fallbackNodeDuration < base.fixedAge)
				{
					base.ai.SetGoalPosition(target);
				}
				UnityEngine.Vector3 targetPosition = position;
				bool allowWalkOffCliff = true;
				UnityEngine.Vector3 vector2 = ((!dominantSkillDriver || !dominantSkillDriver.ignoreNodeGraph) ? (output.nextPosition ?? myBodyFootPosition) : ((!base.body.isFlying) ? vector : position2));
				UnityEngine.Vector3 vector3 = (vector2 - myBodyFootPosition).normalized * 10f;
				UnityEngine.Vector3 vector4 = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, vector3);
				switch (movementType)
				{
				case AISkillDriver.MovementType.ChaseMoveTarget:
					targetPosition = vector2 + (position - myBodyFootPosition);
					break;
				case AISkillDriver.MovementType.FleeMoveTarget:
					targetPosition -= vector3;
					break;
				case AISkillDriver.MovementType.StrafeMovetarget:
					if (strafeTimer <= 0f)
					{
						if (strafeDirection == 0f)
						{
							strafeDirection = ((UnityEngine.Random.Range(0, 1) == 0) ? (-1f) : 1f);
						}
						strafeTimer = 0.25f;
					}
					targetPosition += vector4 * strafeDirection;
					allowWalkOffCliff = false;
					break;
				}
				base.ai.localNavigator.targetPosition = targetPosition;
				base.ai.localNavigator.allowWalkOffCliff = allowWalkOffCliff;
				base.ai.localNavigator.Update(deltaTime);
				if (base.ai.localNavigator.wasObstructedLastUpdate)
				{
					strafeDirection *= -1f;
				}
				bodyInputs.moveVector = base.ai.localNavigator.moveVector;
				bodyInputs.moveVector *= num;
				if (!flag3 || base.ai.hasAimConfirmation)
				{
					bool flag4 = true;
					if (skillDriverEvaluation.target == skillDriverEvaluation.aimTarget && flag && flag2)
					{
						flag2 = false;
					}
					if (flag4 && flag)
					{
						flag4 = skillDriverEvaluation.target.TestLOSNow();
					}
					if (flag4 && flag2)
					{
						flag4 = skillDriverEvaluation.aimTarget.TestLOSNow();
					}
					if (flag4)
					{
						currentSkillMeetsActivationConditions = true;
					}
				}
			}
			if (output.lastPathUpdate > lastPathUpdate && !output.targetReachable && fallbackNodeStartAge + fallbackNodeDuration < base.fixedAge)
			{
				broadNavigationAgent.goalPosition = PickRandomNearbyReachablePosition();
				broadNavigationAgent.InvalidatePath();
			}
			lastPathUpdate = output.lastPathUpdate;
		}

		public override BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs)
		{
			bool pressSkill = false;
			bool pressSkill2 = false;
			bool pressSkill3 = false;
			bool pressSkill4 = false;
			if ((bool)base.bodyInputBank)
			{
				AISkillDriver.ButtonPressType buttonPressType = AISkillDriver.ButtonPressType.Abstain;
				if ((bool)dominantSkillDriver)
				{
					buttonPressType = dominantSkillDriver.buttonPressType;
				}
				bool flag = false;
				switch (currentSkillSlot)
				{
				case SkillSlot.Primary:
					flag = previousBodyInputs.pressSkill1;
					break;
				case SkillSlot.Secondary:
					flag = previousBodyInputs.pressSkill2;
					break;
				case SkillSlot.Utility:
					flag = previousBodyInputs.pressSkill3;
					break;
				case SkillSlot.Special:
					flag = previousBodyInputs.pressSkill4;
					break;
				}
				bool flag2 = currentSkillMeetsActivationConditions;
				switch (buttonPressType)
				{
				case AISkillDriver.ButtonPressType.Abstain:
					flag2 = false;
					break;
				case AISkillDriver.ButtonPressType.TapContinuous:
					flag2 = flag2 && !flag;
					break;
				}
				switch (currentSkillSlot)
				{
				case SkillSlot.Primary:
					pressSkill = flag2;
					break;
				case SkillSlot.Secondary:
					pressSkill2 = flag2;
					break;
				case SkillSlot.Utility:
					pressSkill3 = flag2;
					break;
				case SkillSlot.Special:
					pressSkill4 = flag2;
					break;
				}
			}
			bodyInputs.pressSkill1 = pressSkill;
			bodyInputs.pressSkill2 = pressSkill2;
			bodyInputs.pressSkill3 = pressSkill3;
			bodyInputs.pressSkill4 = pressSkill4;
			bodyInputs.pressSprint = false;
			bodyInputs.pressActivateEquipment = false;
			bodyInputs.desiredAimDirection = UnityEngine.Vector3.zero;
			if ((bool)dominantSkillDriver)
			{
				bodyInputs.pressSprint = dominantSkillDriver.shouldSprint;
				bodyInputs.pressActivateEquipment = dominantSkillDriver.shouldFireEquipment && !previousBodyInputs.pressActivateEquipment;
				AISkillDriver.AimType aimType = dominantSkillDriver.aimType;
				BaseAI.Target aimTarget = base.ai.skillDriverEvaluation.aimTarget;
				if (aimType == AISkillDriver.AimType.MoveDirection)
				{
					AimInDirection(ref bodyInputs, bodyInputs.moveVector);
				}
				if (aimTarget != null)
				{
					AimAt(ref bodyInputs, aimTarget);
				}
			}
			ModifyInputsForJumpIfNeccessary(ref bodyInputs);
			return bodyInputs;
		}

		protected void UpdateBark()
		{
			activeSoundTimer -= GetDeltaTime();
			if (activeSoundTimer <= 0f)
			{
				activeSoundTimer = UnityEngine.Random.Range(3f, 8f);
				base.body.CallRpcBark();
			}
		}
	}
	public class LookBusy : BaseAIState
	{
		private const float minDuration = 2f;

		private const float maxDuration = 7f;

		private UnityEngine.Vector3 targetPosition;

		private float duration;

		private float lookTimer;

		private const float minLookDuration = 0.5f;

		private const float maxLookDuration = 4f;

		private const int lookTries = 4;

		private const float lookRaycastLength = 25f;

		protected virtual void PickNewTargetLookDirection()
		{
			if ((bool)base.bodyInputBank)
			{
				float num = 0f;
				UnityEngine.Vector3 aimOrigin = base.bodyInputBank.aimOrigin;
				for (int i = 0; i < 4; i++)
				{
					UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
					float num2 = 25f;
					if (Physics.Raycast(new Ray(aimOrigin, onUnitSphere), out var hitInfo, 25f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						num2 = hitInfo.distance;
					}
					if (num2 > num)
					{
						num = num2;
						bodyInputs.desiredAimDirection = onUnitSphere;
					}
				}
			}
			lookTimer = UnityEngine.Random.Range(0.5f, 4f);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			duration = UnityEngine.Random.Range(2f, 7f);
			base.bodyInputBank.moveVector = UnityEngine.Vector3.zero;
			base.bodyInputBank.jump.PushState(newState: false);
			PickNewTargetLookDirection();
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.ai || !base.body)
			{
				return;
			}
			if ((bool)base.ai.skillDriverEvaluation.dominantSkillDriver)
			{
				outer.SetNextState(new Combat());
			}
			if (base.ai.hasAimConfirmation)
			{
				lookTimer -= GetDeltaTime();
				if (lookTimer <= 0f)
				{
					PickNewTargetLookDirection();
				}
			}
			if (base.fixedAge >= duration)
			{
				outer.SetNextState(new Wander());
			}
		}

		public override BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs)
		{
			return bodyInputs;
		}
	}
	public class Guard : LookBusy
	{
		public override void FixedUpdate()
		{
			base.FixedUpdate();
			base.fixedAge = 0f;
		}

		protected override void PickNewTargetLookDirection()
		{
		}
	}
	public class Wander : BaseAIState
	{
		private UnityEngine.Vector3? targetPosition;

		private float lookTimer;

		private const float minLookDuration = 0.5f;

		private const float maxLookDuration = 4f;

		private const int lookTries = 1;

		private const float lookRaycastLength = 25f;

		private UnityEngine.Vector3 targetLookPosition;

		private float aiUpdateTimer;

		public override void Reset()
		{
			base.Reset();
			targetPosition = UnityEngine.Vector3.zero;
			lookTimer = 0f;
			targetLookPosition = UnityEngine.Vector3.zero;
		}

		private void PickNewTargetLookPosition()
		{
			if ((bool)base.bodyInputBank)
			{
				float num = 0f;
				UnityEngine.Vector3 aimOrigin = base.bodyInputBank.aimOrigin;
				UnityEngine.Vector3 vector = base.bodyInputBank.moveVector;
				if (vector == UnityEngine.Vector3.zero)
				{
					vector = UnityEngine.Random.onUnitSphere;
				}
				for (int i = 0; i < 1; i++)
				{
					UnityEngine.Vector3 direction = Util.ApplySpread(vector, 0f, 60f, 0f, 0f);
					float num2 = 25f;
					Ray ray = new Ray(aimOrigin, direction);
					if (Physics.Raycast(ray, out var hitInfo, 25f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						num2 = hitInfo.distance;
					}
					if (num2 > num)
					{
						num = num2;
						targetLookPosition = ray.GetPoint(num2);
					}
				}
			}
			lookTimer = UnityEngine.Random.Range(0.5f, 4f);
		}

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)base.ai && (bool)base.body)
			{
				BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent;
				targetPosition = PickRandomNearbyReachablePosition();
				if (targetPosition.HasValue)
				{
					broadNavigationAgent.goalPosition = targetPosition.Value;
					broadNavigationAgent.InvalidatePath();
				}
				PickNewTargetLookPosition();
				aiUpdateTimer = 0.5f;
			}
		}

		public override void OnExit()
		{
			base.OnExit();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			aiUpdateTimer -= GetDeltaTime();
			if (!base.ai || !base.body)
			{
				return;
			}
			if ((bool)base.ai.skillDriverEvaluation.dominantSkillDriver)
			{
				outer.SetNextState(new Combat());
			}
			base.ai.SetGoalPosition(targetPosition);
			_ = base.bodyTransform.position;
			BroadNavigationSystem.Agent broadNavigationAgent = base.ai.broadNavigationAgent;
			if (aiUpdateTimer <= 0f)
			{
				aiUpdateTimer = BaseAIState.cvAIUpdateInterval.value;
				base.ai.localNavigator.targetPosition = broadNavigationAgent.output.nextPosition ?? base.ai.localNavigator.targetPosition;
				base.ai.localNavigator.Update(BaseAIState.cvAIUpdateInterval.value);
				if ((bool)base.bodyInputBank)
				{
					bodyInputs.moveVector = base.ai.localNavigator.moveVector * 0.25f;
					bodyInputs.desiredAimDirection = (targetLookPosition - base.bodyInputBank.aimOrigin).normalized;
				}
				lookTimer -= GetDeltaTime();
				if (lookTimer <= 0f)
				{
					PickNewTargetLookPosition();
				}
				bool flag = false;
				if (targetPosition.HasValue)
				{
					float sqrMagnitude = (base.body.footPosition - targetPosition.Value).sqrMagnitude;
					float num = base.body.radius * base.body.radius * 4f;
					flag = sqrMagnitude > num;
				}
				if (!flag)
				{
					outer.SetNextState(new LookBusy());
				}
			}
		}

		public override BaseAI.BodyInputs GenerateBodyInputs(in BaseAI.BodyInputs previousBodyInputs)
		{
			ModifyInputsForJumpIfNeccessary(ref bodyInputs);
			return bodyInputs;
		}
	}
}
namespace EntityStates.AffixVoid
{
	public class SelfDestruct : BaseState
	{
		[SerializeField]
		public float duration;

		[SerializeField]
		public string animationLayerName;

		[SerializeField]
		public string animationStateName;

		[SerializeField]
		public string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			PlayCrossfade(animationLayerName, animationStateName, duration);
			if ((bool)base.characterBody)
			{
				base.characterBody.isSprinting = false;
			}
			if ((bool)base.characterDirection)
			{
				base.characterDirection.moveVector = base.characterDirection.forward;
			}
			if ((bool)base.rigidbodyMotor)
			{
				base.rigidbodyMotor.moveVector = UnityEngine.Vector3.zero;
			}
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge >= duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
}
namespace EntityStates.AffixEarthHealer
{
	public class Chargeup : BaseState
	{
		private static int chargeUpAnimationStateHash = Animator.StringToHash("ChargeUp");

		private static int chargeUpParamHash = Animator.StringToHash("ChargeUp.playbackRate");

		public static float duration;

		public static string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			FindModelChild("ChargeUpFX").gameObject.SetActive(value: true);
			PlayAnimation("Base", chargeUpAnimationStateHash, chargeUpParamHash, duration);
			Util.PlaySound(enterSoundString, base.gameObject);
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > duration)
			{
				outer.SetNextState(new Heal());
			}
		}

		public override void OnExit()
		{
			FindModelChild("ChargeUpFX").gameObject.SetActive(value: false);
			base.OnExit();
		}
	}
	public class Heal : BaseState
	{
		public static float radius;

		public static float healCoefficient;

		public static float healOrbTravelDuration;

		public static GameObject effectPrefab;

		public override void OnEnter()
		{
			base.OnEnter();
			float healValue = base.characterBody.damage * healCoefficient;
			if (!NetworkServer.active)
			{
				return;
			}
			List<HealthComponent> list = new List<HealthComponent>();
			SphereSearch sphereSearch = new SphereSearch();
			sphereSearch.radius = radius;
			sphereSearch.origin = base.transform.position;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.Ignore;
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			HurtBox[] hurtBoxes = sphereSearch.GetHurtBoxes();
			for (int i = 0; i < hurtBoxes.Length; i++)
			{
				HealthComponent item = hurtBoxes[i].healthComponent;
				if (!list.Contains(item))
				{
					list.Add(item);
				}
			}
			foreach (HealthComponent item2 in list)
			{
				HealOrb healOrb = new HealOrb();
				healOrb.origin = base.transform.position;
				healOrb.target = item2.body.mainHurtBox;
				healOrb.healValue = healValue;
				healOrb.overrideDuration = healOrbTravelDuration;
				OrbManager.instance.AddOrb(healOrb);
			}
			EffectManager.SimpleEffect(effectPrefab, base.transform.position, UnityEngine.Quaternion.identity, transmit: true);
			base.characterBody.healthComponent.Suicide();
		}
	}
	public class DeathState : GenericCharacterDeath
	{
		public static GameObject initialExplosion;

		public static float duration;

		public static string enterSoundString;

		public override void OnEnter()
		{
			base.OnEnter();
			if ((bool)initialExplosion)
			{
				EffectManager.SimpleEffect(initialExplosion, base.transform.position, base.transform.rotation, transmit: false);
			}
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && base.fixedAge > duration)
			{
				EntityState.Destroy(base.gameObject);
			}
		}
	}
}
namespace EntityStates.AcidLarva
{
	public class Death : GenericCharacterDeath
	{
		public static float deathDelay;

		public static GameObject deathEffectPrefab;

		private bool hasDied;

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (base.fixedAge > deathDelay && !hasDied)
			{
				hasDied = true;
				DestroyModel();
				EffectManager.SimpleImpactEffect(deathEffectPrefab, base.characterBody.corePosition, UnityEngine.Vector3.up, transmit: false);
				if (NetworkServer.active)
				{
					DestroyBodyAsapServer();
				}
			}
		}

		public override void OnExit()
		{
			DestroyModel();
			base.OnExit();
		}
	}
	public class LarvaLeap : BaseCharacterMain
	{
		[SerializeField]
		public float minimumDuration;

		[SerializeField]
		public float blastRadius;

		[SerializeField]
		public float blastProcCoefficient;

		[SerializeField]
		public float blastDamageCoefficient;

		[SerializeField]
		public float blastForce;

		[SerializeField]
		public string leapSoundString;

		[SerializeField]
		public GameObject projectilePrefab;

		[SerializeField]
		public UnityEngine.Vector3 blastBonusForce;

		[SerializeField]
		public GameObject blastImpactEffectPrefab;

		[SerializeField]
		public GameObject blastEffectPrefab;

		[SerializeField]
		public float airControl;

		[SerializeField]
		public float aimVelocity;

		[SerializeField]
		public float upwardVelocity;

		[SerializeField]
		public float forwardVelocity;

		[SerializeField]
		public float minimumY;

		[SerializeField]
		public float minYVelocityForAnim;

		[SerializeField]
		public float maxYVelocityForAnim;

		[SerializeField]
		public float knockbackForce;

		[SerializeField]
		public float maxRadiusToConfirmDetonate;

		[SerializeField]
		public bool confirmDetonate;

		[SerializeField]
		public GameObject spinEffectPrefab;

		[SerializeField]
		public string spinEffectMuzzleString;

		[SerializeField]
		public string soundLoopStartEvent;

		[SerializeField]
		public string soundLoopStopEvent;

		[SerializeField]
		public NetworkSoundEventDef landingSound;

		[SerializeField]
		public float detonateSelfDamageFraction;

		private float previousAirControl;

		private GameObject spinEffectInstance;

		protected bool isCritAuthority;

		protected CrocoDamageTypeController crocoDamageTypeController;

		private bool detonateNextFrame;

		private static int EmptyStateHash = Animator.StringToHash("Empty");

		protected virtual DamageTypeCombo GetBlastDamageType()
		{
			return DamageType.Generic;
		}

		public override void OnEnter()
		{
			base.OnEnter();
			previousAirControl = base.characterMotor.airControl;
			base.characterMotor.airControl = airControl;
			UnityEngine.Vector3 direction = GetAimRay().direction;
			if (base.isAuthority)
			{
				base.characterBody.isSprinting = true;
				direction.y = Mathf.Max(direction.y, minimumY);
				UnityEngine.Vector3 vector = direction.normalized * aimVelocity * moveSpeedStat;
				UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up * upwardVelocity;
				UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(direction.x, 0f, direction.z).normalized * forwardVelocity;
				base.characterMotor.Motor.ForceUnground();
				base.characterMotor.velocity = vector + vector2 + vector3;
				isCritAuthority = RollCrit();
			}
			PlayCrossfade("Gesture, Override", "LarvaLeap", 0.1f);
			Util.PlaySound(leapSoundString, base.gameObject);
			base.characterDirection.moveVector = direction;
			spinEffectInstance = UnityEngine.Object.Instantiate(spinEffectPrefab, FindModelChild(spinEffectMuzzleString));
			if (base.isAuthority)
			{
				base.characterMotor.onMovementHit += OnMovementHit;
			}
			Util.PlaySound(soundLoopStartEvent, base.gameObject);
		}

		private void OnMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo)
		{
			detonateNextFrame = true;
		}

		protected override void UpdateAnimationParameters()
		{
			base.UpdateAnimationParameters();
		}

		public override void FixedUpdate()
		{
			base.FixedUpdate();
			if (!base.isAuthority || !base.characterMotor)
			{
				return;
			}
			base.characterMotor.moveDirection = base.inputBank.moveVector;
			base.characterDirection.moveVector = base.characterMotor.velocity;
			base.characterMotor.disableAirControlUntilCollision = base.characterMotor.velocity.y < 0f;
			if (base.fixedAge >= minimumDuration && (detonateNextFrame || (base.characterMotor.Motor.GroundingStatus.IsStableOnGround && !base.characterMotor.Motor.LastGroundingStatus.IsStableOnGround)))
			{
				bool flag = true;
				if (confirmDetonate)
				{
					BullseyeSearch bullseyeSearch = new BullseyeSearch();
					bullseyeSearch.viewer = base.characterBody;
					bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
					bullseyeSearch.teamMaskFilter.RemoveTeam(base.characterBody.teamComponent.teamIndex);
					bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
					bullseyeSearch.minDistanceFilter = 0f;
					bullseyeSearch.maxDistanceFilter = maxRadiusToConfirmDetonate;
					bullseyeSearch.searchOrigin = base.inputBank.aimOrigin;
					bullseyeSearch.searchDirection = base.inputBank.aimDirection;
					bullseyeSearch.maxAngleFilter = 180f;
					bullseyeSearch.filterByLoS = false;
					bullseyeSearch.RefreshCandidates();
					flag = bullseyeSearch.GetResults().FirstOrDefault();
				}
				if (flag)
				{
					DoImpactAuthority();
				}
				outer.SetNextStateToMain();
			}
		}

		protected virtual void DoImpactAuthority()
		{
			DetonateAuthority();
			if ((bool)landingSound)
			{
				EffectManager.SimpleSoundEffect(landingSound.index, base.characterBody.footPosition, transmit: true);
			}
			base.healthComponent.TakeDamage(new DamageInfo
			{
				damage = base.healthComponent.fullCombinedHealth * detonateSelfDamageFraction,
				attacker = base.characterBody.gameObject,
				position = base.characterBody.corePosition,
				damageType = DamageType.Generic
			});
		}

		protected BlastAttack.Result DetonateAuthority()
		{
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			EffectManager.SpawnEffect(blastEffectPrefab, new EffectData
			{
				origin = footPosition,
				scale = blastRadius
			}, transmit: true);
			return new BlastAttack
			{
				attacker = base.gameObject,
				baseDamage = damageStat * blastDamageCoefficient,
				baseForce = blastForce,
				bonusForce = blastBonusForce,
				crit = isCritAuthority,
				damageType = GetBlastDamageType(),
				falloffModel = BlastAttack.FalloffModel.None,
				procCoefficient = blastProcCoefficient,
				radius = blastRadius,
				position = footPosition,
				attackerFiltering = AttackerFiltering.NeverHitSelf,
				impactEffect = EffectCatalog.FindEffectIndexFromPrefab(blastImpactEffectPrefab),
				teamIndex = base.teamComponent.teamIndex
			}.Fire();
		}

		protected void FireProjectile()
		{
			UnityEngine.Vector3 footPosition = base.characterBody.footPosition;
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.crit = isCritAuthority;
			fireProjectileInfo.force = 0f;
			fireProjectileInfo.damage = damageStat;
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
			fireProjectileInfo.position = footPosition;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
		}

		public override void OnExit()
		{
			Util.PlaySound(soundLoopStopEvent, base.gameObject);
			if (base.isAuthority)
			{
				base.characterMotor.onMovementHit -= OnMovementHit;
			}
			base.characterMotor.airControl = previousAirControl;
			base.characterBody.isSprinting = false;
			if ((bool)spinEffectInstance)
			{
				EntityState.Destroy(spinEffectInstance);
			}
			PlayAnimation("Gesture, Override", EmptyStateHash);
			base.OnExit();
		}

		public override InterruptPriority GetMinimumInterruptPriority()
		{
			return InterruptPriority.PrioritySkill;
		}
	}
	public class SpawnState : GenericCharacterSpawnState
	{
	}
}
namespace EntityStates.LightningStorm
{
	public class LightningStormState : BaseState
	{
		[SerializeField]
		public GameObject lightningInstancePrefab;

		public static int strikesPerSurvivor = 4;

		public static float minDistanceBetweenStrikes = 3f;

		public static float maxStrikeDistanceFromPlayer = 5f;

		public static float frequencyOfLightningStrikes = 8f;

		public static float timeBetweenIndividualStrikes = 0.2f;

		private List<NodeGraph.NodeIndex> possibleNodesToTarget = new List<NodeGraph.NodeIndex>();

		private List<UnityEngine.Vector3> possibleNodePositions = new List<UnityEngine.Vector3>();

		private float stormStopwatch;

		private float strikeStopwatch;

		private Queue<UnityEngine.Vector3> positionsToStrike = new Queue<UnityEngine.Vector3>();

		private GameObject startPostProcessingObject;

		private PostProcessDuration startPostProcessDuration;

		private GameObject endPostProcessingObject;

		private PostProcessDuration endPostProcessDuration;

		private Action ExecuteNextStep;

		public override void OnEnter()
		{
			base.OnEnter();
			LightningStormController component = GetComponent<LightningStormController>();
			if ((bool)component)
			{
				startPostProcessingObject = component.startPostProcessingObject;
				startPostProcessDuration = component.startPostProcessDuration;
				endPostProcessingObject = component.endPostProcessingObject;
				endPostProcessDuration = component.endPostProcessDuration;
			}
			HandleStartStorm();
		}

		public override void OnExit()
		{
			base.OnExit();
			HandleStopStorm();
		}

		private void HandleStartStorm()
		{
			ToggleStormVFX(b: true);
			ExecuteNextStep = GenerateTargetPositions;
			stormStopwatch = -1f;
		}

		private void ToggleStormVFX(bool b)
		{
			if ((bool)startPostProcessingObject)
			{
				startPostProcessingObject.SetActive(b);
				startPostProcessDuration.enabled = b;
			}
			if ((bool)endPostProcessingObject)
			{
				endPostProcessingObject.SetActive(!b);
				endPostProcessDuration.enabled = !b;
			}
		}

		private void GenerateTargetPositions()
		{
			if (stormStopwatch > 0f)
			{
				return;
			}
			positionsToStrike.Clear();
			_ = minDistanceBetweenStrikes;
			_ = minDistanceBetweenStrikes;
			LightningStrikePattern lightningPattern = LightningStormController.lightningPattern;
			if (lightningPattern == null)
			{
				UnityEngine.Debug.LogWarning("No Lightning Storm pattern set up in the LightningStormController!");
				return;
			}
			if (!SceneInfo.instance || !SceneInfo.instance.groundNodes)
			{
				UnityEngine.Debug.LogWarning("No ground nodes available, disabling lightning storm");
				HandleStopStorm();
				return;
			}
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			possibleNodesToTarget.Clear();
			float num = 0f;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (!(instance == null) && !(instance.master == null) && instance.master.GetBody() != null)
				{
					num += 1f;
				}
			}
			num -= 1f;
			foreach (PlayerCharacterMasterController instance2 in PlayerCharacterMasterController.instances)
			{
				CharacterBody body = instance2.master.GetBody();
				if (body == null || !body.hasAuthority)
				{
					continue;
				}
				Transform coreTransform = body.coreTransform;
				UnityEngine.Vector3 velocity = body.characterMotor.velocity;
				float magnitude = new UnityEngine.Vector3(velocity.x, 0f, velocity.z).magnitude;
				velocity = velocity.normalized;
				float num2 = magnitude;
				foreach (LightningStormController.LightningStrikePoint lightningStrikePoint in lightningPattern.lightningStrikePoints)
				{
					float maxDistance = LightningStormController.GetMaxDistance(velocity, magnitude, lightningStrikePoint);
					if (maxDistance > num2)
					{
						num2 = maxDistance;
					}
				}
				num2 = Mathf.Max(num2, lightningPattern.maxAcceptableDistanceFromPredictedPoint * 2f);
				possibleNodesToTarget = groundNodes.FindNodesInRange(coreTransform.position, 0f, num2, HullMask.Human);
				possibleNodePositions.Clear();
				int count = possibleNodesToTarget.Count;
				for (int i = 0; i < count; i++)
				{
					if (groundNodes.GetNodePosition(possibleNodesToTarget[i], out var position2))
					{
						possibleNodePositions.Add(position2);
					}
				}
				int count2 = lightningPattern.lightningStrikePoints.Count;
				count2 -= (int)(num * lightningPattern.forEachAdditionalPlayerReduceStrikeTotalBy);
				count2 = Mathf.Max(count2, 1);
				foreach (LightningStormController.LightningStrikePoint lightningStrikePoint2 in lightningPattern.lightningStrikePoints)
				{
					if (positionsToStrike.Count >= count2)
					{
						break;
					}
					UnityEngine.Vector3 position3 = LightningStormController.PredictPosition(coreTransform.position, coreTransform.forward, magnitude, lightningStrikePoint2);
					if (TryPickBestNodePosition(position3, lightningPattern.maxAcceptableDistanceFromPredictedPoint, out var bestPosition2))
					{
						positionsToStrike.Enqueue(bestPosition2);
					}
				}
			}
			ExecuteNextStep = FireNextStrike;
			bool TryPickBestNodePosition(UnityEngine.Vector3 position, float range, out UnityEngine.Vector3 bestPosition)
			{
				int num3 = -1;
				range *= range;
				float num4 = float.MaxValue;
				bestPosition = UnityEngine.Vector3.zero;
				int count3 = possibleNodePositions.Count;
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(position.x, position.z);
				for (int j = 0; j < count3; j++)
				{
					float sqrMagnitude = (new UnityEngine.Vector2(possibleNodePositions[j].x, possibleNodePositions[j].z) - vector).sqrMagnitude;
					if (sqrMagnitude <= range && sqrMagnitude < num4)
					{
						num3 = j;
						num4 = sqrMagnitude;
					}
				}
				if (num3 != -1)
				{
					bestPosition = possibleNodePositions[num3];
					possibleNodePositions.RemoveAt(num3);
					return true;
				}
				return false;
			}
		}

		private void FireNextStrike()
		{
			if (positionsToStrike.Count < 1)
			{
				stormStopwatch = LightningStormController.lightningPattern.frequencyOfLightningStrikes;
				ExecuteNextStep = GenerateTargetPositions;
			}
			else if (!(strikeStopwatch > 0f))
			{
				strikeStopwatch = LightningStormController.lightningPattern.timeBetweenIndividualStrikes;
				LightningStormController.FireLightningBolt(positionsToStrike.Dequeue(), lightningInstancePrefab);
			}
		}

		private void WaitForNextStrike()
		{
			if (stormStopwatch <= 0f)
			{
				ExecuteNextStep = GenerateTargetPositions;
			}
		}

		private void HandleStopStorm()
		{
			ToggleStormVFX(b: false);
			ExecuteNextStep = null;
		}

		public override void Update()
		{
			float deltaTime = Time.deltaTime;
			stormStopwatch -= deltaTime;
			strikeStopwatch -= deltaTime;
			ExecuteNextStep?.Invoke();
		}

		private void LightningStrikeAtPosition(UnityEngine.Vector3 position)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(lightningInstancePrefab);
			LightningStrikeInstance component = gameObject.GetComponent<LightningStrikeInstance>();
			if (!component)
			{
				UnityEngine.Debug.Log("GameObject doesn't have a lightninginstance component!", gameObject);
			}
			else
			{
				component.Initialize(position, null);
			}
		}
	}
}
namespace RoR2
{
	public class TriggerIntroMusicStart : MonoBehaviour
	{
		private void OnEnable()
		{
			MusicController.Instance.StartIntroMusic();
			UnityEngine.Debug.Log("<color=green>Triggered MusicController</color>");
		}
	}
	public class DevotionInventoryController : NetworkBehaviour
	{
		private static NetworkSoundEventDef activationSoundEventDef;

		public static GameObject s_effectPrefab;

		public SfxLocator sfxLocator;

		private static List<DevotionInventoryController> InstanceList = new List<DevotionInventoryController>();

		private static List<EquipmentIndex> lowLevelEliteBuffs = new List<EquipmentIndex>();

		private static List<EquipmentIndex> highLevelEliteBuffs = new List<EquipmentIndex>();

		private bool _isRespawning;

		private CharacterMaster _summonerMaster;

		private Inventory _devotionMinionInventory;

		public CharacterMaster SummonerMaster
		{
			get
			{
				return _summonerMaster;
			}
			set
			{
				_summonerMaster = value;
			}
		}

		public static bool isDevotionEnable => RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Devotion);

		private Interactor _summonerInteractor => _summonerMaster.GetBody().GetComponent<Interactor>();

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnDevotionArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnDevotionArtifactDisabled;
			LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseNullifiedBuffApplied", delegate(NetworkSoundEventDef asset)
			{
				activationSoundEventDef = asset;
			});
		}

		private static void OnDevotionArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != CU8Content.Artifacts.Devotion))
			{
				lowLevelEliteBuffs.Add(RoR2Content.Equipment.AffixRed.equipmentIndex);
				lowLevelEliteBuffs.Add(RoR2Content.Equipment.AffixWhite.equipmentIndex);
				lowLevelEliteBuffs.Add(RoR2Content.Equipment.AffixBlue.equipmentIndex);
				highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixRed.equipmentIndex);
				highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixWhite.equipmentIndex);
				highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixBlue.equipmentIndex);
				highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixPoison.equipmentIndex);
				highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixLunar.equipmentIndex);
				highLevelEliteBuffs.Add(RoR2Content.Equipment.AffixHaunted.equipmentIndex);
				if (DLC1Content.Elites.Earth.IsAvailable())
				{
					lowLevelEliteBuffs.Add(DLC1Content.Elites.Earth.eliteEquipmentDef.equipmentIndex);
					highLevelEliteBuffs.Add(DLC1Content.Elites.Earth.eliteEquipmentDef.equipmentIndex);
				}
				Run.onRunDestroyGlobal += OnRunDestroy;
				s_effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OrbEffects/ItemTakenOrbEffect");
				BossGroup.onBossGroupDefeatedServer += OnBossGroupDefeatedServer;
			}
		}

		private static void OnDevotionArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != CU8Content.Artifacts.Devotion))
			{
				lowLevelEliteBuffs.Clear();
				highLevelEliteBuffs.Clear();
				Run.onRunDestroyGlobal -= OnRunDestroy;
				s_effectPrefab = null;
				BossGroup.onBossGroupDefeatedServer -= OnBossGroupDefeatedServer;
			}
		}

		private static void OnRunDestroy(Run run)
		{
			for (int i = 0; i < InstanceList.Count; i++)
			{
				UnityEngine.Object.Destroy(InstanceList[i].gameObject);
			}
			InstanceList.Clear();
		}

		public static void StartRespawnAllLemurians()
		{
			foreach (DevotionInventoryController instance in InstanceList)
			{
				if (!instance._isRespawning)
				{
					instance.StartCoroutine(instance.TryRespawnLemurians());
				}
			}
		}

		public static DevotionInventoryController GetOrCreateDevotionInventoryController(Interactor summoner)
		{
			DevotionInventoryController devotionInventoryController = null;
			foreach (DevotionInventoryController instance in InstanceList)
			{
				if (instance._summonerInteractor == summoner)
				{
					devotionInventoryController = instance;
					break;
				}
			}
			if (!devotionInventoryController)
			{
				GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/DevotionMinionInventory"));
				devotionInventoryController = obj.GetComponent<DevotionInventoryController>();
				devotionInventoryController.GetComponent<TeamFilter>().teamIndex = TeamIndex.Player;
				devotionInventoryController._summonerMaster = summoner.GetComponent<CharacterBody>().master;
				NetworkServer.Spawn(obj);
			}
			return devotionInventoryController;
		}

		[Server]
		public static void ActivateAllDevotedEvolution()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::ActivateAllDevotedEvolution()' called on client");
				return;
			}
			foreach (DevotionInventoryController instance in InstanceList)
			{
				instance.UpdateAllMinions(shouldEvolve: true);
			}
		}

		[Server]
		public void ActivateDevotedEvolution()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::ActivateDevotedEvolution()' called on client");
			}
			else
			{
				UpdateAllMinions(shouldEvolve: true);
			}
		}

		[Server]
		public void UpdateAllMinions(bool shouldEvolve = false)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::UpdateAllMinions(System.Boolean)' called on client");
			}
			else
			{
				if (!_summonerMaster)
				{
					return;
				}
				MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(_summonerMaster.netId);
				if (minionGroup == null)
				{
					return;
				}
				MinionOwnership[] members = minionGroup.members;
				foreach (MinionOwnership minionOwnership in members)
				{
					if ((bool)minionOwnership && minionOwnership.GetComponent<CharacterMaster>().TryGetComponent<DevotedLemurianController>(out var component))
					{
						UpdateMinionInventory(component, shouldEvolve);
					}
				}
			}
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public void GiveItem(ItemIndex itemIndex, int count = 1)
		{
			_devotionMinionInventory.GiveItem(itemIndex, count);
		}

		public void RemoveItem(ItemIndex itedmIndex, int count = 1)
		{
			_devotionMinionInventory.RemoveItem(itedmIndex, count);
		}

		public bool HasItem(ItemDef item)
		{
			return _devotionMinionInventory.GetItemCount(item) > 0;
		}

		public void DropScrapOnDeath(ItemIndex devotionItem, CharacterBody minionBody)
		{
			PickupIndex pickupIndex = PickupIndex.none;
			ItemDef itemDef = ItemCatalog.GetItemDef(devotionItem);
			if (itemDef != null)
			{
				switch (itemDef.tier)
				{
				case ItemTier.Tier1:
					pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapWhite");
					break;
				case ItemTier.Tier2:
					pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapGreen");
					break;
				case ItemTier.Tier3:
					pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapRed");
					break;
				case ItemTier.Boss:
					pickupIndex = PickupCatalog.FindPickupIndex("ItemIndex.ScrapYellow");
					break;
				}
			}
			if (pickupIndex != PickupIndex.none)
			{
				PickupDropletController.CreatePickupDroplet(pickupIndex, minionBody.corePosition, UnityEngine.Vector3.down * 15f);
			}
		}

		[Server]
		private void UpdateMinionInventory(DevotedLemurianController devotedLemurianController, bool shouldEvolve)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::UpdateMinionInventory(DevotedLemurianController,System.Boolean)' called on client");
				return;
			}
			CharacterBody lemurianBody = devotedLemurianController.LemurianBody;
			Inventory lemurianInventory = devotedLemurianController.LemurianInventory;
			lemurianInventory.CleanInventory();
			if (shouldEvolve)
			{
				if ((bool)activationSoundEventDef)
				{
					UnityEngine.Debug.Log("playing sound effect");
					EffectManager.SimpleSoundEffect(activationSoundEventDef.index, lemurianBody.gameObject.transform.position, transmit: true);
				}
				devotedLemurianController.DevotedEvolutionLevel++;
				_devotionMinionInventory.GiveItem(devotedLemurianController.DevotionItem);
				EvolveDevotedLumerian(devotedLemurianController);
			}
			int num = 0;
			num = ((devotedLemurianController.DevotedEvolutionLevel != 0 && devotedLemurianController.DevotedEvolutionLevel != 2) ? ((devotedLemurianController.DevotedEvolutionLevel != 1 && devotedLemurianController.DevotedEvolutionLevel != 3) ? (20 + devotedLemurianController.DevotedEvolutionLevel - 3) : 20) : 10);
			lemurianInventory.GiveItem(RoR2Content.Items.BoostHp, num);
			lemurianInventory.GiveItem(RoR2Content.Items.BoostDamage, num);
			lemurianInventory.AddItemsFrom(_devotionMinionInventory);
		}

		[Server]
		private void EvolveDevotedLumerian(DevotedLemurianController devotedLemurianController)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::EvolveDevotedLumerian(DevotedLemurianController)' called on client");
				return;
			}
			CharacterBody lemurianBody = devotedLemurianController.LemurianBody;
			switch (devotedLemurianController.DevotedEvolutionLevel)
			{
			case 1:
				GenerateEliteBuff(lemurianBody, devotedLemurianController, isLowLevel: true);
				break;
			case 2:
				lemurianBody.inventory.SetEquipmentIndex(EquipmentIndex.None);
				lemurianBody.master.TransformBody("DevotedLemurianBruiserBody");
				break;
			case 3:
				GenerateEliteBuff(lemurianBody, devotedLemurianController, isLowLevel: false);
				break;
			default:
				UnityEngine.Debug.LogError("shouldn't evolve!");
				break;
			}
		}

		[Server]
		private void GenerateEliteBuff(CharacterBody body, DevotedLemurianController devotedCntroller, bool isLowLevel)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DevotionInventoryController::GenerateEliteBuff(RoR2.CharacterBody,DevotedLemurianController,System.Boolean)' called on client");
				return;
			}
			List<EquipmentIndex> list = (isLowLevel ? lowLevelEliteBuffs : highLevelEliteBuffs);
			int index = UnityEngine.Random.Range(0, list.Count);
			body.inventory.SetEquipmentIndex(list[index]);
		}

		private void Awake()
		{
			_devotionMinionInventory = base.gameObject.GetComponent<Inventory>();
			_devotionMinionInventory.GiveItem(CU8Content.Items.LemurianHarness);
		}

		public static void OnBossGroupDefeatedServer(BossGroup group)
		{
			UnityEngine.Debug.Log("on boss group defeated server in devotion");
			if (!SceneCatalog.GetSceneDefForCurrentScene().needSkipDevotionRespawn)
			{
				ActivateAllDevotedEvolution();
			}
		}

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

		private void OnDisable()
		{
			InstanceList.Remove(this);
		}

		private IEnumerator TryRespawnLemurians()
		{
			_isRespawning = true;
			while (!_summonerMaster.GetBody())
			{
				yield return new WaitForSeconds(1f);
			}
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			List<NodeGraph.NodeIndex> list = nodeGraph.FindNodesInRangeWithFlagConditions(_summonerInteractor.transform.position, 3f, 40f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false);
			while (list.Count == 0)
			{
				yield return new WaitForSeconds(1f);
				list = nodeGraph.FindNodesInRangeWithFlagConditions(_summonerInteractor.transform.position, 3f, 40f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false);
			}
			while (list.Count > 0)
			{
				int index = UnityEngine.Random.Range(0, list.Count);
				NodeGraph.NodeIndex nodeIndex = list[index];
				if (!nodeGraph.GetNodePosition(nodeIndex, out var position))
				{
					continue;
				}
				MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(_summonerMaster.netId);
				if (minionGroup == null)
				{
					break;
				}
				MinionOwnership[] members = minionGroup.members;
				foreach (MinionOwnership minionOwnership in members)
				{
					if ((bool)minionOwnership)
					{
						CharacterMaster component = minionOwnership.GetComponent<CharacterMaster>();
						if (component.TryGetComponent<DevotedLemurianController>(out var _))
						{
							component.Respawn(position, UnityEngine.Quaternion.identity);
						}
					}
				}
				break;
			}
			_isRespawning = false;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public static class BenchmarkCommandProcessor
	{
		private static string targetScene;

		[ConCommand(commandName = "benchmark", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Load first argument as scene, disables baddies, and spawns test prefab for baddies.")]
		public static void CCBenchmark(ConCommandArgs args)
		{
		}
	}
	public class RoRGraphyControl
	{
		private static RoRGraphyControl instance;

		private bool specsActive;

		private bool fpsActive;

		[ConCommand(commandName = "graphy_specs", flags = ConVarFlags.None, helpText = "Graphy testing.")]
		public static void graphySpecs(ConCommandArgs args)
		{
			if (instance.specsActive)
			{
				G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.ADVANCED, GraphyManager.ModuleState.OFF);
				instance.specsActive = false;
			}
			else
			{
				G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.ADVANCED, GraphyManager.ModuleState.FULL);
				instance.specsActive = true;
			}
			G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.AUDIO, GraphyManager.ModuleState.OFF);
		}

		[ConCommand(commandName = "graphy_init", flags = ConVarFlags.None, helpText = "Graphy testing.")]
		public static void verifyInst(ConCommandArgs args)
		{
			if (instance == null)
			{
				instance = new RoRGraphyControl();
				UnityEngine.Object.DontDestroyOnLoad(UnityEngine.Object.Instantiate(Resources.Load("ror2Graphy") as GameObject));
				instance.specsActive = false;
				instance.fpsActive = false;
			}
		}

		[ConCommand(commandName = "graphy_fps", flags = ConVarFlags.None, helpText = "Graphy testing.")]
		public static void graphyFPS(ConCommandArgs args)
		{
			if (instance.fpsActive)
			{
				G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.FPS, GraphyManager.ModuleState.OFF);
				G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.RAM, GraphyManager.ModuleState.OFF);
				instance.fpsActive = false;
			}
			else
			{
				G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.FPS, GraphyManager.ModuleState.FULL);
				G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.RAM, GraphyManager.ModuleState.FULL);
				instance.fpsActive = true;
			}
			G_Singleton<GraphyManager>.Instance.SetModuleMode(GraphyManager.ModuleType.AUDIO, GraphyManager.ModuleState.OFF);
		}
	}
	public class SoulSpiralGhost : MonoBehaviour
	{
		[Tooltip("Triggered at beginning, to make sure the ghost is cleaned up.")]
		[SerializeField]
		private UnityEvent OnEnableAction;

		[SerializeField]
		[Tooltip("Triggered when the orbs are 'boosted'.")]
		private UnityEvent OnOrbBoost;

		[SerializeField]
		[Tooltip("Triggered when the orbs' boost ends.")]
		private UnityEvent OnOrbBoostEnd;

		[Tooltip("Triggered when a given orb has only one hit left.")]
		[SerializeField]
		private UnityEvent OnOrbLastHit;

		public void OnEnable()
		{
			OnEnableAction?.Invoke();
		}

		public void Boost()
		{
			OnOrbBoost?.Invoke();
		}

		public void EndBoost()
		{
			OnOrbBoostEnd?.Invoke();
		}

		public void OnLastHit()
		{
			OnOrbLastHit?.Invoke();
		}
	}
	public class SproutOfLifeHealOrbSpawn : NetworkBehaviour
	{
		private float seedOfLifeOrbsLeft = 10f;

		private float seedOfLifeOrbsTimer;

		private void Start()
		{
			Util.PlaySound("Play_item_use_healAndRevive_healPlantGrow", base.gameObject);
		}

		private void FixedUpdate()
		{
			if (seedOfLifeOrbsLeft > 0f)
			{
				seedOfLifeOrbsTimer -= Time.fixedDeltaTime;
				if (seedOfLifeOrbsTimer <= 0f && NetworkServer.active)
				{
					SproutSpawnHealOrb();
				}
			}
			else
			{
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/SproutOfLifeBurst"), new EffectData
				{
					origin = base.gameObject.transform.position
				}, transmit: true);
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		[Server]
		private void SproutSpawnHealOrb()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SproutOfLifeHealOrbSpawn::SproutSpawnHealOrb()' called on client");
				return;
			}
			seedOfLifeOrbsTimer += 0.5f;
			float num = Mathf.Pow(4f, 0.25f);
			GameObject original = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/HealPack");
			UnityEngine.Vector3 vector = default(UnityEngine.Vector3);
			vector = base.transform.position + new UnityEngine.Vector3(UnityEngine.Random.Range(-1.5f, 1.5f), 0f, UnityEngine.Random.Range(-1.5f, 1.5f));
			GameObject obj = UnityEngine.Object.Instantiate(original, vector, UnityEngine.Random.rotation);
			TeamIndex teamIndex = TeamIndex.Player;
			TeamFilter component = obj.GetComponent<TeamFilter>();
			if ((bool)component)
			{
				component.teamIndex = teamIndex;
			}
			HealthPickup componentInChildren = obj.GetComponentInChildren<HealthPickup>();
			if ((bool)componentInChildren)
			{
				componentInChildren.flatHealing = 0f;
				componentInChildren.fractionalHealing = 0.02f;
			}
			obj.transform.localScale = new UnityEngine.Vector3(num, num, num);
			NetworkServer.Spawn(obj);
			Util.PlaySound("Play_item_use_healAndRevive_healOrb_gather", base.gameObject);
			seedOfLifeOrbsLeft -= 1f;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class GoldSiphonNearbyBodyController : NetworkBehaviour
	{
		protected class TetheredPlayers
		{
			public GameObject tetheredPlayer;

			public bool isTethered;
		}

		public GameObject shrineGameObject;

		private TeamComponent parentTeamComponent;

		public TetherVfxOrigin tetherVfxOrigin;

		public bool automaticallyScaleCostWithDifficulty = true;

		private uint appliedDrain;

		protected SphereSearch sphereSearch;

		protected float timer;

		protected new Transform transform;

		private bool isTetheredToAtLeastOneObject;

		private int tetheredPlayers;

		private HalcyoniteShrineInteractable parentShrineReference;

		protected PurchaseInteraction purchaseInteraction;

		private int goldDrainValue = 1;

		private EntityStateMachine stateMachine;

		public SerializableEntityStateType lowQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteLowQuality));

		public SerializableEntityStateType midQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteMidQuality));

		public SerializableEntityStateType maxQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteMaxQuality));

		private int shrineLowGoldCost = 75;

		private int shrineMidGoldCost = 150;

		private int shrineMaxGoldCost = 300;

		private float tickRate = 5f;

		private int maxTargets = 4;

		private List<TetheredPlayers> tetheredGameObjects;

		private bool isReady;

		private int tierTracker;

		public static event Action onHalcyonShrineGoldDrain;

		protected void Awake()
		{
			parentShrineReference = GetComponentInParent<HalcyoniteShrineInteractable>();
			shrineLowGoldCost = parentShrineReference.lowGoldCost;
			shrineMidGoldCost = parentShrineReference.midGoldCost;
			shrineMaxGoldCost = parentShrineReference.maxGoldCost;
			tickRate = parentShrineReference.tickRate;
			maxTargets = parentShrineReference.maxTargets;
			goldDrainValue = parentShrineReference.goldDrainValue;
			purchaseInteraction = GetComponentInParent<PurchaseInteraction>();
			appliedDrain = (uint)(goldDrainValue * -1);
			stateMachine = GetComponentInParent<EntityStateMachine>();
			sphereSearch = new SphereSearch();
			transform = base.transform;
		}

		protected void FixedUpdate()
		{
			if (parentShrineReference.interactions > 1)
			{
				timer -= Time.fixedDeltaTime;
				if (timer <= 0f)
				{
					timer += 1f / tickRate;
					DrainGold();
				}
			}
		}

		protected void DrainGold()
		{
			if (sphereSearch == null || parentShrineReference == null || stateMachine == null || this.transform == null || purchaseInteraction == null)
			{
				return;
			}
			if (!isReady)
			{
				isReady = true;
				GrabPlayerReferences();
			}
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			SearchForPlayers(list);
			List<Transform> list2 = CollectionPool<Transform, List<Transform>>.RentCollection();
			for (int i = 0; i < list.Count; i++)
			{
				HurtBox hurtBox = list[i];
				bool isPlayerControlled = hurtBox.healthComponent.body.isPlayerControlled;
				if ((bool)hurtBox && (bool)hurtBox.healthComponent && hurtBox.healthComponent.alive && hurtBox.healthComponent.body.master.money > goldDrainValue && isPlayerControlled)
				{
					Transform transform = hurtBox.healthComponent.body?.coreTransform ?? hurtBox.transform;
					list2.Add(transform);
					for (int j = 0; j < tetheredGameObjects.Count; j++)
					{
						if (tetheredGameObjects[j].tetheredPlayer != null && transform.gameObject == tetheredGameObjects[j].tetheredPlayer)
						{
							tetheredGameObjects[j].tetheredPlayer = transform.gameObject;
							tetheredGameObjects[j].isTethered = true;
						}
					}
					if (NetworkServer.active)
					{
						appliedDrain = (uint)parentShrineReference.goldDrainValue;
						CharacterMaster master = hurtBox.healthComponent.body.master;
						_ = master.money;
						master.money = (uint)Mathf.Max(0f, (float)master.money - (float)appliedDrain);
						_ = master.money;
						EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/CoinImpact"), transform.position, UnityEngine.Vector3.up, transmit: true);
						Util.PlaySound("Play_obj_shrineHalcyonite_goldSiphon", transform.gameObject);
						parentShrineReference.StoreDrainValue(parentShrineReference.goldDrainValue);
						GoldSiphonNearbyBodyController.onHalcyonShrineGoldDrain();
						if (parentShrineReference.goldDrained < parentShrineReference.lowGoldCost && tierTracker == 0)
						{
							tierTracker++;
							purchaseInteraction.SetAvailable(newAvailable: false);
						}
						if (parentShrineReference.goldDrained > parentShrineReference.lowGoldCost && parentShrineReference.goldDrained < parentShrineReference.midGoldCost && tierTracker == 1)
						{
							tierTracker++;
							purchaseInteraction.SetAvailable(newAvailable: true);
							stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref lowQualityState));
						}
						if (parentShrineReference.goldDrained > parentShrineReference.midGoldCost && parentShrineReference.goldDrained < parentShrineReference.maxGoldCost && tierTracker == 2)
						{
							tierTracker++;
							stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref midQualityState));
						}
						if (parentShrineReference.goldDrained >= parentShrineReference.maxGoldCost && tierTracker == 3)
						{
							tierTracker++;
							stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref maxQualityState));
						}
					}
				}
				if (list2.Count >= maxTargets)
				{
					break;
				}
			}
			isTetheredToAtLeastOneObject = (float)list2.Count > 0f;
			if ((bool)tetherVfxOrigin)
			{
				tetherVfxOrigin.SetTetheredTransforms(list2);
			}
			for (int k = 0; k < tetheredGameObjects.Count; k++)
			{
				int num = 0;
				for (int l = 0; l < list2.Count; l++)
				{
					if (tetheredGameObjects[k].tetheredPlayer != list2[l])
					{
						num++;
					}
				}
				if (num == list2.Count)
				{
					tetheredGameObjects[k].isTethered = false;
				}
			}
			if (isTetheredToAtLeastOneObject)
			{
				parentShrineReference.IsDraining(drainingActive: true);
			}
			else
			{
				parentShrineReference.IsDraining(drainingActive: false);
			}
			CollectionPool<Transform, List<Transform>>.ReturnCollection(list2);
			CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}

		protected void SearchForPlayers(List<HurtBox> dest)
		{
			TeamMask mask = default(TeamMask);
			mask.AddTeam(TeamIndex.Player);
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.origin = base.gameObject.transform.position;
			sphereSearch.radius = parentShrineReference.radius;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByHurtBoxTeam(mask);
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			sphereSearch.GetHurtBoxes(dest);
			sphereSearch.ClearCandidates();
		}

		private void GrabPlayerReferences()
		{
			tetheredGameObjects = CollectionPool<TetheredPlayers, List<TetheredPlayers>>.RentCollection();
			for (int i = 0; i < PlayerCharacterMasterController.instances.Count; i++)
			{
				PlayerCharacterMasterController playerCharacterMasterController = PlayerCharacterMasterController.instances[i];
				if ((bool)playerCharacterMasterController)
				{
					CharacterBody body = playerCharacterMasterController.master.GetBody();
					if ((bool)body)
					{
						TetheredPlayers tetheredPlayers = new TetheredPlayers();
						tetheredPlayers.tetheredPlayer = body.gameObject;
						tetheredGameObjects.Add(tetheredPlayers);
					}
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class HalcyoniteShrineInteractable : NetworkBehaviour
	{
		[Header("Shrine Core Variables")]
		public bool HalcyoniteShrineActive = true;

		[Tooltip("Flat max gold cost for accessing top quality. *Note, without difficulty cost scaling.")]
		public int maxGoldCost = 300;

		[Tooltip("Flat mid gold cost for accessing top quality. *Note, without difficulty cost scaling.")]
		public int midGoldCost = 150;

		[Tooltip("Minimum amount of gold required to activate boss fight and end drain. *Note, without difficulty cost scaling.")]
		public int lowGoldCost = 75;

		[Tooltip("True if shrine gold mechanic should increase with difficulty. False if it should not.")]
		[SerializeField]
		private bool automaticallyScaleCostWithDifficulty = true;

		[SerializeField]
		private GameObject shrineCollisionObject;

		[Tooltip("Detection radius for picking up the players within range of the Halcyonite Shrine.")]
		[Header("Draining Gold Variables")]
		public float radius = 30f;

		[Tooltip("Amount drained per tick.")]
		public int goldDrainValue = 1;

		[Tooltip("Total amount of gold stored in Shrine.")]
		public int goldDrained;

		[UnityEngine.Min(float.Epsilon)]
		[Tooltip("How many ticks per second.")]
		public float tickRate = 5f;

		[SyncVar]
		[Tooltip("Maximum amount of player targets allowed.")]
		public int maxTargets = 4;

		[Tooltip("Game Object for the network game object responsible for draining the player's gold.")]
		public GameObject siphonObject;

		[SyncVar]
		[HideInInspector]
		public int interactions;

		[SerializeField]
		[Tooltip("Renderer reference for when changing target renderers for the highlight script.")]
		private Renderer shrineRenderer;

		[SyncVar]
		public bool isDraining;

		[SerializeField]
		[Tooltip("Reference to the crystal object for changing its materials.")]
		[Header("Gauge Mechanic")]
		public GameObject crystalObject;

		[SerializeField]
		[SyncVar]
		public GameObject shrineGoldBottom;

		[SyncVar]
		[SerializeField]
		public GameObject shrineGoldMid;

		[SerializeField]
		[SyncVar]
		public GameObject shrineGoldTop;

		[SerializeField]
		public Material goldMaterialController;

		[Tooltip("Color of VFX and Crystal once the encounter is finished and reward has been dispersed.")]
		[SerializeField]
		public GameObject shrineBaseObject;

		[Tooltip("Halcyonite Shrine bubble Game Object reference.")]
		[SerializeField]
		public GameObject shrineHalcyoniteBubble;

		[Tooltip("Entity State Machine reference for handling changes to gauge mechanics for the network.")]
		[SerializeField]
		public EntityStateMachine stateMachine;

		public SerializableEntityStateType noQualityState = new SerializableEntityStateType(typeof(ShrineHalcyoniteNoQuality));

		public SerializableEntityStateType finishedState = new SerializableEntityStateType(typeof(ShrineHalcyoniteFinished));

		public SfxLocator sfxLocator;

		[SerializeField]
		private PurchaseInteraction purchaseInteraction;

		[SerializeField]
		[Header("Shrine Encounter and Rewards")]
		private DirectorCard chosenDirectCard;

		[SerializeField]
		[Tooltip("Drop table dictating what rewards are available at minimum gold value.")]
		private BasicPickupDropTable halcyoniteDropTableTier1;

		[SerializeField]
		[Tooltip("Drop table dictating what rewards are available at middling gold value.")]
		private BasicPickupDropTable halcyoniteDropTableTier2;

		[SerializeField]
		[Tooltip("Drop table dictating what rewards are available at maximum gold value.")]
		private BasicPickupDropTable halcyoniteDropTableTier3;

		[Tooltip("Use this tier to get a pickup index for the reward.  The droplet's visuals will correspond to this.")]
		[SerializeField]
		private ItemTier rewardDisplayTier;

		[SerializeField]
		[Tooltip("The number of options to display when the player interacts with the reward pickup.")]
		private int rewardOptionCount;

		[SerializeField]
		[Tooltip("The prefab to use for the reward pickup.")]
		private GameObject rewardPickupPrefab;

		[SerializeField]
		[Tooltip("Where to spawn the reward droplets relative to the spawn target (the center of the safe ward).")]
		private UnityEngine.Vector3 rewardOffset;

		[SerializeField]
		[Header("Colossus Portal")]
		public ChildLocator modelChildLocator;

		public PortalSpawner[] portalSpawners;

		[Tooltip("Combat Director managing the monster wave that spawns on Halcyon Shrine's gold drain behavior activation.")]
		public CombatDirector activationDirector;

		[Tooltip("Monster credits given to combat director to determine how many monsters to spawn.")]
		public float monsterCredit;

		[SerializeField]
		private bool scaleMonsterCreditWithDifficultyCoefficient = true;

		[SerializeField]
		private CombatDirector combatDirector;

		private int quantityIncreaseFromBuyIn = 1;

		private BasicPickupDropTable rewardDropTable;

		private Xoroshiro128Plus rng;

		[SyncVar]
		public float goldMaterialModifier = -2.2f;

		[SyncVar]
		private bool visualsDone;

		private NetworkInstanceId ___shrineGoldBottomNetId;

		private NetworkInstanceId ___shrineGoldMidNetId;

		private NetworkInstanceId ___shrineGoldTopNetId;

		public static bool isCommandEnabled => RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.Command);

		public int NetworkmaxTargets
		{
			get
			{
				return maxTargets;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref maxTargets, 1u);
			}
		}

		public int Networkinteractions
		{
			get
			{
				return interactions;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref interactions, 2u);
			}
		}

		public bool NetworkisDraining
		{
			get
			{
				return isDraining;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref isDraining, 4u);
			}
		}

		public GameObject NetworkshrineGoldBottom
		{
			get
			{
				return shrineGoldBottom;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref shrineGoldBottom, 8u, ref ___shrineGoldBottomNetId);
			}
		}

		public GameObject NetworkshrineGoldMid
		{
			get
			{
				return shrineGoldMid;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref shrineGoldMid, 16u, ref ___shrineGoldMidNetId);
			}
		}

		public GameObject NetworkshrineGoldTop
		{
			get
			{
				return shrineGoldTop;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref shrineGoldTop, 32u, ref ___shrineGoldTopNetId);
			}
		}

		public float NetworkgoldMaterialModifier
		{
			get
			{
				return goldMaterialModifier;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref goldMaterialModifier, 64u);
			}
		}

		public bool NetworkvisualsDone
		{
			get
			{
				return visualsDone;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref visualsDone, 128u);
			}
		}

		protected void Awake()
		{
			if (NetworkServer.active)
			{
				if (automaticallyScaleCostWithDifficulty)
				{
					lowGoldCost = Run.instance.GetDifficultyScaledCost(lowGoldCost);
					midGoldCost = Run.instance.GetDifficultyScaledCost(midGoldCost);
					maxGoldCost = Run.instance.GetDifficultyScaledCost(maxGoldCost);
					goldDrainValue = Run.instance.GetDifficultyScaledCost(goldDrainValue);
				}
				CalculateCredits();
				HalcyoniteShrineActive = true;
				goldMaterialController.EnableKeyword("_SLICEHEIGHT");
				combatDirector = GetComponent<CombatDirector>();
			}
		}

		private void Start()
		{
			HalcyoniteShrineActive = true;
			shrineCollisionObject.layer = LayerIndex.world.intVal;
		}

		private void CalculateCredits()
		{
			if (scaleMonsterCreditWithDifficultyCoefficient)
			{
				monsterCredit = Mathf.CeilToInt(monsterCredit * Run.instance.difficultyCoefficient);
			}
		}

		[Server]
		public void TrackInteractions()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::TrackInteractions()' called on client");
				return;
			}
			if (interactions == 0)
			{
				GetComponent<Highlight>().targetRenderer = shrineRenderer;
				stateMachine.SetNextStateToMain();
			}
			Networkinteractions = interactions + 1;
			if (interactions >= 3)
			{
				stateMachine.SetNextState(new ShrineHalcyoniteMaxQuality());
			}
		}

		[Server]
		public void IsDraining(bool drainingActive)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::IsDraining(System.Boolean)' called on client");
			}
			else
			{
				NetworkisDraining = drainingActive;
			}
		}

		public void DestroyDrainVFX()
		{
			if ((bool)siphonObject)
			{
				NetworkServer.Destroy(siphonObject);
			}
			if ((bool)shrineHalcyoniteBubble && shrineHalcyoniteBubble.activeInHierarchy)
			{
				shrineHalcyoniteBubble.SetActive(value: false);
			}
			IsDraining(drainingActive: false);
		}

		public void DrainConditionMet()
		{
			DestroyDrainVFX();
			if ((bool)purchaseInteraction && purchaseInteraction.available)
			{
				purchaseInteraction.SetAvailable(newAvailable: false);
			}
			if (goldDrained > lowGoldCost && goldDrained < midGoldCost)
			{
				quantityIncreaseFromBuyIn = 1;
				rewardDropTable = halcyoniteDropTableTier1;
				rewardOptionCount = 3;
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			}
			if (goldDrained > midGoldCost && goldDrained < maxGoldCost)
			{
				quantityIncreaseFromBuyIn = 1;
				rewardDropTable = halcyoniteDropTableTier2;
				rewardOptionCount = 4;
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			}
			if (goldDrained >= maxGoldCost)
			{
				quantityIncreaseFromBuyIn = 1;
				rewardDropTable = halcyoniteDropTableTier3;
				rewardOptionCount = 5;
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			}
			Transform transform = modelChildLocator.FindChild("ModelBase");
			if (transform != null)
			{
				UnityEngine.Vector3 origin = transform.position + new UnityEngine.Vector3(0f, 16f, 0f);
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/HalcyonShrineTierReachVFX"), new EffectData
				{
					origin = origin
				}, transmit: false);
			}
			int difficultyLevel = (int)((float)goldDrained / 100f);
			combatDirector.HalcyoniteShrineActivation(chosenDirectCard.cost, chosenDirectCard, difficultyLevel, base.gameObject.transform);
		}

		public void StoreDrainValue(int value)
		{
			goldDrained += value;
		}

		[Server]
		public void AttemptSpawnPortal()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::AttemptSpawnPortal()' called on client");
				return;
			}
			PortalSpawner[] array = portalSpawners;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].AttemptSpawnPortalServer();
			}
		}

		[Server]
		public void DropRewards()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HalcyoniteShrineInteractable::DropRewards()' called on client");
				return;
			}
			stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref finishedState));
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (participatingPlayerCount <= 0 || !base.gameObject || !rewardDropTable)
			{
				return;
			}
			int num = participatingPlayerCount * quantityIncreaseFromBuyIn;
			float angle = 360f / (float)num;
			UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
			UnityEngine.Vector3 position = base.gameObject.transform.position + rewardOffset;
			int num2 = 0;
			while (num2 < num)
			{
				if (isCommandEnabled)
				{
					int num3 = rewardOptionCount - 2;
					for (int i = 0; i < num3; i++)
					{
						PickupIndex pickupIndex = rewardDropTable.GenerateDrop(rng);
						GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
						createPickupInfo.pickupIndex = pickupIndex;
						createPickupInfo.rotation = UnityEngine.Quaternion.identity;
						createPickupInfo.position = position;
						GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo;
						PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector);
					}
				}
				else
				{
					GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
					createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier);
					createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTablePlusForcedStorm(rewardOptionCount, halcyoniteDropTableTier3, halcyoniteDropTableTier2, rng);
					createPickupInfo.rotation = UnityEngine.Quaternion.identity;
					createPickupInfo.prefabOverride = rewardPickupPrefab;
					GenericPickupController.CreatePickupInfo pickupInfo2 = createPickupInfo;
					pickupInfo2.position = position;
					PickupDropletController.CreatePickupDroplet(pickupInfo2, position, vector);
				}
				num2++;
				vector = quaternion * vector;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)maxTargets);
				writer.WritePackedUInt32((uint)interactions);
				writer.Write(isDraining);
				writer.Write(shrineGoldBottom);
				writer.Write(shrineGoldMid);
				writer.Write(shrineGoldTop);
				writer.Write(goldMaterialModifier);
				writer.Write(visualsDone);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)maxTargets);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)interactions);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(isDraining);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(shrineGoldBottom);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(shrineGoldMid);
			}
			if ((base.syncVarDirtyBits & 0x20u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(shrineGoldTop);
			}
			if ((base.syncVarDirtyBits & 0x40u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(goldMaterialModifier);
			}
			if ((base.syncVarDirtyBits & 0x80u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(visualsDone);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				maxTargets = (int)reader.ReadPackedUInt32();
				interactions = (int)reader.ReadPackedUInt32();
				isDraining = reader.ReadBoolean();
				___shrineGoldBottomNetId = reader.ReadNetworkId();
				___shrineGoldMidNetId = reader.ReadNetworkId();
				___shrineGoldTopNetId = reader.ReadNetworkId();
				goldMaterialModifier = reader.ReadSingle();
				visualsDone = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				maxTargets = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 2u) != 0)
			{
				interactions = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 4u) != 0)
			{
				isDraining = reader.ReadBoolean();
			}
			if (((uint)num & 8u) != 0)
			{
				shrineGoldBottom = reader.ReadGameObject();
			}
			if (((uint)num & 0x10u) != 0)
			{
				shrineGoldMid = reader.ReadGameObject();
			}
			if (((uint)num & 0x20u) != 0)
			{
				shrineGoldTop = reader.ReadGameObject();
			}
			if (((uint)num & 0x40u) != 0)
			{
				goldMaterialModifier = reader.ReadSingle();
			}
			if (((uint)num & 0x80u) != 0)
			{
				visualsDone = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
			if (!___shrineGoldBottomNetId.IsEmpty())
			{
				NetworkshrineGoldBottom = ClientScene.FindLocalObject(___shrineGoldBottomNetId);
			}
			if (!___shrineGoldMidNetId.IsEmpty())
			{
				NetworkshrineGoldMid = ClientScene.FindLocalObject(___shrineGoldMidNetId);
			}
			if (!___shrineGoldTopNetId.IsEmpty())
			{
				NetworkshrineGoldTop = ClientScene.FindLocalObject(___shrineGoldTopNetId);
			}
		}
	}
	public class MultiOptionPickerPanel : MonoBehaviour
	{
		private int numberOfPickUpsSelected;

		public int numberOfPickUpsAvailable = 1;

		private EventFunctions eventFunctions;

		private void Start()
		{
			eventFunctions = base.gameObject.GetComponent<EventFunctions>();
		}

		public void AddPickupSelected()
		{
			numberOfPickUpsSelected++;
			if (numberOfPickUpsSelected >= numberOfPickUpsAvailable)
			{
				KillPanel();
			}
		}

		private void KillPanel()
		{
			eventFunctions.DestroySelf();
		}
	}
	public class DelayedDamageEffectUpdater : MonoBehaviour
	{
		private CharacterBody body;

		private void OnEnable()
		{
			body = GetComponentInParent<CharacterModel>().body;
			CharacterBody characterBody = body;
			characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Combine(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				CharacterBody characterBody = body;
				characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Remove(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
			}
		}

		private void HandleNetworkItemUpdate(CharacterBody.NetworkItemBehaviorData itemBehaviorData)
		{
			if (itemBehaviorData.itemIndex == DLC2Content.Items.DelayedDamage.itemIndex)
			{
				SpawnDelayedDamageEffect();
			}
		}

		public void SpawnDelayedDamageEffect()
		{
			UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/DelayedDamageIndicator"), body.mainHurtBox ? body.mainHurtBox.transform.position : body.transform.position, UnityEngine.Quaternion.identity, body.mainHurtBox ? body.mainHurtBox.transform : body.transform);
		}
	}
	public class GoldOnStageStartBehaviour : MonoBehaviour
	{
		private CharacterBody body;

		private void OnEnable()
		{
			body = GetComponentInParent<CharacterModel>().body;
			CharacterBody characterBody = body;
			characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Combine(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				CharacterBody characterBody = body;
				characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Remove(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
			}
		}

		private void HandleNetworkItemUpdate(CharacterBody.NetworkItemBehaviorData itemBehaviorData)
		{
			if (itemBehaviorData.itemIndex == DLC2Content.Items.GoldOnStageStart.itemIndex)
			{
				GiveWarBondsGold(itemBehaviorData.floatValue);
			}
		}

		private void GiveWarBondsGold(float na)
		{
			if (((body.inventory != null && body.inventory.GetItemCount(DLC2Content.Items.GoldOnStageStart) != 0) ? 1 : 0) > (false ? 1 : 0))
			{
				Util.PlaySound("Play_item_proc_goldOnStageStart", body.gameObject);
				EffectManager.SpawnEffect(CharacterBody.CommonAssets.goldOnStageStartEffect, new EffectData
				{
					origin = base.transform.position
				}, transmit: false);
			}
		}
	}
	public class LowerHealthHigherDamageEffectUpdater : MonoBehaviour
	{
		private CharacterBody body;

		public GameObject rageCrystalEffect;

		private void OnEnable()
		{
			body = GetComponentInParent<CharacterModel>().body;
			CharacterBody characterBody = body;
			characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Combine(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				CharacterBody characterBody = body;
				characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Remove(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
			}
		}

		private void HandleNetworkItemUpdate(CharacterBody.NetworkItemBehaviorData itemBehaviorData)
		{
			if (itemBehaviorData.itemIndex == DLC2Content.Items.LowerHealthHigherDamage.itemIndex)
			{
				UpdateLanternFlameEffect((int)itemBehaviorData.floatValue);
			}
		}

		public void UpdateLanternFlameEffect(int on)
		{
			if (on != 0)
			{
				rageCrystalEffect.SetActive(value: true);
				Util.PlaySound("Play_item_proc_lowerHealthHigherDamage_active_loop", base.gameObject);
			}
			else
			{
				rageCrystalEffect.SetActive(value: false);
				Util.PlaySound("Stop_item_proc_lowerHealthHigherDamage_active_loop", base.gameObject);
			}
		}
	}
	public class JunkContent : IContentPackProvider
	{
		public static class Items
		{
			public static ItemDef AACannon;

			public static ItemDef PlasmaCore;

			public static ItemDef CooldownOnCrit;

			public static ItemDef TempestOnKill;

			public static ItemDef WarCryOnCombat;

			public static ItemDef PlantOnHit;

			public static ItemDef MageAttunement;

			public static ItemDef BurnNearby;

			public static ItemDef CritHeal;

			public static ItemDef Incubator;

			public static ItemDef SkullCounter;
		}

		public static class Equipment
		{
			public static EquipmentDef SoulJar;

			public static EquipmentDef EliteYellowEquipment;

			public static EquipmentDef EliteGoldEquipment;

			public static EquipmentDef GhostGun;

			public static EquipmentDef OrbitalLaser;

			public static EquipmentDef Enigma;

			public static EquipmentDef SoulCorruptor;
		}

		public static class Buffs
		{
			public static BuffDef EnrageAncientWisp;

			public static BuffDef LightningShield;

			public static BuffDef Slow30;

			public static BuffDef EngiTeamShield;

			public static BuffDef GoldEmpowered;

			public static BuffDef LoaderOvercharged;

			public static BuffDef LoaderPylonPowered;

			public static BuffDef Deafened;

			public static BuffDef MeatRegenBoost;

			public static BuffDef BodyArmor;
		}

		public static class Elites
		{
			public static EliteDef Gold;
		}

		private ContentPack contentPack = new ContentPack();

		public string identifier => "RoR2.Junk";

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			contentPack.identifier = identifier;
			AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator("ContentPack:RoR2.Junk");
			yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack);
			loadHelper.AddGenericOperation(delegate
			{
				ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Equipment), contentPack.equipmentDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Buffs), contentPack.buffDefs, (string fieldName) => "bd" + fieldName);
				ContentLoadHelper.PopulateTypeFields(typeof(Elites), contentPack.eliteDefs, (string fieldName) => "ed" + fieldName);
			}, 0.05f);
			while (loadHelper.coroutine.MoveNext())
			{
				args.ReportProgress(loadHelper.progress.value);
				yield return loadHelper.coroutine.Current;
			}
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			ContentPack.Copy(contentPack, args.output);
			yield break;
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			yield break;
		}
	}
	public struct AchievementIndex
	{
		[SerializeField]
		public int intValue;

		public static AchievementIndex operator ++(AchievementIndex achievementIndex)
		{
			achievementIndex.intValue++;
			return achievementIndex;
		}
	}
	public struct ServerAchievementIndex : IEquatable<ServerAchievementIndex>
	{
		[SerializeField]
		public int intValue;

		public bool Equals(ServerAchievementIndex other)
		{
			return intValue == other.intValue;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is ServerAchievementIndex)
			{
				return Equals((ServerAchievementIndex)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return intValue.GetHashCode();
		}

		public static ServerAchievementIndex operator ++(ServerAchievementIndex achievementIndex)
		{
			achievementIndex.intValue++;
			return achievementIndex;
		}

		public static bool operator ==(ServerAchievementIndex a, ServerAchievementIndex b)
		{
			return a.intValue == b.intValue;
		}

		public static bool operator !=(ServerAchievementIndex a, ServerAchievementIndex b)
		{
			return a.intValue != b.intValue;
		}
	}
	public static class NetworkExtensions
	{
		private static int itemMaskBitCount;

		private static int itemMaskByteCount;

		private static byte[] itemMaskByteBuffer;

		public static void WriteAchievementIndex(this NetworkWriter writer, AchievementIndex value)
		{
			writer.WritePackedUInt32((uint)value.intValue);
		}

		public static AchievementIndex ReadAchievementIndex(this NetworkReader reader)
		{
			AchievementIndex result = default(AchievementIndex);
			result.intValue = (int)reader.ReadPackedUInt32();
			return result;
		}

		public static void WriteBodyIndex(this NetworkWriter writer, BodyIndex bodyIndex)
		{
			writer.WritePackedIndex32((int)bodyIndex);
		}

		public static BodyIndex ReadBodyIndex(this NetworkReader reader)
		{
			return (BodyIndex)reader.ReadPackedIndex32();
		}

		public static void WriteBuffIndex(this NetworkWriter writer, BuffIndex buffIndex)
		{
			writer.WritePackedIndex32((int)buffIndex);
		}

		public static BuffIndex ReadBuffIndex(this NetworkReader reader)
		{
			return (BuffIndex)reader.ReadPackedIndex32();
		}

		public static DamageTypeCombo ReadDamageType(this NetworkReader reader)
		{
			return reader.ReadPackedUInt64();
		}

		public static void WriteDamageType(this NetworkWriter writer, DamageTypeCombo damageType)
		{
			writer.WritePackedUInt64(damageType.damageTypeCombined);
		}

		public static DamageColorIndex ReadDamageColorIndex(this NetworkReader reader)
		{
			return (DamageColorIndex)reader.ReadByte();
		}

		public static void Write(this NetworkWriter writer, DamageColorIndex damageColorIndex)
		{
			writer.Write((byte)damageColorIndex);
		}

		public static void Write(this NetworkWriter writer, DamageInfo damageInfo)
		{
			writer.Write(damageInfo.damage);
			writer.Write(damageInfo.crit);
			writer.Write(damageInfo.attacker);
			writer.Write(damageInfo.inflictor);
			writer.Write(damageInfo.position);
			writer.Write(damageInfo.force);
			writer.Write(damageInfo.procChainMask);
			writer.Write(damageInfo.procCoefficient);
			writer.WritePackedUInt32((uint)(ulong)damageInfo.damageType);
			writer.Write((byte)damageInfo.damageColorIndex);
			writer.Write((byte)(damageInfo.dotIndex + 1));
			writer.Write(damageInfo.canRejectForce);
		}

		public static DamageInfo ReadDamageInfo(this NetworkReader reader)
		{
			return new DamageInfo
			{
				damage = reader.ReadSingle(),
				crit = reader.ReadBoolean(),
				attacker = reader.ReadGameObject(),
				inflictor = reader.ReadGameObject(),
				position = reader.ReadVector3(),
				force = reader.ReadVector3(),
				procChainMask = reader.ReadProcChainMask(),
				procCoefficient = reader.ReadSingle(),
				damageType = reader.ReadPackedUInt64(),
				damageColorIndex = (DamageColorIndex)reader.ReadByte(),
				dotIndex = (DotController.DotIndex)(reader.ReadByte() - 1),
				canRejectForce = reader.ReadBoolean()
			};
		}

		public static void WriteEffectIndex(this NetworkWriter writer, EffectIndex effectIndex)
		{
			writer.WritePackedUInt32((uint)(effectIndex + 1));
		}

		public static EffectIndex ReadEffectIndex(this NetworkReader reader)
		{
			return (EffectIndex)(reader.ReadPackedUInt32() - 1);
		}

		public static void Write(this NetworkWriter writer, EffectData effectData)
		{
			effectData.Serialize(writer);
		}

		public static EffectData ReadEffectData(this NetworkReader reader)
		{
			EffectData effectData = new EffectData();
			effectData.Deserialize(reader);
			return effectData;
		}

		public static void ReadEffectData(this NetworkReader reader, EffectData effectData)
		{
			effectData.Deserialize(reader);
		}

		public static void Write(this NetworkWriter writer, EntityStateIndex entityStateIndex)
		{
			writer.WritePackedIndex32((int)entityStateIndex);
		}

		public static EntityStateIndex ReadEntityStateIndex(this NetworkReader reader)
		{
			return (EntityStateIndex)reader.ReadPackedIndex32();
		}

		public static void Write(this NetworkWriter writer, EquipmentIndex equipmentIndex)
		{
			writer.WritePackedUInt32((uint)(equipmentIndex + 1));
		}

		public static EquipmentIndex ReadEquipmentIndex(this NetworkReader reader)
		{
			return (EquipmentIndex)(reader.ReadPackedUInt32() - 1);
		}

		public static void Write(this NetworkWriter writer, Run.TimeStamp timeStamp)
		{
			Run.TimeStamp.Serialize(writer, timeStamp);
		}

		public static Run.TimeStamp ReadTimeStamp(this NetworkReader reader)
		{
			return Run.TimeStamp.Deserialize(reader);
		}

		public static void Write(this NetworkWriter writer, Run.FixedTimeStamp timeStamp)
		{
			Run.FixedTimeStamp.Serialize(writer, timeStamp);
		}

		public static Run.FixedTimeStamp ReadFixedTimeStamp(this NetworkReader reader)
		{
			return Run.FixedTimeStamp.Deserialize(reader);
		}

		public static void Write(this NetworkWriter writer, HurtBoxReference hurtBoxReference)
		{
			hurtBoxReference.Write(writer);
		}

		public static HurtBoxReference ReadHurtBoxReference(this NetworkReader reader)
		{
			HurtBoxReference result = default(HurtBoxReference);
			result.Read(reader);
			return result;
		}

		public static void Write(this NetworkWriter writer, ItemIndex itemIndex)
		{
			writer.WritePackedUInt32((uint)(itemIndex + 1));
		}

		public static ItemIndex ReadItemIndex(this NetworkReader reader)
		{
			return (ItemIndex)(reader.ReadPackedUInt32() - 1);
		}

		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			itemMaskBitCount = ItemCatalog.itemCount;
			itemMaskByteCount = itemMaskBitCount + 7 >> 3;
			itemMaskByteBuffer = new byte[itemMaskByteCount];
		}

		public static void WriteItemStacks(this NetworkWriter writer, int[] srcItemStacks)
		{
			int num = 0;
			for (int i = 0; i < itemMaskByteCount; i++)
			{
				byte b = 0;
				int num2 = 0;
				while (num2 < 8 && num < itemMaskBitCount && num < srcItemStacks.Length)
				{
					if (srcItemStacks[num] > 0)
					{
						b |= (byte)(1 << num2);
					}
					num2++;
					num++;
				}
				itemMaskByteBuffer[i] = b;
			}
			for (int j = 0; j < itemMaskByteCount && j < itemMaskByteBuffer.Length; j++)
			{
				writer.Write(itemMaskByteBuffer[j]);
			}
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount && (int)itemIndex < srcItemStacks.Length; itemIndex++)
			{
				int num3 = srcItemStacks[(int)itemIndex];
				if (num3 > 0)
				{
					writer.WritePackedUInt32((uint)num3);
				}
			}
		}

		public static void ReadItemStacks(this NetworkReader reader, int[] destItemStacks)
		{
			for (int i = 0; i < itemMaskByteCount; i++)
			{
				itemMaskByteBuffer[i] = reader.ReadByte();
			}
			int num = 0;
			for (int j = 0; j < itemMaskByteCount; j++)
			{
				byte b = itemMaskByteBuffer[j];
				int num2 = 0;
				while (num2 < 8 && num < itemMaskBitCount)
				{
					destItemStacks[num] = (int)(((b & (byte)(1 << num2)) != 0) ? reader.ReadPackedUInt32() : 0);
					num2++;
					num++;
				}
			}
		}

		public static void WriteBitArray(this NetworkWriter writer, [NotNull] bool[] values)
		{
			writer.WriteBitArray(values, values.Length);
		}

		public static void WriteBitArray(this NetworkWriter writer, [NotNull] bool[] values, int bufferLength)
		{
			int num = bufferLength + 7 >> 3;
			int num2 = num - 1;
			int num3 = bufferLength - (num2 << 3);
			int num4 = 0;
			for (int i = 0; i < num; i++)
			{
				byte b = 0;
				int num5 = ((i < num2) ? 8 : num3);
				int num6 = 0;
				while (num6 < num5)
				{
					if (values[num4])
					{
						b |= (byte)(1 << num6);
					}
					num6++;
					num4++;
				}
				writer.Write(b);
			}
		}

		public static void ReadBitArray(this NetworkReader reader, [NotNull] bool[] values)
		{
			reader.ReadBitArray(values, values.Length);
		}

		public static void ReadBitArray(this NetworkReader reader, [NotNull] bool[] values, int bufferLength)
		{
			int num = bufferLength + 7 >> 3;
			int num2 = num - 1;
			int num3 = bufferLength - (num2 << 3);
			int num4 = 0;
			for (int i = 0; i < num; i++)
			{
				int num5 = ((i < num2) ? 8 : num3);
				byte b = reader.ReadByte();
				int num6 = 0;
				while (num6 < num5)
				{
					values[num4] = (b & (byte)(1 << num6)) != 0;
					num6++;
					num4++;
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void WritePackedIndex32(this NetworkWriter writer, int index)
		{
			writer.WritePackedUInt32((uint)(index + 1));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int ReadPackedIndex32(this NetworkReader reader)
		{
			return (int)(reader.ReadPackedUInt32() - 1);
		}

		public static void Write(this NetworkWriter writer, NetworkPlayerName networkPlayerName)
		{
			networkPlayerName.Serialize(writer);
		}

		public static NetworkPlayerName ReadNetworkPlayerName(this NetworkReader reader)
		{
			NetworkPlayerName result = default(NetworkPlayerName);
			result.Deserialize(reader);
			return result;
		}

		public static void Write(this NetworkWriter writer, PackedUnitVector3 value)
		{
			writer.Write(value.value);
		}

		public static PackedUnitVector3 ReadPackedUnitVector3(this NetworkReader reader)
		{
			return new PackedUnitVector3(reader.ReadUInt16());
		}

		public static void Write(this NetworkWriter writer, PickupIndex value)
		{
			PickupIndex.WriteToNetworkWriter(writer, value);
		}

		public static PickupIndex ReadPickupIndex(this NetworkReader reader)
		{
			return PickupIndex.ReadFromNetworkReader(reader);
		}

		public static void Write(this NetworkWriter writer, PitchYawPair pitchYawPair)
		{
			writer.Write(pitchYawPair.pitch);
			writer.Write(pitchYawPair.yaw);
		}

		public static PitchYawPair ReadPitchYawPair(this NetworkReader reader)
		{
			float pitch = reader.ReadSingle();
			float yaw = reader.ReadSingle();
			return new PitchYawPair(pitch, yaw);
		}

		public static void Write(this NetworkWriter writer, ProcChainMask procChainMask)
		{
			writer.WritePackedUInt32(procChainMask.mask);
		}

		public static ProcChainMask ReadProcChainMask(this NetworkReader reader)
		{
			ProcChainMask result = default(ProcChainMask);
			result.mask = reader.ReadPackedUInt32();
			return result;
		}

		public static void Write(this NetworkWriter writer, RuleBook src)
		{
			src.Serialize(writer);
		}

		public static void ReadRuleBook(this NetworkReader reader, RuleBook dest)
		{
			dest.Deserialize(reader);
		}

		public static void Write(this NetworkWriter writer, RuleMask src)
		{
			src.Serialize(writer);
		}

		public static void ReadRuleMask(this NetworkReader reader, RuleMask dest)
		{
			dest.Deserialize(reader);
		}

		public static void Write(this NetworkWriter writer, RuleChoiceMask src)
		{
			src.Serialize(writer);
		}

		public static void ReadRuleChoiceMask(this NetworkReader reader, RuleChoiceMask dest)
		{
			dest.Deserialize(reader);
		}

		public static void Write(this NetworkWriter writer, TeamIndex teamIndex)
		{
			byte value = (byte)(teamIndex + 1);
			writer.Write(value);
		}

		public static TeamIndex ReadTeamIndex(this NetworkReader reader)
		{
			return (TeamIndex)(reader.ReadByte() - 1);
		}

		public static void Write(this NetworkWriter writer, UnlockableIndex index)
		{
			writer.WritePackedIndex32((int)index);
		}

		public static UnlockableIndex ReadUnlockableIndex(this NetworkReader reader)
		{
			return (UnlockableIndex)reader.ReadPackedIndex32();
		}
	}
	public static class AchievementManager
	{
		private struct AchievementSortPair
		{
			public int score;

			public AchievementDef achievementDef;
		}

		public struct Enumerator : IEnumerator<AchievementDef>, IEnumerator, IDisposable
		{
			private int position;

			public AchievementDef Current => achievementDefs[position];

			object IEnumerator.Current => Current;

			public bool MoveNext()
			{
				position++;
				return position < achievementDefs.Length;
			}

			public void Reset()
			{
				position = -1;
			}

			void IDisposable.Dispose()
			{
			}
		}

		private static readonly Dictionary<LocalUser, UserAchievementManager> userToManagerMap = new Dictionary<LocalUser, UserAchievementManager>();

		public static ResourceAvailability availability;

		private static readonly Queue<Action> taskQueue = new Queue<Action>();

		private static readonly Dictionary<string, AchievementDef> achievementNamesToDefs = new Dictionary<string, AchievementDef>();

		private static readonly List<string> achievementIdentifiers = new List<string>();

		public static readonly ReadOnlyCollection<string> readOnlyAchievementIdentifiers = achievementIdentifiers.AsReadOnly();

		private static AchievementDef[] achievementDefs;

		private static AchievementDef[] serverAchievementDefs;

		public static readonly GenericStaticEnumerable<AchievementDef, Enumerator> allAchievementDefs;

		public static int achievementCount => achievementDefs.Length;

		public static int serverAchievementCount => serverAchievementDefs.Length;

		public static event Action onAchievementsRegistered;

		public static UserAchievementManager GetUserAchievementManager([NotNull] LocalUser user)
		{
			userToManagerMap.TryGetValue(user, out var value);
			return value;
		}

		public static IEnumerator DoInit()
		{
			yield return CollectAchievementDefs(achievementNamesToDefs);
			LocalUserManager.onUserSignIn += delegate(LocalUser localUser)
			{
				if (localUser.userProfile.canSave)
				{
					UserAchievementManager userAchievementManager = new UserAchievementManager();
					userAchievementManager.OnInstall(localUser);
					userToManagerMap[localUser] = userAchievementManager;
				}
			};
			LocalUserManager.onUserSignOut += delegate(LocalUser localUser)
			{
				if (userToManagerMap.TryGetValue(localUser, out var value))
				{
					value.OnUninstall();
					userToManagerMap.Remove(localUser);
				}
			};
			RoR2Application.onUpdate += delegate
			{
				foreach (KeyValuePair<LocalUser, UserAchievementManager> item in userToManagerMap)
				{
					item.Value.Update();
				}
			};
			availability.MakeAvailable();
		}

		public static void AddTask(Action action)
		{
			taskQueue.Enqueue(action);
		}

		public static void ProcessTasks()
		{
			while (taskQueue.Count > 0)
			{
				taskQueue.Dequeue()();
			}
		}

		public static AchievementDef GetAchievementDef(string achievementIdentifier)
		{
			if (achievementNamesToDefs.TryGetValue(achievementIdentifier, out var value))
			{
				return value;
			}
			return null;
		}

		public static AchievementDef GetAchievementDef(AchievementIndex index)
		{
			if (index.intValue >= 0 && index.intValue < achievementDefs.Length)
			{
				return achievementDefs[index.intValue];
			}
			return null;
		}

		public static AchievementDef GetAchievementDef(ServerAchievementIndex index)
		{
			if (index.intValue >= 0 && index.intValue < serverAchievementDefs.Length)
			{
				return serverAchievementDefs[index.intValue];
			}
			return null;
		}

		public static AchievementDef GetAchievementDefFromUnlockable(string unlockableRewardIdentifier)
		{
			for (int i = 0; i < achievementDefs.Length; i++)
			{
				if (achievementDefs[i].unlockableRewardIdentifier == unlockableRewardIdentifier)
				{
					return achievementDefs[i];
				}
			}
			return null;
		}

		public static IEnumerator CollectAchievementDefs(Dictionary<string, AchievementDef> map)
		{
			List<AchievementDef> achievementDefsList = new List<AchievementDef>();
			map.Clear();
			List<Assembly> list = new List<Assembly>();
			if (RoR2Application.isModded)
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly item in assemblies)
				{
					list.Add(item);
				}
			}
			else
			{
				list.Add(typeof(BaseAchievement).Assembly);
			}
			foreach (Assembly item2 in list)
			{
				Type[] types;
				try
				{
					types = item2.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					UnityEngine.Debug.LogError($"CollectAchievementDefs:  {ex}");
					types = ex.Types;
					if (types == null)
					{
						continue;
					}
				}
				catch (Exception arg)
				{
					UnityEngine.Debug.LogError($"CollectAchievementDefs:  {arg}");
					continue;
				}
				foreach (Type item3 in from type in types
					where type != null && type.IsSubclassOf(typeof(BaseAchievement))
					orderby type.Name
					select type)
				{
					RegisterAchievementAttribute registerAchievementAttribute = (RegisterAchievementAttribute)item3.GetCustomAttributes(inherit: false).FirstOrDefault((object v) => v is RegisterAchievementAttribute);
					if (registerAchievementAttribute != null)
					{
						if (map.ContainsKey(registerAchievementAttribute.identifier))
						{
							UnityEngine.Debug.LogErrorFormat("Class {0} attempted to register as achievement {1}, but class {2} has already registered as that achievement.", item3.FullName, registerAchievementAttribute.identifier, achievementNamesToDefs[registerAchievementAttribute.identifier].type.FullName);
							continue;
						}
						UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(registerAchievementAttribute.unlockableRewardIdentifier);
						AchievementDef achievementDef2 = new AchievementDef
						{
							identifier = registerAchievementAttribute.identifier,
							unlockableRewardIdentifier = registerAchievementAttribute.unlockableRewardIdentifier,
							prerequisiteAchievementIdentifier = registerAchievementAttribute.prerequisiteAchievementIdentifier,
							nameToken = "ACHIEVEMENT_" + registerAchievementAttribute.identifier.ToUpper(CultureInfo.InvariantCulture) + "_NAME",
							descriptionToken = "ACHIEVEMENT_" + registerAchievementAttribute.identifier.ToUpper(CultureInfo.InvariantCulture) + "_DESCRIPTION",
							type = item3,
							serverTrackerType = registerAchievementAttribute.serverTrackerType,
							lunarCoinReward = registerAchievementAttribute.lunarCoinReward
						};
						if ((bool)unlockableDef && (bool)unlockableDef.achievementIcon)
						{
							achievementDef2.SetAchievedIcon(unlockableDef.achievementIcon);
						}
						else
						{
							achievementDef2.iconPath = "Textures/AchievementIcons/tex" + registerAchievementAttribute.identifier + "Icon";
							achievementDef2.PreloadIcon();
						}
						achievementIdentifiers.Add(registerAchievementAttribute.identifier);
						map.Add(registerAchievementAttribute.identifier, achievementDef2);
						achievementDefsList.Add(achievementDef2);
						if (unlockableDef != null)
						{
							unlockableDef.getHowToUnlockString = () => Language.GetStringFormatted("UNLOCK_VIA_ACHIEVEMENT_FORMAT", Language.GetString(achievementDef2.nameToken), Language.GetString(achievementDef2.descriptionToken));
							unlockableDef.getUnlockedString = () => Language.GetStringFormatted("UNLOCKED_FORMAT", Language.GetString(achievementDef2.nameToken), Language.GetString(achievementDef2.descriptionToken));
						}
					}
					yield return null;
				}
			}
			achievementDefs = achievementDefsList.ToArray();
			SortAchievements(achievementDefs);
			serverAchievementDefs = achievementDefs.Where((AchievementDef achievementDef) => achievementDef.serverTrackerType != null).ToArray();
			for (int j = 0; j < achievementDefs.Length; j++)
			{
				achievementDefs[j].index = new AchievementIndex
				{
					intValue = j
				};
			}
			for (int k = 0; k < serverAchievementDefs.Length; k++)
			{
				serverAchievementDefs[k].serverIndex = new ServerAchievementIndex
				{
					intValue = k
				};
			}
			for (int l = 0; l < achievementIdentifiers.Count; l++)
			{
				string currentAchievementIdentifier = achievementIdentifiers[l];
				map[currentAchievementIdentifier].childAchievementIdentifiers = achievementIdentifiers.Where((string v) => map[v].prerequisiteAchievementIdentifier == currentAchievementIdentifier).ToArray();
			}
			AchievementManager.onAchievementsRegistered?.Invoke();
			yield return null;
		}

		private static void SortAchievements(AchievementDef[] achievementDefsArray)
		{
			AchievementSortPair[] array = new AchievementSortPair[achievementDefsArray.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new AchievementSortPair
				{
					score = UnlockableCatalog.GetUnlockableSortScore(achievementDefsArray[i].unlockableRewardIdentifier),
					achievementDef = achievementDefsArray[i]
				};
			}
			Array.Sort(array, (AchievementSortPair a, AchievementSortPair b) => a.score - b.score);
			for (int j = 0; j < array.Length; j++)
			{
				achievementDefsArray[j] = array[j].achievementDef;
			}
		}

		public static Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}
	}
	public class AchievementDef
	{
		public AchievementIndex index;

		public ServerAchievementIndex serverIndex = new ServerAchievementIndex
		{
			intValue = -1
		};

		public string identifier;

		public string unlockableRewardIdentifier;

		public string prerequisiteAchievementIdentifier;

		public string nameToken;

		public string descriptionToken;

		public string iconPath;

		public uint lunarCoinReward;

		public Type type;

		public Type serverTrackerType;

		private static readonly string[] emptyStringArray = Array.Empty<string>();

		public string[] childAchievementIdentifiers = emptyStringArray;

		private Sprite achievedIcon;

		private Sprite unachievedIcon;

		public void SetAchievedIcon(Sprite icon)
		{
			achievedIcon = icon;
		}

		public void PreloadIcon()
		{
			AsyncOperationHandle<Sprite> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Sprite>(iconPath);
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Sprite> x)
			{
				achievedIcon = x.Result;
				if (!achievedIcon)
				{
					AsyncOperationHandle<Sprite> asyncOperationHandle2 = LegacyResourcesAPI.LoadAsync<Sprite>("Textures/AchievementIcons/texPlaceholderAchievement");
					asyncOperationHandle2.Completed += delegate(AsyncOperationHandle<Sprite> handle)
					{
						achievedIcon = handle.Result;
					};
				}
			};
		}

		public string GetReward()
		{
			return lunarCoinReward.ToString();
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Sprite GetAchievedIcon()
		{
			if (!achievedIcon)
			{
				achievedIcon = LegacyResourcesAPI.Load<Sprite>(iconPath);
				if (!achievedIcon)
				{
					achievedIcon = LegacyResourcesAPI.Load<Sprite>("Textures/AchievementIcons/texPlaceholderAchievement");
				}
			}
			return achievedIcon;
		}

		public Sprite GetUnachievedIcon()
		{
			return LegacyResourcesAPI.Load<Sprite>("Textures/MiscIcons/texUnlockIcon");
		}

		public string GetAchievementSoundString()
		{
			if (unlockableRewardIdentifier.Contains("Characters."))
			{
				return "Play_UI_achievementUnlock_enhanced";
			}
			if (unlockableRewardIdentifier.Contains("Skills.") || unlockableRewardIdentifier.Contains("Skins."))
			{
				return "Play_UI_skill_unlock";
			}
			return "Play_UI_achievementUnlock";
		}
	}
	[MeansImplicitUse]
	public class RegisterAchievementAttribute : System.Attribute
	{
		public readonly string identifier;

		public readonly string unlockableRewardIdentifier;

		public readonly string prerequisiteAchievementIdentifier;

		public readonly uint lunarCoinReward;

		public readonly Type serverTrackerType;

		public RegisterAchievementAttribute([NotNull] string identifier, string unlockableRewardIdentifier, string prerequisiteAchievementIdentifier, uint lunarCoinReward, Type serverTrackerType = null)
		{
			this.identifier = identifier;
			this.unlockableRewardIdentifier = unlockableRewardIdentifier;
			this.prerequisiteAchievementIdentifier = prerequisiteAchievementIdentifier;
			this.lunarCoinReward = lunarCoinReward;
			this.serverTrackerType = serverTrackerType;
		}
	}
	public class UserAchievementManager
	{
		private readonly List<BaseAchievement> achievementsList = new List<BaseAchievement>();

		public LocalUser localUser;

		public UserProfile userProfile;

		public int dirtyGrantsCount;

		public int dirtyUpdatesCount;

		private readonly bool[] serverAchievementTrackingMask = new bool[AchievementManager.serverAchievementCount];

		private bool serverAchievementTrackingMaskDirty;

		public event Action<StatSheet> onUserProfileStatsUpdated;

		public event Action<StatSheet> onRunStatsUpdated;

		private void OnUserProfileStatsUpdated()
		{
			StatSheet statSheet = userProfile.statSheet;
			if (statSheet != null)
			{
				OnUserProfileStatsUpdated(statSheet);
			}
			PlayerStatsComponent cachedStatsComponent = localUser.cachedStatsComponent;
			if ((bool)cachedStatsComponent)
			{
				StatSheet currentStats = cachedStatsComponent.currentStats;
				if (currentStats != null)
				{
					OnRunStatsUpdated(currentStats);
				}
			}
		}

		private void OnUserProfileStatsUpdated([NotNull] StatSheet statSheet)
		{
			this.onUserProfileStatsUpdated?.Invoke(statSheet);
		}

		private void OnRunStatsUpdated([NotNull] StatSheet statSheet)
		{
			this.onRunStatsUpdated?.Invoke(statSheet);
		}

		public void SetServerAchievementTracked(ServerAchievementIndex serverAchievementIndex, bool shouldTrack)
		{
			if (serverAchievementTrackingMask[serverAchievementIndex.intValue] != shouldTrack)
			{
				serverAchievementTrackingMask[serverAchievementIndex.intValue] = shouldTrack;
				serverAchievementTrackingMaskDirty = true;
			}
		}

		public void TransmitAchievementRequestsToServer()
		{
			if ((bool)localUser.currentNetworkUser)
			{
				localUser.currentNetworkUser.GetComponent<ServerAchievementTracker>().SendAchievementTrackerRequestsMaskToServer(serverAchievementTrackingMask);
			}
		}

		public void Update()
		{
			if (serverAchievementTrackingMaskDirty)
			{
				serverAchievementTrackingMaskDirty = false;
				TransmitAchievementRequestsToServer();
			}
			int num = achievementsList.Count - 1;
			while (num >= 0 && dirtyGrantsCount > 0)
			{
				BaseAchievement baseAchievement = achievementsList[num];
				if (baseAchievement.shouldGrant)
				{
					dirtyGrantsCount--;
					achievementsList.RemoveAt(num);
					userProfile.AddAchievement(baseAchievement.achievementDef.identifier, isExternal: true);
					baseAchievement.OnGranted();
					baseAchievement.OnUninstall();
					NetworkUser currentNetworkUser = localUser.currentNetworkUser;
					if (currentNetworkUser != null)
					{
						currentNetworkUser.CallCmdReportAchievement(baseAchievement.achievementDef.nameToken);
					}
				}
				num--;
			}
		}

		public void GrantAchievement(AchievementDef achievementDef)
		{
			for (int i = 0; i < achievementsList.Count; i++)
			{
				if (achievementsList[i].achievementDef == achievementDef)
				{
					achievementsList[i].Grant();
				}
			}
		}

		public void HandleServerAchievementCompleted(ServerAchievementIndex serverAchievementIndex)
		{
			achievementsList.FirstOrDefault((BaseAchievement a) => a.achievementDef.serverIndex == serverAchievementIndex)?.Grant();
		}

		public void HandleServerTryToCompleteActivity(ServerAchievementIndex serverAchievementIndex)
		{
			achievementsList.FirstOrDefault((BaseAchievement a) => a.achievementDef.serverIndex == serverAchievementIndex)?.TryToCompleteActivity();
		}

		public float GetAchievementProgress(AchievementDef achievementDef)
		{
			return achievementsList.FirstOrDefault((BaseAchievement a) => a.achievementDef == achievementDef)?.ProgressForAchievement() ?? 1f;
		}

		public void OnInstall(LocalUser localUser)
		{
			this.localUser = localUser;
			userProfile = localUser.userProfile;
			UserProfile obj = userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(OnUserProfileStatsUpdated));
			foreach (string readOnlyAchievementIdentifier in AchievementManager.readOnlyAchievementIdentifiers)
			{
				AchievementDef achievementDef = AchievementManager.GetAchievementDef(readOnlyAchievementIdentifier);
				if (userProfile.HasAchievement(readOnlyAchievementIdentifier))
				{
					if (!userProfile.HasUnlockable(achievementDef.unlockableRewardIdentifier))
					{
						UnityEngine.Debug.LogFormat("UserProfile {0} has achievement {1} but not its unlockable {2}. Granting.", userProfile.name, achievementDef.nameToken, achievementDef.unlockableRewardIdentifier);
						userProfile.AddUnlockToken(achievementDef.unlockableRewardIdentifier);
					}
				}
				else
				{
					BaseAchievement baseAchievement = (BaseAchievement)Activator.CreateInstance(achievementDef.type);
					baseAchievement.achievementDef = achievementDef;
					baseAchievement.owner = this;
					achievementsList.Add(baseAchievement);
					baseAchievement.OnInstall();
				}
			}
		}

		public void OnUninstall()
		{
			for (int num = achievementsList.Count - 1; num >= 0; num--)
			{
				achievementsList[num].OnUninstall();
			}
			achievementsList.Clear();
			UserProfile obj = userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(OnUserProfileStatsUpdated));
			userProfile = null;
			localUser = null;
		}
	}
	public static class AnimationParameters
	{
		public static readonly int isMoving = Animator.StringToHash("isMoving");

		public static readonly int turnAngle = Animator.StringToHash("turnAngle");

		public static readonly int isGrounded = Animator.StringToHash("isGrounded");

		public static readonly int mainRootPlaybackRate = Animator.StringToHash("mainRootPlaybackRate");

		public static readonly int forwardSpeed = Animator.StringToHash("forwardSpeed");

		public static readonly int rightSpeed = Animator.StringToHash("rightSpeed");

		public static readonly int upSpeed = Animator.StringToHash("upSpeed");

		public static readonly int walkSpeed = Animator.StringToHash("walkSpeed");

		public static readonly int isSprinting = Animator.StringToHash("isSprinting");

		public static readonly int aimWeight = Animator.StringToHash("aimWeight");
	}
	[CreateAssetMenu(menuName = "RoR2/DropTables/ArenaMonsterItemDropTable")]
	public class ArenaMonsterItemDropTable : PickupDropTable
	{
		public ItemTag[] requiredItemTags;

		public ItemTag[] bannedItemTags;

		public float tier1Weight = 0.8f;

		public float tier2Weight = 0.2f;

		public float tier3Weight = 0.01f;

		public float bossWeight;

		public float lunarItemWeight;

		public float voidTier1Weight;

		public float voidTier2Weight;

		public float voidTier3Weight;

		public float voidBossWeight;

		private readonly WeightedSelection<PickupIndex> selector = new WeightedSelection<PickupIndex>();

		private bool PassesFilter(PickupIndex pickupIndex)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef.itemIndex != ItemIndex.None)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
				if (ArenaMissionController.instance.inventory.GetItemCount(itemDef.itemIndex) > 0)
				{
					return false;
				}
				ItemTag[] array = requiredItemTags;
				foreach (ItemTag value in array)
				{
					if (Array.IndexOf(itemDef.tags, value) == -1)
					{
						return false;
					}
				}
				array = bannedItemTags;
				foreach (ItemTag value2 in array)
				{
					if (Array.IndexOf(itemDef.tags, value2) != -1)
					{
						return false;
					}
				}
			}
			return true;
		}

		private void Add(List<PickupIndex> sourceDropList, float chance)
		{
			if (chance <= 0f || sourceDropList.Count == 0)
			{
				return;
			}
			foreach (PickupIndex sourceDrop in sourceDropList)
			{
				if (PassesFilter(sourceDrop))
				{
					selector.AddChoice(sourceDrop, chance);
				}
			}
		}

		private void GenerateWeightedSelection(Run run)
		{
			selector.Clear();
			Add(run.availableTier1DropList, tier1Weight);
			Add(run.availableTier2DropList, tier2Weight);
			Add(run.availableTier3DropList, tier3Weight);
			Add(run.availableBossDropList, bossWeight);
			Add(run.availableLunarItemDropList, lunarItemWeight);
			Add(run.availableVoidTier1DropList, voidTier1Weight);
			Add(run.availableVoidTier2DropList, voidTier2Weight);
			Add(run.availableVoidTier3DropList, voidTier3Weight);
			Add(run.availableVoidBossDropList, voidBossWeight);
		}

		protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng)
		{
			GenerateWeightedSelection(Run.instance);
			return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector);
		}

		public override int GetPickupCount()
		{
			return selector.Count;
		}

		protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector);
		}
	}
	public enum ArtifactIndex
	{
		None = -1
	}
	[Serializable]
	public struct ArtifactMask
	{
		[SerializeField]
		public ushort a;

		public static readonly ArtifactMask none;

		public static ArtifactMask all;

		public bool HasArtifact(ArtifactIndex artifactIndex)
		{
			if (artifactIndex < (ArtifactIndex)0 || (int)artifactIndex >= ArtifactCatalog.artifactCount)
			{
				return false;
			}
			return (a & (1 << (int)artifactIndex)) != 0;
		}

		public void AddArtifact(ArtifactIndex artifactIndex)
		{
			if (artifactIndex >= (ArtifactIndex)0 && (int)artifactIndex < ArtifactCatalog.artifactCount)
			{
				a |= (ushort)(1 << (int)artifactIndex);
			}
		}

		public void ToggleArtifact(ArtifactIndex artifactIndex)
		{
			if (artifactIndex >= (ArtifactIndex)0 && (int)artifactIndex < ArtifactCatalog.artifactCount)
			{
				a ^= (ushort)(1 << (int)artifactIndex);
			}
		}

		public void RemoveArtifact(ArtifactIndex artifactIndex)
		{
			if (artifactIndex >= (ArtifactIndex)0 && (int)artifactIndex < ArtifactCatalog.artifactCount)
			{
				a &= (ushort)(~(1 << (int)artifactIndex));
			}
		}

		public static ArtifactMask operator &(ArtifactMask mask1, ArtifactMask mask2)
		{
			ArtifactMask result = default(ArtifactMask);
			result.a = (ushort)(mask1.a & mask2.a);
			return result;
		}

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			all = default(ArtifactMask);
			for (ArtifactIndex artifactIndex = (ArtifactIndex)0; (int)artifactIndex < ArtifactCatalog.artifactCount; artifactIndex++)
			{
				all.AddArtifact(artifactIndex);
			}
		}
	}
	public static class ArtifactCatalog
	{
		private static ArtifactDef[] artifactDefs = Array.Empty<ArtifactDef>();

		public static ResourceAvailability availability;

		public static int artifactCount => artifactDefs.Length;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<ArtifactDef>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.ArtifactCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.artifactDefs);
			}
			remove
			{
			}
		}

		private static void RegisterArtifact(ArtifactIndex artifactIndex, ArtifactDef artifactDef)
		{
			artifactDefs[(int)artifactIndex] = artifactDef;
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetArtifactDefs(ContentManager.artifactDefs);
			availability.MakeAvailable();
		}

		private static void SetArtifactDefs([NotNull] ArtifactDef[] newArtifactDefs)
		{
			artifactDefs = ArrayUtils.Clone(newArtifactDefs);
			Array.Sort(artifactDefs, (ArtifactDef a, ArtifactDef b) => string.CompareOrdinal(a.cachedName, b.cachedName));
			for (int i = 0; i < artifactDefs.Length; i++)
			{
				artifactDefs[i].artifactIndex = (ArtifactIndex)i;
			}
		}

		public static ArtifactIndex FindArtifactIndex(string artifactName)
		{
			for (int i = 0; i < artifactDefs.Length; i++)
			{
				if (string.CompareOrdinal(artifactName, artifactDefs[i].cachedName) == 0)
				{
					return (ArtifactIndex)i;
				}
			}
			return ArtifactIndex.None;
		}

		public static ArtifactDef FindArtifactDef(string artifactName)
		{
			return GetArtifactDef(FindArtifactIndex(artifactName));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static ArtifactDef GetArtifactDef(ArtifactIndex artifactIndex)
		{
			ArtifactDef[] array = artifactDefs;
			ArtifactDef defaultValue = null;
			return ArrayUtils.GetSafe(array, (int)artifactIndex, in defaultValue);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/ArtifactCompoundDef")]
	public class ArtifactCompoundDef : ScriptableObject
	{
		public int value;

		public Material decalMaterial;

		public GameObject modelPrefab;
	}
	[CreateAssetMenu(menuName = "RoR2/ArtifactDef")]
	public class ArtifactDef : ScriptableObject
	{
		public string nameToken;

		public string descriptionToken;

		public UnlockableDef unlockableDef;

		public ExpansionDef requiredExpansion;

		public Sprite smallIconSelectedSprite;

		public Sprite smallIconDeselectedSprite;

		public GameObject extraUIDisplayPrefab;

		[FormerlySerializedAs("worldModelPrefab")]
		public GameObject pickupModelPrefab;

		private string _cachedName;

		public ArtifactIndex artifactIndex { get; set; }

		[Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)]
		public new string name
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public string cachedName
		{
			get
			{
				return _cachedName;
			}
			set
			{
				base.name = value;
				_cachedName = value;
			}
		}

		public static void AttemptGrant(ref PickupDef.GrantContext context)
		{
			ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(PickupCatalog.GetPickupDef(context.controller.pickupIndex).artifactIndex);
			Run.instance.GrantUnlockToAllParticipatingPlayers(artifactDef.unlockableDef);
			context.shouldNotify = true;
			context.shouldDestroy = true;
		}

		public virtual PickupDef CreatePickupDef()
		{
			PickupDef obj = new PickupDef
			{
				internalName = "ArtifactIndex." + cachedName,
				artifactIndex = artifactIndex,
				displayPrefab = pickupModelPrefab,
				nameToken = nameToken,
				baseColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Artifact)
			};
			obj.darkColor = obj.baseColor;
			obj.unlockableDef = unlockableDef;
			obj.interactContextToken = "ITEM_PICKUP_CONTEXT";
			obj.iconTexture = (smallIconSelectedSprite ? smallIconSelectedSprite.texture : null);
			obj.iconSprite = (smallIconSelectedSprite ? smallIconSelectedSprite : null);
			obj.attemptGrant = AttemptGrant;
			return obj;
		}

		private void Awake()
		{
			_cachedName = base.name;
		}

		private void OnValidate()
		{
			_cachedName = base.name;
		}
	}
	public enum AttackerFiltering
	{
		Default,
		AlwaysHit,
		NeverHitSelf,
		AlwaysHitSelf
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
	public class ConditionalHideAttribute : PropertyAttribute
	{
		public enum DisablingType
		{
			ReadOnly = 2,
			DontDraw
		}

		public string comparedPropertyName { get; private set; }

		public object comparedValue { get; private set; }

		public DisablingType disablingType { get; private set; }

		public ConditionalHideAttribute(string comparedPropertyName, object comparedValue, DisablingType disablingType = DisablingType.DontDraw)
		{
			this.comparedPropertyName = comparedPropertyName;
			this.comparedValue = comparedValue;
			this.disablingType = disablingType;
		}
	}
	public static class BackstabManager
	{
		private class BackstabVisualizer
		{
			private class IndicatorInfo
			{
				public GameObject gameObject;

				public Transform transform;

				public ParticleSystem particleSystem;

				public ParticleSystemRenderer renderer;

				public float lastDisplayTime;
			}

			private CameraRigController camera;

			public CharacterBody targetBody;

			private readonly Dictionary<CharacterBody, IndicatorInfo> bodyToIndicator = new Dictionary<CharacterBody, IndicatorInfo>();

			private static readonly Dictionary<CharacterBody, IndicatorInfo> buffer = new Dictionary<CharacterBody, IndicatorInfo>();

			private readonly Stack<IndicatorInfo> indicatorPool = new Stack<IndicatorInfo>();

			private static GameObject indicatorPrefab;

			public void Install(CameraRigController newCamera)
			{
				camera = newCamera;
				RoR2Application.onLateUpdate += UpdateIndicators;
			}

			public void Uninstall()
			{
				RoR2Application.onLateUpdate -= UpdateIndicators;
				camera = null;
				foreach (KeyValuePair<CharacterBody, IndicatorInfo> item in bodyToIndicator)
				{
					UnityEngine.Object.Destroy(item.Value.gameObject);
				}
				bodyToIndicator.Clear();
				foreach (IndicatorInfo item2 in indicatorPool)
				{
					UnityEngine.Object.Destroy(item2.gameObject);
				}
				indicatorPool.Clear();
			}

			[InitDuringStartup]
			private static void OnLoad()
			{
				LegacyResourcesAPI.LoadAsyncCallback("Prefabs/VFX/BackstabIndicator", delegate(GameObject operationResult)
				{
					indicatorPrefab = operationResult;
				});
			}

			private void UpdateIndicators()
			{
				UnityEngine.Vector3 corePosition = targetBody.corePosition;
				TeamIndex teamIndex = targetBody.teamComponent.teamIndex;
				buffer.Clear();
				float unscaledTime = Time.unscaledTime;
				foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
				{
					bool num = TeamManager.IsTeamEnemy(teamIndex, readOnlyInstances.teamComponent.teamIndex);
					bool flag = false;
					if (num)
					{
						flag = IsBackstab(readOnlyInstances.corePosition - corePosition, readOnlyInstances);
					}
					if (num && flag)
					{
						IndicatorInfo value = null;
						if (!bodyToIndicator.TryGetValue(readOnlyInstances, out value))
						{
							value = AddIndicator(readOnlyInstances);
						}
						value.lastDisplayTime = unscaledTime;
					}
				}
				List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
				foreach (KeyValuePair<CharacterBody, IndicatorInfo> item in bodyToIndicator)
				{
					if (item.Value.lastDisplayTime != unscaledTime)
					{
						list.Add(item.Key);
					}
				}
				foreach (CharacterBody item2 in list)
				{
					RemoveIndicator(item2);
				}
				list = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
			}

			private IndicatorInfo AddIndicator(CharacterBody victimBody)
			{
				IndicatorInfo indicatorInfo = null;
				if (indicatorPool.Count > 0)
				{
					indicatorInfo = indicatorPool.Pop();
				}
				else
				{
					indicatorInfo = new IndicatorInfo();
					indicatorInfo.gameObject = UnityEngine.Object.Instantiate(indicatorPrefab);
					indicatorInfo.transform = indicatorInfo.gameObject.transform;
					indicatorInfo.particleSystem = indicatorInfo.gameObject.GetComponent<ParticleSystem>();
					indicatorInfo.renderer = indicatorInfo.gameObject.GetComponent<ParticleSystemRenderer>();
					indicatorInfo.renderer.enabled = false;
				}
				indicatorInfo.gameObject.SetActive(value: true);
				indicatorInfo.particleSystem.Play();
				bodyToIndicator[victimBody] = indicatorInfo;
				return indicatorInfo;
			}

			private void RemoveIndicator(CharacterBody victimBody)
			{
				IndicatorInfo indicatorInfo = bodyToIndicator[victimBody];
				if ((bool)indicatorInfo.gameObject)
				{
					indicatorInfo.particleSystem.Stop();
					indicatorInfo.gameObject.SetActive(value: false);
				}
				bodyToIndicator.Remove(victimBody);
				indicatorPool.Push(indicatorInfo);
			}

			public void OnPreCull()
			{
				foreach (KeyValuePair<CharacterBody, IndicatorInfo> item in bodyToIndicator)
				{
					CharacterBody key = item.Key;
					Transform transform = item.Value.transform;
					if ((bool)key)
					{
						UnityEngine.Vector3? bodyForward = GetBodyForward(key);
						if (bodyForward.HasValue)
						{
							transform.forward = -bodyForward.Value;
						}
						transform.position = key.corePosition - transform.forward * key.radius;
						item.Value.renderer.enabled = true;
					}
				}
			}

			public void OnPostRender()
			{
				foreach (KeyValuePair<CharacterBody, IndicatorInfo> item in bodyToIndicator)
				{
					item.Value.renderer.enabled = false;
				}
			}

			private void Update()
			{
				UpdateIndicators();
			}
		}

		public static GameObject backstabImpactEffectPrefab = null;

		private static readonly bool enableVisualizerSystem = false;

		private static readonly float showBackstabThreshold = Mathf.Cos(MathF.PI / 4f);

		private static readonly Dictionary<CameraRigController, BackstabVisualizer> camToVisualizer = new Dictionary<CameraRigController, BackstabVisualizer>();

		public static bool IsBackstab(UnityEngine.Vector3 attackerCorePositionToHitPosition, CharacterBody victimBody)
		{
			if (!victimBody.canReceiveBackstab)
			{
				return false;
			}
			UnityEngine.Vector3? bodyForward = GetBodyForward(victimBody);
			if (bodyForward.HasValue)
			{
				return UnityEngine.Vector3.Dot(attackerCorePositionToHitPosition, bodyForward.Value) > 0f;
			}
			return false;
		}

		private static UnityEngine.Vector3? GetBodyForward(CharacterBody characterBody)
		{
			UnityEngine.Vector3? vector = null;
			return (!characterBody.characterDirection) ? new UnityEngine.Vector3?(characterBody.transform.forward) : new UnityEngine.Vector3?(characterBody.characterDirection.forward);
		}

		[InitDuringStartup]
		private static void Init()
		{
			if (enableVisualizerSystem)
			{
				InitVisualizerSystem();
			}
			LegacyResourcesAPI.LoadAsyncCallback("Effects/ImpactEffects/BackstabSpark", delegate(GameObject operationResult)
			{
				backstabImpactEffectPrefab = operationResult;
			});
		}

		private static bool ShouldShowBackstab(UnityEngine.Vector3 attackerCorePosition, CharacterBody victimBody)
		{
			if (!victimBody.canReceiveBackstab)
			{
				return false;
			}
			UnityEngine.Vector3? bodyForward = GetBodyForward(victimBody);
			if (bodyForward.HasValue)
			{
				return UnityEngine.Vector3.Dot((attackerCorePosition - victimBody.corePosition).normalized, bodyForward.Value) > showBackstabThreshold;
			}
			return false;
		}

		private static void InitVisualizerSystem()
		{
			CameraRigController.onCameraTargetChanged += OnCameraTargetChanged;
			CameraRigController.onCameraEnableGlobal += OnCameraDiscovered;
			CameraRigController.onCameraDisableGlobal += OnCameraLost;
			SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull;
			SceneCamera.onSceneCameraPostRender += OnSceneCameraPostRender;
		}

		private static void OnCameraTargetChanged(CameraRigController camera, GameObject target)
		{
			RefreshCamera(camera);
		}

		private static void OnCameraDiscovered(CameraRigController camera)
		{
			RefreshCamera(camera);
		}

		private static void OnCameraLost(CameraRigController camera)
		{
			RefreshCamera(camera);
		}

		private static void OnSceneCameraPreCull(SceneCamera sceneCam)
		{
			if (camToVisualizer.TryGetValue(sceneCam.cameraRigController, out var value))
			{
				value.OnPreCull();
			}
		}

		private static void OnSceneCameraPostRender(SceneCamera sceneCam)
		{
			if (camToVisualizer.TryGetValue(sceneCam.cameraRigController, out var value))
			{
				value.OnPostRender();
			}
		}

		private static void RefreshCamera(CameraRigController camera)
		{
			BackstabVisualizer value;
			bool num = camToVisualizer.TryGetValue(camera, out value);
			GameObject gameObject = (camera.isActiveAndEnabled ? camera.target : null);
			CharacterBody characterBody = (gameObject ? gameObject.GetComponent<CharacterBody>() : null);
			bool flag = (bool)characterBody && characterBody.canPerformBackstab;
			if (num != flag)
			{
				if (flag)
				{
					value = new BackstabVisualizer();
					camToVisualizer.Add(camera, value);
					value.Install(camera);
				}
				else
				{
					value.Uninstall();
					camToVisualizer.Remove(camera);
					value = null;
				}
			}
			if (value != null)
			{
				value.targetBody = characterBody;
			}
		}
	}
	public static class BadClientEntityStateMachineFix
	{
		private class Watcher
		{
			public LocalUser localUser;

			private TimerQueue.TimerHandle? currentTimerHandle;

			public void OnInstall()
			{
				localUser.onBodyChanged += OnBodyChanged;
			}

			public void OnUninstall()
			{
				localUser.onBodyChanged -= OnBodyChanged;
				if (currentTimerHandle.HasValue)
				{
					RoR2Application.fixedTimeTimers.RemoveTimer(currentTimerHandle.Value);
					currentTimerHandle = null;
				}
			}

			private void OnBodyChanged()
			{
				if (currentTimerHandle.HasValue)
				{
					RoR2Application.fixedTimeTimers.RemoveTimer(currentTimerHandle.Value);
					currentTimerHandle = null;
				}
				if ((bool)localUser.cachedBody)
				{
					currentTimerHandle = RoR2Application.fixedTimeTimers.CreateTimer(1f, OnTimer);
				}
			}

			private void OnTimer()
			{
				currentTimerHandle = null;
				ForceInitializeEntityStateMachines(localUser.cachedBody);
			}

			private static void ForceInitializeEntityStateMachines(CharacterBody characterBody)
			{
				if (!characterBody)
				{
					return;
				}
				EntityStateMachine[] components = characterBody.GetComponents<EntityStateMachine>();
				for (int i = 0; i < components.Length; i++)
				{
					EntityStateMachine entityStateMachine = components[i];
					if (!entityStateMachine.HasPendingState() && entityStateMachine.state is Uninitialized)
					{
						EntityState entityState = EntityStateCatalog.InstantiateState(ref entityStateMachine.mainStateType);
						if (entityState != null)
						{
							UnityEngine.Debug.LogFormat("Setting {0} uninitialized state machine [{1}] next state to {2}", characterBody.name, i, entityState.GetType().Name);
							entityStateMachine.SetInterruptState(entityState, InterruptPriority.Any);
						}
					}
				}
			}
		}

		private static readonly Dictionary<LocalUser, Watcher> watchers = new Dictionary<LocalUser, Watcher>();

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			LocalUserManager.onUserSignIn += OnUserSignIn;
			LocalUserManager.onUserSignOut += OnUserSignOut;
		}

		private static void OnUserSignIn(LocalUser localUser)
		{
			Watcher watcher = new Watcher
			{
				localUser = localUser
			};
			watchers[localUser] = watcher;
			watcher.OnInstall();
		}

		private static void OnUserSignOut(LocalUser localUser)
		{
			Watcher watcher = watchers[localUser];
			watcher.OnUninstall();
			watcher.localUser = null;
			watchers.Remove(localUser);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/DropTables/BasicPickupDropTable")]
	public class BasicPickupDropTable : PickupDropTable
	{
		public ItemTag[] requiredItemTags = Array.Empty<ItemTag>();

		public ItemTag[] bannedItemTags = Array.Empty<ItemTag>();

		public float tier1Weight = 0.8f;

		public float tier2Weight = 0.2f;

		public float tier3Weight = 0.01f;

		public float bossWeight;

		public float lunarEquipmentWeight;

		public float lunarItemWeight;

		public float lunarCombinedWeight;

		public float equipmentWeight;

		public float voidTier1Weight;

		public float voidTier2Weight;

		public float voidTier3Weight;

		public float voidBossWeight;

		private readonly WeightedSelection<PickupIndex> selector = new WeightedSelection<PickupIndex>();

		protected override void Regenerate(Run run)
		{
			GenerateWeightedSelection(run);
		}

		public void RegenerateDropTable(Run run)
		{
			GenerateWeightedSelection(run);
		}

		public bool IsFilterRequired()
		{
			if (requiredItemTags.Length == 0)
			{
				return bannedItemTags.Length != 0;
			}
			return true;
		}

		public bool PassesFilter(PickupIndex pickupIndex)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef.itemIndex != ItemIndex.None)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
				ItemTag[] array = requiredItemTags;
				foreach (ItemTag value in array)
				{
					if (Array.IndexOf(itemDef.tags, value) == -1)
					{
						return false;
					}
				}
				array = bannedItemTags;
				foreach (ItemTag value2 in array)
				{
					if (Array.IndexOf(itemDef.tags, value2) != -1)
					{
						return false;
					}
				}
			}
			return true;
		}

		private void Add(List<PickupIndex> sourceDropList, float chance)
		{
			if (chance <= 0f || sourceDropList.Count == 0)
			{
				return;
			}
			foreach (PickupIndex sourceDrop in sourceDropList)
			{
				if (!IsFilterRequired() || PassesFilter(sourceDrop))
				{
					selector.AddChoice(sourceDrop, chance);
				}
			}
		}

		private void GenerateWeightedSelection(Run run)
		{
			selector.Clear();
			Add(run.availableTier1DropList, tier1Weight);
			Add(run.availableTier2DropList, tier2Weight);
			Add(run.availableTier3DropList, tier3Weight);
			Add(run.availableBossDropList, bossWeight);
			Add(run.availableLunarItemDropList, lunarItemWeight);
			Add(run.availableLunarEquipmentDropList, lunarEquipmentWeight);
			Add(run.availableLunarCombinedDropList, lunarCombinedWeight);
			Add(run.availableEquipmentDropList, equipmentWeight);
			Add(run.availableVoidTier1DropList, voidTier1Weight);
			Add(run.availableVoidTier2DropList, voidTier2Weight);
			Add(run.availableVoidTier3DropList, voidTier3Weight);
			Add(run.availableVoidBossDropList, voidBossWeight);
		}

		protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector);
		}

		public override int GetPickupCount()
		{
			return selector.Count;
		}

		protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector);
		}
	}
	public class BlastAttack
	{
		public enum FalloffModel
		{
			None,
			Linear,
			SweetSpot
		}

		public enum LoSType
		{
			None,
			NearestHit
		}

		public struct HitPoint
		{
			public HurtBox hurtBox;

			public UnityEngine.Vector3 hitPosition;

			public UnityEngine.Vector3 hitNormal;

			public float distanceSqr;
		}

		public struct Result
		{
			public int hitCount;

			public HitPoint[] hitPoints;
		}

		private struct BlastAttackDamageInfo
		{
			public GameObject attacker;

			public GameObject inflictor;

			public bool crit;

			public float damage;

			public DamageColorIndex damageColorIndex;

			public HurtBox.DamageModifier damageModifier;

			public DamageTypeCombo damageType;

			public UnityEngine.Vector3 force;

			public UnityEngine.Vector3 position;

			public ProcChainMask procChainMask;

			public float procCoefficient;

			public HealthComponent hitHealthComponent;

			public bool canRejectForce;

			public void Write(NetworkWriter writer)
			{
				writer.Write(attacker);
				writer.Write(inflictor);
				writer.Write(crit);
				writer.Write(damage);
				writer.Write(damageColorIndex);
				writer.Write((byte)damageModifier);
				writer.WriteDamageType(damageType);
				writer.Write(force);
				writer.Write(position);
				writer.Write(procChainMask);
				writer.Write(procCoefficient);
				writer.Write(hitHealthComponent.netId);
				writer.Write(canRejectForce);
			}

			public void Read(NetworkReader reader)
			{
				attacker = reader.ReadGameObject();
				inflictor = reader.ReadGameObject();
				crit = reader.ReadBoolean();
				damage = reader.ReadSingle();
				damageColorIndex = reader.ReadDamageColorIndex();
				damageModifier = (HurtBox.DamageModifier)reader.ReadByte();
				damageType = reader.ReadDamageType();
				force = reader.ReadVector3();
				position = reader.ReadVector3();
				procChainMask = reader.ReadProcChainMask();
				procCoefficient = reader.ReadSingle();
				GameObject gameObject = reader.ReadGameObject();
				hitHealthComponent = (gameObject ? gameObject.GetComponent<HealthComponent>() : null);
				canRejectForce = reader.ReadBoolean();
			}
		}

		public GameObject attacker;

		public GameObject inflictor;

		public TeamIndex teamIndex;

		public AttackerFiltering attackerFiltering;

		public UnityEngine.Vector3 position;

		public float radius;

		public FalloffModel falloffModel = FalloffModel.Linear;

		public float baseDamage;

		public float baseForce;

		public UnityEngine.Vector3 bonusForce;

		public bool crit;

		public DamageTypeCombo damageType = DamageType.Generic;

		public DamageColorIndex damageColorIndex;

		public LoSType losType;

		public EffectIndex impactEffect = EffectIndex.Invalid;

		public bool canRejectForce = true;

		public ProcChainMask procChainMask;

		public float procCoefficient = 1f;

		private static readonly int initialBufferSize = 256;

		private static HitPoint[] hitPointsBuffer = new HitPoint[initialBufferSize];

		private static int[] hitOrderBuffer = new int[initialBufferSize];

		private static HealthComponent[] encounteredHealthComponentsBuffer = new HealthComponent[initialBufferSize];

		public static event Action<HitPoint[], GameObject> BlastAttackMultiHit;

		public Result Fire()
		{
			HitPoint[] array = CollectHits();
			HandleHits(array);
			Result result = default(Result);
			result.hitCount = array.Length;
			result.hitPoints = array;
			return result;
		}

		[NetworkMessageHandler(msgType = 75, client = false, server = true)]
		private static void HandleReportBlastAttackDamage(NetworkMessage netMsg)
		{
			NetworkReader reader = netMsg.reader;
			BlastAttackDamageInfo blastAttackDamageInfo = default(BlastAttackDamageInfo);
			blastAttackDamageInfo.Read(reader);
			PerformDamageServer(in blastAttackDamageInfo);
		}

		public void Reset()
		{
			attacker = null;
			inflictor = null;
			teamIndex = TeamIndex.Neutral;
			position = UnityEngine.Vector3.zero;
			radius = 0f;
			falloffModel = FalloffModel.Linear;
			baseDamage = 0f;
			baseForce = 0f;
			bonusForce = UnityEngine.Vector3.zero;
			crit = false;
			damageType = DamageType.Generic;
			damageColorIndex = DamageColorIndex.Default;
			procChainMask.mask = 0u;
			procCoefficient = 1f;
			canRejectForce = true;
		}

		private HitPoint[] CollectHits()
		{
			UnityEngine.Vector3 vector = position;
			Collider[] array = Physics.OverlapSphere(vector, radius, LayerIndex.entityPrecise.mask);
			int num = array.Length;
			int count = 0;
			int encounteredHealthComponentsLength = 0;
			int hitOrderBufferLength = 0;
			ArrayUtils.EnsureCapacity(ref hitPointsBuffer, num);
			ArrayUtils.EnsureCapacity(ref hitOrderBuffer, num);
			ArrayUtils.EnsureCapacity(ref encounteredHealthComponentsBuffer, num);
			for (int i = 0; i < num; i++)
			{
				Collider collider = array[i];
				HurtBox component = collider.GetComponent<HurtBox>();
				if (!component)
				{
					continue;
				}
				HealthComponent healthComponent2 = component.healthComponent;
				if (!healthComponent2)
				{
					continue;
				}
				bool flag = true;
				switch (attackerFiltering)
				{
				case AttackerFiltering.Default:
					flag = true;
					break;
				case AttackerFiltering.AlwaysHitSelf:
					flag = true;
					if (healthComponent2.gameObject == attacker)
					{
						flag = false;
					}
					break;
				case AttackerFiltering.AlwaysHit:
					flag = false;
					break;
				case AttackerFiltering.NeverHitSelf:
					flag = true;
					if (healthComponent2.gameObject == attacker)
					{
						continue;
					}
					break;
				}
				if (!flag || FriendlyFireManager.ShouldSplashHitProceed(healthComponent2, teamIndex))
				{
					UnityEngine.Vector3 vector2 = collider.transform.position;
					UnityEngine.Vector3 hitNormal = vector - vector2;
					float sqrMagnitude = hitNormal.sqrMagnitude;
					hitPointsBuffer[count++] = new HitPoint
					{
						hurtBox = component,
						hitPosition = vector2,
						hitNormal = hitNormal,
						distanceSqr = sqrMagnitude
					};
				}
			}
			if (true)
			{
				for (int j = 0; j < count; j++)
				{
					ref HitPoint reference = ref hitPointsBuffer[j];
					if ((object)reference.hurtBox != null && reference.distanceSqr > 0f && reference.hurtBox.collider.Raycast(new Ray(vector, -reference.hitNormal), out var hitInfo, radius))
					{
						reference.distanceSqr = (vector - hitInfo.point).sqrMagnitude;
						reference.hitPosition = hitInfo.point;
						reference.hitNormal = hitInfo.normal;
					}
				}
			}
			hitOrderBufferLength = count;
			for (int k = 0; k < count; k++)
			{
				hitOrderBuffer[k] = k;
			}
			for (int l = 1; l < count; l++)
			{
				int num2 = l;
				while (num2 > 0 && hitPointsBuffer[hitOrderBuffer[num2 - 1]].distanceSqr > hitPointsBuffer[hitOrderBuffer[num2]].distanceSqr)
				{
					int num3 = hitOrderBuffer[num2 - 1];
					hitOrderBuffer[num2 - 1] = hitOrderBuffer[num2];
					hitOrderBuffer[num2] = num3;
					num2--;
				}
			}
			bool flag2 = losType == LoSType.None || losType == LoSType.NearestHit;
			for (int m = 0; m < hitOrderBufferLength; m++)
			{
				int num4 = hitOrderBuffer[m];
				ref HitPoint reference2 = ref hitPointsBuffer[num4];
				HealthComponent healthComponent3 = reference2.hurtBox.healthComponent;
				if (!EntityIsMarkedEncountered(healthComponent3))
				{
					MarkEntityAsEncountered(healthComponent3);
				}
				else if (flag2)
				{
					reference2.hurtBox = null;
				}
			}
			ClearEncounteredEntities();
			CondenseHitOrderBuffer();
			LoSType loSType = losType;
			if (loSType != 0 && loSType == LoSType.NearestHit)
			{
				NativeArray<RaycastCommand> commands = new NativeArray<RaycastCommand>(hitOrderBufferLength, Allocator.TempJob);
				NativeArray<RaycastHit> results = new NativeArray<RaycastHit>(hitOrderBufferLength, Allocator.TempJob);
				int n = 0;
				int num5 = 0;
				for (; n < hitOrderBufferLength; n++)
				{
					int num6 = hitOrderBuffer[n];
					ref HitPoint reference3 = ref hitPointsBuffer[num6];
					commands[num5++] = new RaycastCommand(vector, reference3.hitPosition - vector, Mathf.Sqrt(reference3.distanceSqr), LayerIndex.world.mask);
				}
				bool queriesHitTriggers = Physics.queriesHitTriggers;
				Physics.queriesHitTriggers = true;
				RaycastCommand.ScheduleBatch(commands, results, 1).Complete();
				Physics.queriesHitTriggers = queriesHitTriggers;
				int num7 = 0;
				int num8 = 0;
				for (; num7 < hitOrderBufferLength; num7++)
				{
					int num9 = hitOrderBuffer[num7];
					ref HitPoint reference4 = ref hitPointsBuffer[num9];
					if ((object)reference4.hurtBox != null && (bool)results[num8++].collider)
					{
						reference4.hurtBox = null;
					}
				}
				results.Dispose();
				commands.Dispose();
				CondenseHitOrderBuffer();
			}
			HitPoint[] array2 = new HitPoint[hitOrderBufferLength];
			for (int num10 = 0; num10 < hitOrderBufferLength; num10++)
			{
				int num11 = hitOrderBuffer[num10];
				array2[num10] = hitPointsBuffer[num11];
			}
			ArrayUtils.Clear(hitPointsBuffer, ref count);
			ClearEncounteredEntities();
			return array2;
			void ClearEncounteredEntities()
			{
				Array.Clear(encounteredHealthComponentsBuffer, 0, encounteredHealthComponentsLength);
				encounteredHealthComponentsLength = 0;
			}
			void CondenseHitOrderBuffer()
			{
				for (int num12 = 0; num12 < hitOrderBufferLength; num12++)
				{
					int num13 = 0;
					for (int num14 = num12; num14 < hitOrderBufferLength; num14++)
					{
						int num15 = hitOrderBuffer[num14];
						if ((object)hitPointsBuffer[num15].hurtBox != null)
						{
							break;
						}
						num13++;
					}
					if (num13 > 0)
					{
						ArrayUtils.ArrayRemoveAt(hitOrderBuffer, ref hitOrderBufferLength, num12, num13);
					}
				}
			}
			bool EntityIsMarkedEncountered(HealthComponent healthComponent)
			{
				for (int num16 = 0; num16 < encounteredHealthComponentsLength; num16++)
				{
					if ((object)encounteredHealthComponentsBuffer[num16] == healthComponent)
					{
						return true;
					}
				}
				return false;
			}
			void MarkEntityAsEncountered(HealthComponent healthComponent)
			{
				encounteredHealthComponentsBuffer[encounteredHealthComponentsLength++] = healthComponent;
			}
		}

		private void HandleHits(HitPoint[] hitPoints)
		{
			UnityEngine.Vector3 vector = position;
			for (int i = 0; i < hitPoints.Length; i++)
			{
				HitPoint hitPoint = hitPoints[i];
				float num = Mathf.Sqrt(hitPoint.distanceSqr);
				float num2 = 0f;
				UnityEngine.Vector3 vector2 = ((num > 0f) ? ((hitPoint.hitPosition - vector) / num) : UnityEngine.Vector3.zero);
				HealthComponent healthComponent = (hitPoint.hurtBox ? hitPoint.hurtBox.healthComponent : null);
				if ((bool)healthComponent)
				{
					switch (falloffModel)
					{
					case FalloffModel.None:
						num2 = 1f;
						break;
					case FalloffModel.Linear:
						num2 = 1f - Mathf.Clamp01(num / radius);
						break;
					case FalloffModel.SweetSpot:
						num2 = 1f - ((num > radius / 2f) ? 0.75f : 0f);
						break;
					}
					BlastAttackDamageInfo blastAttackDamageInfo = default(BlastAttackDamageInfo);
					blastAttackDamageInfo.attacker = attacker;
					blastAttackDamageInfo.inflictor = inflictor;
					blastAttackDamageInfo.crit = crit;
					blastAttackDamageInfo.damage = baseDamage * num2;
					blastAttackDamageInfo.damageColorIndex = damageColorIndex;
					blastAttackDamageInfo.damageModifier = hitPoint.hurtBox.damageModifier;
					blastAttackDamageInfo.damageType = damageType | DamageType.AOE;
					blastAttackDamageInfo.force = bonusForce * num2 + baseForce * num2 * vector2;
					blastAttackDamageInfo.position = hitPoint.hitPosition;
					blastAttackDamageInfo.procChainMask = procChainMask;
					blastAttackDamageInfo.procCoefficient = procCoefficient;
					blastAttackDamageInfo.hitHealthComponent = healthComponent;
					blastAttackDamageInfo.canRejectForce = canRejectForce;
					BlastAttackDamageInfo blastAttackDamageInfo2 = blastAttackDamageInfo;
					if (NetworkServer.active)
					{
						PerformDamageServer(in blastAttackDamageInfo2);
					}
					else
					{
						ClientReportDamage(in blastAttackDamageInfo2);
					}
					if (impactEffect != EffectIndex.Invalid)
					{
						EffectData effectData = new EffectData();
						effectData.origin = hitPoint.hitPosition;
						effectData.rotation = UnityEngine.Quaternion.LookRotation(-vector2);
						EffectManager.SpawnEffect(impactEffect, effectData, transmit: true);
					}
				}
			}
			BlastAttack.BlastAttackMultiHit?.Invoke(hitPoints, attacker);
		}

		private static void ClientReportDamage(in BlastAttackDamageInfo blastAttackDamageInfo)
		{
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.StartMessage(75);
			blastAttackDamageInfo.Write(networkWriter);
			networkWriter.FinishMessage();
			PlatformSystems.networkManager.client.connection.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
		}

		private static void PerformDamageServer(in BlastAttackDamageInfo blastAttackDamageInfo)
		{
			if ((bool)blastAttackDamageInfo.hitHealthComponent)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.attacker = blastAttackDamageInfo.attacker;
				damageInfo.inflictor = blastAttackDamageInfo.inflictor;
				damageInfo.damage = blastAttackDamageInfo.damage;
				damageInfo.crit = blastAttackDamageInfo.crit;
				damageInfo.force = blastAttackDamageInfo.force;
				damageInfo.procChainMask = blastAttackDamageInfo.procChainMask;
				damageInfo.procCoefficient = blastAttackDamageInfo.procCoefficient;
				damageInfo.damageType = blastAttackDamageInfo.damageType;
				damageInfo.damageColorIndex = blastAttackDamageInfo.damageColorIndex;
				damageInfo.position = blastAttackDamageInfo.position;
				damageInfo.canRejectForce = blastAttackDamageInfo.canRejectForce;
				damageInfo.ModifyDamageInfo(blastAttackDamageInfo.damageModifier);
				blastAttackDamageInfo.hitHealthComponent.TakeDamage(damageInfo);
				GlobalEventManager.instance.OnHitEnemy(damageInfo, blastAttackDamageInfo.hitHealthComponent.gameObject);
				GlobalEventManager.instance.OnHitAll(damageInfo, blastAttackDamageInfo.hitHealthComponent.gameObject);
			}
		}
	}
	public class DustStreakManager : MonoBehaviour
	{
		public GameObject dustStreakPrefab;

		public float timeBetweenStreaksMin;

		public float timeBetweenStreaksMax;

		private float streakTimer;

		public List<Transform> dustStreakLocations = new List<Transform>();

		private int streakNum;

		private bool startDustStreaks;

		private void Start()
		{
			streakTimer = UnityEngine.Random.Range(timeBetweenStreaksMin, timeBetweenStreaksMax);
			startDustStreaks = true;
		}

		private void FixedUpdate()
		{
			if (startDustStreaks)
			{
				streakTimer -= Time.deltaTime;
				if (streakTimer <= 0f)
				{
					streakTimer = UnityEngine.Random.Range(timeBetweenStreaksMin, timeBetweenStreaksMax);
					streakNum = UnityEngine.Random.Range(0, dustStreakLocations.Count);
					EffectManager.SimpleEffect(dustStreakPrefab, dustStreakLocations[streakNum].position, dustStreakPrefab.transform.rotation, transmit: true);
				}
			}
		}
	}
	public class NoGravZone : MonoBehaviour
	{
		public void OnTriggerEnter(Collider other)
		{
			ICharacterGravityParameterProvider component = other.GetComponent<ICharacterGravityParameterProvider>();
			if (component != null)
			{
				CharacterGravityParameters gravityParameters = component.gravityParameters;
				gravityParameters.environmentalAntiGravityGranterCount++;
				component.gravityParameters = gravityParameters;
			}
			ICharacterFlightParameterProvider component2 = other.GetComponent<ICharacterFlightParameterProvider>();
			if (component2 != null)
			{
				CharacterFlightParameters flightParameters = component2.flightParameters;
				flightParameters.channeledFlightGranterCount++;
				component2.flightParameters = flightParameters;
			}
		}

		public void OnTriggerExit(Collider other)
		{
			ICharacterFlightParameterProvider component = other.GetComponent<ICharacterFlightParameterProvider>();
			if (component != null)
			{
				CharacterFlightParameters flightParameters = component.flightParameters;
				flightParameters.channeledFlightGranterCount--;
				component.flightParameters = flightParameters;
			}
			ICharacterGravityParameterProvider component2 = other.GetComponent<ICharacterGravityParameterProvider>();
			if (component2 != null)
			{
				CharacterGravityParameters gravityParameters = component2.gravityParameters;
				gravityParameters.environmentalAntiGravityGranterCount--;
				component2.gravityParameters = gravityParameters;
			}
		}
	}
	public enum BodyIndex
	{
		None = -1
	}
	public static class BodyCatalog
	{
		public static class SpecialCases
		{
			private static BodyIndex chief = BodyIndex.None;

			private static BodyIndex railgunner = BodyIndex.None;

			private static BodyIndex heretic = BodyIndex.None;

			public static BodyIndex Chief()
			{
				if (chief == BodyIndex.None)
				{
					chief = FindBodyIndex("ChefBody");
				}
				return chief;
			}

			public static BodyIndex RailGunner()
			{
				if (railgunner == BodyIndex.None)
				{
					railgunner = FindBodyIndex("RailgunnerBody");
				}
				return railgunner;
			}

			public static BodyIndex HereticBody()
			{
				if (heretic == BodyIndex.None)
				{
					heretic = FindBodyIndex("HereticBody");
				}
				return heretic;
			}
		}

		public static ResourceAvailability availability = default(ResourceAvailability);

		private static string[] bodyNames;

		private static GameObject[] bodyPrefabs;

		private static CharacterBody[] bodyPrefabBodyComponents;

		private static Component[][] bodyComponents;

		private static GenericSkill[][] skillSlots;

		private static SkinDef[][] skins;

		private static readonly Dictionary<string, BodyIndex> nameToIndexMap = new Dictionary<string, BodyIndex>();

		private static Texture2D defaultPortraitIcon;

		public static int bodyCount { get; private set; }

		public static IEnumerable<GameObject> allBodyPrefabs => bodyPrefabs;

		public static IEnumerable<CharacterBody> allBodyPrefabBodyBodyComponents => bodyPrefabBodyComponents;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<GameObject>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.BodyCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.bodyPrefabs);
			}
			remove
			{
			}
		}

		public static GameObject GetBodyPrefab(BodyIndex bodyIndex)
		{
			return ArrayUtils.GetSafe(bodyPrefabs, (int)bodyIndex);
		}

		[CanBeNull]
		public static CharacterBody GetBodyPrefabBodyComponent(BodyIndex bodyIndex)
		{
			return ArrayUtils.GetSafe(bodyPrefabBodyComponents, (int)bodyIndex);
		}

		public static string GetBodyName(BodyIndex bodyIndex)
		{
			return ArrayUtils.GetSafe(bodyNames, (int)bodyIndex);
		}

		public static BodyIndex FindBodyIndex([NotNull] string bodyName)
		{
			if (nameToIndexMap.TryGetValue(bodyName, out var value))
			{
				return value;
			}
			return BodyIndex.None;
		}

		public static BodyIndex FindBodyIndexCaseInsensitive([NotNull] string bodyName)
		{
			for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < bodyPrefabs.Length; bodyIndex++)
			{
				if (string.Compare(bodyPrefabs[(int)bodyIndex].name, bodyName, StringComparison.OrdinalIgnoreCase) == 0)
				{
					return bodyIndex;
				}
			}
			return BodyIndex.None;
		}

		public static BodyIndex FindBodyIndex(GameObject bodyObject)
		{
			return FindBodyIndex(bodyObject ? bodyObject.GetComponent<CharacterBody>() : null);
		}

		public static BodyIndex FindBodyIndex(CharacterBody characterBody)
		{
			return characterBody?.bodyIndex ?? BodyIndex.None;
		}

		[CanBeNull]
		public static GameObject FindBodyPrefab([NotNull] string bodyName)
		{
			BodyIndex bodyIndex = FindBodyIndex(bodyName);
			if (bodyIndex != BodyIndex.None)
			{
				return GetBodyPrefab(bodyIndex);
			}
			return null;
		}

		[CanBeNull]
		public static GameObject FindBodyPrefab(CharacterBody characterBody)
		{
			return GetBodyPrefab(FindBodyIndex(characterBody));
		}

		[CanBeNull]
		public static GameObject FindBodyPrefab(GameObject characterBodyObject)
		{
			return GetBodyPrefab(FindBodyIndex(characterBodyObject));
		}

		[CanBeNull]
		public static GenericSkill[] GetBodyPrefabSkillSlots(BodyIndex bodyIndex)
		{
			return ArrayUtils.GetSafe(skillSlots, (int)bodyIndex);
		}

		public static SkinDef[] GetBodySkins(BodyIndex bodyIndex)
		{
			SkinDef[][] array = skins;
			SkinDef[] defaultValue = Array.Empty<SkinDef>();
			return ArrayUtils.GetSafe(array, (int)bodyIndex, in defaultValue);
		}

		[SystemInitializer(new Type[] { })]
		public static IEnumerator Init()
		{
			AsyncOperationHandle<Texture2D> mysteryIconHandler = LegacyResourcesAPI.LoadAsync<Texture2D>("Textures/MiscIcons/texMysteryIcon");
			while (!mysteryIconHandler.IsDone)
			{
				yield return null;
			}
			defaultPortraitIcon = mysteryIconHandler.Result;
			SetBodyPrefabs(ContentManager.bodyPrefabs);
			availability.MakeAvailable();
		}

		private static void SetBodyPrefabs([NotNull] GameObject[] newBodyPrefabs)
		{
			bodyPrefabs = ArrayUtils.Clone(newBodyPrefabs);
			Array.Sort(bodyPrefabs, (GameObject a, GameObject b) => string.CompareOrdinal(a.name, b.name));
			bodyPrefabBodyComponents = new CharacterBody[bodyPrefabs.Length];
			bodyNames = new string[bodyPrefabs.Length];
			bodyComponents = new Component[bodyPrefabs.Length][];
			skillSlots = new GenericSkill[bodyPrefabs.Length][];
			skins = new SkinDef[bodyPrefabs.Length][];
			nameToIndexMap.Clear();
			for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < bodyPrefabs.Length; bodyIndex++)
			{
				GameObject gameObject = bodyPrefabs[(int)bodyIndex];
				string name = gameObject.name;
				bodyNames[(int)bodyIndex] = name;
				bodyComponents[(int)bodyIndex] = gameObject.GetComponents<Component>();
				skillSlots[(int)bodyIndex] = gameObject.GetComponents<GenericSkill>();
				nameToIndexMap.Add(name, bodyIndex);
				nameToIndexMap.Add(name + "(Clone)", bodyIndex);
				CharacterBody characterBody = (bodyPrefabBodyComponents[(int)bodyIndex] = gameObject.GetComponent<CharacterBody>());
				characterBody.bodyIndex = bodyIndex;
				BodyIndex _temporaryBodyIndex = bodyIndex;
				AsyncOperationHandle<Texture2D> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Texture2D>("Textures/BodyIcons/" + name);
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Texture2D> x)
				{
					FinishAsyncLoads(_temporaryBodyIndex, x.Result);
				};
				skins[(int)bodyIndex] = gameObject.GetComponent<ModelLocator>()?.modelTransform?.GetComponent<ModelSkinController>()?.skins ?? Array.Empty<SkinDef>();
				if (string.IsNullOrEmpty(characterBody.baseNameToken))
				{
					characterBody.baseNameToken = "UNIDENTIFIED";
				}
			}
			bodyCount = bodyPrefabs.Length;
		}

		private static void FinishAsyncLoads(BodyIndex _bodyIndex, Texture2D tex)
		{
			CharacterBody characterBody = bodyPrefabBodyComponents[(int)_bodyIndex];
			if ((bool)tex)
			{
				characterBody.portraitIcon = tex;
			}
			else if (characterBody.portraitIcon == null)
			{
				characterBody.portraitIcon = defaultPortraitIcon;
			}
		}

		private static IEnumerator GeneratePortraits(bool forceRegeneration)
		{
			UnityEngine.Debug.LogError("Starting portrait generation.");
			UnityEngine.Debug.Break();
			ModelPanel modelPanel = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/IconGenerator")).GetComponentInChildren<ModelPanel>();
			yield return new WaitForEndOfFrame();
			int i = 0;
			while (i < bodyPrefabs.Length)
			{
				CharacterBody characterBody = bodyPrefabBodyComponents[i];
				if ((bool)characterBody && (forceRegeneration || IconIsNotSuitable(characterBody.portraitIcon)))
				{
					float num = 1f;
					try
					{
						UnityEngine.Debug.LogFormat("Generating portrait for {0}", bodyPrefabs[i].name);
						modelPanel.modelPrefab = bodyPrefabs[i].GetComponent<ModelLocator>()?.modelTransform.gameObject;
						modelPanel.SetAnglesForCharacterThumbnail(setZoom: true);
						PrintController printController = modelPanel.modelPrefab?.GetComponentInChildren<PrintController>();
						if ((object)printController != null)
						{
							num = Mathf.Max(num, printController.printTime + 1f);
						}
						TemporaryOverlay temporaryOverlay = modelPanel.modelPrefab?.GetComponentInChildren<TemporaryOverlay>();
						if ((object)temporaryOverlay != null)
						{
							num = Mathf.Max(num, temporaryOverlay.durationInstance + 1f);
						}
					}
					catch (Exception)
					{
					}
					RoR2Application.onLateUpdate += UpdateCamera;
					yield return new WaitForSeconds(num);
					modelPanel.SetAnglesForCharacterThumbnail(setZoom: true);
					yield return new WaitForEndOfFrame();
					yield return new WaitForEndOfFrame();
					try
					{
						Texture2D texture2D = new Texture2D(modelPanel.renderTexture.width, modelPanel.renderTexture.height, TextureFormat.ARGB32, mipChain: false, linear: false);
						RenderTexture active = RenderTexture.active;
						RenderTexture.active = modelPanel.renderTexture;
						texture2D.ReadPixels(new UnityEngine.Rect(0f, 0f, modelPanel.renderTexture.width, modelPanel.renderTexture.height), 0, 0, recalculateMipMaps: false);
						RenderTexture.active = active;
						byte[] array = texture2D.EncodeToPNG();
						using FileStream fileStream = new FileStream("Assets/RoR2/GeneratedPortraits/" + bodyPrefabs[i].name + ".png", FileMode.Create, FileAccess.Write);
						fileStream.Write(array, 0, array.Length);
					}
					catch (Exception)
					{
					}
					RoR2Application.onLateUpdate -= UpdateCamera;
					yield return new WaitForEndOfFrame();
				}
				int num2 = i + 1;
				i = num2;
			}
			UnityEngine.Object.Destroy(modelPanel.transform.root.gameObject);
			static bool IconIsNotSuitable(Texture texture)
			{
				if (!texture)
				{
					return true;
				}
				string name = texture.name;
				if (name == "texMysteryIcon" || name == "texNullIcon")
				{
					return true;
				}
				return false;
			}
			void UpdateCamera()
			{
				modelPanel.SetAnglesForCharacterThumbnail(setZoom: true);
			}
		}

		[ConCommand(commandName = "body_generate_portraits", flags = ConVarFlags.None, helpText = "Generates portraits for all bodies that are currently using the default.")]
		private static void CCBodyGeneratePortraits(ConCommandArgs args)
		{
			RoR2Application.instance.StartCoroutine(GeneratePortraits(args.TryGetArgBool(0).GetValueOrDefault()));
		}

		[ConCommand(commandName = "body_list", flags = ConVarFlags.None, helpText = "Prints a list of all character bodies in the game.")]
		private static void CCBodyList(ConCommandArgs args)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < bodyComponents.Length; i++)
			{
				stringBuilder.Append("[").Append(i).Append("]=")
					.Append(bodyNames[i])
					.AppendLine();
			}
		}

		[ConCommand(commandName = "body_reload_all", flags = ConVarFlags.Cheat, helpText = "Reloads all bodies and repopulates the BodyCatalog.")]
		private static void CCBodyReloadAll(ConCommandArgs args)
		{
			SetBodyPrefabs(Resources.LoadAll<GameObject>("Prefabs/CharacterBodies/"));
		}
	}
	public static class ConCommandArgExtensions
	{
		public abstract class BaseCharacterBodyInstanceSearchHandler
		{
			public abstract bool ShouldHandle(ConCommandArgs args, string argString);

			public abstract void GetResults(ConCommandArgs args, string argString, List<CharacterBody> dest);
		}

		public class NearestCharacterBodyInstanceSearchHandler : BaseCharacterBodyInstanceSearchHandler
		{
			public override bool ShouldHandle(ConCommandArgs args, string argString)
			{
				return argString.Equals("nearest", StringComparison.OrdinalIgnoreCase);
			}

			public override void GetResults(ConCommandArgs args, string argString, List<CharacterBody> dest)
			{
				CharacterBody senderBody = args.TryGetSenderBody();
				if (!senderBody)
				{
					throw new ConCommandException($"Sender must have a valid body to use \"{argString}\".");
				}
				UnityEngine.Vector3 myPosition = senderBody.corePosition;
				ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
				dest.AddRange(from candidateBody in readOnlyInstancesList
					where (object)senderBody != candidateBody
					orderby (candidateBody.corePosition - myPosition).sqrMagnitude
					select candidateBody);
			}
		}

		public class SenderCharacterBodyInstanceSearchHandler : BaseCharacterBodyInstanceSearchHandler
		{
			public override bool ShouldHandle(ConCommandArgs args, string argString)
			{
				return argString.Equals("me", StringComparison.OrdinalIgnoreCase);
			}

			public override void GetResults(ConCommandArgs args, string argString, List<CharacterBody> dest)
			{
				CharacterBody characterBody = args.TryGetSenderBody();
				if (!characterBody)
				{
					throw new ConCommandException($"Sender must have a valid body to use \"{argString}\".");
				}
				dest.Add(characterBody);
			}
		}

		private static readonly BaseCharacterBodyInstanceSearchHandler[] finders = new BaseCharacterBodyInstanceSearchHandler[2]
		{
			new SenderCharacterBodyInstanceSearchHandler(),
			new NearestCharacterBodyInstanceSearchHandler()
		};

		public static BodyIndex? TryGetArgBodyIndex(this ConCommandArgs args, int index)
		{
			if (index < args.userArgs.Count)
			{
				BodyIndex bodyIndex = BodyCatalog.FindBodyIndexCaseInsensitive(args[index]);
				if (bodyIndex != BodyIndex.None)
				{
					return bodyIndex;
				}
			}
			return null;
		}

		public static BodyIndex GetArgBodyIndex(this ConCommandArgs args, int index)
		{
			return args.TryGetArgBodyIndex(index) ?? throw new ConCommandException($"Argument {index} is not a valid body name.");
		}

		public static EquipmentIndex? TryGetArgEquipmentIndex(this ConCommandArgs args, int index)
		{
			string text = args.TryGetArgString(index);
			if (text != null)
			{
				EquipmentIndex equipmentIndex = EquipmentCatalog.FindEquipmentIndex(text);
				if (equipmentIndex != EquipmentIndex.None || text.Equals("None", StringComparison.Ordinal))
				{
					return equipmentIndex;
				}
			}
			return null;
		}

		public static EquipmentIndex GetArgEquipmentIndex(this ConCommandArgs args, int index)
		{
			return args.TryGetArgEquipmentIndex(index) ?? throw new ConCommandException("No EquipmentIndex is defined for an equipment named '" + args.TryGetArgString(index) + "'. Use the \"equipment_list\" command to get a list of all valid equipment.");
		}

		public static void GetArgCharacterBodyInstances(this ConCommandArgs args, int argIndex, List<CharacterBody> dest)
		{
			if (argIndex >= args.userArgs.Count)
			{
				return;
			}
			string argString = args[argIndex];
			args.TryGetSenderBody();
			List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			try
			{
				for (int i = 0; i < finders.Length; i++)
				{
					BaseCharacterBodyInstanceSearchHandler baseCharacterBodyInstanceSearchHandler = finders[i];
					if (baseCharacterBodyInstanceSearchHandler.ShouldHandle(args, argString))
					{
						baseCharacterBodyInstanceSearchHandler.GetResults(args, argString, list);
						dest.AddRange(list);
						break;
					}
				}
			}
			catch (ConCommandException ex)
			{
				throw new ConCommandException($"Argument {argIndex}: {ex.Message}");
			}
			finally
			{
				list = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
			}
		}

		public static void TryGetArgCharacterBodyInstances(this ConCommandArgs args, int argIndex, List<CharacterBody> dest)
		{
			try
			{
				args.GetArgCharacterBodyInstances(argIndex, dest);
			}
			catch (ConCommandException)
			{
			}
		}

		public static CharacterBody GetArgCharacterBodyInstance(this ConCommandArgs args, int argIndex)
		{
			List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			try
			{
				args.GetArgCharacterBodyInstances(argIndex, list);
				return (list.Count > 0) ? list[0] : null;
			}
			finally
			{
				list = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
			}
		}

		public static CharacterBody TryGetArgCharacterBodyInstance(this ConCommandArgs args, int argIndex)
		{
			try
			{
				return args.GetArgCharacterBodyInstance(argIndex);
			}
			catch (ConCommandException)
			{
				return null;
			}
		}

		public static CharacterMaster GetArgCharacterMasterInstance(this ConCommandArgs args, int argIndex)
		{
			CharacterBody argCharacterBodyInstance = args.GetArgCharacterBodyInstance(argIndex);
			if ((bool)argCharacterBodyInstance)
			{
				return argCharacterBodyInstance.master;
			}
			return null;
		}

		public static CharacterMaster TryGetArgCharacterMasterInstance(this ConCommandArgs args, int argIndex)
		{
			try
			{
				return args.GetArgCharacterMasterInstance(argIndex);
			}
			catch (ConCommandException)
			{
				return null;
			}
		}

		public static ItemIndex? TryGetArgItemIndex(this ConCommandArgs args, int index)
		{
			string text = args.TryGetArgString(index);
			if (text != null)
			{
				ItemIndex itemIndex = ItemCatalog.FindItemIndex(text);
				if (itemIndex != ItemIndex.None || text.Equals("None", StringComparison.Ordinal))
				{
					return itemIndex;
				}
			}
			return null;
		}

		public static ItemIndex GetArgItemIndex(this ConCommandArgs args, int index)
		{
			return args.TryGetArgItemIndex(index) ?? throw new ConCommandException("No ItemIndex is defined for an item named '" + args.TryGetArgString(index) + "'. Use the \"item_list\" command to get a list of all valid items.");
		}

		public static MasterCatalog.MasterIndex? TryGetArgMasterIndex(this ConCommandArgs args, int argIndex)
		{
			if (argIndex < args.userArgs.Count)
			{
				string text = args[argIndex];
				MasterCatalog.MasterIndex masterIndex = MasterCatalog.FindMasterIndex(text);
				if (masterIndex != MasterCatalog.MasterIndex.none || text.Equals("None", StringComparison.OrdinalIgnoreCase))
				{
					return masterIndex;
				}
			}
			return null;
		}

		public static MasterCatalog.MasterIndex GetArgMasterIndex(this ConCommandArgs args, int index)
		{
			return args.TryGetArgMasterIndex(index) ?? throw new ConCommandException($"Argument {index} is not a valid character master prefab name.");
		}
	}
	public class BodySplitter
	{
		public CharacterBody body;

		public float moneyMultiplier;

		private int _count = 1;

		public readonly MasterSummon masterSummon;

		private Dictionary<CharacterBody, UnityEngine.Vector3> spawnedBodyVelocity = new Dictionary<CharacterBody, UnityEngine.Vector3>();

		public int count
		{
			get
			{
				return _count;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("'value' cannot be non-positive.", "value");
				}
				_count = value;
			}
		}

		public UnityEngine.Vector3 splinterInitialVelocityLocal { get; set; } = UnityEngine.Vector3.zero;


		public float minSpawnCircleRadius { get; set; }

		public BodySplitter()
		{
			masterSummon = new MasterSummon
			{
				masterPrefab = null,
				ignoreTeamMemberLimit = false,
				useAmbientLevel = null,
				teamIndexOverride = null
			};
		}

		public void Perform()
		{
			PerformInternal(masterSummon);
		}

		private void PerformInternal(MasterSummon masterSummon)
		{
			if ((object)body == null)
			{
				throw new InvalidOperationException("'body' is null.");
			}
			if (!body)
			{
				throw new InvalidOperationException("'body' is an invalid object.");
			}
			GameObject masterPrefab = masterSummon.masterPrefab;
			CharacterMaster obj = masterPrefab.GetComponent<CharacterMaster>() ?? throw new InvalidOperationException("'splinterMasterPrefab' does not have a CharacterMaster component.");
			if (!obj.masterIndex.isValid)
			{
				throw new InvalidOperationException("'splinterMasterPrefab' is not registered with MasterCatalog.");
			}
			if ((object)MasterCatalog.GetMasterPrefab(obj.masterIndex) != masterPrefab)
			{
				throw new InvalidOperationException("'splinterMasterPrefab' is not a prefab.");
			}
			UnityEngine.Vector3 position = body.transform.position;
			float y = UnityEngine.Quaternion.LookRotation(body.inputBank.aimDirection).eulerAngles.y;
			GameObject bodyPrefab = obj.bodyPrefab;
			bodyPrefab.GetComponent<CharacterBody>();
			float num = CalcBodyXZRadius(bodyPrefab);
			float a = 0f;
			if (count > 1)
			{
				a = num / Mathf.Sin(MathF.PI / (float)count);
			}
			a = Mathf.Max(a, minSpawnCircleRadius);
			masterSummon.summonerBodyObject = body.gameObject;
			masterSummon.inventoryToCopy = body.inventory;
			masterSummon.loadout = (body.master ? body.master.loadout : null);
			masterSummon.inventoryItemCopyFilter = CopyItemFilter;
			foreach (float item in new DegreeSlices(count, 0.5f))
			{
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, y + item + 180f, 0f);
				UnityEngine.Vector3 vector = quaternion * UnityEngine.Vector3.forward;
				float num2 = a;
				if (Physics.Raycast(new Ray(position, vector), out var hitInfo, a + num, LayerIndex.world.intVal, QueryTriggerInteraction.Ignore))
				{
					num2 = hitInfo.distance - num;
				}
				UnityEngine.Vector3 position2 = position + vector * num2;
				masterSummon.position = position2;
				masterSummon.rotation = quaternion;
				try
				{
					CharacterMaster characterMaster = masterSummon.Perform();
					if ((bool)characterMaster)
					{
						CharacterBody characterBody = characterMaster.GetBody();
						if ((bool)characterBody)
						{
							spawnedBodyVelocity.Add(characterBody, quaternion * splinterInitialVelocityLocal);
							characterMaster.money = (uint)Mathf.FloorToInt((float)body.master.money * moneyMultiplier);
							characterBody.characterMotor.onMotorStart += OnCharacterMotorStart;
						}
					}
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
		}

		private void OnCharacterMotorStart(CharacterBody characterBody)
		{
			if (spawnedBodyVelocity.TryGetValue(characterBody, out var value))
			{
				AddBodyVelocity(characterBody, value);
			}
			else
			{
				UnityEngine.Debug.LogError("Split characterBody has not stored split velocity");
			}
		}

		private static float CalcBodyXZRadius(GameObject bodyPrefab)
		{
			Collider component = bodyPrefab.GetComponent<Collider>();
			if (!component)
			{
				return 0f;
			}
			UnityEngine.Vector3 position = bodyPrefab.transform.position;
			Bounds bounds = component.bounds;
			UnityEngine.Vector3 min = bounds.min;
			UnityEngine.Vector3 max = bounds.max;
			return Mathf.Max(Mathf.Max(Mathf.Max(Mathf.Max(0f, position.x - min.x), position.z - min.z), max.x - position.x), max.z - position.z);
		}

		private static void AddBodyVelocity(CharacterBody body, UnityEngine.Vector3 additionalVelocity)
		{
			IPhysMotor component = body.GetComponent<IPhysMotor>();
			if (component != null)
			{
				PhysForceInfo physForceInfo = PhysForceInfo.Create();
				physForceInfo.force = additionalVelocity;
				physForceInfo.massIsOne = true;
				physForceInfo.ignoreGroundStick = true;
				physForceInfo.disableAirControlUntilCollision = false;
				component.ApplyForceImpulse(in physForceInfo);
			}
		}

		private static bool CopyItemFilter(ItemIndex itemIndex)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if ((bool)itemDef)
			{
				return itemDef.tier == ItemTier.NoTier;
			}
			return false;
		}
	}
	public enum BuffIndex
	{
		None = -1
	}
	public static class BuffCatalog
	{
		private static BuffDef[] buffDefs;

		public static BuffIndex[] eliteBuffIndices;

		public static BuffIndex[] debuffBuffIndices;

		public static BuffIndex[] nonHiddenBuffIndices;

		public static BuffIndex[] ignoreGrowthNectarIndices;

		private static readonly Dictionary<string, BuffIndex> nameToBuffIndex = new Dictionary<string, BuffIndex>();

		[Obsolete("Use IContentPackProvider instead.")]
		public static readonly CatalogModHelperProxy<BuffDef> modHelper = new CatalogModHelperProxy<BuffDef>("RoR2.BuffCatalog.modHelper", LegacyModContentPackProvider.instance.registrationContentPack.buffDefs);

		public static int buffCount => buffDefs.Length;

		private static void RegisterBuff(BuffIndex buffIndex, BuffDef buffDef)
		{
			buffDef.buffIndex = buffIndex;
			nameToBuffIndex[buffDef.name] = buffIndex;
		}

		public static BuffDef GetBuffDef(BuffIndex buffIndex)
		{
			return ArrayUtils.GetSafe(buffDefs, (int)buffIndex);
		}

		public static BuffIndex FindBuffIndex(string buffName)
		{
			if (nameToBuffIndex.TryGetValue(buffName, out var value))
			{
				return value;
			}
			return BuffIndex.None;
		}

		public static T[] GetPerBuffBuffer<T>()
		{
			return new T[buffCount];
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetBuffDefs(ContentManager.buffDefs);
		}

		private static void SetBuffDefs(BuffDef[] newBuffDefs)
		{
			nameToBuffIndex.Clear();
			buffDefs = ArrayUtils.Clone(newBuffDefs);
			for (BuffIndex buffIndex = (BuffIndex)0; (int)buffIndex < buffDefs.Length; buffIndex++)
			{
				RegisterBuff(buffIndex, buffDefs[(int)buffIndex]);
			}
			eliteBuffIndices = (from buffDef in buffDefs
				where buffDef.isElite
				select buffDef.buffIndex).ToArray();
			debuffBuffIndices = (from buffDef in buffDefs
				where buffDef.isDebuff
				select buffDef.buffIndex).ToArray();
			nonHiddenBuffIndices = (from buffDef in buffDefs
				where !buffDef.isHidden
				select buffDef.buffIndex).ToArray();
			ignoreGrowthNectarIndices = (from buffDef in buffDefs
				where buffDef.ignoreGrowthNectar
				select buffDef.buffIndex).ToArray();
		}
	}
	public class BulletAttack
	{
		public enum FalloffModel
		{
			None,
			DefaultBullet,
			Buckshot
		}

		public delegate bool HitCallback(BulletAttack bulletAttack, ref BulletHit hitInfo);

		public delegate void ModifyOutgoingDamageCallback(BulletAttack bulletAttack, ref BulletHit hitInfo, DamageInfo damageInfo);

		public delegate bool FilterCallback(BulletAttack bulletAttack, ref BulletHit hitInfo);

		public class BulletHit
		{
			public UnityEngine.Vector3 direction;

			public UnityEngine.Vector3 point;

			public UnityEngine.Vector3 surfaceNormal;

			public float distance;

			public Collider collider;

			public HurtBox hitHurtBox;

			public GameObject entityObject;

			public HurtBox.DamageModifier damageModifier;

			public bool isSniperHit;

			public HurtBox hurtBox;

			public void Reset()
			{
				direction = UnityEngine.Vector3.zero;
				point = UnityEngine.Vector3.zero;
				surfaceNormal = UnityEngine.Vector3.zero;
				distance = 0f;
				collider = null;
				entityObject = null;
				damageModifier = HurtBox.DamageModifier.Normal;
				isSniperHit = false;
				hurtBox = null;
			}
		}

		public class BulletHitPool : GenericPool<BulletHit>
		{
			protected override BulletHit CreateNewObject(bool inPoolEntry = true)
			{
				return new BulletHit();
			}

			public void ReturnAllInUse()
			{
				if (_InUse != null)
				{
					for (int num = _InUse.Count - 1; num >= 0; num--)
					{
						ReturnObject(_InUse[num]);
					}
				}
			}
		}

		private static GameObject sniperTargetHitEffect;

		public GameObject owner;

		public GameObject weapon;

		public float damage = 1f;

		public bool isCrit;

		public float force = 1f;

		public ProcChainMask procChainMask;

		public float procCoefficient = 1f;

		public DamageTypeCombo damageType = DamageType.Generic;

		public DamageColorIndex damageColorIndex;

		public bool sniper;

		public FalloffModel falloffModel = FalloffModel.DefaultBullet;

		public GameObject tracerEffectPrefab;

		public GameObject hitEffectPrefab;

		public string muzzleName = "";

		public bool HitEffectNormal = true;

		public UnityEngine.Vector3 origin;

		private UnityEngine.Vector3 _aimVector;

		private float _maxDistance = 200f;

		public float radius;

		public uint bulletCount = 1u;

		public float minSpread;

		public float maxSpread;

		public float spreadPitchScale = 1f;

		public float spreadYawScale = 1f;

		public QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore;

		private static readonly LayerMask defaultHitMask = (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask;

		public LayerMask hitMask = defaultHitMask;

		private static readonly LayerMask defaultStopperMask = defaultHitMask;

		public LayerMask stopperMask = defaultStopperMask;

		public bool smartCollision;

		public bool cheapMultiBullet;

		public float multiBulletOdds = 0.4f;

		public bool allowTrajectoryAimAssist = true;

		public float trajectoryAimAssistMultiplier = 1f;

		public HitCallback hitCallback;

		protected DamageInfo _dmgInfo;

		public static readonly HitCallback defaultHitCallback = DefaultHitCallbackImplementation;

		public ModifyOutgoingDamageCallback modifyOutgoingDamageCallback;

		private static NetworkWriter messageWriter = new NetworkWriter();

		public FilterCallback filterCallback;

		public static readonly FilterCallback defaultFilterCallback = DefaultFilterCallbackImplementation;

		protected static BulletHitPool __BulletHitPool = null;

		protected static List<BulletHit> _BulletHits = new List<BulletHit>();

		protected static List<GameObject> _IgnoreList = new List<GameObject>();

		protected static HashSet<GameObject> _EncounteredEntityObjects = new HashSet<GameObject>();

		protected static bool _UsePools = true;

		protected static EffectData _effectData = null;

		public UnityEngine.Vector3 aimVector
		{
			get
			{
				return _aimVector;
			}
			set
			{
				_aimVector = value;
				_aimVector.Normalize();
			}
		}

		public float maxDistance
		{
			get
			{
				return _maxDistance;
			}
			set
			{
				if (!float.IsInfinity(value) && !float.IsNaN(value))
				{
					_maxDistance = value;
					return;
				}
				UnityEngine.Debug.LogFormat("BulletAttack.maxDistance was assigned a value other than a finite number. value={0}", value);
			}
		}

		[Obsolete("Use .defaultHitCallback instead.", false)]
		public static HitCallback DefaultHitCallback => defaultHitCallback;

		[Obsolete("Use .defaultFilterCallback instead.", false)]
		public static FilterCallback DefaultFilterCallback => defaultFilterCallback;

		protected static BulletHitPool _BulletHitPool
		{
			get
			{
				if (__BulletHitPool == null)
				{
					__BulletHitPool = new BulletHitPool();
					__BulletHitPool.AlwaysGrowable = true;
					__BulletHitPool.Initialize(20, 10);
				}
				return __BulletHitPool;
			}
		}

		public static bool UsePools => _UsePools;

		public BulletAttack()
		{
			filterCallback = defaultFilterCallback;
			hitCallback = defaultHitCallback;
		}

		[InitDuringStartup]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/Effects/ImpactEffects/SniperTargetHitEffect", delegate(GameObject operationResult)
			{
				sniperTargetHitEffect = operationResult;
			});
		}

		public void Reset()
		{
			owner = null;
			weapon = null;
			damage = 1f;
			isCrit = false;
			force = 1f;
			procChainMask.mask = 0u;
			procCoefficient = 1f;
			damageType = DamageType.Generic;
			damageColorIndex = DamageColorIndex.Default;
			sniper = false;
			falloffModel = FalloffModel.DefaultBullet;
			tracerEffectPrefab = null;
			hitEffectPrefab = null;
			muzzleName = "";
			HitEffectNormal = true;
			origin = UnityEngine.Vector3.zero;
			_aimVector = UnityEngine.Vector3.zero;
			_maxDistance = 200f;
			radius = 0f;
			bulletCount = 1u;
			minSpread = 0f;
			maxSpread = 0f;
			spreadPitchScale = 1f;
			spreadYawScale = 1f;
			queryTriggerInteraction = QueryTriggerInteraction.Ignore;
			hitMask = defaultHitMask;
			stopperMask = defaultStopperMask;
			smartCollision = false;
			cheapMultiBullet = false;
			filterCallback = defaultFilterCallback;
			hitCallback = defaultHitCallback;
		}

		private static void PlayHitEffect(BulletAttack bulletAttack, ref BulletHit hitInfo)
		{
			if ((bool)bulletAttack.hitEffectPrefab)
			{
				EffectManager.SimpleImpactEffect(bulletAttack.hitEffectPrefab, hitInfo.point, bulletAttack.HitEffectNormal ? hitInfo.surfaceNormal : (-hitInfo.direction), transmit: true);
			}
			if (hitInfo.isSniperHit && (object)sniperTargetHitEffect != null)
			{
				EffectData effectData = new EffectData
				{
					origin = hitInfo.point,
					rotation = UnityEngine.Quaternion.LookRotation(-hitInfo.direction)
				};
				effectData.SetHurtBoxReference(hitInfo.hitHurtBox);
				EffectManager.SpawnEffect(sniperTargetHitEffect, effectData, transmit: true);
			}
			if ((bool)hitInfo.collider)
			{
				SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitInfo.collider, hitInfo.point);
				if ((bool)objectSurfaceDef && (bool)objectSurfaceDef.impactEffectPrefab)
				{
					EffectData effectData2 = new EffectData
					{
						origin = hitInfo.point,
						rotation = UnityEngine.Quaternion.LookRotation(hitInfo.surfaceNormal),
						color = objectSurfaceDef.approximateColor,
						surfaceDefIndex = objectSurfaceDef.surfaceDefIndex
					};
					EffectManager.SpawnEffect(objectSurfaceDef.impactEffectPrefab, effectData2, transmit: true);
				}
			}
		}

		private static bool DefaultHitCallbackImplementation(BulletAttack bulletAttack, ref BulletHit hitInfo)
		{
			bool result = false;
			if ((bool)hitInfo.collider)
			{
				result = ((1 << hitInfo.collider.gameObject.layer) & (int)bulletAttack.stopperMask) == 0;
			}
			PlayHitEffect(bulletAttack, ref hitInfo);
			GameObject entityObject = hitInfo.entityObject;
			if ((bool)entityObject)
			{
				float num = CalcFalloffFactor(bulletAttack.falloffModel, hitInfo.distance);
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = bulletAttack.damage * num;
				damageInfo.crit = bulletAttack.isCrit;
				damageInfo.attacker = bulletAttack.owner;
				damageInfo.inflictor = bulletAttack.weapon;
				damageInfo.position = hitInfo.point;
				damageInfo.force = hitInfo.direction * (bulletAttack.force * num);
				damageInfo.procChainMask = bulletAttack.procChainMask;
				damageInfo.procCoefficient = bulletAttack.procCoefficient;
				damageInfo.damageType = bulletAttack.damageType;
				damageInfo.damageColorIndex = bulletAttack.damageColorIndex;
				damageInfo.ModifyDamageInfo(hitInfo.damageModifier);
				if (hitInfo.isSniperHit)
				{
					damageInfo.crit = true;
					damageInfo.damageColorIndex = DamageColorIndex.Sniper;
				}
				bulletAttack.modifyOutgoingDamageCallback?.Invoke(bulletAttack, ref hitInfo, damageInfo);
				TeamIndex attackerTeamIndex = TeamIndex.None;
				if ((bool)bulletAttack.owner)
				{
					TeamComponent component = bulletAttack.owner.GetComponent<TeamComponent>();
					if ((bool)component)
					{
						attackerTeamIndex = component.teamIndex;
					}
				}
				HealthComponent healthComponent = null;
				if ((bool)hitInfo.hitHurtBox)
				{
					healthComponent = hitInfo.hitHurtBox.healthComponent;
				}
				bool flag = (bool)healthComponent && FriendlyFireManager.ShouldDirectHitProceed(healthComponent, attackerTeamIndex);
				if (NetworkServer.active)
				{
					if (flag)
					{
						healthComponent.TakeDamage(damageInfo);
						GlobalEventManager.instance.OnHitEnemy(damageInfo, hitInfo.entityObject);
					}
					GlobalEventManager.instance.OnHitAll(damageInfo, hitInfo.entityObject);
				}
				else if (ClientScene.ready)
				{
					messageWriter.StartMessage(53);
					int currentLogLevel = LogFilter.currentLogLevel;
					LogFilter.currentLogLevel = 4;
					messageWriter.Write(entityObject);
					LogFilter.currentLogLevel = currentLogLevel;
					messageWriter.Write(damageInfo);
					messageWriter.Write(flag);
					messageWriter.FinishMessage();
					ClientScene.readyConnection.SendWriter(messageWriter, QosChannelIndex.defaultReliable.intVal);
				}
			}
			return result;
		}

		private static float CalcFalloffFactor(FalloffModel falloffModel, float distance)
		{
			return falloffModel switch
			{
				FalloffModel.DefaultBullet => 0.5f + Mathf.Clamp01(Mathf.InverseLerp(60f, 25f, distance)) * 0.5f, 
				FalloffModel.Buckshot => 0.25f + Mathf.Clamp01(Mathf.InverseLerp(25f, 7f, distance)) * 0.75f, 
				_ => 1f, 
			};
		}

		private static bool DefaultFilterCallbackImplementation(BulletAttack bulletAttack, ref BulletHit hitInfo)
		{
			HurtBox component = hitInfo.collider.GetComponent<HurtBox>();
			if ((bool)component && (bool)component.healthComponent && component.healthComponent.gameObject == bulletAttack.weapon)
			{
				return false;
			}
			return hitInfo.entityObject != bulletAttack.weapon;
		}

		private void InitBulletHitFromOriginHit(ref BulletHit bulletHit, UnityEngine.Vector3 direction, Collider hitCollider)
		{
			bulletHit.direction = direction;
			bulletHit.point = origin;
			bulletHit.surfaceNormal = -direction;
			bulletHit.distance = 0f;
			bulletHit.collider = hitCollider;
			HurtBox component = bulletHit.collider.GetComponent<HurtBox>();
			bulletHit.hitHurtBox = component;
			bulletHit.entityObject = (((bool)component && (bool)component.healthComponent) ? component.healthComponent.gameObject : bulletHit.collider.gameObject);
			bulletHit.damageModifier = (component ? component.damageModifier : HurtBox.DamageModifier.Normal);
		}

		private void InitBulletHitFromRaycastHit(ref BulletHit bulletHit, UnityEngine.Vector3 origin, UnityEngine.Vector3 direction, ref RaycastHit raycastHit)
		{
			bulletHit.direction = direction;
			bulletHit.surfaceNormal = raycastHit.normal;
			bulletHit.distance = raycastHit.distance;
			bulletHit.collider = raycastHit.collider;
			bulletHit.point = ((bulletHit.distance == 0f) ? origin : raycastHit.point);
			HurtBox component = bulletHit.collider.GetComponent<HurtBox>();
			bulletHit.hitHurtBox = component;
			bulletHit.entityObject = (((bool)component && (bool)component.healthComponent) ? component.healthComponent.gameObject : bulletHit.collider.gameObject);
			bulletHit.damageModifier = (component ? component.damageModifier : HurtBox.DamageModifier.Normal);
		}

		private bool ProcessHit(ref BulletHit hitInfo)
		{
			if (!filterCallback(this, ref hitInfo))
			{
				return true;
			}
			if (sniper)
			{
				hitInfo.isSniperHit = IsSniperTargetHit(in hitInfo);
			}
			return hitCallback(this, ref hitInfo);
		}

		private static bool IsSniperTargetHit(in BulletHit hitInfo)
		{
			if ((bool)hitInfo.hitHurtBox && (bool)hitInfo.hitHurtBox.hurtBoxGroup)
			{
				HurtBox[] hurtBoxes = hitInfo.hitHurtBox.hurtBoxGroup.hurtBoxes;
				foreach (HurtBox hurtBox in hurtBoxes)
				{
					if ((bool)hurtBox && hurtBox.isSniperTarget && UnityEngine.Vector3.ProjectOnPlane(hitInfo.point - hurtBox.transform.position, hitInfo.direction).sqrMagnitude <= HurtBox.sniperTargetRadiusSqr)
					{
						return true;
					}
				}
			}
			return false;
		}

		private GameObject ProcessHitList(List<BulletHit> hits, ref UnityEngine.Vector3 endPosition, List<GameObject> ignoreList)
		{
			int count = hits.Count;
			int[] array = new int[count];
			for (int i = 0; i < count; i++)
			{
				array[i] = i;
			}
			for (int j = 0; j < count; j++)
			{
				float distance = maxDistance;
				int num = j;
				for (int k = j; k < count; k++)
				{
					int index = array[k];
					if (hits[index].distance < distance)
					{
						distance = hits[index].distance;
						num = k;
					}
				}
				GameObject entityObject = hits[array[num]].entityObject;
				if (!ignoreList.Contains(entityObject))
				{
					ignoreList.Add(entityObject);
					BulletHit hitInfo = hits[array[num]];
					if (!ProcessHit(ref hitInfo))
					{
						endPosition = hits[array[num]].point;
						return entityObject;
					}
				}
				array[num] = array[j];
			}
			return null;
		}

		private static GameObject LookUpColliderEntityObject(Collider collider)
		{
			HurtBox component = collider.GetComponent<HurtBox>();
			if (!component || !component.healthComponent)
			{
				return collider.gameObject;
			}
			return component.healthComponent.gameObject;
		}

		private static Collider[] PhysicsOverlapPoint(UnityEngine.Vector3 point, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.Ignore)
		{
			return Physics.OverlapBox(point, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity, layerMask, queryTriggerInteraction);
		}

		public void Fire()
		{
			if (allowTrajectoryAimAssist)
			{
				aimVector = TrajectoryAimAssist.ApplyTrajectoryAimAssist(aimVector, origin, maxDistance, owner, weapon, trajectoryAimAssistMultiplier);
			}
			UnityEngine.Vector3[] array = new UnityEngine.Vector3[bulletCount];
			UnityEngine.Vector3 up = UnityEngine.Vector3.up;
			UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimVector);
			for (int i = 0; i < bulletCount; i++)
			{
				float x = UnityEngine.Random.Range(minSpread, maxSpread);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f) * spreadYawScale;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f * spreadPitchScale;
				array[i] = UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimVector);
			}
			int muzzleIndex = -1;
			if (!weapon)
			{
				weapon = owner;
			}
			if ((bool)weapon)
			{
				ModelLocator component = weapon.GetComponent<ModelLocator>();
				if ((bool)component && (bool)component.modelTransform)
				{
					ChildLocator component2 = component.modelTransform.GetComponent<ChildLocator>();
					if ((bool)component2)
					{
						muzzleIndex = component2.FindChildIndex(muzzleName);
					}
				}
			}
			UnityEngine.Vector3 axis2 = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, aimVector);
			UnityEngine.Vector3 forward = UnityEngine.Vector3.forward;
			if (cheapMultiBullet)
			{
				float x2 = UnityEngine.Random.Range(minSpread, maxSpread);
				float z2 = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 vector2 = UnityEngine.Quaternion.Euler(0f, 0f, z2) * (UnityEngine.Quaternion.Euler(x2, 0f, 0f) * UnityEngine.Vector3.forward);
				float y2 = vector2.y;
				vector2.y = 0f;
				float angle3 = (Mathf.Atan2(vector2.z, vector2.x) * 57.29578f - 90f) * spreadYawScale;
				float angle4 = Mathf.Atan2(y2, vector2.magnitude) * 57.29578f * spreadPitchScale;
				forward = UnityEngine.Quaternion.AngleAxis(angle3, UnityEngine.Vector3.up) * (UnityEngine.Quaternion.AngleAxis(angle4, axis2) * aimVector);
				FireMulti(forward, muzzleIndex);
				return;
			}
			for (int j = 0; j < bulletCount; j++)
			{
				float x3 = UnityEngine.Random.Range(minSpread, maxSpread);
				float z3 = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 vector3 = UnityEngine.Quaternion.Euler(0f, 0f, z3) * (UnityEngine.Quaternion.Euler(x3, 0f, 0f) * UnityEngine.Vector3.forward);
				float y3 = vector3.y;
				vector3.y = 0f;
				float angle5 = (Mathf.Atan2(vector3.z, vector3.x) * 57.29578f - 90f) * spreadYawScale;
				float angle6 = Mathf.Atan2(y3, vector3.magnitude) * 57.29578f * spreadPitchScale;
				forward = UnityEngine.Quaternion.AngleAxis(angle5, UnityEngine.Vector3.up) * (UnityEngine.Quaternion.AngleAxis(angle6, axis2) * aimVector);
				FireSingle(forward, muzzleIndex);
			}
		}

		public UnityEngine.Vector3 Fire_ReturnHit()
		{
			int muzzleIndex = -1;
			_ = origin;
			if (!weapon)
			{
				weapon = owner;
			}
			if ((bool)weapon)
			{
				ModelLocator component = weapon.GetComponent<ModelLocator>();
				if ((bool)component && (bool)component.modelTransform)
				{
					ChildLocator component2 = component.modelTransform.GetComponent<ChildLocator>();
					if ((bool)component2)
					{
						muzzleIndex = component2.FindChildIndex(muzzleName);
					}
				}
			}
			UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, aimVector);
			UnityEngine.Vector3 forward = UnityEngine.Vector3.forward;
			UnityEngine.Vector3 result = UnityEngine.Vector3.zero;
			for (int i = 0; i < bulletCount; i++)
			{
				float x = UnityEngine.Random.Range(minSpread, maxSpread);
				float z = UnityEngine.Random.Range(0f, 360f);
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
				float y = vector.y;
				vector.y = 0f;
				float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f) * spreadYawScale;
				float angle2 = Mathf.Atan2(y, vector.magnitude) * 57.29578f * spreadPitchScale;
				forward = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimVector);
				result = FireSingle_ReturnHit(forward, muzzleIndex);
			}
			return result;
		}

		public static void TogglePooling()
		{
			_UsePools = !_UsePools;
			UnityEngine.Debug.LogFormat("BulletAttack pooling {0}", _UsePools ? "ENABLED" : "DISABLED");
		}

		public static void DumpPools()
		{
			UnityEngine.Debug.LogFormat("BulletAttack Pool: Pooled {0}, InUse {1}", _BulletHitPool.PoolCount(), _BulletHitPool.InUseCount());
		}

		protected static BulletHit GetBulletHit()
		{
			BulletHit @object = _BulletHitPool.GetObject();
			@object.Reset();
			return @object;
		}

		private void FireSingle(UnityEngine.Vector3 normal, int muzzleIndex)
		{
			if (_UsePools)
			{
				float distance = maxDistance;
				UnityEngine.Vector3 endPosition = origin + normal * maxDistance;
				_BulletHits.Clear();
				bool num = radius == 0f || smartCollision;
				bool flag = radius != 0f;
				if (smartCollision)
				{
					_EncounteredEntityObjects.Clear();
				}
				if (num)
				{
					int num2 = 0;
					num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction);
					for (int i = 0; i < num2; i++)
					{
						BulletHit bulletHit = GetBulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]);
						_BulletHits.Add(bulletHit);
						if (smartCollision)
						{
							_EncounteredEntityObjects.Add(bulletHit.entityObject);
						}
						if (bulletHit.distance < distance)
						{
							distance = bulletHit.distance;
						}
					}
					HGPhysics.ReturnResults(hits);
				}
				if (flag)
				{
					LayerMask layerMask = hitMask;
					if (smartCollision)
					{
						layerMask = (int)layerMask & ~(int)LayerIndex.world.mask;
					}
					int num3 = 0;
					num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction);
					for (int j = 0; j < num3; j++)
					{
						BulletHit bulletHit2 = GetBulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]);
						if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject))
						{
							_BulletHits.Add(bulletHit2);
						}
					}
					HGPhysics.ReturnResults(hits2);
				}
				_IgnoreList.Clear();
				ProcessHitList(_BulletHits, ref endPosition, _IgnoreList);
				if ((bool)tracerEffectPrefab)
				{
					if (_effectData == null)
					{
						_effectData = new EffectData();
					}
					_effectData.Reset();
					_effectData.origin = endPosition;
					_effectData.start = origin;
					_effectData.SetChildLocatorTransformReference(weapon, muzzleIndex);
					EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true);
				}
				_BulletHitPool.ReturnAllInUse();
				_EncounteredEntityObjects.Clear();
				return;
			}
			float distance2 = maxDistance;
			UnityEngine.Vector3 endPosition2 = origin + normal * maxDistance;
			List<BulletHit> list = new List<BulletHit>();
			bool num4 = radius == 0f || smartCollision;
			bool flag2 = radius != 0f;
			HashSet<GameObject> hashSet = null;
			if (smartCollision)
			{
				hashSet = new HashSet<GameObject>();
			}
			if (num4)
			{
				int num5 = 0;
				num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction);
				for (int k = 0; k < num5; k++)
				{
					BulletHit bulletHit3 = new BulletHit();
					InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]);
					list.Add(bulletHit3);
					if (smartCollision)
					{
						hashSet.Add(bulletHit3.entityObject);
					}
					if (bulletHit3.distance < distance2)
					{
						distance2 = bulletHit3.distance;
					}
				}
				HGPhysics.ReturnResults(hits3);
			}
			if (flag2)
			{
				LayerMask layerMask2 = hitMask;
				if (smartCollision)
				{
					layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask;
				}
				int num6 = 0;
				num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction);
				for (int l = 0; l < num6; l++)
				{
					BulletHit bulletHit4 = new BulletHit();
					InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]);
					if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject))
					{
						list.Add(bulletHit4);
					}
				}
				HGPhysics.ReturnResults(hits4);
			}
			ProcessHitList(list, ref endPosition2, new List<GameObject>());
			if ((bool)tracerEffectPrefab)
			{
				EffectData effectData = new EffectData
				{
					origin = endPosition2,
					start = origin
				};
				effectData.SetChildLocatorTransformReference(weapon, muzzleIndex);
				EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
			}
		}

		private void FireMulti(UnityEngine.Vector3 normal, int muzzleIndex)
		{
			if (_UsePools)
			{
				float distance = maxDistance;
				UnityEngine.Vector3 endPosition = origin + normal * maxDistance;
				_BulletHits.Clear();
				bool num = radius == 0f || smartCollision;
				bool flag = radius != 0f;
				if (smartCollision)
				{
					_EncounteredEntityObjects.Clear();
				}
				if (num)
				{
					int num2 = 0;
					num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction);
					for (int i = 0; i < num2; i++)
					{
						BulletHit bulletHit = GetBulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]);
						_BulletHits.Add(bulletHit);
						if (smartCollision)
						{
							_EncounteredEntityObjects.Add(bulletHit.entityObject);
						}
						if (bulletHit.distance < distance)
						{
							distance = bulletHit.distance;
						}
					}
					HGPhysics.ReturnResults(hits);
				}
				if (flag)
				{
					LayerMask layerMask = hitMask;
					if (smartCollision)
					{
						layerMask = (int)layerMask & ~(int)LayerIndex.world.mask;
					}
					int num3 = 0;
					num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction);
					for (int j = 0; j < num3; j++)
					{
						BulletHit bulletHit2 = GetBulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]);
						if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject))
						{
							_BulletHits.Add(bulletHit2);
						}
					}
					HGPhysics.ReturnResults(hits2);
				}
				_IgnoreList.Clear();
				ProcessHitList(_BulletHits, ref endPosition, _IgnoreList);
				if ((bool)tracerEffectPrefab)
				{
					if (_effectData == null)
					{
						_effectData = new EffectData();
					}
					_effectData.Reset();
					_effectData.origin = endPosition;
					_effectData.start = origin;
					_effectData.SetChildLocatorTransformReference(weapon, muzzleIndex);
					EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true);
				}
				_BulletHitPool.ReturnAllInUse();
				_EncounteredEntityObjects.Clear();
				return;
			}
			float distance2 = maxDistance;
			UnityEngine.Vector3 endPosition2 = origin + normal * maxDistance;
			List<BulletHit> list = new List<BulletHit>();
			bool num4 = radius == 0f || smartCollision;
			bool flag2 = radius != 0f;
			HashSet<GameObject> hashSet = null;
			if (smartCollision)
			{
				hashSet = new HashSet<GameObject>();
			}
			if (num4)
			{
				int num5 = 0;
				num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction);
				for (int k = 0; k < num5; k++)
				{
					BulletHit bulletHit3 = new BulletHit();
					InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]);
					list.Add(bulletHit3);
					if (smartCollision)
					{
						hashSet.Add(bulletHit3.entityObject);
					}
					if (bulletHit3.distance < distance2)
					{
						distance2 = bulletHit3.distance;
					}
				}
				HGPhysics.ReturnResults(hits3);
			}
			if (flag2)
			{
				LayerMask layerMask2 = hitMask;
				if (smartCollision)
				{
					layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask;
				}
				int num6 = 0;
				num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction);
				for (int l = 0; l < num6; l++)
				{
					BulletHit bulletHit4 = new BulletHit();
					InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]);
					if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject))
					{
						list.Add(bulletHit4);
					}
				}
				HGPhysics.ReturnResults(hits4);
			}
			ProcessHitList(list, ref endPosition2, new List<GameObject>());
			if ((bool)tracerEffectPrefab)
			{
				EffectData effectData = new EffectData
				{
					origin = endPosition2,
					start = origin
				};
				effectData.SetChildLocatorTransformReference(weapon, muzzleIndex);
				EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
			}
		}

		private UnityEngine.Vector3 FireSingle_ReturnHit(UnityEngine.Vector3 normal, int muzzleIndex)
		{
			UnityEngine.Vector3 endPosition;
			if (_UsePools)
			{
				float distance = maxDistance;
				endPosition = origin + normal * maxDistance;
				_BulletHits.Clear();
				bool num = radius == 0f || smartCollision;
				bool flag = radius != 0f;
				if (smartCollision)
				{
					_EncounteredEntityObjects.Clear();
				}
				if (num)
				{
					int num2 = 0;
					num2 = HGPhysics.RaycastAll(out var hits, origin, normal, distance, hitMask, queryTriggerInteraction);
					for (int i = 0; i < num2; i++)
					{
						BulletHit bulletHit = GetBulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit, origin, normal, ref hits[i]);
						_BulletHits.Add(bulletHit);
						if (smartCollision)
						{
							_EncounteredEntityObjects.Add(bulletHit.entityObject);
						}
						if (bulletHit.distance < distance)
						{
							distance = bulletHit.distance;
						}
					}
					HGPhysics.ReturnResults(hits);
				}
				if (flag)
				{
					LayerMask layerMask = hitMask;
					if (smartCollision)
					{
						layerMask = (int)layerMask & ~(int)LayerIndex.world.mask;
					}
					int num3 = 0;
					num3 = HGPhysics.SphereCastAll(out var hits2, origin, radius, normal, distance, layerMask, queryTriggerInteraction);
					for (int j = 0; j < num3; j++)
					{
						BulletHit bulletHit2 = GetBulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit2, origin, normal, ref hits2[j]);
						if (!smartCollision || !_EncounteredEntityObjects.Contains(bulletHit2.entityObject))
						{
							_BulletHits.Add(bulletHit2);
						}
					}
					HGPhysics.ReturnResults(hits2);
				}
				_IgnoreList.Clear();
				ProcessHitList(_BulletHits, ref endPosition, _IgnoreList);
				if ((bool)tracerEffectPrefab)
				{
					if (_effectData == null)
					{
						_effectData = new EffectData();
					}
					_effectData.Reset();
					_effectData.origin = endPosition;
					_effectData.start = origin;
					_effectData.SetChildLocatorTransformReference(weapon, muzzleIndex);
					EffectManager.SpawnEffect(tracerEffectPrefab, _effectData, transmit: true);
				}
				_BulletHitPool.ReturnAllInUse();
				_EncounteredEntityObjects.Clear();
			}
			else
			{
				float distance2 = maxDistance;
				endPosition = origin + normal * maxDistance;
				List<BulletHit> list = new List<BulletHit>();
				bool num4 = radius == 0f || smartCollision;
				bool flag2 = radius != 0f;
				HashSet<GameObject> hashSet = null;
				if (smartCollision)
				{
					hashSet = new HashSet<GameObject>();
				}
				if (num4)
				{
					int num5 = 0;
					num5 = HGPhysics.RaycastAll(out var hits3, origin, normal, distance2, hitMask, queryTriggerInteraction);
					for (int k = 0; k < num5; k++)
					{
						BulletHit bulletHit3 = new BulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit3, origin, normal, ref hits3[k]);
						list.Add(bulletHit3);
						if (smartCollision)
						{
							hashSet.Add(bulletHit3.entityObject);
						}
						if (bulletHit3.distance < distance2)
						{
							distance2 = bulletHit3.distance;
						}
					}
					HGPhysics.ReturnResults(hits3);
				}
				if (flag2)
				{
					LayerMask layerMask2 = hitMask;
					if (smartCollision)
					{
						layerMask2 = (int)layerMask2 & ~(int)LayerIndex.world.mask;
					}
					int num6 = 0;
					num6 = HGPhysics.SphereCastAll(out var hits4, origin, radius, normal, distance2, layerMask2, queryTriggerInteraction);
					for (int l = 0; l < num6; l++)
					{
						BulletHit bulletHit4 = new BulletHit();
						InitBulletHitFromRaycastHit(ref bulletHit4, origin, normal, ref hits4[l]);
						if (!smartCollision || !hashSet.Contains(bulletHit4.entityObject))
						{
							list.Add(bulletHit4);
						}
					}
					HGPhysics.ReturnResults(hits4);
				}
				ProcessHitList(list, ref endPosition, new List<GameObject>());
				if ((bool)tracerEffectPrefab)
				{
					EffectData effectData = new EffectData
					{
						origin = endPosition,
						start = origin
					};
					effectData.SetChildLocatorTransformReference(weapon, muzzleIndex);
					EffectManager.SpawnEffect(tracerEffectPrefab, effectData, transmit: true);
				}
			}
			return endPosition;
		}

		[NetworkMessageHandler(msgType = 53, server = true)]
		private static void HandleBulletDamage(NetworkMessage netMsg)
		{
			NetworkReader reader = netMsg.reader;
			GameObject gameObject = reader.ReadGameObject();
			DamageInfo damageInfo = reader.ReadDamageInfo();
			if (reader.ReadBoolean() && (bool)gameObject)
			{
				HealthComponent component = gameObject.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					component.TakeDamage(damageInfo);
				}
				GlobalEventManager.instance.OnHitEnemy(damageInfo, gameObject);
			}
			GlobalEventManager.instance.OnHitAll(damageInfo, gameObject);
		}
	}
	public class CallbackCheck<TResult, TArg> where TResult : struct
	{
		public delegate void CallbackDelegate(TArg arg, ref TResult? resultOverride);

		private CallbackDelegate[] callbacks = Array.Empty<CallbackDelegate>();

		private int callbackCount;

		public void AddCallback([NotNull] CallbackDelegate callback)
		{
			if (callbacks.Length <= callbackCount + 1)
			{
				Array.Resize(ref callbacks, callbackCount + 1);
			}
			callbacks[callbackCount++] = callback;
		}

		public void RemoveCallback([NotNull] CallbackDelegate callback)
		{
			for (int i = 0; i < callbackCount; i++)
			{
				if ((object)callbacks[i] == callback)
				{
					for (int num = callbackCount - 1; i < num; i++)
					{
						callbacks[i] = callbacks[i + 1];
					}
					callbacks[--callbackCount] = null;
					break;
				}
			}
		}

		public void Clear()
		{
			Array.Clear(callbacks, 0, callbackCount);
			callbackCount = 0;
		}

		public TResult? Evaluate(TArg arg)
		{
			TResult? resultOverride = null;
			for (int i = 0; i < callbackCount; i++)
			{
				callbacks[i](arg, ref resultOverride);
				if (resultOverride.HasValue)
				{
					break;
				}
			}
			return resultOverride;
		}
	}
	public class CatalogModHelper<TEntry>
	{
		private readonly Action<int, TEntry> registrationDelegate;

		private readonly Func<TEntry, string> nameGetter;

		public event Action<List<TEntry>> getAdditionalEntries;

		public CatalogModHelper(Action<int, TEntry> registrationDelegate, Func<TEntry, string> nameGetter)
		{
			this.registrationDelegate = registrationDelegate;
			this.nameGetter = nameGetter;
		}

		public void CollectAndRegisterAdditionalEntries(ref TEntry[] entries)
		{
			int num = entries.Length;
			List<TEntry> list = new List<TEntry>();
			this.getAdditionalEntries?.Invoke(list);
			list.Sort((TEntry a, TEntry b) => StringComparer.Ordinal.Compare(nameGetter(a), nameGetter(b)));
			Array.Resize(ref entries, entries.Length + list.Count);
			int i = 0;
			for (int count = list.Count; i < count; i++)
			{
				entries[num + i] = list[i];
				registrationDelegate?.Invoke(num + i, list[i]);
			}
		}
	}
	public class CatalogModHelperProxy<TEntry>
	{
		private string name;

		private NamedAssetCollection<TEntry> dest;

		[Obsolete("Use IContentPackProvider instead.")]
		public event Action<List<TEntry>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries(name, value, dest);
			}
			remove
			{
			}
		}

		public CatalogModHelperProxy(string name, NamedAssetCollection<TEntry> dest)
		{
			this.name = name;
			this.dest = dest;
		}
	}
	public struct CharacterAnimatorWalkParamCalculator
	{
		private float animatorReferenceMagnitudeVelocity;

		private float animatorReferenceAngleVelocity;

		public UnityEngine.Vector2 animatorWalkSpeed { get; private set; }

		public float remainingTurnAngle { get; private set; }

		public void Update(UnityEngine.Vector3 worldMoveVector, UnityEngine.Vector3 animatorForward, in BodyAnimatorSmoothingParameters.SmoothingParameters smoothingParameters, float deltaTime)
		{
			UnityEngine.Vector3 rhs = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, animatorForward);
			float x = UnityEngine.Vector3.Dot(worldMoveVector, animatorForward);
			float y = UnityEngine.Vector3.Dot(worldMoveVector, rhs);
			UnityEngine.Vector2 to = new UnityEngine.Vector2(x, y);
			float magnitude = to.magnitude;
			float num = ((magnitude > 0f) ? UnityEngine.Vector2.SignedAngle(UnityEngine.Vector2.right, to) : 0f);
			float magnitude2 = animatorWalkSpeed.magnitude;
			float current = ((magnitude2 > 0f) ? UnityEngine.Vector2.SignedAngle(UnityEngine.Vector2.right, animatorWalkSpeed) : 0f);
			float num2 = Mathf.SmoothDamp(magnitude2, magnitude, ref animatorReferenceMagnitudeVelocity, smoothingParameters.walkMagnitudeSmoothDamp, float.PositiveInfinity, deltaTime);
			float num3 = Mathf.SmoothDampAngle(current, num, ref animatorReferenceAngleVelocity, smoothingParameters.walkAngleSmoothDamp, float.PositiveInfinity, deltaTime);
			remainingTurnAngle = num3 - num;
			animatorWalkSpeed = new UnityEngine.Vector2(Mathf.Cos(num3 * (MathF.PI / 180f)), Mathf.Sin(num3 * (MathF.PI / 180f))) * num2;
		}
	}
	public struct CharacterAnimParamAvailability
	{
		public bool isMoving;

		public bool turnAngle;

		public bool isGrounded;

		public bool mainRootPlaybackRate;

		public bool forwardSpeed;

		public bool rightSpeed;

		public bool upSpeed;

		public bool walkSpeed;

		public bool isSprinting;

		public static CharacterAnimParamAvailability FromAnimator(Animator animator)
		{
			AnimatorControllerParameter[] parameters = animator.parameters;
			CharacterAnimParamAvailability result = default(CharacterAnimParamAvailability);
			result.isMoving = Util.HasAnimationParameter(AnimationParameters.isMoving, parameters);
			result.turnAngle = Util.HasAnimationParameter(AnimationParameters.turnAngle, parameters);
			result.isGrounded = Util.HasAnimationParameter(AnimationParameters.isGrounded, parameters);
			result.mainRootPlaybackRate = Util.HasAnimationParameter(AnimationParameters.mainRootPlaybackRate, parameters);
			result.forwardSpeed = Util.HasAnimationParameter(AnimationParameters.forwardSpeed, parameters);
			result.rightSpeed = Util.HasAnimationParameter(AnimationParameters.rightSpeed, parameters);
			result.upSpeed = Util.HasAnimationParameter(AnimationParameters.upSpeed, parameters);
			result.walkSpeed = Util.HasAnimationParameter(AnimationParameters.walkSpeed, parameters);
			result.isSprinting = Util.HasAnimationParameter(AnimationParameters.isSprinting, parameters);
			return result;
		}
	}
	public class CharacterLosTracker : IDisposable
	{
		private struct BodyInfo
		{
			public bool hasLos;

			public Run.FixedTimeStamp lastChecked;
		}

		public UnityEngine.Vector3 origin;

		public int maxRaycastsPerStep = 4;

		private Dictionary<CharacterBody, BodyInfo> bodyToBodyInfo = new Dictionary<CharacterBody, BodyInfo>();

		private bool _enabled;

		private int currentCheckedBodyIndex;

		public bool enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				if (_enabled != value)
				{
					_enabled = value;
					if (_enabled)
					{
						OnEnable();
					}
					else
					{
						OnDisable();
					}
				}
			}
		}

		public event Action<CharacterBody> onBodyDiscovered;

		public event Action<CharacterBody> onBodyLost;

		private void OnEnable()
		{
			CharacterBody.onBodyAwakeGlobal += OnBodyAwakeGlobal;
			CharacterBody.onBodyDestroyGlobal += OnBodyDestroyGlobal;
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				OnBodyDiscovered(readOnlyInstancesList[i]);
			}
		}

		private void OnDisable()
		{
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				OnBodyLost(readOnlyInstancesList[i]);
			}
			CharacterBody.onBodyDestroyGlobal -= OnBodyDestroyGlobal;
			CharacterBody.onBodyAwakeGlobal -= OnBodyAwakeGlobal;
		}

		private void OnBodyAwakeGlobal(CharacterBody characterBody)
		{
			OnBodyDiscovered(characterBody);
		}

		private void OnBodyDestroyGlobal(CharacterBody characterBody)
		{
			OnBodyLost(characterBody);
		}

		public void Step()
		{
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			if (readOnlyInstancesList.Count == 0)
			{
				return;
			}
			for (int i = 0; i < maxRaycastsPerStep; i++)
			{
				if (++currentCheckedBodyIndex >= readOnlyInstancesList.Count)
				{
					currentCheckedBodyIndex = 0;
				}
				CharacterBody characterBody = readOnlyInstancesList[currentCheckedBodyIndex];
				if ((bool)characterBody.mainHurtBox)
				{
					UnityEngine.Vector3 position = characterBody.mainHurtBox.transform.position;
					BodyInfo value = bodyToBodyInfo[characterBody];
					RaycastHit hitInfo;
					bool flag = Physics.Linecast(origin, position, out hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
					value.hasLos = !flag;
					bodyToBodyInfo[characterBody] = value;
				}
			}
		}

		public bool CheckBodyHasLos(CharacterBody characterBody)
		{
			if (bodyToBodyInfo.TryGetValue(characterBody, out var value))
			{
				return value.hasLos;
			}
			return false;
		}

		public void Dispose()
		{
			enabled = false;
			bodyToBodyInfo.Clear();
		}

		private void OnBodyDiscovered(CharacterBody characterBody)
		{
			bodyToBodyInfo.Add(characterBody, new BodyInfo
			{
				hasLos = false,
				lastChecked = Run.FixedTimeStamp.now
			});
			try
			{
				this.onBodyDiscovered?.Invoke(characterBody);
			}
			catch (Exception exception)
			{
				UnityEngine.Debug.LogException(exception);
			}
		}

		private void OnBodyLost(CharacterBody characterBody)
		{
			bodyToBodyInfo.Remove(characterBody);
			try
			{
				this.onBodyLost?.Invoke(characterBody);
			}
			catch (Exception exception)
			{
				UnityEngine.Debug.LogException(exception);
			}
		}
	}
	public static class Chat
	{
		public class UserChatMessage : ChatMessageBase
		{
			public GameObject sender;

			public string text;

			public override string ConstructChatString()
			{
				if ((bool)sender)
				{
					NetworkUser component = sender.GetComponent<NetworkUser>();
					if ((bool)component)
					{
						return string.Format(CultureInfo.InvariantCulture, "<color=#e5eefc>{0}: {1}</color>", Util.EscapeRichTextForTextMeshPro(component.userName), Util.EscapeRichTextForTextMeshPro(text));
					}
				}
				return null;
			}

			public override void OnProcessed()
			{
				base.OnProcessed();
				Util.PlaySound("Play_UI_chatMessage", RoR2Application.instance.gameObject);
			}

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(sender);
				writer.Write(text);
			}

			public override void Deserialize(NetworkReader reader)
			{
				sender = reader.ReadGameObject();
				text = reader.ReadString();
			}
		}

		public class NpcChatMessage : ChatMessageBase
		{
			public GameObject sender;

			public string baseToken;

			public string sound;

			public string formatStringToken;

			public override string ConstructChatString()
			{
				return Language.GetStringFormatted(formatStringToken, Language.GetString(baseToken));
			}

			public override void OnProcessed()
			{
				base.OnProcessed();
				if ((bool)sender)
				{
					Util.PlaySound(sound, sender);
				}
			}

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(sender);
				writer.Write(baseToken);
				writer.Write(sound);
				writer.Write(formatStringToken);
			}

			public override void Deserialize(NetworkReader reader)
			{
				sender = reader.ReadGameObject();
				baseToken = reader.ReadString();
				sound = reader.ReadString();
				formatStringToken = reader.ReadString();
			}
		}

		public class SimpleChatMessage : ChatMessageBase
		{
			public string baseToken;

			public string[] paramTokens;

			public override string ConstructChatString()
			{
				string text = Language.GetString(baseToken);
				if (paramTokens != null && paramTokens.Length != 0)
				{
					CultureInfo invariantCulture = CultureInfo.InvariantCulture;
					string format = text;
					object[] args = paramTokens;
					text = string.Format(invariantCulture, format, args);
				}
				return text;
			}

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(baseToken);
				GeneratedNetworkCode._WriteArrayString_None(writer, paramTokens);
			}

			public override void Deserialize(NetworkReader reader)
			{
				baseToken = reader.ReadString();
				paramTokens = GeneratedNetworkCode._ReadArrayString_None(reader);
			}
		}

		public class BodyChatMessage : ChatMessageBase
		{
			public GameObject bodyObject;

			public string token;

			public override string ConstructChatString()
			{
				CharacterBody characterBody = bodyObject?.GetComponent<CharacterBody>();
				if ((bool)characterBody)
				{
					string bestBodyName = Util.GetBestBodyName(characterBody.gameObject);
					return string.Format(CultureInfo.InvariantCulture, "<color=#e5eefc>{0}: {1}</color>", Util.EscapeRichTextForTextMeshPro(bestBodyName), Language.GetString(token));
				}
				return null;
			}

			public override void OnProcessed()
			{
				base.OnProcessed();
				Util.PlaySound("Play_UI_chatMessage", RoR2Application.instance.gameObject);
			}

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(bodyObject);
				writer.Write(token);
			}

			public override void Deserialize(NetworkReader reader)
			{
				bodyObject = reader.ReadGameObject();
				token = reader.ReadString();
			}
		}

		public class SubjectFormatChatMessage : SubjectChatMessage
		{
			private static readonly string[] empty = new string[0];

			public string[] paramTokens = empty;

			public override string ConstructChatString()
			{
				string @string = Language.GetString(GetResolvedToken());
				string subjectName = GetSubjectName();
				string[] array = new string[1 + paramTokens.Length];
				array[0] = subjectName;
				Array.Copy(paramTokens, 0, array, 1, paramTokens.Length);
				for (int i = 1; i < array.Length; i++)
				{
					array[i] = Language.GetString(array[i]);
				}
				object[] args = array;
				return string.Format(@string, args);
			}

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
				writer.Write((byte)paramTokens.Length);
				for (int i = 0; i < paramTokens.Length; i++)
				{
					writer.Write(paramTokens[i]);
				}
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
				paramTokens = new string[reader.ReadByte()];
				for (int i = 0; i < paramTokens.Length; i++)
				{
					paramTokens[i] = reader.ReadString();
				}
			}
		}

		public class PlayerPickupChatMessage : SubjectChatMessage
		{
			public string pickupToken;

			public Color32 pickupColor;

			public uint pickupQuantity;

			public override string ConstructChatString()
			{
				string subjectName = GetSubjectName();
				string @string = Language.GetString(GetResolvedToken());
				string arg = "";
				if (pickupQuantity != 1)
				{
					arg = "(" + pickupQuantity + ")";
				}
				string str = Language.GetString(pickupToken) ?? "???";
				str = Util.GenerateColoredString(str, pickupColor);
				try
				{
					return string.Format(@string, subjectName, str, arg);
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
				return "";
			}

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
				writer.Write(pickupToken);
				writer.Write(pickupColor);
				writer.WritePackedUInt32(pickupQuantity);
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
				pickupToken = reader.ReadString();
				pickupColor = reader.ReadColor32();
				pickupQuantity = reader.ReadPackedUInt32();
			}
		}

		public class PlayerDeathChatMessage : SubjectFormatChatMessage
		{
			public override string ConstructChatString()
			{
				string text = base.ConstructChatString();
				if (text != null)
				{
					return "<style=cDeath><sprite name=\"Skull\" tint=1> " + text + " <sprite name=\"Skull\" tint=1></style>";
				}
				return text;
			}

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
			}
		}

		public class NamedObjectChatMessage : ChatMessageBase
		{
			public GameObject namedObject;

			public string baseToken;

			public string[] paramTokens;

			public override string ConstructChatString()
			{
				return string.Format(Language.GetString(baseToken), GetObjectName(namedObject));
			}

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(namedObject);
				writer.Write(baseToken);
				GeneratedNetworkCode._WriteArrayString_None(writer, paramTokens);
			}

			public override void Deserialize(NetworkReader reader)
			{
				namedObject = reader.ReadGameObject();
				baseToken = reader.ReadString();
				paramTokens = GeneratedNetworkCode._ReadArrayString_None(reader);
			}
		}

		public class PlayerChatMessage : ChatMessageBase
		{
			public NetworkPlayerName networkPlayerName;

			public string baseToken;

			public override string ConstructChatString()
			{
				return string.Format(Language.GetString(baseToken), networkPlayerName.GetResolvedName());
			}

			public override void Serialize(NetworkWriter writer)
			{
				((MessageBase)this).Serialize(writer);
				writer.Write(networkPlayerName);
				writer.Write(baseToken);
			}

			public override void Deserialize(NetworkReader reader)
			{
				((MessageBase)this).Deserialize(reader);
				networkPlayerName = reader.ReadNetworkPlayerName();
				baseToken = reader.ReadString();
			}
		}

		public class PlayerPauseChatMessage : ChatMessageBase
		{
			public string playerName;

			public string baseToken;

			public override string ConstructChatString()
			{
				return string.Format(Language.GetString(baseToken), playerName);
			}

			public override void Serialize(NetworkWriter writer)
			{
				((MessageBase)this).Serialize(writer);
				writer.Write(playerName);
				writer.Write(baseToken);
			}

			public override void Deserialize(NetworkReader reader)
			{
				((MessageBase)this).Deserialize(reader);
				playerName = reader.ReadString();
				baseToken = reader.ReadString();
			}
		}

		private static List<string> log = new List<string>();

		private static ReadOnlyCollection<string> _readOnlyLog = log.AsReadOnly();

		private static IntConVar cvChatMaxMessages = new IntConVar("chat_max_messages", ConVarFlags.None, "30", "Maximum number of chat messages to store.");

		public static ReadOnlyCollection<string> readOnlyLog => _readOnlyLog;

		public static event Action onChatChanged;

		public static void AddMessage(string message)
		{
			int num = Mathf.Max(cvChatMaxMessages.value, 1);
			while (log.Count > num)
			{
				log.RemoveAt(0);
			}
			log.Add(message);
			if (Chat.onChatChanged != null)
			{
				Chat.onChatChanged();
			}
		}

		public static void Clear()
		{
			log.Clear();
			Chat.onChatChanged?.Invoke();
		}

		public static void SendBroadcastChat(ChatMessageBase message)
		{
			SendBroadcastChat(message, QosChannelIndex.chat.intVal);
		}

		public static void SendBroadcastChat(ChatMessageBase message, int channelIndex)
		{
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.StartMessage(59);
			networkWriter.Write(message.GetTypeIndex());
			networkWriter.Write(message);
			networkWriter.FinishMessage();
			foreach (NetworkConnection connection in NetworkServer.connections)
			{
				connection?.SendWriter(networkWriter, channelIndex);
			}
		}

		public static void SendPlayerConnectedMessage(NetworkUser user)
		{
			SendBroadcastChat(new PlayerChatMessage
			{
				networkPlayerName = user.GetNetworkPlayerName(),
				baseToken = "PLAYER_CONNECTED"
			});
		}

		public static void SendPlayerDisconnectedMessage(NetworkUser user)
		{
			SendBroadcastChat(new PlayerChatMessage
			{
				networkPlayerName = user.GetNetworkPlayerName(),
				baseToken = "PLAYER_DISCONNECTED"
			});
		}

		public static void SendPlayerPausedMessage(string playerName)
		{
			SendBroadcastChat(new PlayerPauseChatMessage
			{
				playerName = playerName,
				baseToken = "PLAYER_PAUSED"
			});
		}

		public static void SendPlayerResumedMessage(string playerName)
		{
			SendBroadcastChat(new PlayerPauseChatMessage
			{
				playerName = playerName,
				baseToken = "PLAYER_RESUMED"
			});
		}

		public static void AddPickupMessage(CharacterBody body, string pickupToken, Color32 pickupColor, uint pickupQuantity)
		{
			AddMessage(new PlayerPickupChatMessage
			{
				subjectAsCharacterBody = body,
				baseToken = "PLAYER_PICKUP",
				pickupToken = pickupToken,
				pickupColor = pickupColor,
				pickupQuantity = pickupQuantity
			});
		}

		[NetworkMessageHandler(msgType = 59, client = true)]
		private static void HandleBroadcastChat(NetworkMessage netMsg)
		{
			ChatMessageBase chatMessageBase = ChatMessageBase.Instantiate(netMsg.reader.ReadByte());
			if (chatMessageBase != null)
			{
				chatMessageBase.Deserialize(netMsg.reader);
				if (!PlatformSystems.userManager.CurrentUserHasRestriction(UserManager.PlatformRestriction.TextChat))
				{
					AddMessage(chatMessageBase);
				}
			}
		}

		private static void AddMessage(ChatMessageBase message)
		{
			string text = message.ConstructChatString();
			if (text != null)
			{
				AddMessage(text);
				message.OnProcessed();
			}
		}

		[ConCommand(commandName = "say", flags = ConVarFlags.ExecuteOnServer, helpText = "Sends a chat message.")]
		private static void CCSay(ConCommandArgs args)
		{
			args.CheckArgumentCount(1);
			if ((bool)args.sender)
			{
				SendBroadcastChat(new UserChatMessage
				{
					sender = args.sender.gameObject,
					text = args[0]
				});
			}
		}
	}
	public abstract class ChatMessageBase : MessageBase
	{
		private static readonly BoolConVar cvChatDebug;

		private static readonly Dictionary<Type, byte> chatMessageTypeToIndex;

		private static readonly List<Type> chatMessageIndexToType;

		static ChatMessageBase()
		{
			cvChatDebug = new BoolConVar("chat_debug", ConVarFlags.None, "0", "Enables logging of chat network messages.");
			chatMessageTypeToIndex = new Dictionary<Type, byte>();
			chatMessageIndexToType = new List<Type>();
			BuildMessageTypeNetMap();
		}

		public abstract string ConstructChatString();

		public virtual void OnProcessed()
		{
		}

		private static void BuildMessageTypeNetMap()
		{
			Type[] types = typeof(ChatMessageBase).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (type.IsSubclassOf(typeof(ChatMessageBase)))
				{
					chatMessageTypeToIndex.Add(type, (byte)chatMessageIndexToType.Count);
					chatMessageIndexToType.Add(type);
				}
			}
		}

		protected string GetObjectName(GameObject namedObject)
		{
			string result = "???";
			if ((bool)namedObject)
			{
				result = namedObject.name;
				NetworkUser networkUser = namedObject.GetComponent<NetworkUser>();
				if (!networkUser)
				{
					networkUser = Util.LookUpBodyNetworkUser(namedObject);
				}
				if ((bool)networkUser)
				{
					result = Util.EscapeRichTextForTextMeshPro(networkUser.userName);
				}
			}
			return result;
		}

		public byte GetTypeIndex()
		{
			return chatMessageTypeToIndex[GetType()];
		}

		public static ChatMessageBase Instantiate(byte typeIndex)
		{
			Type type = chatMessageIndexToType[typeIndex];
			if (cvChatDebug.value)
			{
				UnityEngine.Debug.LogFormat("Received chat message typeIndex={0} type={1}", typeIndex, type?.Name);
			}
			if (type != null)
			{
				return (ChatMessageBase)Activator.CreateInstance(type);
			}
			return null;
		}

		public override void Serialize(NetworkWriter writer)
		{
		}

		public override void Deserialize(NetworkReader reader)
		{
		}
	}
	public class ColoredTokenChatMessage : SubjectChatMessage
	{
		private static readonly string[] empty = new string[0];

		public string[] paramTokens = empty;

		public Color32[] paramColors = new Color32[0];

		public override string ConstructChatString()
		{
			string @string = Language.GetString(GetResolvedToken());
			string subjectName = GetSubjectName();
			string[] array = new string[1 + paramTokens.Length];
			array[0] = subjectName;
			Array.Copy(paramTokens, 0, array, 1, paramTokens.Length);
			for (int i = 1; i < array.Length; i++)
			{
				int num = i - 1;
				if (num < paramColors.Length)
				{
					array[i] = Util.GenerateColoredString(Language.GetString(array[i]), paramColors[num]);
				}
				else
				{
					array[i] = Language.GetString(array[i]);
				}
			}
			object[] args = array;
			return string.Format(@string, args);
		}

		public override void Serialize(NetworkWriter writer)
		{
			base.Serialize(writer);
			writer.Write((byte)paramTokens.Length);
			for (int i = 0; i < paramTokens.Length; i++)
			{
				writer.Write(paramTokens[i]);
			}
			writer.Write((byte)paramColors.Length);
			for (int j = 0; j < paramColors.Length; j++)
			{
				writer.Write(paramColors[j]);
			}
		}

		public override void Deserialize(NetworkReader reader)
		{
			base.Deserialize(reader);
			paramTokens = new string[reader.ReadByte()];
			for (int i = 0; i < paramTokens.Length; i++)
			{
				paramTokens[i] = reader.ReadString();
			}
			paramColors = new Color32[reader.ReadByte()];
			for (int j = 0; j < paramColors.Length; j++)
			{
				paramColors[j] = reader.ReadColor32();
			}
		}
	}
	public class SubjectChatMessage : ChatMessageBase
	{
		private GameObject subjectNetworkUserObject;

		private GameObject subjectCharacterBodyGameObject;

		public string baseToken;

		private MemoizedGetComponent<NetworkUser> subjectNetworkUserGetComponent;

		private MemoizedGetComponent<CharacterBody> subjectCharacterBodyGetComponent;

		public NetworkUser subjectAsNetworkUser
		{
			get
			{
				return subjectNetworkUserGetComponent.Get(subjectNetworkUserObject);
			}
			set
			{
				subjectNetworkUserObject = (value ? value.gameObject : null);
				CharacterBody characterBody = null;
				if ((bool)value)
				{
					characterBody = value.GetCurrentBody();
				}
				subjectCharacterBodyGameObject = (characterBody ? characterBody.gameObject : null);
			}
		}

		public CharacterBody subjectAsCharacterBody
		{
			get
			{
				return subjectCharacterBodyGetComponent.Get(subjectCharacterBodyGameObject);
			}
			set
			{
				subjectCharacterBodyGameObject = (value ? value.gameObject : null);
				subjectNetworkUserObject = Util.LookUpBodyNetworkUser(value)?.gameObject;
			}
		}

		protected string GetSubjectName()
		{
			if ((bool)subjectAsNetworkUser)
			{
				return Util.EscapeRichTextForTextMeshPro(subjectAsNetworkUser.userName);
			}
			if ((bool)subjectAsCharacterBody)
			{
				return subjectAsCharacterBody.GetDisplayName();
			}
			return "???";
		}

		protected bool IsSecondPerson()
		{
			if (LocalUserManager.readOnlyLocalUsersList.Count == 1 && (bool)subjectAsNetworkUser && subjectAsNetworkUser.localUser != null)
			{
				return true;
			}
			return false;
		}

		protected string GetResolvedToken()
		{
			if (!IsSecondPerson())
			{
				return baseToken;
			}
			return baseToken + "_2P";
		}

		public override string ConstructChatString()
		{
			return string.Format(Language.GetString(GetResolvedToken()), GetSubjectName());
		}

		public override void Serialize(NetworkWriter writer)
		{
			((MessageBase)this).Serialize(writer);
			writer.Write(subjectNetworkUserObject);
			writer.Write(subjectCharacterBodyGameObject);
			writer.Write(baseToken);
		}

		public override void Deserialize(NetworkReader reader)
		{
			((MessageBase)this).Deserialize(reader);
			subjectNetworkUserObject = reader.ReadGameObject();
			subjectCharacterBodyGameObject = reader.ReadGameObject();
			baseToken = reader.ReadString();
		}
	}
	public class ColorCatalog
	{
		public enum ColorIndex
		{
			None,
			Tier1Item,
			Tier2Item,
			Tier3Item,
			LunarItem,
			Equipment,
			Interactable,
			Teleporter,
			Money,
			Blood,
			Unaffordable,
			Unlockable,
			LunarCoin,
			BossItem,
			Error,
			EasyDifficulty,
			NormalDifficulty,
			HardDifficulty,
			Tier1ItemDark,
			Tier2ItemDark,
			Tier3ItemDark,
			LunarItemDark,
			BossItemDark,
			WIP,
			Artifact,
			VoidItem,
			VoidItemDark,
			VoidCoin,
			Count
		}

		private static readonly Color32[] indexToColor32;

		private static readonly string[] indexToHexString;

		private static readonly UnityEngine.Color[] multiplayerColors;

		static ColorCatalog()
		{
			indexToColor32 = new Color32[28];
			indexToHexString = new string[28];
			multiplayerColors = new UnityEngine.Color[4]
			{
				new Color32(252, 62, 62, byte.MaxValue),
				new Color32(62, 109, 252, byte.MaxValue),
				new Color32(129, 252, 62, byte.MaxValue),
				new Color32(252, 241, 62, byte.MaxValue)
			};
			indexToColor32[1] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			indexToColor32[2] = new Color32(119, byte.MaxValue, 23, byte.MaxValue);
			indexToColor32[3] = new Color32(231, 84, 58, byte.MaxValue);
			indexToColor32[4] = new Color32(48, 127, byte.MaxValue, byte.MaxValue);
			indexToColor32[5] = new Color32(byte.MaxValue, 128, 0, byte.MaxValue);
			indexToColor32[6] = new Color32(235, 232, 122, byte.MaxValue);
			indexToColor32[7] = new Color32(231, 84, 58, byte.MaxValue);
			indexToColor32[8] = new Color32(239, 235, 26, byte.MaxValue);
			indexToColor32[9] = new Color32(206, 41, 41, byte.MaxValue);
			indexToColor32[10] = new Color32(100, 100, 100, byte.MaxValue);
			indexToColor32[11] = Color32.Lerp(new Color32(142, 56, 206, byte.MaxValue), new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue), 0.575f);
			indexToColor32[12] = new Color32(173, 189, 250, byte.MaxValue);
			indexToColor32[13] = UnityEngine.Color.yellow;
			indexToColor32[14] = new Color32(byte.MaxValue, 0, byte.MaxValue, byte.MaxValue);
			indexToColor32[15] = new Color32(106, 170, 95, byte.MaxValue);
			indexToColor32[16] = new Color32(173, 117, 80, byte.MaxValue);
			indexToColor32[17] = new Color32(142, 49, 49, byte.MaxValue);
			indexToColor32[18] = new Color32(193, 193, 193, byte.MaxValue);
			indexToColor32[19] = new Color32(88, 149, 88, byte.MaxValue);
			indexToColor32[20] = new Color32(142, 49, 49, byte.MaxValue);
			indexToColor32[21] = new Color32(76, 84, 144, byte.MaxValue);
			indexToColor32[22] = new Color32(189, 180, 60, byte.MaxValue);
			indexToColor32[23] = new Color32(200, 80, 0, byte.MaxValue);
			indexToColor32[24] = new Color32(140, 114, 219, byte.MaxValue);
			indexToColor32[25] = new Color32(237, 127, 205, byte.MaxValue);
			indexToColor32[26] = new Color32(163, 77, 132, byte.MaxValue);
			indexToColor32[27] = new Color32(244, 173, 250, byte.MaxValue);
			for (ColorIndex colorIndex = ColorIndex.None; colorIndex < ColorIndex.Count; colorIndex++)
			{
				indexToHexString[(int)colorIndex] = Util.RGBToHex(indexToColor32[(int)colorIndex]);
			}
		}

		public static Color32 GetColor(ColorIndex colorIndex)
		{
			if (colorIndex < ColorIndex.None || colorIndex >= ColorIndex.Count)
			{
				colorIndex = ColorIndex.Error;
			}
			return indexToColor32[(int)colorIndex];
		}

		public static string GetColorHexString(ColorIndex colorIndex)
		{
			if (colorIndex < ColorIndex.None || colorIndex >= ColorIndex.Count)
			{
				colorIndex = ColorIndex.Error;
			}
			return indexToHexString[(int)colorIndex];
		}

		public static UnityEngine.Color GetMultiplayerColor(int playerSlot)
		{
			if (playerSlot >= 0 && playerSlot < multiplayerColors.Length)
			{
				return multiplayerColors[playerSlot];
			}
			return UnityEngine.Color.black;
		}
	}
	public static class CommonLanguageTokens
	{
		public static string ok = "OK";

		public static string cancel = "CANCEL";

		public static string optionRebindDialogTitle = "OPTION_REBIND_DIALOG_TITLE";

		public static string optionRebindDialogDescription = "OPTION_REBIND_DIALOG_DESCRIPTION";
	}
	public static class CommonShaderProperties
	{
		public static readonly int _FlashColor = Shader.PropertyToID("_FlashColor");

		public static readonly int _Fade = Shader.PropertyToID("_Fade");

		public static readonly int _EliteIndex = Shader.PropertyToID("_EliteIndex");

		public static readonly int _LimbPrimeMask = Shader.PropertyToID("_LimbPrimeMask");

		public static readonly int _ExternalAlpha = Shader.PropertyToID("_ExternalAlpha");
	}
	public enum CostTypeIndex
	{
		None,
		Money,
		PercentHealth,
		LunarCoin,
		WhiteItem,
		GreenItem,
		RedItem,
		Equipment,
		VolatileBattery,
		LunarItemOrEquipment,
		BossItem,
		ArtifactShellKillerItem,
		TreasureCacheItem,
		TreasureCacheVoidItem,
		VoidCoin,
		SoulCost,
		Count
	}
	public class CostTypeDef
	{
		public delegate void BuildCostStringDelegate(CostTypeDef costTypeDef, BuildCostStringContext context);

		public struct BuildCostStringContext
		{
			public StringBuilder stringBuilder;

			public int cost;
		}

		public delegate Color32 GetCostColorDelegate(CostTypeDef costTypeDef, GetCostColorContext context);

		public struct GetCostColorContext
		{
			public bool forWorldDisplay;
		}

		public delegate void BuildCostStringStyledDelegate(CostTypeDef costTypeDef, BuildCostStringStyledContext context);

		public struct BuildCostStringStyledContext
		{
			public StringBuilder stringBuilder;

			public int cost;

			public bool forWorldDisplay;

			public bool includeColor;
		}

		public delegate bool IsAffordableDelegate(CostTypeDef costTypeDef, IsAffordableContext context);

		public struct IsAffordableContext
		{
			public int cost;

			public Interactor activator;
		}

		public delegate void PayCostDelegate(CostTypeDef costTypeDef, PayCostContext context);

		public struct PayCostContext
		{
			public int cost;

			public Interactor activator;

			public CharacterBody activatorBody;

			public CharacterMaster activatorMaster;

			public GameObject purchasedObject;

			public PayCostResults results;

			public Xoroshiro128Plus rng;

			public ItemIndex avoidedItemIndex;
		}

		public class PayCostResults
		{
			public List<ItemIndex> itemsTaken = new List<ItemIndex>();

			public List<EquipmentIndex> equipmentTaken = new List<EquipmentIndex>();
		}

		public string name;

		public ItemTier itemTier = ItemTier.NoTier;

		public ColorCatalog.ColorIndex colorIndex = ColorCatalog.ColorIndex.Error;

		public string costStringFormatToken;

		public string costStringStyle;

		public bool saturateWorldStyledCostString = true;

		public bool darkenWorldStyledCostString = true;

		public BuildCostStringDelegate buildCostString { private get; set; } = BuildCostStringDefault;


		public GetCostColorDelegate getCostColor { private get; set; } = GetCostColorDefault;


		public BuildCostStringStyledDelegate buildCostStringStyled { private get; set; } = BuildCostStringStyledDefault;


		public IsAffordableDelegate isAffordable { private get; set; }

		public PayCostDelegate payCost { private get; set; }

		public void BuildCostString(int cost, [NotNull] StringBuilder stringBuilder)
		{
			buildCostString(this, new BuildCostStringContext
			{
				cost = cost,
				stringBuilder = stringBuilder
			});
		}

		public static void BuildCostStringDefault(CostTypeDef costTypeDef, BuildCostStringContext context)
		{
			context.stringBuilder.Append(Language.GetStringFormatted(costTypeDef.costStringFormatToken, context.cost));
		}

		public Color32 GetCostColor(bool forWorldDisplay)
		{
			return getCostColor(this, new GetCostColorContext
			{
				forWorldDisplay = forWorldDisplay
			});
		}

		public static Color32 GetCostColorDefault(CostTypeDef costTypeDef, GetCostColorContext context)
		{
			Color32 color = ColorCatalog.GetColor(costTypeDef.colorIndex);
			if (context.forWorldDisplay)
			{
				UnityEngine.Color.RGBToHSV(color, out var H, out var S, out var V);
				if (costTypeDef.saturateWorldStyledCostString && S > 0f)
				{
					S = 1f;
				}
				if (costTypeDef.darkenWorldStyledCostString)
				{
					V *= 0.5f;
				}
				color = UnityEngine.Color.HSVToRGB(H, S, V);
			}
			return color;
		}

		public void BuildCostStringStyled(int cost, [NotNull] StringBuilder stringBuilder, bool forWorldDisplay, bool includeColor = true)
		{
			buildCostStringStyled(this, new BuildCostStringStyledContext
			{
				cost = cost,
				forWorldDisplay = forWorldDisplay,
				stringBuilder = stringBuilder,
				includeColor = includeColor
			});
		}

		public static void BuildCostStringStyledDefault(CostTypeDef costTypeDef, BuildCostStringStyledContext context)
		{
			StringBuilder stringBuilder = context.stringBuilder;
			stringBuilder.Append("<nobr>");
			if (costTypeDef.costStringStyle != null)
			{
				stringBuilder.Append("<style=");
				stringBuilder.Append(costTypeDef.costStringStyle);
				stringBuilder.Append(">");
			}
			if (context.includeColor)
			{
				Color32 costColor = costTypeDef.GetCostColor(context.forWorldDisplay);
				stringBuilder.Append("<color=#");
				stringBuilder.AppendColor32RGBHexValues(costColor);
				stringBuilder.Append(">");
			}
			costTypeDef.BuildCostString(context.cost, context.stringBuilder);
			if (context.includeColor)
			{
				stringBuilder.Append("</color>");
			}
			if (costTypeDef.costStringStyle != null)
			{
				stringBuilder.Append("</style>");
			}
			stringBuilder.Append("</nobr>");
		}

		public bool IsAffordable(int cost, Interactor activator)
		{
			return isAffordable(this, new IsAffordableContext
			{
				cost = cost,
				activator = activator
			});
		}

		public PayCostResults PayCost(int cost, Interactor activator, GameObject purchasedObject, Xoroshiro128Plus rng, ItemIndex avoidedItemIndex)
		{
			PayCostResults payCostResults = new PayCostResults();
			CharacterBody component = activator.GetComponent<CharacterBody>();
			payCost(this, new PayCostContext
			{
				cost = cost,
				activator = activator,
				activatorBody = component,
				activatorMaster = (component ? component.master : null),
				purchasedObject = purchasedObject,
				results = payCostResults,
				rng = rng,
				avoidedItemIndex = avoidedItemIndex
			});
			return payCostResults;
		}
	}
	public static class CostTypeCatalog
	{
		private static class LunarItemOrEquipmentCostTypeHelper
		{
			private static ItemIndex[] lunarItemIndices = Array.Empty<ItemIndex>();

			private static EquipmentIndex[] lunarEquipmentIndices = Array.Empty<EquipmentIndex>();

			public static bool IsAffordable(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
			{
				CharacterBody component = context.activator.GetComponent<CharacterBody>();
				if (!component)
				{
					return false;
				}
				Inventory inventory = component.inventory;
				if (!inventory)
				{
					return false;
				}
				int cost = context.cost;
				int num = 0;
				for (int i = 0; i < lunarItemIndices.Length; i++)
				{
					int itemCount = inventory.GetItemCount(lunarItemIndices[i]);
					num += itemCount;
					if (num >= cost)
					{
						return true;
					}
				}
				int j = 0;
				for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++)
				{
					EquipmentState equipment = inventory.GetEquipment((uint)j);
					for (int k = 0; k < lunarEquipmentIndices.Length; k++)
					{
						if (equipment.equipmentIndex == lunarEquipmentIndices[k])
						{
							num++;
							if (num >= cost)
							{
								return true;
							}
						}
					}
				}
				return false;
			}

			public static void PayCost(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
			{
				Inventory inventory = context.activator.GetComponent<CharacterBody>().inventory;
				int cost = context.cost;
				int itemWeight = 0;
				int equipmentWeight = 0;
				for (int i = 0; i < lunarItemIndices.Length; i++)
				{
					ItemIndex itemIndex = lunarItemIndices[i];
					int itemCount = inventory.GetItemCount(itemIndex);
					itemWeight += itemCount;
				}
				int j = 0;
				for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++)
				{
					EquipmentState equipment = inventory.GetEquipment((uint)j);
					if (Array.IndexOf(lunarEquipmentIndices, equipment.equipmentIndex) != -1)
					{
						int num = equipmentWeight + 1;
						equipmentWeight = num;
					}
				}
				int totalWeight = itemWeight + equipmentWeight;
				for (int k = 0; k < cost; k++)
				{
					TakeOne();
				}
				MultiShopCardUtils.OnNonMoneyPurchase(context);
				void TakeOne()
				{
					float nextNormalizedFloat = context.rng.nextNormalizedFloat;
					float num2 = (float)itemWeight / (float)totalWeight;
					if (nextNormalizedFloat < num2)
					{
						int num3 = Mathf.FloorToInt(Util.Remap(Util.Remap(nextNormalizedFloat, 0f, num2, 0f, 1f), 0f, 1f, 0f, itemWeight));
						int num4 = 0;
						for (int l = 0; l < lunarItemIndices.Length; l++)
						{
							ItemIndex itemIndex2 = lunarItemIndices[l];
							int itemCount2 = inventory.GetItemCount(itemIndex2);
							num4 += itemCount2;
							if (num3 < num4)
							{
								inventory.RemoveItem(itemIndex2);
								context.results.itemsTaken.Add(itemIndex2);
								break;
							}
						}
					}
					else
					{
						int num5 = Mathf.FloorToInt(Util.Remap(Util.Remap(nextNormalizedFloat, num2, 1f, 0f, 1f), 0f, 1f, 0f, equipmentWeight));
						int num6 = 0;
						for (int m = 0; m < inventory.GetEquipmentSlotCount(); m++)
						{
							EquipmentIndex equipmentIndex = inventory.GetEquipment((uint)m).equipmentIndex;
							if (Array.IndexOf(lunarEquipmentIndices, equipmentIndex) != -1)
							{
								num6++;
								if (num5 < num6)
								{
									inventory.SetEquipment(EquipmentState.empty, (uint)m);
									context.results.equipmentTaken.Add(equipmentIndex);
								}
							}
						}
					}
				}
			}

			private static void PayOne(Inventory inventory)
			{
				new WeightedSelection<ItemIndex>(lunarItemIndices.Length);
				new WeightedSelection<uint>(inventory.GetEquipmentSlotCount());
				int num = 0;
				int num2 = 0;
				for (int i = 0; i < lunarItemIndices.Length; i++)
				{
					ItemIndex itemIndex = lunarItemIndices[i];
					int itemCount = inventory.GetItemCount(itemIndex);
					num += itemCount;
				}
				int j = 0;
				for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++)
				{
					EquipmentState equipment = inventory.GetEquipment((uint)j);
					if (Array.IndexOf(lunarEquipmentIndices, equipment.equipmentIndex) != -1)
					{
						num2++;
					}
				}
			}

			[SystemInitializer(new Type[]
			{
				typeof(ItemCatalog),
				typeof(EquipmentCatalog)
			})]
			private static void Init()
			{
				lunarItemIndices = ItemCatalog.lunarItemList.ToArray();
				lunarEquipmentIndices = EquipmentCatalog.equipmentList.Where((EquipmentIndex v) => EquipmentCatalog.GetEquipmentDef(v).isLunar).ToArray();
			}
		}

		private static CostTypeDef[] costTypeDefs;

		public static readonly CatalogModHelper<CostTypeDef> modHelper = new CatalogModHelper<CostTypeDef>(delegate(int i, CostTypeDef def)
		{
			Register((CostTypeIndex)i, def);
		}, (CostTypeDef v) => v.name);

		public static int costTypeCount => costTypeDefs.Length;

		private static void Register(CostTypeIndex costType, CostTypeDef costTypeDef)
		{
			if (costType < CostTypeIndex.Count)
			{
				costTypeDef.name = costType.ToString();
			}
			costTypeDefs[(int)costType] = costTypeDef;
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			costTypeDefs = new CostTypeDef[16];
			Register(CostTypeIndex.None, new CostTypeDef
			{
				buildCostString = delegate(CostTypeDef costTypeDef, CostTypeDef.BuildCostStringContext context)
				{
					context.stringBuilder.Append("");
				},
				isAffordable = (CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context) => true,
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					MultiShopCardUtils.OnNonMoneyPurchase(context);
				}
			});
			Register(CostTypeIndex.Money, new CostTypeDef
			{
				costStringFormatToken = "COST_MONEY_FORMAT",
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					CharacterBody component14 = context.activator.GetComponent<CharacterBody>();
					if ((bool)component14)
					{
						CharacterMaster master2 = component14.master;
						if ((bool)master2)
						{
							return master2.money >= context.cost;
						}
					}
					return false;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					if ((bool)context.activatorMaster)
					{
						context.activatorMaster.money -= (uint)context.cost;
						MultiShopCardUtils.OnMoneyPurchase(context);
					}
				},
				colorIndex = ColorCatalog.ColorIndex.Money
			});
			Register(CostTypeIndex.PercentHealth, new CostTypeDef
			{
				costStringFormatToken = "COST_PERCENTHEALTH_FORMAT",
				saturateWorldStyledCostString = false,
				darkenWorldStyledCostString = true,
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					HealthComponent component13 = context.activator.GetComponent<HealthComponent>();
					return (bool)component13 && component13.combinedHealth / component13.fullCombinedHealth * 100f >= (float)context.cost;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					HealthComponent component12 = context.activator.GetComponent<HealthComponent>();
					if ((bool)component12)
					{
						float combinedHealth2 = component12.combinedHealth;
						float num3 = component12.fullCombinedHealth * (float)context.cost / 100f;
						if (combinedHealth2 > num3)
						{
							component12.TakeDamage(new DamageInfo
							{
								damage = num3,
								attacker = context.purchasedObject,
								position = context.purchasedObject.transform.position,
								damageType = (DamageType.NonLethal | DamageType.BypassArmor)
							});
							MultiShopCardUtils.OnNonMoneyPurchase(context);
						}
					}
				},
				colorIndex = ColorCatalog.ColorIndex.Blood
			});
			Register(CostTypeIndex.LunarCoin, new CostTypeDef
			{
				costStringFormatToken = "COST_LUNARCOIN_FORMAT",
				saturateWorldStyledCostString = false,
				darkenWorldStyledCostString = true,
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					NetworkUser networkUser2 = Util.LookUpBodyNetworkUser(context.activator.gameObject);
					return (bool)networkUser2 && networkUser2.lunarCoins >= context.cost;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					NetworkUser networkUser = Util.LookUpBodyNetworkUser(context.activator.gameObject);
					if ((bool)networkUser)
					{
						networkUser.DeductLunarCoins((uint)context.cost);
						MultiShopCardUtils.OnNonMoneyPurchase(context);
					}
				},
				colorIndex = ColorCatalog.ColorIndex.LunarCoin
			});
			Register(CostTypeIndex.VoidCoin, new CostTypeDef
			{
				costStringFormatToken = "COST_VOIDCOIN_FORMAT",
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					CharacterBody component11 = context.activator.GetComponent<CharacterBody>();
					if ((bool)component11)
					{
						CharacterMaster master = component11.master;
						if ((bool)master)
						{
							return master.voidCoins >= context.cost;
						}
					}
					return false;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					if ((bool)context.activatorMaster)
					{
						context.activatorMaster.voidCoins -= (uint)context.cost;
						MultiShopCardUtils.OnNonMoneyPurchase(context);
					}
				},
				saturateWorldStyledCostString = false,
				darkenWorldStyledCostString = true,
				colorIndex = ColorCatalog.ColorIndex.VoidCoin
			});
			Register(CostTypeIndex.SoulCost, new CostTypeDef
			{
				costStringFormatToken = "COST_SOULCOST_FORMAT",
				saturateWorldStyledCostString = false,
				darkenWorldStyledCostString = true,
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					HealthComponent component10 = context.activator.GetComponent<HealthComponent>();
					return (bool)component10 && component10.combinedHealth / component10.fullCombinedHealth * 100f >= (float)context.cost;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					HealthComponent component9 = context.activator.GetComponent<HealthComponent>();
					if ((bool)component9)
					{
						float combinedHealth = component9.combinedHealth;
						float num2 = component9.fullCombinedHealth * (float)context.cost / 100f;
						int newCount = context.cost / 10;
						if (combinedHealth > num2)
						{
							component9.body.SetBuffCount(DLC2Content.Buffs.SoulCost.buffIndex, newCount);
							MultiShopCardUtils.OnNonMoneyPurchase(context);
						}
					}
				},
				colorIndex = ColorCatalog.ColorIndex.BossItem
			});
			Register(CostTypeIndex.WhiteItem, new CostTypeDef
			{
				costStringFormatToken = "COST_ITEM_FORMAT",
				isAffordable = IsAffordableItem,
				payCost = PayCostItems,
				colorIndex = ColorCatalog.ColorIndex.Tier1Item,
				itemTier = ItemTier.Tier1
			});
			Register(CostTypeIndex.GreenItem, new CostTypeDef
			{
				costStringFormatToken = "COST_ITEM_FORMAT",
				saturateWorldStyledCostString = true,
				isAffordable = IsAffordableItem,
				payCost = PayCostItems,
				colorIndex = ColorCatalog.ColorIndex.Tier2Item,
				itemTier = ItemTier.Tier2
			});
			Register(CostTypeIndex.RedItem, new CostTypeDef
			{
				costStringFormatToken = "COST_ITEM_FORMAT",
				saturateWorldStyledCostString = false,
				darkenWorldStyledCostString = true,
				isAffordable = IsAffordableItem,
				payCost = PayCostItems,
				colorIndex = ColorCatalog.ColorIndex.Tier3Item,
				itemTier = ItemTier.Tier3
			});
			Register(CostTypeIndex.BossItem, new CostTypeDef
			{
				costStringFormatToken = "COST_ITEM_FORMAT",
				darkenWorldStyledCostString = true,
				isAffordable = IsAffordableItem,
				payCost = PayCostItems,
				colorIndex = ColorCatalog.ColorIndex.BossItem,
				itemTier = ItemTier.Boss
			});
			Register(CostTypeIndex.Equipment, new CostTypeDef
			{
				costStringFormatToken = "COST_EQUIPMENT_FORMAT",
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					CharacterBody component8 = context.activator.gameObject.GetComponent<CharacterBody>();
					if ((bool)component8)
					{
						Inventory inventory8 = component8.inventory;
						if ((bool)inventory8)
						{
							return inventory8.currentEquipmentIndex != EquipmentIndex.None;
						}
					}
					return false;
				},
				payCost = PayEquipment,
				colorIndex = ColorCatalog.ColorIndex.Equipment
			});
			Register(CostTypeIndex.VolatileBattery, new CostTypeDef
			{
				costStringFormatToken = "COST_VOLATILEBATTERY_FORMAT",
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					CharacterBody component7 = context.activator.gameObject.GetComponent<CharacterBody>();
					if ((bool)component7)
					{
						Inventory inventory7 = component7.inventory;
						if ((bool)inventory7)
						{
							return inventory7.currentEquipmentIndex == RoR2Content.Equipment.QuestVolatileBattery.equipmentIndex;
						}
					}
					return false;
				},
				payCost = PayEquipment,
				colorIndex = ColorCatalog.ColorIndex.Equipment
			});
			Register(CostTypeIndex.LunarItemOrEquipment, new CostTypeDef
			{
				costStringFormatToken = "COST_LUNAR_FORMAT",
				isAffordable = LunarItemOrEquipmentCostTypeHelper.IsAffordable,
				payCost = LunarItemOrEquipmentCostTypeHelper.PayCost,
				colorIndex = ColorCatalog.ColorIndex.LunarItem
			});
			Register(CostTypeIndex.ArtifactShellKillerItem, new CostTypeDef
			{
				costStringFormatToken = "COST_ARTIFACTSHELLKILLERITEM_FORMAT",
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					CharacterBody component6 = context.activator.gameObject.GetComponent<CharacterBody>();
					if ((bool)component6)
					{
						Inventory inventory6 = component6.inventory;
						if ((bool)inventory6)
						{
							return inventory6.GetItemCount(RoR2Content.Items.ArtifactKey) >= context.cost;
						}
					}
					return false;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					context.activatorBody.inventory.RemoveItem(RoR2Content.Items.ArtifactKey, context.cost);
					MultiShopCardUtils.OnNonMoneyPurchase(context);
				},
				colorIndex = ColorCatalog.ColorIndex.Artifact
			});
			Register(CostTypeIndex.TreasureCacheItem, new CostTypeDef
			{
				costStringFormatToken = "COST_TREASURECACHEITEM_FORMAT",
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					CharacterBody component5 = context.activator.gameObject.GetComponent<CharacterBody>();
					if ((bool)component5)
					{
						Inventory inventory5 = component5.inventory;
						if ((bool)inventory5)
						{
							return inventory5.GetItemCount(RoR2Content.Items.TreasureCache) >= context.cost;
						}
					}
					return false;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					context.activatorBody.inventory.RemoveItem(RoR2Content.Items.TreasureCache, context.cost);
					MultiShopCardUtils.OnNonMoneyPurchase(context);
				},
				colorIndex = ColorCatalog.ColorIndex.Tier1Item
			});
			Register(CostTypeIndex.TreasureCacheVoidItem, new CostTypeDef
			{
				costStringFormatToken = "COST_TREASURECACHEVOIDITEM_FORMAT",
				isAffordable = delegate(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
				{
					CharacterBody component4 = context.activator.gameObject.GetComponent<CharacterBody>();
					if ((bool)component4)
					{
						Inventory inventory4 = component4.inventory;
						if ((bool)inventory4)
						{
							return inventory4.GetItemCount(DLC1Content.Items.TreasureCacheVoid) >= context.cost;
						}
					}
					return false;
				},
				payCost = delegate(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
				{
					context.activatorBody.inventory.RemoveItem(DLC1Content.Items.TreasureCacheVoid, context.cost);
					MultiShopCardUtils.OnNonMoneyPurchase(context);
				},
				colorIndex = ColorCatalog.ColorIndex.VoidItem
			});
			modHelper.CollectAndRegisterAdditionalEntries(ref costTypeDefs);
			static bool IsAffordableItem(CostTypeDef costTypeDef, CostTypeDef.IsAffordableContext context)
			{
				CharacterBody component3 = context.activator.GetComponent<CharacterBody>();
				if ((bool)component3)
				{
					Inventory inventory3 = component3.inventory;
					if ((bool)inventory3)
					{
						return inventory3.HasAtLeastXTotalItemsOfTier(costTypeDef.itemTier, context.cost);
					}
				}
				return false;
			}
			static void PayCostItems(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
			{
				List<ItemIndex> itemsToTake;
				if ((bool)context.activatorBody)
				{
					Inventory inventory2 = context.activatorBody.inventory;
					if ((bool)inventory2)
					{
						itemsToTake = CollectionPool<ItemIndex, List<ItemIndex>>.RentCollection();
						WeightedSelection<ItemIndex> weightedSelection2 = new WeightedSelection<ItemIndex>();
						WeightedSelection<ItemIndex> weightedSelection3 = new WeightedSelection<ItemIndex>();
						WeightedSelection<ItemIndex> weightedSelection4 = new WeightedSelection<ItemIndex>();
						foreach (ItemIndex allItem in ItemCatalog.allItems)
						{
							if (allItem != context.avoidedItemIndex)
							{
								int itemCount = inventory2.GetItemCount(allItem);
								if (itemCount > 0)
								{
									ItemDef itemDef = ItemCatalog.GetItemDef(allItem);
									if (itemDef.tier == costTypeDef.itemTier)
									{
										(itemDef.ContainsTag(ItemTag.PriorityScrap) ? weightedSelection4 : (itemDef.ContainsTag(ItemTag.Scrap) ? weightedSelection3 : weightedSelection2)).AddChoice(allItem, itemCount);
									}
								}
							}
						}
						TakeItemsFromWeightedSelection(weightedSelection4);
						TakeItemsFromWeightedSelection(weightedSelection3);
						TakeItemsFromWeightedSelection(weightedSelection2);
						for (int i = itemsToTake.Count; i < context.cost; i++)
						{
							itemsToTake.Add(context.avoidedItemIndex);
						}
						bool flag = false;
						for (int j = 0; j < itemsToTake.Count; j++)
						{
							ItemIndex itemIndex = itemsToTake[j];
							context.results.itemsTaken.Add(itemIndex);
							if (itemIndex == DLC1Content.Items.RegeneratingScrap.itemIndex)
							{
								flag = true;
								inventory2.GiveItem(DLC1Content.Items.RegeneratingScrapConsumed);
								EntitySoundManager.EmitSoundServer(NetworkSoundEventCatalog.FindNetworkSoundEventIndex("Play_item_proc_regenScrap_consume"), context.activatorBody.gameObject);
								ModelLocator component = context.activatorBody.GetComponent<ModelLocator>();
								if ((bool)component)
								{
									Transform modelTransform = component.modelTransform;
									if ((bool)modelTransform)
									{
										CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
										if ((bool)component2)
										{
											List<GameObject> itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.RegeneratingScrap.itemIndex);
											if (itemDisplayObjects.Count > 0)
											{
												GameObject gameObject = itemDisplayObjects[0];
												GameObject effectPrefab = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/RegeneratingScrap/RegeneratingScrapExplosionDisplay.prefab").WaitForCompletion();
												EffectData effectData = new EffectData
												{
													origin = gameObject.transform.position,
													rotation = gameObject.transform.rotation
												};
												EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
											}
										}
									}
								}
								EffectManager.SimpleMuzzleFlash(Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/RegeneratingScrap/RegeneratingScrapExplosionInPrinter.prefab").WaitForCompletion(), context.purchasedObject, "DropPivot", transmit: true);
							}
							inventory2.RemoveItem(itemIndex);
						}
						if (flag)
						{
							CharacterMasterNotificationQueue.SendTransformNotification(context.activatorBody.master, DLC1Content.Items.RegeneratingScrap.itemIndex, DLC1Content.Items.RegeneratingScrapConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default);
						}
						CollectionPool<ItemIndex, List<ItemIndex>>.ReturnCollection(itemsToTake);
					}
				}
				MultiShopCardUtils.OnNonMoneyPurchase(context);
				void TakeItemsFromWeightedSelection(WeightedSelection<ItemIndex> weightedSelection)
				{
					while (weightedSelection.Count > 0 && itemsToTake.Count < context.cost)
					{
						int choiceIndex2 = weightedSelection.EvaluateToChoiceIndex(context.rng.nextNormalizedFloat);
						TakeItemFromWeightedSelection(weightedSelection, choiceIndex2);
					}
				}
			}
			static void PayEquipment(CostTypeDef costTypeDef, CostTypeDef.PayCostContext context)
			{
				Inventory inventory = context.activatorBody.inventory;
				EquipmentIndex equipmentIndex = inventory.GetEquipmentIndex();
				if ((bool)inventory)
				{
					inventory.SetEquipmentIndex(EquipmentIndex.None);
				}
				context.results.equipmentTaken.Add(equipmentIndex);
				MultiShopCardUtils.OnNonMoneyPurchase(context);
			}
			void TakeItemFromWeightedSelection(WeightedSelection<ItemIndex> weightedSelection, int choiceIndex)
			{
				WeightedSelection<ItemIndex>.ChoiceInfo choice = weightedSelection.GetChoice(choiceIndex);
				ItemIndex value = choice.value;
				int num = (int)choice.weight;
				num--;
				if (num <= 0)
				{
					weightedSelection.RemoveChoice(choiceIndex);
				}
				else
				{
					weightedSelection.ModifyChoiceWeight(choiceIndex, num);
				}
				P_2.itemsToTake.Add(value);
			}
		}

		public static CostTypeDef GetCostTypeDef(CostTypeIndex costTypeIndex)
		{
			return ArrayUtils.GetSafe(costTypeDefs, (int)costTypeIndex);
		}
	}
	public class CU8Content : IContentPackProvider
	{
		public static class Artifacts
		{
			public static ArtifactDef Devotion;

			public static ArtifactDef Delusion;
		}

		public static class Items
		{
			public static ItemDef LemurianHarness;
		}

		public static class ItemRelationshipTypes
		{
		}

		public static class Equipment
		{
		}

		public static class Buffs
		{
		}

		public static class Elites
		{
		}

		public static class GameEndings
		{
		}

		public static class Survivors
		{
		}

		public static class MiscPickups
		{
		}

		private ContentPack contentPack = new ContentPack();

		private static readonly string addressablesLabel = "ContentPack:RoR2.CU8";

		public string identifier => "RoR2.CU8";

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			contentPack.identifier = identifier;
			AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator(addressablesLabel);
			yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack);
			loadHelper.AddGenericOperation(delegate
			{
				ContentLoadHelper.PopulateTypeFields(typeof(Artifacts), contentPack.artifactDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs);
			}, 0.05f);
			while (loadHelper.coroutine.MoveNext())
			{
				args.ReportProgress(loadHelper.progress.value);
				yield return loadHelper.coroutine.Current;
			}
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			ContentPack.Copy(contentPack, args.output);
			yield break;
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			yield break;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/Animation Curve Asset")]
	public class AnimationCurveAsset : ScriptableObject
	{
		public AnimationCurve value;
	}
	[CreateAssetMenu(menuName = "RoR2/AssetCollection")]
	public class AssetCollection : ScriptableObject
	{
		public UnityEngine.Object[] assets = Array.Empty<UnityEngine.Object>();

		[ContextMenu("Add selected assets.")]
		private void AddSelectedAssets()
		{
			UnityEngine.Object[] additionalAssets = Array.Empty<UnityEngine.Object>();
			AddAssets(additionalAssets);
		}

		public void AddAssets(UnityEngine.Object[] additionalAssets)
		{
			int num = assets.Length;
			Array.Resize(ref assets, assets.Length + additionalAssets.Length);
			for (int i = 0; i < additionalAssets.Length; i++)
			{
				assets[num + i] = additionalAssets[i];
			}
		}
	}
	[Serializable]
	public class AssetReferenceScene : AssetReference
	{
		public AssetReferenceScene(string guid)
			: base(guid)
		{
		}

		public override bool ValidateAsset(string path)
		{
			if (base.ValidateAsset(path))
			{
				return path.EndsWith(".unity", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		public override bool ValidateAsset(UnityEngine.Object obj)
		{
			bool num = base.ValidateAsset(obj);
			bool flag = false;
			return num && flag;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SpawnCards/BodySpawnCard")]
	public class BodySpawnCard : SpawnCard
	{
		protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result)
		{
			UnityEngine.Vector3 position2 = position;
			position2.y += Util.GetBodyPrefabFootOffset(prefab);
			GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position2, rotation);
			NetworkServer.Spawn(gameObject);
			result.spawnedInstance = gameObject;
			result.success = true;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/BuffDef")]
	public class BuffDef : ScriptableObject
	{
		[Obsolete("BuffDef.iconPath is deprecated and no longer functions. Use .iconSprite instead.", false)]
		public string iconPath = "Textures/ItemIcons/texNullIcon";

		public Sprite iconSprite;

		public UnityEngine.Color buffColor = UnityEngine.Color.white;

		public bool canStack;

		public EliteDef eliteDef;

		public bool isDebuff;

		public bool ignoreGrowthNectar;

		public bool isCooldown;

		public bool isHidden;

		public NetworkSoundEventDef startSfx;

		public BuffIndex buffIndex { get; set; } = BuffIndex.None;


		public bool isElite => (object)eliteDef != null;

		protected void OnValidate()
		{
			ReplaceIconFromPathWithDirectReference();
		}

		[ContextMenu("Update iconPath to iconSprite")]
		private void ReplaceIconFromPathWithDirectReference()
		{
			string text = iconPath;
			if (!string.IsNullOrEmpty(text))
			{
				Sprite sprite = LegacyResourcesAPI.Load<Sprite>(text);
				if ((bool)sprite)
				{
					iconSprite = sprite;
					iconPath = string.Empty;
					EditorUtil.SetDirty(this);
				}
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/CharacterCameraParams")]
	public class CharacterCameraParams : ScriptableObject
	{
		[SerializeField]
		[HideInInspector]
		private int version;

		public CharacterCameraParamsData data;

		private static readonly float minPitchDefault = -70f;

		private static readonly float maxPitchDefault = 70f;

		private static readonly float wallCushionDefault = 0.1f;

		private static readonly float pivotVerticalOffsetDefault = 1.6f;

		private static readonly UnityEngine.Vector3 standardLocalCameraPosDefault = new UnityEngine.Vector3(0f, 0f, -5f);

		[Obsolete("Use data.minPitch instead.", false)]
		[ShowFieldObsolete]
		public float minPitch = minPitchDefault;

		[Obsolete("Use data.maxPitch instead.", false)]
		[ShowFieldObsolete]
		public float maxPitch = maxPitchDefault;

		[ShowFieldObsolete]
		[Obsolete("Use data.wallCushion instead.", false)]
		public float wallCushion = wallCushionDefault;

		[Obsolete("Use data.pivotVerticalOffset instead.", false)]
		[ShowFieldObsolete]
		public float pivotVerticalOffset = pivotVerticalOffsetDefault;

		[ShowFieldObsolete]
		[Obsolete("Use data.standardLocalCameraPos instead.", false)]
		public UnityEngine.Vector3 standardLocalCameraPos = standardLocalCameraPosDefault;

		private void Awake()
		{
			UpdateVersion();
		}

		private void UpdateVersion()
		{
			if (version < 1)
			{
				SetBlendableFromValue(out data.minPitch, minPitch, minPitchDefault);
				SetBlendableFromValue(out data.maxPitch, maxPitch, maxPitchDefault);
				SetBlendableFromValue(out data.wallCushion, wallCushion, wallCushionDefault);
				SetBlendableFromValue(out data.pivotVerticalOffset, pivotVerticalOffset, pivotVerticalOffsetDefault);
				SetBlendableFromValue(out data.idealLocalCameraPos, standardLocalCameraPos, standardLocalCameraPosDefault);
				version = 1;
			}
			else
			{
				minPitch = data.minPitch.value;
				maxPitch = data.maxPitch.value;
				wallCushion = data.wallCushion.value;
				pivotVerticalOffset = data.pivotVerticalOffset.value;
				standardLocalCameraPos = data.idealLocalCameraPos.value;
			}
		}

		private static void SetBlendableFromValue(out BlendableFloat dest, float src, float defaultValue)
		{
			dest.value = src;
			dest.alpha = (src.Equals(defaultValue) ? 0f : 1f);
		}

		private static void SetBlendableFromValue(out BlendableVector3 dest, UnityEngine.Vector3 src, UnityEngine.Vector3 defaultValue)
		{
			dest.value = src;
			dest.alpha = (src.Equals(defaultValue) ? 0f : 1f);
		}

		private static void SetBlendableFromValue(out BlendableBool dest, bool src, bool defaultValue)
		{
			dest.value = src;
			dest.alpha = (src.Equals(defaultValue) ? 0f : 1f);
		}
	}
	[Serializable]
	public struct CharacterCameraParamsData
	{
		public BlendableFloat minPitch;

		public BlendableFloat maxPitch;

		public BlendableFloat wallCushion;

		public BlendableFloat pivotVerticalOffset;

		public BlendableVector3 idealLocalCameraPos;

		public BlendableFloat fov;

		public BlendableBool isFirstPerson;

		public float overrideFirstPersonFadeDuration;

		public static readonly CharacterCameraParamsData basic = new CharacterCameraParamsData
		{
			minPitch = -70f,
			maxPitch = 70f,
			wallCushion = 0.1f,
			pivotVerticalOffset = 1.6f,
			idealLocalCameraPos = new UnityEngine.Vector3(0f, 0f, -5f),
			fov = new BlendableFloat
			{
				value = 60f,
				alpha = 0f
			},
			overrideFirstPersonFadeDuration = 0f
		};

		public static void Blend(in CharacterCameraParamsData src, ref CharacterCameraParamsData dest, float alpha)
		{
			BlendableFloat.Blend(in src.minPitch, ref dest.minPitch, alpha);
			BlendableFloat.Blend(in src.maxPitch, ref dest.maxPitch, alpha);
			BlendableFloat.Blend(in src.wallCushion, ref dest.wallCushion, alpha);
			BlendableFloat.Blend(in src.pivotVerticalOffset, ref dest.pivotVerticalOffset, alpha);
			BlendableVector3.Blend(in src.idealLocalCameraPos, ref dest.idealLocalCameraPos, alpha);
			BlendableFloat.Blend(in src.fov, ref dest.fov, alpha);
			BlendableBool.Blend(in src.isFirstPerson, ref dest.isFirstPerson, alpha);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SpawnCards/CharacterSpawnCard")]
	public class CharacterSpawnCard : SpawnCard, MasterSummon.IInventorySetupCallback
	{
		public bool noElites;

		public bool forbiddenAsBoss;

		[CanBeNull]
		[Tooltip("The loadout for any summoned character to use.")]
		[FormerlySerializedAs("loadout")]
		[SerializeField]
		private SerializableLoadout _loadout;

		[CanBeNull]
		[Tooltip("The inventory from which to initially paste into any summoned character's inventory. Will skip certain non-bequeathable items. This is usually not a good idea to set up in the editor, and is more reserved for runtime.")]
		public Inventory inventoryToCopy;

		[CanBeNull]
		public Func<ItemIndex, bool> inventoryItemCopyFilter;

		[Tooltip("The set of equipment to grant to any summoned character, after inventory copy.")]
		[NotNull]
		public EquipmentDef[] equipmentToGrant = Array.Empty<EquipmentDef>();

		[Tooltip("The set of items to grant to any summoned character, after inventory copy.")]
		[NotNull]
		public ItemCountPair[] itemsToGrant = Array.Empty<ItemCountPair>();

		[CanBeNull]
		protected Loadout runtimeLoadout;

		private static ResourceAvailability loadoutAvailability;

		[CanBeNull]
		public SerializableLoadout loadout
		{
			get
			{
				return _loadout;
			}
			set
			{
				if (_loadout != value)
				{
					_loadout = value;
					if (loadoutAvailability.available)
					{
						SetLoadoutFromSerializedLoadout();
					}
					else
					{
						loadoutAvailability.CallWhenAvailable(SetLoadoutFromSerializedLoadout);
					}
				}
			}
		}

		public void Awake()
		{
			if (!loadoutAvailability.available)
			{
				loadoutAvailability.CallWhenAvailable(SetLoadoutFromSerializedLoadout);
			}
			else
			{
				SetLoadoutFromSerializedLoadout();
			}
		}

		private void SetLoadoutFromSerializedLoadout()
		{
			SetLoadout(loadout);
		}

		private void SetLoadout([CanBeNull] SerializableLoadout serializableLoadout)
		{
			if (Application.isPlaying)
			{
				runtimeLoadout = ((serializableLoadout != null && !serializableLoadout.isEmpty) ? new Loadout() : null);
				if (runtimeLoadout != null)
				{
					serializableLoadout.Apply(runtimeLoadout);
				}
			}
		}

		[CanBeNull]
		protected virtual Loadout GetRuntimeLoadout()
		{
			return runtimeLoadout;
		}

		[CanBeNull]
		protected virtual Action<CharacterMaster> GetPreSpawnSetupCallback()
		{
			return null;
		}

		protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result)
		{
			MasterSummon masterSummon = new MasterSummon
			{
				masterPrefab = prefab,
				position = position,
				rotation = rotation,
				summonerBodyObject = directorSpawnRequest.summonerBodyObject,
				teamIndexOverride = directorSpawnRequest.teamIndexOverride,
				ignoreTeamMemberLimit = directorSpawnRequest.ignoreTeamMemberLimit,
				loadout = GetRuntimeLoadout(),
				inventoryToCopy = inventoryToCopy,
				inventoryItemCopyFilter = inventoryItemCopyFilter,
				inventorySetupCallback = this,
				preSpawnSetupCallback = GetPreSpawnSetupCallback(),
				useAmbientLevel = true
			};
			result.spawnedInstance = masterSummon.Perform()?.gameObject;
			result.success = result.spawnedInstance;
		}

		[SystemInitializer(new Type[] { typeof(Loadout) })]
		private static void Init()
		{
			loadoutAvailability.MakeAvailable();
		}

		void MasterSummon.IInventorySetupCallback.SetupSummonedInventory(MasterSummon masterSummon, Inventory summonedInventory)
		{
			SetupSummonedInventory(masterSummon, summonedInventory);
		}

		protected virtual void SetupSummonedInventory(MasterSummon masterSummon, Inventory summonedInventory)
		{
			for (int i = 0; i < equipmentToGrant.Length; i++)
			{
				EquipmentState equipment = summonedInventory.GetEquipment((uint)i);
				summonedInventory.SetEquipment(new EquipmentState(equipmentToGrant[i]?.equipmentIndex ?? EquipmentIndex.None, equipment.chargeFinishTime, equipment.charges), (uint)i);
			}
			for (int j = 0; j < itemsToGrant.Length; j++)
			{
				ItemCountPair itemCountPair = itemsToGrant[j];
				summonedInventory.GiveItem(itemCountPair.itemDef, itemCountPair.count);
			}
		}

		public void OnValidate()
		{
			if (occupyPosition)
			{
				UnityEngine.Debug.LogErrorFormat("{0} OccupyPosition=1.This is only intended for limited spawns, and will prevent spawning on this node in the future! Are ya sure? ", this);
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/DCCS/DccsPool")]
	public class DccsPool : ScriptableObject
	{
		[Serializable]
		public class PoolEntry : ISerializationCallbackReceiver
		{
			public DirectorCardCategorySelection dccs;

			[Tooltip("The weight of this entry relative to its siblings")]
			public float weight;

			[HideInInspector]
			[SerializeField]
			protected bool hasBeenSerialized;

			public void OnBeforeSerialize()
			{
				hasBeenSerialized = true;
			}

			public virtual void OnAfterDeserialize()
			{
				if (!hasBeenSerialized)
				{
					weight = 1f;
				}
			}
		}

		[Serializable]
		public class ConditionalPoolEntry : PoolEntry
		{
			[Tooltip("ALL expansions in this list must be enabled for this run for this entry to be considered.")]
			public ExpansionDef[] requiredExpansions;
		}

		[Serializable]
		public class Category : ISerializationCallbackReceiver
		{
			[Tooltip("A name to help identify this category")]
			public string name;

			[Tooltip("The weight of all entries in this category relative to the sibling categories.")]
			public float categoryWeight = 1f;

			[Tooltip("These entries are always considered.")]
			public PoolEntry[] alwaysIncluded;

			[Tooltip("These entries are only considered if their individual conditions are met.")]
			public ConditionalPoolEntry[] includedIfConditionsMet;

			[Tooltip("These entries are considered only if no entries from 'includedIfConditionsMet' have been included.")]
			public PoolEntry[] includedIfNoConditionsMet;

			[HideInInspector]
			[SerializeField]
			protected bool hasBeenSerialized;

			public void OnBeforeSerialize()
			{
				hasBeenSerialized = true;
			}

			public void OnAfterDeserialize()
			{
				if (!hasBeenSerialized)
				{
					categoryWeight = 1f;
				}
			}
		}

		[SerializeField]
		private Category[] poolCategories;

		internal DirectorCardCategorySelection TrySelectPool(string selectionName)
		{
			return poolCategories.FirstOrDefault((Category category) => category.includedIfConditionsMet.Any((ConditionalPoolEntry entry) => entry.dccs.name == selectionName))?.includedIfConditionsMet.First().dccs;
		}

		public WeightedSelection<DirectorCardCategorySelection> GenerateWeightedSelection()
		{
			WeightedSelection<DirectorCardCategorySelection> weightedSelection = new WeightedSelection<DirectorCardCategorySelection>();
			Category[] array = poolCategories;
			foreach (Category category in array)
			{
				float num = SumAllWeightsInCategory(category);
				if (!(num > 0f))
				{
					continue;
				}
				float num2 = category.categoryWeight / num;
				PoolEntry[] alwaysIncluded = category.alwaysIncluded;
				foreach (PoolEntry poolEntry in alwaysIncluded)
				{
					if (poolEntry.dccs.IsAvailable())
					{
						weightedSelection.AddChoice(poolEntry.dccs, poolEntry.weight * num2);
					}
				}
				bool flag = false;
				ConditionalPoolEntry[] includedIfConditionsMet = category.includedIfConditionsMet;
				foreach (ConditionalPoolEntry conditionalPoolEntry in includedIfConditionsMet)
				{
					if (conditionalPoolEntry.dccs.IsAvailable() && AreConditionsMet(conditionalPoolEntry))
					{
						weightedSelection.AddChoice(conditionalPoolEntry.dccs, conditionalPoolEntry.weight * num2);
						flag = true;
					}
				}
				if (flag)
				{
					continue;
				}
				alwaysIncluded = category.includedIfNoConditionsMet;
				foreach (PoolEntry poolEntry2 in alwaysIncluded)
				{
					if (poolEntry2.dccs.IsAvailable())
					{
						weightedSelection.AddChoice(poolEntry2.dccs, poolEntry2.weight * num2);
					}
				}
			}
			return weightedSelection;
		}

		private float SumAllWeightsInCategory(Category category)
		{
			float num = 0f;
			PoolEntry[] alwaysIncluded = category.alwaysIncluded;
			foreach (PoolEntry poolEntry in alwaysIncluded)
			{
				if (poolEntry.dccs.IsAvailable())
				{
					num += poolEntry.weight;
				}
			}
			bool flag = false;
			ConditionalPoolEntry[] includedIfConditionsMet = category.includedIfConditionsMet;
			foreach (ConditionalPoolEntry conditionalPoolEntry in includedIfConditionsMet)
			{
				if (conditionalPoolEntry.dccs.IsAvailable() && AreConditionsMet(conditionalPoolEntry))
				{
					num += conditionalPoolEntry.weight;
					flag = true;
				}
			}
			if (!flag)
			{
				alwaysIncluded = category.includedIfNoConditionsMet;
				foreach (PoolEntry poolEntry2 in alwaysIncluded)
				{
					if (poolEntry2.dccs.IsAvailable())
					{
						num += poolEntry2.weight;
					}
				}
			}
			return num;
		}

		private bool AreConditionsMet(ConditionalPoolEntry entry)
		{
			if (Run.instance != null)
			{
				ExpansionDef[] requiredExpansions = entry.requiredExpansions;
				foreach (ExpansionDef expansionDef in requiredExpansions)
				{
					if (!Run.instance.IsExpansionEnabled(expansionDef))
					{
						return false;
					}
				}
				return true;
			}
			return false;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/DCCS/DirectorCardCategorySelection")]
	public class DirectorCardCategorySelection : ScriptableObject
	{
		public delegate void CalcCardWeight(DirectorCard card, ref float weight);

		[Serializable]
		public struct Category
		{
			[Tooltip("A name to help identify this category")]
			public string name;

			public DirectorCard[] cards;

			public float selectionWeight;
		}

		public Category[] categories = Array.Empty<Category>();

		public static event CalcCardWeight calcCardWeight;

		public float SumAllWeightsInCategory(Category category)
		{
			float num = 0f;
			for (int i = 0; i < category.cards.Length; i++)
			{
				if (category.cards[i].IsAvailable())
				{
					num += (float)category.cards[i].selectionWeight;
				}
			}
			return num;
		}

		public int FindCategoryIndexByName(string categoryName)
		{
			for (int i = 0; i < categories.Length; i++)
			{
				if (string.CompareOrdinal(categories[i].name, categoryName) == 0)
				{
					return i;
				}
			}
			return -1;
		}

		public void CopyFrom([NotNull] DirectorCardCategorySelection src)
		{
			Category[] array = src.categories;
			Array.Resize(ref categories, src.categories.Length);
			for (int i = 0; i < categories.Length; i++)
			{
				ref Category reference = ref categories[i];
				reference = array[i];
				reference.cards = ArrayUtils.Clone(reference.cards);
			}
		}

		public WeightedSelection<DirectorCard> GenerateDirectorCardWeightedSelection()
		{
			WeightedSelection<DirectorCard> weightedSelection = new WeightedSelection<DirectorCard>();
			for (int i = 0; i < categories.Length; i++)
			{
				ref Category reference = ref categories[i];
				float num = SumAllWeightsInCategory(reference);
				float num2 = reference.selectionWeight / num;
				if (!(num > 0f))
				{
					continue;
				}
				DirectorCard[] cards = reference.cards;
				foreach (DirectorCard directorCard in cards)
				{
					if (directorCard.IsAvailable())
					{
						float weight = (float)directorCard.selectionWeight * num2;
						DirectorCardCategorySelection.calcCardWeight?.Invoke(directorCard, ref weight);
						weightedSelection.AddChoice(directorCard, weight);
					}
				}
			}
			return weightedSelection;
		}

		public void Clear()
		{
			categories = Array.Empty<Category>();
		}

		public int AddCategory(string name, float selectionWeight)
		{
			Category category = default(Category);
			category.name = name;
			category.cards = Array.Empty<DirectorCard>();
			category.selectionWeight = selectionWeight;
			Category value = category;
			ArrayUtils.ArrayAppend(ref categories, in value);
			return categories.Length - 1;
		}

		public int AddCard(int categoryIndex, DirectorCard card)
		{
			if ((uint)categoryIndex >= categories.Length)
			{
				throw new ArgumentOutOfRangeException("categoryIndex");
			}
			ref DirectorCard[] cards = ref categories[categoryIndex].cards;
			ArrayUtils.ArrayAppend(ref cards, in card);
			return cards.Length - 1;
		}

		public void RemoveCardsThatFailFilter(Predicate<DirectorCard> predicate)
		{
			for (int i = 0; i < categories.Length; i++)
			{
				ref Category reference = ref categories[i];
				for (int num = reference.cards.Length - 1; num >= 0; num--)
				{
					DirectorCard obj = reference.cards[num];
					if (!predicate(obj))
					{
						ArrayUtils.ArrayRemoveAtAndResize(ref reference.cards, num);
					}
				}
			}
		}

		public virtual bool IsAvailable()
		{
			return true;
		}

		public virtual void OnSelected(ClassicStageInfo stageInfo)
		{
		}

		public void OnValidate()
		{
			for (int i = 0; i < categories.Length; i++)
			{
				Category category = categories[i];
				if (category.selectionWeight <= 0f)
				{
					UnityEngine.Debug.LogErrorFormat("'{0}' in '{1}' has no weight!", category.name, this);
				}
				for (int j = 0; j < category.cards.Length; j++)
				{
					DirectorCard directorCard = category.cards[j];
					if ((float)directorCard.selectionWeight <= 0f)
					{
						UnityEngine.Debug.LogErrorFormat("'{0}' in '{1}' has no weight!", directorCard.spawnCard.name, this);
					}
				}
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/EliteDef")]
	public class EliteDef : ScriptableObject
	{
		public string modifierToken;

		public EquipmentDef eliteEquipmentDef;

		public Color32 color;

		public int shaderEliteRampIndex = -1;

		public float healthBoostCoefficient = 1f;

		public float damageBoostCoefficient = 1f;

		public EliteIndex eliteIndex { get; set; } = EliteIndex.None;


		public bool IsAvailable()
		{
			if ((bool)eliteEquipmentDef)
			{
				if ((bool)Run.instance)
				{
					return !Run.instance.IsEquipmentExpansionLocked(eliteEquipmentDef.equipmentIndex);
				}
				return false;
			}
			return true;
		}

		[ConCommand(commandName = "elites_migrate", flags = ConVarFlags.None, helpText = "Generates EliteDef assets from the existing catalog entries.")]
		private static void CCElitesMigrate(ConCommandArgs args)
		{
			for (EliteIndex eliteIndex = (EliteIndex)0; (int)eliteIndex < EliteCatalog.eliteList.Count; eliteIndex++)
			{
				EditorUtil.CopyToScriptableObject<EliteDef, EliteDef>(EliteCatalog.GetEliteDef(eliteIndex), "Assets/RoR2/Resources/EliteDefs/");
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/EntityStateConfiguration")]
	public class EntityStateConfiguration : ScriptableObject
	{
		[SerializableSystemType.RequiredBaseType(typeof(EntityState))]
		public SerializableSystemType targetType;

		public SerializedFieldCollection serializedFieldsCollection;

		public static event Action<EntityStateConfiguration> onEditorUpdatedConfigurationGlobal;

		[ContextMenu("Set Name from Target Type")]
		public void SetNameFromTargetType()
		{
			Type type = (Type)targetType;
			if (!(type == null))
			{
				base.name = type.FullName;
			}
		}

		public void ApplyStatic()
		{
			Type type = (Type)targetType;
			if (type == null)
			{
				return;
			}
			SerializedField[] serializedFields = serializedFieldsCollection.serializedFields;
			for (int i = 0; i < serializedFields.Length; i++)
			{
				SerializedField serializedField = serializedFields[i];
				try
				{
					FieldInfo field = type.GetField(serializedField.fieldName, BindingFlags.Static | BindingFlags.Public);
					if ((object)field != null)
					{
						SerializedValue fieldValue = serializedField.fieldValue;
						field.SetValue(null, fieldValue.GetValue(field));
					}
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
		}

		[CanBeNull]
		public Action<object> BuildInstanceInitializer()
		{
			Type type = (Type)targetType;
			if (type == null)
			{
				return null;
			}
			SerializedField[] serializedFields = serializedFieldsCollection.serializedFields;
			List<(FieldInfo, object)> list = CollectionPool<(FieldInfo, object), List<(FieldInfo, object)>>.RentCollection();
			for (int i = 0; i < serializedFields.Length; i++)
			{
				ref SerializedField reference = ref serializedFields[i];
				try
				{
					FieldInfo field = type.GetField(reference.fieldName);
					if (!(field == null) && FieldPassesFilter(field))
					{
						list.Add((field, reference.fieldValue.GetValue(field)));
					}
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
			if (list.Count == 0)
			{
				list = CollectionPool<(FieldInfo, object), List<(FieldInfo, object)>>.ReturnCollection(list);
				return null;
			}
			(FieldInfo, object)[] fieldValuesArray = list.ToArray();
			list = CollectionPool<(FieldInfo, object), List<(FieldInfo, object)>>.ReturnCollection(list);
			return InitializeObject;
			static bool FieldPassesFilter(FieldInfo fieldInfo)
			{
				return CustomAttributeExtensions.GetCustomAttribute<SerializeField>(fieldInfo) != null;
			}
			void InitializeObject(object obj)
			{
				for (int j = 0; j < fieldValuesArray.Length; j++)
				{
					var (fieldInfo2, value) = fieldValuesArray[j];
					fieldInfo2.SetValue(obj, value);
				}
			}
		}

		private void Awake()
		{
			serializedFieldsCollection.PurgeUnityPsuedoNullFields();
		}

		private void OnValidate()
		{
			if (Application.isPlaying)
			{
				RoR2Application.onNextUpdate += delegate
				{
					EntityStateConfiguration.onEditorUpdatedConfigurationGlobal?.Invoke(this);
				};
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/EquipmentDef")]
	public class EquipmentDef : ScriptableObject
	{
		private EquipmentIndex _equipmentIndex = EquipmentIndex.None;

		public GameObject pickupModelPrefab;

		public float cooldown;

		public string nameToken;

		public string pickupToken;

		public string descriptionToken;

		public string loreToken;

		public bool isConsumed;

		public Sprite pickupIconSprite;

		public UnlockableDef unlockableDef;

		public ColorCatalog.ColorIndex colorIndex = ColorCatalog.ColorIndex.Equipment;

		public bool canDrop;

		[Range(0f, 1f)]
		public float dropOnDeathChance;

		public bool canBeRandomlyTriggered = true;

		public bool enigmaCompatible;

		public bool isLunar;

		public bool isBoss;

		public BuffDef passiveBuffDef;

		public bool appearsInSinglePlayer = true;

		public bool appearsInMultiPlayer = true;

		public ExpansionDef requiredExpansion;

		public static GameObject dropletDisplayPrefab;

		[HideInInspector]
		[Obsolete]
		public MageElement mageElement;

		public EquipmentIndex equipmentIndex
		{
			get
			{
				if (_equipmentIndex == EquipmentIndex.None)
				{
					UnityEngine.Debug.LogError("EquipmentDef '" + base.name + "' has an equipment index of 'None'.  Attempting to fix...");
					_equipmentIndex = EquipmentCatalog.FindEquipmentIndex(base.name);
					if (_equipmentIndex != EquipmentIndex.None)
					{
						UnityEngine.Debug.LogError($"Able to fix EquipmentDef '{base.name}' (equipment index = {_equipmentIndex}).  This is probably because the asset is being duplicated across bundles.");
					}
				}
				return _equipmentIndex;
			}
			set
			{
				_equipmentIndex = value;
			}
		}

		public Texture pickupIconTexture
		{
			get
			{
				if (!pickupIconSprite)
				{
					return null;
				}
				return pickupIconSprite.texture;
			}
		}

		public Texture bgIconTexture
		{
			get
			{
				if (isLunar)
				{
					return LegacyResourcesAPI.Load<Texture>("Textures/ItemIcons/BG/texLunarBGIcon");
				}
				return LegacyResourcesAPI.Load<Texture>("Textures/ItemIcons/BG/texEquipmentBGIcon");
			}
		}

		public static void AttemptGrant(ref PickupDef.GrantContext context)
		{
			context.controller.StartWaitTime();
			Inventory inventory = context.body.inventory;
			EquipmentIndex currentEquipmentIndex = inventory.currentEquipmentIndex;
			EquipmentIndex equipmentIndex = PickupCatalog.GetPickupDef(context.controller.pickupIndex)?.equipmentIndex ?? EquipmentIndex.None;
			inventory.SetEquipmentIndex(equipmentIndex);
			context.controller.NetworkpickupIndex = PickupCatalog.FindPickupIndex(currentEquipmentIndex);
			context.shouldDestroy = false;
			context.shouldNotify = true;
			if (context.controller.pickupIndex == PickupIndex.none)
			{
				context.shouldDestroy = true;
			}
			if (context.controller.selfDestructIfPickupIndexIsNotIdeal && context.controller.pickupIndex != PickupCatalog.FindPickupIndex(context.controller.idealPickupIndex.pickupName))
			{
				PickupDropletController.CreatePickupDroplet(context.controller.pickupIndex, context.controller.transform.position, new UnityEngine.Vector3(UnityEngine.Random.Range(-4f, 4f), 20f, UnityEngine.Random.Range(-4f, 4f)));
				context.shouldDestroy = true;
			}
		}

		[ContextMenu("Auto Populate Tokens")]
		public void AutoPopulateTokens()
		{
			string arg = base.name.ToUpperInvariant();
			nameToken = $"EQUIPMENT_{arg}_NAME";
			pickupToken = $"EQUIPMENT_{arg}_PICKUP";
			descriptionToken = $"EQUIPMENT_{arg}_DESC";
			loreToken = $"EQUIPMENT_{arg}_LORE";
		}

		public static void SetDropletDisplayPrefab(GameObject gameObj)
		{
			dropletDisplayPrefab = gameObj;
		}

		public virtual PickupDef CreatePickupDef()
		{
			PickupDef obj = new PickupDef
			{
				internalName = "EquipmentIndex." + base.name,
				equipmentIndex = equipmentIndex,
				displayPrefab = pickupModelPrefab,
				dropletDisplayPrefab = dropletDisplayPrefab,
				nameToken = nameToken,
				baseColor = ColorCatalog.GetColor(colorIndex)
			};
			obj.darkColor = obj.baseColor;
			obj.unlockableDef = unlockableDef;
			obj.interactContextToken = "EQUIPMENT_PICKUP_CONTEXT";
			obj.isLunar = isLunar;
			obj.isBoss = isBoss;
			obj.iconTexture = pickupIconTexture;
			obj.iconSprite = pickupIconSprite;
			obj.attemptGrant = AttemptGrant;
			return obj;
		}

		[ConCommand(commandName = "equipment_migrate", flags = ConVarFlags.None, helpText = "Generates EquipmentDef assets from the existing catalog entries.")]
		private static void CCEquipmentMigrate(ConCommandArgs args)
		{
			for (EquipmentIndex equipmentIndex = (EquipmentIndex)0; (int)equipmentIndex < EquipmentCatalog.equipmentCount; equipmentIndex++)
			{
				EditorUtil.CopyToScriptableObject<EquipmentDef, EquipmentDef>(EquipmentCatalog.GetEquipmentDef(equipmentIndex), "Assets/RoR2/Resources/EquipmentDefs/");
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/DCCS/FamilyDirectorCardCategorySelection")]
	public class FamilyDirectorCardCategorySelection : DirectorCardCategorySelection
	{
		private const float chatMessageDelaySeconds = 1f;

		[SerializeField]
		private string selectionChatString;

		[SerializeField]
		[Tooltip("The minimum (inclusive) number of stages COMPLETED (not reached) before this family event becomes available.")]
		private int minimumStageCompletion = 1;

		[Tooltip("The maximum (exclusive) number of stages COMPLETED (not reached) before this family event becomes unavailable.")]
		[SerializeField]
		private int maximumStageCompletion = int.MaxValue;

		public override bool IsAvailable()
		{
			if ((bool)Run.instance && Run.instance.canFamilyEventTrigger && minimumStageCompletion <= Run.instance.stageClearCount)
			{
				return maximumStageCompletion > Run.instance.stageClearCount;
			}
			return false;
		}

		public override void OnSelected(ClassicStageInfo stageInfo)
		{
			if (!string.IsNullOrEmpty(selectionChatString))
			{
				stageInfo.StartCoroutine(stageInfo.BroadcastFamilySelection(selectionChatString));
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/GameEndingDef")]
	public class GameEndingDef : ScriptableObject
	{
		public string endingTextToken;

		public UnityEngine.Color backgroundColor;

		public UnityEngine.Color foregroundColor;

		public Sprite icon;

		public Material material;

		[Tooltip("The body prefab to use as the killer when this ending is triggered while players are still alive.")]
		public GameObject defaultKillerOverride;

		public bool isWin;

		public bool showCredits;

		public SerializableEntityStateType gameOverControllerState;

		public uint lunarCoinReward;

		private string _cachedName;

		public GameEndingIndex gameEndingIndex { get; set; }

		[Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)]
		public new string name
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public string cachedName
		{
			get
			{
				return _cachedName;
			}
			set
			{
				base.name = value;
				_cachedName = value;
			}
		}

		private void Awake()
		{
			_cachedName = base.name;
		}

		private void OnValidate()
		{
			_cachedName = base.name;
		}
	}
	public enum GameEndingIndex
	{
		Invalid = -1
	}
	public static class GameEndingCatalog
	{
		private static GameEndingDef[] gameEndingDefs = Array.Empty<GameEndingDef>();

		public static int endingCount => gameEndingDefs.Length;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<GameEndingDef>> collectEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.GameEndingCatalog.collectEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.gameEndingDefs);
			}
			remove
			{
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			HGXml.Register(delegate(XElement element, GameEndingDef contents)
			{
				element.Value = contents?.cachedName ?? "";
			}, delegate(XElement element, ref GameEndingDef contents)
			{
				contents = FindGameEndingDef(element.Value);
				return true;
			});
			SetGameEndingDefs(ContentManager.gameEndingDefs);
		}

		private static void SetGameEndingDefs(GameEndingDef[] newGameEndingDefs)
		{
			GameEndingDef[] array = gameEndingDefs;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].gameEndingIndex = GameEndingIndex.Invalid;
			}
			ArrayUtils.CloneTo(newGameEndingDefs, ref gameEndingDefs);
			Array.Sort(gameEndingDefs, (GameEndingDef a, GameEndingDef b) => string.CompareOrdinal(a.cachedName, b.cachedName));
			for (int j = 0; j < gameEndingDefs.Length; j++)
			{
				gameEndingDefs[j].gameEndingIndex = (GameEndingIndex)j;
			}
		}

		public static GameEndingDef GetGameEndingDef(GameEndingIndex gameEndingIndex)
		{
			return ArrayUtils.GetSafe(gameEndingDefs, (int)gameEndingIndex);
		}

		public static GameEndingIndex FindGameEndingIndex(string gameEndingName)
		{
			for (int i = 0; i < gameEndingDefs.Length; i++)
			{
				if (string.CompareOrdinal(gameEndingName, gameEndingDefs[i].cachedName) == 0)
				{
					return (GameEndingIndex)i;
				}
			}
			return GameEndingIndex.Invalid;
		}

		public static GameEndingDef FindGameEndingDef(string gameEndingName)
		{
			return GetGameEndingDef(FindGameEndingIndex(gameEndingName));
		}

		public static GameEndingIndex GetGameEndingIndex([CanBeNull] GameEndingDef gameEndingDef)
		{
			if (!gameEndingDef)
			{
				return GameEndingIndex.Invalid;
			}
			return gameEndingDef.gameEndingIndex;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/GameObjectFactory")]
	public class GameObjectFactory : ScriptableObject
	{
		public bool clearOnPerformInstantiate = true;

		private GameObject prefab;

		private UnityEngine.Vector3 spawnPosition;

		private UnityEngine.Quaternion spawnRotation;

		private bool isNetworkPrefab;

		private AnimationClip spawnModificationsClip;

		public void Reset()
		{
			Clear();
			clearOnPerformInstantiate = true;
		}

		public void Clear()
		{
			prefab = null;
			spawnPosition = UnityEngine.Vector3.zero;
			spawnRotation = UnityEngine.Quaternion.identity;
			isNetworkPrefab = false;
			spawnModificationsClip = null;
		}

		public void SetPrefab(GameObject newPrefab)
		{
			prefab = newPrefab;
			isNetworkPrefab = prefab?.GetComponent<NetworkIdentity>();
		}

		public void SetSpawnLocation(Transform newSpawnLocation)
		{
			spawnPosition = newSpawnLocation.position;
			spawnRotation = newSpawnLocation.rotation;
		}

		public void SetSpawnModificationsClip(AnimationClip newSpawnModificationsClip)
		{
			spawnModificationsClip = newSpawnModificationsClip;
		}

		public void PerformInstantiate()
		{
			if ((bool)prefab)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(prefab, spawnPosition, spawnRotation);
				if ((bool)spawnModificationsClip)
				{
					Animator obj = gameObject.AddComponent<Animator>();
					spawnModificationsClip.SampleAnimation(gameObject, 0f);
					UnityEngine.Object.Destroy(obj);
				}
				gameObject.SetActive(value: true);
				if (isNetworkPrefab && NetworkServer.active)
				{
					NetworkServer.Spawn(gameObject);
				}
				if (clearOnPerformInstantiate)
				{
					Clear();
				}
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/Singletons/GlobalEventMethodLibrary")]
	public class GlobalEventMethodLibrary : ScriptableObject
	{
		public void RunAdvanceStageServer(SceneDef nextScene)
		{
			if (NetworkServer.active && (bool)Run.instance)
			{
				Run.instance.AdvanceStage(nextScene);
			}
		}

		public void RunBeginGameOverServer(GameEndingDef endingDef)
		{
			if (NetworkServer.active && (bool)Run.instance)
			{
				Run.instance.BeginGameOver(endingDef);
			}
		}

		public void LogMessage(string message)
		{
		}

		public void ForcePlayableDirectorFinish(PlayableDirector playableDirector)
		{
			playableDirector.time = playableDirector.duration;
		}

		public new void DestroyObject(UnityEngine.Object obj)
		{
			UnityEngine.Object.Destroy(obj);
		}

		public void DisableAllSiblings(Transform transform)
		{
			if (!transform)
			{
				return;
			}
			Transform parent = transform.parent;
			if (!parent)
			{
				return;
			}
			int i = 0;
			for (int childCount = parent.childCount; i < childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if ((bool)child && child != transform)
				{
					child.gameObject.SetActive(value: false);
				}
			}
		}

		public void DisableAllSiblings(GameObject gameObject)
		{
			if ((bool)gameObject)
			{
				DisableAllSiblings(gameObject.transform);
			}
		}

		public void ActivateGameObjectIfServer(GameObject gameObject)
		{
			if ((bool)gameObject && NetworkServer.active)
			{
				gameObject.SetActive(value: true);
			}
		}

		public void DeactivateGameObjectIfServer(GameObject gameObject)
		{
			if ((bool)gameObject && NetworkServer.active)
			{
				gameObject.SetActive(value: false);
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/Infinite Tower/Infinite Tower Wave Artifact Prerequisites")]
	public class InfiniteTowerWaveArtifactPrerequisites : InfiniteTowerWavePrerequisites
	{
		[SerializeField]
		[Tooltip("This wave cannot be selected while this artifact is enabled.")]
		private ArtifactDef bannedArtifact;

		public override bool AreMet(InfiniteTowerRun run)
		{
			return !RunArtifactManager.instance.IsArtifactEnabled(bannedArtifact);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/Infinite Tower/Infinite Tower Wave Category")]
	public class InfiniteTowerWaveCategory : ScriptableObject
	{
		[Serializable]
		public struct WeightedWave
		{
			public GameObject wavePrefab;

			public InfiniteTowerWavePrerequisites prerequisites;

			public float weight;
		}

		private readonly WeightedSelection<GameObject> weightedSelection = new WeightedSelection<GameObject>();

		[SerializeField]
		[Tooltip("The weighted selection for which wave prefab to use")]
		private WeightedWave[] wavePrefabs;

		[Tooltip("The period of how often this category is available, e.g.\"every N waves\".")]
		[SerializeField]
		private int availabilityPeriod;

		[Tooltip("The minimum wave index where this category is available (inclusive)")]
		[SerializeField]
		private int minWaveIndex;

		public bool IsAvailable(InfiniteTowerRun run)
		{
			bool num = availabilityPeriod > 0 && run.waveIndex % availabilityPeriod == 0;
			bool flag = run.waveIndex >= minWaveIndex;
			bool flag2 = wavePrefabs.Length != 0;
			if (num && flag && flag2)
			{
				WeightedWave[] array = wavePrefabs;
				for (int i = 0; i < array.Length; i++)
				{
					WeightedWave weightedWave = array[i];
					if (!weightedWave.prerequisites || weightedWave.prerequisites.AreMet(run))
					{
						return true;
					}
				}
			}
			return false;
		}

		public GameObject SelectWavePrefab(InfiniteTowerRun run, Xoroshiro128Plus rng)
		{
			if (weightedSelection.Count < wavePrefabs.Length)
			{
				GenerateWeightedSelection();
			}
			WeightedWave[] array = wavePrefabs;
			for (int i = 0; i < array.Length; i++)
			{
				WeightedWave weightedWave = array[i];
				if (!weightedWave.prerequisites || weightedWave.prerequisites.AreMet(run))
				{
					continue;
				}
				for (int j = 0; j < weightedSelection.Count; j++)
				{
					if ((object)weightedSelection.choices[j].value == weightedWave.wavePrefab)
					{
						weightedSelection.RemoveChoice(j);
						break;
					}
				}
			}
			return weightedSelection.Evaluate(rng.nextNormalizedFloat);
		}

		private void GenerateWeightedSelection()
		{
			weightedSelection.Clear();
			WeightedWave[] array = wavePrefabs;
			for (int i = 0; i < array.Length; i++)
			{
				WeightedWave weightedWave = array[i];
				weightedSelection.AddChoice(weightedWave.wavePrefab, weightedWave.weight);
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/Infinite Tower/Infinite Tower Wave Count Prerequisites")]
	public class InfiniteTowerWaveCountPrerequisites : InfiniteTowerWavePrerequisites
	{
		[SerializeField]
		private int minimumWaveCount;

		public override bool AreMet(InfiniteTowerRun run)
		{
			return run.waveIndex >= minimumWaveCount;
		}
	}
	public abstract class InfiniteTowerWavePrerequisites : ScriptableObject
	{
		public abstract bool AreMet(InfiniteTowerRun run);
	}
	[CreateAssetMenu(menuName = "RoR2/InspectableDef")]
	public class InspectDef : ScriptableObject
	{
		public InspectInfo Info;
	}
	[CreateAssetMenu(menuName = "RoR2/SpawnCards/InteractableSpawnCard")]
	public class InteractableSpawnCard : SpawnCard
	{
		[Tooltip("Whether or not to orient the object to the normal of the ground it spawns on.")]
		public bool orientToFloor;

		[Tooltip("Slightly tweaks the rotation for things like chests and barrels so it looks more natural.")]
		public bool slightlyRandomizeOrientation;

		public bool skipSpawnWhenSacrificeArtifactEnabled;

		[Tooltip("When Sacrifice is enabled, this is multiplied by the card's weight")]
		public float weightScalarWhenSacrificeArtifactEnabled = 1f;

		public bool skipSpawnWhenDevotionArtifactEnabled;

		[Tooltip("Won't spawn more than this many per stage.  If it's negative, there's no cap")]
		public int maxSpawnsPerStage = -1;

		[Range(0f, 1f)]
		[SerializeField]
		[Tooltip("When playing Primatic Trials, this interactable will have a required check to see if it is supposed to spawn. 0 is will not spawn, 1 will 100% spawn and will be default.")]
		public float prismaticTrialSpawnChance = 1f;

		private static readonly float floorOffset = 3f;

		private static readonly float raycastLength = 6f;

		private static readonly Xoroshiro128Plus rng = new Xoroshiro128Plus(0uL);

		protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result)
		{
			ulong nextUlong = directorSpawnRequest.rng.nextUlong;
			rng.ResetSeed(nextUlong);
			if (skipSpawnWhenSacrificeArtifactEnabled && RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.sacrificeArtifactDef))
			{
				return;
			}
			GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position, rotation);
			Transform transform = gameObject.transform;
			if (orientToFloor)
			{
				UnityEngine.Vector3 up = gameObject.transform.up;
				if (Physics.Raycast(new Ray(position + up * floorOffset, -up), out var hitInfo, raycastLength + floorOffset, LayerIndex.world.mask))
				{
					transform.up = hitInfo.normal;
				}
			}
			transform.Rotate(UnityEngine.Vector3.up, rng.RangeFloat(0f, 360f), Space.Self);
			if (slightlyRandomizeOrientation)
			{
				transform.Translate(UnityEngine.Vector3.down * 0.3f, Space.Self);
				transform.rotation *= UnityEngine.Quaternion.Euler(rng.RangeFloat(-30f, 30f), rng.RangeFloat(-30f, 30f), rng.RangeFloat(-30f, 30f));
			}
			NetworkServer.Spawn(gameObject);
			result.spawnedInstance = gameObject;
			result.success = true;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/ItemDef")]
	public class ItemDef : ScriptableObject
	{
		[Serializable]
		public struct Pair : IEquatable<Pair>
		{
			public ItemDef itemDef1;

			public ItemDef itemDef2;

			public override int GetHashCode()
			{
				return itemDef1.GetHashCode() ^ ~itemDef2.GetHashCode();
			}

			public override bool Equals(object obj)
			{
				if (obj is Pair)
				{
					return Equals((Pair)obj);
				}
				return false;
			}

			public bool Equals(Pair other)
			{
				if (other.itemDef1 == itemDef1)
				{
					return other.itemDef2 == itemDef2;
				}
				return false;
			}
		}

		private ItemIndex _itemIndex = ItemIndex.None;

		[FormerlySerializedAs("tier")]
		[Obsolete("Replaced by itemTierDef field", false)]
		[Tooltip("Deprecated.  Use itemTierDef instead.")]
		[SerializeField]
		private ItemTier deprecatedTier;

		[SerializeField]
		private ItemTierDef _itemTierDef;

		public string nameToken;

		public string pickupToken;

		public string descriptionToken;

		public string loreToken;

		public UnlockableDef unlockableDef;

		public GameObject pickupModelPrefab;

		public Sprite pickupIconSprite;

		public bool isConsumed;

		public bool hidden;

		public bool canRemove = true;

		public ItemTag[] tags = Array.Empty<ItemTag>();

		public ExpansionDef requiredExpansion;

		public ItemIndex itemIndex
		{
			get
			{
				if (_itemIndex == ItemIndex.None)
				{
					UnityEngine.Debug.LogError("ItemDef '" + base.name + "' has an item index of 'None'.  Attempting to fix...");
					_itemIndex = ItemCatalog.FindItemIndex(base.name);
					if (_itemIndex != ItemIndex.None)
					{
						UnityEngine.Debug.LogError($"Able to fix ItemDef '{base.name}' (item index = {_itemIndex}).  This is probably because the asset is being duplicated across bundles.");
					}
				}
				return _itemIndex;
			}
			set
			{
				_itemIndex = value;
			}
		}

		public ItemTier tier
		{
			get
			{
				if ((bool)_itemTierDef)
				{
					return _itemTierDef.tier;
				}
				return deprecatedTier;
			}
			set
			{
				_itemTierDef = ItemTierCatalog.GetItemTierDef(value);
			}
		}

		[Obsolete("Get isDroppable from the ItemTierDef instead")]
		public bool inDroppableTier
		{
			get
			{
				ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(tier);
				if ((bool)itemTierDef)
				{
					return itemTierDef.isDroppable;
				}
				return false;
			}
		}

		public Texture pickupIconTexture
		{
			get
			{
				if (!pickupIconSprite)
				{
					return null;
				}
				return pickupIconSprite.texture;
			}
		}

		[Obsolete("Get bgIconTexture from the ItemTierDef instead")]
		public Texture bgIconTexture => ItemTierCatalog.GetItemTierDef(tier)?.bgIconTexture;

		[Obsolete("Get colorIndex from the ItemTierDef instead")]
		public ColorCatalog.ColorIndex colorIndex => ItemTierCatalog.GetItemTierDef(tier)?.colorIndex ?? ColorCatalog.ColorIndex.Unaffordable;

		[Obsolete("Get darkColorIndex from the ItemTierDef instead")]
		public ColorCatalog.ColorIndex darkColorIndex => ItemTierCatalog.GetItemTierDef(tier)?.darkColorIndex ?? ColorCatalog.ColorIndex.Unaffordable;

		public static void AttemptGrant(ref PickupDef.GrantContext context)
		{
			context.body.inventory.GiveItem(PickupCatalog.GetPickupDef(context.controller.pickupIndex)?.itemIndex ?? ItemIndex.None);
			context.body.inventory.GetItemCount(PickupCatalog.GetPickupDef(context.controller.pickupIndex).itemIndex);
			context.shouldDestroy = true;
			context.shouldNotify = true;
		}

		public bool ContainsTag(ItemTag tag)
		{
			if (tag == ItemTag.Any)
			{
				return true;
			}
			return Array.IndexOf(tags, tag) != -1;
		}

		public bool DoesNotContainTag(ItemTag tag)
		{
			return Array.IndexOf(tags, tag) == -1;
		}

		public virtual PickupDef CreatePickupDef()
		{
			ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(tier);
			return new PickupDef
			{
				internalName = "ItemIndex." + base.name,
				itemIndex = itemIndex,
				itemTier = tier,
				displayPrefab = pickupModelPrefab,
				dropletDisplayPrefab = itemTierDef?.dropletDisplayPrefab,
				nameToken = nameToken,
				baseColor = ColorCatalog.GetColor(colorIndex),
				darkColor = ColorCatalog.GetColor(darkColorIndex),
				unlockableDef = unlockableDef,
				interactContextToken = "ITEM_PICKUP_CONTEXT",
				isLunar = (tier == ItemTier.Lunar),
				isBoss = (tier == ItemTier.Boss),
				iconTexture = pickupIconTexture,
				iconSprite = pickupIconSprite,
				attemptGrant = AttemptGrant
			};
		}

		[ContextMenu("Auto Populate Tokens")]
		public void AutoPopulateTokens()
		{
			string arg = base.name.ToUpperInvariant();
			nameToken = $"ITEM_{arg}_NAME";
			pickupToken = $"ITEM_{arg}_PICKUP";
			descriptionToken = $"ITEM_{arg}_DESC";
			loreToken = $"ITEM_{arg}_LORE";
		}

		[ConCommand(commandName = "items_migrate", flags = ConVarFlags.None, helpText = "Generates ItemDef assets from the existing catalog entries.")]
		private static void CCItemsMigrate(ConCommandArgs args)
		{
			for (ItemIndex itemIndex = ItemIndex.Count; (int)itemIndex < ItemCatalog.itemCount; itemIndex++)
			{
				EditorUtil.CopyToScriptableObject<ItemDef, ItemDef>(ItemCatalog.GetItemDef(itemIndex), "Assets/RoR2/Resources/ItemDefs/");
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/ItemDisplayRuleSet")]
	public class ItemDisplayRuleSet : ScriptableObject
	{
		[Serializable]
		[Obsolete]
		public struct NamedRuleGroup
		{
			public string name;

			public DisplayRuleGroup displayRuleGroup;
		}

		[Serializable]
		public struct KeyAssetRuleGroup
		{
			public UnityEngine.Object keyAsset;

			public DisplayRuleGroup displayRuleGroup;
		}

		[SerializeField]
		[Obsolete("Use .assetRuleGroups instead.")]
		private NamedRuleGroup[] namedItemRuleGroups = Array.Empty<NamedRuleGroup>();

		[Obsolete("Use .assetRuleGroups instead.")]
		[SerializeField]
		private NamedRuleGroup[] namedEquipmentRuleGroups = Array.Empty<NamedRuleGroup>();

		public KeyAssetRuleGroup[] keyAssetRuleGroups = Array.Empty<KeyAssetRuleGroup>();

		private DisplayRuleGroup[] runtimeItemRuleGroups;

		private DisplayRuleGroup[] runtimeEquipmentRuleGroups;

		private static readonly List<ItemDisplayRuleSet> instancesList = new List<ItemDisplayRuleSet>();

		private static bool runtimeDependenciesReady = false;

		private bool hasObsoleteNamedRuleGroups
		{
			get
			{
				if (namedItemRuleGroups.Length == 0)
				{
					return namedEquipmentRuleGroups.Length != 0;
				}
				return true;
			}
		}

		public bool isEmpty => keyAssetRuleGroups.Length == 0;

		[SystemInitializer(new Type[]
		{
			typeof(ItemCatalog),
			typeof(EquipmentCatalog)
		})]
		private static void Init()
		{
			runtimeDependenciesReady = true;
			for (int i = 0; i < instancesList.Count; i++)
			{
				instancesList[i].GenerateRuntimeValues();
			}
		}

		private void OnEnable()
		{
			instancesList.Add(this);
			if (runtimeDependenciesReady)
			{
				GenerateRuntimeValues();
			}
		}

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void OnValidate()
		{
			if (hasObsoleteNamedRuleGroups)
			{
				UnityEngine.Debug.LogWarningFormat(this, "ItemDisplayRuleSet \"{0}\" still defines one or more entries in an obsolete format. Run the upgrade from the inspector context menu.", this);
			}
		}

		public void GenerateRuntimeValues()
		{
			runtimeItemRuleGroups = ItemCatalog.GetPerItemBuffer<DisplayRuleGroup>();
			runtimeEquipmentRuleGroups = EquipmentCatalog.GetPerEquipmentBuffer<DisplayRuleGroup>();
			ArrayUtils.SetAll(runtimeItemRuleGroups, in DisplayRuleGroup.empty);
			ArrayUtils.SetAll(runtimeEquipmentRuleGroups, in DisplayRuleGroup.empty);
			for (int i = 0; i < keyAssetRuleGroups.Length; i++)
			{
				ref KeyAssetRuleGroup reference = ref keyAssetRuleGroups[i];
				UnityEngine.Object keyAsset = reference.keyAsset;
				if (!(keyAsset is ItemDef itemDef))
				{
					if (keyAsset is EquipmentDef { equipmentIndex: not EquipmentIndex.None } equipmentDef)
					{
						runtimeEquipmentRuleGroups[(int)equipmentDef.equipmentIndex] = reference.displayRuleGroup;
					}
				}
				else if (itemDef.itemIndex != ItemIndex.None)
				{
					runtimeItemRuleGroups[(int)itemDef.itemIndex] = reference.displayRuleGroup;
				}
			}
		}

		public DisplayRuleGroup FindDisplayRuleGroup(UnityEngine.Object keyAsset)
		{
			if ((bool)keyAsset)
			{
				for (int i = 0; i < keyAssetRuleGroups.Length; i++)
				{
					ref KeyAssetRuleGroup reference = ref keyAssetRuleGroups[i];
					if ((object)reference.keyAsset == keyAsset)
					{
						return reference.displayRuleGroup;
					}
				}
			}
			return DisplayRuleGroup.empty;
		}

		public void SetDisplayRuleGroup(UnityEngine.Object keyAsset, DisplayRuleGroup displayRuleGroup)
		{
			if (!keyAsset)
			{
				return;
			}
			for (int i = 0; i < keyAssetRuleGroups.Length; i++)
			{
				ref KeyAssetRuleGroup reference = ref keyAssetRuleGroups[i];
				if ((object)reference.keyAsset == keyAsset)
				{
					reference.displayRuleGroup = displayRuleGroup;
					return;
				}
			}
			ref KeyAssetRuleGroup[] array = ref keyAssetRuleGroups;
			KeyAssetRuleGroup value = new KeyAssetRuleGroup
			{
				keyAsset = keyAsset,
				displayRuleGroup = displayRuleGroup
			};
			ArrayUtils.ArrayAppend(ref array, in value);
		}

		public DisplayRuleGroup GetItemDisplayRuleGroup(ItemIndex itemIndex)
		{
			return ArrayUtils.GetSafe(runtimeItemRuleGroups, (int)itemIndex, in DisplayRuleGroup.empty);
		}

		public DisplayRuleGroup GetEquipmentDisplayRuleGroup(EquipmentIndex equipmentIndex)
		{
			return ArrayUtils.GetSafe(runtimeEquipmentRuleGroups, (int)equipmentIndex, in DisplayRuleGroup.empty);
		}

		public void Reset()
		{
			keyAssetRuleGroups = Array.Empty<KeyAssetRuleGroup>();
			runtimeItemRuleGroups = Array.Empty<DisplayRuleGroup>();
			runtimeEquipmentRuleGroups = Array.Empty<DisplayRuleGroup>();
		}

		[ContextMenu("Upgrade to keying by asset")]
		public void UpdgradeToAssetKeying()
		{
			_ = Application.isPlaying;
			if (hasObsoleteNamedRuleGroups)
			{
				List<string> list = new List<string>();
				UpgradeNamedRuleGroups(ref namedItemRuleGroups, "ItemDef", (string assetName) => ItemCatalog.GetItemDef(ItemCatalog.FindItemIndex(assetName)), list);
				UpgradeNamedRuleGroups(ref namedEquipmentRuleGroups, "EquipmentDef", (string assetName) => EquipmentCatalog.GetEquipmentDef(EquipmentCatalog.FindEquipmentIndex(assetName)), list);
				if (list.Count > 0)
				{
					UnityEngine.Debug.LogWarningFormat("Encountered {0} errors attempting to upgrade ItemDisplayRuleSet \"{1}\":\n{2}", list.Count, base.name, string.Join("\n", list));
				}
				EditorUtil.SetDirty(this);
			}
		}

		private void UpgradeNamedRuleGroups(ref NamedRuleGroup[] namedRuleGroups, string assetTypeName, Func<string, UnityEngine.Object> assetLookupMethod, List<string> failureMessagesList)
		{
			int arraySize = namedRuleGroups.Length;
			for (int i = 0; i < arraySize; i++)
			{
				NamedRuleGroup namedRuleGroup = namedRuleGroups[i];
				UnityEngine.Object @object = assetLookupMethod(namedRuleGroup.name);
				string text = null;
				if (!namedRuleGroup.displayRuleGroup.isEmpty)
				{
					if ((bool)@object)
					{
						if (FindDisplayRuleGroup(@object).isEmpty)
						{
							SetDisplayRuleGroup(@object, namedRuleGroup.displayRuleGroup);
						}
						else
						{
							text = "Conflicts with existing rule group.";
						}
					}
					else
					{
						text = "Named asset not found.";
					}
				}
				if (text != null)
				{
					failureMessagesList.Add(assetTypeName + " \"" + namedRuleGroup.name + "\": " + text);
				}
				else
				{
					ArrayUtils.ArrayRemoveAt(namedRuleGroups, ref arraySize, i);
					i--;
				}
			}
			Array.Resize(ref namedRuleGroups, arraySize);
		}
	}
	public enum ItemDisplayRuleType
	{
		ParentedPrefab,
		LimbMask
	}
	[Flags]
	public enum LimbFlags
	{
		None = 0,
		Head = 1,
		RightArm = 2,
		LeftArm = 4,
		RightCalf = 8,
		LeftLeg = 0x10,
		Count = 5
	}
	[Serializable]
	public struct ItemDisplayRule : IEquatable<ItemDisplayRule>
	{
		public ItemDisplayRuleType ruleType;

		public GameObject followerPrefab;

		public string childName;

		public UnityEngine.Vector3 localPos;

		public UnityEngine.Vector3 localAngles;

		public UnityEngine.Vector3 localScale;

		public LimbFlags limbMask;

		public bool Equals(ItemDisplayRule other)
		{
			if (ruleType == other.ruleType && object.Equals(followerPrefab, other.followerPrefab) && string.Equals(childName, other.childName) && localPos.Equals(other.localPos) && localAngles.Equals(other.localAngles) && localScale.Equals(other.localScale))
			{
				return limbMask == other.limbMask;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is ItemDisplayRule other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((((((((((((int)ruleType * 397) ^ ((followerPrefab != null) ? followerPrefab.GetHashCode() : 0)) * 397) ^ ((childName != null) ? childName.GetHashCode() : 0)) * 397) ^ localPos.GetHashCode()) * 397) ^ localAngles.GetHashCode()) * 397) ^ localScale.GetHashCode()) * 397) ^ (int)limbMask;
		}
	}
	[Serializable]
	public struct DisplayRuleGroup : IEquatable<DisplayRuleGroup>
	{
		public static readonly DisplayRuleGroup empty = new DisplayRuleGroup
		{
			rules = null
		};

		public ItemDisplayRule[] rules;

		public bool isEmpty
		{
			get
			{
				if (rules != null)
				{
					return rules.Length == 0;
				}
				return true;
			}
		}

		public void AddDisplayRule(ItemDisplayRule itemDisplayRule)
		{
			if (rules == null)
			{
				rules = Array.Empty<ItemDisplayRule>();
			}
			ArrayUtils.ArrayAppend(ref rules, in itemDisplayRule);
		}

		public bool Equals(DisplayRuleGroup other)
		{
			return ArrayUtils.SequenceEquals(rules, other.rules);
		}

		public override bool Equals(object obj)
		{
			if (obj is DisplayRuleGroup other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			if (rules == null)
			{
				return 0;
			}
			return rules.GetHashCode();
		}
	}
	[CreateAssetMenu(menuName = "RoR2/ItemRelationshipProvider")]
	public class ItemRelationshipProvider : ScriptableObject
	{
		public ItemRelationshipType relationshipType;

		public ItemDef.Pair[] relationships;
	}
	[CreateAssetMenu(menuName = "RoR2/ItemRelationshipType")]
	public class ItemRelationshipType : ScriptableObject
	{
	}
	[CreateAssetMenu(menuName = "RoR2/ItemTierDef")]
	public class ItemTierDef : ScriptableObject
	{
		public enum PickupRules
		{
			Default,
			ConfirmFirst,
			ConfirmAll
		}

		[SerializeField]
		[FormerlySerializedAs("tier")]
		private ItemTier _tier;

		public Texture bgIconTexture;

		public ColorCatalog.ColorIndex colorIndex;

		public ColorCatalog.ColorIndex darkColorIndex;

		public bool isDroppable;

		public bool canScrap;

		public bool canRestack;

		public PickupRules pickupRules;

		public GameObject highlightPrefab;

		public GameObject dropletDisplayPrefab;

		public ItemTier tier
		{
			get
			{
				if (_tier == ItemTier.AssignedAtRuntime)
				{
					UnityEngine.Debug.LogError("ItemTierDef '" + base.name + "' has a tier of 'AssignedAtRuntime'.  Attempting to fix...");
					_tier = ItemTierCatalog.FindTierDef(base.name)?._tier ?? _tier;
					if (_tier != ItemTier.AssignedAtRuntime)
					{
						UnityEngine.Debug.LogError($"Able to fix ItemTierDef '{base.name}' (_tier = {_tier}).  This is probably because the asset is being duplicated across bundles.");
					}
				}
				return _tier;
			}
			set
			{
				_tier = value;
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/MiscPickupDefs/LunarCoinDef")]
	public class LunarCoinDef : MiscPickupDef
	{
		[SerializeField]
		public string internalNameOverride;

		public override string GetInternalName()
		{
			if (!string.IsNullOrEmpty(internalNameOverride))
			{
				return internalNameOverride;
			}
			return "MiscPickupIndex." + base.name;
		}

		public override void GrantPickup(ref PickupDef.GrantContext context)
		{
			NetworkUser networkUser = Util.LookUpBodyNetworkUser(context.body);
			if ((bool)networkUser)
			{
				networkUser.AwardLunarCoins(coinValue);
				context.shouldDestroy = true;
				context.shouldNotify = true;
			}
			else
			{
				context.shouldNotify = false;
				context.shouldDestroy = false;
			}
		}
	}
	public class MasterCopySpawnCard : CharacterSpawnCard
	{
		protected CharacterMaster srcCharacterMaster;

		protected int[] srcItemStacks;

		protected EquipmentIndex[] srcEquipment;

		protected Action<CharacterMaster> onPreSpawnSetup;

		public static MasterCopySpawnCard FromMaster(CharacterMaster srcCharacterMaster, bool copyItems, bool copyEquipment, Action<CharacterMaster> onPreSpawnSetup = null)
		{
			if (!srcCharacterMaster || !srcCharacterMaster.GetBody())
			{
				return null;
			}
			MasterCopySpawnCard masterCopySpawnCard = ScriptableObject.CreateInstance<MasterCopySpawnCard>();
			masterCopySpawnCard.onPreSpawnSetup = onPreSpawnSetup;
			CopyDataFromMaster(masterCopySpawnCard, srcCharacterMaster, copyItems, copyEquipment);
			return masterCopySpawnCard;
		}

		protected static void CopyDataFromMaster(MasterCopySpawnCard spawnCard, CharacterMaster srcCharacterMaster, bool copyItems, bool copyEquipment)
		{
			spawnCard.srcItemStacks = ItemCatalog.RequestItemStackArray();
			spawnCard.srcEquipment = Array.Empty<EquipmentIndex>();
			if (!srcCharacterMaster)
			{
				return;
			}
			spawnCard.sendOverNetwork = true;
			spawnCard.runtimeLoadout = new Loadout();
			spawnCard.srcCharacterMaster = srcCharacterMaster;
			spawnCard.srcCharacterMaster.loadout.Copy(spawnCard.runtimeLoadout);
			if (copyItems)
			{
				srcCharacterMaster.inventory.WriteItemStacks(spawnCard.srcItemStacks);
			}
			if (copyEquipment)
			{
				spawnCard.srcEquipment = new EquipmentIndex[srcCharacterMaster.inventory.GetEquipmentSlotCount()];
				for (uint num = 0u; num < spawnCard.srcEquipment.Length; num++)
				{
					spawnCard.srcEquipment[num] = srcCharacterMaster.inventory.GetEquipment(num).equipmentIndex;
				}
			}
			CharacterBody body = srcCharacterMaster.GetBody();
			if ((bool)body)
			{
				spawnCard.hullSize = body.hullClassification;
				spawnCard.nodeGraphType = (body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground);
				spawnCard.prefab = MasterCatalog.GetMasterPrefab(MasterCatalog.FindAiMasterIndexForBody(body.bodyIndex));
			}
		}

		public void GiveItem(ItemIndex itemIndex, int count = 1)
		{
			srcItemStacks[(int)itemIndex] += count;
		}

		public void GiveItem(ItemDef itemDef, int count = 1)
		{
			GiveItem(itemDef?.itemIndex ?? ItemIndex.None, count);
		}

		protected override Loadout GetRuntimeLoadout()
		{
			return srcCharacterMaster.loadout;
		}

		protected override Action<CharacterMaster> GetPreSpawnSetupCallback()
		{
			Action<CharacterMaster> baseCallback = base.GetPreSpawnSetupCallback();
			return Callback;
			void Callback(CharacterMaster spawnedMaster)
			{
				if (srcItemStacks != null)
				{
					spawnedMaster.inventory.AddItemsFrom(srcItemStacks, (ItemIndex _) => true);
				}
				if (srcEquipment != null)
				{
					for (uint num = 0u; num < srcEquipment.Length; num++)
					{
						spawnedMaster.inventory.SetEquipmentIndexForSlot(srcEquipment[num], num);
					}
				}
				baseCallback?.Invoke(spawnedMaster);
				onPreSpawnSetup?.Invoke(spawnedMaster);
				if (srcItemStacks != null)
				{
					ItemCatalog.ReturnItemStackArray(srcItemStacks);
				}
			}
		}
	}
	public abstract class MiscPickupDef : ScriptableObject
	{
		[SerializeField]
		public uint coinValue;

		[SerializeField]
		public string nameToken;

		[SerializeField]
		public GameObject displayPrefab;

		[SerializeField]
		public GameObject dropletDisplayPrefab;

		[SerializeField]
		public ColorCatalog.ColorIndex baseColor;

		[SerializeField]
		public ColorCatalog.ColorIndex darkColor;

		[SerializeField]
		public string interactContextToken;

		[SerializeField]
		public string descriptionToken;

		[SerializeField]
		public Sprite visual;

		[NonSerialized]
		public MiscPickupIndex miscPickupIndex;

		public abstract void GrantPickup(ref PickupDef.GrantContext context);

		public virtual string GetInternalName()
		{
			return "MiscPickupIndex." + base.name;
		}

		public virtual PickupDef CreatePickupDef()
		{
			return new PickupDef
			{
				internalName = GetInternalName(),
				coinValue = coinValue,
				nameToken = nameToken,
				displayPrefab = displayPrefab,
				dropletDisplayPrefab = dropletDisplayPrefab,
				baseColor = ColorCatalog.GetColor(baseColor),
				darkColor = ColorCatalog.GetColor(darkColor),
				interactContextToken = interactContextToken,
				attemptGrant = GrantPickup,
				miscPickupIndex = miscPickupIndex
			};
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SpawnCards/MultiCharacterSpawnCard")]
	public class MultiCharacterSpawnCard : CharacterSpawnCard
	{
		public GameObject[] masterPrefabs;

		protected override void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest directorSpawnRequest, ref SpawnResult result)
		{
			prefab = masterPrefabs[(int)(directorSpawnRequest.rng.nextNormalizedFloat * (float)masterPrefabs.Length)];
			base.Spawn(position, rotation, directorSpawnRequest, ref result);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/NetworkSoundEventDef")]
	public class NetworkSoundEventDef : ScriptableObject
	{
		public string eventName;

		public NetworkSoundEventIndex index { get; set; }

		public uint akId { get; set; }
	}
	[CreateAssetMenu(menuName = "RoR2/RoachParams")]
	public class RoachParams : ScriptableObject
	{
		public float reorientTimerMin = 0.2f;

		public float reorientTimerMax = 0.5f;

		public float turnSpeed = 72f;

		public float acceleration = 400f;

		public float maxSpeed = 100f;

		public float backupDuration = 0.1f;

		public float wiggle = 720f;

		public float stepSize = 0.1f;

		public float minSimulationDuration = 3f;

		public float maxSimulationDuration = 7f;

		public float chanceToFinishOnBump = 0.5f;

		public float keyframeInterval = 1f / 15f;

		public float minReactionTime;

		public float maxReactionTime = 0.2f;

		public GameObject roachPrefab;
	}
	[CreateAssetMenu(menuName = "RoR2/SceneCollection")]
	public class SceneCollection : ScriptableObject
	{
		[Serializable]
		public struct SceneEntry
		{
			public SceneDef sceneDef;

			[SerializeField]
			private float weightMinusOne;

			public float weight
			{
				get
				{
					return weightMinusOne + 1f;
				}
				set
				{
					weightMinusOne = value - 1f;
				}
			}
		}

		[FormerlySerializedAs("sceneReferences")]
		[SerializeField]
		private SceneEntry[] _sceneEntries = Array.Empty<SceneEntry>();

		public ReadOnlyArray<SceneEntry> sceneEntries => _sceneEntries;

		public bool isEmpty => _sceneEntries.Length == 0;

		public void SetSceneEntries(IReadOnlyList<SceneEntry> newSceneReferences)
		{
			Array.Resize(ref _sceneEntries, newSceneReferences.Count);
			for (int i = 0; i < 0; i++)
			{
				_sceneEntries[i] = newSceneReferences[i];
			}
		}

		public void AddToWeightedSelection(WeightedSelection<SceneDef> dest, Func<SceneDef, bool> canAdd = null)
		{
			foreach (SceneEntry sceneEntry in sceneEntries)
			{
				SceneDef sceneDef = sceneEntry.sceneDef;
				if ((bool)sceneDef && (canAdd == null || canAdd(sceneDef)))
				{
					dest.AddChoice(sceneDef, sceneEntry.weight);
				}
			}
		}
	}
	public enum SceneType
	{
		Invalid = -1,
		Menu,
		Stage,
		Intermission,
		Cutscene,
		TimedIntermission,
		UntimedStage
	}
	[CreateAssetMenu(menuName = "RoR2/SceneDef")]
	public class SceneDef : ScriptableObject
	{
		[Tooltip("The address of the associated scene. There is a name-based fallback systems for mods to use if the address isn't provided, but all official scenes must provide this.")]
		[Header("Scene")]
		public AssetReferenceScene sceneAddress;

		[Tooltip("The \"base\" name used for things like unlockables and stat tracking associated with this scene. If empty, the name of this asset will be used instead.")]
		public string baseSceneNameOverride;

		[Header("Classification")]
		public SceneType sceneType;

		public bool isOfflineScene;

		public int stageOrder;

		public ExpansionDef requiredExpansion;

		[Header("User-Facing Name")]
		public string nameToken;

		public string subtitleToken;

		public Texture previewTexture;

		[Header("Bazaar")]
		public Material portalMaterial;

		public string portalSelectionMessageString;

		[Header("Logbook")]
		public bool shouldIncludeInLogbook = true;

		[Tooltip("The logbook text for this scene. If empty, this scene will not be represented in the logbook.")]
		public string loreToken;

		public GameObject dioramaPrefab;

		[Header("Music")]
		[FormerlySerializedAs("song")]
		public MusicTrackDef mainTrack;

		[FormerlySerializedAs("bossSong")]
		public MusicTrackDef bossTrack;

		[Header("Color")]
		[Tooltip("Representative color of the environment, to be used for things such as hardware lights.")]
		public UnityEngine.Color environmentColor;

		[Tooltip("scene has safe start or not.")]
		[Header("Combat Message")]
		public bool hasSafeStart;

		[Tooltip("Prevents players from spawning into the scene. This is usually for cutscenes.")]
		[Header("Behavior")]
		public bool suppressPlayerEntry;

		[Tooltip("Prevents persistent NPCs (like drones) from spawning into the scene. This is usually for cutscenes, or areas that get them killed them due to hazards they're not smart enough to avoid.")]
		public bool suppressNpcEntry;

		[Tooltip("Prevents Captain from using orbital skills.")]
		public bool blockOrbitalSkills;

		[Tooltip("Is this stage allowed to be selected when using a random stage order (e.g., in Prismatic Trials?)")]
		public bool validForRandomSelection = true;

		[Tooltip("Allow objects from items to spawn in this level. Overrides the need to have the SceneType = Stage.")]
		public bool allowItemsToSpawnObjects;

		[Tooltip("Devotion lemurians should respawn later when find a valid node graph")]
		[Header("Artifact")]
		public bool needSkipDevotionRespawn;

		[Tooltip("A collection of stages that can be destinations of the teleporter.")]
		[Header("Destinations")]
		public SceneCollection destinationsGroup;

		[Tooltip("A collection of stages that can be destinations of the teleporter after looping.")]
		public SceneCollection loopedDestinationsGroup;

		[Tooltip("A collection of stages that can be destinations of the teleporter after looping.")]
		[SerializeField]
		private bool shouldUpdateSceneCollectionAfterLooping;

		[Tooltip("A bool that tracks if this stage is available before looping.")]
		public bool isLockedBeforeLooping;

		[Tooltip("For specific portal transitions that references the original and needs the looped version.")]
		public SceneDef loopedSceneDef;

		[ShowFieldObsolete]
		[Obsolete("Use destinationsGroup instead.")]
		[Tooltip("Stages that can be destinations of the teleporter.")]
		public SceneDef[] destinations = Array.Empty<SceneDef>();

		[Header("Portal Appearance")]
		public GameObject preferredPortalPrefab;

		private string _cachedName;

		[NonSerialized]
		[HideInInspector]
		[Obsolete]
		public List<string> sceneNameOverrides;

		public SceneIndex sceneDefIndex { get; set; }

		public string baseSceneName
		{
			get
			{
				if (string.IsNullOrEmpty(baseSceneNameOverride))
				{
					return cachedName;
				}
				return baseSceneNameOverride;
			}
		}

		public bool isFinalStage
		{
			get
			{
				if (sceneType == SceneType.Stage)
				{
					return !hasAnyDestinations;
				}
				return false;
			}
		}

		public bool hasAnyDestinations
		{
			get
			{
				if (destinations.Length == 0)
				{
					if ((bool)destinationsGroup)
					{
						return !destinationsGroup.isEmpty;
					}
					return false;
				}
				return true;
			}
		}

		[Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)]
		public new string name
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public string cachedName
		{
			get
			{
				return _cachedName;
			}
			set
			{
				base.name = value;
				_cachedName = value;
			}
		}

		private void Awake()
		{
			_cachedName = base.name;
		}

		private void OnValidate()
		{
			_cachedName = base.name;
			if (string.IsNullOrEmpty(sceneAddress?.AssetGUID))
			{
				AutoAssignSceneAddress();
			}
		}

		[ContextMenu("Auto-assign scene address")]
		private void AutoAssignSceneAddress()
		{
		}

		public void AddDestinationsToWeightedSelection(WeightedSelection<SceneDef> dest, Func<SceneDef, bool> canAdd = null)
		{
			if ((bool)destinationsGroup)
			{
				if (Run.instance.stageClearCount >= 4 && shouldUpdateSceneCollectionAfterLooping)
				{
					if ((bool)loopedDestinationsGroup)
					{
						loopedDestinationsGroup.AddToWeightedSelection(dest, canAdd);
					}
					else
					{
						UnityEngine.Debug.LogError("Should be looping but looped scene collection is missing.");
					}
				}
				else
				{
					destinationsGroup.AddToWeightedSelection(dest, canAdd);
				}
			}
			SceneDef[] array = destinations;
			foreach (SceneDef value in array)
			{
				dest.AddChoice(value, 1f);
			}
		}
	}
	[Serializable]
	public class AssetReferenceSceneDef : AssetReferenceT<SceneDef>
	{
		public AssetReferenceSceneDef(string guid)
			: base(guid)
		{
		}
	}
	[CreateAssetMenu(menuName = "RoR2/Sha256 Hash")]
	public class Sha256HashAsset : ScriptableObject
	{
		public Sha256Hash value;
	}
	[CreateAssetMenu(menuName = "RoR2/SimpleSpriteAnimation")]
	public class SimpleSpriteAnimation : ScriptableObject
	{
		[Serializable]
		public struct Frame
		{
			public Sprite sprite;

			public int duration;
		}

		public float frameRate = 60f;

		public Frame[] frames = Array.Empty<Frame>();
	}
	[CreateAssetMenu(menuName = "RoR2/SpawnCards/SpawnCard")]
	public class SpawnCard : ScriptableObject
	{
		public struct SpawnResult
		{
			public GameObject spawnedInstance;

			public DirectorSpawnRequest spawnRequest;

			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;

			public bool success;
		}

		public enum EliteRules
		{
			Default,
			ArtifactOnly,
			Lunar
		}

		public GameObject prefab;

		public bool sendOverNetwork;

		public HullClassification hullSize;

		public MapNodeGroup.GraphType nodeGraphType;

		[EnumMask(typeof(NodeFlags))]
		public NodeFlags requiredFlags;

		[EnumMask(typeof(NodeFlags))]
		public NodeFlags forbiddenFlags;

		public int directorCreditCost;

		public bool occupyPosition;

		[Tooltip("Default = default rules, ArtifactOnly = only elite when forced by the elite-only artifact, Lunar = special lunar elites only (+ regular w/ elite-only artifact)")]
		public EliteRules eliteRules;

		public static event Action<SpawnResult> onSpawnedServerGlobal;

		protected virtual void Spawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest spawnRequest, ref SpawnResult spawnResult)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position, rotation);
			if (sendOverNetwork)
			{
				NetworkServer.Spawn(gameObject);
			}
			spawnResult.spawnedInstance = gameObject;
			spawnResult.success = true;
		}

		public SpawnResult DoSpawn(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, DirectorSpawnRequest spawnRequest)
		{
			SpawnResult spawnResult = default(SpawnResult);
			spawnResult.spawnRequest = spawnRequest;
			spawnResult.position = position;
			spawnResult.rotation = rotation;
			SpawnResult spawnResult2 = spawnResult;
			Spawn(position, rotation, spawnRequest, ref spawnResult2);
			spawnRequest.onSpawnedServer?.Invoke(spawnResult2);
			SpawnCard.onSpawnedServerGlobal?.Invoke(spawnResult2);
			return spawnResult2;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SurfaceDef")]
	public class SurfaceDef : ScriptableObject
	{
		[HideInInspector]
		public SurfaceDefIndex surfaceDefIndex = SurfaceDefIndex.Invalid;

		public UnityEngine.Color approximateColor;

		public GameObject impactEffectPrefab;

		public GameObject footstepEffectPrefab;

		public string impactSoundString;

		public string materialSwitchString;

		public bool isSlippery;

		public bool isLava;

		public float damage;

		public float speedBoost;

		private void OnValidate()
		{
			if (!Application.isPlaying && surfaceDefIndex != SurfaceDefIndex.Invalid)
			{
				surfaceDefIndex = SurfaceDefIndex.Invalid;
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SurvivorDef")]
	public class SurvivorDef : ScriptableObject
	{
		private string _cachedName;

		public GameObject bodyPrefab;

		public GameObject displayPrefab;

		[Obsolete("Use 'unlockableDef' instead.")]
		public string unlockableName = "";

		public UnlockableDef unlockableDef;

		public string displayNameToken;

		public string descriptionToken;

		public string outroFlavorToken;

		public string mainEndingEscapeFailureFlavorToken;

		public UnityEngine.Color primaryColor;

		public float desiredSortPosition;

		public bool hidden;

		public SurvivorIndex survivorIndex { get; set; } = SurvivorIndex.None;


		[Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)]
		public new string name
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public string cachedName
		{
			get
			{
				return _cachedName;
			}
			set
			{
				base.name = value;
				_cachedName = value;
			}
		}

		private void Awake()
		{
			_cachedName = base.name;
		}

		private void OnValidate()
		{
			_cachedName = base.name;
		}

		[ContextMenu("Auto Populate Tokens")]
		public void AutoPopulateTokens()
		{
			string arg = base.name.ToUpperInvariant();
			displayNameToken = displayPrefab.GetComponent<CharacterBody>().baseNameToken;
			descriptionToken = $"{arg}_DESCRIPTION";
			outroFlavorToken = $"{arg}_OUTRO_FLAVOR";
		}

		[ContextMenu("Upgrade unlockableName to unlockableDef")]
		public void UpgradeUnlockableNameToUnlockableDef()
		{
			if (!string.IsNullOrEmpty(unlockableName) && !this.unlockableDef)
			{
				UnlockableDef unlockableDef = LegacyResourcesAPI.Load<UnlockableDef>("UnlockableDefs/" + unlockableName);
				if ((bool)unlockableDef)
				{
					this.unlockableDef = unlockableDef;
					unlockableName = null;
				}
			}
			EditorUtil.SetDirty(this);
		}

		public ExpansionDef GetRequiredExpansion()
		{
			ExpansionRequirementComponent component = bodyPrefab.GetComponent<ExpansionRequirementComponent>();
			if (!component)
			{
				return null;
			}
			return component.requiredExpansion;
		}

		public EntitlementDef GetRequiredEntitlement()
		{
			ExpansionDef requiredExpansion = GetRequiredExpansion();
			if (!requiredExpansion)
			{
				return null;
			}
			return requiredExpansion.requiredEntitlement;
		}

		public bool CheckUserHasRequiredEntitlement(NetworkUser networkUser)
		{
			EntitlementDef requiredEntitlement = GetRequiredEntitlement();
			if (!requiredEntitlement)
			{
				return true;
			}
			return EntitlementManager.networkUserEntitlementTracker.UserHasEntitlement(networkUser, requiredEntitlement);
		}

		public bool CheckUserHasRequiredEntitlement(LocalUser localUser)
		{
			EntitlementDef requiredEntitlement = GetRequiredEntitlement();
			if (!requiredEntitlement)
			{
				return true;
			}
			return EntitlementManager.localUserEntitlementTracker.UserHasEntitlement(localUser, requiredEntitlement);
		}

		public bool CheckLocalUserHasRequiredEntitlement()
		{
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				if (CheckUserHasRequiredEntitlement(readOnlyLocalUsers))
				{
					return true;
				}
			}
			return false;
		}

		public bool CheckRequiredExpansionEnabled(NetworkUser networkUser = null)
		{
			ExpansionDef requiredExpansion = GetRequiredExpansion();
			if (!requiredExpansion)
			{
				return true;
			}
			if (requiredExpansion.enabledChoice == null)
			{
				return false;
			}
			if ((bool)networkUser && !EntitlementManager.networkUserEntitlementTracker.UserHasEntitlement(networkUser, requiredExpansion.requiredEntitlement))
			{
				return false;
			}
			return (PreGameController.instance ? PreGameController.instance.readOnlyRuleBook : (Run.instance ? Run.instance.ruleBook : null))?.IsChoiceActive(requiredExpansion.enabledChoice) ?? true;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/Timer String Formatter")]
	public class TimerStringFormatter : ScriptableObject
	{
		[Serializable]
		public struct Format
		{
			[Serializable]
			public struct Unit
			{
				[CanBeNull]
				public string name;

				public double conversionRate;

				public uint minDigits;

				public uint maxDigits;

				[CanBeNull]
				public string prefix;

				[CanBeNull]
				public string suffix;
			}

			[CanBeNull]
			public Unit[] units;

			public string prefix;

			public string suffix;

			public static Format Clone(in Format src)
			{
				Format result = default(Format);
				result.prefix = src.prefix;
				result.suffix = src.suffix;
				result.units = ((src.units != null) ? ArrayUtils.Clone(src.units) : null);
				return result;
			}
		}

		public Format format = defaultFormat;

		private const double hoursPerDay = 24.0;

		private const double minutesPerDay = 1440.0;

		private const double secondsPerDay = 86400.0;

		private const double minutesPerHour = 60.0;

		private const double secondsPerMinute = 60.0;

		private const double secondsPerSecond = 1.0;

		private const double secondsPerCentisecond = 0.01;

		private const double secondsPerHour = 3600.0;

		private static readonly Format defaultFormat = new Format
		{
			prefix = "<mspace=0.5em>",
			suffix = "</mspace>",
			units = new Format.Unit[5]
			{
				new Format.Unit
				{
					name = "days",
					conversionRate = 86400.0,
					maxDigits = 2147483647u,
					minDigits = 2u,
					prefix = string.Empty,
					suffix = string.Empty
				},
				new Format.Unit
				{
					name = "hours",
					conversionRate = 3600.0,
					maxDigits = 2u,
					minDigits = 2u,
					prefix = ":",
					suffix = string.Empty
				},
				new Format.Unit
				{
					name = "minutes",
					conversionRate = 60.0,
					maxDigits = 2u,
					minDigits = 2u,
					prefix = ":",
					suffix = string.Empty
				},
				new Format.Unit
				{
					name = "seconds",
					conversionRate = 1.0,
					maxDigits = 2u,
					minDigits = 2u,
					prefix = ":",
					suffix = string.Empty
				},
				new Format.Unit
				{
					name = "centiseconds",
					conversionRate = 0.01,
					maxDigits = 2u,
					minDigits = 2u,
					prefix = "<voffset=0.4em><size=40%><mspace=0.5em>.",
					suffix = "</size></voffset></mspace>"
				}
			}
		};

		public void AppendToStringBuilder(double seconds, [NotNull] StringBuilder dest)
		{
			double num = seconds;
			if (!string.IsNullOrEmpty(format.prefix))
			{
				dest.Append(format.prefix);
			}
			if (num < 0.0)
			{
				num = 0.0 - num;
				dest.Append("-");
			}
			Format.Unit[] units = format.units;
			for (int i = 0; i < units.Length; i++)
			{
				Format.Unit unit = units[i];
				double num2 = Math.Floor(num / unit.conversionRate);
				num -= num2 * unit.conversionRate;
				int num3 = (int)num2;
				uint minDigits = unit.minDigits;
				uint num4 = unit.maxDigits;
				if (num4 < minDigits)
				{
					num4 = minDigits;
				}
				if (num4 != 0 && (minDigits != 0 || num3 >= 10))
				{
					if (!string.IsNullOrEmpty(unit.prefix))
					{
						dest.Append(unit.prefix);
					}
					dest.AppendInt(num3, minDigits, num4);
					if (!string.IsNullOrEmpty(unit.suffix))
					{
						dest.Append(unit.suffix);
					}
				}
			}
			if (!string.IsNullOrEmpty(format.suffix))
			{
				dest.Append(format.suffix);
			}
		}

		private void Reset()
		{
			format = Format.Clone(in defaultFormat);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/UI Layer")]
	public class UILayer : ScriptableObject
	{
		public int priority;
	}
	[CreateAssetMenu(menuName = "RoR2/UnlockableDef")]
	public class UnlockableDef : ScriptableObject
	{
		private string _cachedName;

		public string nameToken = "???";

		[Obsolete("UnlockableDef.displayModelPath is obsolete. Use .displayModel instead.", false)]
		public string displayModelPath = "Prefabs/NullModel";

		public GameObject displayModelPrefab;

		public bool hidden;

		public Sprite achievementIcon;

		[Tooltip("Set this to override Unlockable Catalog automatic Expansion linking")]
		public ExpansionDef requiredExpansion;

		public UnlockableIndex index { get; set; } = UnlockableIndex.None;


		[Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)]
		public new string name
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public string cachedName
		{
			get
			{
				return _cachedName;
			}
			set
			{
				base.name = value;
				_cachedName = value;
			}
		}

		[NotNull]
		public Func<string> getHowToUnlockString { get; set; } = () => "???";


		[NotNull]
		public Func<string> getUnlockedString { get; set; } = () => "???";


		public int sortScore { get; set; }

		private void Awake()
		{
			_cachedName = base.name;
		}

		private void OnValidate()
		{
			_cachedName = base.name;
		}

		[ContextMenu("Update displayModelPath to displayModelPrefab")]
		private void ReplaceDisplayModelPrefabPathWithDirectReference()
		{
			string text = displayModelPath;
			if (!string.IsNullOrEmpty(text))
			{
				GameObject gameObject = LegacyResourcesAPI.Load<GameObject>(text);
				if ((bool)gameObject)
				{
					displayModelPrefab = gameObject;
					displayModelPath = string.Empty;
					EditorUtil.SetDirty(this);
				}
			}
		}

		[ConCommand(commandName = "unlockable_migrate", flags = ConVarFlags.None, helpText = "Generates UnlockableDef assets from the existing catalog entries.")]
		private static void CCUnlockableMigrate(ConCommandArgs args)
		{
			for (UnlockableIndex unlockableIndex = (UnlockableIndex)0; (int)unlockableIndex < UnlockableCatalog.unlockableCount; unlockableIndex++)
			{
				EditorUtil.CopyToScriptableObject<UnlockableDef, UnlockableDef>(UnlockableCatalog.GetUnlockableDef(unlockableIndex), "Assets/RoR2/Resources/UnlockableDefs/");
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/MiscPickupDefs/VoidCoinDef")]
	public class VoidCoinDef : MiscPickupDef
	{
		public override void GrantPickup(ref PickupDef.GrantContext context)
		{
			if ((bool)context.body.master)
			{
				context.body.master.GiveVoidCoins(coinValue);
				context.shouldDestroy = true;
				context.shouldNotify = true;
			}
			else
			{
				context.shouldNotify = false;
				context.shouldDestroy = false;
			}
		}
	}
	[RequireComponent(typeof(Camera))]
	public class BlurOptimized : MonoBehaviour
	{
		public enum BlurType
		{
			StandardGauss,
			SgxGauss
		}

		[Range(0f, 2f)]
		public int downsample = 1;

		[Range(0f, 10f)]
		public float blurSize = 3f;

		[Range(1f, 4f)]
		public int blurIterations = 2;

		public BlurType blurType;

		[HideInInspector]
		public Material blurMaterial;

		public void Start()
		{
			blurMaterial = new Material(LegacyShaderAPI.Find("Hidden/FastBlur"));
			base.enabled = false;
		}

		public void OnRenderImage(RenderTexture source, RenderTexture destination)
		{
			float num = 1f / (1f * (float)(1 << downsample));
			blurMaterial.SetVector("_Parameter", new UnityEngine.Vector4(blurSize * num, (0f - blurSize) * num, 0f, 0f));
			source.filterMode = FilterMode.Bilinear;
			int width = source.width >> downsample;
			int height = source.height >> downsample;
			RenderTexture renderTexture = RenderTexture.GetTemporary(width, height, 0, source.format);
			renderTexture.filterMode = FilterMode.Bilinear;
			Graphics.Blit(source, renderTexture, blurMaterial, 0);
			int num2 = ((blurType != 0) ? 2 : 0);
			for (int i = 0; i < blurIterations; i++)
			{
				float num3 = (float)i * 1f;
				blurMaterial.SetVector("_Parameter", new UnityEngine.Vector4(blurSize * num + num3, (0f - blurSize) * num - num3, 0f, 0f));
				RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, source.format);
				temporary.filterMode = FilterMode.Bilinear;
				Graphics.Blit(renderTexture, temporary, blurMaterial, 1 + num2);
				RenderTexture.ReleaseTemporary(renderTexture);
				renderTexture = temporary;
				temporary = RenderTexture.GetTemporary(width, height, 0, source.format);
				temporary.filterMode = FilterMode.Bilinear;
				Graphics.Blit(renderTexture, temporary, blurMaterial, 2 + num2);
				RenderTexture.ReleaseTemporary(renderTexture);
				renderTexture = temporary;
			}
			Graphics.Blit(renderTexture, destination);
			RenderTexture.ReleaseTemporary(renderTexture);
		}
	}
	[Flags]
	public enum DamageType : uint
	{
		Generic = 0u,
		NonLethal = 1u,
		BypassArmor = 2u,
		ResetCooldownsOnKill = 4u,
		SlowOnHit = 8u,
		WeakPointHit = 0x10u,
		Stun1s = 0x20u,
		BypassBlock = 0x40u,
		IgniteOnHit = 0x80u,
		Freeze2s = 0x100u,
		ClayGoo = 0x200u,
		BleedOnHit = 0x400u,
		Silent = 0x800u,
		PoisonOnHit = 0x1000u,
		PercentIgniteOnHit = 0x2000u,
		WeakOnHit = 0x4000u,
		Nullify = 0x8000u,
		VoidDeath = 0x10000u,
		AOE = 0x20000u,
		BypassOneShotProtection = 0x40000u,
		BonusToLowHealth = 0x80000u,
		BlightOnHit = 0x100000u,
		FallDamage = 0x200000u,
		CrippleOnHit = 0x400000u,
		ApplyMercExpose = 0x800000u,
		Shock5s = 0x1000000u,
		LunarSecondaryRootOnHit = 0x2000000u,
		DoT = 0x4000000u,
		SuperBleedOnCrit = 0x8000000u,
		GiveSkullOnKill = 0x10000000u,
		FruitOnHit = 0x20000000u,
		LunarRuin = 0x40000000u,
		OutOfBounds = 0x80000000u
	}
	[Flags]
	public enum DamageTypeExtended : uint
	{
		Generic = 0u,
		ChefSearDamage = 0x4000000u,
		SojournVehicleDamage = 0x8000000u,
		DamagePercentOfMaxHealth = 0x10000000u,
		ApplyBuffPermanently = 0x20000000u,
		DisableAllSkills = 0x40000000u,
		OutOfBounds = 0x80000000u
	}
	[Serializable]
	[StructLayout(LayoutKind.Explicit)]
	public struct DamageTypeCombo
	{
		internal static readonly DamageTypeCombo Generic = new DamageTypeCombo
		{
			damageType = DamageType.Generic,
			damageTypeExtended = DamageTypeExtended.Generic
		};

		[FieldOffset(0)]
		[NonSerialized]
		public ulong damageTypeCombined;

		[FieldOffset(0)]
		public DamageType damageType;

		[FieldOffset(4)]
		public DamageTypeExtended damageTypeExtended;

		public DamageTypeCombo(DamageTypeCombo damageType, DamageTypeExtended damageTypeExtended)
		{
			this = default(DamageTypeCombo);
			this.damageType = damageType;
			this.damageTypeExtended = damageTypeExtended;
		}

		public static implicit operator DamageTypeCombo(DamageType damage)
		{
			DamageTypeCombo result = default(DamageTypeCombo);
			result.damageType = damage;
			return result;
		}

		public static implicit operator DamageTypeCombo(DamageTypeExtended damage)
		{
			DamageTypeCombo result = default(DamageTypeCombo);
			result.damageTypeExtended = damage;
			return result;
		}

		public static implicit operator DamageTypeCombo(ulong damage)
		{
			DamageTypeCombo result = default(DamageTypeCombo);
			result.damageTypeCombined = damage;
			return result;
		}

		public static implicit operator DamageType(DamageTypeCombo combo)
		{
			return combo.damageType;
		}

		public static implicit operator DamageTypeExtended(DamageTypeCombo combo)
		{
			return combo.damageTypeExtended;
		}

		public static implicit operator ulong(DamageTypeCombo combo)
		{
			return combo.damageTypeCombined;
		}

		public static DamageTypeCombo operator &(DamageTypeCombo operand1, DamageTypeCombo operand2)
		{
			return new DamageTypeCombo(operand1.damageType & operand2.damageType, operand1.damageTypeExtended & operand2.damageTypeExtended);
		}

		public static DamageTypeCombo operator |(DamageTypeCombo operand1, DamageTypeCombo operand2)
		{
			return new DamageTypeCombo(operand1.damageType | operand2.damageType, operand1.damageTypeExtended | operand2.damageTypeExtended);
		}

		public static DamageTypeCombo operator ^(DamageTypeCombo operand1, DamageTypeCombo operand2)
		{
			return new DamageTypeCombo(operand1.damageType ^ operand2.damageType, operand1.damageTypeExtended ^ operand2.damageTypeExtended);
		}

		public static DamageTypeCombo operator ~(DamageTypeCombo operand)
		{
			return new DamageTypeCombo(~operand.damageType, ~operand.damageTypeExtended);
		}

		public override string ToString()
		{
			return $"DamageType: {damageType}, DamageTypeExtended: {damageTypeExtended}";
		}
	}
	public enum DamageColorIndex : byte
	{
		Default,
		Heal,
		Bleed,
		Item,
		Poison,
		WeakPoint,
		CritHeal,
		DeathMark,
		SuperBleed,
		Void,
		Nearby,
		Fragile,
		Sniper,
		Luminous,
		Count
	}
	public static class DamageColor
	{
		private static UnityEngine.Color[] colors;

		static DamageColor()
		{
			colors = new UnityEngine.Color[14];
			colors[0] = UnityEngine.Color.white;
			colors[1] = new UnityEngine.Color(28f / 85f, 84f / 85f, 0.1764706f);
			colors[2] = new UnityEngine.Color(0.79607844f, 16f / 85f, 16f / 85f);
			colors[8] = new UnityEngine.Color(0.9372549f, 8f / 85f, 8f / 85f);
			colors[9] = new Color32(237, 127, 205, byte.MaxValue);
			colors[3] = new UnityEngine.Color(0.827451f, 0.7490196f, 16f / 51f);
			colors[4] = new UnityEngine.Color(0.76862746f, 0.96862745f, 0.34901962f);
			colors[5] = new UnityEngine.Color(0.9372549f, 44f / 85f, 0.20392157f);
			colors[7] = new UnityEngine.Color(0.6392157f, 0.2f, 0.20784314f);
			colors[10] = new UnityEngine.Color(47f / 51f, 23f / 51f, 0.827451f);
			colors[11] = new UnityEngine.Color(1f, 47f / 51f, 32f / 51f);
			colors[12] = new UnityEngine.Color(1f, 8f / 15f, 0.54509807f);
			colors[13] = UnityEngine.Color.yellow;
		}

		public static UnityEngine.Color FindColor(DamageColorIndex colorIndex)
		{
			if ((int)colorIndex < 0 || (int)colorIndex >= 14)
			{
				return UnityEngine.Color.white;
			}
			return colors[(uint)colorIndex];
		}
	}
	public class DamageInfo
	{
		public float damage;

		public bool crit;

		public GameObject inflictor;

		public GameObject attacker;

		public UnityEngine.Vector3 position;

		public UnityEngine.Vector3 force;

		public bool rejected;

		public bool delayedDamageSecondHalf;

		public ProcChainMask procChainMask;

		public float procCoefficient = 1f;

		public DamageTypeCombo damageType = DamageType.Generic;

		public DamageColorIndex damageColorIndex;

		public DotController.DotIndex dotIndex = DotController.DotIndex.None;

		public bool canRejectForce = true;

		public void ModifyDamageInfo(HurtBox.DamageModifier damageModifier)
		{
			switch (damageModifier)
			{
			case HurtBox.DamageModifier.Weak:
				damageType |= (DamageTypeCombo)DamageType.WeakPointHit;
				break;
			case HurtBox.DamageModifier.Normal:
			case HurtBox.DamageModifier.SniperTarget:
				break;
			}
		}
	}
	public class DamageReport
	{
		public readonly HealthComponent victim;

		public readonly CharacterBody victimBody;

		public readonly BodyIndex victimBodyIndex;

		public readonly TeamIndex victimTeamIndex;

		public readonly CharacterMaster victimMaster;

		public readonly bool victimIsElite;

		public readonly bool victimIsBoss;

		public readonly bool victimIsChampion;

		public readonly DamageInfo damageInfo;

		public readonly GameObject attacker;

		public readonly CharacterBody attackerBody;

		public readonly BodyIndex attackerBodyIndex;

		public readonly TeamIndex attackerTeamIndex;

		public readonly CharacterMaster attackerMaster;

		public readonly CharacterMaster attackerOwnerMaster;

		public readonly BodyIndex attackerOwnerBodyIndex;

		public readonly DotController.DotIndex dotType;

		public readonly float damageDealt;

		public readonly float combinedHealthBeforeDamage;

		public readonly bool hitLowHealth;

		public bool isFriendlyFire
		{
			get
			{
				if (attackerTeamIndex == victimTeamIndex)
				{
					return attackerTeamIndex != TeamIndex.None;
				}
				return false;
			}
		}

		public bool isFallDamage => (ulong)(damageInfo.damageType & DamageType.FallDamage) != 0;

		public DamageReport(DamageInfo damageInfo, HealthComponent victim, float damageDealt, float combinedHealthBeforeDamage)
		{
			this.damageInfo = damageInfo;
			this.victim = victim;
			victimBody = (victim ? victim.body : null);
			if ((bool)victimBody)
			{
				victimBodyIndex = victimBody.bodyIndex;
				victimMaster = victimBody.master;
				victimIsElite = victimBody.isElite;
				victimIsBoss = victimBody.isBoss;
				victimIsChampion = victimBody.isChampion;
				if ((bool)victimBody.teamComponent)
				{
					victimTeamIndex = victimBody.teamComponent.teamIndex;
				}
				else
				{
					victimTeamIndex = TeamIndex.None;
				}
			}
			else
			{
				victimBodyIndex = BodyIndex.None;
				victimTeamIndex = TeamIndex.None;
				victimIsElite = false;
				victimIsBoss = false;
				victimIsChampion = false;
			}
			attacker = damageInfo.attacker;
			attackerBody = (attacker ? attacker.GetComponent<CharacterBody>() : null);
			if ((bool)attackerBody)
			{
				attackerBodyIndex = attackerBody.bodyIndex;
				if ((bool)attackerBody.teamComponent)
				{
					attackerTeamIndex = attackerBody.teamComponent.teamIndex;
				}
				else
				{
					attackerTeamIndex = TeamIndex.None;
				}
				attackerOwnerBodyIndex = BodyIndex.None;
				attackerMaster = attackerBody.master;
				if ((bool)attackerMaster && (bool)attackerMaster.minionOwnership)
				{
					attackerOwnerMaster = attackerMaster.minionOwnership.ownerMaster;
					if ((bool)attackerOwnerMaster)
					{
						CharacterBody body = attackerOwnerMaster.GetBody();
						if ((bool)body)
						{
							attackerOwnerBodyIndex = body.bodyIndex;
						}
					}
				}
			}
			else
			{
				attackerBodyIndex = BodyIndex.None;
				attackerTeamIndex = TeamIndex.None;
				attackerOwnerBodyIndex = BodyIndex.None;
			}
			if ((bool)victim)
			{
				hitLowHealth = victim.isHealthLow;
			}
			else
			{
				hitLowHealth = false;
			}
			if (damageInfo != null)
			{
				dotType = damageInfo.dotIndex;
			}
			this.damageDealt = damageDealt;
			this.combinedHealthBeforeDamage = combinedHealthBeforeDamage;
		}

		public StringBuilder AppendToStringBuilderMultiline(StringBuilder stringBuilder)
		{
			stringBuilder.Append("VictimBody=").AppendLine(ObjToString(victimBody));
			stringBuilder.Append("VictimTeamIndex=").AppendLine(victimTeamIndex.ToString());
			stringBuilder.Append("VictimMaster=").AppendLine(ObjToString(victimMaster));
			stringBuilder.Append("AttackerBody=").AppendLine(ObjToString(attackerBody));
			stringBuilder.Append("AttackerTeamIndex=").AppendLine(attackerTeamIndex.ToString());
			stringBuilder.Append("AttackerMaster=").AppendLine(ObjToString(attackerMaster));
			stringBuilder.Append("Inflictor=").AppendLine(ObjToString(damageInfo.inflictor));
			stringBuilder.Append("Damage=").AppendLine(damageInfo.damage.ToString());
			stringBuilder.Append("Crit=").AppendLine(damageInfo.crit.ToString());
			stringBuilder.Append("ProcChainMask=").AppendLine(damageInfo.procChainMask.ToString());
			stringBuilder.Append("ProcCoefficient=").AppendLine(damageInfo.procCoefficient.ToString());
			stringBuilder.Append("DamageType=").AppendLine(damageInfo.damageType.ToString());
			stringBuilder.Append("DotIndex=").AppendLine(damageInfo.dotIndex.ToString());
			stringBuilder.Append("DamageColorIndex=").AppendLine(damageInfo.damageColorIndex.ToString());
			stringBuilder.Append("Position=").AppendLine(damageInfo.position.ToString());
			stringBuilder.Append("Force=").AppendLine(damageInfo.force.ToString());
			stringBuilder.Append("Rejected=").AppendLine(damageInfo.rejected.ToString());
			return stringBuilder;
			static string ObjToString(object obj)
			{
				if (obj == null)
				{
					return "null";
				}
				return obj.ToString();
			}
		}

		public override string ToString()
		{
			return AppendToStringBuilderMultiline(new StringBuilder()).ToString();
		}
	}
	[Serializable]
	public class DamageReportUnityEvent : UnityEvent<DamageReport>
	{
	}
	public static class DefaultControllerMaps
	{
		public delegate void LogFormatFunction(string inFormat, params object[] inParams);

		public const string defaultKeyboardMapString = "<?xml version=\"1.0\" encoding=\"utf-16\"?><KeyboardMap dataVersion=\"2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://guavaman.com/rewired http://guavaman.com/schemas/rewired/1.1/KeyboardMap.xsd\" xmlns=\"http://guavaman.com/rewired\"><sourceMapId>0</sourceMapId><categoryId>0</categoryId><layoutId>0</layoutId><name></name><hardwareGuid>00000000-0000-0000-0000-000000000000</hardwareGuid><enabled>false</enabled><buttonMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>0</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>100</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>0</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>1</axisContribution><keyboardKeyCode>97</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>1</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>119</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>1</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>1</axisContribution><keyboardKeyCode>115</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>4</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>32</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>18</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>306</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>5</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>101</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>6</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>113</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>9</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>304</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>10</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>114</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>19</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>9</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></buttonMaps></KeyboardMap>";

		public const string defaultMouseMapString = "<?xml version=\"1.0\" encoding=\"utf-16\"?><MouseMap dataVersion=\"2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://guavaman.com/rewired http://guavaman.com/schemas/rewired/1.1/MouseMap.xsd\" xmlns=\"http://guavaman.com/rewired\"><sourceMapId>0</sourceMapId><categoryId>0</categoryId><layoutId>0</layoutId><name></name><hardwareGuid>00000000-0000-0000-0000-000000000000</hardwareGuid><enabled>false</enabled><buttonMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>7</actionId><elementType>1</elementType><elementIdentifierId>3</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>8</actionId><elementType>1</elementType><elementIdentifierId>4</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>28</actionId><elementType>1</elementType><elementIdentifierId>5</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></buttonMaps><axisMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>2</actionId><elementType>0</elementType><elementIdentifierId>0</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>3</actionId><elementType>0</elementType><elementIdentifierId>1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></axisMaps></MouseMap>";

		public static readonly Guid gamepadTemplateGuid = new Guid("83b427e4-086f-47f3-bb06-be266abd1ca5");

		public static readonly Guid xboneControllerGuid = new Guid("19002688-7406-4f4a-8340-8d25335406c8");

		public static readonly Guid xbox360ControllerGuid = new Guid("d74a350e-fe8b-4e9e-bbcd-efff16d34115");

		public static readonly Guid switchDualGuid = new Guid("521b808c-0248-4526-bc10-f1d16ee76bf1");

		public static readonly Guid switchHandheldGuid = new Guid("1fbdd13b-0795-4173-8a95-a2a75de9d204");

		public static readonly Guid switchProGuid = new Guid("7bf3154b-9db8-4d52-950f-cd0eed8a5819");

		public static readonly Guid PS4Guid = new Guid("cd9718bf-a87a-44bc-8716-60a0def28a9f");

		public static readonly Guid PS5Guid = new Guid("5286706d-19b4-4a45-b635-207ce78d8394");

		public static readonly string xbox360ControllerName = "Xbox 360 Controller";

		public static readonly string xboxOneControllerName = "Xbox One Controller";

		public static readonly string dualshock4ControllerName = "Sony DualShock 4";

		public static readonly string dualshock4ControllerNameAlt = "PlayStation Controller";

		public static readonly string dualSenseController = "Sony DualSense";

		public static readonly string switchControllerName = "Nintendo Controller";

		public static readonly string switchProControllerName = "Nintendo Switch Pro Controller";

		public static readonly string switchProControllerNameAlt = "Pro Controller";

		public static readonly string stadiaControllerName = "Stadia Controller";

		public static readonly KeyboardMap defaultKeyboardMap = (KeyboardMap)ControllerMap.CreateFromXml(ControllerType.Keyboard, "<?xml version=\"1.0\" encoding=\"utf-16\"?><KeyboardMap dataVersion=\"2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://guavaman.com/rewired http://guavaman.com/schemas/rewired/1.1/KeyboardMap.xsd\" xmlns=\"http://guavaman.com/rewired\"><sourceMapId>0</sourceMapId><categoryId>0</categoryId><layoutId>0</layoutId><name></name><hardwareGuid>00000000-0000-0000-0000-000000000000</hardwareGuid><enabled>false</enabled><buttonMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>0</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>100</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>0</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>1</axisContribution><keyboardKeyCode>97</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>1</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>119</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>1</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>1</axisContribution><keyboardKeyCode>115</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>4</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>32</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>18</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>306</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>5</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>101</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>6</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>113</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>9</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>304</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>10</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>114</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>19</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>9</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></buttonMaps></KeyboardMap>");

		public static readonly MouseMap defaultMouseMap = (MouseMap)ControllerMap.CreateFromXml(ControllerType.Mouse, "<?xml version=\"1.0\" encoding=\"utf-16\"?><MouseMap dataVersion=\"2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://guavaman.com/rewired http://guavaman.com/schemas/rewired/1.1/MouseMap.xsd\" xmlns=\"http://guavaman.com/rewired\"><sourceMapId>0</sourceMapId><categoryId>0</categoryId><layoutId>0</layoutId><name></name><hardwareGuid>00000000-0000-0000-0000-000000000000</hardwareGuid><enabled>false</enabled><buttonMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>7</actionId><elementType>1</elementType><elementIdentifierId>3</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>8</actionId><elementType>1</elementType><elementIdentifierId>4</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>28</actionId><elementType>1</elementType><elementIdentifierId>5</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></buttonMaps><axisMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>2</actionId><elementType>0</elementType><elementIdentifierId>0</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>3</actionId><elementType>0</elementType><elementIdentifierId>1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></axisMaps></MouseMap>");

		private static Dictionary<Guid, string> _DefaultJoystickMaps_Xml = new Dictionary<Guid, string>();

		private static bool _FilledDefaultJoystickMaps = false;

		public static JoystickMap DefaultJoystickMap
		{
			get
			{
				FillDefaultJoystickMaps();
				if (_DefaultJoystickMaps_Xml.ContainsKey(PlatformManager.DefaultControllerGuid))
				{
					string xmlString = _DefaultJoystickMaps_Xml[PlatformManager.DefaultControllerGuid];
					return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString) as JoystickMap;
				}
				return null;
			}
		}

		public static bool RewiredLoggingEnabled()
		{
			return false;
		}

		public static void RewiredLogLineForce(LogFormatFunction inLogFcn, string inFormat, params object[] inParams)
		{
			if (inParams != null && inParams.Length != 0)
			{
				inLogFcn(inFormat, inParams);
			}
			else
			{
				inLogFcn(inFormat);
			}
		}

		public static void RewiredLogLine(LogFormatFunction inLogFcn, string inFormat, params object[] inParams)
		{
		}

		public static void RewiredDebugLog(string inFormat, params object[] inParams)
		{
			RewiredLogLine(UnityEngine.Debug.LogFormat, inFormat, inParams);
		}

		public static void RewiredDebugWarn(string inFormat, params object[] inParams)
		{
			RewiredLogLine(UnityEngine.Debug.LogWarningFormat, inFormat, inParams);
		}

		public static void RewiredDebugError(string inFormat, params object[] inParams)
		{
			RewiredLogLineForce(UnityEngine.Debug.LogErrorFormat, inFormat, inParams);
		}

		public static void RewiredDebugLogForce(string inFormat, params object[] inParams)
		{
			RewiredLogLineForce(UnityEngine.Debug.LogFormat, inFormat, inParams);
		}

		public static void RewiredDebugWarnForce(string inFormat, params object[] inParams)
		{
			RewiredLogLineForce(UnityEngine.Debug.LogWarningFormat, inFormat, inParams);
		}

		private static void FillDefaultJoystickMaps()
		{
			if (_FilledDefaultJoystickMaps)
			{
				return;
			}
			RewiredDebugLog("FillDefaultJoysticksMap");
			if (ReInput.mapping != null)
			{
				JoystickMap joystickMapInstance = ReInput.mapping.GetJoystickMapInstance(gamepadTemplateGuid, 0, 0);
				JoystickMap joystickMapInstance2 = ReInput.mapping.GetJoystickMapInstance(xboneControllerGuid, 0, 0);
				JoystickMap joystickMapInstance3 = ReInput.mapping.GetJoystickMapInstance(xbox360ControllerGuid, 0, 0);
				JoystickMap joystickMapInstance4 = ReInput.mapping.GetJoystickMapInstance(PS4Guid, 0, 0);
				JoystickMap joystickMapInstance5 = ReInput.mapping.GetJoystickMapInstance(PS5Guid, 0, 0);
				JoystickMap joystickMapInstance6 = ReInput.mapping.GetJoystickMapInstance(switchProGuid, 0, 0);
				JoystickMap joystickMapInstance7 = ReInput.mapping.GetJoystickMapInstance(switchDualGuid, 0, 0);
				JoystickMap joystickMapInstance8 = ReInput.mapping.GetJoystickMapInstance(switchHandheldGuid, 0, 0);
				string value = joystickMapInstance.ToXmlString();
				string value2 = joystickMapInstance2.ToXmlString();
				string value3 = joystickMapInstance3.ToXmlString();
				string value4 = joystickMapInstance4.ToXmlString();
				string value5 = joystickMapInstance5.ToXmlString();
				string value6 = joystickMapInstance6.ToXmlString();
				string value7 = joystickMapInstance7.ToXmlString();
				string value8 = joystickMapInstance8.ToXmlString();
				_DefaultJoystickMaps_Xml.Add(gamepadTemplateGuid, value);
				if (joystickMapInstance2.buttonMapCount > 0)
				{
					_DefaultJoystickMaps_Xml.Add(xboneControllerGuid, value2);
				}
				_DefaultJoystickMaps_Xml.Add(xbox360ControllerGuid, value3);
				_DefaultJoystickMaps_Xml.Add(PS4Guid, value4);
				_DefaultJoystickMaps_Xml.Add(PS5Guid, value5);
				_DefaultJoystickMaps_Xml.Add(switchProGuid, value6);
				_DefaultJoystickMaps_Xml.Add(switchDualGuid, value7);
				_DefaultJoystickMaps_Xml.Add(switchHandheldGuid, value8);
				_FilledDefaultJoystickMaps = true;
			}
		}

		public static Dictionary<Guid, JoystickMap> GetDefaultJoystickMaps()
		{
			FillDefaultJoystickMaps();
			Dictionary<Guid, JoystickMap> dictionary = new Dictionary<Guid, JoystickMap>();
			foreach (KeyValuePair<Guid, string> item in _DefaultJoystickMaps_Xml)
			{
				JoystickMap value = ControllerMap.CreateFromXml(ControllerType.Joystick, item.Value) as JoystickMap;
				dictionary.Add(item.Key, value);
			}
			return dictionary;
		}

		public static KeyboardMap GetDefaultKeyboardMap()
		{
			return ControllerMap.CreateFromXml(ControllerType.Keyboard, "<?xml version=\"1.0\" encoding=\"utf-16\"?><KeyboardMap dataVersion=\"2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://guavaman.com/rewired http://guavaman.com/schemas/rewired/1.1/KeyboardMap.xsd\" xmlns=\"http://guavaman.com/rewired\"><sourceMapId>0</sourceMapId><categoryId>0</categoryId><layoutId>0</layoutId><name></name><hardwareGuid>00000000-0000-0000-0000-000000000000</hardwareGuid><enabled>false</enabled><buttonMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>0</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>100</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>0</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>1</axisContribution><keyboardKeyCode>97</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>1</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>119</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>1</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>1</axisContribution><keyboardKeyCode>115</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>4</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>32</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>18</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>306</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>5</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>101</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>6</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>113</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>9</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>304</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>10</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>114</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>19</actionId><elementType>1</elementType><elementIdentifierId>-1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>9</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></buttonMaps></KeyboardMap>") as KeyboardMap;
		}

		public static MouseMap GetDefaultMoustMap()
		{
			return ControllerMap.CreateFromXml(ControllerType.Mouse, "<?xml version=\"1.0\" encoding=\"utf-16\"?><MouseMap dataVersion=\"2\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://guavaman.com/rewired http://guavaman.com/schemas/rewired/1.1/MouseMap.xsd\" xmlns=\"http://guavaman.com/rewired\"><sourceMapId>0</sourceMapId><categoryId>0</categoryId><layoutId>0</layoutId><name></name><hardwareGuid>00000000-0000-0000-0000-000000000000</hardwareGuid><enabled>false</enabled><buttonMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>7</actionId><elementType>1</elementType><elementIdentifierId>3</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>8</actionId><elementType>1</elementType><elementIdentifierId>4</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>28</actionId><elementType>1</elementType><elementIdentifierId>5</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></buttonMaps><axisMaps><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>2</actionId><elementType>0</elementType><elementIdentifierId>0</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap><ActionElementMap><actionCategoryId>0</actionCategoryId><actionId>3</actionId><elementType>0</elementType><elementIdentifierId>1</elementIdentifierId><axisRange>0</axisRange><invert>false</invert><axisContribution>0</axisContribution><keyboardKeyCode>0</keyboardKeyCode><modifierKey1>0</modifierKey1><modifierKey2>0</modifierKey2><modifierKey3>0</modifierKey3><enabled>true</enabled></ActionElementMap></axisMaps></MouseMap>") as MouseMap;
		}

		public static JoystickMap GetDefaultJoystickMap(Guid inControllerGuid)
		{
			FillDefaultJoystickMaps();
			if (_DefaultJoystickMaps_Xml.ContainsKey(inControllerGuid))
			{
				string xmlString = _DefaultJoystickMaps_Xml[inControllerGuid];
				return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString) as JoystickMap;
			}
			RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}...");
			if (inControllerGuid == xboneControllerGuid && _DefaultJoystickMaps_Xml.ContainsKey(xbox360ControllerGuid))
			{
				RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... returning Xbox360 mapping (XInput detected)");
				string xmlString2 = _DefaultJoystickMaps_Xml[xbox360ControllerGuid];
				return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString2) as JoystickMap;
			}
			if (inControllerGuid == xbox360ControllerGuid && _DefaultJoystickMaps_Xml.ContainsKey(xboneControllerGuid))
			{
				RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... returning Xbone mapping (XInput detected)");
				string xmlString3 = _DefaultJoystickMaps_Xml[xboneControllerGuid];
				return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString3) as JoystickMap;
			}
			if (_DefaultJoystickMaps_Xml.ContainsKey(PlatformManager.DefaultControllerGuid))
			{
				RewiredDebugWarn($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... returning default");
				string xmlString4 = _DefaultJoystickMaps_Xml[PlatformManager.DefaultControllerGuid];
				return ControllerMap.CreateFromXml(ControllerType.Joystick, xmlString4) as JoystickMap;
			}
			RewiredDebugError($"GetDefaultControllerMap: Failed to find guid {inControllerGuid}... nor default {PlatformManager.DefaultControllerGuid}. Returning null");
			return null;
		}

		public static bool HardwareGuidsMatch(Guid inA, Guid inB)
		{
			if (inA == inB)
			{
				RewiredDebugLog("HardwareGuidsMatch: TRUE, direct match: {0} --> {1}", inA.ToString(), inB.ToString());
				return true;
			}
			RewiredDebugLog("HardwareGuidsMatch: FALSE, no match: {0} --> {1}", inA.ToString(), inB.ToString());
			return false;
		}

		public static Guid LocalHardwareGuidRemap(Guid inHardwareGuid)
		{
			Guid result = inHardwareGuid;
			RewiredDebugLog("LocalHardwareGuidRemap: {0} --> {1}", inHardwareGuid.ToString(), result.ToString());
			return result;
		}

		[ConCommand(commandName = "export_default_controller_maps", flags = ConVarFlags.None, helpText = "Prints all default Rewired ControllerMaps.")]
		public static void CCExportDefaultControllerMaps(ConCommandArgs args)
		{
		}
	}
	public struct DegreeSlices : IEnumerable<float>, IEnumerable
	{
		public struct Enumerator : IEnumerator<float>, IEnumerator, IDisposable
		{
			public readonly float sliceSize;

			public readonly float offset;

			public int i;

			public int iEnd;

			public float Current => (float)i * sliceSize + offset;

			object IEnumerator.Current => Current;

			public Enumerator(int sliceCount, float sliceOffset)
			{
				sliceSize = 360f / (float)sliceCount;
				offset = sliceOffset * sliceSize;
				i = -1;
				iEnd = sliceCount;
			}

			public void Dispose()
			{
			}

			public bool MoveNext()
			{
				i++;
				return i < iEnd;
			}

			public void Reset()
			{
				i = -1;
			}
		}

		public readonly int sliceCount;

		public readonly float sliceOffset;

		public DegreeSlices(int sliceCount, float sliceOffset)
		{
			this.sliceCount = sliceCount;
			this.sliceOffset = sliceOffset;
		}

		public Enumerator GetEnumerator()
		{
			return new Enumerator(sliceCount, sliceOffset);
		}

		IEnumerator<float> IEnumerable<float>.GetEnumerator()
		{
			return GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	public class DeployableMinionSpawner : IDisposable
	{
		public float respawnInterval = 30f;

		[CanBeNull]
		public SpawnCard spawnCard;

		public float minSpawnDistance = 3f;

		public float maxSpawnDistance = 40f;

		[NotNull]
		private Xoroshiro128Plus rng;

		private float respawnStopwatch = float.PositiveInfinity;

		[CanBeNull]
		public CharacterMaster ownerMaster { get; }

		public DeployableSlot deployableSlot { get; }

		public event Action<SpawnCard.SpawnResult> onMinionSpawnedServer;

		public DeployableMinionSpawner([CanBeNull] CharacterMaster ownerMaster, DeployableSlot deployableSlot, [NotNull] Xoroshiro128Plus rng)
		{
			this.ownerMaster = ownerMaster;
			this.deployableSlot = deployableSlot;
			this.rng = rng;
			RoR2Application.onFixedUpdate += FixedUpdate;
		}

		public void Dispose()
		{
			RoR2Application.onFixedUpdate -= FixedUpdate;
		}

		private void FixedUpdate()
		{
			if (!ownerMaster)
			{
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			int deployableCount = ownerMaster.GetDeployableCount(deployableSlot);
			int deployableSameSlotLimit = ownerMaster.GetDeployableSameSlotLimit(deployableSlot);
			if (deployableCount >= deployableSameSlotLimit)
			{
				return;
			}
			respawnStopwatch += fixedDeltaTime;
			if (!(respawnStopwatch >= respawnInterval))
			{
				return;
			}
			CharacterBody body = ownerMaster.GetBody();
			if ((bool)body && (bool)spawnCard)
			{
				try
				{
					SpawnMinion(spawnCard, body);
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
				respawnStopwatch = 0f;
			}
		}

		private void SpawnMinion([NotNull] SpawnCard spawnCard, [NotNull] CharacterBody spawnTarget)
		{
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Approximate,
				minDistance = minSpawnDistance,
				maxDistance = maxSpawnDistance,
				spawnOnTarget = spawnTarget.transform
			}, RoR2Application.rng);
			directorSpawnRequest.summonerBodyObject = ownerMaster.GetBodyObject();
			directorSpawnRequest.onSpawnedServer = OnMinionSpawnedServerInternal;
			DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
		}

		private void OnMinionSpawnedServerInternal([NotNull] SpawnCard.SpawnResult spawnResult)
		{
			GameObject spawnedInstance = spawnResult.spawnedInstance;
			if ((bool)spawnedInstance)
			{
				CharacterMaster component = spawnedInstance.GetComponent<CharacterMaster>();
				Deployable deployable = spawnedInstance.AddComponent<Deployable>();
				deployable.onUndeploy = deployable.onUndeploy ?? new UnityEvent();
				if ((bool)component)
				{
					deployable.onUndeploy.AddListener(component.TrueKill);
				}
				else
				{
					deployable.onUndeploy.AddListener(delegate
					{
						UnityEngine.Object.Destroy(spawnedInstance);
					});
				}
				ownerMaster.AddDeployable(deployable, deployableSlot);
			}
			this.onMinionSpawnedServer?.Invoke(spawnResult);
		}
	}
	public static class DevCommands
	{
		private class CvSvNetLogObjectIds : ToggleVirtualConVar
		{
			private static readonly CvSvNetLogObjectIds instance = new CvSvNetLogObjectIds("sv_net_log_object_ids", ConVarFlags.None, "0", "Logs objects associated with each network id to net_id_log.txt as encountered by the server.");

			private uint highestObservedId;

			private FieldInfo monitoredField;

			private TextWriter writer;

			public CvSvNetLogObjectIds(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				monitoredField = typeof(NetworkIdentity).GetField("s_NextNetworkId", BindingFlags.Static | BindingFlags.NonPublic);
			}

			protected override void OnEnable()
			{
				RoR2Application.onFixedUpdate += Update;
				RoR2Application.onUpdate += Update;
				writer = new StreamWriter("net_id_log.txt", append: false);
				highestObservedId = GetCurrentHighestID();
			}

			protected override void OnDisable()
			{
				writer.Dispose();
				writer = null;
				RoR2Application.onUpdate -= Update;
				RoR2Application.onFixedUpdate -= Update;
			}

			private uint GetCurrentHighestID()
			{
				return (uint)monitoredField.GetValue(null);
			}

			private void Update()
			{
				if (NetworkServer.active)
				{
					uint currentHighestID = GetCurrentHighestID();
					while (highestObservedId < currentHighestID)
					{
						GameObject gameObject = NetworkServer.FindLocalObject(new NetworkInstanceId(highestObservedId));
						writer.WriteLine(string.Format("[{0, 0:D10}]={1}", highestObservedId, gameObject ? gameObject.name : "null"));
						highestObservedId++;
					}
				}
			}
		}

		private static void AddTokenIfDefault(List<string> lines, string token)
		{
			if (!string.IsNullOrEmpty(token) && (object)Language.GetString(token) == token)
			{
				lines.Add(string.Format("\t\t\"{0}\": \"{0}\",", token));
			}
		}

		[ConCommand(commandName = "language_generate_tokens", flags = ConVarFlags.None, helpText = "Generates default token definitions to be inserted into a JSON language file.")]
		private static void CCLanguageGenerateTokens(ConCommandArgs args)
		{
			List<string> list = new List<string>();
			foreach (ItemDef item in ItemCatalog.allItems.Select(ItemCatalog.GetItemDef))
			{
				AddTokenIfDefault(list, item.nameToken);
				AddTokenIfDefault(list, item.pickupToken);
				AddTokenIfDefault(list, item.descriptionToken);
			}
			list.Add("\r\n");
			foreach (EquipmentDef item2 in EquipmentCatalog.allEquipment.Select(EquipmentCatalog.GetEquipmentDef))
			{
				AddTokenIfDefault(list, item2.nameToken);
				AddTokenIfDefault(list, item2.pickupToken);
				AddTokenIfDefault(list, item2.descriptionToken);
			}
		}

		[ConCommand(commandName = "rng_test_roll", flags = ConVarFlags.None, helpText = "Tests the RNG. First argument is a percent chance, second argument is a number of rolls to perform. Result is the average number of rolls that passed.")]
		private static void CCTestRng(ConCommandArgs args)
		{
			float argFloat = args.GetArgFloat(0);
			ulong argULong = args.GetArgULong(1);
			ulong num = 0uL;
			for (ulong num2 = 0uL; num2 < argULong; num2++)
			{
				if (RoR2Application.rng.RangeFloat(0f, 100f) < argFloat)
				{
					num++;
				}
			}
		}

		[ConCommand(commandName = "getpos", flags = ConVarFlags.None, helpText = "Prints the current position of the sender's body.")]
		private static void CCGetPos(ConCommandArgs args)
		{
			UnityEngine.Vector3 position = args.GetSenderBody().transform.position;
			UnityEngine.Debug.LogFormat("{0} {1} {2}", position.x, position.y, position.z);
		}

		[ConCommand(commandName = "setpos", flags = ConVarFlags.Cheat, helpText = "Teleports the sender's body to the specified position.")]
		private static void CCSetPos(ConCommandArgs args)
		{
			CharacterBody senderBody = args.GetSenderBody();
			TeleportHelper.TeleportGameObject(newPosition: new UnityEngine.Vector3(args.GetArgFloat(0), args.GetArgFloat(1), args.GetArgFloat(2)), gameObject: senderBody.gameObject);
		}

		[ConCommand(commandName = "create_object_from_resources", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Instantiates an object from the Resources folder where the sender is looking.")]
		private static void CreateObjectFromResources(ConCommandArgs args)
		{
			CharacterBody senderBody = args.GetSenderBody();
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>(args.GetArgString(0));
			if (!gameObject)
			{
				throw new ConCommandException("Prefab could not be found at the specified path. Argument must be a Resources/-relative path to a prefab.");
			}
			if (senderBody.GetComponent<InputBankTest>().GetAimRaycast(float.PositiveInfinity, out var hitInfo))
			{
				UnityEngine.Vector3 point = hitInfo.point;
				UnityEngine.Quaternion identity = UnityEngine.Quaternion.identity;
				NetworkServer.Spawn(UnityEngine.Object.Instantiate(gameObject, point, identity));
			}
		}

		[ConCommand(commandName = "resources_load_async_test", flags = ConVarFlags.None, helpText = "Tests Resources.LoadAsync. Loads the asset at the specified path and prints out the results of the operation.")]
		private static void CCResourcesLoadAsyncTest(ConCommandArgs args)
		{
			Resources.LoadAsync(args.GetArgString(0)).completed += Check;
			static void Check(AsyncOperation asyncOperation)
			{
			}
		}

		private static UnityEngine.Object FindObjectFromInstanceID(int instanceId)
		{
			return (UnityEngine.Object)typeof(UnityEngine.Object).GetMethod("FindObjectFromInstanceID", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[1] { instanceId });
		}

		[ConCommand(commandName = "dump_object_info", flags = ConVarFlags.None, helpText = "Prints debug info about the object with the provided instance ID.")]
		private static void CCDumpObjectInfo(ConCommandArgs args)
		{
			int argInt = args.GetArgInt(0);
			UnityEngine.Object @object = FindObjectFromInstanceID(argInt);
			if (!@object)
			{
				throw new Exception($"Object is not valid. objectInstanceId={argInt}");
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(@object.name);
			stringBuilder.AppendLine($"  instanceId={@object.GetInstanceID()}");
			stringBuilder.AppendLine("  type=" + @object.GetType().FullName);
			GameObject gameObject = null;
			if (@object is GameObject gameObject2)
			{
				gameObject = gameObject2;
			}
			else if (@object is Component component)
			{
				gameObject = component.gameObject;
			}
			if ((bool)gameObject)
			{
				stringBuilder.Append("  scene=\"" + gameObject.scene.name + "\"");
				stringBuilder.Append("  transformPath=" + Util.BuildPrefabTransformPath(gameObject.transform.root, gameObject.transform, appendCloneSuffix: false, includeRoot: true));
			}
			args.Log(stringBuilder.ToString());
		}
	}
	public enum DifficultyIndex
	{
		Invalid = -1,
		Easy,
		Normal,
		Hard,
		Eclipse1,
		Eclipse2,
		Eclipse3,
		Eclipse4,
		Eclipse5,
		Eclipse6,
		Eclipse7,
		Eclipse8,
		Count
	}
	public class DifficultyDef
	{
		public readonly float scalingValue;

		public readonly string descriptionToken;

		public readonly string nameToken;

		public readonly string iconPath;

		public readonly UnityEngine.Color color;

		public readonly string serverTag;

		private Sprite iconSprite;

		private bool foundIconSprite;

		public bool countsAsHardMode { get; private set; }

		public DifficultyDef(float scalingValue, string nameToken, string iconPath, string descriptionToken, UnityEngine.Color color, string serverTag, bool countsAsHardMode)
		{
			this.scalingValue = scalingValue;
			this.descriptionToken = descriptionToken;
			this.nameToken = nameToken;
			this.iconPath = iconPath;
			this.color = color;
			this.serverTag = serverTag;
			this.countsAsHardMode = countsAsHardMode;
		}

		public Sprite GetIconSprite()
		{
			if (!foundIconSprite)
			{
				iconSprite = LegacyResourcesAPI.Load<Sprite>(iconPath);
				foundIconSprite = iconSprite;
			}
			return iconSprite;
		}
	}
	public static class DifficultyCatalog
	{
		private static readonly DifficultyDef[] difficultyDefs;

		public static int standardDifficultyCount;

		static DifficultyCatalog()
		{
			standardDifficultyCount = 3;
			difficultyDefs = new DifficultyDef[11];
			difficultyDefs[0] = new DifficultyDef(1f, "DIFFICULTY_EASY_NAME", "Textures/DifficultyIcons/texDifficultyEasyIcon", "DIFFICULTY_EASY_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.EasyDifficulty), "dz", countsAsHardMode: false);
			difficultyDefs[1] = new DifficultyDef(2f, "DIFFICULTY_NORMAL_NAME", "Textures/DifficultyIcons/texDifficultyNormalIcon", "DIFFICULTY_NORMAL_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.NormalDifficulty), "rs", countsAsHardMode: false);
			difficultyDefs[2] = new DifficultyDef(3f, "DIFFICULTY_HARD_NAME", "Textures/DifficultyIcons/texDifficultyHardIcon", "DIFFICULTY_HARD_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[3] = new DifficultyDef(3f, "ECLIPSE_1_NAME", "Textures/DifficultyIcons/texDifficultyEclipse1Icon", "ECLIPSE_1_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[4] = new DifficultyDef(3f, "ECLIPSE_2_NAME", "Textures/DifficultyIcons/texDifficultyEclipse2Icon", "ECLIPSE_2_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[5] = new DifficultyDef(3f, "ECLIPSE_3_NAME", "Textures/DifficultyIcons/texDifficultyEclipse3Icon", "ECLIPSE_3_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[6] = new DifficultyDef(3f, "ECLIPSE_4_NAME", "Textures/DifficultyIcons/texDifficultyEclipse4Icon", "ECLIPSE_4_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[7] = new DifficultyDef(3f, "ECLIPSE_5_NAME", "Textures/DifficultyIcons/texDifficultyEclipse5Icon", "ECLIPSE_5_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[8] = new DifficultyDef(3f, "ECLIPSE_6_NAME", "Textures/DifficultyIcons/texDifficultyEclipse6Icon", "ECLIPSE_6_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[9] = new DifficultyDef(3f, "ECLIPSE_7_NAME", "Textures/DifficultyIcons/texDifficultyEclipse7Icon", "ECLIPSE_7_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
			difficultyDefs[10] = new DifficultyDef(3f, "ECLIPSE_8_NAME", "Textures/DifficultyIcons/texDifficultyEclipse8Icon", "ECLIPSE_8_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty), "mn", countsAsHardMode: true);
		}

		public static DifficultyDef GetDifficultyDef(DifficultyIndex difficultyIndex)
		{
			return ArrayUtils.GetSafe(difficultyDefs, (int)difficultyIndex);
		}
	}
	public class DLC1Content : IContentPackProvider
	{
		public static class Items
		{
			public static ItemDef MoveSpeedOnKill;

			public static ItemDef HealingPotion;

			public static ItemDef HealingPotionConsumed;

			public static ItemDef PermanentDebuffOnHit;

			public static ItemDef AttackSpeedAndMoveSpeed;

			public static ItemDef CritDamage;

			public static ItemDef BearVoid;

			public static ItemDef MushroomVoid;

			public static ItemDef CloverVoid;

			public static ItemDef StrengthenBurn;

			public static ItemDef GummyCloneIdentifier;

			public static ItemDef RegeneratingScrap;

			public static ItemDef RegeneratingScrapConsumed;

			public static ItemDef BleedOnHitVoid;

			public static ItemDef CritGlassesVoid;

			public static ItemDef TreasureCacheVoid;

			public static ItemDef SlowOnHitVoid;

			public static ItemDef MissileVoid;

			public static ItemDef ChainLightningVoid;

			public static ItemDef ExtraLifeVoid;

			public static ItemDef ExtraLifeVoidConsumed;

			public static ItemDef EquipmentMagazineVoid;

			public static ItemDef ExplodeOnDeathVoid;

			public static ItemDef FragileDamageBonus;

			public static ItemDef FragileDamageBonusConsumed;

			public static ItemDef OutOfCombatArmor;

			public static ItemDef ScrapWhiteSuppressed;

			public static ItemDef ScrapGreenSuppressed;

			public static ItemDef ScrapRedSuppressed;

			public static ItemDef MoreMissile;

			public static ItemDef ImmuneToDebuff;

			public static ItemDef RandomEquipmentTrigger;

			public static ItemDef PrimarySkillShuriken;

			public static ItemDef RandomlyLunar;

			public static ItemDef GoldOnHurt;

			public static ItemDef HalfAttackSpeedHalfCooldowns;

			public static ItemDef HalfSpeedDoubleHealth;

			public static ItemDef FreeChest;

			public static ItemDef ConvertCritChanceToCritDamage;

			public static ItemDef ElementalRingVoid;

			public static ItemDef LunarSun;

			public static ItemDef DroneWeapons;

			public static ItemDef DroneWeaponsBoost;

			public static ItemDef DroneWeaponsDisplay1;

			public static ItemDef DroneWeaponsDisplay2;

			public static ItemDef VoidmanPassiveItem;

			public static ItemDef MinorConstructOnKill;

			public static ItemDef VoidMegaCrabItem;
		}

		public static class ItemRelationshipTypes
		{
			public static ItemRelationshipType ContagiousItem;
		}

		public static class Equipment
		{
			public static EquipmentDef Molotov;

			public static EquipmentDef VendingMachine;

			public static EquipmentDef BossHunter;

			public static EquipmentDef BossHunterConsumed;

			public static EquipmentDef GummyClone;

			public static EquipmentDef MultiShopCard;

			public static EquipmentDef LunarPortalOnUse;

			public static EquipmentDef EliteVoidEquipment;
		}

		public static class Buffs
		{
			public static BuffDef ElementalRingVoidReady;

			public static BuffDef ElementalRingVoidCooldown;

			public static BuffDef BearVoidReady;

			public static BuffDef BearVoidCooldown;

			public static BuffDef KillMoveSpeed;

			public static BuffDef PermanentDebuff;

			public static BuffDef MushroomVoidActive;

			public static BuffDef StrongerBurn;

			public static BuffDef Fracture;

			public static BuffDef OutOfCombatArmorBuff;

			public static BuffDef PrimarySkillShurikenBuff;

			public static BuffDef Blinded;

			public static BuffDef EliteEarth;

			public static BuffDef EliteVoid;

			public static BuffDef JailerTether;

			public static BuffDef JailerSlow;

			public static BuffDef VoidRaidCrabWardWipeFog;

			public static BuffDef VoidSurvivorCorruptMode;

			public static BuffDef ImmuneToDebuffReady;

			public static BuffDef ImmuneToDebuffCooldown;
		}

		public static class Elites
		{
			public static EliteDef Earth;

			public static EliteDef EarthHonor;

			public static EliteDef Void;
		}

		public static class GameEndings
		{
			public static GameEndingDef VoidEnding;
		}

		public static class Survivors
		{
			public static SurvivorDef Railgunner;
		}

		public static class MiscPickups
		{
			public static MiscPickupDef VoidCoin;
		}

		private ContentPack contentPack = new ContentPack();

		private static readonly string addressablesLabel = "ContentPack:RoR2.DLC1";

		public string identifier => "RoR2.DLC1";

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			contentPack.identifier = identifier;
			AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator(addressablesLabel);
			yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack);
			loadHelper.AddGenericOperation(delegate
			{
				ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(ItemRelationshipTypes), contentPack.itemRelationshipTypes);
				ContentLoadHelper.PopulateTypeFields(typeof(Equipment), contentPack.equipmentDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Buffs), contentPack.buffDefs, (string fieldName) => "bd" + fieldName);
				ContentLoadHelper.PopulateTypeFields(typeof(Elites), contentPack.eliteDefs, (string fieldName) => "ed" + fieldName);
				ContentLoadHelper.PopulateTypeFields(typeof(Survivors), contentPack.survivorDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(GameEndings), contentPack.gameEndingDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(MiscPickups), contentPack.miscPickupDefs);
			}, 0.05f);
			while (loadHelper.coroutine.MoveNext())
			{
				args.ReportProgress(loadHelper.progress.value);
				yield return loadHelper.coroutine.Current;
			}
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			ContentPack.Copy(contentPack, args.output);
			yield break;
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			yield break;
		}
	}
	public class DLC2Content : IContentPackProvider
	{
		public static class Artifacts
		{
			public static ArtifactDef Rebirth;
		}

		public static class Items
		{
			public static ItemDef LowerHealthHigherDamage;

			public static ItemDef NegateAttack;

			public static ItemDef ExtraShrineItem;

			public static ItemDef StunAndPierce;

			public static ItemDef BoostAllStats;

			public static ItemDef KnockBackHitEnemies;

			public static ItemDef TriggerEnemyDebuffs;

			public static ItemDef LowerPricedChests;

			public static ItemDef LowerPricedChestsConsumed;

			public static ItemDef ResetChests;

			public static ItemDef IncreaseDamageOnMultiKill;

			public static ItemDef GoldOnStageStart;

			public static ItemDef IncreasePrimaryDamage;

			public static ItemDef DelayedDamage;

			public static ItemDef TeleportOnLowHealth;

			public static ItemDef TeleportOnLowHealthConsumed;

			public static ItemDef ExtraStatsOnLevelUp;

			public static ItemDef MeteorAttackOnHighDamage;

			public static ItemDef OnLevelUpFreeUnlock;

			public static ItemDef LemurianHarness;
		}

		public static class ItemRelationshipTypes
		{
		}

		public static class Equipment
		{
			public static EquipmentDef HealAndRevive;

			public static EquipmentDef HealAndReviveConsumed;

			public static EquipmentDef EliteBeadEquipment;

			public static EquipmentDef EliteAurelioniteEquipment;
		}

		public static class Buffs
		{
			public static BuffDef KnockUpHitEnemies;

			public static BuffDef KnockDownHitEnemies;

			public static BuffDef BoostAllStatsBuff;

			public static BuffDef LowerHealthHigherDamageBuff;

			public static BuffDef IncreaseDamageBuff;

			public static BuffDef IncreasePrimaryDamageBuff;

			public static BuffDef DelayedDamageBuff;

			public static BuffDef DelayedDamageDebuff;

			public static BuffDef ExtraStatsOnLevelUpBuff;

			public static BuffDef lunarruin;

			public static BuffDef TamperedHeart;

			public static BuffDef CorruptionFesters;

			public static BuffDef WeakenedBeating;

			public static BuffDef StunAndPierceBuff;

			public static BuffDef ChakraBuff;

			public static BuffDef RevitalizeBuff;

			public static BuffDef FreeChest;

			public static BuffDef Boosted;

			public static BuffDef boostedFireEffect;

			public static BuffDef CookingChopped;

			public static BuffDef CookingOiled;

			public static BuffDef CookingRoasted;

			public static BuffDef CookingRolled;

			public static BuffDef CookingFlambe;

			public static BuffDef CookingSearing;

			public static BuffDef CookingRolling;

			public static BuffDef FreeUnlocks;

			public static BuffDef GeodeBuff;

			public static BuffDef DisableAllSkills;

			public static BuffDef SoulCost;

			public static BuffDef ExtraLifeBuff;

			public static BuffDef EliteBead;

			public static BuffDef EliteBeadCorruption;

			public static BuffDef EliteBeadThorns;

			public static BuffDef EliteAurelionite;

			public static BuffDef AurelioniteBlessing;

			public static BuffDef HealAndReviveRegenBuff;

			public static BuffDef ChildFrolicCooldown;

			public static BuffDef TeleportOnLowHealth;

			public static BuffDef TeleportOnLowHealthCooldown;

			public static BuffDef SojournVehicle;

			public static BuffDef SojournHealing;

			public static BuffDef HiddenRejectAllDamage;
		}

		public static class Elites
		{
			public static EliteDef Aurelionite;

			public static EliteDef Bead;
		}

		public static class GameEndings
		{
			public static GameEndingDef RebirthEndingDef;
		}

		public static class Survivors
		{
			public static SurvivorDef Seeker;

			public static SurvivorDef FalseSon;

			public static SurvivorDef Chef;
		}

		public static class MiscPickups
		{
		}

		private ContentPack contentPack = new ContentPack();

		private static readonly string addressablesLabel = "ContentPack:RoR2.DLC2";

		public string identifier => "RoR2.DLC2";

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			contentPack.identifier = identifier;
			AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator(addressablesLabel);
			yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack);
			loadHelper.AddGenericOperation(delegate
			{
				ContentLoadHelper.PopulateTypeFields(typeof(Artifacts), contentPack.artifactDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(ItemRelationshipTypes), contentPack.itemRelationshipTypes);
				ContentLoadHelper.PopulateTypeFields(typeof(Equipment), contentPack.equipmentDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Buffs), contentPack.buffDefs, (string fieldName) => "bd" + fieldName);
				ContentLoadHelper.PopulateTypeFields(typeof(Elites), contentPack.eliteDefs, (string fieldName) => "ed" + fieldName);
				ContentLoadHelper.PopulateTypeFields(typeof(Survivors), contentPack.survivorDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(GameEndings), contentPack.gameEndingDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(MiscPickups), contentPack.miscPickupDefs);
			}, 0.05f);
			while (loadHelper.coroutine.MoveNext())
			{
				args.ReportProgress(loadHelper.progress.value);
				yield return loadHelper.coroutine.Current;
			}
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			ContentPack.Copy(contentPack, args.output);
			yield break;
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			yield break;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/DropTables/DoppelgangerDropTable")]
	public class DoppelgangerDropTable : PickupDropTable
	{
		public ItemTag[] requiredItemTags = Array.Empty<ItemTag>();

		public ItemTag[] bannedItemTags = Array.Empty<ItemTag>();

		public float tier1Weight = 0.8f;

		public float tier2Weight = 0.2f;

		public float tier3Weight = 0.01f;

		public float bossWeight;

		public float lunarItemWeight;

		public float voidTier1Weight;

		public float voidTier2Weight;

		public float voidTier3Weight;

		public float voidBossWeight;

		private readonly WeightedSelection<PickupIndex> selector = new WeightedSelection<PickupIndex>();

		private Inventory doppelgangerInventory;

		protected override void OnEnable()
		{
			base.OnEnable();
			DoppelgangerInvasionManager.onDoppelgangerDeath += OnDoppelgangerDeath;
		}

		protected override void OnDisable()
		{
			DoppelgangerInvasionManager.onDoppelgangerDeath -= OnDoppelgangerDeath;
			base.OnDisable();
		}

		protected override void Regenerate(Run run)
		{
			GenerateWeightedSelection();
		}

		private bool CanSelectItem(ItemDef itemDef)
		{
			ItemTag[] array = requiredItemTags;
			foreach (ItemTag value in array)
			{
				if (Array.IndexOf(itemDef.tags, value) == -1)
				{
					return false;
				}
			}
			array = bannedItemTags;
			foreach (ItemTag value2 in array)
			{
				if (Array.IndexOf(itemDef.tags, value2) != -1)
				{
					return false;
				}
			}
			return itemDef.canRemove;
		}

		private void GenerateWeightedSelection()
		{
			selector.Clear();
			if (!doppelgangerInventory)
			{
				return;
			}
			foreach (ItemIndex item in doppelgangerInventory.itemAcquisitionOrder)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(item);
				PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(item);
				if (!CanSelectItem(itemDef))
				{
					continue;
				}
				float num = 0f;
				switch (itemDef.tier)
				{
				case ItemTier.Tier1:
					if (Run.instance.availableTier1DropList.Contains(pickupIndex))
					{
						num = tier1Weight;
					}
					break;
				case ItemTier.Tier2:
					if (Run.instance.availableTier2DropList.Contains(pickupIndex))
					{
						num = tier2Weight;
					}
					break;
				case ItemTier.Tier3:
					if (Run.instance.availableTier3DropList.Contains(pickupIndex))
					{
						num = tier3Weight;
					}
					break;
				case ItemTier.Boss:
					if (Run.instance.availableBossDropList.Contains(pickupIndex))
					{
						num = bossWeight;
					}
					break;
				case ItemTier.Lunar:
					if (Run.instance.availableLunarItemDropList.Contains(pickupIndex))
					{
						num = lunarItemWeight;
					}
					break;
				case ItemTier.VoidTier1:
					if (Run.instance.availableVoidTier1DropList.Contains(pickupIndex))
					{
						num = voidTier1Weight;
					}
					break;
				case ItemTier.VoidTier2:
					if (Run.instance.availableVoidTier2DropList.Contains(pickupIndex))
					{
						num = voidTier2Weight;
					}
					break;
				case ItemTier.VoidTier3:
					if (Run.instance.availableVoidTier3DropList.Contains(pickupIndex))
					{
						num = voidTier3Weight;
					}
					break;
				case ItemTier.VoidBoss:
					if (Run.instance.availableVoidTier3DropList.Contains(pickupIndex))
					{
						num = voidBossWeight;
					}
					break;
				}
				if (num > 0f)
				{
					selector.AddChoice(pickupIndex, num);
				}
			}
		}

		protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector);
		}

		private void OnDoppelgangerDeath(DamageReport damageReport)
		{
			doppelgangerInventory = damageReport.victimMaster?.inventory;
			GenerateWeightedSelection();
		}

		public override int GetPickupCount()
		{
			return selector.Count;
		}

		protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector);
		}
	}
	public static class EditorUtil
	{
		private static int recursionLimit;

		private static int recursionStep;

		private static readonly char[] directorySeparators;

		private static event Action _onNextUpdate;

		public static event Action onNextUpdate
		{
			add
			{
			}
			remove
			{
			}
		}

		static EditorUtil()
		{
			recursionLimit = 3;
			recursionStep = 0;
			directorySeparators = new char[2] { '/', '\\' };
		}

		private static void StaticUpdate()
		{
			Action action = EditorUtil._onNextUpdate;
			EditorUtil._onNextUpdate = null;
			action?.Invoke();
		}

		public static bool IsPrefabVariant(UnityEngine.Object obj)
		{
			return false;
		}

		public static void SetDirty(UnityEngine.Object obj)
		{
		}

		public static void NonSerializedObjectGUI<T>(ref T obj)
		{
		}

		[UsedImplicitly]
		private static void SetFieldGeneric<T>(FieldInfo fieldInfo, object instance, T value)
		{
			if (fieldInfo.FieldType.IsAssignableFrom(typeof(T)))
			{
				fieldInfo.SetValue(instance, value);
				return;
			}
			UnityEngine.Debug.LogErrorFormat("Cannot assign value {0} of type {1} to field {2} of type {3}", value, value.GetType().Name, fieldInfo.Name, fieldInfo.FieldType.Name);
		}

		public static UnityEngine.Object PrefabUtilityGetNearestPrefabInstanceRoot(UnityEngine.Object obj)
		{
			throw new NotImplementedException();
		}

		public static UnityEngine.Object PrefabUtilityInstantiatePrefab(UnityEngine.Object prefab, Transform parent)
		{
			throw new NotImplementedException();
		}

		public static void CopyToScriptableObject<TSrc, TDest>(TSrc src, string folder) where TDest : ScriptableObject
		{
			TDest val = ScriptableObject.CreateInstance<TDest>();
			Dictionary<string, (Type, Func<TSrc, object>)> dictionary = new Dictionary<string, (Type, Func<TSrc, object>)>();
			Dictionary<string, (Type, Action<TDest, object>)> dictionary2 = new Dictionary<string, (Type, Action<TDest, object>)>();
			FieldInfo[] fields = typeof(TSrc).GetFields();
			foreach (FieldInfo srcField in fields)
			{
				dictionary[srcField.Name] = (srcField.FieldType, (TSrc s) => srcField.GetValue(s));
			}
			PropertyInfo[] properties = typeof(TSrc).GetProperties();
			foreach (PropertyInfo srcProperty in properties)
			{
				if (!(srcProperty.GetMethod == null))
				{
					dictionary[srcProperty.Name] = (srcProperty.PropertyType, (TSrc s) => srcProperty.GetValue(s));
				}
			}
			fields = typeof(TDest).GetFields();
			foreach (FieldInfo destField in fields)
			{
				dictionary2[destField.Name] = (destField.FieldType, delegate(TDest d, object v)
				{
					destField.SetValue(d, v);
				});
			}
			properties = typeof(TDest).GetProperties();
			foreach (PropertyInfo destProperty in properties)
			{
				if (!(destProperty.SetMethod == null))
				{
					dictionary2[destProperty.Name] = (destProperty.PropertyType, delegate(TDest d, object v)
					{
						destProperty.SetValue(d, v);
					});
				}
			}
			foreach (KeyValuePair<string, (Type, Func<TSrc, object>)> item in dictionary)
			{
				string key = item.Key;
				var (c, func) = item.Value;
				if (dictionary2.TryGetValue(key, out var value))
				{
					var (type, action) = value;
					if (type.IsAssignableFrom(c))
					{
						action(val, func(src));
					}
				}
			}
			CreateAsset(val, folder + val.name + ".asset");
		}

		private static void CreateAsset(UnityEngine.Object asset, string path)
		{
		}

		private static void AssetDatabaseSaveAssets()
		{
		}

		private static void AssetDatabaseRefresh()
		{
		}

		private static void AssetDatabaseMoveAsset(string oldPath, string newPath)
		{
		}

		private static void AssetDatabaseDeleteAsset(string path)
		{
		}

		private static void AssetDatabaseCreateFolder(string parentFolder, string newFolderName)
		{
		}

		public static void EnsureDirectoryExists(string directoryPath)
		{
			string[] array = directoryPath.Split(directorySeparators);
			string text = array[0].ToString();
			int i = 1;
			for (int num = array.Length; i < num; i++)
			{
				string text2 = array[i].ToString();
				string text3 = $"{text}{'/'}{text2}";
				if (!Directory.Exists(text3))
				{
					AssetDatabaseCreateFolder(text, text2);
				}
				text = text3;
			}
			if (!Directory.Exists(directoryPath))
			{
				UnityEngine.Debug.LogWarning("Failed to ensure path \"" + directoryPath + "\"");
			}
		}

		public static void MoveAsset(string oldPath, string newPath, bool deleteEmpty = true)
		{
			string directoryName = System.IO.Path.GetDirectoryName(oldPath);
			EnsureDirectoryExists(System.IO.Path.GetDirectoryName(newPath));
			AssetDatabaseMoveAsset(oldPath, newPath);
			if (deleteEmpty)
			{
				DeleteDirectoryEmptyChildren(directoryName);
			}
		}

		public static void DeleteDirectoryIfEmpty(string directory)
		{
			DeleteDirectoryEmptyChildren(directory);
			DeleteDirectoryEmptyParents(directory);
		}

		private static bool DeleteDirectoryEmptyChildren(string directory)
		{
			bool flag = true;
			try
			{
				string[] directories = Directory.GetDirectories(directory);
				for (int i = 0; i < directories.Length; i++)
				{
					string fileName = System.IO.Path.GetFileName(directories[i]);
					if (!DeleteDirectoryEmptyChildren(directory + "/" + fileName))
					{
						flag = false;
					}
				}
				flag &= Directory.GetFiles(directory).Length == 0;
				if (flag)
				{
					AssetDatabaseDeleteAsset(directory);
				}
			}
			catch (Exception ex)
			{
				throw new Exception($"DeleteDirectoryEmptyChildren(\"{directory}\") error: {ex}", ex);
			}
			return flag;
		}

		private static void DeleteDirectoryEmptyParents(string directory)
		{
			string directoryName = System.IO.Path.GetDirectoryName(directory);
			bool flag = Directory.GetDirectories(directoryName).Length != 0;
			bool flag2 = Directory.GetFiles(directoryName).Length != 0;
			if (!flag && !flag2)
			{
				AssetDatabaseDeleteAsset(directory);
				DeleteDirectoryEmptyParents(directoryName);
			}
		}

		public static IEnumerable<string> GetAllAssetsInDirectory(string directory, bool includeSubdirectories)
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(directory);
			FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
			for (int i = 0; i < fileSystemInfos.Length; i++)
			{
				string name = fileSystemInfos[i].Name;
				if (!name.EndsWith(".meta"))
				{
					yield return directory + "/" + name;
				}
			}
			if (!includeSubdirectories)
			{
				yield break;
			}
			DirectoryInfo[] directories = directoryInfo.GetDirectories();
			foreach (DirectoryInfo directoryInfo2 in directories)
			{
				string directory2 = directory + "/" + directoryInfo2.Name;
				foreach (string item in GetAllAssetsInDirectory(directory2, includeSubdirectories))
				{
					yield return item;
				}
			}
		}
	}
	public enum EffectIndex
	{
		Invalid = -1
	}
	public class EffectDef
	{
		private GameObject _prefab;

		public Func<EffectData, bool> cullMethod;

		public EffectIndex index { get; internal set; } = EffectIndex.Invalid;


		public GameObject prefab
		{
			get
			{
				return _prefab;
			}
			set
			{
				if (!value)
				{
					throw new ArgumentNullException("Prefab is invalid.");
				}
				if ((object)_prefab != value)
				{
					EffectComponent component = value.GetComponent<EffectComponent>();
					if (!component)
					{
						throw new ArgumentException($"Prefab \"{value}\" does not have EffectComponent attached.");
					}
					_prefab = value;
					prefabEffectComponent = component;
					prefabVfxAttributes = _prefab.GetComponent<VFXAttributes>();
					prefabName = _prefab.name;
					spawnSoundEventName = prefabEffectComponent.soundName;
				}
			}
		}

		public EffectComponent prefabEffectComponent { get; private set; }

		public VFXAttributes prefabVfxAttributes { get; private set; }

		public string prefabName { get; private set; }

		public string spawnSoundEventName { get; private set; }

		public EffectDef()
		{
		}

		public EffectDef(GameObject effectPrefab)
		{
			prefab = effectPrefab;
		}
	}
	public static class EffectCatalog
	{
		private static EffectDef[] entries = Array.Empty<EffectDef>();

		public static int effectCount => entries.Length;

		[SystemInitializer(new Type[] { })]
		public static void Init()
		{
			SetEntries(ContentManager.effectDefs);
		}

		public static void SetEntries(EffectDef[] newEntries)
		{
			EffectDef[] array = entries;
			foreach (EffectDef obj in array)
			{
				obj.index = EffectIndex.Invalid;
				obj.prefabEffectComponent.effectIndex = EffectIndex.Invalid;
			}
			ArrayUtils.CloneTo(newEntries, ref entries);
			Array.Sort(entries, (EffectDef a, EffectDef b) => string.CompareOrdinal(a.prefabName, b.prefabName));
			for (int j = 0; j < entries.Length; j++)
			{
				ref EffectDef reference = ref entries[j];
				reference.index = (EffectIndex)j;
				reference.prefabEffectComponent.effectIndex = reference.index;
			}
		}

		public static EffectIndex FindEffectIndexFromPrefab(GameObject effectPrefab)
		{
			if ((bool)effectPrefab)
			{
				EffectComponent component = effectPrefab.GetComponent<EffectComponent>();
				if ((bool)component)
				{
					return component.effectIndex;
				}
			}
			return EffectIndex.Invalid;
		}

		public static EffectDef GetEffectDef(EffectIndex effectIndex)
		{
			EffectDef[] array = entries;
			EffectDef defaultValue = null;
			return ArrayUtils.GetSafe(array, (int)effectIndex, in defaultValue);
		}

		[ConCommand(commandName = "effects_reload", flags = ConVarFlags.Cheat, helpText = "Reloads the effect catalog.")]
		private static void CCEffectsReload(ConCommandArgs args)
		{
			throw new ConCommandException("Command unavailable outside editor until asset reloading is implemented at the ContentPack level.");
		}
	}
	public class EffectData
	{
		private UnityEngine.Vector3 _origin;

		public UnityEngine.Quaternion rotation = defaultRotation;

		public float scale = defaultScale;

		public Color32 color = defaultColor;

		public UnityEngine.Vector3 start = defaultStart;

		public SurfaceDefIndex surfaceDefIndex = defaultSurfaceDefIndex;

		public uint genericUInt = defaultGenericUInt;

		public float genericFloat = defaultGenericFloat;

		public bool genericBool = defaultGenericBool;

		public NetworkSoundEventIndex networkSoundEventIndex = defaultNetworkSoundEventIndex;

		private static readonly uint useNonDefaultRotationFlag = 1u;

		private static readonly uint useNonDefaultRootObjectFlag = 2u;

		private static readonly uint useNonDefaultModelChildIndexFlag = 4u;

		private static readonly uint useNonDefaultScaleFlag = 8u;

		private static readonly uint useNonDefaultColorFlag = 16u;

		private static readonly uint useNonDefaultStartFlag = 32u;

		private static readonly uint useNonDefaultSurfaceDefIndexFlag = 64u;

		private static readonly uint useNonDefaultGenericUIntFlag = 128u;

		private static readonly uint useNonDefaultGenericFloatFlag = 256u;

		private static readonly uint useNonDefaultGenericBoolFlag = 512u;

		private static readonly uint useNonDefaultNetworkSoundEventIndexFlag = 1024u;

		private static readonly UnityEngine.Quaternion defaultRotation = UnityEngine.Quaternion.identity;

		private static readonly GameObject defaultRootObject = null;

		private static readonly short defaultModelChildIndex = -1;

		private static readonly float defaultScale = 1f;

		private static readonly Color32 defaultColor = UnityEngine.Color.white;

		private static readonly UnityEngine.Vector3 defaultStart = UnityEngine.Vector3.zero;

		private static readonly SurfaceDefIndex defaultSurfaceDefIndex = SurfaceDefIndex.Invalid;

		private static readonly uint defaultGenericUInt = 0u;

		private static readonly float defaultGenericFloat = 0f;

		private static readonly bool defaultGenericBool = false;

		public bool forceUnpooled;

		private static readonly NetworkSoundEventIndex defaultNetworkSoundEventIndex = NetworkSoundEventIndex.Invalid;

		public UnityEngine.Vector3 origin
		{
			get
			{
				return _origin;
			}
			set
			{
				if (!Util.PositionIsValid(value))
				{
					UnityEngine.Debug.LogFormat("EffectData.origin assignment position is invalid! Position={0}", value);
				}
				else
				{
					_origin = value;
				}
			}
		}

		public GameObject rootObject { get; private set; } = defaultRootObject;


		public short modelChildIndex { get; private set; } = defaultModelChildIndex;


		public static void Copy([NotNull] EffectData src, [NotNull] EffectData dest)
		{
			dest.origin = src.origin;
			dest.rotation = src.rotation;
			dest.rootObject = src.rootObject;
			dest.modelChildIndex = src.modelChildIndex;
			dest.scale = src.scale;
			dest.color = src.color;
			dest.start = src.start;
			dest.surfaceDefIndex = src.surfaceDefIndex;
			dest.genericUInt = src.genericUInt;
			dest.genericFloat = src.genericFloat;
			dest.genericBool = src.genericBool;
			dest.networkSoundEventIndex = src.networkSoundEventIndex;
			dest.forceUnpooled = src.forceUnpooled;
		}

		public void Reset()
		{
			_origin = UnityEngine.Vector3.zero;
			rotation = UnityEngine.Quaternion.identity;
			rootObject = null;
			modelChildIndex = -1;
			scale = 1f;
			color = UnityEngine.Color.white;
			start = UnityEngine.Vector3.zero;
			genericUInt = 0u;
			genericFloat = 0f;
			genericBool = false;
			forceUnpooled = false;
		}

		public void SetNetworkedObjectReference(GameObject networkedObject)
		{
			rootObject = networkedObject;
			modelChildIndex = -1;
		}

		public GameObject ResolveNetworkedObjectReference()
		{
			return rootObject;
		}

		public void SetHurtBoxReference(HurtBox hurtBox)
		{
			if (!hurtBox || !hurtBox.healthComponent)
			{
				rootObject = null;
				modelChildIndex = -1;
			}
			else
			{
				rootObject = hurtBox.healthComponent.gameObject;
				modelChildIndex = hurtBox.indexInGroup;
			}
		}

		public void SetHurtBoxReference(GameObject gameObject)
		{
			HurtBox hurtBox = gameObject?.GetComponent<HurtBox>();
			if ((bool)hurtBox)
			{
				SetHurtBoxReference(hurtBox);
				return;
			}
			rootObject = gameObject;
			modelChildIndex = -1;
		}

		public GameObject ResolveHurtBoxReference()
		{
			if (modelChildIndex == -1)
			{
				return rootObject;
			}
			if (!rootObject)
			{
				return null;
			}
			ModelLocator component = rootObject.GetComponent<ModelLocator>();
			if (!component)
			{
				return null;
			}
			Transform modelTransform = component.modelTransform;
			if (!modelTransform)
			{
				return null;
			}
			HurtBoxGroup component2 = modelTransform.GetComponent<HurtBoxGroup>();
			if (!component2)
			{
				return null;
			}
			HurtBox safe = ArrayUtils.GetSafe(component2.hurtBoxes, modelChildIndex);
			if (!safe)
			{
				return null;
			}
			return safe.gameObject;
		}

		public void SetChildLocatorTransformReference(GameObject rootObject, int childIndex)
		{
			this.rootObject = rootObject;
			modelChildIndex = (short)childIndex;
		}

		public Transform ResolveChildLocatorTransformReference()
		{
			if ((bool)rootObject)
			{
				if (modelChildIndex == -1)
				{
					return rootObject.transform;
				}
				ModelLocator component = rootObject.GetComponent<ModelLocator>();
				if ((bool)component && (bool)component.modelTransform)
				{
					ChildLocator component2 = component.modelTransform.GetComponent<ChildLocator>();
					if ((bool)component2)
					{
						return component2.FindChild(modelChildIndex);
					}
				}
			}
			return null;
		}

		public EffectData Clone()
		{
			EffectData effectData = new EffectData();
			Copy(this, effectData);
			return effectData;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static bool ColorEquals(in Color32 x, in Color32 y)
		{
			if (x.r == y.r && x.g == y.g && x.b == y.b)
			{
				return x.a == y.a;
			}
			return false;
		}

		public void Serialize(NetworkWriter writer)
		{
			uint num = 0u;
			bool num2 = !rotation.Equals(defaultRotation);
			bool flag = rootObject != defaultRootObject;
			bool flag2 = modelChildIndex != defaultModelChildIndex;
			bool flag3 = scale != defaultScale;
			bool flag4 = !ColorEquals(in color, in defaultColor);
			bool flag5 = !start.Equals(defaultStart);
			bool flag6 = surfaceDefIndex != defaultSurfaceDefIndex;
			bool flag7 = genericUInt != defaultGenericUInt;
			bool flag8 = genericFloat != defaultGenericFloat;
			bool flag9 = genericBool != defaultGenericBool;
			bool flag10 = networkSoundEventIndex != defaultNetworkSoundEventIndex;
			if (num2)
			{
				num |= useNonDefaultRotationFlag;
			}
			if (flag)
			{
				num |= useNonDefaultRootObjectFlag;
			}
			if (flag2)
			{
				num |= useNonDefaultModelChildIndexFlag;
			}
			if (flag3)
			{
				num |= useNonDefaultScaleFlag;
			}
			if (flag4)
			{
				num |= useNonDefaultColorFlag;
			}
			if (flag5)
			{
				num |= useNonDefaultStartFlag;
			}
			if (flag6)
			{
				num |= useNonDefaultSurfaceDefIndexFlag;
			}
			if (flag7)
			{
				num |= useNonDefaultGenericUIntFlag;
			}
			if (flag8)
			{
				num |= useNonDefaultGenericFloatFlag;
			}
			if (flag9)
			{
				num |= useNonDefaultGenericBoolFlag;
			}
			if (flag10)
			{
				num |= useNonDefaultNetworkSoundEventIndexFlag;
			}
			writer.WritePackedUInt32(num);
			writer.Write(origin);
			if (num2)
			{
				writer.Write(rotation);
			}
			if (flag)
			{
				writer.Write(rootObject);
			}
			if (flag2)
			{
				writer.Write((byte)(modelChildIndex + 1));
			}
			if (flag3)
			{
				writer.Write(scale);
			}
			if (flag4)
			{
				writer.Write(color);
			}
			if (flag5)
			{
				writer.Write(start);
			}
			if (flag6)
			{
				writer.WritePackedIndex32((int)surfaceDefIndex);
			}
			if (flag7)
			{
				writer.WritePackedUInt32(genericUInt);
			}
			if (flag8)
			{
				writer.Write(genericFloat);
			}
			if (flag9)
			{
				writer.Write(genericBool);
			}
			if (flag10)
			{
				writer.WriteNetworkSoundEventIndex(networkSoundEventIndex);
			}
			writer.Write(forceUnpooled);
		}

		public void Deserialize(NetworkReader reader)
		{
			uint flags = reader.ReadPackedUInt32();
			bool flag = HasFlag(in useNonDefaultRotationFlag);
			bool flag2 = HasFlag(in useNonDefaultRootObjectFlag);
			bool flag3 = HasFlag(in useNonDefaultModelChildIndexFlag);
			bool flag4 = HasFlag(in useNonDefaultScaleFlag);
			bool flag5 = HasFlag(in useNonDefaultColorFlag);
			bool flag6 = HasFlag(in useNonDefaultStartFlag);
			bool flag7 = HasFlag(in useNonDefaultSurfaceDefIndexFlag);
			bool flag8 = HasFlag(in useNonDefaultGenericUIntFlag);
			bool flag9 = HasFlag(in useNonDefaultGenericFloatFlag);
			bool flag10 = HasFlag(in useNonDefaultGenericBoolFlag);
			bool flag11 = HasFlag(in useNonDefaultNetworkSoundEventIndexFlag);
			origin = reader.ReadVector3();
			rotation = (flag ? reader.ReadQuaternion() : defaultRotation);
			rootObject = (flag2 ? reader.ReadGameObject() : defaultRootObject);
			modelChildIndex = (flag3 ? ((short)(reader.ReadByte() - 1)) : defaultModelChildIndex);
			scale = (flag4 ? reader.ReadSingle() : defaultScale);
			color = (flag5 ? reader.ReadColor32() : defaultColor);
			start = (flag6 ? reader.ReadVector3() : defaultStart);
			surfaceDefIndex = (flag7 ? ((SurfaceDefIndex)reader.ReadPackedIndex32()) : defaultSurfaceDefIndex);
			genericUInt = (flag8 ? reader.ReadPackedUInt32() : defaultGenericUInt);
			genericFloat = (flag9 ? reader.ReadSingle() : defaultGenericFloat);
			genericBool = (flag10 ? reader.ReadBoolean() : defaultGenericBool);
			networkSoundEventIndex = (flag11 ? reader.ReadNetworkSoundEventIndex() : defaultNetworkSoundEventIndex);
			forceUnpooled = reader.ReadBoolean();
			bool HasFlag(in uint mask)
			{
				return (flags & mask) != 0;
			}
		}
	}
	public static class EffectManager
	{
		private class EffectMessage : MessageBase
		{
			public EffectIndex effectIndex;

			public readonly EffectData effectData = new EffectData();

			public override void Serialize(NetworkWriter writer)
			{
				writer.WriteEffectIndex(effectIndex);
				writer.Write(effectData);
			}

			public override void Deserialize(NetworkReader reader)
			{
				effectIndex = reader.ReadEffectIndex();
				reader.ReadEffectData(effectData);
			}
		}

		public static bool DisableAllEffectSpawning = false;

		private static bool _UsePools = true;

		private static Dictionary<GameObject, EffectPool> _EffectPrefabMap = new Dictionary<GameObject, EffectPool>();

		private static Dictionary<GameObject, bool> _ShouldUsePooledEffectMap = new Dictionary<GameObject, bool>();

		private static EffectManagerHelper _LastSpawnedEffect = null;

		private static EffectData _simpleEffectData = null;

		private const float POOL_EXPIRATION_TIME = 45f;

		private const int POOLS_UNLOADING_TIMESTEP = 5;

		private const int MINIMAL_POOLS_AMOUNT_BEFORE_UNLOADING = 5;

		private const int MAXIMUM_POOLS_AMOUNT_BEFORE_UNLOADING_IN_USE_POOLS = 30;

		private static readonly QosChannelIndex qosChannel = QosChannelIndex.effects;

		private static int frameCount = 0;

		private static readonly EffectMessage outgoingEffectMessage = new EffectMessage();

		private static readonly EffectMessage incomingEffectMessage = new EffectMessage();

		public static EffectManagerHelper LastSpawnedEffect
		{
			get
			{
				EffectManagerHelper lastSpawnedEffect = _LastSpawnedEffect;
				_LastSpawnedEffect = null;
				return lastSpawnedEffect;
			}
		}

		public static bool UsePools => _UsePools;

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
		private static void Init()
		{
			RoR2Application.onUpdate += Update;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
		}

		private static void OnSceneUnloaded(Scene scene)
		{
			KillAllPools();
		}

		public static void TogglePooling()
		{
			_UsePools = !_UsePools;
			UnityEngine.Debug.LogFormat("EffectManager pooling is {0}", _UsePools ? "ENABLED" : "DISABLED");
		}

		public static bool ShouldUsePooledEffect(GameObject inPrefab)
		{
			if (inPrefab != null && UsePools)
			{
				if (!_ShouldUsePooledEffectMap.TryGetValue(inPrefab, out var value))
				{
					VFXAttributes component = inPrefab.GetComponent<VFXAttributes>();
					if (component != null)
					{
						value = !component.DoNotPool;
						_ShouldUsePooledEffectMap.Add(inPrefab, value);
					}
					else
					{
						value = true;
						_ShouldUsePooledEffectMap.Add(inPrefab, value);
					}
				}
				return value;
			}
			return false;
		}

		private static void CreatePoolIfNotPresent(GameObject inPrefab)
		{
			if (!_EffectPrefabMap.ContainsKey(inPrefab))
			{
				EffectPool effectPool = new EffectPool();
				effectPool.PrefabObject = inPrefab;
				effectPool.AlwaysGrowable = true;
				effectPool.AddComponentIfMissing = true;
				effectPool.Initialize(1, 1);
				_EffectPrefabMap.Add(inPrefab, effectPool);
			}
		}

		public static EffectManagerHelper GetPooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation)
		{
			CreatePoolIfNotPresent(inPrefab);
			EffectPool effectPool = _EffectPrefabMap[inPrefab];
			EffectManagerHelper @object = effectPool.GetObject();
			if (@object != null)
			{
				@object.SetOwningPool(effectPool);
				@object.Initialize();
				@object.gameObject.transform.position = inPosition;
				@object.gameObject.transform.rotation = inRotation;
			}
			return @object;
		}

		public static EffectManagerHelper GetAndActivatePooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation)
		{
			EffectManagerHelper pooledEffect = GetPooledEffect(inPrefab, inPosition, inRotation);
			pooledEffect.Reset(inActivate: true);
			pooledEffect.gameObject.SetActive(value: true);
			pooledEffect.ResetPostActivate();
			return pooledEffect;
		}

		public static EffectManagerHelper GetPooledEffect(GameObject inPrefab, Transform inTransform)
		{
			CreatePoolIfNotPresent(inPrefab);
			EffectPool effectPool = _EffectPrefabMap[inPrefab];
			EffectManagerHelper @object = effectPool.GetObject();
			if (@object != null)
			{
				@object.SetOwningPool(effectPool);
				@object.Initialize();
				@object.gameObject.transform.SetParent(inTransform);
			}
			return @object;
		}

		public static EffectManagerHelper GetAndActivatePooledEffect(GameObject inPrefab, Transform inTransform, bool inResetLocal = false)
		{
			EffectManagerHelper pooledEffect = GetPooledEffect(inPrefab, inTransform);
			if (inResetLocal)
			{
				pooledEffect.gameObject.transform.localPosition = UnityEngine.Vector3.zero;
				pooledEffect.gameObject.transform.localRotation = UnityEngine.Quaternion.identity;
				pooledEffect.gameObject.transform.localScale = UnityEngine.Vector3.one;
			}
			pooledEffect.Reset(inActivate: true);
			pooledEffect.gameObject.SetActive(value: true);
			pooledEffect.ResetPostActivate();
			return pooledEffect;
		}

		public static EffectManagerHelper GetPooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation, Transform inTransform)
		{
			CreatePoolIfNotPresent(inPrefab);
			EffectPool effectPool = _EffectPrefabMap[inPrefab];
			EffectManagerHelper @object = effectPool.GetObject();
			if (@object != null)
			{
				@object.SetOwningPool(effectPool);
				@object.Initialize();
				@object.gameObject.transform.localPosition = inPosition;
				@object.gameObject.transform.localRotation = inRotation;
			}
			return @object;
		}

		public static EffectManagerHelper GetAndActivatePooledEffect(GameObject inPrefab, UnityEngine.Vector3 inPosition, UnityEngine.Quaternion inRotation, Transform inTransform)
		{
			EffectManagerHelper pooledEffect = GetPooledEffect(inPrefab, inPosition, inRotation, inTransform);
			pooledEffect.Reset(inActivate: true);
			pooledEffect.gameObject.SetActive(value: true);
			pooledEffect.ResetPostActivate();
			return pooledEffect;
		}

		public static void ClearPool(GameObject inPrefab)
		{
			if (_EffectPrefabMap.ContainsKey(inPrefab))
			{
				_EffectPrefabMap[inPrefab].Reset();
				_EffectPrefabMap.Remove(inPrefab);
			}
		}

		public static void KillAllPools()
		{
			UnityEngine.Debug.LogWarning("EffectManager: Killing all pools");
			foreach (EffectPool value in _EffectPrefabMap.Values)
			{
				value.Kill();
			}
			_EffectPrefabMap.Clear();
			_ShouldUsePooledEffectMap.Clear();
			GC.Collect();
		}

		public static void ClearAllPools(bool inForceAllClear = false)
		{
			UnityEngine.Debug.LogWarning("EffectManager: Clearing all pools");
			foreach (EffectPool value in _EffectPrefabMap.Values)
			{
				value.Reset(inForceAllClear);
			}
			_EffectPrefabMap.Clear();
			_ShouldUsePooledEffectMap.Clear();
		}

		public static void DumpPools()
		{
		}

		[NetworkMessageHandler(msgType = 52, server = true)]
		private static void HandleEffectServer(NetworkMessage netMsg)
		{
			HandleEffectServerInternal(netMsg);
		}

		[NetworkMessageHandler(msgType = 52, client = true)]
		private static void HandleEffectClient(NetworkMessage netMsg)
		{
			HandleEffectClientInternal(netMsg);
		}

		public static void SpawnEffect(GameObject effectPrefab, EffectData effectData, bool transmit)
		{
			if (DisableAllEffectSpawning)
			{
				return;
			}
			EffectIndex effectIndex = EffectCatalog.FindEffectIndexFromPrefab(effectPrefab);
			if (effectIndex == EffectIndex.Invalid)
			{
				if ((bool)effectPrefab && !string.IsNullOrEmpty(effectPrefab.name))
				{
					UnityEngine.Debug.LogError("Unable to SpawnEffect from prefab named '" + effectPrefab?.name + "'");
				}
				else
				{
					UnityEngine.Debug.LogError($"Unable to SpawnEffect.  Is null? {effectPrefab == null}.  Name = '{effectPrefab?.name}'.\n{new StackTrace()}");
				}
			}
			else
			{
				SpawnEffect(effectIndex, effectData, transmit);
			}
		}

		public static void SpawnEffect(EffectIndex effectIndex, EffectData effectData, bool transmit)
		{
			if (DisableAllEffectSpawning)
			{
				return;
			}
			if (transmit)
			{
				TransmitEffect(effectIndex, effectData);
				if (NetworkServer.active)
				{
					return;
				}
			}
			if (!NetworkClient.active)
			{
				return;
			}
			if (effectData.networkSoundEventIndex != NetworkSoundEventIndex.Invalid)
			{
				PointSoundManager.EmitSoundLocal(NetworkSoundEventCatalog.GetAkIdFromNetworkSoundEventIndex(effectData.networkSoundEventIndex), effectData.origin);
			}
			EffectDef effectDef = EffectCatalog.GetEffectDef(effectIndex);
			if (effectDef == null)
			{
				return;
			}
			string spawnSoundEventName = effectDef.spawnSoundEventName;
			if (!string.IsNullOrEmpty(spawnSoundEventName))
			{
				PointSoundManager.EmitSoundLocal((AkEventIdArg)spawnSoundEventName, effectData.origin);
			}
			SurfaceDef surfaceDef = SurfaceDefCatalog.GetSurfaceDef(effectData.surfaceDefIndex);
			if ((object)surfaceDef != null)
			{
				string impactSoundString = surfaceDef.impactSoundString;
				if (!string.IsNullOrEmpty(impactSoundString))
				{
					PointSoundManager.EmitSoundLocal((AkEventIdArg)impactSoundString, effectData.origin);
				}
			}
			if (!VFXBudget.CanAffordSpawn(effectDef.prefabVfxAttributes) || (effectDef.cullMethod != null && !effectDef.cullMethod(effectData)))
			{
				return;
			}
			EffectData effectData2 = effectData.Clone();
			EffectManagerHelper effectManagerHelper = null;
			if (!ShouldUsePooledEffect(effectDef.prefab))
			{
				EffectComponent component = UnityEngine.Object.Instantiate(effectDef.prefab, effectData2.origin, effectData2.rotation).GetComponent<EffectComponent>();
				if ((bool)component)
				{
					component.effectData = effectData2.Clone();
				}
				return;
			}
			effectManagerHelper = GetPooledEffect(effectDef.prefab, effectData2.origin, effectData2.rotation);
			EffectComponent component2 = effectManagerHelper.gameObject.GetComponent<EffectComponent>();
			if ((bool)component2)
			{
				component2.effectData = effectData2.Clone();
				effectManagerHelper.Reset(inActivate: true);
				effectManagerHelper.gameObject.SetActive(value: true);
				effectManagerHelper.ResetPostActivate();
			}
		}

		private static void Update()
		{
			frameCount++;
			if (frameCount >= 5)
			{
				frameCount = 0;
				_ = _EffectPrefabMap.Count;
				_ = 5;
				UnloadOutdatedPools();
			}
		}

		private static void UnloadOutdatedPools()
		{
			float num = float.PositiveInfinity;
			PrefabComponentPool<EffectManagerHelper> prefabComponentPool = null;
			bool flag = _EffectPrefabMap.Count > 30;
			foreach (EffectPool value in _EffectPrefabMap.Values)
			{
				if (!value.DoNotCull && value.timestamp < num && (value.InUseCount() < 1 || flag))
				{
					num = value.timestamp;
					prefabComponentPool = value;
				}
			}
			if (Time.realtimeSinceStartup - num > 45f)
			{
				prefabComponentPool.Kill();
				_EffectPrefabMap.Remove(prefabComponentPool.PrefabObject);
			}
		}

		private static void TransmitEffect(EffectIndex effectIndex, EffectData effectData, NetworkConnection netOrigin = null)
		{
			outgoingEffectMessage.effectIndex = effectIndex;
			EffectData.Copy(effectData, outgoingEffectMessage.effectData);
			if (NetworkServer.active)
			{
				foreach (NetworkConnection connection in NetworkServer.connections)
				{
					if (connection != null && connection != netOrigin)
					{
						connection.SendByChannel(52, outgoingEffectMessage, qosChannel.intVal);
					}
				}
				return;
			}
			if (ClientScene.readyConnection != null)
			{
				ClientScene.readyConnection.SendByChannel(52, outgoingEffectMessage, qosChannel.intVal);
			}
		}

		private static void HandleEffectClientInternal(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(incomingEffectMessage);
			SpawnEffect(incomingEffectMessage.effectIndex, incomingEffectMessage.effectData, transmit: false);
		}

		private static void HandleEffectServerInternal(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(incomingEffectMessage);
			TransmitEffect(incomingEffectMessage.effectIndex, incomingEffectMessage.effectData, netMsg.conn);
		}

		public static void SimpleMuzzleFlash(GameObject effectPrefab, GameObject obj, string muzzleName, bool transmit)
		{
			if (!obj)
			{
				return;
			}
			ModelLocator component = obj.GetComponent<ModelLocator>();
			if (!component || !component.modelTransform)
			{
				return;
			}
			ChildLocator component2 = component.modelTransform.GetComponent<ChildLocator>();
			if ((bool)component2)
			{
				int childIndex = component2.FindChildIndex(muzzleName);
				Transform transform = component2.FindChild(childIndex);
				if ((bool)transform)
				{
					EffectData effectData = new EffectData
					{
						origin = transform.position
					};
					effectData.SetChildLocatorTransformReference(obj, childIndex);
					SpawnEffect(effectPrefab, effectData, transmit);
				}
			}
		}

		public static void SimpleImpactEffect(GameObject effectPrefab, UnityEngine.Vector3 hitPos, UnityEngine.Vector3 normal, bool transmit)
		{
			SpawnEffect(effectPrefab, new EffectData
			{
				origin = hitPos,
				rotation = ((normal == UnityEngine.Vector3.zero) ? UnityEngine.Quaternion.identity : Util.QuaternionSafeLookRotation(normal))
			}, transmit);
		}

		public static void SimpleImpactEffect(GameObject effectPrefab, UnityEngine.Vector3 hitPos, UnityEngine.Vector3 normal, UnityEngine.Color color, bool transmit)
		{
			SpawnEffect(effectPrefab, new EffectData
			{
				origin = hitPos,
				rotation = Util.QuaternionSafeLookRotation(normal),
				color = color
			}, transmit);
		}

		public static void SimpleEffect(GameObject effectPrefab, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, bool transmit)
		{
			SpawnEffect(effectPrefab, new EffectData
			{
				origin = position,
				rotation = rotation
			}, transmit);
		}

		public static void SimpleSoundEffect(NetworkSoundEventIndex soundEventIndex, UnityEngine.Vector3 position, bool transmit)
		{
			SpawnEffect(EffectIndex.Invalid, new EffectData
			{
				origin = position,
				networkSoundEventIndex = soundEventIndex
			}, transmit);
		}

		public static void ReturnToPoolOrDestroyInstance(this EffectManagerHelper effectManagerHelper, ref GameObject instance)
		{
			if (UsePools)
			{
				if (effectManagerHelper != null && effectManagerHelper.OwningPool != null)
				{
					effectManagerHelper.OwningPool.ReturnObject(effectManagerHelper);
				}
				else
				{
					UnityEngine.Object.Destroy(instance);
				}
				effectManagerHelper = null;
			}
			else
			{
				UnityEngine.Object.Destroy(instance);
			}
		}
	}
	public enum EliteIndex
	{
		None = -1
	}
	public static class EliteCatalog
	{
		public static List<EliteIndex> eliteList = new List<EliteIndex>();

		private static EliteDef[] eliteDefs;

		[Obsolete("Use IContentPackProvider instead.")]
		public static readonly CatalogModHelperProxy<EliteDef> modHelper = new CatalogModHelperProxy<EliteDef>("RoR2.EliteCatalog.modHelper", LegacyModContentPackProvider.instance.registrationContentPack.eliteDefs);

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetEliteDefs(ContentManager.eliteDefs);
		}

		private static void SetEliteDefs(EliteDef[] newEliteDefs)
		{
			eliteDefs = ArrayUtils.Clone(newEliteDefs);
			for (EliteIndex eliteIndex = (EliteIndex)0; (int)eliteIndex < eliteDefs.Length; eliteIndex++)
			{
				RegisterElite(eliteIndex, eliteDefs[(int)eliteIndex]);
			}
		}

		private static void RegisterElite(EliteIndex eliteIndex, EliteDef eliteDef)
		{
			eliteDef.eliteIndex = eliteIndex;
			eliteList.Add(eliteIndex);
			eliteDefs[(int)eliteIndex] = eliteDef;
		}

		public static EliteDef GetEliteDef(EliteIndex eliteIndex)
		{
			return ArrayUtils.GetSafe(eliteDefs, (int)eliteIndex);
		}
	}
	public static class EngineConVars
	{
		private class SyncPhysicsConVar : BaseConVar
		{
			public static SyncPhysicsConVar instance = new SyncPhysicsConVar("sync_physics", ConVarFlags.None, "0", "Enable/disables Physics 'autosyncing' between moves.");

			private SyncPhysicsConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				Physics.autoSyncTransforms = BaseConVar.ParseBoolInvariant(newValue);
			}

			public override string GetString()
			{
				if (!Physics.autoSyncTransforms)
				{
					return "0";
				}
				return "1";
			}
		}

		private class AutoSimulatePhysicsConVar : BaseConVar
		{
			public static AutoSimulatePhysicsConVar instance = new AutoSimulatePhysicsConVar("auto_simulate_physics", ConVarFlags.None, "1", "Enable/disables Physics autosimulate.");

			private AutoSimulatePhysicsConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				Physics.autoSimulation = BaseConVar.ParseBoolInvariant(newValue);
			}

			public override string GetString()
			{
				if (!Physics.autoSimulation)
				{
					return "0";
				}
				return "1";
			}
		}

		private class TimeScaleConVar : BaseConVar
		{
			private static readonly TimeScaleConVar instance = new TimeScaleConVar("timescale", ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat | ConVarFlags.Engine, null, "The timescale of the game.");

			public TimeScaleConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				Time.timeScale = BaseConVar.ParseFloatInvariant(newValue);
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(Time.timeScale);
			}
		}

		private class TimeStepConVar : BaseConVar
		{
			private static readonly TimeStepConVar instance = new TimeStepConVar("timestep", ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat | ConVarFlags.Engine, null, "The timestep of the game.");

			public TimeStepConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				Time.fixedDeltaTime = BaseConVar.ParseFloatInvariant(newValue);
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(Time.fixedDeltaTime);
			}
		}
	}
	public enum EntityStateIndex
	{
		Invalid = -1
	}
	public static class EntityStateCatalog
	{
		private static readonly Dictionary<Type, EntityStateIndex> stateTypeToIndex = new Dictionary<Type, EntityStateIndex>(1000);

		private static Type[] stateIndexToType = Array.Empty<Type>();

		private static readonly Dictionary<Type, Action<object>> instanceFieldInitializers = new Dictionary<Type, Action<object>>();

		private static string[] stateIndexToTypeName = Array.Empty<string>();

		[Obsolete("This is only for use in legacy editors only until they're fully phased out.")]
		public static string[] baseGameStateTypeNames = new string[0];

		private static void SetStateInstanceInitializer([NotNull] Type stateType, [NotNull] Action<object> initializer)
		{
			if (typeof(EntityState).IsAssignableFrom(stateType))
			{
				instanceFieldInitializers[stateType] = initializer;
			}
		}

		public static void InitializeStateFields([NotNull] EntityState entityState)
		{
			if (instanceFieldInitializers.TryGetValue(entityState.GetType(), out var value))
			{
				value(entityState);
			}
		}

		private static IEnumerator SetElements(Type[] newEntityStateTypes, EntityStateConfiguration[] newEntityStateConfigurations)
		{
			ArrayUtils.CloneTo(newEntityStateTypes, ref stateIndexToType);
			int _length = stateIndexToType.Length;
			string[] typeNames = new string[_length];
			for (int i = 0; i < _length; i++)
			{
				typeNames[i] = stateIndexToType[i].AssemblyQualifiedName;
			}
			yield return null;
			Array.Sort(typeNames, stateIndexToType, StringComparer.Ordinal);
			yield return null;
			stateTypeToIndex.Clear();
			for (int j = 0; j < _length; j++)
			{
				Type key = stateIndexToType[j];
				stateTypeToIndex[key] = (EntityStateIndex)j;
			}
			yield return null;
			Array.Resize(ref stateIndexToTypeName, stateIndexToType.Length);
			for (int k = 0; k < stateIndexToType.Length; k++)
			{
				stateIndexToTypeName[k] = stateIndexToType[k].Name;
			}
			yield return null;
			instanceFieldInitializers.Clear();
			int limitForLoop = 10;
			int loopIndex = 0;
			for (_length = 0; _length < newEntityStateConfigurations.Length; _length++)
			{
				ApplyEntityStateConfiguration(newEntityStateConfigurations[_length]);
				if (loopIndex++ >= limitForLoop)
				{
					loopIndex = 0;
					yield return null;
				}
			}
		}

		private static void ApplyEntityStateConfiguration(EntityStateConfiguration entityStateConfiguration)
		{
			Type type = (Type)entityStateConfiguration.targetType;
			if (type == null)
			{
				UnityEngine.Debug.LogFormat("ApplyEntityStateConfiguration({0}) failed: state type is null.", entityStateConfiguration);
				return;
			}
			if (!stateTypeToIndex.ContainsKey(type))
			{
				UnityEngine.Debug.LogFormat("ApplyEntityStateConfiguration({0}) failed: state type {1} is not registered.", entityStateConfiguration, type.FullName);
				return;
			}
			entityStateConfiguration.ApplyStatic();
			Action<object> action = entityStateConfiguration.BuildInstanceInitializer();
			if (action == null)
			{
				instanceFieldInitializers.Remove(type);
			}
			else
			{
				instanceFieldInitializers[type] = action;
			}
		}

		private static void OnStateConfigurationUpdatedByEditor(EntityStateConfiguration entityStateConfiguration)
		{
			ApplyEntityStateConfiguration(entityStateConfiguration);
		}

		public static IEnumerator Init()
		{
			EntityStateConfiguration.onEditorUpdatedConfigurationGlobal += OnStateConfigurationUpdatedByEditor;
			yield return SetElements(ContentManager.entityStateTypes, ContentManager.entityStateConfigurations);
		}

		public static EntityStateIndex GetStateIndex(Type entityStateType)
		{
			if (stateTypeToIndex.TryGetValue(entityStateType, out var value))
			{
				return value;
			}
			return EntityStateIndex.Invalid;
		}

		public static Type GetStateType(EntityStateIndex entityStateIndex)
		{
			Type[] array = stateIndexToType;
			Type defaultValue = null;
			return ArrayUtils.GetSafe(array, (int)entityStateIndex, in defaultValue);
		}

		[CanBeNull]
		public static string GetStateTypeName(Type entityStateType)
		{
			return GetStateTypeName(GetStateIndex(entityStateType));
		}

		[CanBeNull]
		public static string GetStateTypeName(EntityStateIndex entityStateIndex)
		{
			return ArrayUtils.GetSafe(stateIndexToTypeName, (int)entityStateIndex);
		}

		public static EntityState InstantiateState(EntityStateIndex entityStateIndex)
		{
			Type stateType = GetStateType(entityStateIndex);
			if (stateType != null)
			{
				return Activator.CreateInstance(stateType) as EntityState;
			}
			UnityEngine.Debug.LogFormat("Bad stateTypeIndex {0}", entityStateIndex);
			return null;
		}

		public static EntityState InstantiateState(Type stateType)
		{
			if (stateType != null && stateType.IsSubclassOf(typeof(EntityState)))
			{
				return Activator.CreateInstance(stateType) as EntityState;
			}
			UnityEngine.Debug.LogFormat("Bad stateType {0}", (stateType == null) ? "null" : stateType.FullName);
			return null;
		}

		public static EntityState InstantiateState(ref SerializableEntityStateType serializableStateType)
		{
			return InstantiateState(serializableStateType.stateType);
		}
	}
	[RequireComponent(typeof(EntityStateMachine))]
	[RequireComponent(typeof(CharacterBody))]
	public class ChildMonsterController : MonoBehaviour
	{
		public CharacterBody characterBody;

		public EntityStateMachine stateMachine;

		public GameObject tpEffectPrefab;

		[Tooltip("If Child receives this much cumulative damage, they will start trying to teleport.")]
		[FormerlySerializedAs("frolicThreshold")]
		public float cumulativeDamageThresholdBeforeFrolic = 10f;

		[Tooltip("Does not apply to 'falling off cliffs!' teleporting.")]
		public float teleportCooldown = 20f;

		[Tooltip("Which skill slot is 'Frolic' (teleport) categorized as.")]
		public SkillSlot frolicSkillSlot;

		private float inAirTimer;

		public float amountToFallBeforeTp = 1.5f;

		private float cachedYPosition;

		private SkillLocator skillLocator;

		private float lastTeleportTimestamp = -1f;

		private float healthAtLastTeleport;

		private BaseState requestedTeleportState;

		private bool hasAuthority;

		private void Start()
		{
			skillLocator = characterBody.skillLocator;
			cachedYPosition = characterBody.corePosition.y;
			hasAuthority = Util.HasEffectiveAuthority(characterBody.networkIdentity);
			RegisterTeleport(addInvincibility: false);
			lastTeleportTimestamp = -1f;
		}

		private void Update()
		{
			if (characterBody == null || !characterBody.healthComponent.alive)
			{
				return;
			}
			TryRefreshTeleportAbility();
			if (hasAuthority)
			{
				HandleFalling();
				HandleCumulativeDamage();
				if (requestedTeleportState != null)
				{
					SetNextStateToTeleport();
				}
			}
		}

		private void SetNextStateToTeleport()
		{
			if (stateMachine.CanInterruptState(requestedTeleportState.GetMinimumInterruptPriority()))
			{
				stateMachine.SetNextState(requestedTeleportState);
				requestedTeleportState = null;
			}
		}

		private void HandleFalling()
		{
			if (!characterBody.characterMotor.isGrounded && characterBody.corePosition.y < cachedYPosition)
			{
				inAirTimer += Time.deltaTime;
			}
			else
			{
				inAirTimer = 0f;
			}
			cachedYPosition = characterBody.corePosition.y;
			if (inAirTimer > amountToFallBeforeTp)
			{
				inAirTimer = 0f;
				requestedTeleportState = new FrolicAway();
			}
		}

		private void TryRefreshTeleportAbility()
		{
			if (lastTeleportTimestamp != -1f && CheckTeleportAvailable())
			{
				lastTeleportTimestamp = -1f;
			}
		}

		private void HandleCumulativeDamage()
		{
			if (requestedTeleportState == null && CheckTeleportAvailable() && healthAtLastTeleport - characterBody.healthComponent.health >= cumulativeDamageThresholdBeforeFrolic)
			{
				requestedTeleportState = new Frolic();
			}
		}

		public bool CheckTeleportAvailable()
		{
			if (lastTeleportTimestamp != -1f)
			{
				return Time.time - lastTeleportTimestamp >= teleportCooldown;
			}
			return true;
		}

		public void RegisterTeleport(bool addInvincibility = true)
		{
			lastTeleportTimestamp = Time.time;
			healthAtLastTeleport = characterBody.healthComponent.health;
			requestedTeleportState = null;
			skillLocator.GetSkill(frolicSkillSlot)?.DeductStock(100);
			if (addInvincibility && NetworkServer.active && !characterBody.HasBuff(RoR2Content.Buffs.HiddenInvincibility))
			{
				characterBody.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 1.5f);
			}
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class FalseSonController : NetworkBehaviour
	{
		public CharacterBody characterBody;

		public SkillDef falseSonBodyTheTamperedHeart;

		public SkillDef tempAltDefName;

		public GenericSkill passiveSkillSlot;

		[SerializeField]
		private float tamperedHeartRegen;

		[SerializeField]
		private float tamperedHeartMoveSpeed;

		[SerializeField]
		private float tamperedHeartArmor;

		[SerializeField]
		private float tamperedHeartAttackSpeed;

		private bool tamperedHeart;

		private SkillLocator skillLocator;

		private int maxSecondaryStock;

		private int oldMaxSecondaryStock;

		private int secondaryStock;

		private int oldSecondaryStock;

		private int extraShardFromHealth;

		private int oldExtraShardFromHealth;

		private float maxHealth;

		private float oldMaxHealth;

		private int bonusSecondarySkillCountFromItems;

		private int oldBonusSecondarySkillCountFromItems;

		private bool alreadyResetMaxSecondaryStockCount;

		private int lunarSpikeSkillIndex;

		private int laserBurstSkillIndex;

		private GenericSkill lunarSpikeSkill;

		private GenericSkill laserSpecialSkill;

		private bool cachedEffectiveAuthority;

		private NetworkIdentity networkIdentity;

		private float clubSwingAltSecondaryTimestamp;

		private static int kCmdCmdUpdateAmmoAmounts;

		private bool secondarySkillIsFalseSonDefault => lunarSpikeSkill.baseSkill.skillIndex == lunarSpikeSkillIndex;

		private bool sendAmmoUpdatesToServer
		{
			get
			{
				if (cachedEffectiveAuthority)
				{
					return !NetworkServer.active;
				}
				return false;
			}
		}

		private void OnEnable()
		{
			skillLocator = GetComponent<SkillLocator>();
			networkIdentity = skillLocator.GetComponent<NetworkIdentity>();
			lunarSpikeSkill = skillLocator.GetSkill(SkillSlot.Secondary);
			laserSpecialSkill = skillLocator.GetSkill(SkillSlot.Special);
			CacheEffectiveAuthority();
			oldMaxSecondaryStock = GetMaxSecondaryStock();
			oldSecondaryStock = maxSecondaryStock;
			lunarSpikeSkillIndex = SkillCatalog.FindSkillIndexByName("LunarSpikes");
			laserBurstSkillIndex = SkillCatalog.FindSkillIndexByName("LaserBurst");
		}

		private void Update()
		{
			bool flag = false;
			CacheEffectiveAuthority();
			if (passiveSkillSlot.skillDef == falseSonBodyTheTamperedHeart)
			{
				if (!secondarySkillIsFalseSonDefault && !alreadyResetMaxSecondaryStockCount)
				{
					characterBody.extraSecondaryFromSkill = 0;
					oldExtraShardFromHealth = 0;
					UpdateStats();
					alreadyResetMaxSecondaryStockCount = true;
				}
				maxHealth = characterBody.maxHealth;
				maxSecondaryStock = GetMaxSecondaryStock();
				if ((maxHealth != oldMaxHealth && characterBody.maxBonusHealth > 0f) || oldMaxSecondaryStock != maxSecondaryStock || (!secondarySkillIsFalseSonDefault ^ alreadyResetMaxSecondaryStockCount))
				{
					if (secondarySkillIsFalseSonDefault)
					{
						IncreaseStockCount();
						flag = true;
						alreadyResetMaxSecondaryStockCount = false;
					}
					oldMaxHealth = maxHealth;
					oldMaxSecondaryStock = maxSecondaryStock;
				}
				secondaryStock = GetSecondaryStock();
				if (secondaryStock != oldSecondaryStock || flag)
				{
					CalcTamperedHeartStats();
					flag = true;
				}
			}
			if (sendAmmoUpdatesToServer && flag)
			{
				CallCmdUpdateAmmoAmounts(secondaryStock, maxSecondaryStock);
			}
		}

		[Command]
		public void CmdUpdateAmmoAmounts(int _secondaryStock, int _maxSecondaryStock)
		{
			maxSecondaryStock = _maxSecondaryStock;
			secondaryStock = _secondaryStock;
			CalcTamperedHeartStats();
		}

		public int GetTotalSpikeCount()
		{
			int num = 0;
			float num2 = 15f;
			float num3 = 5f;
			float num4 = characterBody.maxBonusHealth - (characterBody.baseMaxHealth + characterBody.levelMaxHealth * (float)((int)characterBody.level - 1));
			int num5 = 10;
			while (num4 > num2)
			{
				num4 -= num2;
				if (num4 < 0f)
				{
					break;
				}
				num++;
				if (num + 4 > num5)
				{
					num5 += 10;
					num3 = 5f + 5f * (float)(num / 10);
				}
				num2 = 15f + num3 * (float)num;
			}
			return num;
		}

		private int GetMaxSecondaryStock()
		{
			if (cachedEffectiveAuthority)
			{
				return lunarSpikeSkill.GetBaseMaxStock();
			}
			return maxSecondaryStock;
		}

		private int GetSecondaryStock()
		{
			if (cachedEffectiveAuthority)
			{
				return lunarSpikeSkill.GetBaseStock();
			}
			return secondaryStock;
		}

		private void UpdateStats()
		{
			characterBody.RecalculateStats();
		}

		private void CalcTamperedHeartStats()
		{
			int num = maxSecondaryStock - secondaryStock;
			if (num < 0)
			{
				num = 0;
			}
			float heartRegen = tamperedHeartRegen * (float)num;
			float heartMSpeed = tamperedHeartMoveSpeed * (float)num;
			float attackSpeed = tamperedHeartAttackSpeed * (float)secondaryStock;
			float armor = tamperedHeartArmor * (float)secondaryStock;
			float heartDamage = 0f;
			characterBody.ApplyTamperedHeartPassive(heartRegen, heartMSpeed, heartDamage, armor, attackSpeed);
			UpdateStats();
			oldSecondaryStock = secondaryStock;
		}

		private float CalculateHyperbolicStatBonuses(float statCalc, float spikesToCalculate)
		{
			float num = 0f;
			if (spikesToCalculate > 0f)
			{
				if (spikesToCalculate <= 4f)
				{
					num += spikesToCalculate * statCalc;
				}
				else if (spikesToCalculate > 4f)
				{
					num += statCalc * 4f + (1f - 1f / (statCalc * (spikesToCalculate - 4f) + 1f));
				}
			}
			return num;
		}

		private float RegenAndMoveSpeedCalc(float statCalc)
		{
			if (secondaryStock < maxSecondaryStock)
			{
				return statCalc * (float)(maxSecondaryStock - secondaryStock);
			}
			return 0f;
		}

		private void IncreaseStockCount()
		{
			extraShardFromHealth = GetTotalSpikeCount();
			if (extraShardFromHealth != oldExtraShardFromHealth)
			{
				if (extraShardFromHealth < 0)
				{
					extraShardFromHealth = 0;
				}
				characterBody.extraSecondaryFromSkill = extraShardFromHealth;
				int num = extraShardFromHealth / 4;
				if (laserSpecialSkill.skillDef.skillIndex == laserBurstSkillIndex && num > 0)
				{
					characterBody.extraSpecialFromSkill = num;
				}
				UpdateStats();
				oldExtraShardFromHealth = extraShardFromHealth;
			}
			maxSecondaryStock = GetMaxSecondaryStock();
		}

		public float GetClubSwingAltSecondaryTimestamp()
		{
			return clubSwingAltSecondaryTimestamp;
		}

		public void SetClubSwingAltSecondaryTimestamp()
		{
			clubSwingAltSecondaryTimestamp = Time.time;
		}

		private void CacheEffectiveAuthority()
		{
			cachedEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdUpdateAmmoAmounts(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdUpdateAmmoAmounts called on client.");
			}
			else
			{
				((FalseSonController)obj).CmdUpdateAmmoAmounts((int)reader.ReadPackedUInt32(), (int)reader.ReadPackedUInt32());
			}
		}

		public void CallCmdUpdateAmmoAmounts(int _secondaryStock, int _maxSecondaryStock)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdUpdateAmmoAmounts called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdUpdateAmmoAmounts(_secondaryStock, _maxSecondaryStock);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdUpdateAmmoAmounts);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)_secondaryStock);
			networkWriter.WritePackedUInt32((uint)_maxSecondaryStock);
			SendCommandInternal(networkWriter, 0, "CmdUpdateAmmoAmounts");
		}

		static FalseSonController()
		{
			kCmdCmdUpdateAmmoAmounts = -634793383;
			NetworkBehaviour.RegisterCommandDelegate(typeof(FalseSonController), kCmdCmdUpdateAmmoAmounts, InvokeCmdCmdUpdateAmmoAmounts);
			NetworkCRC.RegisterBehaviour("FalseSonController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class FalseSonBossController : MonoBehaviour
	{
		public CharacterBody characterBody;

		public Animator characterAnimator;

		public ModelLocator modelLocator;

		public GameObject lunarSpikePrefab;

		public ChildLocator childLocator;

		public HealthComponent healthComponent;

		public GameObject masterFSPrefab;

		public Transform lunarSpike;

		public Transform lunarSpikeLocation;

		private float maxHealth;

		private float currentHealth;

		private bool health75;

		public bool health50;

		public bool lunarSpikeActive;

		private float testTimeGate = 2f;

		private float spikeTimer;

		public int swingCounter;

		public bool firedLunarSpike;

		private void OnEnable()
		{
			lunarSpikeLocation = childLocator.FindChild("LunarSpike");
		}

		private void Start()
		{
			maxHealth = healthComponent.health;
		}

		private void FixedUpdate()
		{
			if (healthComponent.health <= maxHealth * 0.5f && !health50)
			{
				PlayAnimation("FullBody, Override", "OverloadErruption", "OverloadErruption.playbackRate", 6f);
				spikeTimer += Time.deltaTime;
				if (spikeTimer > 2.8f)
				{
					SpawnLunarSpike();
				}
				health50 = true;
			}
			if (!lunarSpikeActive)
			{
				return;
			}
			if (characterBody.GetBuffCount(RoR2Content.Buffs.HiddenInvincibility) < 1)
			{
				characterBody.AddBuff(RoR2Content.Buffs.HiddenInvincibility);
			}
			if (!lunarSpike)
			{
				characterBody.RemoveBuff(RoR2Content.Buffs.HiddenInvincibility);
				characterBody.RemoveBuff(DLC2Content.Buffs.CorruptionFesters);
				if (health50)
				{
					characterBody.AddTimedBuff(DLC2Content.Buffs.WeakenedBeating, 60f);
				}
				lunarSpikeActive = false;
			}
		}

		protected void PlayAnimation(string layerName, string animationStateName, string playbackRateParam, float duration)
		{
			if (duration <= 0f)
			{
				UnityEngine.Debug.LogWarningFormat("EntityState.PlayAnimation: Zero duration is not allowed. type={0}", GetType().Name);
				return;
			}
			Animator modelAnimator = GetModelAnimator();
			if ((bool)modelAnimator)
			{
				PlayAnimationOnAnimator(modelAnimator, layerName, animationStateName, playbackRateParam, duration);
			}
		}

		protected static void PlayAnimationOnAnimator(Animator modelAnimator, string layerName, string animationStateName, string playbackRateParam, float duration)
		{
			modelAnimator.speed = 1f;
			modelAnimator.Update(0f);
			int layerIndex = modelAnimator.GetLayerIndex(layerName);
			if (layerIndex >= 0)
			{
				modelAnimator.SetFloat(playbackRateParam, 1f);
				modelAnimator.PlayInFixedTime(animationStateName, layerIndex, 0f);
				modelAnimator.Update(0f);
				float length = modelAnimator.GetCurrentAnimatorStateInfo(layerIndex).length;
				modelAnimator.SetFloat(playbackRateParam, length / duration);
			}
		}

		protected Animator GetModelAnimator()
		{
			if ((bool)modelLocator && (bool)modelLocator.modelTransform)
			{
				return modelLocator.modelTransform.GetComponent<Animator>();
			}
			return null;
		}

		public void SpawnLunarSpike()
		{
			MasterSpawnSlotController component = GetComponent<MasterSpawnSlotController>();
			if (NetworkServer.active && (bool)component)
			{
				component.SpawnRandomOpen(1, Run.instance.stageRng, base.gameObject);
			}
			lunarSpike = lunarSpikeLocation.transform.GetChild(0);
			lunarSpike.transform.rotation = lunarSpikeLocation.rotation;
			lunarSpike.GetComponent<CharacterBody>().baseMaxHealth = maxHealth * 0.2f;
			DamageInfo damageInfo = new DamageInfo
			{
				damage = healthComponent.health * 0.1f
			};
			healthComponent.TakeDamage(damageInfo);
			characterBody.AddBuff(DLC2Content.Buffs.CorruptionFesters);
			lunarSpikeActive = true;
			firedLunarSpike = true;
		}
	}
	public class FissureSlamCracksController : MonoBehaviour
	{
		private class Meteor
		{
			public UnityEngine.Vector3 impactPosition;

			public float startTime;

			public bool didTravelEffect;

			public bool valid = true;
		}

		private class MeteorWave
		{
			private readonly CharacterBody[] targets;

			private int currentStep;

			private float hitChance = 0.4f;

			private readonly UnityEngine.Vector3 center;

			public float timer;

			private NodeGraphSpider nodeGraphSpider;

			public MeteorWave(CharacterBody[] targets, UnityEngine.Vector3 center)
			{
				this.targets = new CharacterBody[targets.Length];
				targets.CopyTo(this.targets, 0);
				Util.ShuffleArray(targets);
				this.center = center;
				nodeGraphSpider = new NodeGraphSpider(SceneInfo.instance.groundNodes, HullMask.Human);
				nodeGraphSpider.AddNodeForNextStep(SceneInfo.instance.groundNodes.FindClosestNode(center, HullClassification.Human));
				int i = 0;
				for (int num = 10; i < num; i++)
				{
					if (!nodeGraphSpider.PerformStep())
					{
						break;
					}
				}
			}

			public Meteor GetNextMeteor()
			{
				if (currentStep >= targets.Length)
				{
					return null;
				}
				CharacterBody characterBody = targets[currentStep];
				Meteor meteor = new Meteor();
				if ((bool)characterBody && UnityEngine.Random.value < hitChance)
				{
					meteor.impactPosition = characterBody.corePosition;
					UnityEngine.Vector3 origin = meteor.impactPosition + UnityEngine.Vector3.up * 6f;
					UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
					onUnitSphere.y = -1f;
					if (Physics.Raycast(origin, onUnitSphere, out var hitInfo, 12f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						meteor.impactPosition = hitInfo.point;
					}
					else if (Physics.Raycast(meteor.impactPosition, UnityEngine.Vector3.down, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						meteor.impactPosition = hitInfo.point;
					}
				}
				else if (nodeGraphSpider.collectedSteps.Count != 0)
				{
					int index = UnityEngine.Random.Range(0, nodeGraphSpider.collectedSteps.Count);
					SceneInfo.instance.groundNodes.GetNodePosition(nodeGraphSpider.collectedSteps[index].node, out meteor.impactPosition);
				}
				else
				{
					meteor.valid = false;
				}
				meteor.startTime = Run.instance.time;
				currentStep++;
				return meteor;
			}
		}

		public int waveCount;

		public float waveMinInterval;

		public float waveMaxInterval;

		public GameObject warningEffectPrefab;

		public GameObject travelEffectPrefab;

		public float travelEffectDuration;

		public GameObject impactEffectPrefab;

		public float impactDelay;

		public float blastDamageCoefficient;

		public float blastRadius;

		public float blastForce;

		[NonSerialized]
		public GameObject owner;

		[NonSerialized]
		public float ownerDamage;

		[NonSerialized]
		public bool isCrit;

		public UnityEvent onDestroyEvents;

		private List<Meteor> meteorList;

		private List<MeteorWave> waveList;

		private int wavesPerformed;

		private float waveTimer;

		private void Start()
		{
			if (NetworkServer.active)
			{
				meteorList = new List<Meteor>();
				waveList = new List<MeteorWave>();
			}
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			waveTimer -= Time.fixedDeltaTime;
			if (waveTimer <= 0f && wavesPerformed < waveCount)
			{
				wavesPerformed++;
				waveTimer = UnityEngine.Random.Range(waveMinInterval, waveMaxInterval);
				MeteorWave item = new MeteorWave(CharacterBody.readOnlyInstancesList.ToArray(), base.transform.position);
				waveList.Add(item);
			}
			for (int num = waveList.Count - 1; num >= 0; num--)
			{
				MeteorWave meteorWave = waveList[num];
				meteorWave.timer -= Time.fixedDeltaTime;
				if (meteorWave.timer <= 0f)
				{
					meteorWave.timer = UnityEngine.Random.Range(0.05f, 0.075f);
					Meteor nextMeteor = meteorWave.GetNextMeteor();
					if (nextMeteor == null)
					{
						waveList.RemoveAt(num);
					}
					else if (nextMeteor.valid)
					{
						meteorList.Add(nextMeteor);
						EffectManager.SpawnEffect(warningEffectPrefab, new EffectData
						{
							origin = nextMeteor.impactPosition,
							scale = blastRadius
						}, transmit: true);
					}
				}
			}
			float num2 = Run.instance.time - impactDelay;
			float num3 = num2 - travelEffectDuration;
			for (int num4 = meteorList.Count - 1; num4 >= 0; num4--)
			{
				Meteor meteor = meteorList[num4];
				if (meteor.startTime < num3 && !meteor.didTravelEffect)
				{
					DoMeteorEffect(meteor);
				}
				if (meteor.startTime < num2)
				{
					meteorList.RemoveAt(num4);
					DetonateMeteor(meteor);
				}
			}
			if (wavesPerformed == waveCount && meteorList.Count == 0)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void OnDestroy()
		{
			onDestroyEvents.Invoke();
		}

		private void DoMeteorEffect(Meteor meteor)
		{
			meteor.didTravelEffect = true;
			if ((bool)travelEffectPrefab)
			{
				EffectManager.SpawnEffect(travelEffectPrefab, new EffectData
				{
					origin = meteor.impactPosition,
					scale = blastRadius
				}, transmit: true);
			}
		}

		private void DetonateMeteor(Meteor meteor)
		{
			EffectData effectData = new EffectData
			{
				origin = meteor.impactPosition,
				scale = blastRadius
			};
			EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true);
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.inflictor = base.gameObject;
			blastAttack.baseDamage = blastDamageCoefficient * ownerDamage;
			blastAttack.baseForce = blastForce;
			blastAttack.attackerFiltering = AttackerFiltering.AlwaysHit;
			blastAttack.crit = isCrit;
			blastAttack.falloffModel = BlastAttack.FalloffModel.Linear;
			blastAttack.attacker = owner;
			blastAttack.bonusForce = UnityEngine.Vector3.zero;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.position = meteor.impactPosition;
			blastAttack.procChainMask = default(ProcChainMask);
			blastAttack.procCoefficient = 1f;
			blastAttack.radius = blastRadius;
			blastAttack.Fire();
		}
	}
	public class MeridianReportBossFinalPosition : MonoBehaviour
	{
		private void Start()
		{
			MeridianEventTriggerInteraction.bossTransform = base.transform;
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class SpawnerPodsController : MonoBehaviour
	{
		[FormerlySerializedAs("maxSpawnTimer")]
		public float incubationDuration;

		public GameObject spawnEffect;

		public GameObject hatchEffect;

		[FormerlySerializedAs("dissolveTime")]
		public float dissolveDuration;

		public string podSpawnSound = "";

		public string podHatchSound = "";

		private CharacterMaster ownerMaster;

		private CharacterBody characterBody;

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
		}

		private void Start()
		{
			ownerMaster = characterBody.master.minionOwnership.ownerMaster;
			if (NetworkServer.active)
			{
				Deployable component = GetComponent<Deployable>();
				if ((bool)ownerMaster)
				{
					ownerMaster.AddDeployable(component, DeployableSlot.ParentPodAlly);
				}
			}
		}

		public void UndeployKill()
		{
			characterBody.healthComponent.Suicide();
		}

		public void Dissolve()
		{
			PrintController printController = characterBody.modelLocator.modelTransform.gameObject.AddComponent<PrintController>();
			printController.printTime = dissolveDuration;
			printController.enabled = true;
			printController.startingPrintHeight = 99999f;
			printController.maxPrintHeight = 99999f;
			printController.startingPrintBias = 0.95f;
			printController.maxPrintBias = 1.95f;
			printController.animateFlowmapPower = true;
			printController.startingFlowmapPower = 1.14f;
			printController.maxFlowmapPower = 30f;
			printController.disableWhenFinished = false;
			printController.printCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
		}
	}
	public class GeodeSecretMissionController : MonoBehaviour
	{
		public int numberOfGeodesNecessary = 1;

		public List<GameObject> geodeMissionObjects = new List<GameObject>();

		public GameObject rewardSpawnLocation;

		public EntityStateMachine entityStateMachine;

		public GameObject rewardPrefab;

		public bool increaseRewardPerPlayer;

		public int numberOfRewardsSpawned = 1;

		public int numberOfRewardOptions = 3;

		public BasicPickupDropTable rewardDropTable;

		[Tooltip("Use this tier to get a pickup index for the reward. The droplet's visuals will correspond to this.")]
		public ItemTier rewardDisplayTier;

		[HideInInspector]
		public int geodeInteractionsTracker;

		public OnCollisionEventController onCollisionEventController;

		public void AdvanceGeodeSecretMission()
		{
			geodeInteractionsTracker++;
			CheckIfRewardShouldBeGranted();
		}

		public void CheckIfRewardShouldBeGranted()
		{
			if (numberOfGeodesNecessary <= geodeInteractionsTracker)
			{
				onCollisionEventController.SetAvailable(setActive: true);
			}
		}
	}
	public class VoidRaidEncounterController : NetworkBehaviour
	{
		public GameObject VoidRaidBossPrefab;

		public Transform VoidRaidBossSpawnPosition;

		private void Start()
		{
			GameObject obj = UnityEngine.Object.Instantiate(VoidRaidBossPrefab, VoidRaidBossSpawnPosition.position, UnityEngine.Quaternion.identity);
			obj.GetComponent<CharacterMaster>().teamIndex = TeamIndex.Monster;
			NetworkServer.Spawn(obj);
			obj.GetComponent<CharacterMaster>().SpawnBodyHere();
		}

		private void Update()
		{
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class SeekerController : NetworkBehaviour, IOnKilledServerReceiver
	{
		private byte currentChakraGate;

		public bool doesExitVehicle;

		[SerializeField]
		public GameObject healingExplosionPrefab;

		[SerializeField]
		public GameObject scopeOverlayPrefab;

		[SerializeField]
		public string overlayChild;

		private OverlayController overlayController;

		private List<ImageFillController> fillUiList = new List<ImageFillController>();

		private ChildLocator overlayInstanceChildLocator;

		public Color32 chakraDefaultColor = new Color32(0, 0, 0, 128);

		public Color32 chakraGrantedColor = new Color32(byte.MaxValue, 233, 124, 200);

		public Color32 chakraFinishedColor = new Color32(0, byte.MaxValue, 0, 200);

		public Color32 chakraAfterReviveColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 125);

		public Color32 chakraAfterReviveCompleteColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 200);

		public Color32 chakraSplashDefaultColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 125);

		public Color32 chakraSplashGrantedColor = new Color32(116, 226, 203, 200);

		public Color32 chakraSplashBurnedColor = new Color32(0, 0, 0, 0);

		public Color32 chakraBurnedColor = new Color32(byte.MaxValue, 0, 0, 200);

		public string[] chakraOrder = new string[7] { "Pedal1", "Pedal7", "Pedal2", "Pedal6", "Pedal3", "Pedal5", "Pedal4" };

		public string finalActivation = "Glow";

		[Tooltip("If a new respawn point is needed from a dead player, how far from the Seeker can it be.")]
		public float newRespawnPointMaxDistanceFromSeeker = 10f;

		[Tooltip("In case we need a new respawn point, we may only get one. So we randomize positions around that point for safety. Not too high: they might spawn through a wall.")]
		public UnityEngine.Vector3 randomDistanceForPlayerRespawn = new UnityEngine.Vector3(2f, 1f, 2f);

		private SeekerSoulSpiralManager soulSpiralManager;

		private CharacterBody characterBody;

		[NonSerialized]
		public sbyte[] meditationStepAndSequence = new sbyte[6];

		[NonSerialized]
		public bool meditationUIDirty;

		private List<NodeGraph.NodeIndex> possibleNodesToTarget = new List<NodeGraph.NodeIndex>();

		private static int kCmdCmdUnlockGateEffects;

		private static int kCmdCmdUpdateMeditationInput;

		private static int kRpcRpcSetMeditation;

		private static int kRpcRpcSetPedalsValue;

		private static int kRpcRpcSpiralCommand;

		private static int kCmdCmdTriggerHealPulse;

		private static int kCmdCmdSpiralCommand;

		public sbyte meditationInputStep
		{
			get
			{
				return meditationStepAndSequence[0];
			}
			set
			{
				meditationUIDirty = true;
				meditationStepAndSequence[0] = value;
				CallCmdUpdateMeditationInput(meditationStepAndSequence);
			}
		}

		public sbyte GetNextMeditationStep()
		{
			int num = meditationStepAndSequence[0] + 1;
			if (0 <= num && num >= meditationStepAndSequence.Length)
			{
				return -1;
			}
			return meditationStepAndSequence[num];
		}

		private void OnEnable()
		{
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams
			{
				prefab = scopeOverlayPrefab,
				childLocatorEntry = overlayChild
			});
			overlayController.onInstanceAdded += OnOverlayInstanceAdded;
			overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
			if (soulSpiralManager == null)
			{
				soulSpiralManager = new SeekerSoulSpiralManager(this);
			}
			characterBody = GetComponent<CharacterBody>();
		}

		private bool IsPositionWithinBounds(UnityEngine.Vector3 position)
		{
			List<MapZone> instancesList = InstanceTracker.GetInstancesList<MapZone>();
			bool flag = false;
			int num = 0;
			foreach (MapZone item in instancesList)
			{
				if (item.gameObject.activeSelf && item.zoneType == MapZone.ZoneType.OutOfBounds && item.triggerType == MapZone.TriggerType.TriggerExit)
				{
					num++;
					flag |= item.IsPointInsideMapZone(position);
				}
			}
			if (num < 1)
			{
				return true;
			}
			return flag;
		}

		private UnityEngine.Vector3 FindNewSpawnPosition(UnityEngine.Vector3 spawnPosition)
		{
			UnityEngine.Vector3 footPosition = characterBody.footPosition;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			if (possibleNodesToTarget.Count < 1)
			{
				newRespawnPointMaxDistanceFromSeeker = Mathf.Max(newRespawnPointMaxDistanceFromSeeker, 1f);
				groundNodes.FindNodesInRange(footPosition, 1f, newRespawnPointMaxDistanceFromSeeker, HullMask.Human, possibleNodesToTarget);
			}
			if (possibleNodesToTarget.Count < 1)
			{
				return spawnPosition;
			}
			groundNodes.GetNodePosition(possibleNodesToTarget[^1], out var position);
			possibleNodesToTarget.RemoveAt(possibleNodesToTarget.Count - 1);
			return position;
		}

		[Command]
		private void CmdUnlockGateEffects(byte chakraGate)
		{
			currentChakraGate = chakraGate;
			CharacterBody characterBody = this.characterBody;
			if (chakraGate < 7)
			{
				characterBody.AddBuff(DLC2Content.Buffs.ChakraBuff.buffIndex);
			}
			else if (chakraGate == 7 && characterBody.master.getSeekerUsedRevive() == CharacterMaster.SEEKER_REVIVE_STATUS.UNUSED)
			{
				foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
				{
					if (instance == null)
					{
						continue;
					}
					CharacterMaster master = instance.master;
					if (instance.isConnected && master.IsDeadAndOutOfLivesServer())
					{
						UnityEngine.Vector3 vector = master.deathFootPosition;
						if (!IsPositionWithinBounds(vector))
						{
							vector = FindNewSpawnPosition(vector);
							vector.y += UnityEngine.Random.Range(0.5f, Mathf.Abs(randomDistanceForPlayerRespawn.y));
							vector.x += UnityEngine.Random.Range(0f - randomDistanceForPlayerRespawn.x, randomDistanceForPlayerRespawn.x);
							vector.z += UnityEngine.Random.Range(0f - randomDistanceForPlayerRespawn.z, randomDistanceForPlayerRespawn.z);
						}
						master.Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true);
						CharacterBody body = master.GetBody();
						if ((bool)body)
						{
							body.AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
							EntityStateMachine[] components = body.GetComponents<EntityStateMachine>();
							foreach (EntityStateMachine obj in components)
							{
								obj.initialStateType = obj.mainStateType;
							}
							GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/TeleporterHealNovaPulse");
							if ((bool)gameObject)
							{
								EffectManager.SpawnEffect(gameObject, new EffectData
								{
									origin = vector,
									rotation = body.transform.rotation
								}, transmit: true);
							}
						}
					}
					else if ((object)master == null || master.GetBody()?.HasBuff(DLC2Content.Buffs.RevitalizeBuff.buffIndex) != true)
					{
						master?.GetBody()?.AddBuff(DLC2Content.Buffs.RevitalizeBuff.buffIndex);
					}
				}
				GetComponent<CharacterBody>().master.CallRpcSetSeekerRevive(CharacterMaster.SEEKER_REVIVE_STATUS.USED);
			}
			CallRpcSetPedalsValue(chakraGate);
		}

		public void RandomizeMeditationInputs()
		{
			meditationStepAndSequence[0] = 0;
			for (int i = 1; i <= 5; i++)
			{
				meditationStepAndSequence[i] = (sbyte)UnityEngine.Random.Range(0, 4);
			}
			CallCmdUpdateMeditationInput(meditationStepAndSequence);
		}

		[Command]
		private void CmdUpdateMeditationInput(sbyte[] sequence)
		{
			meditationStepAndSequence = sequence;
			meditationUIDirty = true;
			CallRpcSetMeditation(sequence);
		}

		[ClientRpc]
		private void RpcSetMeditation(sbyte[] sequence)
		{
			meditationStepAndSequence = sequence;
			meditationUIDirty = true;
		}

		public void IncrementChakraGate()
		{
			MonoBehaviour.print("triggered unlock gate");
			currentChakraGate++;
			CallCmdUnlockGateEffects(currentChakraGate);
		}

		[ClientRpc]
		public void RpcSetPedalsValue(byte value)
		{
			if (base.hasAuthority)
			{
				currentChakraGate = value;
				UpdatePetalsUI();
			}
		}

		public void UpdatePetalsUI()
		{
			CharacterMaster.SEEKER_REVIVE_STATUS seekerUsedRevive = GetComponent<CharacterBody>().master.getSeekerUsedRevive();
			UnityEngine.UI.Image component = overlayInstanceChildLocator.FindChild(finalActivation).GetComponent<UnityEngine.UI.Image>();
			switch (seekerUsedRevive)
			{
			case CharacterMaster.SEEKER_REVIVE_STATUS.UNUSED:
				component.color = chakraSplashDefaultColor;
				setColors(chakraGrantedColor, chakraDefaultColor);
				break;
			case CharacterMaster.SEEKER_REVIVE_STATUS.USED:
				component.color = chakraSplashGrantedColor;
				setColors(chakraFinishedColor, chakraDefaultColor);
				break;
			case CharacterMaster.SEEKER_REVIVE_STATUS.BURNED:
				component.color = chakraSplashBurnedColor;
				if (currentChakraGate >= 7)
				{
					setColors(chakraAfterReviveCompleteColor, chakraDefaultColor);
					break;
				}
				currentChakraGate = (byte)((currentChakraGate < 1) ? 1 : currentChakraGate);
				setColors(chakraAfterReviveColor, chakraDefaultColor);
				break;
			}
			void setColors(Color32 active, Color32 inactive)
			{
				for (int i = 0; i < 7; i++)
				{
					if (i < currentChakraGate)
					{
						overlayInstanceChildLocator.FindChild(chakraOrder[i]).GetComponent<UnityEngine.UI.Image>().color = active;
					}
					else
					{
						overlayInstanceChildLocator.FindChild(chakraOrder[i]).GetComponent<UnityEngine.UI.Image>().color = inactive;
					}
				}
			}
		}

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			fillUiList.Add(instance.GetComponent<ImageFillController>());
			overlayInstanceChildLocator = instance.GetComponent<ChildLocator>();
			UpdatePetalsUI();
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			fillUiList.Remove(instance.GetComponent<ImageFillController>());
		}

		public void FireSoulSpiral(FireProjectileInfo projectileInfo)
		{
			soulSpiralManager.FireSoulSpiral(projectileInfo);
		}

		public void SpiralSendCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg)
		{
			if (NetworkServer.active)
			{
				CallRpcSpiralCommand(msg);
			}
			else
			{
				CallCmdSpiralCommand(msg);
			}
		}

		[ClientRpc]
		public void RpcSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg)
		{
			if (!soulSpiralManager.hasAuthority && !NetworkServer.active)
			{
				soulSpiralManager.ReceiveSpiralCommand(msg);
			}
		}

		[Command]
		internal void CmdTriggerHealPulse(float value, UnityEngine.Vector3 corePosition, float blastRadius)
		{
			HealingPulse healingPulse = new HealingPulse();
			healingPulse.healAmount = value;
			healingPulse.origin = corePosition;
			healingPulse.radius = blastRadius;
			healingPulse.effectPrefab = healingExplosionPrefab;
			healingPulse.teamIndex = TeamIndex.Player;
			healingPulse.overShield = 0f;
			healingPulse.Fire();
		}

		[Command]
		public void CmdSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg)
		{
			if (!soulSpiralManager.hasAuthority)
			{
				soulSpiralManager.ReceiveSpiralCommand(msg);
			}
			CallRpcSpiralCommand(msg);
		}

		private void FixedUpdate()
		{
			if (soulSpiralManager.runFixedUpdate)
			{
				soulSpiralManager.MyFixedUpdate();
			}
		}

		private void OnDestroy()
		{
			soulSpiralManager.ShutdownAndCleanupSpirals();
		}

		public void OnKilledServer(DamageReport damageReport)
		{
			if (NetworkServer.active)
			{
				soulSpiralManager.ShutdownAndCleanupSpirals();
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdUnlockGateEffects(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdUnlockGateEffects called on client.");
			}
			else
			{
				((SeekerController)obj).CmdUnlockGateEffects((byte)reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeCmdCmdUpdateMeditationInput(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdUpdateMeditationInput called on client.");
			}
			else
			{
				((SeekerController)obj).CmdUpdateMeditationInput(GeneratedNetworkCode._ReadArraySByte_None(reader));
			}
		}

		protected static void InvokeCmdCmdTriggerHealPulse(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdTriggerHealPulse called on client.");
			}
			else
			{
				((SeekerController)obj).CmdTriggerHealPulse(reader.ReadSingle(), reader.ReadVector3(), reader.ReadSingle());
			}
		}

		protected static void InvokeCmdCmdSpiralCommand(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSpiralCommand called on client.");
			}
			else
			{
				((SeekerController)obj).CmdSpiralCommand((SeekerSoulSpiralManager.SoulSpiralCommandType)reader.ReadInt32());
			}
		}

		public void CallCmdUnlockGateEffects(byte chakraGate)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdUnlockGateEffects called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdUnlockGateEffects(chakraGate);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdUnlockGateEffects);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32(chakraGate);
			SendCommandInternal(networkWriter, 0, "CmdUnlockGateEffects");
		}

		public void CallCmdUpdateMeditationInput(sbyte[] sequence)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdUpdateMeditationInput called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdUpdateMeditationInput(sequence);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdUpdateMeditationInput);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteArraySByte_None(networkWriter, sequence);
			SendCommandInternal(networkWriter, 0, "CmdUpdateMeditationInput");
		}

		public void CallCmdTriggerHealPulse(float value, UnityEngine.Vector3 corePosition, float blastRadius)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdTriggerHealPulse called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdTriggerHealPulse(value, corePosition, blastRadius);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdTriggerHealPulse);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(value);
			networkWriter.Write(corePosition);
			networkWriter.Write(blastRadius);
			SendCommandInternal(networkWriter, 0, "CmdTriggerHealPulse");
		}

		public void CallCmdSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSpiralCommand called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSpiralCommand(msg);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSpiralCommand);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)msg);
			SendCommandInternal(networkWriter, 0, "CmdSpiralCommand");
		}

		protected static void InvokeRpcRpcSetMeditation(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetMeditation called on server.");
			}
			else
			{
				((SeekerController)obj).RpcSetMeditation(GeneratedNetworkCode._ReadArraySByte_None(reader));
			}
		}

		protected static void InvokeRpcRpcSetPedalsValue(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetPedalsValue called on server.");
			}
			else
			{
				((SeekerController)obj).RpcSetPedalsValue((byte)reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeRpcRpcSpiralCommand(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSpiralCommand called on server.");
			}
			else
			{
				((SeekerController)obj).RpcSpiralCommand((SeekerSoulSpiralManager.SoulSpiralCommandType)reader.ReadInt32());
			}
		}

		public void CallRpcSetMeditation(sbyte[] sequence)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetMeditation called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetMeditation);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteArraySByte_None(networkWriter, sequence);
			SendRPCInternal(networkWriter, 0, "RpcSetMeditation");
		}

		public void CallRpcSetPedalsValue(byte value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetPedalsValue called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetPedalsValue);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32(value);
			SendRPCInternal(networkWriter, 0, "RpcSetPedalsValue");
		}

		public void CallRpcSpiralCommand(SeekerSoulSpiralManager.SoulSpiralCommandType msg)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSpiralCommand called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSpiralCommand);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)msg);
			SendRPCInternal(networkWriter, 0, "RpcSpiralCommand");
		}

		static SeekerController()
		{
			kCmdCmdUnlockGateEffects = -1757393198;
			NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdUnlockGateEffects, InvokeCmdCmdUnlockGateEffects);
			kCmdCmdUpdateMeditationInput = -1791025022;
			NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdUpdateMeditationInput, InvokeCmdCmdUpdateMeditationInput);
			kCmdCmdTriggerHealPulse = -416543526;
			NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdTriggerHealPulse, InvokeCmdCmdTriggerHealPulse);
			kCmdCmdSpiralCommand = -1428889191;
			NetworkBehaviour.RegisterCommandDelegate(typeof(SeekerController), kCmdCmdSpiralCommand, InvokeCmdCmdSpiralCommand);
			kRpcRpcSetMeditation = -72748599;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SeekerController), kRpcRpcSetMeditation, InvokeRpcRpcSetMeditation);
			kRpcRpcSetPedalsValue = 1863576493;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SeekerController), kRpcRpcSetPedalsValue, InvokeRpcRpcSetPedalsValue);
			kRpcRpcSpiralCommand = 1157507459;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SeekerController), kRpcRpcSpiralCommand, InvokeRpcRpcSpiralCommand);
			NetworkCRC.RegisterBehaviour("SeekerController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class SeekerSoulSpiralManager
	{
		public enum SoulSpiralCommandType
		{
			RegisterIncomingSpiral,
			Boost,
			EndBoost
		}

		public SeekerController seekerController;

		private NetworkIdentity seekerNetworkIdentity;

		public CharacterBody seekerBody;

		private SoulSpiralProjectile[] soulSpiralArray;

		private SoulSpiralOrbiter soulSpiralOrbiter;

		private static GameObject soulSpiralBoostVFXPrefab;

		private static string soulSpiralBoostVFXPrefabGuid = "085f424d57ade224388b2ec514439cd9";

		private static string soulSpiralBoostVFXParentName = "Base";

		private EffectManagerHelper boostFXInstance;

		private Transform boostFXParent;

		public bool runFixedUpdate;

		private int soulSpiralLimit = 6;

		private int spiralsRequested;

		private int nextIndex;

		public bool hasAuthority
		{
			get
			{
				if (seekerNetworkIdentity == null)
				{
					return false;
				}
				return Util.HasEffectiveAuthority(seekerNetworkIdentity);
			}
		}

		public SeekerSoulSpiralManager(SeekerController _seekerController)
		{
			seekerController = _seekerController;
			seekerNetworkIdentity = _seekerController.GetComponent<NetworkIdentity>();
			seekerBody = _seekerController.GetComponent<CharacterBody>();
			soulSpiralArray = new SoulSpiralProjectile[soulSpiralLimit * 2];
			soulSpiralOrbiter = new SoulSpiralOrbiter(_seekerController, this);
			ChildLocator childLocator = seekerBody.modelLocator?.modelTransform.GetComponent<ChildLocator>();
			if (childLocator != null)
			{
				int childIndex = childLocator.FindChildIndex(soulSpiralBoostVFXParentName);
				boostFXParent = childLocator.FindChild(childIndex)?.transform;
			}
			if (!(soulSpiralBoostVFXPrefab == null))
			{
				return;
			}
			if (!Addressables.LoadAssetAsync<GameObject>(soulSpiralBoostVFXPrefabGuid).IsValid())
			{
				UnityEngine.Debug.LogError("SeekerSoulSpiralManager failed to load " + soulSpiralBoostVFXPrefabGuid + ". Check the path and try again?");
				return;
			}
			LegacyResourcesAPI.LoadAsyncCallback(soulSpiralBoostVFXPrefabGuid, delegate(GameObject result)
			{
				soulSpiralBoostVFXPrefab = result;
			});
		}

		public void ReceiveSpiralCommand(SoulSpiralCommandType msg)
		{
			switch (msg)
			{
			case SoulSpiralCommandType.RegisterIncomingSpiral:
				RegisterIncomingSpiral();
				break;
			case SoulSpiralCommandType.Boost:
				BoostSpirals();
				break;
			case SoulSpiralCommandType.EndBoost:
				NonAuthorityEndBoost();
				break;
			}
		}

		public void MyFixedUpdate()
		{
			soulSpiralOrbiter.UpdateSpirals(ref soulSpiralArray);
		}

		public void FireSoulSpiral(FireProjectileInfo projectileInfo)
		{
			runFixedUpdate = hasAuthority;
			if (!CheckOurSpiralBudget())
			{
				BoostSpirals();
			}
			else
			{
				FireSoulSpiralInternal(projectileInfo);
			}
		}

		public void BoostSpirals()
		{
			FireBoostFX();
			if (hasAuthority)
			{
				soulSpiralOrbiter.BoostAuthority();
			}
		}

		public void FireBoostFX()
		{
			if (!(boostFXParent == null))
			{
				if (boostFXInstance != null && boostFXInstance.gameObject.activeSelf)
				{
					EndBoostFX();
				}
				boostFXInstance = EffectManager.GetAndActivatePooledEffect(soulSpiralBoostVFXPrefab, boostFXParent, inResetLocal: true);
				boostFXInstance.transform.SetParent(boostFXParent, worldPositionStays: false);
			}
		}

		public void EndBoostFX()
		{
			if (!(boostFXInstance == null))
			{
				boostFXInstance.ReturnToPool();
			}
		}

		public void NonAuthorityEndBoost()
		{
			EndBoostFX();
			int num = soulSpiralArray.Length;
			for (int i = 0; i < num; i++)
			{
				if (!(soulSpiralArray[i] == null))
				{
					soulSpiralArray[i].EndBoost();
				}
			}
		}

		private void FireSoulSpiralInternal(FireProjectileInfo projectileInfo)
		{
			RegisterIncomingSpiral();
			ProjectileManager.instance.FireProjectile(projectileInfo);
		}

		public void RegisterIncomingSpiral()
		{
			if (spiralsRequested < 1)
			{
				RoR2Application.onUpdate += DiscoverUnassignedSpirals;
			}
			spiralsRequested++;
		}

		private void DiscoverUnassignedSpirals()
		{
			if (seekerController == null)
			{
				StopListeningForUnassignedSpirals();
				return;
			}
			if (spiralsRequested > 0)
			{
				List<SoulSpiralProjectile> unassignedSoulSpirals = SoulSpiralProjectile.unassignedSoulSpirals;
				int count = unassignedSoulSpirals.Count;
				bool flag = hasAuthority;
				for (int i = 0; i < count; i++)
				{
					SoulSpiralProjectile soulSpiralProjectile = unassignedSoulSpirals[i];
					if (!(soulSpiralProjectile == null) && !(soulSpiralProjectile.projectileController.owner != seekerController.gameObject))
					{
						if (!TryToCacheSoulSpiral(soulSpiralProjectile, out var spiralPosition))
						{
							break;
						}
						soulSpiralProjectile.AssignSpiralOwner(this);
						if (flag)
						{
							SetSpiralOrbitPosition(soulSpiralProjectile, spiralPosition);
						}
						if (!soulSpiralProjectile.projectileController.isPrediction)
						{
							spiralsRequested--;
						}
					}
				}
			}
			if (spiralsRequested < 1)
			{
				RoR2Application.onUpdate -= DiscoverUnassignedSpirals;
			}
		}

		private bool TryToCacheSoulSpiral(SoulSpiralProjectile soulSpiral, out int spiralPosition)
		{
			spiralPosition = -1;
			for (int i = 0; i < soulSpiralLimit; i++)
			{
				if (soulSpiralArray[nextIndex] == null)
				{
					if (soulSpiral.projectileController.isPrediction)
					{
						soulSpiralArray[nextIndex * 2] = soulSpiral;
					}
					else
					{
						soulSpiralArray[nextIndex] = soulSpiral;
					}
					spiralPosition = nextIndex;
					if (!soulSpiral.projectileController.isPrediction)
					{
						nextIndex = (nextIndex + 1) % soulSpiralLimit;
					}
					soulSpiralOrbiter.ResetValues(soulSpiral);
					return true;
				}
				nextIndex = (nextIndex + 1) % soulSpiralLimit;
			}
			return false;
		}

		private bool CheckOurSpiralBudget()
		{
			int num = spiralsRequested;
			for (int i = 0; i < soulSpiralLimit; i++)
			{
				if (soulSpiralArray[i] != null)
				{
					num++;
				}
			}
			return num < soulSpiralLimit;
		}

		private float GetSoulSpiralOffsetDegreesByIndex(int index)
		{
			return index switch
			{
				1 => 240f, 
				2 => 120f, 
				3 => 300f, 
				4 => 60f, 
				5 => 180f, 
				_ => 0f, 
			};
		}

		private void SetSpiralOrbitPosition(SoulSpiralProjectile soulSpiral, int positionIndex)
		{
			soulSpiral.SetInitialDegreesFromOwnerForward(GetSoulSpiralOffsetDegreesByIndex(positionIndex), positionIndex);
		}

		public void ShutdownAndCleanupSpirals()
		{
			if (NetworkServer.active)
			{
				DestroyAllSpirals();
				CatchAndDestroyUnassignedSpirals();
			}
			StopListeningForUnassignedSpirals();
			runFixedUpdate = false;
		}

		private void CatchAndDestroyUnassignedSpirals()
		{
			if (seekerController == null || seekerController.gameObject == null)
			{
				return;
			}
			List<SoulSpiralProjectile> unassignedSoulSpirals = SoulSpiralProjectile.unassignedSoulSpirals;
			for (int num = unassignedSoulSpirals.Count - 1; num >= 0; num--)
			{
				SoulSpiralProjectile soulSpiralProjectile = unassignedSoulSpirals[num];
				if (!(soulSpiralProjectile == null) && !(soulSpiralProjectile.projectileController.owner != seekerController.gameObject))
				{
					soulSpiralProjectile.DestroySpiral();
				}
			}
		}

		private void StopListeningForUnassignedSpirals()
		{
			if (spiralsRequested > 0)
			{
				RoR2Application.onUpdate -= DiscoverUnassignedSpirals;
			}
			spiralsRequested = 0;
		}

		public void DestroyAllSpirals()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			runFixedUpdate = false;
			int num = soulSpiralArray.Length;
			for (int i = 0; i < num; i++)
			{
				if (soulSpiralArray[i] != null)
				{
					soulSpiralArray[i].DestroySpiral();
				}
			}
		}
	}
	[RequireComponent(typeof(VehicleSeat))]
	public class SojournVehicle : NetworkBehaviour, ICameraStateProvider
	{
		[Header("Vehicle Parameters")]
		public float nonLinearSpeedRate = 0.15f;

		public float nonLinearSpeedInterval = 1f;

		private float currentSpeed;

		public float startingSpeedBoost = 25f;

		private float startingSpeed;

		public float endSpeedTarget;

		public float endSpeedBodyInfluance = 1f;

		private float trueEndSpeed;

		public float cameraLerpTime = 1f;

		public float cameraForward = 2f;

		[Header("Blast Parameters")]
		public bool detonateOnCollision;

		public GameObject explosionEffectPrefab;

		public float blastDamageCoefficient;

		public float blastForce;

		public BlastAttack.FalloffModel blastFalloffModel;

		public DamageTypeCombo blastDamageType;

		public UnityEngine.Vector3 blastBonusForce;

		public float blastProcCoefficient;

		public string explosionSoundString;

		public GameObject healingExplosionPrefab;

		public float dmgAddedPerSecond = 0.5f;

		[Header("Blast Growth Rate")]
		private float blastRadius;

		public float minBlastSize = 4f;

		public float baseMaxBlastSize = 10f;

		public float perChakraAddMax = 2f;

		public float perChakraAddMin = 0.5f;

		public float blastNonlinearGrowthRate = 1f;

		[Tooltip("These are the explosion size indicators. They will be scaled up by blast size.")]
		public GameObject[] blastRadiusIndicators = new GameObject[0];

		[Tooltip("This is the scale of the visible size indicators.")]
		public float blastRadiusIndicatorScale = 0.125f;

		[Tooltip("This will be multiplied by the bast size before calculating collision. Larger will expand the collider.")]
		public float blastRadiusCollisionMult = 1f;

		public GameObject effectsToFlatten;

		[Header("Overlap Parameters")]
		public float overlapDamageCoefficient;

		public float overlapProcCoefficient;

		public float overlapForce;

		public float overlapFirePeriod;

		public float overlapVehicleDurationBonusPerHit;

		public GameObject overlapHitEffectPrefab;

		private float age;

		private VehicleSeat vehicleSeat;

		private Rigidbody vehicleRigidbody;

		[Header("Camera Parameters")]
		public PlayerCharacterMasterController playerCharacterMasterController;

		public GameObject sojournOverlayPrefab;

		private CameraTargetParams cameraTargetParams;

		private CharacterBody characterBody;

		[Header("Flight Parameters")]
		private SeekerController seekerController;

		private float increaseAgeCheck;

		public float agePerTenthSecondsCheck = 0.1f;

		public float incrementalFlightDamage = 0.075f;

		[FormerlySerializedAs("initialFlightDamageDelay")]
		public float initialFlightGracePeriod = 0.3f;

		public float afterGraceLerpDownTime = 1f;

		[Header("Healing Parameters")]
		private float healingOverShield;

		private float healingExplosionAmount;

		private bool skillKeyWasDown = true;

		private bool skillHeldDown = true;

		private OverlayController overlayController;

		private List<ImageFillController> fillUiList = new List<ImageFillController>();

		private ChildLocator overlayInstanceChildLocator;

		private OverlapAttack overlapAttack;

		private float overlapFireAge;

		private float overlapResetAge;

		private float agePerSecond;

		private float totalHealth;

		public Sojourn sojournState;

		public float barrierPercentage;

		public GameObject effectGameObject;

		public GameObject hitBox;

		private LocalUser localUser;

		private static int kRpcRpcEndSojournState;

		private void CacheLocalUser()
		{
			localUser = null;
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				if (readOnlyLocalPlayers.master == characterBody.master)
				{
					localUser = readOnlyLocalPlayers.localUser;
				}
			}
		}

		private void Awake()
		{
			playerCharacterMasterController = GetComponent<PlayerCharacterMasterController>();
			vehicleSeat = GetComponent<VehicleSeat>();
			vehicleSeat.onPassengerEnter += OnPassengerEnter;
			vehicleSeat.onPassengerExit += OnPassengerExit;
			vehicleRigidbody = GetComponent<Rigidbody>();
			effectGameObject = base.transform.Find("Effect").gameObject;
			hitBox = base.transform.Find("HitBox").gameObject;
			increaseAgeCheck = agePerTenthSecondsCheck;
		}

		private void Start()
		{
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, new OverlayCreationParams
			{
				prefab = sojournOverlayPrefab,
				childLocatorEntry = "CrosshairExtras"
			});
			totalHealth = characterBody.baseMaxHealth + characterBody.levelMaxHealth * (float)((int)characterBody.level - 1);
			UpdateBlastRadius();
		}

		private void OnPassengerExit(GameObject passenger)
		{
			foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList)
			{
				if (readOnlyInstances.target == passenger)
				{
					readOnlyInstances.SetOverrideCam(this, 0f);
					readOnlyInstances.SetOverrideCam(null, cameraLerpTime);
				}
			}
			DetonateServer();
		}

		[ClientRpc]
		private void RpcEndSojournState()
		{
			Util.PlaySound(explosionSoundString, base.gameObject);
			seekerController.doesExitVehicle = true;
		}

		private void OnPassengerEnter(GameObject passenger)
		{
			skillHeldDown = vehicleSeat.currentPassengerInputBank.skill3.down;
			vehicleSeat.currentPassengerBody.GetComponent<InteractionDriver>().interactableOverride = null;
			UnityEngine.Vector3 aimDirection = vehicleSeat.currentPassengerInputBank.aimDirection;
			vehicleRigidbody.rotation = UnityEngine.Quaternion.LookRotation(aimDirection);
			characterBody = vehicleSeat.currentPassengerBody;
			seekerController = characterBody.transform.GetComponent<SeekerController>();
			CacheLocalUser();
			overlapAttack = new OverlapAttack
			{
				attacker = characterBody.gameObject,
				damage = 0f,
				pushAwayForce = overlapForce,
				isCrit = characterBody.RollCrit(),
				damageColorIndex = DamageColorIndex.Item,
				inflictor = base.gameObject,
				procChainMask = default(ProcChainMask),
				procCoefficient = overlapProcCoefficient,
				teamIndex = characterBody.teamComponent.teamIndex,
				hitBoxGroup = base.gameObject.GetComponent<HitBoxGroup>(),
				hitEffectPrefab = overlapHitEffectPrefab,
				damageType = DamageType.Stun1s
			};
			startingSpeed = characterBody.moveSpeed + startingSpeedBoost;
			trueEndSpeed = endSpeedBodyInfluance * characterBody.moveSpeed + endSpeedTarget;
			currentSpeed = startingSpeed;
			vehicleRigidbody.velocity = aimDirection * currentSpeed;
		}

		[Server]
		private void DetonateServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SojournVehicle::DetonateServer()' called on client");
				return;
			}
			float num = blastRadius * blastRadiusCollisionMult;
			EffectData effectData = new EffectData
			{
				origin = base.transform.position,
				scale = num
			};
			EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true);
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = characterBody.gameObject;
			blastAttack.baseDamage = blastDamageCoefficient * characterBody.damage;
			blastAttack.baseForce = blastForce;
			blastAttack.bonusForce = blastBonusForce;
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.crit = characterBody.RollCrit();
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.damageType = blastDamageType;
			blastAttack.falloffModel = blastFalloffModel;
			blastAttack.inflictor = base.gameObject;
			blastAttack.position = base.transform.position;
			blastAttack.procChainMask = default(ProcChainMask);
			blastAttack.procCoefficient = blastProcCoefficient;
			blastAttack.radius = num;
			blastAttack.teamIndex = characterBody.teamComponent.teamIndex;
			blastAttack.Fire();
			Util.PlaySound(explosionSoundString, base.gameObject);
			seekerController.doesExitVehicle = true;
			CallRpcEndSojournState();
			UnityEngine.Object.Destroy(base.gameObject);
		}

		private void Update()
		{
			effectsToFlatten.transform.rotation = UnityEngine.Quaternion.identity;
		}

		private void FixedUpdate()
		{
			age += Time.fixedDeltaTime;
			if (NetworkServer.active)
			{
				FixedUpdateOverlayAttack();
				if (age > agePerTenthSecondsCheck)
				{
					FixedUpdatePerTenthSecond();
					agePerTenthSecondsCheck += increaseAgeCheck;
				}
			}
			FixedUpdateMovement();
			if (age > agePerSecond)
			{
				if (age > initialFlightGracePeriod)
				{
					blastForce += 25f;
					characterBody.AddBuff(DLC2Content.Buffs.SojournHealing);
					blastDamageCoefficient += dmgAddedPerSecond;
				}
				agePerSecond += 1f;
			}
			if (age > initialFlightGracePeriod)
			{
				float normalizedHealth = characterBody.healthComponent.GetNormalizedHealth();
				float b = Mathf.Lerp(trueEndSpeed, startingSpeed, normalizedHealth);
				float t = Mathf.Clamp01((age - initialFlightGracePeriod) / afterGraceLerpDownTime);
				currentSpeed = Mathf.LerpUnclamped(startingSpeed, b, t);
			}
			UpdateBlastRadius();
			if (localUser != null && vehicleSeat != null)
			{
				bool flag = localUser?.userProfile.toggleSeekerSojourn ?? true;
				bool? flag2 = vehicleSeat.currentPassengerInputBank?.skill3.down;
				if ((!flag && !flag2.Value) || (flag && flag2.Value && !skillKeyWasDown))
				{
					vehicleSeat.currentPassengerInputBank.skill3.hasPressBeenClaimed = true;
					vehicleSeat.CallCmdEjectPassenger();
				}
				skillKeyWasDown = vehicleSeat.currentPassengerInputBank?.skill3.down ?? false;
			}
			_ = effectGameObject.transform.position != hitBox.transform.position;
		}

		private void UpdateBlastRadius()
		{
			int buffCount = characterBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff);
			float t = Util.ConvertAmplificationPercentageIntoReductionNormalized(blastNonlinearGrowthRate * age);
			blastRadius = Mathf.Lerp(minBlastSize + perChakraAddMin * (float)buffCount, baseMaxBlastSize + perChakraAddMax * (float)buffCount, t);
			UnityEngine.Vector3 localScale = UnityEngine.Vector3.one * (blastRadius * blastRadiusIndicatorScale);
			GameObject[] array = blastRadiusIndicators;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].transform.localScale = localScale;
			}
		}

		[Server]
		private void FixedUpdateOverlayAttack()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SojournVehicle::FixedUpdateOverlayAttack()' called on client");
				return;
			}
			overlapFireAge += Time.fixedDeltaTime;
			overlapResetAge += Time.fixedDeltaTime;
			if (overlapFireAge > overlapFirePeriod)
			{
				overlapAttack.Fire();
				overlapFireAge = 0f;
			}
		}

		private void FixedUpdateMovement()
		{
			if (vehicleSeat.currentPassengerInputBank != null)
			{
				Ray aimRay = vehicleSeat.currentPassengerInputBank.GetAimRay();
				aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out var _);
				vehicleRigidbody.MoveRotation(UnityEngine.Quaternion.LookRotation(aimRay.direction));
				vehicleRigidbody.velocity = aimRay.direction * currentSpeed;
			}
		}

		[Server]
		private void FixedUpdatePerTenthSecond()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SojournVehicle::FixedUpdatePerTenthSecond()' called on client");
				return;
			}
			float damage = totalHealth * incrementalFlightDamage;
			DamageInfo damageInfo = new DamageInfo
			{
				damageType = DamageTypeExtended.SojournVehicleDamage,
				damage = damage,
				position = base.gameObject.transform.position
			};
			if (age > initialFlightGracePeriod)
			{
				if (characterBody.healthComponent.health < totalHealth * 0.15f)
				{
					vehicleSeat.CallCmdEjectPassenger();
				}
				else
				{
					characterBody.healthComponent.TakeDamage(damageInfo);
				}
			}
		}

		private void OnCollisionEnter(Collision collision)
		{
			if (detonateOnCollision && NetworkServer.active)
			{
				vehicleSeat.CallCmdEjectPassenger();
			}
		}

		public void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState)
		{
			cameraState.position = base.transform.position + base.transform.forward * cameraForward;
		}

		public bool IsUserLookAllowed(CameraRigController cameraRigController)
		{
			return true;
		}

		public bool IsUserControlAllowed(CameraRigController cameraRigController)
		{
			return true;
		}

		public bool IsHudAllowed(CameraRigController cameraRigController)
		{
			return true;
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcEndSojournState(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcEndSojournState called on server.");
			}
			else
			{
				((SojournVehicle)obj).RpcEndSojournState();
			}
		}

		public void CallRpcEndSojournState()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcEndSojournState called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcEndSojournState);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcEndSojournState");
		}

		static SojournVehicle()
		{
			kRpcRpcEndSojournState = -1858892214;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SojournVehicle), kRpcRpcEndSojournState, InvokeRpcRpcEndSojournState);
			NetworkCRC.RegisterBehaviour("SojournVehicle", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class SoulSpiralProjectile : MonoBehaviour
	{
		public static List<SoulSpiralProjectile> unassignedSoulSpirals = new List<SoulSpiralProjectile>();

		[SerializeField]
		[Header("Basic setup")]
		public UnityEngine.Vector3 offset;

		[SerializeField]
		public float initialDegreesFromOwnerForward;

		[SerializeField]
		public float degreesPerSecond;

		[SerializeField]
		public float radius;

		[SerializeField]
		public UnityEngine.Vector3 planeNormal = UnityEngine.Vector3.up;

		[SerializeField]
		public int hitStackPerBuff = 1;

		[SerializeField]
		[Tooltip("How much from 'baseline' can we move up or down during our sine wave")]
		public float verticalSineWaveOffset = 0.25f;

		[SerializeField]
		public float sineWavesPerSecond = 1.5f;

		[Space(20f)]
		[Header("Easing speeds")]
		[Tooltip("How long it takes the projectile to ease into its orbit from starting position.")]
		[SerializeField]
		public float easeInDuration;

		[Tooltip("How long it takes the projectile to transition from base speed to boosted speed")]
		[SerializeField]
		public float boostEaseDuration;

		[SerializeField]
		[Space(20f)]
		[Header("Boost variables")]
		[Tooltip("On the last hit, the projectile does more damage.")]
		public float lastHitDamageMultiplier;

		[SerializeField]
		[Tooltip("How long will the spiral spin after being boosted")]
		public float boostDuration;

		[SerializeField]
		[Tooltip("Coefficient for calculating Speed boost - multiplied against the # of boosts we have.")]
		public float speedBoostCoefficient;

		[Tooltip("How much should baseDamage be multipled by, if the speed is 100% faster than base.")]
		[SerializeField]
		public float damageMultiplier;

		[Tooltip("Triggered when the orbs are 'boosted'.")]
		[SerializeField]
		private UnityEvent OnOrbBoost;

		private SeekerSoulSpiralManager spiralManager;

		[HideInInspector]
		public ProjectileController projectileController;

		[HideInInspector]
		public ProjectileDamage projectileDamage;

		[HideInInspector]
		public ProjectileOverlapLimitHits projectileOverlapLimitHits;

		private SoulSpiralGhost _soulSpiralGhost;

		private Rigidbody rigidBody;

		private Transform ownerTransform;

		private float initialStartTimeStamp;

		private UnityEngine.Vector3 initialRadialDirection;

		private float prevDamage;

		private float baseDamage;

		private int baseHitLimit;

		private const float twoPi = MathF.PI * 2f;

		private SoulSpiralGhost soulSpiralGhost
		{
			get
			{
				if (_soulSpiralGhost == null)
				{
					if (projectileController == null || projectileController.ghost == null)
					{
						return null;
					}
					_soulSpiralGhost = projectileController.ghost.GetComponent<SoulSpiralGhost>();
				}
				return _soulSpiralGhost;
			}
			set
			{
				_soulSpiralGhost = value;
			}
		}

		private void OnEnable()
		{
			unassignedSoulSpirals.Add(this);
			spiralManager = null;
			projectileController = projectileController ?? GetComponent<ProjectileController>();
			rigidBody = rigidBody ?? GetComponent<Rigidbody>();
			projectileDamage = projectileDamage ?? GetComponent<ProjectileDamage>();
			projectileOverlapLimitHits = projectileOverlapLimitHits ?? GetComponent<ProjectileOverlapLimitHits>();
			baseHitLimit = (projectileOverlapLimitHits ? projectileOverlapLimitHits.hitLimit : 3);
			if (sineWavesPerSecond < 0f)
			{
				sineWavesPerSecond = Mathf.Abs(sineWavesPerSecond);
			}
			if (sineWavesPerSecond == 0f)
			{
				sineWavesPerSecond = 1f;
			}
		}

		private void OnDisable()
		{
			if (unassignedSoulSpirals.Contains(this))
			{
				unassignedSoulSpirals.Remove(this);
			}
		}

		public void AssignSpiralOwner(SeekerSoulSpiralManager _spiralManager)
		{
			spiralManager = _spiralManager;
			if (unassignedSoulSpirals.Contains(this))
			{
				unassignedSoulSpirals.Remove(this);
			}
			ownerTransform = _spiralManager.seekerBody.transform;
			SetDefaultVariables();
		}

		private void SetDefaultVariables()
		{
			if (hitStackPerBuff < 1)
			{
				hitStackPerBuff = 1;
			}
			projectileOverlapLimitHits.hitLimit = baseHitLimit + spiralManager.seekerBody.GetBuffCount(DLC2Content.Buffs.ChakraBuff.buffIndex) * hitStackPerBuff;
			initialStartTimeStamp = Time.fixedTime;
			initialRadialDirection = UnityEngine.Quaternion.AngleAxis(initialDegreesFromOwnerForward, planeNormal) * ownerTransform.forward;
			baseDamage = projectileDamage.damage;
			soulSpiralGhost = projectileController.ghost?.GetComponent<SoulSpiralGhost>();
		}

		public void OnLastHit()
		{
			soulSpiralGhost?.OnLastHit();
		}

		public void Boost()
		{
			soulSpiralGhost?.Boost();
		}

		public void EndBoost()
		{
			soulSpiralGhost?.EndBoost();
		}

		public void UpdateProjectile(float currentTime, float degreesRotated, float damageMultiplier, bool doBoost = false, bool doEndBoost = false)
		{
			if (!(ownerTransform == null))
			{
				if (doBoost)
				{
					OnOrbBoost?.Invoke();
					soulSpiralGhost?.Boost();
				}
				if (doEndBoost)
				{
					soulSpiralGhost?.EndBoost();
				}
				UnityEngine.Vector3 vector = ownerTransform.position + offset + UnityEngine.Quaternion.AngleAxis(degreesRotated, planeNormal) * initialRadialDirection * radius;
				float num = verticalSineWaveOffset;
				float num2 = (degreesRotated + initialDegreesFromOwnerForward) / degreesPerSecond;
				float num3 = Mathf.Cos(MathF.PI * 2f * num2 * sineWavesPerSecond);
				vector.y += num3 * num;
				if (currentTime - initialStartTimeStamp <= easeInDuration)
				{
					float num4 = currentTime - initialStartTimeStamp;
					vector = UnityEngine.Vector3.Lerp(base.transform.position, vector, num4 / easeInDuration);
				}
				if ((bool)rigidBody)
				{
					rigidBody.MovePosition(vector);
				}
				else
				{
					base.transform.position = vector;
				}
				float num5 = baseDamage * damageMultiplier;
				if (projectileOverlapLimitHits.IsLastHit())
				{
					num5 *= lastHitDamageMultiplier;
				}
				if (num5 != prevDamage)
				{
					projectileDamage.damage = num5;
					prevDamage = num5;
				}
			}
		}

		public void SetInitialDegreesFromOwnerForward(float degrees, int positionIndex)
		{
			initialDegreesFromOwnerForward = degrees;
			if ((bool)ownerTransform)
			{
				initialRadialDirection = UnityEngine.Quaternion.AngleAxis(initialDegreesFromOwnerForward, planeNormal) * ownerTransform.forward;
			}
		}

		public void DestroySpiral()
		{
			EffectManagerHelper component = GetComponent<EffectManagerHelper>();
			if ((bool)component && component.OwningPool != null)
			{
				component.OwningPool.ReturnObject(component);
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	public class SoulSpiralOrbiter
	{
		private float degreesRotated;

		public float easeInDuration;

		public float boostEaseDuration;

		public float boostDuration;

		public float speedBoostCoefficient;

		public float damageMultiplier;

		private int boostCount;

		private bool doBoost;

		private bool endBoost;

		private float baseDegreesPerSecond;

		private float targetAdditionalDegreesPerSecond;

		private float currentAdditionalDegreesPerSecond;

		private float baseProjectileDamage;

		private float currentDamageMultiplier;

		private float prevTimeStamp;

		private float deltaTime;

		private float boostChangedTimeStamp;

		private int length;

		private SeekerController seekerController;

		private SeekerSoulSpiralManager soulSpiralManager;

		public SoulSpiralOrbiter(SeekerController seekerController, SeekerSoulSpiralManager soulSpiralManager)
		{
			this.seekerController = seekerController;
			this.soulSpiralManager = soulSpiralManager;
			prevTimeStamp = Time.fixedTime;
			degreesRotated = 0f;
			baseProjectileDamage = 1f;
		}

		public void ResetValues(SoulSpiralProjectile soulSpiralInstance)
		{
			baseDegreesPerSecond = soulSpiralInstance.degreesPerSecond;
			boostEaseDuration = soulSpiralInstance.boostEaseDuration;
			boostDuration = soulSpiralInstance.boostDuration;
			damageMultiplier = soulSpiralInstance.damageMultiplier;
			easeInDuration = soulSpiralInstance.easeInDuration;
			speedBoostCoefficient = soulSpiralInstance.speedBoostCoefficient;
		}

		public void UpdateSpirals(ref SoulSpiralProjectile[] array)
		{
			length = array.Length;
			UpdateCurrentSpeedAndDamage(Time.fixedTime);
			for (int i = 0; i < length; i++)
			{
				if (!(array[i] == null))
				{
					array[i].UpdateProjectile(prevTimeStamp, degreesRotated, currentDamageMultiplier, doBoost, endBoost);
				}
			}
			doBoost = false;
			endBoost = false;
		}

		public void UpdateCurrentSpeedAndDamage(float _currentTime)
		{
			deltaTime = _currentTime - prevTimeStamp;
			float boostTime = _currentTime - boostChangedTimeStamp;
			HandleBoostExpiring(_currentTime, ref boostTime);
			float num = 1f;
			if (boostCount > 0)
			{
				targetAdditionalDegreesPerSecond = speedBoostCoefficient * (float)boostCount / (speedBoostCoefficient * (float)boostCount + 1f);
				targetAdditionalDegreesPerSecond *= baseDegreesPerSecond;
				num = (targetAdditionalDegreesPerSecond + baseDegreesPerSecond) / baseDegreesPerSecond;
			}
			else
			{
				targetAdditionalDegreesPerSecond = 0f;
			}
			currentAdditionalDegreesPerSecond = Mathf.Lerp(currentAdditionalDegreesPerSecond, targetAdditionalDegreesPerSecond, boostTime / boostEaseDuration);
			degreesRotated += deltaTime * (baseDegreesPerSecond + currentAdditionalDegreesPerSecond);
			currentDamageMultiplier = baseProjectileDamage + (num - 1f) * damageMultiplier * baseProjectileDamage;
			prevTimeStamp = _currentTime;
		}

		private void HandleBoostExpiring(float stopWatchTime, ref float boostTime)
		{
			if (boostCount != 0 && boostTime > boostDuration)
			{
				boostCount = 0;
				boostChangedTimeStamp = stopWatchTime;
				boostTime = 0f;
				endBoost = true;
				soulSpiralManager.EndBoostFX();
				seekerController.SpiralSendCommand(SeekerSoulSpiralManager.SoulSpiralCommandType.EndBoost);
			}
		}

		public void BoostAuthority()
		{
			boostCount++;
			boostChangedTimeStamp = Time.fixedTime;
			doBoost = true;
			seekerController.SpiralSendCommand(SeekerSoulSpiralManager.SoulSpiralCommandType.Boost);
		}
	}
	[RequireComponent(typeof(BezierCurveLine))]
	public class JailerTetherController : NetworkBehaviour
	{
		[SyncVar]
		public GameObject targetRoot;

		[SyncVar]
		public GameObject ownerRoot;

		[SyncVar]
		public GameObject origin;

		[SyncVar]
		public float reelSpeed = 12f;

		[NonSerialized]
		public float breakDistanceSqr;

		[NonSerialized]
		public float damageCoefficientPerTick;

		[NonSerialized]
		public float tickInterval;

		[NonSerialized]
		public float tickTimer;

		public float attachTime;

		private float fixedAge;

		private float age;

		private bool beginSiphon;

		private BezierCurveLine bezierCurveLine;

		private HealthComponent targetHealthComponent;

		private CharacterBody ownerBody;

		private CharacterBody targetBody;

		private BuffDef tetheredBuff;

		private NetworkInstanceId ___targetRootNetId;

		private NetworkInstanceId ___ownerRootNetId;

		private NetworkInstanceId ___originNetId;

		public GameObject NetworktargetRoot
		{
			get
			{
				return targetRoot;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref targetRoot, 1u, ref ___targetRootNetId);
			}
		}

		public GameObject NetworkownerRoot
		{
			get
			{
				return ownerRoot;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref ownerRoot, 2u, ref ___ownerRootNetId);
			}
		}

		public GameObject Networkorigin
		{
			get
			{
				return origin;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref origin, 4u, ref ___originNetId);
			}
		}

		public float NetworkreelSpeed
		{
			get
			{
				return reelSpeed;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref reelSpeed, 8u);
			}
		}

		private void Awake()
		{
			bezierCurveLine = GetComponent<BezierCurveLine>();
		}

		private void Start()
		{
			if (!targetHealthComponent)
			{
				targetHealthComponent = targetRoot.GetComponent<HealthComponent>();
			}
			if (!ownerBody)
			{
				ownerBody = ownerRoot.GetComponent<CharacterBody>();
			}
			Networkorigin = ((origin != null) ? origin : ownerRoot);
		}

		private void LateUpdate()
		{
			age += Time.deltaTime;
			UnityEngine.Vector3 position = origin.transform.position;
			if (!beginSiphon)
			{
				UnityEngine.Vector3 position2 = UnityEngine.Vector3.Lerp(position, GetTargetRootPosition(), age / attachTime);
				bezierCurveLine.endTransform.position = position2;
			}
			else if ((bool)targetRoot)
			{
				bezierCurveLine.endTransform.position = targetRoot.transform.position;
			}
		}

		private void FixedUpdate()
		{
			fixedAge += Time.fixedDeltaTime;
			if ((bool)targetRoot && (bool)ownerRoot)
			{
				UnityEngine.Vector3 targetRootPosition = GetTargetRootPosition();
				if (!beginSiphon && fixedAge >= attachTime)
				{
					beginSiphon = true;
					return;
				}
				UnityEngine.Vector3 vector = origin.transform.position - targetRootPosition;
				if (NetworkServer.active)
				{
					float sqrMagnitude = vector.sqrMagnitude;
					tickTimer -= Time.fixedDeltaTime;
					if (tickTimer <= 0f)
					{
						tickTimer += tickInterval;
						DoDamageTick();
					}
					if (sqrMagnitude > breakDistanceSqr)
					{
						UnityEngine.Object.Destroy(base.gameObject);
						return;
					}
				}
				if (!Util.HasEffectiveAuthority(targetRoot))
				{
					return;
				}
				UnityEngine.Vector3 vector2 = reelSpeed * Time.fixedDeltaTime * vector.normalized;
				CharacterMotor component = targetRoot.GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					component.rootMotion += vector2;
					return;
				}
				Rigidbody component2 = targetRoot.GetComponent<Rigidbody>();
				if ((bool)component2)
				{
					component2.velocity += vector2;
				}
			}
			else if (NetworkServer.active)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void DoDamageTick()
		{
			DamageInfo damageInfo = new DamageInfo
			{
				position = targetRoot.transform.position,
				attacker = null,
				inflictor = null,
				damage = damageCoefficientPerTick * ownerBody.damage,
				damageColorIndex = DamageColorIndex.Default,
				damageType = DamageType.Generic,
				crit = false,
				force = UnityEngine.Vector3.zero,
				procChainMask = default(ProcChainMask),
				procCoefficient = 0f
			};
			targetHealthComponent.TakeDamage(damageInfo);
			if (!targetHealthComponent.alive)
			{
				NetworktargetRoot = null;
			}
		}

		public override void OnNetworkDestroy()
		{
			if (NetworkServer.active)
			{
				RemoveBuff();
			}
			base.OnNetworkDestroy();
		}

		private void RemoveBuff()
		{
			if ((bool)tetheredBuff && (bool)targetBody)
			{
				targetBody.RemoveBuff(tetheredBuff);
			}
		}

		public CharacterBody GetTargetBody()
		{
			if ((bool)targetBody)
			{
				return targetBody;
			}
			if ((bool)targetRoot)
			{
				targetBody = targetRoot.GetComponent<CharacterBody>();
				return targetBody;
			}
			return null;
		}

		private UnityEngine.Vector3 GetTargetRootPosition()
		{
			if ((bool)targetRoot)
			{
				UnityEngine.Vector3 result = targetRoot.transform.position;
				if ((bool)targetHealthComponent)
				{
					result = targetHealthComponent.body.corePosition;
				}
				return result;
			}
			return base.transform.position;
		}

		public void SetTetheredBuff(BuffDef buffDef)
		{
			if (buffDef != null)
			{
				CharacterBody characterBody = GetTargetBody();
				if ((bool)characterBody)
				{
					tetheredBuff = buffDef;
					characterBody.AddBuff(tetheredBuff);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(targetRoot);
				writer.Write(ownerRoot);
				writer.Write(origin);
				writer.Write(reelSpeed);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(targetRoot);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(ownerRoot);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(origin);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(reelSpeed);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___targetRootNetId = reader.ReadNetworkId();
				___ownerRootNetId = reader.ReadNetworkId();
				___originNetId = reader.ReadNetworkId();
				reelSpeed = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				targetRoot = reader.ReadGameObject();
			}
			if (((uint)num & 2u) != 0)
			{
				ownerRoot = reader.ReadGameObject();
			}
			if (((uint)num & 4u) != 0)
			{
				origin = reader.ReadGameObject();
			}
			if (((uint)num & 8u) != 0)
			{
				reelSpeed = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
			if (!___targetRootNetId.IsEmpty())
			{
				NetworktargetRoot = ClientScene.FindLocalObject(___targetRootNetId);
			}
			if (!___ownerRootNetId.IsEmpty())
			{
				NetworkownerRoot = ClientScene.FindLocalObject(___ownerRootNetId);
			}
			if (!___originNetId.IsEmpty())
			{
				Networkorigin = ClientScene.FindLocalObject(___originNetId);
			}
		}
	}
	public class EnumMaskAttribute : PropertyAttribute
	{
		public Type enumType;

		public EnumMaskAttribute(Type enumType)
		{
			this.enumType = enumType;
		}
	}
	public static class EOSLobbyDataGenerator
	{
		private static class ToStringCache
		{
			public static MemoizedToString<PlatformID, ToStringDefault<PlatformID>> serverId;

			public static MemoizedToString<AddressPortPair, ToStringDefault<AddressPortPair>> serverAddress;

			public static MemoizedToString<int, ToStringImplementationInvariant> playerCount;

			public static MemoizedToString<int, ToStringImplementationInvariant> edition;

			public static MemoizedToString<int, ToStringImplementationInvariant> serverMaxPlayers;

			public static MemoizedToString<int, ToStringImplementationInvariant> serverPlayerCount;
		}

		private const int k_cubChatMetadataMax = 8192;

		private const int k_nMaxLobbyKeyLength = 255;

		private static string lobbyId;

		private static int edition;

		private static RuleBook cachedRuleBook;

		private static bool dirty = false;

		private static readonly string[] specialKeys = new string[9] { "joinable", "name", "appid", "lobbytype", "total_max_players", "v", "qp_cutoff_time", "qp", "starting" };

		private static readonly List<KeyValuePair<string, string>> ruleBookKeyValues = new List<KeyValuePair<string, string>>(1);

		private static readonly KeyValueSplitter ruleBookKeyValueSplitter = new KeyValueSplitter("rulebook", 255, 8192, SetRuleBookKeyValue);

		public static event Action<List<KeyValuePair<string, string>>> getAdditionalKeyValues;

		[SystemInitializer(new Type[] { typeof(RuleBook) })]
		private static void Init()
		{
			cachedRuleBook = new RuleBook();
			if (PlatformSystems.EgsToggleConVar.value == 1)
			{
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onLobbyOwnershipGained = (Action)Delegate.Combine(lobbyManager.onLobbyOwnershipGained, new Action(OnLobbyOwnershipGained));
				LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
				lobbyManager2.onLobbyOwnershipLost = (Action)Delegate.Combine(lobbyManager2.onLobbyOwnershipLost, new Action(OnLobbyOwnershipLost));
			}
		}

		private static void OnLobbyOwnershipGained()
		{
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			lobbyId = obj.CurrentLobbyId;
			edition = 0;
			LobbyDetails currentLobbyDetails = obj.CurrentLobbyDetails;
			LobbyDetailsCopyAttributeByKeyOptions options = new LobbyDetailsCopyAttributeByKeyOptions
			{
				AttrKey = "v"
			};
			if (currentLobbyDetails.CopyAttributeByKey(ref options, out var outAttribute) == Result.Success)
			{
				int.TryParse(outAttribute.Value.Data.ToString(), out edition);
			}
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyMemberDataUpdated = (Action<PlatformID>)Delegate.Combine(lobbyManager.onLobbyMemberDataUpdated, new Action<PlatformID>(EOSLobbyManagerOnOnLobbyMemberDataUpdated));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyStateChanged = (Action)Delegate.Combine(lobbyManager2.onLobbyStateChanged, new Action(EOSLobbyManagerOnOnLobbyStateChanged));
			NetworkManagerSystem.onStartClientGlobal += NetworkManagerSystemOnOnStartClientGlobal;
			NetworkManagerSystem.onStopClientGlobal += NetworkManagerSystemOnOnStopClientGlobal;
			SceneCatalog.onMostRecentSceneDefChanged += SceneCatalogOnOnMostRecentSceneDefChanged;
			NetworkUser.onNetworkUserDiscovered += NetworkUserOnOnNetworkUserDiscovered;
			NetworkUser.onNetworkUserLost += NetworkUserOnOnNetworkUserLost;
			PreGameController.onPreGameControllerSetRuleBookGlobal += OnPreGameControllerSetRuleBook;
			Run.onRunSetRuleBookGlobal += OnRunSetRuleBook;
			UpdateRuleBook();
			RebuildLobbyData();
		}

		private static void OnLobbyOwnershipLost()
		{
			lobbyId = string.Empty;
			edition = 0;
			Run.onRunSetRuleBookGlobal -= OnRunSetRuleBook;
			PreGameController.onPreGameControllerSetRuleBookGlobal -= OnPreGameControllerSetRuleBook;
			NetworkUser.onNetworkUserLost -= NetworkUserOnOnNetworkUserLost;
			NetworkUser.onNetworkUserDiscovered -= NetworkUserOnOnNetworkUserDiscovered;
			SceneCatalog.onMostRecentSceneDefChanged -= SceneCatalogOnOnMostRecentSceneDefChanged;
			NetworkManagerSystem.onStopClientGlobal -= NetworkManagerSystemOnOnStopClientGlobal;
			NetworkManagerSystem.onStartClientGlobal -= NetworkManagerSystemOnOnStartClientGlobal;
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyMemberDataUpdated = (Action<PlatformID>)Delegate.Remove(lobbyManager.onLobbyMemberDataUpdated, new Action<PlatformID>(EOSLobbyManagerOnOnLobbyMemberDataUpdated));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyStateChanged = (Action)Delegate.Remove(lobbyManager2.onLobbyStateChanged, new Action(EOSLobbyManagerOnOnLobbyStateChanged));
		}

		private static void OnPreGameControllerSetRuleBook(PreGameController run, RuleBook ruleBook)
		{
			UpdateRuleBook();
		}

		private static void OnRunSetRuleBook(Run run, RuleBook ruleBook)
		{
			UpdateRuleBook();
		}

		private static void EOSLobbyManagerOnOnLobbyMemberDataUpdated(PlatformID memberId)
		{
			SetDirty();
		}

		private static void EOSLobbyManagerOnOnLobbyStateChanged()
		{
			SetDirty();
		}

		private static void NetworkManagerSystemOnOnStartClientGlobal(NetworkClient networkClient)
		{
			SetDirty();
		}

		private static void NetworkManagerSystemOnOnStopClientGlobal()
		{
			SetDirty();
		}

		private static void SceneCatalogOnOnMostRecentSceneDefChanged(SceneDef sceneDef)
		{
			SetDirty();
		}

		private static void NetworkUserOnOnNetworkUserDiscovered(NetworkUser networkUser)
		{
			SetDirty();
		}

		private static void NetworkUserOnOnNetworkUserLost(NetworkUser networkUser)
		{
			SetDirty();
		}

		public static void SetDirty()
		{
			if (!dirty)
			{
				dirty = true;
				RoR2Application.onNextUpdate += RebuildLobbyData;
			}
		}

		public static void RebuildLobbyData()
		{
			try
			{
				dirty = false;
				LobbyDetails currentLobbyDetails = (PlatformSystems.lobbyManager as EOSLobbyManager).CurrentLobbyDetails;
				if (currentLobbyDetails == null)
				{
					return;
				}
				LobbyDetails lobbyDetails = currentLobbyDetails;
				Dictionary<string, string> KVPs = CollectionPool<KeyValuePair<string, string>, Dictionary<string, string>>.RentCollection();
				EOSLobbyManager.GetAllCurrentLobbyKVPs(currentLobbyDetails, ref KVPs);
				if (!EOSLobbyManager.IsLobbyOwner(currentLobbyDetails) || KVPs == null || lobbyDetails == null)
				{
					CollectionPool<KeyValuePair<string, string>, Dictionary<string, string>>.ReturnCollection(KVPs);
					return;
				}
				LobbyModification currentLobbyModification = (PlatformSystems.lobbyManager as EOSLobbyManager).CurrentLobbyModification;
				string value2 = null;
				KVPs.TryGetValue("total_max_players", out value2);
				if (value2 == null || !int.TryParse(value2, out var result))
				{
					result = LobbyManager.cvSteamLobbyMaxMembers.value;
					EOSLobbyManager.SetLobbyStringValue(currentLobbyModification, "total_max_players", result.ToString());
				}
				int num = result - PlatformSystems.lobbyManager.calculatedExtraPlayersCount;
				LobbyDetailsGetMemberCountOptions options = default(LobbyDetailsGetMemberCountOptions);
				currentLobbyDetails.GetMemberCount(ref options);
				_ = num;
				Dictionary<string, string> newData = CollectionPool<KeyValuePair<string, string>, Dictionary<string, string>>.RentCollection();
				List<KeyValuePair<string, string>> list = CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.RentCollection();
				EOSLobbyDataGenerator.getAdditionalKeyValues?.Invoke(list);
				for (int i = 0; i < list.Count; i++)
				{
					KeyValuePair<string, string> keyValuePair = list[i];
					AddData(keyValuePair.Key, keyValuePair.Value);
				}
				CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.ReturnCollection(list);
				AddData("build_id", RoR2Application.GetBuildId());
				AddData("_mh", NetworkModCompatibilityHelper.networkModHash);
				int input = PlatformSystems.lobbyManager.calculatedTotalPlayerCount;
				AddData("player_count", ToStringCache.playerCount.GetString(in input));
				string value3 = SceneCatalog.GetSceneDefForCurrentScene()?.baseSceneName;
				if (!string.IsNullOrEmpty(value3))
				{
					AddData("_map", value3);
				}
				GetServerInfo(out var serverId, out var serverAddress, out var isSelf);
				bool flag = false;
				bool num2 = KVPs?.ContainsKey("server_id") ?? false;
				bool flag2 = KVPs?.ContainsKey("server_address") ?? false;
				bool flag3 = num2 || flag2;
				bool flag4 = false;
				if ((bool)NetworkSession.instance)
				{
					flag = NetworkSession.instance.HasFlag(NetworkSession.Flags.HasPassword);
					AddData("_ds", NetworkSession.instance.HasFlag(NetworkSession.Flags.IsDedicatedServer) ? "1" : "0");
					AddData("_pw", flag ? "1" : "0");
					AddData("_svtags", (NetworkSession.instance.tagsString != null) ? NetworkSession.instance.tagsString : "");
					input = (int)NetworkSession.instance.maxPlayers;
					AddData("_svmpl", ToStringCache.serverMaxPlayers.GetString(in input));
					input = NetworkUser.readOnlyInstancesList.Count;
					AddData("_svplc", ToStringCache.serverPlayerCount.GetString(in input));
					AddData("_svnm", NetworkSession.instance.serverName);
					if (serverId != null)
					{
						AddData("server_id", serverId.ToString());
						flag4 = true;
					}
					if (serverAddress.isValid)
					{
						AddData("server_address", ToStringCache.serverAddress.GetString(in serverAddress));
						flag4 = true;
					}
				}
				GameModeIndex gameModeIndex = GameModeIndex.Invalid;
				if ((bool)Run.instance)
				{
					gameModeIndex = Run.instance.gameModeIndex;
				}
				else if ((bool)PreGameController.instance)
				{
					gameModeIndex = PreGameController.instance.gameModeIndex;
				}
				if (gameModeIndex != GameModeIndex.Invalid)
				{
					string gameModeName = GameModeCatalog.GetGameModeName(gameModeIndex);
					AddData("_svgm", gameModeName);
				}
				if (flag4 && !flag3 && flag)
				{
					string value4 = (isSelf ? NetworkManagerSystem.SvPasswordConVar.instance.value : NetworkManagerSystem.cvClPassword.value);
					NetworkWriter networkWriter = new NetworkWriter();
					networkWriter.Write(value4);
					(PlatformSystems.lobbyManager as EOSLobbyManager).SendLobbyMessage(LobbyManager.LobbyMessageType.Password, networkWriter);
				}
				for (int j = 0; j < ruleBookKeyValues.Count; j++)
				{
					KeyValuePair<string, string> keyValuePair2 = ruleBookKeyValues[j];
					AddData(keyValuePair2.Key, keyValuePair2.Value);
				}
				for (int k = 0; k < specialKeys.Length; k++)
				{
					KVPs.Remove(specialKeys[k]);
				}
				bool flag5 = false;
				List<string> list2 = CollectionPool<string, List<string>>.RentCollection();
				if (KVPs != null)
				{
					foreach (KeyValuePair<string, string> item in KVPs)
					{
						if (!newData.ContainsKey(item.Key))
						{
							list2.Add(item.Key);
						}
					}
				}
				for (int l = 0; l < list2.Count; l++)
				{
					EOSLobbyManager.RemoveLobbyStringValue(currentLobbyModification, list2[l]);
				}
				if (list2.Count > 0)
				{
					flag5 = true;
				}
				CollectionPool<string, List<string>>.ReturnCollection(list2);
				foreach (KeyValuePair<string, string> item2 in newData)
				{
					string value5 = null;
					if (KVPs == null || !KVPs.TryGetValue(item2.Key, out value5) || !item2.Value.Equals(value5, StringComparison.Ordinal))
					{
						EOSLobbyManager.SetLobbyStringValue(currentLobbyModification, item2.Key, item2.Value);
						flag5 = true;
					}
				}
				if (flag5)
				{
					edition++;
				}
				EOSLobbyManager.SetLobbyStringValue(currentLobbyModification, "v", ToStringCache.edition.GetString(in edition));
				EOSLobbyManager.UpdateLobby(currentLobbyModification);
				CollectionPool<KeyValuePair<string, string>, Dictionary<string, string>>.ReturnCollection(newData);
				CollectionPool<KeyValuePair<string, string>, Dictionary<string, string>>.ReturnCollection(KVPs);
				void AddData(string key, string value)
				{
					newData.Add(key, (value != null) ? value : "");
				}
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private static void GetServerInfo(out ProductUserId serverId, out AddressPortPair serverAddress, out bool isSelf)
		{
			serverId = new ProductUserId();
			serverAddress = default(AddressPortPair);
			isSelf = false;
			HostDescription desiredHost = NetworkManagerSystem.singleton.desiredHost;
			if (desiredHost.hostType == HostDescription.HostType.None)
			{
				return;
			}
			if (desiredHost.hostType == HostDescription.HostType.Self)
			{
				if (NetworkServer.active)
				{
					serverId = NetworkManagerSystem.singleton.serverP2PId.productUserID;
					isSelf = true;
				}
			}
			else if (desiredHost.hostType == HostDescription.HostType.Steam)
			{
				serverId = desiredHost.userID.productUserID;
			}
			else if (desiredHost.hostType == HostDescription.HostType.IPv4)
			{
				serverAddress = desiredHost.addressPortPair;
			}
		}

		private static void UpdateRuleBook()
		{
			RuleBook ruleBook = null;
			if ((bool)Run.instance)
			{
				ruleBook = Run.instance.ruleBook;
			}
			else if ((bool)PreGameController.instance)
			{
				ruleBook = PreGameController.instance.readOnlyRuleBook;
			}
			if (ruleBook != null && !ruleBook.Equals(cachedRuleBook))
			{
				cachedRuleBook.Copy(ruleBook);
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				RuleBook.WriteBase64ToStringBuilder(cachedRuleBook, stringBuilder);
				ruleBookKeyValueSplitter.SetValue(stringBuilder);
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			}
			else
			{
				cachedRuleBook.SetToDefaults();
			}
		}

		private static void SetRuleBookKeyValue(string key, string value)
		{
			int num = -1;
			for (int i = 0; i < ruleBookKeyValues.Count; i++)
			{
				if (ruleBookKeyValues[i].Key.Equals(key, StringComparison.Ordinal))
				{
					if (ruleBookKeyValues[i].Value.Equals(value, StringComparison.Ordinal))
					{
						return;
					}
					num = i;
					break;
				}
			}
			if (value == null)
			{
				if (num != -1)
				{
					ruleBookKeyValues.RemoveAt(num);
				}
			}
			else
			{
				KeyValuePair<string, string> keyValuePair = new KeyValuePair<string, string>(key, value);
				if (num != -1)
				{
					ruleBookKeyValues[num] = keyValuePair;
				}
				else
				{
					ruleBookKeyValues.Add(keyValuePair);
				}
			}
			SetDirty();
		}

		[ConCommand(commandName = "steam_lobby_data_regenerate", flags = ConVarFlags.None, helpText = "Forces the current lobby data to be regenerated.")]
		public static void CCSteamLobbyRegenerateData(ConCommandArgs args)
		{
			SetDirty();
		}
	}
	public enum EquipmentIndex
	{
		None = -1
	}
	[Serializable]
	public class EquipmentMask : ICollection<EquipmentIndex>, IEnumerable<EquipmentIndex>, IEnumerable
	{
		public struct Enumerator : IEnumerator<EquipmentIndex>, IEnumerator, IDisposable
		{
			private bool[] target;

			public EquipmentIndex Current { get; private set; }

			object IEnumerator.Current => Current;

			public Enumerator(bool[] array)
			{
				Current = EquipmentIndex.None;
				target = array;
			}

			public bool MoveNext()
			{
				EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount;
				while (Current < equipmentCount)
				{
					if (target[(int)Current])
					{
						return true;
					}
					EquipmentIndex current = Current + 1;
					Current = current;
				}
				return false;
			}

			public void Reset()
			{
				Current = EquipmentIndex.None;
			}

			public void Dispose()
			{
			}
		}

		private readonly bool[] array;

		public int Count => array.Length;

		public bool IsReadOnly => false;

		public EquipmentMask()
		{
			array = new bool[EquipmentCatalog.equipmentCount];
		}

		public static EquipmentMask Rent()
		{
			return CollectionPool<EquipmentIndex, EquipmentMask>.RentCollection();
		}

		public static void Return(EquipmentMask equipmentMask)
		{
			if (equipmentMask.array.Length == EquipmentCatalog.equipmentCount)
			{
				CollectionPool<EquipmentIndex, EquipmentMask>.ReturnCollection(equipmentMask);
			}
		}

		public bool Contains(EquipmentIndex equipmentIndex)
		{
			bool[] obj = array;
			bool defaultValue = false;
			return ArrayUtils.GetSafe(obj, (int)equipmentIndex, in defaultValue);
		}

		public void Add(EquipmentIndex equipmentIndex)
		{
			if (ArrayUtils.IsInBounds(array, (int)equipmentIndex))
			{
				array[(int)equipmentIndex] = true;
			}
		}

		public bool Remove(EquipmentIndex equipmentIndex)
		{
			if (ArrayUtils.IsInBounds(array, (int)equipmentIndex))
			{
				ref bool reference = ref array[(int)equipmentIndex];
				bool result = reference;
				reference = false;
				return result;
			}
			return false;
		}

		public void Clear()
		{
			bool[] obj = array;
			bool value = false;
			ArrayUtils.SetAll(obj, in value);
		}

		public void CopyTo(EquipmentIndex[] array, int arrayIndex)
		{
			for (int i = 0; i < this.array.Length; i++)
			{
				if (this.array[i])
				{
					array[arrayIndex++] = (EquipmentIndex)i;
				}
			}
		}

		public Enumerator GetEnumerator()
		{
			return new Enumerator(array);
		}

		IEnumerator<EquipmentIndex> IEnumerable<EquipmentIndex>.GetEnumerator()
		{
			return GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	public static class EquipmentCatalog
	{
		public struct AllEquipmentEnumerator : IEnumerator<EquipmentIndex>, IEnumerator, IDisposable
		{
			private EquipmentIndex position;

			public EquipmentIndex Current => position;

			object IEnumerator.Current => Current;

			public bool MoveNext()
			{
				position++;
				return (int)position < equipmentCount;
			}

			public void Reset()
			{
				position = EquipmentIndex.None;
			}

			void IDisposable.Dispose()
			{
			}
		}

		private static EquipmentDef[] equipmentDefs = Array.Empty<EquipmentDef>();

		public static List<EquipmentIndex> equipmentList = new List<EquipmentIndex>();

		public static List<EquipmentIndex> enigmaEquipmentList = new List<EquipmentIndex>();

		public static List<EquipmentIndex> randomTriggerEquipmentList = new List<EquipmentIndex>();

		private static readonly Dictionary<string, EquipmentIndex> equipmentNameToIndex = new Dictionary<string, EquipmentIndex>();

		public static ResourceAvailability availability = default(ResourceAvailability);

		public static readonly GenericStaticEnumerable<EquipmentIndex, AllEquipmentEnumerator> allEquipment;

		public static int equipmentCount => equipmentDefs.Length;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<EquipmentDef>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.EquipmentCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.equipmentDefs);
			}
			remove
			{
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetEquipmentDefs(ContentManager.equipmentDefs);
			availability.MakeAvailable();
		}

		private static void SetEquipmentDefs(EquipmentDef[] newEquipmentDefs)
		{
			EquipmentDef[] array = equipmentDefs;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].equipmentIndex = EquipmentIndex.None;
			}
			equipmentNameToIndex.Clear();
			equipmentList.Clear();
			enigmaEquipmentList.Clear();
			randomTriggerEquipmentList.Clear();
			ArrayUtils.CloneTo(newEquipmentDefs, ref equipmentDefs);
			Array.Sort(equipmentDefs, (EquipmentDef a, EquipmentDef b) => string.CompareOrdinal(a.name, b.name));
			for (EquipmentIndex equipmentIndex = (EquipmentIndex)0; (int)equipmentIndex < equipmentDefs.Length; equipmentIndex++)
			{
				RegisterEquipment(equipmentIndex, equipmentDefs[(int)equipmentIndex]);
			}
		}

		private static void RegisterEquipment(EquipmentIndex equipmentIndex, EquipmentDef equipmentDef)
		{
			equipmentDef.equipmentIndex = equipmentIndex;
			if (equipmentDef.canDrop)
			{
				equipmentList.Add(equipmentIndex);
				if (equipmentDef.enigmaCompatible)
				{
					enigmaEquipmentList.Add(equipmentIndex);
				}
				if (equipmentDef.canBeRandomlyTriggered)
				{
					randomTriggerEquipmentList.Add(equipmentIndex);
				}
			}
			string name = equipmentDef.name;
			equipmentNameToIndex[name] = equipmentIndex;
		}

		public static EquipmentDef GetEquipmentDef(EquipmentIndex equipmentIndex)
		{
			return ArrayUtils.GetSafe(equipmentDefs, (int)equipmentIndex);
		}

		public static EquipmentIndex FindEquipmentIndex(string equipmentName)
		{
			if (equipmentNameToIndex.TryGetValue(equipmentName, out var value))
			{
				return value;
			}
			return EquipmentIndex.None;
		}

		public static T[] GetPerEquipmentBuffer<T>()
		{
			return new T[equipmentCount];
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsIndexValid(in EquipmentIndex equipmentIndex)
		{
			return (uint)equipmentIndex < (uint)equipmentCount;
		}

		[ConCommand(commandName = "equipment_list", flags = ConVarFlags.None, helpText = "Lists internal names of all equipment registered to the equipment catalog.")]
		private static void CCEquipmentList(ConCommandArgs args)
		{
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			EquipmentDef[] array = equipmentDefs;
			foreach (EquipmentDef equipmentDef in array)
			{
				stringBuilder.AppendLine(equipmentDef.name + "  (" + Language.GetString(equipmentDef.nameToken) + ")");
			}
			args.Log(stringBuilder.ToString());
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/DropTables/ExplicitPickupDropTable")]
	public class ExplicitPickupDropTable : PickupDropTable
	{
		[Serializable]
		public struct StringEntry
		{
			public string pickupName;

			public float pickupWeight;
		}

		[Serializable]
		public struct PickupDefEntry
		{
			[TypeRestrictedReference(new Type[]
			{
				typeof(ItemDef),
				typeof(EquipmentDef),
				typeof(MiscPickupDef)
			})]
			public UnityEngine.Object pickupDef;

			public float pickupWeight;
		}

		public PickupDefEntry[] pickupEntries = Array.Empty<PickupDefEntry>();

		[Header("Deprecated")]
		[Obsolete("Use pickupEntries instead.", false)]
		public StringEntry[] entries = Array.Empty<StringEntry>();

		private readonly WeightedSelection<PickupIndex> weightedSelection = new WeightedSelection<PickupIndex>();

		protected override void Regenerate(Run run)
		{
			GenerateWeightedSelection();
		}

		private void GenerateWeightedSelection()
		{
			weightedSelection.Clear();
			StringEntry[] array = entries;
			for (int i = 0; i < array.Length; i++)
			{
				StringEntry stringEntry = array[i];
				weightedSelection.AddChoice(PickupCatalog.FindPickupIndex(stringEntry.pickupName), stringEntry.pickupWeight);
			}
			PickupDefEntry[] array2 = pickupEntries;
			for (int i = 0; i < array2.Length; i++)
			{
				PickupDefEntry pickupDefEntry = array2[i];
				PickupIndex pickupIndex = PickupIndex.none;
				UnityEngine.Object pickupDef = pickupDefEntry.pickupDef;
				if (!(pickupDef is ItemDef itemDef))
				{
					if (pickupDef is EquipmentDef equipmentDef)
					{
						pickupIndex = PickupCatalog.FindPickupIndex(equipmentDef.equipmentIndex);
					}
					else
					{
						MiscPickupDef miscPickupDef = pickupDefEntry.pickupDef as MiscPickupDef;
						if (miscPickupDef != null)
						{
							pickupIndex = PickupCatalog.FindPickupIndex(miscPickupDef.miscPickupIndex);
						}
					}
				}
				else
				{
					pickupIndex = PickupCatalog.FindPickupIndex(itemDef.itemIndex);
				}
				if (pickupIndex != PickupIndex.none)
				{
					weightedSelection.AddChoice(pickupIndex, pickupDefEntry.pickupWeight);
				}
			}
		}

		protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateDropFromWeightedSelection(rng, weightedSelection);
		}

		public override int GetPickupCount()
		{
			return weightedSelection.Count;
		}

		protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, weightedSelection);
		}
	}
	public static class FadeToBlackManager
	{
		private static UnityEngine.UI.Image image;

		public static int fadeCount;

		private static float alpha;

		public static bool fadePaused;

		private const float fadeDuration = 0.25f;

		private const float inversefadeDuration = 4f;

		public static bool fullyFaded => alpha == 2f;

		[InitDuringStartup]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback<GameObject>("Prefabs/UI/ScreenTintCanvas", InitCanvas);
			static void InitCanvas(GameObject prefab)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(prefab, RoR2Application.instance.mainCanvas.transform);
				alpha = 0f;
				image = gameObject.transform.GetChild(0).GetComponent<UnityEngine.UI.Image>();
				UpdateImageAlpha(alpha);
				RoR2Application.onUpdate += Update;
				SceneManager.sceneUnloaded += OnSceneUnloaded;
			}
		}

		public static void OnSceneUnloaded(Scene scene)
		{
			ForceFullBlack();
		}

		public static void ForceFullBlack()
		{
			alpha = 2f;
		}

		private static void Update()
		{
			if (!fadePaused)
			{
				float target = 2f;
				float num = 4f;
				if (fadeCount <= 0)
				{
					target = 0f;
					num *= 0.25f;
				}
				alpha = Mathf.MoveTowards(alpha, target, Time.unscaledDeltaTime * num);
				float num2 = 0f;
				List<FadeToBlackOffset> instancesList = InstanceTracker.GetInstancesList<FadeToBlackOffset>();
				for (int i = 0; i < instancesList.Count; i++)
				{
					FadeToBlackOffset fadeToBlackOffset = instancesList[i];
					num2 += fadeToBlackOffset.value;
				}
				UpdateImageAlpha(alpha + num2);
			}
		}

		private static void UpdateImageAlpha(float finalAlpha)
		{
			UnityEngine.Color color = image.color;
			UnityEngine.Color color2 = color;
			color2.a = finalAlpha;
			image.color = color2;
			image.raycastTarget = color2.a > color.a;
		}

		public static void ForceClear()
		{
			fadeCount = 0;
			alpha = 0f;
			TransitionCommand.ForceClearFadeToBlack();
		}

		public static bool IsFading()
		{
			return alpha > 0f;
		}
	}
	public static class FileIoIndicatorManager
	{
		private static int activeWriteCount;

		private static volatile float saveIconAlpha;

		public static void IncrementActiveWriteCount()
		{
			Interlocked.Increment(ref activeWriteCount);
			saveIconAlpha = 2f;
		}

		public static void DecrementActiveWriteCount()
		{
			Interlocked.Decrement(ref activeWriteCount);
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			UnityEngine.UI.Image saveImage = RoR2Application.instance.saveIconImage;
			RoR2Application.onUpdate += delegate
			{
				UnityEngine.Color color = saveImage.color;
				if (activeWriteCount <= 0)
				{
					color.a = (saveIconAlpha = Mathf.Max(saveIconAlpha - 4f * Time.unscaledDeltaTime, 0f));
				}
				saveImage.color = color;
			};
		}
	}
	public class FixedSizeArrayPool<T>
	{
		public enum ClearType
		{
			RESET,
			CLEAR,
			NONE
		}

		private int _lengthOfArrays;

		[NotNull]
		private T[][] pooledArrays;

		private int count;

		public int lengthOfArrays
		{
			get
			{
				return _lengthOfArrays;
			}
			set
			{
				if (_lengthOfArrays != value)
				{
					ArrayUtils.Clear(pooledArrays, ref count);
					_lengthOfArrays = value;
				}
			}
		}

		public FixedSizeArrayPool(int lengthOfArrays)
		{
			_lengthOfArrays = lengthOfArrays;
			pooledArrays = Array.Empty<T[]>();
		}

		[NotNull]
		public T[] Request()
		{
			if (count <= 0)
			{
				return new T[_lengthOfArrays];
			}
			T[] result = pooledArrays[--count];
			pooledArrays[count] = null;
			return result;
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		[NotNull]
		private static ArgumentException CreateArraySizeMismatchException(int incomingArrayLength, int arrayPoolSizeRequirement)
		{
			return new ArgumentException($"Array of length {incomingArrayLength} may not be returned to pool for arrays of length {arrayPoolSizeRequirement}", "array");
		}

		public void Return([NotNull] T[] array, ClearType clearType = ClearType.RESET)
		{
			if (array.Length != _lengthOfArrays)
			{
				throw CreateArraySizeMismatchException(array.Length, _lengthOfArrays);
			}
			switch (clearType)
			{
			case ClearType.RESET:
			{
				T[] array2 = array;
				T value = default(T);
				ArrayUtils.SetAll(array2, in value);
				break;
			}
			case ClearType.CLEAR:
				Array.Clear(array, 0, array.Length);
				break;
			}
			ArrayUtils.ArrayAppend(ref pooledArrays, ref count, in array);
		}
	}
	public class ForcePingable : MonoBehaviour
	{
		public bool bypassEntityLocator = true;
	}
	[CreateAssetMenu(menuName = "RoR2/DropTables/FreeChestDropTable")]
	public class FreeChestDropTable : PickupDropTable
	{
		[SerializeField]
		private float tier1Weight = 0.79f;

		[SerializeField]
		private float tier2Weight = 0.2f;

		[SerializeField]
		private float tier3Weight = 0.01f;

		private readonly WeightedSelection<PickupIndex> selector = new WeightedSelection<PickupIndex>();

		private void Add(List<PickupIndex> sourceDropList, float listWeight)
		{
			if (listWeight <= 0f || sourceDropList.Count == 0)
			{
				return;
			}
			float weight = listWeight / (float)sourceDropList.Count;
			foreach (PickupIndex sourceDrop in sourceDropList)
			{
				selector.AddChoice(sourceDrop, weight);
			}
		}

		protected override PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng)
		{
			int num = 0;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if ((bool)instance.master)
				{
					int itemCount = instance.master.inventory.GetItemCount(DLC1Content.Items.FreeChest);
					num += itemCount;
				}
			}
			if (num <= 0)
			{
				num = 1;
			}
			selector.Clear();
			Add(Run.instance.availableTier1DropList, tier1Weight);
			Add(Run.instance.availableTier2DropList, tier2Weight * (float)num);
			Add(Run.instance.availableTier3DropList, tier3Weight * Mathf.Pow(num, 2f));
			return PickupDropTable.GenerateDropFromWeightedSelection(rng, selector);
		}

		public override int GetPickupCount()
		{
			return selector.Count;
		}

		protected override PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng)
		{
			return PickupDropTable.GenerateUniqueDropsFromWeightedSelection(maxDrops, rng, selector);
		}
	}
	public static class FriendlyFireManager
	{
		public enum FriendlyFireMode
		{
			Off,
			FriendlyFire,
			FreeForAll
		}

		public static FriendlyFireMode friendlyFireMode = FriendlyFireMode.Off;

		public static float friendlyFireDamageScale { get; private set; } = 0.5f;


		public static bool ShouldSplashHitProceed(HealthComponent victim, TeamIndex attackerTeamIndex)
		{
			if (victim.body.teamComponent.teamIndex == attackerTeamIndex && friendlyFireMode == FriendlyFireMode.Off)
			{
				return attackerTeamIndex == TeamIndex.None;
			}
			return true;
		}

		public static bool ShouldDirectHitProceed(HealthComponent victim, TeamIndex attackerTeamIndex)
		{
			if (victim.body.teamComponent.teamIndex == attackerTeamIndex && friendlyFireMode == FriendlyFireMode.Off)
			{
				return attackerTeamIndex == TeamIndex.None;
			}
			return true;
		}

		public static bool ShouldSeekingProceed(HealthComponent victim, TeamIndex attackerTeamIndex)
		{
			if (victim.body.teamComponent.teamIndex == attackerTeamIndex && friendlyFireMode != FriendlyFireMode.FreeForAll)
			{
				return attackerTeamIndex == TeamIndex.None;
			}
			return true;
		}
	}
	public class AchievementGranter : NetworkBehaviour
	{
		private static int kRpcRpcGrantAchievement;

		[ClientRpc]
		public void RpcGrantAchievement(string achievementName)
		{
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				AchievementManager.GetUserAchievementManager(readOnlyLocalUsers).GrantAchievement(AchievementManager.GetAchievementDef(achievementName));
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcGrantAchievement(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcGrantAchievement called on server.");
			}
			else
			{
				((AchievementGranter)obj).RpcGrantAchievement(reader.ReadString());
			}
		}

		public void CallRpcGrantAchievement(string achievementName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcGrantAchievement called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcGrantAchievement);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(achievementName);
			SendRPCInternal(networkWriter, 0, "RpcGrantAchievement");
		}

		static AchievementGranter()
		{
			kRpcRpcGrantAchievement = -180752285;
			NetworkBehaviour.RegisterRpcDelegate(typeof(AchievementGranter), kRpcRpcGrantAchievement, InvokeRpcRpcGrantAchievement);
			NetworkCRC.RegisterBehaviour("AchievementGranter", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class AddCurvedTorque : MonoBehaviour
	{
		public AnimationCurve torqueCurve;

		public UnityEngine.Vector3 localTorqueVector;

		public float lifetime;

		public Rigidbody[] rigidbodies;

		private float stopwatch;

		private void FixedUpdate()
		{
			stopwatch += Time.fixedDeltaTime;
			float num = torqueCurve.Evaluate(stopwatch / lifetime);
			Rigidbody[] array = rigidbodies;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].AddRelativeTorque(localTorqueVector * num);
			}
		}
	}
	[RequireComponent(typeof(Animator))]
	public class AimAnimator : MonoBehaviour, ILifeBehavior
	{
		public enum AimType
		{
			Direct,
			Smart
		}

		public class DirectionOverrideRequest : IDisposable
		{
			public readonly Func<UnityEngine.Vector3> directionGetter;

			private Action<DirectionOverrideRequest> disposeCallback;

			public DirectionOverrideRequest(Func<UnityEngine.Vector3> getter, Action<DirectionOverrideRequest> onDispose)
			{
				disposeCallback = onDispose;
				directionGetter = getter;
			}

			public void Dispose()
			{
				disposeCallback?.Invoke(this);
				disposeCallback = null;
			}
		}

		private struct AimAngles
		{
			public float pitch;

			public float yaw;
		}

		[Tooltip("The input bank component of the character.")]
		public InputBankTest inputBank;

		[Tooltip("The direction component of the character.")]
		public CharacterDirection directionComponent;

		[Tooltip("The minimum pitch supplied by the aiming animation.")]
		public float pitchRangeMin;

		[Tooltip("The maximum pitch supplied by the aiming animation.")]
		public float pitchRangeMax;

		[Tooltip("The minimum yaw supplied by the aiming animation.")]
		public float yawRangeMin;

		[Tooltip("The maximum yaw supplied by the aiming animation.")]
		public float yawRangeMax;

		[Tooltip("If the pitch is this many degrees beyond the range the aiming animations support, the character will return to neutral pose after waiting the giveup duration.")]
		public float pitchGiveupRange;

		[Tooltip("If the yaw is this many degrees beyond the range the aiming animations support, the character will return to neutral pose after waiting the giveup duration.")]
		public float yawGiveupRange;

		[Tooltip("If the pitch or yaw exceed the range supported by the aiming animations, the character will return to neutral pose after waiting this long.")]
		public float giveupDuration;

		[Tooltip("The speed in degrees/second to approach the desired pitch/yaw by while the weapon should be raised.")]
		public float raisedApproachSpeed = 720f;

		[Tooltip("The speed in degrees/second to approach the desired pitch/yaw by while the weapon should be lowered.")]
		public float loweredApproachSpeed = 360f;

		[Tooltip("The smoothing time for the motion.")]
		public float smoothTime = 0.1f;

		[Tooltip("Whether or not the character can do full 360 yaw turns.")]
		public bool fullYaw;

		[Tooltip("Switches between Direct (point straight at target) or Smart (only turn when outside angle range).")]
		public AimType aimType;

		[Tooltip("Assigns the weight of the aim from the center as an animator value 'aimWeight' between 0-1.")]
		public bool enableAimWeight;

		public bool UseTransformedAimVector;

		private Animator animatorComponent;

		private float pitchClipCycleEnd;

		private float yawClipCycleEnd;

		private float giveupTimer;

		private AimAngles localAnglesToAimVector;

		private AimAngles overshootAngles;

		private AimAngles clampedLocalAnglesToAimVector;

		private AimAngles currentLocalAngles;

		private AimAngles smoothingVelocity;

		private List<DirectionOverrideRequest> directionOverrideRequests = new List<DirectionOverrideRequest>();

		private static readonly int aimPitchCycleHash = Animator.StringToHash("aimPitchCycle");

		private static readonly int aimYawCycleHash = Animator.StringToHash("aimYawCycle");

		private static readonly int aimWeightHash = Animator.StringToHash("aimWeight");

		public bool isOutsideOfRange { get; private set; }

		private bool shouldGiveup => giveupTimer <= 0f;

		public DirectionOverrideRequest RequestDirectionOverride(Func<UnityEngine.Vector3> getter)
		{
			DirectionOverrideRequest directionOverrideRequest = new DirectionOverrideRequest(getter, RemoveRequest);
			directionOverrideRequests.Add(directionOverrideRequest);
			return directionOverrideRequest;
		}

		private void RemoveRequest(DirectionOverrideRequest request)
		{
			directionOverrideRequests.Remove(request);
		}

		private void Awake()
		{
			animatorComponent = GetComponent<Animator>();
		}

		private void Start()
		{
			int layerIndex = animatorComponent.GetLayerIndex("AimPitch");
			int layerIndex2 = animatorComponent.GetLayerIndex("AimYaw");
			animatorComponent.Play("PitchControl", layerIndex);
			animatorComponent.Play("YawControl", layerIndex2);
			animatorComponent.Update(0f);
			AnimatorClipInfo[] currentAnimatorClipInfo = animatorComponent.GetCurrentAnimatorClipInfo(layerIndex);
			AnimatorClipInfo[] currentAnimatorClipInfo2 = animatorComponent.GetCurrentAnimatorClipInfo(layerIndex2);
			if (currentAnimatorClipInfo.Length != 0)
			{
				AnimationClip clip = currentAnimatorClipInfo[0].clip;
				double num = clip.length * clip.frameRate;
				pitchClipCycleEnd = (float)((num - 1.0) / num);
			}
			if (currentAnimatorClipInfo2.Length != 0)
			{
				AnimationClip clip2 = currentAnimatorClipInfo2[0].clip;
				_ = clip2.length;
				_ = clip2.frameRate;
				yawClipCycleEnd = 0.999f;
			}
		}

		private void Update()
		{
			if (!(Time.deltaTime <= 0f))
			{
				UpdateLocalAnglesToAimVector();
				UpdateGiveup();
				ApproachDesiredAngles();
				UpdateAnimatorParameters(animatorComponent, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax);
			}
		}

		public void OnDeathStart()
		{
			base.enabled = false;
			currentLocalAngles = new AimAngles
			{
				pitch = 0f,
				yaw = 0f
			};
			UpdateAnimatorParameters(animatorComponent, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax);
		}

		private static float Remap(float value, float inMin, float inMax, float outMin, float outMax)
		{
			return outMin + (value - inMin) / (inMax - inMin) * (outMax - outMin);
		}

		private static float NormalizeAngle(float angle)
		{
			return Mathf.Repeat(angle + 180f, 360f) - 180f;
		}

		private void UpdateLocalAnglesToAimVector()
		{
			UnityEngine.Vector3 vector = ((directionOverrideRequests.Count <= 0) ? (inputBank ? inputBank.aimDirection : base.transform.forward) : directionOverrideRequests[directionOverrideRequests.Count - 1].directionGetter());
			if (UseTransformedAimVector)
			{
				UnityEngine.Vector3 eulerAngles = Util.QuaternionSafeLookRotation(base.transform.InverseTransformDirection(vector), base.transform.up).eulerAngles;
				localAnglesToAimVector = new AimAngles
				{
					pitch = NormalizeAngle(eulerAngles.x),
					yaw = NormalizeAngle(eulerAngles.y)
				};
			}
			else
			{
				float y = (directionComponent ? directionComponent.yaw : base.transform.eulerAngles.y);
				float x = (directionComponent ? directionComponent.transform.eulerAngles.x : base.transform.eulerAngles.x);
				float z = (directionComponent ? directionComponent.transform.eulerAngles.z : base.transform.eulerAngles.z);
				UnityEngine.Vector3 eulerAngles2 = Util.QuaternionSafeLookRotation(vector, base.transform.up).eulerAngles;
				UnityEngine.Vector3 vector2 = vector;
				UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(x, y, z);
				vector2.y = 0f;
				localAnglesToAimVector = new AimAngles
				{
					pitch = (0f - Mathf.Atan2(vector.y, vector2.magnitude)) * 57.29578f,
					yaw = NormalizeAngle(eulerAngles2.y - vector3.y)
				};
			}
			overshootAngles = new AimAngles
			{
				pitch = Mathf.Max(pitchRangeMin - localAnglesToAimVector.pitch, localAnglesToAimVector.pitch - pitchRangeMax),
				yaw = Mathf.Max(Mathf.DeltaAngle(localAnglesToAimVector.yaw, yawRangeMin), Mathf.DeltaAngle(yawRangeMax, localAnglesToAimVector.yaw))
			};
			clampedLocalAnglesToAimVector = new AimAngles
			{
				pitch = Mathf.Clamp(localAnglesToAimVector.pitch, pitchRangeMin, pitchRangeMax),
				yaw = Mathf.Clamp(localAnglesToAimVector.yaw, yawRangeMin, yawRangeMax)
			};
		}

		private void ApproachDesiredAngles()
		{
			AimAngles aimAngles2;
			float maxSpeed;
			if (shouldGiveup)
			{
				AimAngles aimAngles = default(AimAngles);
				aimAngles.pitch = 0f;
				aimAngles.yaw = 0f;
				aimAngles2 = aimAngles;
				maxSpeed = loweredApproachSpeed;
			}
			else
			{
				aimAngles2 = clampedLocalAnglesToAimVector;
				maxSpeed = raisedApproachSpeed;
			}
			float yaw = ((!fullYaw) ? Mathf.SmoothDamp(currentLocalAngles.yaw, aimAngles2.yaw, ref smoothingVelocity.yaw, smoothTime, maxSpeed, Time.deltaTime) : NormalizeAngle(Mathf.SmoothDampAngle(currentLocalAngles.yaw, aimAngles2.yaw, ref smoothingVelocity.yaw, smoothTime, maxSpeed, Time.deltaTime)));
			currentLocalAngles = new AimAngles
			{
				pitch = Mathf.SmoothDampAngle(currentLocalAngles.pitch, aimAngles2.pitch, ref smoothingVelocity.pitch, smoothTime, maxSpeed, Time.deltaTime),
				yaw = yaw
			};
		}

		private void ResetGiveup()
		{
			giveupTimer = giveupDuration;
		}

		private void UpdateGiveup()
		{
			if (overshootAngles.pitch > pitchGiveupRange || (!fullYaw && overshootAngles.yaw > yawGiveupRange))
			{
				giveupTimer -= Time.deltaTime;
				isOutsideOfRange = true;
			}
			else
			{
				isOutsideOfRange = false;
				ResetGiveup();
			}
		}

		public void AimImmediate()
		{
			UpdateLocalAnglesToAimVector();
			ResetGiveup();
			currentLocalAngles = clampedLocalAnglesToAimVector;
			smoothingVelocity = new AimAngles
			{
				pitch = 0f,
				yaw = 0f
			};
			UpdateAnimatorParameters(animatorComponent, pitchRangeMin, pitchRangeMax, yawRangeMin, yawRangeMax);
		}

		public void UpdateAnimatorParameters(Animator animator, float pitchRangeMin, float pitchRangeMax, float yawRangeMin, float yawRangeMax)
		{
			float num = 1f;
			if (enableAimWeight)
			{
				num = animatorComponent.GetFloat(aimWeightHash);
			}
			animator.SetFloat(aimPitchCycleHash, Remap(currentLocalAngles.pitch * num, pitchRangeMin, pitchRangeMax, pitchClipCycleEnd, 0f));
			animator.SetFloat(aimYawCycleHash, Remap(currentLocalAngles.yaw * num, yawRangeMin, yawRangeMax, 0f, yawClipCycleEnd));
		}
	}
	public class AimAssistTarget : MonoBehaviour
	{
		public Transform point0;

		public Transform point1;

		public float assistScale = 1f;

		public HealthComponent healthComponent;

		public TeamComponent teamComponent;

		public static List<AimAssistTarget> instancesList = new List<AimAssistTarget>();

		public static FloatConVar debugAimAssistVisualCoefficient = new FloatConVar("debug_aim_assist_visual_coefficient", ConVarFlags.None, "2", "Magic for debug visuals. Don't touch.");

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.fixedDeltaTime);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			if ((bool)healthComponent && !healthComponent.alive)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void OnDrawGizmos()
		{
			if ((bool)point0)
			{
				Gizmos.color = UnityEngine.Color.red;
				Gizmos.DrawWireSphere(point0.position, 1f * assistScale * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value);
				Gizmos.color = UnityEngine.Color.white;
				Gizmos.DrawWireSphere(point0.position, 1f * assistScale * CameraRigController.aimStickAssistMaxSize.value * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value);
			}
			if ((bool)point1)
			{
				Gizmos.color = UnityEngine.Color.red;
				Gizmos.DrawWireSphere(point1.position, 1f * assistScale * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value);
				Gizmos.color = UnityEngine.Color.white;
				Gizmos.DrawWireSphere(point1.position, 1f * assistScale * CameraRigController.aimStickAssistMaxSize.value * CameraRigController.aimStickAssistMinSize.value * debugAimAssistVisualCoefficient.value);
			}
			if ((bool)point0 && (bool)point1)
			{
				Gizmos.DrawLine(point0.position, point1.position);
			}
		}
	}
	public class AimTurnStateController : MonoBehaviour
	{
		[Tooltip("The component we use to determine the current orientation")]
		[SerializeField]
		private CharacterDirection characterDirection;

		[SerializeField]
		[Tooltip("The component we use to determine the current aim")]
		private InputBankTest inputBank;

		[SerializeField]
		[Tooltip("The state machine we should modify")]
		private EntityStateMachine targetStateMachine;

		[SerializeField]
		[Tooltip("The state we should push")]
		private SerializableEntityStateType turnStateType;

		[SerializeField]
		[Tooltip("The priority of the new state")]
		private InterruptPriority interruptPriority;

		[SerializeField]
		[Tooltip("The minimum difference between the current orientation and the aim before we should push the state")]
		private float minTriggerDegrees;

		[SerializeField]
		[Tooltip("The minimum time before we should push the state again")]
		private float retriggerDelaySeconds;

		[Tooltip("The aim/direction vectors are multiplied by this vector and normalized before comparison.  This can be used to exclude a dimension from the calculation.")]
		[SerializeField]
		private UnityEngine.Vector3 aimScale = new UnityEngine.Vector3(1f, 1f, 1f);

		private float lastTriggerTime;

		private void FixedUpdate()
		{
			if (!(Run.instance.fixedTime - lastTriggerTime > retriggerDelaySeconds))
			{
				return;
			}
			UnityEngine.Vector3 aimDirection = inputBank.aimDirection;
			aimDirection.Scale(aimScale);
			aimDirection.Normalize();
			UnityEngine.Vector3 forward = characterDirection.forward;
			forward.Scale(aimScale);
			forward.Normalize();
			if (UnityEngine.Vector3.Angle(aimDirection, forward) > minTriggerDegrees)
			{
				lastTriggerTime = Run.instance.fixedTime;
				if ((bool)targetStateMachine)
				{
					EntityState newNextState = EntityStateCatalog.InstantiateState(ref turnStateType);
					targetStateMachine.SetInterruptState(newNextState, interruptPriority);
				}
			}
		}
	}
	public class AlignToNormal : MonoBehaviour
	{
		[Tooltip("The amount to raycast down from.")]
		public float maxDistance;

		[Tooltip("The amount to pull the object out of the ground initially to test.")]
		public float offsetDistance;

		[Tooltip("Send to floor only - don't change normals.")]
		public bool changePositionOnly;

		private void Start()
		{
			if (Physics.Raycast(base.transform.position + base.transform.up * offsetDistance, -base.transform.up, out var hitInfo, maxDistance, LayerIndex.world.mask))
			{
				base.transform.position = hitInfo.point;
				if (!changePositionOnly)
				{
					base.transform.up = hitInfo.normal;
				}
			}
		}
	}
	[RequireComponent(typeof(Rigidbody))]
	public class AllPlayersTrigger : MonoBehaviour
	{
		public UnityEvent onTriggerStart;

		public UnityEvent onTriggerEnd;

		private Queue<Collider> collisionQueueServer;

		private bool triggerActiveServer;

		private void Awake()
		{
			if (NetworkServer.active)
			{
				collisionQueueServer = new Queue<Collider>();
				triggerActiveServer = false;
			}
		}

		private void OnEnable()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
			}
		}

		private void OnTriggerStay(Collider other)
		{
			if (base.enabled)
			{
				collisionQueueServer.Enqueue(other);
			}
		}

		private void FixedUpdate()
		{
			if (!Run.instance)
			{
				return;
			}
			int num = 0;
			List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			while (collisionQueueServer.Count > 0)
			{
				Collider collider = collisionQueueServer.Dequeue();
				if ((bool)collider)
				{
					CharacterBody component = collider.GetComponent<CharacterBody>();
					if ((bool)component && component.isPlayerControlled && !list.Contains(component))
					{
						list.Add(component);
						num++;
					}
				}
			}
			CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
			bool flag = num == Run.instance.livingPlayerCount && num != 0;
			if (triggerActiveServer != flag)
			{
				triggerActiveServer = flag;
				(triggerActiveServer ? onTriggerStart : onTriggerEnd)?.Invoke();
			}
		}
	}
	public class AmmoPickup : MonoBehaviour
	{
		[Tooltip("The base object to destroy when this pickup is consumed.")]
		public GameObject baseObject;

		[Tooltip("The team filter object which determines who can pick up this pack.")]
		public TeamFilter teamFilter;

		public GameObject pickupEffect;

		private bool alive = true;

		private void OnTriggerStay(Collider other)
		{
			if (NetworkServer.active && alive && TeamComponent.GetObjectTeam(other.gameObject) == teamFilter.teamIndex)
			{
				SkillLocator component = other.GetComponent<SkillLocator>();
				if ((bool)component)
				{
					alive = false;
					component.ApplyAmmoPack();
					EffectManager.SimpleEffect(pickupEffect, base.transform.position, UnityEngine.Quaternion.identity, transmit: true);
					UnityEngine.Object.Destroy(baseObject);
				}
			}
		}
	}
	[RequireComponent(typeof(CharacterModel))]
	public class AncientWispFireController : MonoBehaviour
	{
		public ParticleSystem normalParticles;

		public Light normalLight;

		public ParticleSystem rageParticles;

		public Light rageLight;

		private CharacterModel characterModel;

		private void Awake()
		{
			characterModel = GetComponent<CharacterModel>();
		}

		private void Update()
		{
			bool flag = false;
			CharacterBody body = characterModel.body;
			if ((bool)body)
			{
				flag = body.HasBuff(JunkContent.Buffs.EnrageAncientWisp);
			}
			if ((bool)normalParticles)
			{
				ParticleSystem.EmissionModule emission = normalParticles.emission;
				if (emission.enabled == flag)
				{
					emission.enabled = !flag;
					if (!flag)
					{
						normalParticles.Play();
					}
				}
			}
			if ((bool)rageParticles)
			{
				ParticleSystem.EmissionModule emission2 = rageParticles.emission;
				if (emission2.enabled != flag)
				{
					emission2.enabled = flag;
					if (flag)
					{
						rageParticles.Play();
					}
				}
			}
			if ((bool)normalLight)
			{
				normalLight.enabled = !flag;
			}
			if ((bool)rageLight)
			{
				rageLight.enabled = flag;
			}
		}
	}
	public class AnimateImageAlpha : MonoBehaviour
	{
		public AnimationCurve alphaCurve;

		public UnityEngine.UI.Image[] images;

		public float timeMax = 5f;

		public float delayBetweenElements;

		[HideInInspector]
		public float stopwatch;

		private void OnEnable()
		{
			stopwatch = 0f;
		}

		public void ResetStopwatch()
		{
			stopwatch = 0f;
		}

		private void LateUpdate()
		{
			stopwatch += Time.unscaledDeltaTime;
			int num = 0;
			UnityEngine.UI.Image[] array = images;
			foreach (UnityEngine.UI.Image obj in array)
			{
				num++;
				float a = alphaCurve.Evaluate((stopwatch + delayBetweenElements * (float)num) / timeMax);
				UnityEngine.Color color = obj.color;
				obj.color = new UnityEngine.Color(color.r, color.g, color.b, a);
			}
		}
	}
	public class AnimateShaderAlpha : MonoBehaviour
	{
		public AnimationCurve alphaCurve;

		private Renderer targetRenderer;

		private MaterialPropertyBlock _propBlock;

		private Material[] materials;

		public float timeMax = 5f;

		[Tooltip("Optional field if you want to animate Decal 'Fade' rather than renderer _ExternalAlpha.")]
		public Decal decal;

		public bool pauseTime;

		public bool destroyOnEnd;

		public bool disableOnEnd;

		[HideInInspector]
		public float time;

		private float initialFade;

		[HideInInspector]
		public bool initialyEnabled;

		[HideInInspector]
		public UnityEvent OnFinished;

		public bool continueExistingAfterTimeMaxIsReached;

		private bool initialised;

		private void Start()
		{
			Initialise();
		}

		private void Initialise()
		{
			if (!initialised)
			{
				targetRenderer = GetComponent<Renderer>();
				if ((bool)targetRenderer)
				{
					materials = targetRenderer.materials;
				}
				if ((bool)decal)
				{
					initialFade = decal.Fade;
				}
				initialised = true;
			}
		}

		public void Reset()
		{
			Initialise();
			time = 0f;
			if ((bool)decal)
			{
				decal.Fade = initialFade;
			}
			else
			{
				Material[] array = materials;
				for (int i = 0; i < array.Length; i++)
				{
					_ = array[i];
					_propBlock = new MaterialPropertyBlock();
					targetRenderer.GetPropertyBlock(_propBlock);
					_propBlock.SetFloat("_ExternalAlpha", 1f);
					targetRenderer.SetPropertyBlock(_propBlock);
				}
			}
			base.enabled = initialyEnabled;
		}

		private void OnDestroy()
		{
			OnFinished.RemoveAllListeners();
		}

		private void Update()
		{
			if (!pauseTime)
			{
				time = Mathf.Min(timeMax, time + Time.deltaTime);
			}
			float num = alphaCurve.Evaluate(time / timeMax);
			if ((bool)decal)
			{
				decal.Fade = num * initialFade;
			}
			else
			{
				Material[] array = materials;
				for (int i = 0; i < array.Length; i++)
				{
					_ = array[i];
					_propBlock = new MaterialPropertyBlock();
					targetRenderer.GetPropertyBlock(_propBlock);
					_propBlock.SetFloat("_ExternalAlpha", num);
					targetRenderer.SetPropertyBlock(_propBlock);
				}
			}
			if (time >= timeMax)
			{
				OnFinished?.Invoke();
				if (disableOnEnd)
				{
					base.enabled = false;
				}
				if (destroyOnEnd)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}
	}
	public class AnimationEvents : MonoBehaviour
	{
		public GameObject soundCenter;

		private GameObject bodyObject;

		private CharacterModel characterModel;

		private ChildLocator childLocator;

		private EntityLocator entityLocator;

		private Renderer meshRenderer;

		private ModelLocator modelLocator;

		private float printHeight;

		private float printTime;

		private void Start()
		{
			childLocator = GetComponent<ChildLocator>();
			entityLocator = GetComponent<EntityLocator>();
			meshRenderer = GetComponentInChildren<Renderer>();
			characterModel = GetComponent<CharacterModel>();
			if ((bool)characterModel && (bool)characterModel.body)
			{
				bodyObject = characterModel.body.gameObject;
				modelLocator = bodyObject.GetComponent<ModelLocator>();
			}
		}

		public void UpdateIKState(AnimationEvent animationEvent)
		{
			childLocator.FindChild(animationEvent.stringParameter).GetComponent<IIKTargetBehavior>()?.UpdateIKState(animationEvent.intParameter);
		}

		public void PlaySound(string soundString)
		{
			Util.PlaySound(soundString, soundCenter ? soundCenter : bodyObject);
		}

		public void NormalizeToFloor()
		{
			if ((bool)modelLocator)
			{
				modelLocator.normalizeToFloor = true;
			}
		}

		public void SetIK(AnimationEvent animationEvent)
		{
			if ((bool)modelLocator && (bool)modelLocator.modelTransform)
			{
				bool flag = ((animationEvent.intParameter != 0) ? true : false);
				InverseKinematics component = modelLocator.modelTransform.GetComponent<InverseKinematics>();
				StriderLegController component2 = modelLocator.modelTransform.GetComponent<StriderLegController>();
				if ((bool)component)
				{
					component.enabled = flag;
				}
				if ((bool)component2)
				{
					component2.enabled = flag;
				}
			}
		}

		public void RefreshAllIK()
		{
			IKTargetPassive[] componentsInChildren = GetComponentsInChildren<IKTargetPassive>();
			foreach (IKTargetPassive obj in componentsInChildren)
			{
				obj.UpdateIKTargetPosition();
				obj.UpdateYOffset();
			}
		}

		public void CreateEffect(AnimationEvent animationEvent)
		{
			Transform transform = base.transform;
			int num = -1;
			if (!string.IsNullOrEmpty(animationEvent.stringParameter))
			{
				num = childLocator.FindChildIndex(animationEvent.stringParameter);
				if (num != -1)
				{
					transform = childLocator.FindChild(num);
				}
			}
			bool transmit = animationEvent.intParameter != 0;
			EffectData effectData = new EffectData();
			effectData.origin = transform.position;
			effectData.SetChildLocatorTransformReference(bodyObject, num);
			EffectManager.SpawnEffect((GameObject)animationEvent.objectReferenceParameter, effectData, transmit);
		}

		public void CreatePrefab(AnimationEvent animationEvent)
		{
			GameObject gameObject = (GameObject)animationEvent.objectReferenceParameter;
			bool flag = EffectManager.ShouldUsePooledEffect(gameObject);
			string stringParameter = animationEvent.stringParameter;
			Transform transform = base.transform;
			int intParameter = animationEvent.intParameter;
			if ((bool)childLocator)
			{
				Transform transform2 = childLocator.FindChild(stringParameter);
				if ((bool)transform2)
				{
					if (intParameter == 0)
					{
						if (!flag)
						{
							UnityEngine.Object.Instantiate(gameObject, transform2.position, UnityEngine.Quaternion.identity);
						}
						else
						{
							EffectManager.GetAndActivatePooledEffect(gameObject, transform2.position, UnityEngine.Quaternion.identity);
						}
					}
					else if (!flag)
					{
						UnityEngine.Object.Instantiate(gameObject, transform2.position, transform2.rotation).transform.parent = transform2;
					}
					else
					{
						EffectManager.GetAndActivatePooledEffect(gameObject, transform2.position, transform2.rotation, transform2);
					}
				}
				else if ((bool)gameObject)
				{
					if (!flag)
					{
						UnityEngine.Object.Instantiate(gameObject, transform.position, transform.rotation);
					}
					else
					{
						EffectManager.GetAndActivatePooledEffect(gameObject, transform.position, transform.rotation);
					}
				}
			}
			else if ((bool)gameObject)
			{
				if (!flag)
				{
					UnityEngine.Object.Instantiate(gameObject, transform.position, transform.rotation);
				}
				else
				{
					EffectManager.GetAndActivatePooledEffect(gameObject, transform.position, transform.rotation);
				}
			}
		}

		public void ItemDrop()
		{
			if (NetworkServer.active && (bool)entityLocator)
			{
				IChestBehavior component = entityLocator.entity.GetComponent<IChestBehavior>();
				if ((bool)(Component)component)
				{
					component.ItemDrop();
				}
			}
		}

		public void BeginPrint(AnimationEvent animationEvent)
		{
			if ((bool)meshRenderer)
			{
				Material material = (Material)animationEvent.objectReferenceParameter;
				float floatParameter = animationEvent.floatParameter;
				float maxPrintHeight = animationEvent.intParameter;
				meshRenderer.material = material;
				printTime = 0f;
				MaterialPropertyBlock printPropertyBlock = new MaterialPropertyBlock();
				StartCoroutine(startPrint(floatParameter, maxPrintHeight, printPropertyBlock));
			}
		}

		private IEnumerator startPrint(float maxPrintTime, float maxPrintHeight, MaterialPropertyBlock printPropertyBlock)
		{
			if ((bool)meshRenderer)
			{
				while (printHeight < maxPrintHeight)
				{
					printTime += Time.deltaTime;
					printHeight = printTime / maxPrintTime * maxPrintHeight;
					meshRenderer.GetPropertyBlock(printPropertyBlock);
					printPropertyBlock.Clear();
					printPropertyBlock.SetFloat("_SliceHeight", printHeight);
					meshRenderer.SetPropertyBlock(printPropertyBlock);
					yield return new WaitForEndOfFrame();
				}
			}
		}

		public void SetChildEnable(AnimationEvent animationEvent)
		{
			string stringParameter = animationEvent.stringParameter;
			bool active = animationEvent.intParameter > 0;
			if ((bool)childLocator)
			{
				Transform transform = childLocator.FindChild(stringParameter);
				if ((bool)transform)
				{
					transform.gameObject.SetActive(active);
				}
			}
		}

		public void SwapMaterial(AnimationEvent animationEvent)
		{
			Material material = (Material)animationEvent.objectReferenceParameter;
			if ((bool)meshRenderer)
			{
				meshRenderer.material = material;
			}
		}
	}
	[RequireComponent(typeof(Rigidbody))]
	public class AntiGravityForce : MonoBehaviour
	{
		public Rigidbody rb;

		[Tooltip("How much to oppose gravity. A value of 1 means it is unaffected by gravity.")]
		public float antiGravityCoefficient;

		private void FixedUpdate()
		{
			rb.AddForce(-Physics.gravity * antiGravityCoefficient, ForceMode.Acceleration);
		}
	}
	public class ApplyForceOnStart : MonoBehaviour
	{
		public UnityEngine.Vector3 localForce;

		private void Start()
		{
			Rigidbody component = GetComponent<Rigidbody>();
			if ((bool)component)
			{
				component.AddRelativeForce(localForce);
			}
		}
	}
	public class ApplyJiggleBoneMotion : MonoBehaviour
	{
		public float forceScale = 100f;

		public Transform rootTransform;

		public Rigidbody[] rigidbodies;

		private UnityEngine.Vector3 lastRootPosition;

		private void FixedUpdate()
		{
			UnityEngine.Vector3 position = rootTransform.position;
			Rigidbody[] array = rigidbodies;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].AddForce((lastRootPosition - position) * forceScale * Time.fixedDeltaTime);
			}
			lastRootPosition = position;
		}
	}
	public class ApplyTorqueOnStart : MonoBehaviour
	{
		public UnityEngine.Vector3 localTorque;

		public bool randomize;

		private void Start()
		{
			Rigidbody component = GetComponent<Rigidbody>();
			if ((bool)component)
			{
				UnityEngine.Vector3 torque = localTorque;
				if (randomize)
				{
					torque.x = UnityEngine.Random.Range((0f - torque.x) / 2f, torque.x / 2f);
					torque.y = UnityEngine.Random.Range((0f - torque.y) / 2f, torque.y / 2f);
					torque.z = UnityEngine.Random.Range((0f - torque.z) / 2f, torque.z / 2f);
				}
				component.AddRelativeTorque(torque);
			}
		}
	}
	[RequireComponent(typeof(EntityStateMachine))]
	[RequireComponent(typeof(Inventory))]
	public class ArenaMissionController : NetworkBehaviour
	{
		public class ArenaMissionBaseState : EntityState
		{
			protected ArenaMissionController arenaMissionController => instance;
		}

		public class MissionCompleted : ArenaMissionBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				base.arenaMissionController.clearedEffect.SetActive(value: true);
			}
		}

		[Serializable]
		public struct MonsterItemStackData
		{
			public PickupDropTable dropTable;

			public int stacks;
		}

		[Header("Behavior Values")]
		public float baseMonsterCredit;

		public float creditMultiplierPerRound;

		public int minimumNumberToSpawnPerMonsterType;

		public int totalRoundsMax;

		public int maximumNumberToSpawnBeforeSkipping;

		public float spawnDistanceMultiplier;

		public float eliteBias;

		[Header("Cached Components")]
		public GameObject[] nullWards;

		public GameObject monsterSpawnPosition;

		public GameObject rewardSpawnPosition;

		public CombatDirector[] combatDirectors;

		public GameObject clearedEffect;

		public GameObject killEffectPrefab;

		public GameObject fogDamagePrefab;

		public PortalSpawner[] completionPortalSpawners;

		public MonsterItemStackData[] monsterItemStackOrder;

		public PickupDropTable[] playerRewardOrder;

		[SerializeField]
		private int numRewardOptions;

		[SerializeField]
		private GameObject pickupPrefab;

		private EntityStateMachine mainStateMachine;

		private Xoroshiro128Plus rng;

		private List<DirectorCard> activeMonsterCards = new List<DirectorCard>();

		public readonly SyncListInt syncActiveMonsterBodies = new SyncListInt();

		private WeightedSelection<DirectorCard> availableMonsterCards;

		private float cachedDifficultyCoefficient;

		[SyncVar]
		private int _clearedRounds;

		private int nextItemStackIndex;

		private GameObject fogDamageInstance;

		private static int kListsyncActiveMonsterBodies;

		public int currentRound { get; private set; }

		public int clearedRounds
		{
			get
			{
				return _clearedRounds;
			}
			private set
			{
				Network_clearedRounds = value;
			}
		}

		public static ArenaMissionController instance { get; private set; }

		private float creditsThisRound => (baseMonsterCredit + creditMultiplierPerRound * (float)(currentRound - 1)) * cachedDifficultyCoefficient;

		public Inventory inventory { get; private set; }

		public int Network_clearedRounds
		{
			get
			{
				return _clearedRounds;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _clearedRounds, 2u);
			}
		}

		public static event Action onBeatArena;

		public static event Action onInstanceChangedGlobal;

		private void Awake()
		{
			mainStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Main");
			inventory = GetComponent<Inventory>();
			syncActiveMonsterBodies.InitializeBehaviour(this, kListsyncActiveMonsterBodies);
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			ArenaMissionController.onInstanceChangedGlobal?.Invoke();
			SceneDirector.onPreGeneratePlayerSpawnPointsServer += OnPreGeneratePlayerSpawnPointsServer;
		}

		private void OnDisable()
		{
			SceneDirector.onPreGeneratePlayerSpawnPointsServer -= OnPreGeneratePlayerSpawnPointsServer;
			instance = SingletonHelper.Unassign(instance, this);
			ArenaMissionController.onInstanceChangedGlobal?.Invoke();
		}

		private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod)
		{
			generationMethod = GeneratePlayerSpawnPointsServer;
		}

		private void GeneratePlayerSpawnPointsServer()
		{
			if (nullWards.Length == 0)
			{
				return;
			}
			UnityEngine.Vector3 position = nullWards[0].transform.position;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(SceneInfo.instance.groundNodes, HullMask.Human);
			nodeGraphSpider.AddNodeForNextStep(groundNodes.FindClosestNode(position, HullClassification.Human));
			for (int i = 0; i < 4; i++)
			{
				nodeGraphSpider.PerformStep();
				if (nodeGraphSpider.collectedSteps.Count > 16)
				{
					break;
				}
			}
			for (int j = 0; j < nodeGraphSpider.collectedSteps.Count; j++)
			{
				NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[j];
				SpawnPoint.AddSpawnPoint(groundNodes, stepInfo.node, rng);
			}
		}

		[Server]
		public override void OnStartServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::OnStartServer()' called on client");
				return;
			}
			base.OnStartServer();
			fogDamageInstance = UnityEngine.Object.Instantiate(fogDamagePrefab);
			FogDamageController component = fogDamageInstance.GetComponent<FogDamageController>();
			GameObject[] array = nullWards;
			foreach (GameObject gameObject in array)
			{
				component.AddSafeZone(gameObject.GetComponent<SphereZone>());
			}
			NetworkServer.Spawn(fogDamageInstance);
			cachedDifficultyCoefficient = Run.instance.difficultyCoefficient;
			rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint);
			InitCombatDirectors();
			Util.ShuffleArray(nullWards, rng);
			ReadyNextNullWard();
			availableMonsterCards = Util.CreateReasonableDirectorCardSpawnList(baseMonsterCredit * cachedDifficultyCoefficient, maximumNumberToSpawnBeforeSkipping, minimumNumberToSpawnPerMonsterType);
			_ = availableMonsterCards.Count;
		}

		[Server]
		private void ReadyNextNullWard()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::ReadyNextNullWard()' called on client");
				return;
			}
			if (currentRound > nullWards.Length)
			{
				UnityEngine.Debug.LogError("Out of null wards! Aborting.");
				return;
			}
			EntityStateMachine component = nullWards[currentRound].GetComponent<EntityStateMachine>();
			component.initialStateType = new SerializableEntityStateType(typeof(WardOnAndReady));
			component.SetNextState(new WardOnAndReady());
		}

		[Server]
		private void InitCombatDirectors()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::InitCombatDirectors()' called on client");
				return;
			}
			for (int i = 0; i < combatDirectors.Length; i++)
			{
				CombatDirector obj = combatDirectors[i];
				obj.maximumNumberToSpawnBeforeSkipping = maximumNumberToSpawnBeforeSkipping;
				obj.onSpawnedServer.AddListener(ModifySpawnedMasters);
				obj.spawnDistanceMultiplier = spawnDistanceMultiplier;
				obj.eliteBias = eliteBias;
			}
		}

		[Server]
		public void BeginRound()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::BeginRound()' called on client");
				return;
			}
			currentRound++;
			switch (currentRound)
			{
			case 1:
				AddMonsterType();
				break;
			case 2:
				AddItemStack();
				break;
			case 3:
				AddMonsterType();
				break;
			case 4:
				AddItemStack();
				break;
			case 5:
				AddMonsterType();
				break;
			case 6:
				AddItemStack();
				break;
			case 7:
				AddMonsterType();
				break;
			case 8:
				AddItemStack();
				break;
			case 9:
				AddItemStack();
				break;
			}
			int count = activeMonsterCards.Count;
			for (int i = 0; i < count; i++)
			{
				DirectorCard directorCard = activeMonsterCards[i];
				float num = creditsThisRound / (float)count;
				float creditMultiplier = creditMultiplierPerRound * (float)currentRound / (float)count;
				if (i > combatDirectors.Length)
				{
					UnityEngine.Debug.LogError("Trying to activate more combat directors than available. Aborting.");
					break;
				}
				CombatDirector obj = combatDirectors[i];
				obj.monsterCredit += num;
				obj.creditMultiplier = creditMultiplier;
				obj.currentSpawnTarget = monsterSpawnPosition;
				obj.OverrideCurrentMonsterCard(directorCard);
				obj.monsterSpawnTimer = 0f;
				obj.enabled = true;
				UnityEngine.Debug.LogFormat("Enabling director {0} with {1} credits to spawn {2}", i, num, directorCard.spawnCard.name);
			}
		}

		[Server]
		public void ModifySpawnedMasters(GameObject targetGameObject)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::ModifySpawnedMasters(UnityEngine.GameObject)' called on client");
				return;
			}
			CharacterMaster component = targetGameObject.GetComponent<CharacterMaster>();
			BaseAI ai = component.GetComponent<BaseAI>();
			if ((bool)ai)
			{
				ai.onBodyDiscovered += OnBodyDiscovered;
			}
			CharacterBody body = component.GetBody();
			if ((bool)body)
			{
				EntityStateMachine[] components = body.GetComponents<EntityStateMachine>();
				foreach (EntityStateMachine obj in components)
				{
					obj.initialStateType = obj.mainStateType;
				}
			}
			component.inventory.AddItemsFrom(inventory);
			void OnBodyDiscovered(CharacterBody newBody)
			{
				ai.ForceAcquireNearestEnemyIfNoCurrentEnemy();
				ai.onBodyDiscovered -= OnBodyDiscovered;
			}
		}

		[Server]
		public void EndRound()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::EndRound()' called on client");
				return;
			}
			clearedRounds++;
			if (currentRound < totalRoundsMax)
			{
				ReadyNextNullWard();
			}
			else
			{
				if ((bool)fogDamageInstance)
				{
					UnityEngine.Object.Destroy(fogDamageInstance);
					fogDamageInstance = null;
				}
				ArenaMissionController.onBeatArena?.Invoke();
				mainStateMachine.SetNextState(new MissionCompleted());
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = "ARENA_END"
				});
				PortalSpawner[] array = completionPortalSpawners;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].AttemptSpawnPortalServer();
				}
			}
			for (int j = 0; j < combatDirectors.Length; j++)
			{
				CombatDirector obj = combatDirectors[j];
				obj.enabled = false;
				obj.monsterCredit = 0f;
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Monster);
			for (int num = teamMembers.Count - 1; num >= 0; num--)
			{
				teamMembers[num].body.healthComponent.Suicide(base.gameObject, base.gameObject, DamageType.VoidDeath);
			}
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (participatingPlayerCount == 0 || !rewardSpawnPosition)
			{
				return;
			}
			PickupIndex[] array2 = Array.Empty<PickupIndex>();
			int num2 = currentRound - 1;
			if (num2 < playerRewardOrder.Length)
			{
				array2 = playerRewardOrder[num2]?.GenerateUniqueDrops(numRewardOptions, rng);
			}
			if (array2.Length != 0)
			{
				ItemTier itemTier = PickupCatalog.GetPickupDef(array2[0]).itemTier;
				int num3 = participatingPlayerCount;
				float angle = 360f / (float)num3;
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				int num4 = 0;
				while (num4 < num3)
				{
					GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
					createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromArray(array2);
					createPickupInfo.prefabOverride = pickupPrefab;
					createPickupInfo.position = rewardSpawnPosition.transform.position;
					createPickupInfo.rotation = UnityEngine.Quaternion.identity;
					createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(itemTier);
					GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo;
					PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector);
					num4++;
					vector = quaternion * vector;
				}
			}
		}

		[Server]
		private void AddMonsterType()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::AddMonsterType()' called on client");
			}
			else if (availableMonsterCards.Count != 0)
			{
				int num = availableMonsterCards.EvaluateToChoiceIndex(rng.nextNormalizedFloat);
				DirectorCard value = availableMonsterCards.choices[num].value;
				activeMonsterCards.Add(value);
				syncActiveMonsterBodies.Add((int)(value.spawnCard.prefab.GetComponent<CharacterMaster>()?.bodyPrefab.GetComponent<CharacterBody>()?.bodyIndex ?? BodyIndex.None));
				availableMonsterCards.RemoveChoice(num);
				CharacterBody component = value.spawnCard.prefab.GetComponent<CharacterMaster>().bodyPrefab.GetComponent<CharacterBody>();
				Chat.SubjectFormatChatMessage subjectFormatChatMessage = new Chat.SubjectFormatChatMessage();
				subjectFormatChatMessage.baseToken = "ARENA_ADD_MONSTER";
				subjectFormatChatMessage.paramTokens = new string[1] { component.baseNameToken };
				Chat.SendBroadcastChat(subjectFormatChatMessage);
			}
		}

		[Server]
		private void AddItemStack()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ArenaMissionController::AddItemStack()' called on client");
				return;
			}
			PickupIndex pickupIndex = PickupIndex.none;
			if (nextItemStackIndex < monsterItemStackOrder.Length)
			{
				PickupDropTable dropTable = monsterItemStackOrder[nextItemStackIndex].dropTable;
				if ((bool)dropTable)
				{
					pickupIndex = dropTable.GenerateDrop(rng);
				}
			}
			if (pickupIndex != PickupIndex.none)
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
				ItemIndex itemIndex = pickupDef.itemIndex;
				inventory.GiveItem(itemIndex, monsterItemStackOrder[nextItemStackIndex].stacks);
				Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage
				{
					baseToken = "ARENA_ADD_ITEM",
					pickupToken = pickupDef.nameToken,
					pickupColor = pickupDef.baseColor
				});
			}
			nextItemStackIndex++;
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeSyncListsyncActiveMonsterBodies(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("SyncList syncActiveMonsterBodies called on server.");
			}
			else
			{
				((ArenaMissionController)obj).syncActiveMonsterBodies.HandleMsg(reader);
			}
		}

		static ArenaMissionController()
		{
			kListsyncActiveMonsterBodies = 1496902198;
			NetworkBehaviour.RegisterSyncListDelegate(typeof(ArenaMissionController), kListsyncActiveMonsterBodies, InvokeSyncListsyncActiveMonsterBodies);
			NetworkCRC.RegisterBehaviour("ArenaMissionController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				SyncListInt.WriteInstance(writer, syncActiveMonsterBodies);
				writer.WritePackedUInt32((uint)_clearedRounds);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				SyncListInt.WriteInstance(writer, syncActiveMonsterBodies);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)_clearedRounds);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				SyncListInt.ReadReference(reader, syncActiveMonsterBodies);
				_clearedRounds = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SyncListInt.ReadReference(reader, syncActiveMonsterBodies);
			}
			if (((uint)num & 2u) != 0)
			{
				_clearedRounds = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class ArtifactEnabledResponse : MonoBehaviour
	{
		public ArtifactDef artifact;

		public UnityEvent onDiscoveredArtifactEnabled;

		public UnityEvent onLostArtifactEnabled;

		private bool _active;

		private bool active
		{
			get
			{
				return _active;
			}
			set
			{
				if (_active != value)
				{
					_active = value;
					if (active)
					{
						onDiscoveredArtifactEnabled?.Invoke();
					}
					else
					{
						onLostArtifactEnabled?.Invoke();
					}
				}
			}
		}

		private void OnEnable()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabledGlobal;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabledGlobal;
			active = RunArtifactManager.instance.IsArtifactEnabled(artifact);
		}

		private void OnDisable()
		{
			active = false;
			RunArtifactManager.onArtifactDisabledGlobal -= OnArtifactDisabledGlobal;
			RunArtifactManager.onArtifactEnabledGlobal -= OnArtifactEnabledGlobal;
		}

		private void OnArtifactEnabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != artifact))
			{
				active = true;
			}
		}

		private void OnArtifactDisabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != artifact))
			{
				active = false;
			}
		}
	}
	public class ArtifactEnabler : MonoBehaviour
	{
		[SerializeField]
		private ArtifactDef artifactDef;

		private bool artifactWasEnabled;

		private void OnEnable()
		{
			if (NetworkServer.active && (bool)artifactDef)
			{
				artifactWasEnabled = RunArtifactManager.instance.IsArtifactEnabled(artifactDef);
				RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, newEnabled: true);
			}
		}

		private void OnDisable()
		{
			if (NetworkServer.active && (bool)artifactDef && (bool)RunArtifactManager.instance)
			{
				RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, artifactWasEnabled);
			}
		}
	}
	public class ArtifactFormulaDisplay : MonoBehaviour
	{
		[Serializable]
		public struct ArtifactCompoundDisplayInfo
		{
			public ArtifactCompoundDef artifactCompoundDef;

			public Decal decal;
		}

		public ArtifactCompoundDisplayInfo[] artifactCompoundDisplayInfos;

		private void Start()
		{
			ArtifactCompoundDisplayInfo[] array = artifactCompoundDisplayInfos;
			for (int i = 0; i < array.Length; i++)
			{
				ArtifactCompoundDisplayInfo artifactCompoundDisplayInfo = array[i];
				artifactCompoundDisplayInfo.decal.Material = artifactCompoundDisplayInfo.artifactCompoundDef.decalMaterial;
			}
		}
	}
	public class ArtifactTrialMissionController : NetworkBehaviour
	{
		private class ArtifactTrialMissionControllerBaseState : EntityState
		{
			protected ArtifactTrialMissionController missionController { get; private set; }

			protected virtual bool shouldEnableCombatDirector => false;

			protected virtual bool shouldEnableBossGroup => false;

			protected virtual bool shouldAllowMonsters => shouldEnableCombatDirector;

			public override void OnEnter()
			{
				base.OnEnter();
				missionController = GetComponent<ArtifactTrialMissionController>();
				if (NetworkServer.active)
				{
					CombatDirector[] combatDirectors = missionController.combatDirectors;
					for (int i = 0; i < combatDirectors.Length; i++)
					{
						combatDirectors[i].enabled = shouldEnableCombatDirector;
					}
					if (!shouldAllowMonsters)
					{
						for (int num = CharacterMaster.readOnlyInstancesList.Count - 1; num >= 0; num--)
						{
							CharacterMaster characterMaster = CharacterMaster.readOnlyInstancesList[num];
							if (characterMaster.teamIndex == TeamIndex.Monster && (object)characterMaster != missionController.artifactShellMaster)
							{
								characterMaster.TrueKill();
							}
						}
					}
				}
				if ((bool)missionController.bossGroup)
				{
					missionController.bossGroup.enabled = shouldEnableBossGroup;
				}
			}

			public override void OnExit()
			{
				missionController = null;
				base.OnExit();
			}
		}

		private class WaitForPlayersState : ArtifactTrialMissionControllerBaseState
		{
			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && NetworkUser.AllParticipatingNetworkUsersReady())
				{
					outer.SetNextState(new IntroState());
				}
			}

			public override void OnEnter()
			{
				base.OnEnter();
				FadeToBlackManager.fadeCount++;
				FadeToBlackManager.ForceFullBlack();
			}

			public override void OnExit()
			{
				FadeToBlackManager.fadeCount--;
				base.OnExit();
			}
		}

		private class IntroState : ArtifactTrialMissionControllerBaseState
		{
			private ForcedCamera cameraController;

			public override void OnEnter()
			{
				base.OnEnter();
				cameraController = base.missionController?.introCameraController;
				if ((bool)cameraController)
				{
					cameraController.gameObject.SetActive(value: true);
				}
			}

			public override void OnExit()
			{
				if ((bool)cameraController)
				{
					cameraController.enabled = false;
					cameraController = null;
				}
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && !cameraController.enabled)
				{
					outer.SetNextState(new SetupState());
				}
			}
		}

		private class SetupState : ArtifactTrialMissionControllerBaseState
		{
			public static float delayBeforePushingNotification;

			private float keyRespawnTimer;

			private GameObject keyPickupInstance;

			private bool pushedNotification;

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active)
				{
					CharacterBody body = base.missionController.artifactShellMaster.GetBody();
					if (!body || body.healthComponent.combinedHealthFraction < 1f)
					{
						outer.SetNextState(new PreCombatState());
						return;
					}
					if (!keyPickupInstance)
					{
						keyRespawnTimer -= Time.deltaTime;
						if (keyRespawnTimer < 0f)
						{
							keyRespawnTimer = 30f;
							GenericPickupController.CreatePickupInfo createPickupInfo = new GenericPickupController.CreatePickupInfo
							{
								pickupIndex = PickupCatalog.FindPickupIndex(RoR2Content.Items.ArtifactKey.itemIndex),
								position = base.missionController.initialKeyLocation.position,
								rotation = UnityEngine.Quaternion.identity
							};
							keyPickupInstance = GenericPickupController.CreatePickup(in createPickupInfo).gameObject;
						}
					}
				}
				if (pushedNotification || !(base.fixedAge > delayBeforePushingNotification) || !(base.fixedAge > 1.5f))
				{
					return;
				}
				pushedNotification = true;
				foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
				{
					if ((bool)readOnlyInstances.playerCharacterMasterController && (bool)readOnlyInstances.playerCharacterMasterController.networkUserObject && readOnlyInstances.playerCharacterMasterController.networkUserObject.GetComponent<NetworkIdentity>().isLocalPlayer)
					{
						CharacterMasterNotificationQueue.PushArtifactNotification(readOnlyInstances, base.missionController.currentArtifact);
					}
				}
			}
		}

		private class PreCombatState : ArtifactTrialMissionControllerBaseState
		{
			private static float baseDuration = 1f;

			protected override bool shouldAllowMonsters => true;

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= baseDuration)
				{
					outer.SetNextState(new CombatState());
				}
			}
		}

		private class CombatState : ArtifactTrialMissionControllerBaseState
		{
			protected override bool shouldEnableCombatDirector => true;

			protected override bool shouldEnableBossGroup => true;

			public override void OnEnter()
			{
				base.OnEnter();
				if (NetworkServer.active)
				{
					GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
				}
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if (Util.CheckRoll(Util.GetExpAdjustedDropChancePercent(base.missionController.chanceForKeyDrop * 100f, damageReport.victim.gameObject)))
				{
					UnityEngine.Debug.LogFormat("Creating artifact key pickup droplet.");
					PickupDropletController.CreatePickupDroplet(base.missionController.GenerateDrop(), damageReport.victimBody.corePosition, UnityEngine.Vector3.up * 20f);
				}
			}

			public override void OnExit()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && (!base.missionController.artifactShellMaster || !base.missionController.artifactShellMaster.hasBody))
				{
					outer.SetNextState(new WaitForRewardTaken());
				}
			}
		}

		private class WaitForRewardTaken : ArtifactTrialMissionControllerBaseState
		{
			private float timer = 3f;

			protected bool shouldShowBossHealthBar = true;

			public override void OnEnter()
			{
				base.OnEnter();
				if ((bool)base.missionController.destroyDisplayRingObject)
				{
					base.missionController.destroyDisplayRingObject.SetActive(value: true);
				}
				if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion))
				{
					foreach (ChestBehavior instances in InstanceTracker.GetInstancesList<ChestBehavior>())
					{
						instances.CallRpcResetChests();
					}
				}
				if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Devotion))
				{
					DevotionInventoryController.ActivateAllDevotedEvolution();
				}
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && !base.missionController.artifactPickup)
				{
					timer -= Time.fixedDeltaTime;
					if (timer <= 0f)
					{
						outer.SetNextState(new SpawnExitPortalAndIdle());
					}
				}
			}
		}

		private class SpawnExitPortalAndIdle : ArtifactTrialMissionControllerBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				if (NetworkServer.active)
				{
					GameObject obj = UnityEngine.Object.Instantiate(base.missionController.exitPortalPrefab, base.missionController.exitPortalLocation.position, base.missionController.exitPortalLocation.rotation);
					obj.GetComponent<SceneExitController>().useRunNextStageScene = true;
					NetworkServer.Spawn(obj);
				}
			}
		}

		[Header("Artifact")]
		public GenericPickupController artifactPickup;

		public CharacterMaster artifactShellMaster;

		public GameObject destroyDisplayRingObject;

		[Header("Intro Cutscene")]
		public ForcedCamera introCameraController;

		[Header("Mission Key Parameters")]
		public Transform initialKeyLocation;

		public float chanceForKeyDrop = 0.04f;

		public PickupDropTable keyDropTable;

		[Header("Exit Portal")]
		public GameObject exitPortalPrefab;

		public Transform exitPortalLocation;

		[Header("Combat")]
		public CombatDirector[] combatDirectors;

		public BossGroup bossGroup;

		public static ArtifactDef trialArtifact;

		[SyncVar(hook = "TrySetCurrentArtifact")]
		private int currentArtifactIndex = -1;

		private bool artifactWasEnabled;

		private Xoroshiro128Plus rng;

		public ArtifactDef currentArtifact => ArtifactCatalog.GetArtifactDef((ArtifactIndex)currentArtifactIndex);

		public int NetworkcurrentArtifactIndex
		{
			get
			{
				return currentArtifactIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					TrySetCurrentArtifact(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref currentArtifactIndex, 1u);
			}
		}

		public static event Action<ArtifactTrialMissionController, DamageReport> onShellTakeDamageServer;

		public static event Action<ArtifactTrialMissionController, DamageReport> onShellDeathServer;

		private void TrySetCurrentArtifact(int newArtifactIndex)
		{
			UnityEngine.Debug.LogFormat("TrySetCurrentArtifact currentArtifactIndex={0} newArtifactIndex={1}", currentArtifactIndex, newArtifactIndex);
			if (newArtifactIndex != currentArtifactIndex)
			{
				base.syncVarHookGuard = true;
				SetCurrentArtifact(newArtifactIndex);
				base.syncVarHookGuard = false;
			}
		}

		private void SetCurrentArtifact(int newArtifactIndex)
		{
			if ((bool)currentArtifact)
			{
				OnCurrentArtifactLost(currentArtifact);
			}
			NetworkcurrentArtifactIndex = newArtifactIndex;
			if ((bool)currentArtifact)
			{
				OnCurrentArtifactDiscovered(currentArtifact);
			}
		}

		private void Awake()
		{
			if (NetworkServer.active && (bool)trialArtifact)
			{
				TrySetCurrentArtifact((int)trialArtifact.artifactIndex);
				trialArtifact = null;
			}
		}

		private void OnDestroy()
		{
			TrySetCurrentArtifact(-1);
			GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt;
			if (NetworkServer.active)
			{
				RemoveAllMissionKeys();
			}
		}

		public override void OnStartServer()
		{
			base.OnStartServer();
			rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong);
			GlobalEventManager.onServerDamageDealt += OnServerDamageDealt;
			GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			if (!NetworkServer.active)
			{
				SetCurrentArtifact(currentArtifactIndex);
			}
		}

		private void OnCurrentArtifactDiscovered(ArtifactDef artifactDef)
		{
			if (NetworkServer.active && (bool)artifactDef)
			{
				artifactWasEnabled = RunArtifactManager.instance.IsArtifactEnabled(artifactDef);
				RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, newEnabled: true);
				if ((bool)artifactPickup)
				{
					artifactPickup.NetworkpickupIndex = PickupCatalog.FindPickupIndex(artifactDef.artifactIndex);
				}
			}
		}

		private void OnCurrentArtifactLost(ArtifactDef artifactDef)
		{
			if (NetworkServer.active)
			{
				if ((bool)artifactDef && (bool)RunArtifactManager.instance)
				{
					RunArtifactManager.instance.SetArtifactEnabledServer(artifactDef, artifactWasEnabled);
				}
				if ((bool)artifactPickup)
				{
					artifactPickup.NetworkpickupIndex = PickupIndex.none;
				}
			}
		}

		private void OnServerDamageDealt(DamageReport damageReport)
		{
			if ((object)damageReport.victimMaster == artifactShellMaster)
			{
				OnShellTakeDamageServer(damageReport);
			}
		}

		private void OnCharacterDeathGlobal(DamageReport damageReport)
		{
			if ((object)damageReport.victimMaster == artifactShellMaster)
			{
				OnShellDeathServer(damageReport);
			}
		}

		private void OnShellTakeDamageServer(DamageReport damageReport)
		{
			RemoveAllMissionKeys();
			ArtifactTrialMissionController.onShellTakeDamageServer?.Invoke(this, damageReport);
		}

		private void OnShellDeathServer(DamageReport damageReport)
		{
			ArtifactTrialMissionController.onShellDeathServer?.Invoke(this, damageReport);
		}

		public PickupIndex GenerateDrop()
		{
			if ((bool)keyDropTable)
			{
				PickupIndex pickupIndex = keyDropTable.GenerateDrop(rng);
				UnityEngine.Debug.LogFormat("itemIndex = {0}, isValid = {1}, pickupNameToken = {2}", pickupIndex.itemIndex, pickupIndex.isValid, pickupIndex.GetPickupNameToken());
				return keyDropTable.GenerateDrop(rng);
			}
			UnityEngine.Debug.LogError("Failed to generate key drop!");
			return PickupIndex.none;
		}

		public static void RemoveAllMissionKeys()
		{
			ItemIndex itemIndex = RoR2Content.Items.ArtifactKey.itemIndex;
			PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(itemIndex);
			foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
			{
				int itemCount = readOnlyInstances.inventory.GetItemCount(itemIndex);
				if (itemCount > 0)
				{
					readOnlyInstances.inventory.RemoveItem(itemIndex, itemCount);
				}
			}
			List<GenericPickupController> instancesList = InstanceTracker.GetInstancesList<GenericPickupController>();
			for (int num = instancesList.Count - 1; num >= 0; num--)
			{
				GenericPickupController genericPickupController = instancesList[num];
				if (genericPickupController.pickupIndex == pickupIndex)
				{
					UnityEngine.Object.Destroy(genericPickupController.gameObject);
				}
			}
			List<PickupPickerController> instancesList2 = InstanceTracker.GetInstancesList<PickupPickerController>();
			for (int num2 = instancesList2.Count - 1; num2 >= 0; num2--)
			{
				PickupPickerController pickupPickerController = instancesList2[num2];
				if (pickupPickerController.IsChoiceAvailable(pickupIndex))
				{
					UnityEngine.Object.Destroy(pickupPickerController.gameObject);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)currentArtifactIndex);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)currentArtifactIndex);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				currentArtifactIndex = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				TrySetCurrentArtifact((int)reader.ReadPackedUInt32());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class AssignRandomMaterial : MonoBehaviour
	{
		public Renderer rend;

		public Material[] materials;

		private void Awake()
		{
			rend.material = materials[UnityEngine.Random.Range(0, materials.Length)];
		}
	}
	[RequireComponent(typeof(AkGameObj))]
	public class AudioManager : MonoBehaviour
	{
		private class VolumeConVar : BaseConVar
		{
			private readonly string rtpcName;

			private string fallbackString = "100";

			public VolumeConVar(string name, ConVarFlags flags, string defaultValue, string helpText, string rtpcName)
				: base(name, flags, defaultValue, helpText)
			{
				this.rtpcName = rtpcName;
			}

			public override void SetString(string newValue)
			{
				if (!AkSoundEngine.IsInitialized())
				{
					return;
				}
				fallbackString = newValue;
				if (TextSerialization.TryParseInvariant(newValue, out float result))
				{
					if (rtpcName == cvVolumeMaster.rtpcName)
					{
						float num = float.Parse(cvVolumeParentMsx.GetString());
						num *= result / 100f;
						cvVolumeMsx.fallbackString = num.ToString();
						AkSoundEngine.SetRTPCValue(cvVolumeMsx.rtpcName, Mathf.Clamp(num, 0f, 100f));
					}
					else if (rtpcName == cvVolumeParentMsx.rtpcName)
					{
						float num2 = float.Parse(cvVolumeMaster.fallbackString);
						float value = result * (num2 / 100f);
						cvVolumeMsx.fallbackString = value.ToString();
						AkSoundEngine.SetRTPCValue(cvVolumeMsx.rtpcName, Mathf.Clamp(value, 0f, 100f));
						return;
					}
					AkSoundEngine.SetRTPCValue(rtpcName, Mathf.Clamp(result, 0f, 100f));
				}
			}

			public override string GetString()
			{
				int io_rValueType = 1;
				if (AkSoundEngine.GetRTPCValue(rtpcName, ulong.MaxValue, 0u, out var out_rValue, ref io_rValueType) == AKRESULT.AK_Success)
				{
					return TextSerialization.ToStringInvariant(out_rValue);
				}
				return fallbackString;
			}
		}

		private class AudioFocusedOnlyConVar : BaseConVar
		{
			private class ApplicationFocusListener : MonoBehaviour
			{
				public Action<bool> onApplicationFocus;

				private void OnApplicationFocus(bool focus)
				{
					onApplicationFocus?.Invoke(focus);
				}
			}

			private static AudioFocusedOnlyConVar instance = new AudioFocusedOnlyConVar("audio_focused_only", ConVarFlags.Archive | ConVarFlags.Engine, null, "Whether or not audio should mute when focus is lost.");

			private bool onlyPlayWhenFocused;

			private bool isFocused;

			private static MethodInfo akSoundEngineController_ActivateAudio_methodInfo = typeof(AkSoundEngineController).GetMethod("ActivateAudio", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

			public AudioFocusedOnlyConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				isFocused = Application.isFocused;
				RoR2Application.onUpdate += SearchForAkInitializer;
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					onlyPlayWhenFocused = result != 0;
					Refresh();
				}
			}

			public override string GetString()
			{
				if (!onlyPlayWhenFocused)
				{
					return "0";
				}
				return "1";
			}

			private void OnApplicationFocus(bool focus)
			{
				isFocused = focus;
				Refresh();
			}

			private void Refresh()
			{
				bool flag = !isFocused && onlyPlayWhenFocused;
				bool flag2 = false;
				AkSoundEngineController akSoundEngineController = AkSoundEngineController.Instance;
				if (akSoundEngineController != null)
				{
					AkSoundEngineController_ActivateAudio(akSoundEngineController, !flag, !flag2);
				}
			}

			private static void AkSoundEngineController_ActivateAudio(AkSoundEngineController akSoundEngineController, bool activate, bool renderAnyway)
			{
				akSoundEngineController_ActivateAudio_methodInfo.Invoke(akSoundEngineController, new object[2] { activate, renderAnyway });
			}

			private void SearchForAkInitializer()
			{
				AkInitializer akInitializer = (AkInitializer)akInitializerMsInstanceField.GetValue(null);
				if ((bool)akInitializer)
				{
					RoR2Application.onUpdate -= SearchForAkInitializer;
					ApplicationFocusListener applicationFocusListener = akInitializer.gameObject.AddComponent<ApplicationFocusListener>();
					applicationFocusListener.onApplicationFocus = (Action<bool>)Delegate.Combine(applicationFocusListener.onApplicationFocus, new Action<bool>(OnApplicationFocus));
					Refresh();
				}
			}
		}

		private class WwiseLogEnabledConVar : BaseConVar
		{
			private static WwiseLogEnabledConVar instance = new WwiseLogEnabledConVar("wwise_log_enabled", ConVarFlags.Archive | ConVarFlags.Engine, null, "Wwise logging. 0 = disabled 1 = enabled");

			private WwiseLogEnabledConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (!TextSerialization.TryParseInvariant(newValue, out int result))
				{
					return;
				}
				AkInitializer akInitializer = akInitializerMsInstanceField.GetValue(null) as AkInitializer;
				if ((bool)akInitializer)
				{
					AkCallbackManager.InitializationSettings initializationSettings = akInitializer.InitializationSettings?.CallbackManagerInitializationSettings;
					if (initializationSettings != null)
					{
						initializationSettings.IsLoggingEnabled = result != 0;
					}
				}
			}

			public override string GetString()
			{
				AkInitializer akInitializer = akInitializerMsInstanceField.GetValue(null) as AkInitializer;
				if ((bool)akInitializer && akInitializer.InitializationSettings?.CallbackManagerInitializationSettings != null)
				{
					if (!akInitializer.InitializationSettings.CallbackManagerInitializationSettings.IsLoggingEnabled)
					{
						return "0";
					}
					return "1";
				}
				return "1";
			}
		}

		private AkGameObj akGameObj;

		private static VolumeConVar cvVolumeMaster;

		private static VolumeConVar cvVolumeSfx;

		private static VolumeConVar cvVolumeMsx;

		private static VolumeConVar cvVolumeParentMsx;

		private static readonly FieldInfo akInitializerMsInstanceField;

		public static AudioManager instance { get; private set; }

		public static event Action<AudioManager> onAwakeGlobal;

		private void Awake()
		{
			instance = this;
			akGameObj = GetComponent<AkGameObj>();
			AudioManager.onAwakeGlobal?.Invoke(this);
		}

		static AudioManager()
		{
			cvVolumeMaster = new VolumeConVar("volume_master", ConVarFlags.Archive | ConVarFlags.Engine, "100", "The master volume of the game audio, from 0 to 100.", "Volume_Master");
			cvVolumeSfx = new VolumeConVar("volume_sfx", ConVarFlags.Archive | ConVarFlags.Engine, "100", "The volume of sound effects, from 0 to 100.", "Volume_SFX");
			cvVolumeMsx = new VolumeConVar("volume_music", ConVarFlags.Archive | ConVarFlags.Engine, "100", "The music volume, from 0 to 100.", "Volume_MSX");
			cvVolumeParentMsx = new VolumeConVar("parent_volume_music", ConVarFlags.Archive, "100", "The parent music volume, from 0 to 100.", "Parent_Volume_MSX");
			akInitializerMsInstanceField = typeof(AkInitializer).GetField("ms_Instance", BindingFlags.Static | BindingFlags.NonPublic);
			PauseManager.onPauseStartGlobal = (Action)Delegate.Combine(PauseManager.onPauseStartGlobal, (Action)delegate
			{
				AkSoundEngine.PostEvent("Pause_All", ulong.MaxValue);
			});
			PauseManager.onPauseEndGlobal = (Action)Delegate.Combine(PauseManager.onPauseEndGlobal, (Action)delegate
			{
				AkSoundEngine.PostEvent("Unpause_All", ulong.MaxValue);
			});
		}
	}
	public sealed class AurelioniteHeartController : NetworkBehaviour, IInteractable, IDisplayNameProvider
	{
		public string displayNameToken = "AURELIONITE_HEART_NAME";

		public string contextToken;

		public uint expReward;

		[SerializeField]
		private EntityStateMachine entityStateMachine;

		public Animator heartAnimator;

		[SyncVar]
		[HideInInspector]
		public bool activated;

		public GameObject rebirthShrine;

		public bool shouldProximityHighlight = true;

		public bool Networkactivated
		{
			get
			{
				return activated;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref activated, 1u);
			}
		}

		private void Start()
		{
			if ((bool)Run.instance)
			{
				expReward = (uint)((float)expReward * Run.instance.difficultyCoefficient);
			}
		}

		public void OnInteractionBegin(Interactor activator)
		{
			if (!activated)
			{
				Networkactivated = true;
				if ((bool)entityStateMachine)
				{
					entityStateMachine.SetNextState(new AurelioniteHeartActivationState());
				}
				ExperienceManager.instance.AwardExperience(base.transform.position, activator.GetComponent<CharacterBody>(), expReward);
			}
		}

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextToken);
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (activated)
			{
				return Interactability.Disabled;
			}
			return Interactability.Available;
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public void OnEnable()
		{
			InstanceTracker.Add(this);
		}

		public void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			return !activated;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(activated);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(activated);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				activated = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				activated = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class AwakeEvent : MonoBehaviour
	{
		public UnityEvent action;

		private void Awake()
		{
			action.Invoke();
		}
	}
	public sealed class BarrelInteraction : NetworkBehaviour, IInteractable, IDisplayNameProvider
	{
		public int goldReward;

		public uint expReward;

		public string displayNameToken = "BARREL1_NAME";

		public string contextToken;

		public bool shouldProximityHighlight = true;

		[SyncVar]
		private bool opened;

		public bool Networkopened
		{
			get
			{
				return opened;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref opened, 1u);
			}
		}

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextToken);
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (opened)
			{
				return Interactability.Disabled;
			}
			return Interactability.Available;
		}

		private void Start()
		{
			if ((bool)Run.instance)
			{
				goldReward = (int)((float)goldReward * Run.instance.difficultyCoefficient);
				expReward = (uint)((float)expReward * Run.instance.difficultyCoefficient);
			}
		}

		[Server]
		public void OnInteractionBegin(Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.BarrelInteraction::OnInteractionBegin(RoR2.Interactor)' called on client");
			}
			else if (!opened)
			{
				Networkopened = true;
				EntityStateMachine component = GetComponent<EntityStateMachine>();
				if ((bool)component)
				{
					component.SetNextState(new EntityStates.Barrel.Opening());
				}
				CharacterBody component2 = activator.GetComponent<CharacterBody>();
				if ((bool)component2)
				{
					TeamIndex objectTeam = TeamComponent.GetObjectTeam(component2.gameObject);
					TeamManager.instance.GiveTeamMoney(objectTeam, (uint)goldReward);
				}
				CoinDrop();
				ExperienceManager.instance.AwardExperience(base.transform.position, activator.GetComponent<CharacterBody>(), expReward);
			}
		}

		[Server]
		private void CoinDrop()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.BarrelInteraction::CoinDrop()' called on client");
				return;
			}
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/CoinEmitter"), new EffectData
			{
				origin = base.transform.position,
				genericFloat = goldReward
			}, transmit: true);
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public void OnEnable()
		{
			InstanceTracker.Add(this);
		}

		public void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			return !opened;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(opened);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(opened);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				opened = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				opened = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class BaseDefenseRun : Run
	{
		protected new void Awake()
		{
			base.Awake();
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public abstract class BaseZoneBehavior : NetworkBehaviour, IZone
	{
		public abstract bool IsInBounds(UnityEngine.Vector3 position);

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class BasicBezierSpline : MonoBehaviour, ISerializationCallbackReceiver
	{
		private struct KeyFrame
		{
			public CubicBezier3 curve;

			public float approximateLength;
		}

		public BasicBezierSplineControlPoint[] controlPoints = Array.Empty<BasicBezierSplineControlPoint>();

		public int samplesPerSegment = 20;

		private KeyFrame[] keyFrames = Array.Empty<KeyFrame>();

		private UnityEngine.Vector3[] samplesBuffer = Array.Empty<UnityEngine.Vector3>();

		private float totalLength;

		private bool keyFramesDirty = true;

		private void BuildKeyFrames()
		{
			totalLength = 0f;
			Array.Resize(ref keyFrames, controlPoints.Length);
			Array.Resize(ref samplesBuffer, samplesPerSegment);
			int i = 0;
			for (int num = controlPoints.Length - 1; i < num; i++)
			{
				BasicBezierSplineControlPoint basicBezierSplineControlPoint = controlPoints[i];
				BasicBezierSplineControlPoint basicBezierSplineControlPoint2 = controlPoints[i + 1];
				if (!basicBezierSplineControlPoint || !basicBezierSplineControlPoint2)
				{
					break;
				}
				CubicBezier3 curveSegment = GetCurveSegment(basicBezierSplineControlPoint, basicBezierSplineControlPoint2);
				float num2 = curveSegment.ApproximateLength(samplesPerSegment);
				keyFrames[i] = new KeyFrame
				{
					curve = curveSegment,
					approximateLength = num2
				};
				totalLength += num2;
			}
		}

		public UnityEngine.Vector3 Evaluate(float normalizedPosition)
		{
			if (keyFramesDirty)
			{
				if (Application.isPlaying)
				{
					keyFramesDirty = false;
				}
				BuildKeyFrames();
			}
			float num = normalizedPosition * totalLength;
			float num2 = 0f;
			int i = 0;
			for (int num3 = keyFrames.Length; i < num3; i++)
			{
				ref KeyFrame reference = ref keyFrames[i];
				float a = num2;
				num2 += reference.approximateLength;
				if (num2 >= num)
				{
					float t = Mathf.InverseLerp(a, num2, num);
					return EvaluateKeyFrame(t, in reference);
				}
			}
			if (keyFrames.Length != 0)
			{
				return keyFrames[keyFrames.Length - 1].curve.p1;
			}
			return UnityEngine.Vector3.zero;
		}

		private UnityEngine.Vector3 EvaluateKeyFrame(float t, in KeyFrame keyFrame)
		{
			float num = t * keyFrame.approximateLength;
			keyFrame.curve.ToVertices(samplesBuffer);
			float a = 0f;
			float num2 = 0f;
			UnityEngine.Vector3 vector = samplesBuffer[0];
			for (int i = 1; i < samplesBuffer.Length; i++)
			{
				UnityEngine.Vector3 vector2 = samplesBuffer[i];
				float num3 = UnityEngine.Vector3.Distance(vector2, vector);
				num2 += num3;
				if (num2 >= num)
				{
					return UnityEngine.Vector3.Lerp(vector, vector2, Mathf.InverseLerp(a, num2, num));
				}
				vector = vector2;
				a = num2;
			}
			return keyFrame.curve.p1;
		}

		private void DrawKeyFrame(in KeyFrame keyFrame)
		{
			Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.green, UnityEngine.Color.black, 0.5f);
			Gizmos.DrawRay(keyFrame.curve.p0, keyFrame.curve.v0);
			Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.red, UnityEngine.Color.black, 0.5f);
			Gizmos.DrawRay(keyFrame.curve.p1, keyFrame.curve.v1);
			for (int i = 1; i <= 20; i++)
			{
				float num = (float)i * 0.05f;
				Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.red, UnityEngine.Color.green, num);
				UnityEngine.Vector3 vector = keyFrame.curve.Evaluate(num - 0.05f);
				UnityEngine.Vector3 vector2 = keyFrame.curve.Evaluate(num);
				Gizmos.DrawRay(vector, vector2 - vector);
			}
		}

		public void OnDrawGizmos()
		{
			if (keyFramesDirty)
			{
				if (Application.isPlaying)
				{
					keyFramesDirty = false;
				}
				BuildKeyFrames();
			}
			for (int i = 0; i < keyFrames.Length; i++)
			{
				DrawKeyFrame(in keyFrames[i]);
			}
		}

		public static CubicBezier3 GetCurveSegment(BasicBezierSplineControlPoint startControlPoint, BasicBezierSplineControlPoint endControlPoint)
		{
			Transform obj = startControlPoint.transform;
			Transform transform = endControlPoint.transform;
			UnityEngine.Vector3 position = obj.position;
			UnityEngine.Vector3 v = obj.rotation * startControlPoint.forwardVelocity;
			UnityEngine.Vector3 position2 = transform.position;
			UnityEngine.Vector3 v2 = transform.rotation * endControlPoint.backwardVelocity;
			return CubicBezier3.FromVelocities(position, v, position2, v2);
		}

		public void OnBeforeSerialize()
		{
		}

		public void OnAfterDeserialize()
		{
			keyFramesDirty = true;
		}
	}
	public class BasicBezierSplineControlPoint : MonoBehaviour
	{
		public UnityEngine.Vector3 forwardVelocity = UnityEngine.Vector3.forward;

		public UnityEngine.Vector3 backwardVelocity = UnityEngine.Vector3.back;

		private void OnDrawGizmos()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			UnityEngine.Matrix4x4 identity = UnityEngine.Matrix4x4.identity;
			identity.SetTRS(base.transform.position, base.transform.rotation, UnityEngine.Vector3.one);
			Gizmos.matrix = identity;
			Gizmos.DrawRay(UnityEngine.Vector3.zero, forwardVelocity);
			Gizmos.DrawRay(UnityEngine.Vector3.zero, backwardVelocity);
			Gizmos.DrawFrustum(UnityEngine.Vector3.zero, 60f, -0.2f, 0f, 1f);
		}
	}
	public class BazaarController : MonoBehaviour
	{
		[Serializable]
		public struct SeerSceneOverride
		{
			[SerializeField]
			public SceneDef sceneDef;

			[SerializeField]
			public ExpansionDef requiredExpasion;

			[SerializeField]
			[Range(0f, 1f)]
			public float overrideChance;

			[SerializeField]
			public int minStagesCleared;

			[SerializeField]
			public string bannedEventFlag;
		}

		public GameObject shopkeeper;

		public TextMeshPro shopkeeperChat;

		public float shopkeeperTrackDistance = 250f;

		public float shopkeeperTrackAngle = 120f;

		[Tooltip("Any PurchaseInteraction objects here will have their activation state set based on whether or not the specified unlockable is available.")]
		public PurchaseInteraction[] unlockableTerminals;

		public SeerStationController[] seerStations;

		public SeerSceneOverride[] seerSceneOverrides;

		private InputBankTest shopkeeperInputBank;

		private CharacterBody shopkeeperTargetBody;

		private Xoroshiro128Plus rng;

		public static BazaarController instance { get; private set; }

		private void Awake()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				OnStartServer();
			}
		}

		private void OnStartServer()
		{
			rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong);
			SetUpSeerStations();
		}

		private void SetUpSeerStations()
		{
			SceneDef nextStageScene = Run.instance.nextStageScene;
			List<SceneDef> list = new List<SceneDef>();
			if (nextStageScene != null)
			{
				int stageOrder = nextStageScene.stageOrder;
				foreach (SceneDef allSceneDef in SceneCatalog.allSceneDefs)
				{
					if (allSceneDef.stageOrder == stageOrder && (allSceneDef.requiredExpansion == null || Run.instance.IsExpansionEnabled(allSceneDef.requiredExpansion)) && IsUnlockedBeforeLooping(allSceneDef))
					{
						list.Add(allSceneDef);
					}
				}
			}
			WeightedSelection<SceneDef> weightedSelection = new WeightedSelection<SceneDef>();
			float num = 0f;
			SeerSceneOverride[] array = seerSceneOverrides;
			for (int i = 0; i < array.Length; i++)
			{
				SeerSceneOverride seerSceneOverride = array[i];
				bool num2 = Run.instance.stageClearCount >= seerSceneOverride.minStagesCleared;
				bool flag = seerSceneOverride.requiredExpasion == null || Run.instance.IsExpansionEnabled(seerSceneOverride.requiredExpasion);
				bool flag2 = string.IsNullOrEmpty(seerSceneOverride.bannedEventFlag) || !Run.instance.GetEventFlag(seerSceneOverride.bannedEventFlag);
				if (num2 && flag && flag2)
				{
					weightedSelection.AddChoice(seerSceneOverride.sceneDef, seerSceneOverride.overrideChance);
					num += seerSceneOverride.overrideChance;
				}
			}
			SeerStationController[] array2 = seerStations;
			foreach (SeerStationController seerStationController in array2)
			{
				if (list.Count == 0)
				{
					seerStationController.GetComponent<PurchaseInteraction>().SetAvailable(newAvailable: false);
					continue;
				}
				Util.ShuffleList(list, rng);
				int index = list.Count - 1;
				SceneDef sceneDef = list[index];
				if (rng.nextNormalizedFloat < num)
				{
					sceneDef = weightedSelection.Evaluate(rng.nextNormalizedFloat);
				}
				if (IsSceneAlreadySelected(sceneDef))
				{
					sceneDef = list[index];
				}
				list.RemoveAt(index);
				seerStationController.SetTargetScene(sceneDef);
			}
		}

		private bool IsUnlockedBeforeLooping(SceneDef sceneDef)
		{
			if (Run.instance.stageClearCount < 4 && sceneDef.isLockedBeforeLooping)
			{
				return false;
			}
			return true;
		}

		private bool IsSceneAlreadySelected(SceneDef sceneDef)
		{
			for (int i = 0; i < seerStations.Length; i++)
			{
				if (sceneDef.sceneDefIndex == (SceneIndex)seerStations[i].ReturnTargetSceneDefIndex())
				{
					return true;
				}
			}
			return false;
		}

		private void OnDestroy()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		public void CommentOnAnnoy()
		{
			int maxExclusive = 6;
			if (Util.CheckRoll(20f))
			{
				Chat.SendBroadcastChat(new Chat.NpcChatMessage
				{
					sender = shopkeeper,
					baseToken = "NEWT_ANNOY_" + UnityEngine.Random.Range(1, maxExclusive)
				});
			}
		}

		public void CommentOnEnter()
		{
		}

		public void CommentOnLeaving()
		{
		}

		public void CommentOnLunarPurchase()
		{
			int maxExclusive = 8;
			if (Util.CheckRoll(20f))
			{
				Chat.SendBroadcastChat(new Chat.NpcChatMessage
				{
					sender = shopkeeper,
					baseToken = "NEWT_LUNAR_PURCHASE_" + UnityEngine.Random.Range(1, maxExclusive)
				});
			}
		}

		public void CommentOnBlueprintPurchase()
		{
		}

		public void CommentOnDronePurchase()
		{
		}

		public void CommentOnUpgrade()
		{
			int maxExclusive = 3;
			if (Util.CheckRoll(100f))
			{
				Chat.SendBroadcastChat(new Chat.NpcChatMessage
				{
					sender = shopkeeper,
					baseToken = "NEWT_UPGRADE_" + UnityEngine.Random.Range(1, maxExclusive)
				});
			}
		}

		private void Update()
		{
			if (!shopkeeper)
			{
				return;
			}
			if (!shopkeeperInputBank)
			{
				shopkeeperInputBank = shopkeeper.GetComponent<InputBankTest>();
				return;
			}
			Ray aimRay = new Ray(shopkeeperInputBank.aimOrigin, shopkeeper.transform.forward);
			shopkeeperTargetBody = Util.GetEnemyEasyTarget(shopkeeper.GetComponent<CharacterBody>(), aimRay, shopkeeperTrackDistance, shopkeeperTrackAngle);
			if ((bool)shopkeeperTargetBody)
			{
				UnityEngine.Vector3 direction = shopkeeperTargetBody.mainHurtBox.transform.position - aimRay.origin;
				aimRay.direction = direction;
			}
			shopkeeperInputBank.aimDirection = aimRay.direction;
		}
	}
	public sealed class BazaarUpgradeInteraction : NetworkBehaviour, IInteractable, IHologramContentProvider, IDisplayNameProvider
	{
		[SyncVar]
		public bool available = true;

		public string displayNameToken;

		public int cost;

		public string contextToken;

		public string[] unlockableProgression;

		private UnlockableDef[] unlockableProgressionDefs;

		public float activationCooldownDuration = 1f;

		private float activationTimer;

		public GameObject purchaseEffect;

		public bool shouldProximityHighlight = true;

		private static readonly Color32 lunarCoinColor = new Color32(198, 173, 250, byte.MaxValue);

		private static readonly string lunarCoinColorString = Util.RGBToHex(lunarCoinColor);

		public bool Networkavailable
		{
			get
			{
				return available;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref available, 1u);
			}
		}

		private void Awake()
		{
			unlockableProgressionDefs = new UnlockableDef[unlockableProgression.Length];
			for (int i = 0; i < unlockableProgressionDefs.Length; i++)
			{
				unlockableProgressionDefs[i] = UnlockableCatalog.GetUnlockableDef(unlockableProgression[i]);
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active && !available)
			{
				activationTimer -= Time.fixedDeltaTime;
				if (activationTimer <= 0f)
				{
					Networkavailable = true;
				}
			}
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		private UnlockableDef GetInteractorNextUnlockable(GameObject activatorGameObject)
		{
			NetworkUser networkUser = Util.LookUpBodyNetworkUser(activatorGameObject);
			if ((bool)networkUser)
			{
				LocalUser localUser = networkUser.localUser;
				if (localUser != null)
				{
					for (int i = 0; i < unlockableProgressionDefs.Length; i++)
					{
						UnlockableDef unlockableDef = unlockableProgressionDefs[i];
						if (!localUser.userProfile.HasUnlockable(unlockableDef))
						{
							return unlockableDef;
						}
					}
				}
				else
				{
					for (int j = 0; j < unlockableProgressionDefs.Length; j++)
					{
						UnlockableDef unlockableDef2 = unlockableProgressionDefs[j];
						if (!networkUser.unlockables.Contains(unlockableDef2))
						{
							return unlockableDef2;
						}
					}
				}
			}
			return null;
		}

		private static bool ActivatorHasUnlockable(Interactor activator, string unlockableName)
		{
			NetworkUser networkUser = Util.LookUpBodyNetworkUser(activator.gameObject);
			if ((bool)networkUser)
			{
				return networkUser.localUser?.userProfile.HasUnlockable(unlockableName) ?? networkUser.unlockables.Contains(UnlockableCatalog.GetUnlockableDef(unlockableName));
			}
			return true;
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		private string GetCostString()
		{
			return string.Format(" (<color=#{1}>{0}</color>)", cost, lunarCoinColorString);
		}

		public string GetContextString(Interactor activator)
		{
			if (!CanBeAffordedByInteractor(activator))
			{
				return null;
			}
			return Language.GetString(contextToken) + GetCostString();
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (GetInteractorNextUnlockable(activator.gameObject) == null || !available)
			{
				return Interactability.Disabled;
			}
			if (!CanBeAffordedByInteractor(activator))
			{
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Available;
		}

		public void OnInteractionBegin(Interactor activator)
		{
		}

		private int GetCostForInteractor(Interactor activator)
		{
			return cost;
		}

		public bool CanBeAffordedByInteractor(Interactor activator)
		{
			NetworkUser networkUser = Util.LookUpBodyNetworkUser(activator.gameObject);
			if ((bool)networkUser)
			{
				return networkUser.lunarCoins >= GetCostForInteractor(activator);
			}
			return false;
		}

		public bool ShouldDisplayHologram(GameObject viewer)
		{
			return GetInteractorNextUnlockable(viewer) != null;
		}

		public GameObject GetHologramContentPrefab()
		{
			return LegacyResourcesAPI.Load<GameObject>("Prefabs/CostHologramContent");
		}

		public void UpdateHologramContent(GameObject hologramContentObject, Transform viewer)
		{
			CostHologramContent component = hologramContentObject.GetComponent<CostHologramContent>();
			if ((bool)component)
			{
				component.displayValue = cost;
				component.costType = CostTypeIndex.LunarCoin;
			}
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			return available;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(available);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(available);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				available = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				available = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class Billboard : MonoBehaviour
	{
		private static List<Transform> instanceTransformsList;

		static Billboard()
		{
			instanceTransformsList = new List<Transform>();
			SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull;
		}

		private static void OnSceneCameraPreCull(SceneCamera sceneCamera)
		{
			UnityEngine.Quaternion rotation = sceneCamera.transform.rotation;
			for (int i = 0; i < instanceTransformsList.Count; i++)
			{
				instanceTransformsList[i].rotation = rotation;
			}
		}

		private void OnEnable()
		{
			instanceTransformsList.Add(base.transform);
		}

		private void OnDisable()
		{
			instanceTransformsList.Remove(base.transform);
		}
	}
	public class BloodSiphonNearbyController : NetworkBehaviour
	{
		[UnityEngine.Min(float.Epsilon)]
		public float minHealthFractionCoefficient;

		public float maxHealthFractionCoefficient;

		public float tickRate = 1f;

		public DamageTypeCombo damageType;

		[SyncVar]
		public int maxTargets;

		public TetherVfxOrigin tetherVfxOrigin;

		public GameObject activeVfx;

		protected new Transform transform;

		private HoldoutZoneController holdoutZone;

		protected SphereSearch sphereSearch;

		protected float timer;

		protected float currentRadius;

		private bool isTetheredToAtLeastOneObject;

		public int NetworkmaxTargets
		{
			get
			{
				return maxTargets;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref maxTargets, 1u);
			}
		}

		protected void Awake()
		{
			transform = base.transform;
			sphereSearch = new SphereSearch();
			timer = 0f;
			holdoutZone = GetComponentInParent<HoldoutZoneController>();
		}

		protected void FixedUpdate()
		{
			timer -= Time.fixedDeltaTime;
			if (timer <= 0f)
			{
				timer += 1f / tickRate;
				Tick();
			}
		}

		private void OnTransformParentChanged()
		{
			holdoutZone = GetComponentInParent<HoldoutZoneController>();
		}

		protected void Tick()
		{
			if ((bool)holdoutZone)
			{
				currentRadius = holdoutZone.currentRadius;
			}
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			SearchForTargets(list);
			float num = minHealthFractionCoefficient;
			if ((bool)holdoutZone)
			{
				num = Mathf.Lerp(minHealthFractionCoefficient, maxHealthFractionCoefficient, holdoutZone.charge);
			}
			float num2 = num / tickRate;
			List<Transform> list2 = CollectionPool<Transform, List<Transform>>.RentCollection();
			for (int i = 0; i < list.Count; i++)
			{
				HurtBox hurtBox = list[i];
				if ((bool)hurtBox && (bool)hurtBox.healthComponent && hurtBox.healthComponent.alive)
				{
					HealthComponent healthComponent = hurtBox.healthComponent;
					Transform transform = healthComponent.body.coreTransform ?? hurtBox.transform;
					list2.Add(transform);
					if (NetworkServer.active)
					{
						DamageInfo damageInfo = new DamageInfo();
						damageInfo.attacker = null;
						damageInfo.inflictor = base.gameObject;
						damageInfo.position = transform.position;
						damageInfo.crit = false;
						damageInfo.damage = num2 * healthComponent.fullCombinedHealth;
						damageInfo.damageColorIndex = DamageColorIndex.Bleed;
						damageInfo.damageType = damageType;
						damageInfo.force = UnityEngine.Vector3.zero;
						damageInfo.procCoefficient = 0f;
						damageInfo.procChainMask = default(ProcChainMask);
						hurtBox.healthComponent.TakeDamage(damageInfo);
					}
				}
				if (list2.Count >= maxTargets)
				{
					break;
				}
			}
			isTetheredToAtLeastOneObject = (float)list2.Count > 0f;
			if ((bool)tetherVfxOrigin)
			{
				tetherVfxOrigin.SetTetheredTransforms(list2);
			}
			if ((bool)activeVfx)
			{
				activeVfx.SetActive(isTetheredToAtLeastOneObject);
			}
			CollectionPool<Transform, List<Transform>>.ReturnCollection(list2);
			CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}

		protected void SearchForTargets(List<HurtBox> dest)
		{
			if (currentRadius > 0f)
			{
				TeamMask mask = default(TeamMask);
				mask.AddTeam(TeamIndex.Player);
				sphereSearch.mask = LayerIndex.entityPrecise.mask;
				sphereSearch.origin = transform.position;
				sphereSearch.radius = currentRadius;
				sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
				sphereSearch.RefreshCandidates();
				sphereSearch.FilterCandidatesByHurtBoxTeam(mask);
				sphereSearch.OrderCandidatesByDistance();
				sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
				sphereSearch.GetHurtBoxes(dest);
				sphereSearch.ClearCandidates();
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)maxTargets);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)maxTargets);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				maxTargets = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				maxTargets = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class BlueprintController : MonoBehaviour
	{
		[NonSerialized]
		public bool ok;

		public Material okMaterial;

		public Material invalidMaterial;

		public Renderer[] renderers;

		private new Transform transform;

		private void Awake()
		{
			transform = base.transform;
		}

		private void Update()
		{
			Material sharedMaterial = (ok ? okMaterial : invalidMaterial);
			for (int i = 0; i < renderers.Length; i++)
			{
				renderers[i].sharedMaterial = sharedMaterial;
			}
		}

		public void PushState(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, bool ok)
		{
			transform.position = position;
			transform.rotation = rotation;
			this.ok = ok;
		}
	}
	public class BlueprintTerminal : NetworkBehaviour
	{
		[Serializable]
		public struct UnlockableOption
		{
			[Obsolete("'unlockableName' will be discontinued. Use 'unlockableDef' instead.", false)]
			[Tooltip("'unlockableName' will be discontinued. Use 'unlockableDef' instead.")]
			public string unlockableName;

			public UnlockableDef unlockableDef;

			public int cost;

			public float weight;

			public UnlockableDef GetResolvedUnlockableDef()
			{
				string text = unlockableName;
				if (!unlockableDef && !string.IsNullOrEmpty(text))
				{
					unlockableDef = UnlockableCatalog.GetUnlockableDef(text);
				}
				return unlockableDef;
			}
		}

		[SyncVar(hook = "SetHasBeenPurchased")]
		private bool hasBeenPurchased;

		public Transform displayBaseTransform;

		[Tooltip("The unlockables to grant")]
		public UnlockableOption[] unlockableOptions;

		private int unlockableChoice;

		public string unlockSoundString;

		public float idealDisplayVolume = 1.5f;

		public GameObject unlockEffect;

		private GameObject displayInstance;

		public bool NetworkhasBeenPurchased
		{
			get
			{
				return hasBeenPurchased;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetHasBeenPurchased(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref hasBeenPurchased, 1u);
			}
		}

		private void SetHasBeenPurchased(bool newHasBeenPurchased)
		{
			if (hasBeenPurchased != newHasBeenPurchased)
			{
				NetworkhasBeenPurchased = newHasBeenPurchased;
				Rebuild();
			}
		}

		public void Start()
		{
			if (NetworkServer.active)
			{
				RollChoice();
			}
			if (NetworkClient.active)
			{
				Rebuild();
			}
		}

		private void RollChoice()
		{
			WeightedSelection<int> weightedSelection = new WeightedSelection<int>();
			for (int i = 0; i < unlockableOptions.Length; i++)
			{
				weightedSelection.AddChoice(i, unlockableOptions[i].weight);
			}
			unlockableChoice = weightedSelection.Evaluate(UnityEngine.Random.value);
			Rebuild();
		}

		private void Rebuild()
		{
			UnlockableOption unlockableOption = unlockableOptions[unlockableChoice];
			if ((bool)displayInstance)
			{
				UnityEngine.Object.Destroy(displayInstance);
			}
			displayBaseTransform.gameObject.SetActive(!hasBeenPurchased);
			if (!hasBeenPurchased && (bool)displayBaseTransform)
			{
				UnlockableDef resolvedUnlockableDef = unlockableOption.GetResolvedUnlockableDef();
				if ((bool)resolvedUnlockableDef)
				{
					GameObject displayModelPrefab = resolvedUnlockableDef.displayModelPrefab;
					if ((bool)displayModelPrefab)
					{
						displayInstance = UnityEngine.Object.Instantiate(displayModelPrefab, displayBaseTransform.position, displayBaseTransform.transform.rotation, displayBaseTransform);
						Renderer componentInChildren = displayInstance.GetComponentInChildren<Renderer>();
						float num = 1f;
						if ((bool)componentInChildren)
						{
							displayInstance.transform.rotation = UnityEngine.Quaternion.identity;
							UnityEngine.Vector3 size = componentInChildren.bounds.size;
							float f = size.x * size.y * size.z;
							num *= Mathf.Pow(idealDisplayVolume, 1f / 3f) / Mathf.Pow(f, 1f / 3f);
						}
						displayInstance.transform.localScale = new UnityEngine.Vector3(num, num, num);
					}
				}
			}
			PurchaseInteraction component = GetComponent<PurchaseInteraction>();
			if ((bool)component)
			{
				component.Networkcost = unlockableOption.cost;
			}
		}

		[Server]
		public void GrantUnlock(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.BlueprintTerminal::GrantUnlock(RoR2.Interactor)' called on client");
				return;
			}
			SetHasBeenPurchased(newHasBeenPurchased: true);
			UnlockableOption unlockableOption = unlockableOptions[unlockableChoice];
			UnlockableDef resolvedUnlockableDef = unlockableOption.GetResolvedUnlockableDef();
			EffectManager.SpawnEffect(unlockEffect, new EffectData
			{
				origin = base.transform.position
			}, transmit: true);
			if ((bool)Run.instance)
			{
				Util.PlaySound(unlockSoundString, interactor.gameObject);
				CharacterBody component = interactor.GetComponent<CharacterBody>();
				Run.instance.GrantUnlockToSinglePlayer(resolvedUnlockableDef, component);
				string pickupToken = "???";
				if (resolvedUnlockableDef != null)
				{
					pickupToken = resolvedUnlockableDef.nameToken;
				}
				Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage
				{
					subjectAsCharacterBody = component,
					baseToken = "PLAYER_PICKUP",
					pickupToken = pickupToken,
					pickupColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unlockable),
					pickupQuantity = 1u
				});
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(hasBeenPurchased);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(hasBeenPurchased);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				hasBeenPurchased = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetHasBeenPurchased(reader.ReadBoolean());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class BodyAnimatorSmoothingParameters : MonoBehaviour
	{
		[Serializable]
		public struct SmoothingParameters
		{
			public float walkMagnitudeSmoothDamp;

			public float walkAngleSmoothDamp;

			public float forwardSpeedSmoothDamp;

			public float rightSpeedSmoothDamp;

			public float intoJumpTransitionTime;

			public float turnAngleSmoothDamp;
		}

		public SmoothingParameters smoothingParameters;

		public static SmoothingParameters defaultParameters = new SmoothingParameters
		{
			walkMagnitudeSmoothDamp = 0.2f,
			walkAngleSmoothDamp = 0.2f,
			forwardSpeedSmoothDamp = 0.1f,
			rightSpeedSmoothDamp = 0.1f,
			intoJumpTransitionTime = 0.05f,
			turnAngleSmoothDamp = 1f
		};
	}
	public class BoneParticleController : MonoBehaviour
	{
		public GameObject childParticlePrefab;

		public float spawnFrequency;

		public SkinnedMeshRenderer skinnedMeshRenderer;

		private float stopwatch;

		private List<Transform> bonesList;

		private void Start()
		{
			bonesList = new List<Transform>();
			Transform[] bones = skinnedMeshRenderer.bones;
			foreach (Transform transform in bones)
			{
				if (transform.name.IndexOf("IK", StringComparison.OrdinalIgnoreCase) == -1 && transform.name.IndexOf("Root", StringComparison.OrdinalIgnoreCase) == -1 && transform.name.IndexOf("Base", StringComparison.OrdinalIgnoreCase) == -1)
				{
					UnityEngine.Debug.LogFormat("added bone {0}", transform);
					bonesList.Add(transform);
				}
			}
		}

		private void Update()
		{
			if (!skinnedMeshRenderer)
			{
				return;
			}
			stopwatch += Time.deltaTime;
			if (stopwatch > 1f / spawnFrequency)
			{
				stopwatch -= 1f / spawnFrequency;
				int count = bonesList.Count;
				Transform transform = bonesList[UnityEngine.Random.Range(0, count)];
				if ((bool)transform)
				{
					UnityEngine.Object.Instantiate(childParticlePrefab, transform.transform.position, UnityEngine.Quaternion.identity, transform);
				}
			}
		}
	}
	public class BoneShrink : MonoBehaviour
	{
		private new Transform transform;

		private void Awake()
		{
			transform = base.transform;
		}

		private void LateUpdate()
		{
			transform.localScale = new UnityEngine.Vector3(0.01f, 0.01f, 0.01f);
		}
	}
	[RequireComponent(typeof(CombatSquad))]
	public class BossGroup : MonoBehaviour
	{
		private struct BossMemory
		{
			public NetworkInstanceId masterInstanceId;

			public float maxObservedMaxHealth;

			public float lastObservedHealth;

			public CharacterMaster cachedMaster;

			public CharacterBody cachedBody;
		}

		private class DefeatBossObjectiveTracker : ObjectivePanelController.ObjectiveTracker
		{
			public DefeatBossObjectiveTracker()
			{
				baseToken = "OBJECTIVE_DEFEAT_BOSS";
			}
		}

		public class EnableHudHealthBarState : EntityState
		{
			private BossGroup bossGroup;

			public override void OnEnter()
			{
				base.OnEnter();
				bossGroup = GetComponent<BossGroup>();
				if ((object)bossGroup != null)
				{
					bossGroup.shouldDisplayHealthBarOnHud = true;
				}
			}

			public override void OnExit()
			{
				if ((object)bossGroup != null)
				{
					bossGroup.shouldDisplayHealthBarOnHud = false;
				}
				base.OnExit();
			}
		}

		public float bossDropChance = 0.15f;

		public Transform dropPosition;

		public PickupDropTable dropTable;

		public bool scaleRewardsByPlayerCount = true;

		[Tooltip("Whether or not this boss group should display a health bar on the HUD while any of its members are alive. Other scripts can change this at runtime to suppress a health bar until the boss is angered, for example. This field is not networked, so whatever is driving the value should be synchronized over the network.")]
		public bool shouldDisplayHealthBarOnHud = true;

		private Xoroshiro128Plus rng;

		private List<PickupDropTable> bossDropTables;

		private Run.FixedTimeStamp enabledTime;

		[Header("Deprecated")]
		public bool forceTier3Reward;

		private List<PickupIndex> bossDrops;

		private static readonly int initialBossMemoryCapacity = 8;

		private BossMemory[] bossMemories = new BossMemory[initialBossMemoryCapacity];

		private int bossMemoryCount;

		private static int lastTotalBossCount = 0;

		private static bool totalBossCountDirty = false;

		public float fixedAge => combatSquad.awakeTime.timeSince;

		public float fixedTimeSinceEnabled => enabledTime.timeSince;

		public int bonusRewardCount { get; set; }

		public CombatSquad combatSquad { get; private set; }

		public string bestObservedName { get; private set; } = "";


		public string bestObservedSubtitle { get; private set; } = "";


		public float totalMaxObservedMaxHealth { get; private set; }

		public float totalObservedHealth { get; private set; }

		public static event Action<BossGroup> onBossGroupStartServer;

		public static event Action<BossGroup> onBossGroupDefeatedServer;

		private void Awake()
		{
			base.enabled = false;
			combatSquad = GetComponent<CombatSquad>();
			combatSquad.onMemberDiscovered += OnMemberDiscovered;
			combatSquad.onMemberLost += OnMemberLost;
			if (NetworkServer.active)
			{
				combatSquad.onDefeatedServer += OnDefeatedServer;
				combatSquad.onMemberAddedServer += OnMemberAddedServer;
				combatSquad.onMemberDefeatedServer += OnMemberDefeatedServer;
				rng = new Xoroshiro128Plus(Run.instance.bossRewardRng.nextUlong);
				bossDrops = new List<PickupIndex>();
				bossDropTables = new List<PickupDropTable>();
			}
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				BossGroup.onBossGroupStartServer?.Invoke(this);
			}
		}

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			ObjectivePanelController.collectObjectiveSources += ReportObjective;
			enabledTime = Run.FixedTimeStamp.now;
		}

		private void OnDisable()
		{
			ObjectivePanelController.collectObjectiveSources -= ReportObjective;
			InstanceTracker.Remove(this);
		}

		private void FixedUpdate()
		{
			UpdateBossMemories();
		}

		private void OnDefeatedServer()
		{
			DropRewards();
			Run.instance.OnServerBossDefeated(this);
			BossGroup.onBossGroupDefeatedServer?.Invoke(this);
		}

		private void OnMemberAddedServer(CharacterMaster memberMaster)
		{
			Run.instance.OnServerBossAdded(this, memberMaster);
		}

		private void OnMemberDefeatedServer(CharacterMaster memberMaster, DamageReport damageReport)
		{
			DeathRewards deathRewards = memberMaster.GetBodyObject()?.GetComponent<DeathRewards>();
			if (!deathRewards)
			{
				return;
			}
			if ((bool)deathRewards.bossDropTable)
			{
				bossDropTables.Add(deathRewards.bossDropTable);
				return;
			}
			PickupIndex pickupIndex = (PickupIndex)deathRewards.bossPickup;
			if (pickupIndex != PickupIndex.none)
			{
				bossDrops.Add(pickupIndex);
			}
		}

		private void OnMemberDiscovered(CharacterMaster memberMaster)
		{
			base.enabled = true;
			memberMaster.isBoss = true;
			totalBossCountDirty = true;
			RememberBoss(memberMaster);
		}

		private void OnMemberLost(CharacterMaster memberMaster)
		{
			memberMaster.isBoss = false;
			totalBossCountDirty = true;
			if (combatSquad.memberCount == 0)
			{
				base.enabled = false;
			}
		}

		private void DropRewards()
		{
			if (!Run.instance)
			{
				UnityEngine.Debug.LogError("No valid run instance!");
				return;
			}
			if (rng == null)
			{
				UnityEngine.Debug.LogError("RNG is null!");
				return;
			}
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (participatingPlayerCount == 0)
			{
				return;
			}
			if ((bool)dropPosition)
			{
				PickupIndex none = PickupIndex.none;
				if ((bool)dropTable)
				{
					none = dropTable.GenerateDrop(rng);
				}
				else
				{
					List<PickupIndex> list = Run.instance.availableTier2DropList;
					if (forceTier3Reward)
					{
						list = Run.instance.availableTier3DropList;
					}
					none = rng.NextElementUniform(list);
				}
				int num = 1 + bonusRewardCount;
				if (scaleRewardsByPlayerCount)
				{
					num *= participatingPlayerCount;
				}
				float angle = 360f / (float)num;
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				bool flag = bossDrops != null && bossDrops.Count > 0;
				bool flag2 = bossDropTables != null && bossDropTables.Count > 0;
				int num2 = 0;
				while (num2 < num)
				{
					PickupIndex pickupIndex = none;
					if (bossDrops != null && (flag || flag2) && rng.nextNormalizedFloat <= bossDropChance)
					{
						if (flag2)
						{
							PickupDropTable pickupDropTable = rng.NextElementUniform(bossDropTables);
							if (pickupDropTable != null)
							{
								pickupIndex = pickupDropTable.GenerateDrop(rng);
							}
						}
						else
						{
							pickupIndex = rng.NextElementUniform(bossDrops);
						}
					}
					PickupDropletController.CreatePickupDroplet(pickupIndex, dropPosition.position, vector);
					num2++;
					vector = quaternion * vector;
				}
			}
			else
			{
				UnityEngine.Debug.LogWarning("dropPosition not set for BossGroup! No item will be spawned.");
			}
		}

		private int FindBossMemoryIndex(NetworkInstanceId id)
		{
			for (int i = 0; i < bossMemoryCount; i++)
			{
				if (bossMemories[i].masterInstanceId == id)
				{
					return i;
				}
			}
			return -1;
		}

		private void RememberBoss(CharacterMaster master)
		{
			if ((bool)master)
			{
				int num = FindBossMemoryIndex(master.netId);
				if (num == -1)
				{
					num = AddBossMemory(master);
				}
				ref BossMemory reference = ref bossMemories[num];
				reference.cachedMaster = master;
				reference.cachedBody = master.GetBody();
				UpdateObservations(ref reference);
			}
		}

		private void UpdateObservations(ref BossMemory memory)
		{
			memory.lastObservedHealth = 0f;
			if ((bool)memory.cachedMaster && !memory.cachedBody)
			{
				memory.cachedBody = memory.cachedMaster.GetBody();
			}
			if (!memory.cachedBody)
			{
				return;
			}
			if (bestObservedName.Length == 0 && bestObservedSubtitle.Length == 0 && Time.fixedDeltaTime * 3f < memory.cachedBody.localStartTime.timeSince)
			{
				bestObservedName = Util.GetBestBodyName(memory.cachedBody.gameObject);
				bestObservedSubtitle = memory.cachedBody.GetSubtitle();
				if (bestObservedSubtitle.Length == 0)
				{
					bestObservedSubtitle = Language.GetString("NULL_SUBTITLE");
				}
				bestObservedSubtitle = "<sprite name=\"CloudLeft\" tint=1> " + bestObservedSubtitle + "<sprite name=\"CloudRight\" tint=1>";
			}
			HealthComponent healthComponent = memory.cachedBody.healthComponent;
			memory.maxObservedMaxHealth = Mathf.Max(memory.maxObservedMaxHealth, healthComponent.fullCombinedHealth);
			memory.lastObservedHealth = healthComponent.combinedHealth;
		}

		private int AddBossMemory(CharacterMaster master)
		{
			BossMemory bossMemory = default(BossMemory);
			bossMemory.masterInstanceId = master.netId;
			bossMemory.maxObservedMaxHealth = 0f;
			bossMemory.cachedMaster = master;
			BossMemory value = bossMemory;
			ArrayUtils.ArrayAppend(ref bossMemories, ref bossMemoryCount, in value);
			return bossMemoryCount - 1;
		}

		private void UpdateBossMemories()
		{
			totalMaxObservedMaxHealth = 0f;
			totalObservedHealth = 0f;
			for (int i = 0; i < bossMemoryCount; i++)
			{
				ref BossMemory reference = ref bossMemories[i];
				UpdateObservations(ref reference);
				totalMaxObservedMaxHealth += reference.maxObservedMaxHealth;
				totalObservedHealth += Mathf.Max(reference.lastObservedHealth, 0f);
			}
		}

		public static int GetTotalBossCount()
		{
			if (totalBossCountDirty)
			{
				totalBossCountDirty = false;
				lastTotalBossCount = 0;
				List<BossGroup> instancesList = InstanceTracker.GetInstancesList<BossGroup>();
				for (int i = 0; i < instancesList.Count; i++)
				{
					lastTotalBossCount += instancesList[i].combatSquad.readOnlyMembersList.Count;
				}
			}
			return lastTotalBossCount;
		}

		public static BossGroup FindBossGroup(CharacterBody body)
		{
			if (!body || !body.isBoss)
			{
				return null;
			}
			CharacterMaster master = body.master;
			if (!master)
			{
				return null;
			}
			List<BossGroup> instancesList = InstanceTracker.GetInstancesList<BossGroup>();
			for (int i = 0; i < instancesList.Count; i++)
			{
				BossGroup bossGroup = instancesList[i];
				if (bossGroup.combatSquad.ContainsMember(master))
				{
					return bossGroup;
				}
			}
			return null;
		}

		public void ReportObjective(CharacterMaster master, List<ObjectivePanelController.ObjectiveSourceDescriptor> output)
		{
			if (combatSquad.readOnlyMembersList.Count != 0)
			{
				output.Add(new ObjectivePanelController.ObjectiveSourceDescriptor
				{
					source = this,
					master = master,
					objectiveType = typeof(DefeatBossObjectiveTracker)
				});
			}
		}
	}
	public class BoxZone : BaseZoneBehavior, IZone
	{
		[SerializeField]
		[Tooltip("If false, \"IsInBounds\" returns true when inside the box.  If true, outside the box is considered in bounds.")]
		private bool isInverted;

		public override bool IsInBounds(UnityEngine.Vector3 position)
		{
			UnityEngine.Vector3 vector = position - base.transform.position;
			vector.x = Mathf.Abs(vector.x);
			vector.y = Mathf.Abs(vector.y);
			vector.z = Mathf.Abs(vector.z);
			UnityEngine.Vector3 vector2 = base.transform.lossyScale * 0.5f;
			if (isInverted)
			{
				if (vector.x > vector2.x && vector.y > vector2.y)
				{
					return vector.z > vector2.z;
				}
				return false;
			}
			if (vector.x < vector2.x && vector.y < vector2.y)
			{
				return vector.z < vector2.z;
			}
			return false;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class BuffPassengerWhileSeated : MonoBehaviour
	{
		[SerializeField]
		private BuffDef buff;

		[SerializeField]
		private VehicleSeat vehicleSeat;

		private void OnEnable()
		{
			if ((bool)vehicleSeat)
			{
				if ((bool)vehicleSeat.currentPassengerBody)
				{
					AddBuff(vehicleSeat.currentPassengerBody);
				}
				vehicleSeat.onPassengerEnter += OnPassengerEnter;
				vehicleSeat.onPassengerExit += OnPassengerExit;
			}
		}

		private void OnDisable()
		{
			if ((bool)vehicleSeat)
			{
				if ((bool)vehicleSeat.currentPassengerBody)
				{
					RemoveBuff(vehicleSeat.currentPassengerBody);
				}
				vehicleSeat.onPassengerEnter -= OnPassengerEnter;
				vehicleSeat.onPassengerExit -= OnPassengerExit;
			}
		}

		private void OnPassengerEnter(GameObject passengerObject)
		{
			CharacterBody component = passengerObject.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				AddBuff(component);
			}
		}

		private void OnPassengerExit(GameObject passengerObject)
		{
			CharacterBody component = passengerObject.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				RemoveBuff(component);
			}
		}

		private void AddBuff(CharacterBody passengerBody)
		{
			passengerBody.AddBuff(buff);
		}

		private void RemoveBuff(CharacterBody passengerBody)
		{
			passengerBody.RemoveBuff(buff);
		}
	}
	public class BuffPickup : MonoBehaviour
	{
		[Tooltip("The base object to destroy when this pickup is consumed.")]
		public GameObject baseObject;

		[Tooltip("The team filter object which determines who can pick up this pack.")]
		public TeamFilter teamFilter;

		public GameObject pickupEffect;

		public BuffDef buffDef;

		public float buffDuration;

		private bool alive = true;

		private void OnTriggerStay(Collider other)
		{
			if (NetworkServer.active && alive && TeamComponent.GetObjectTeam(other.gameObject) == teamFilter.teamIndex)
			{
				CharacterBody component = other.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					component.AddTimedBuff(buffDef.buffIndex, buffDuration);
					UnityEngine.Object.Instantiate(pickupEffect, other.transform.position, UnityEngine.Quaternion.identity);
					UnityEngine.Object.Destroy(baseObject);
				}
			}
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	public class BuffWard : NetworkBehaviour
	{
		public enum BuffWardShape
		{
			Sphere,
			VerticalTube,
			Count
		}

		[Tooltip("The shape of the area")]
		public BuffWardShape shape;

		[Tooltip("The area of effect.")]
		[SyncVar]
		public float radius;

		[Tooltip("How long between buff pulses in the area of effect.")]
		public float interval = 1f;

		[Tooltip("The child range indicator object. Will be scaled to the radius.")]
		public Transform rangeIndicator;

		[Tooltip("The buff type to grant")]
		public BuffDef buffDef;

		[Tooltip("The buff duration")]
		public float buffDuration;

		[Tooltip("Should the ward be floored on start")]
		public bool floorWard;

		[Tooltip("Does the ward disappear over time?")]
		public bool expires;

		[Tooltip("If set, applies to all teams BUT the one selected.")]
		public bool invertTeamFilter;

		public float expireDuration;

		public bool animateRadius;

		public AnimationCurve radiusCoefficientCurve;

		[Tooltip("If set, the ward will give you this amount of time to play removal effects.")]
		public float removalTime;

		private bool needsRemovalTime;

		public string removalSoundString = "";

		public UnityEvent onRemoval;

		public bool requireGrounded;

		private TeamFilter teamFilter;

		private float buffTimer;

		private float rangeIndicatorScaleVelocity;

		private float stopwatch;

		private float calculatedRadius;

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 1u);
			}
		}

		private void Awake()
		{
			teamFilter = GetComponent<TeamFilter>();
		}

		private void OnEnable()
		{
			if ((bool)rangeIndicator)
			{
				rangeIndicator.gameObject.SetActive(value: true);
			}
		}

		private void OnDisable()
		{
			if ((bool)rangeIndicator)
			{
				rangeIndicator.gameObject.SetActive(value: false);
			}
		}

		private void Start()
		{
			if (removalTime > 0f)
			{
				needsRemovalTime = true;
			}
			if (floorWard && Physics.Raycast(base.transform.position, UnityEngine.Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask))
			{
				base.transform.position = hitInfo.point;
				base.transform.up = hitInfo.normal;
			}
			if ((bool)rangeIndicator && expires)
			{
				ScaleParticleSystemDuration component = rangeIndicator.GetComponent<ScaleParticleSystemDuration>();
				if ((bool)component)
				{
					component.newDuration = expireDuration;
				}
			}
		}

		private void Update()
		{
			calculatedRadius = (animateRadius ? (radius * radiusCoefficientCurve.Evaluate(stopwatch / expireDuration)) : radius);
			stopwatch += Time.deltaTime;
			if (expires && NetworkServer.active)
			{
				if (needsRemovalTime)
				{
					if (stopwatch >= expireDuration - removalTime)
					{
						needsRemovalTime = false;
						Util.PlaySound(removalSoundString, base.gameObject);
						onRemoval.Invoke();
					}
				}
				else if (expireDuration <= stopwatch)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
			if ((bool)rangeIndicator)
			{
				float num = Mathf.SmoothDamp(rangeIndicator.localScale.x, calculatedRadius, ref rangeIndicatorScaleVelocity, 0.2f);
				rangeIndicator.localScale = new UnityEngine.Vector3(num, num, num);
			}
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			buffTimer -= Time.fixedDeltaTime;
			if (!(buffTimer <= 0f))
			{
				return;
			}
			buffTimer = interval;
			float radiusSqr = calculatedRadius * calculatedRadius;
			UnityEngine.Vector3 position = base.transform.position;
			if (invertTeamFilter)
			{
				for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
				{
					if (teamIndex != teamFilter.teamIndex)
					{
						BuffTeam(TeamComponent.GetTeamMembers(teamIndex), radiusSqr, position);
					}
				}
			}
			else
			{
				BuffTeam(TeamComponent.GetTeamMembers(teamFilter.teamIndex), radiusSqr, position);
			}
		}

		private void BuffTeam(IEnumerable<TeamComponent> recipients, float radiusSqr, UnityEngine.Vector3 currentPosition)
		{
			if (!NetworkServer.active || !buffDef)
			{
				return;
			}
			foreach (TeamComponent recipient in recipients)
			{
				UnityEngine.Vector3 vector = recipient.transform.position - currentPosition;
				if (shape == BuffWardShape.VerticalTube)
				{
					vector.y = 0f;
				}
				if (vector.sqrMagnitude <= radiusSqr)
				{
					CharacterBody component = recipient.GetComponent<CharacterBody>();
					if ((bool)component && (!requireGrounded || !component.characterMotor || component.characterMotor.isGrounded))
					{
						component.AddTimedBuff(buffDef.buffIndex, buffDuration);
					}
				}
			}
		}

		private void OnValidate()
		{
			if (!buffDef)
			{
				UnityEngine.Debug.LogWarningFormat(this, "BuffWard {0} has no buff specified.", this);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(radius);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(radius);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				radius = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				radius = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class BurnEffectController : MonoBehaviour
	{
		public class EffectParams
		{
			public string startSound;

			public string stopSound;

			public Material overlayMaterial;

			public GameObject fireEffectPrefab;
		}

		private List<BurnEffectControllerHelper> burnEffectInstances;

		public GameObject target;

		private TemporaryOverlayInstance temporaryOverlay;

		private int soundID;

		public EffectParams effectType = normalEffect;

		public static EffectParams normalEffect;

		public static EffectParams helfireEffect;

		public static EffectParams poisonEffect;

		public static EffectParams blightEffect;

		public static EffectParams strongerBurnEffect;

		public float fireParticleSize = 5f;

		[InitDuringStartup]
		private static void Init()
		{
			normalEffect = new EffectParams
			{
				startSound = "Play_item_proc_igniteOnKill_Loop",
				stopSound = "Stop_item_proc_igniteOnKill_Loop"
			};
			LegacyResourcesAPI.LoadAsyncCallback("Materials/matOnFire", delegate(Material val)
			{
				normalEffect.overlayMaterial = val;
			});
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/FireEffect", delegate(GameObject val)
			{
				normalEffect.fireEffectPrefab = val;
			});
			helfireEffect = new EffectParams
			{
				startSound = "Play_item_proc_igniteOnKill_Loop",
				stopSound = "Stop_item_proc_igniteOnKill_Loop"
			};
			LegacyResourcesAPI.LoadAsyncCallback("Materials/matOnHelfire", delegate(Material val)
			{
				helfireEffect.overlayMaterial = val;
			});
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/HelfireEffect", delegate(GameObject val)
			{
				helfireEffect.fireEffectPrefab = val;
			});
			poisonEffect = new EffectParams();
			LegacyResourcesAPI.LoadAsyncCallback("Materials/matPoisoned", delegate(Material val)
			{
				poisonEffect.overlayMaterial = val;
			});
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/PoisonEffect", delegate(GameObject val)
			{
				poisonEffect.fireEffectPrefab = val;
			});
			blightEffect = new EffectParams();
			LegacyResourcesAPI.LoadAsyncCallback("Materials/matBlighted", delegate(Material val)
			{
				blightEffect.overlayMaterial = val;
			});
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/BlightEffect", delegate(GameObject val)
			{
				blightEffect.fireEffectPrefab = val;
			});
			strongerBurnEffect = new EffectParams();
			LegacyResourcesAPI.LoadAsyncCallback("Materials/matStrongerBurn", delegate(Material val)
			{
				strongerBurnEffect.overlayMaterial = val;
			});
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/StrongerBurnEffect", delegate(GameObject val)
			{
				strongerBurnEffect.fireEffectPrefab = val;
			});
		}

		private void Start()
		{
			if (effectType == null)
			{
				UnityEngine.Debug.LogError("BurnEffectController on " + base.gameObject.name + " has no effect type!");
				return;
			}
			Util.PlaySound(effectType.startSound, base.gameObject);
			burnEffectInstances = new List<BurnEffectControllerHelper>();
			if (effectType.overlayMaterial != null)
			{
				temporaryOverlay = TemporaryOverlayManager.AddOverlay(base.gameObject);
				temporaryOverlay.originalMaterial = effectType.overlayMaterial;
			}
			if (!target)
			{
				return;
			}
			CharacterModel component = target.GetComponent<CharacterModel>();
			if (!component)
			{
				return;
			}
			if (temporaryOverlay != null)
			{
				temporaryOverlay.AddToCharacterModel(component);
			}
			CharacterBody body = component.body;
			CharacterModel.RendererInfo[] baseRendererInfos = component.baseRendererInfos;
			if (!body)
			{
				return;
			}
			for (int i = 0; i < baseRendererInfos.Length; i++)
			{
				if (!baseRendererInfos[i].ignoreOverlays)
				{
					BurnEffectControllerHelper burnEffectControllerHelper = AddFireParticles(baseRendererInfos[i].renderer, body.coreTransform);
					if ((bool)burnEffectControllerHelper)
					{
						burnEffectInstances.Add(burnEffectControllerHelper);
					}
				}
			}
		}

		private void OnDestroy()
		{
			Util.PlaySound(effectType.stopSound, base.gameObject);
			if (temporaryOverlay != null)
			{
				temporaryOverlay.Destroy();
			}
			for (int i = 0; i < burnEffectInstances.Count; i++)
			{
				if ((bool)burnEffectInstances[i])
				{
					burnEffectInstances[i].EndEffect();
				}
			}
		}

		private BurnEffectControllerHelper AddFireParticles(Renderer modelRenderer, Transform targetParentTransform)
		{
			if (modelRenderer is MeshRenderer || modelRenderer is SkinnedMeshRenderer)
			{
				GameObject fireEffectPrefab = effectType.fireEffectPrefab;
				EffectManagerHelper andActivatePooledEffect = EffectManager.GetAndActivatePooledEffect(fireEffectPrefab, targetParentTransform);
				if (!andActivatePooledEffect)
				{
					UnityEngine.Debug.LogWarning("Could not spawn the BurnEffect prefab: " + fireEffectPrefab?.ToString() + ".");
					return null;
				}
				BurnEffectControllerHelper component = andActivatePooledEffect.GetComponent<BurnEffectControllerHelper>();
				if (!component)
				{
					UnityEngine.Debug.LogWarning("Burn effect " + fireEffectPrefab?.ToString() + " doesn't have a BurnEffectControllerHelper applied.  It can't be applied.");
					andActivatePooledEffect.ReturnToPool();
					return null;
				}
				component.InitializeBurnEffect(modelRenderer);
				return component;
			}
			return null;
		}

		public void HandleDestroy()
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}
	public class BurnEffectControllerHelper : MonoBehaviour
	{
		public ParticleSystem burnParticleSystem;

		public DestroyOnTimer destroyOnTimer;

		public LightIntensityCurve lightIntensityCurve;

		public NormalizeParticleScale normalizeParticleScale;

		public BoneParticleController boneParticleController;

		private void Awake()
		{
			if (!burnParticleSystem)
			{
				burnParticleSystem = GetComponent<ParticleSystem>();
			}
			if (!destroyOnTimer)
			{
				destroyOnTimer = GetComponent<DestroyOnTimer>();
			}
			if (!lightIntensityCurve)
			{
				lightIntensityCurve = GetComponentInChildren<LightIntensityCurve>();
			}
			if (!normalizeParticleScale)
			{
				normalizeParticleScale = GetComponentInChildren<NormalizeParticleScale>();
			}
			if (!boneParticleController)
			{
				boneParticleController = GetComponentInChildren<BoneParticleController>();
			}
		}

		private void OnEnable()
		{
			if ((bool)lightIntensityCurve)
			{
				lightIntensityCurve.enabled = false;
			}
		}

		public void InitializeBurnEffect(Renderer modelRenderer)
		{
			if (!burnParticleSystem || !modelRenderer)
			{
				return;
			}
			ParticleSystem.ShapeModule shape = burnParticleSystem.shape;
			if (modelRenderer is MeshRenderer meshRenderer)
			{
				shape.shapeType = ParticleSystemShapeType.MeshRenderer;
				shape.meshRenderer = meshRenderer;
			}
			else if (modelRenderer is SkinnedMeshRenderer skinnedMeshRenderer)
			{
				shape.shapeType = ParticleSystemShapeType.SkinnedMeshRenderer;
				shape.skinnedMeshRenderer = skinnedMeshRenderer;
				if ((bool)boneParticleController)
				{
					boneParticleController.skinnedMeshRenderer = skinnedMeshRenderer;
				}
			}
			if ((bool)normalizeParticleScale)
			{
				normalizeParticleScale.UpdateParticleSystem();
			}
			burnParticleSystem.gameObject.SetActive(value: true);
		}

		public void EndEffect()
		{
			if ((bool)burnParticleSystem)
			{
				ParticleSystem.EmissionModule emission = burnParticleSystem.emission;
				emission.enabled = false;
			}
			if ((bool)destroyOnTimer)
			{
				destroyOnTimer.enabled = true;
			}
			if ((bool)lightIntensityCurve)
			{
				lightIntensityCurve.enabled = true;
			}
		}
	}
	[DisallowMultipleComponent]
	[RequireComponent(typeof(Camera))]
	public class CameraResolutionScaler : MonoBehaviour
	{
		private class ResolutionScaleConVar : BaseConVar
		{
			private static ResolutionScaleConVar instance = new ResolutionScaleConVar("resolution_scale", ConVarFlags.Archive, null, "Resolution scale. Currently nonfunctional.");

			private ResolutionScaleConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				TextSerialization.TryParseInvariant(newValue, out float _);
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(resolutionScale);
			}
		}

		private RenderTexture oldRenderTexture;

		private static float resolutionScale = 1f;

		private RenderTexture scalingRenderTexture;

		public Camera camera { get; private set; }

		private void Awake()
		{
			camera = GetComponent<Camera>();
		}

		private void OnPreRender()
		{
			ApplyScalingRenderTexture();
		}

		private void OnRenderImage(RenderTexture source, RenderTexture destination)
		{
			if (!scalingRenderTexture)
			{
				Graphics.Blit(source, destination);
				return;
			}
			camera.targetTexture = oldRenderTexture;
			Graphics.Blit(source, oldRenderTexture);
			oldRenderTexture = null;
		}

		private static void SetResolutionScale(float newResolutionScale)
		{
			if (resolutionScale != newResolutionScale)
			{
				resolutionScale = newResolutionScale;
			}
		}

		private void ApplyScalingRenderTexture()
		{
			oldRenderTexture = camera.targetTexture;
			bool flag = resolutionScale != 1f;
			camera.targetTexture = null;
			UnityEngine.Rect pixelRect = camera.pixelRect;
			int num = Mathf.FloorToInt(pixelRect.width * resolutionScale);
			int num2 = Mathf.FloorToInt(pixelRect.height * resolutionScale);
			if ((bool)scalingRenderTexture && (scalingRenderTexture.width != num || scalingRenderTexture.height != num2))
			{
				UnityEngine.Object.Destroy(scalingRenderTexture);
				scalingRenderTexture = null;
			}
			if (flag != (bool)scalingRenderTexture)
			{
				if (flag)
				{
					scalingRenderTexture = new RenderTexture(num, num2, 24);
					scalingRenderTexture.autoGenerateMips = false;
					scalingRenderTexture.filterMode = (((double)resolutionScale > 1.0) ? FilterMode.Bilinear : FilterMode.Point);
				}
				else
				{
					UnityEngine.Object.Destroy(scalingRenderTexture);
					scalingRenderTexture = null;
				}
			}
			if (flag)
			{
				camera.targetTexture = scalingRenderTexture;
			}
		}

		private void OnDestroy()
		{
			if ((bool)scalingRenderTexture)
			{
				UnityEngine.Object.Destroy(scalingRenderTexture);
				scalingRenderTexture = null;
			}
		}
	}
	public interface ICameraStateProvider
	{
		void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState);

		bool IsUserLookAllowed(CameraRigController cameraRigController);

		bool IsUserControlAllowed(CameraRigController cameraRigController);

		bool IsHudAllowed(CameraRigController cameraRigController);
	}
	public struct CameraState
	{
		public UnityEngine.Vector3 position;

		public UnityEngine.Quaternion rotation;

		public float fov;

		public static CameraState Lerp(ref CameraState a, ref CameraState b, float t)
		{
			CameraState result = default(CameraState);
			result.position = UnityEngine.Vector3.LerpUnclamped(a.position, b.position, t);
			result.rotation = UnityEngine.Quaternion.SlerpUnclamped(a.rotation, b.rotation, t);
			result.fov = Mathf.LerpUnclamped(a.fov, b.fov, t);
			return result;
		}

		public static CameraState SmoothDamp(CameraState current, CameraState target, ref UnityEngine.Vector3 positionVelocity, ref float angleVelocity, ref float fovVelocity, float smoothTime)
		{
			CameraState result = default(CameraState);
			result.position = UnityEngine.Vector3.SmoothDamp(current.position, target.position, ref positionVelocity, smoothTime);
			result.rotation = Util.SmoothDampQuaternion(current.rotation, target.rotation, ref angleVelocity, smoothTime);
			result.fov = Mathf.SmoothDamp(current.fov, target.fov, ref fovVelocity, smoothTime);
			return result;
		}
	}
	public enum HudType
	{
		Default,
		Large,
		Auto
	}
	public class CameraRigController : MonoBehaviour
	{
		[Obsolete("CameraMode objects are now used instead of enums.", true)]
		public enum CameraMode
		{
			None,
			PlayerBasic,
			Fly,
			SpectateOrbit,
			SpectateUser
		}

		public struct AimAssistInfo
		{
			public HurtBox aimAssistHurtbox;

			public UnityEngine.Vector3 localPositionOnHurtbox;

			public UnityEngine.Vector3 worldPosition;
		}

		[Tooltip("The main camera for rendering the scene.")]
		[Header("Component References")]
		public Camera sceneCam;

		[Tooltip("The UI camera.")]
		public Camera uiCam;

		[Tooltip("The skybox camera.")]
		public Camera skyboxCam;

		[Tooltip("The particle system to play while sprinting.")]
		public ParticleSystem sprintingParticleSystem;

		[Tooltip("The particle system to play while skills are disabled.")]
		public ParticleSystem disabledSkillsParticleSystem;

		[Header("Camera Parameters")]
		[Tooltip("The default FOV of this camera.")]
		public float baseFov = 60f;

		[Tooltip("The viewport to use.")]
		public UnityEngine.Rect viewport = new UnityEngine.Rect(0f, 0f, 1f, 1f);

		[Tooltip("The maximum distance of the raycast used to determine the aim vector.")]
		public float maxAimRaycastDistance = 1000f;

		[Tooltip("If true, treat this camera as though it's in a cutscene")]
		public bool isCutscene;

		[Header("Near-Camera Character Dithering")]
		public bool enableFading = true;

		public float fadeStartDistance = 1f;

		public float fadeEndDistance = 4f;

		[Header("Behavior")]
		[Tooltip("Whether or not to create a HUD.")]
		public bool createHud = true;

		[Tooltip("Whether or not this camera being enabled forces player-owned cameras to be disabled.")]
		public bool suppressPlayerCameras;

		[Tooltip("Forces music to be enabled for this camera.")]
		public bool enableMusic;

		private ulong musicListenerId;

		private bool musicEnabled;

		[Header("Target (for debug only)")]
		public GameObject nextTarget;

		public static Action OnChangeHUD;

		public static Action OnHUDUpdated;

		private CameraModeBase _cameraMode;

		private GameObject _target;

		private CameraState desiredCameraState;

		public CameraState currentCameraState;

		public bool doNotOverrideCameraState;

		private CameraState lerpCameraState;

		private float lerpCameraTime = 1f;

		private float lerpCameraTimeScale = 1f;

		private ICameraStateProvider overrideCam;

		private CameraModeBase.CameraModeContext cameraModeContext;

		private NetworkUser _viewer;

		private LocalUser _localUserViewer;

		private static GameObject DamageNumberManagerPrefab;

		private static GameObject HudPrefab;

		private static string previousHudPath;

		public CameraTargetParams targetParams;

		private const string musicSystemDeviceShareSet = "Music_Audio_Device";

		public AimAssistInfo lastAimAssist;

		public AimAssistInfo aimAssist;

		private static List<CameraRigController> instancesList = new List<CameraRigController>();

		public static readonly ReadOnlyCollection<CameraRigController> readOnlyInstancesList = instancesList.AsReadOnly();

		public static FloatConVar aimStickExponent = new FloatConVar("aim_stick_exponent", ConVarFlags.None, "1", "The exponent for stick input used for aiming.");

		public static FloatConVar aimStickDualZoneThreshold = new FloatConVar("aim_stick_dual_zone_threshold", ConVarFlags.None, "0.90", "The threshold for stick dual zone behavior.");

		public static FloatConVar aimStickDualZoneSlope = new FloatConVar("aim_stick_dual_zone_slope", ConVarFlags.None, "0.40", "The slope value for stick dual zone behavior.");

		public static FloatConVar aimStickDualZoneSmoothing = new FloatConVar("aim_stick_smoothing", ConVarFlags.None, "0.05", "The smoothing value for stick aiming.");

		public static FloatConVar aimStickGlobalScale = new FloatConVar("aim_stick_global_scale", ConVarFlags.Archive, "1.00", "The global sensitivity scale for stick aiming.");

		public static FloatConVar aimStickAssistMinSlowdownScale = new FloatConVar("aim_stick_assist_min_slowdown_scale", ConVarFlags.None, "1", "The MIN amount the sensitivity scales down when passing over an enemy.");

		public static FloatConVar aimStickAssistMaxSlowdownScale = new FloatConVar("aim_stick_assist_max_slowdown_scale", ConVarFlags.None, "0.4", "The MAX amount the sensitivity scales down when passing over an enemy. UNUSED");

		public static FloatConVar aimStickAssistMinDelta = new FloatConVar("aim_stick_assist_min_delta", ConVarFlags.None, "0", "The MIN amount in radians the aim assist will turn towards");

		public static FloatConVar aimStickAssistMaxDelta = new FloatConVar("aim_stick_assist_max_delta", ConVarFlags.None, "1.57", "The MAX amount in radians the aim assist will turn towards");

		public static FloatConVar aimStickAssistMaxInputHelp = new FloatConVar("aim_stick_assist_max_input_help", ConVarFlags.None, "0.2", "The amount, from 0-1, that the aim assist will actually ADD magnitude towards. Helps you keep target while strafing. CURRENTLY UNUSED.");

		public static FloatConVar aimStickAssistMaxSize = new FloatConVar("aim_stick_assist_max_size", ConVarFlags.None, "3", "The size, as a coefficient, of the aim assist 'white' zone.");

		public static FloatConVar aimStickAssistMinSize = new FloatConVar("aim_stick_assist_min_size", ConVarFlags.None, "1", "The minimum size, as a percentage of the GUI, of the aim assist 'red' zone.");

		public static BoolConVar enableSprintSensitivitySlowdown = new BoolConVar("enable_sprint_sensitivity_slowdown", ConVarFlags.Archive, "1", "Enables sensitivity reduction while sprinting.");

		private float hitmarkerAlpha;

		private float hitmarkerTimer;

		public bool disableSpectating { get; set; }

		public CameraModeBase cameraMode
		{
			get
			{
				return _cameraMode;
			}
			set
			{
				if (_cameraMode != value)
				{
					_cameraMode?.OnUninstall(this);
					_cameraMode = value;
					_cameraMode?.OnInstall(this);
				}
			}
		}

		public HUD hud { get; private set; }

		public GameObject firstPersonTarget { get; private set; }

		public TeamIndex targetTeamIndex { get; private set; } = TeamIndex.None;


		public CharacterBody targetBody { get; private set; }

		public UnityEngine.Vector3 rawScreenShakeDisplacement { get; private set; }

		public UnityEngine.Vector3 crosshairWorldPosition { get; private set; }

		public bool hasOverride => overrideCam != null;

		public bool isControlAllowed
		{
			get
			{
				if (hasOverride)
				{
					return overrideCam.IsUserControlAllowed(this);
				}
				return true;
			}
		}

		public bool isHudAllowed
		{
			get
			{
				if ((bool)target)
				{
					if (hasOverride)
					{
						return overrideCam.IsHudAllowed(this);
					}
					return true;
				}
				return false;
			}
		}

		public GameObject target
		{
			get
			{
				return _target;
			}
			private set
			{
				if ((object)_target != value)
				{
					GameObject oldTarget = _target;
					_target = value;
					bool flag = _target;
					targetParams = (flag ? target.GetComponent<CameraTargetParams>() : null);
					targetBody = (flag ? target.GetComponent<CharacterBody>() : null);
					cameraMode?.OnTargetChanged(this, new CameraModeBase.OnTargetChangedArgs
					{
						oldTarget = oldTarget,
						newTarget = _target
					});
					CameraRigController.onCameraTargetChanged?.Invoke(this, target);
				}
			}
		}

		public NetworkUser viewer
		{
			get
			{
				return _viewer;
			}
			set
			{
				_viewer = value;
				localUserViewer = (_viewer ? _viewer.localUser : null);
			}
		}

		public LocalUser localUserViewer
		{
			get
			{
				return _localUserViewer;
			}
			private set
			{
				if (_localUserViewer != value)
				{
					if (_localUserViewer != null)
					{
						_localUserViewer.cameraRigController = null;
					}
					_localUserViewer = value;
					if (_localUserViewer != null)
					{
						_localUserViewer.cameraRigController = this;
					}
					if ((bool)hud)
					{
						hud.localUserViewer = _localUserViewer;
					}
				}
			}
		}

		public HurtBox lastCrosshairHurtBox { get; private set; }

		public static event Action<CameraRigController, GameObject> onCameraTargetChanged;

		public static event Action<CameraRigController> onCameraEnableGlobal;

		public static event Action<CameraRigController> onCameraDisableGlobal;

		private void StartStateLerp(float lerpDuration)
		{
			lerpCameraState = currentCameraState;
			if (lerpDuration > 0f)
			{
				lerpCameraTime = 0f;
				lerpCameraTimeScale = 1f / lerpDuration;
			}
			else
			{
				lerpCameraTime = 1f;
				lerpCameraTimeScale = 0f;
			}
		}

		public void SetOverrideCam(ICameraStateProvider newOverrideCam, float lerpDuration = 1f)
		{
			if (newOverrideCam != overrideCam)
			{
				if (overrideCam != null && newOverrideCam == null)
				{
					cameraMode?.MatchState(in cameraModeContext, in currentCameraState);
				}
				overrideCam = newOverrideCam;
				StartStateLerp(lerpDuration);
			}
		}

		public bool IsOverrideCam(ICameraStateProvider testOverrideCam)
		{
			return overrideCam == testOverrideCam;
		}

		public static IEnumerator InitializeReferences()
		{
			AsyncOperationHandle<GameObject> handle2 = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/DamageNumberManager");
			while (!handle2.IsDone)
			{
				yield return null;
			}
			DamageNumberManagerPrefab = handle2.Result;
			previousHudPath = GetHUDPath();
			handle2 = LegacyResourcesAPI.LoadAsync<GameObject>(previousHudPath);
			while (!handle2.IsDone)
			{
				yield return null;
			}
			HudPrefab = handle2.Result;
		}

		private void Start()
		{
			RoR2Application.onUpdate += EarlyUpdate;
			OnChangeHUD = (Action)Delegate.Combine(OnChangeHUD, new Action(UpdateHUD));
			UpdateHUD();
			if ((bool)uiCam)
			{
				uiCam.transform.parent = null;
				uiCam.transform.SetPositionAndRotation(UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity);
			}
			if (!DamageNumberManager.instance)
			{
				if (DamageNumberManagerPrefab != null)
				{
					UnityEngine.Object.Instantiate(DamageNumberManagerPrefab);
				}
				else
				{
					AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/DamageNumberManager");
					asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
					{
						UnityEngine.Object.Instantiate(x.Result);
					};
				}
			}
			currentCameraState = new CameraState
			{
				position = base.transform.position,
				rotation = base.transform.rotation,
				fov = baseFov
			};
			cameraMode = CameraModePlayerBasic.playerBasic;
			if (enableMusic && (!RoR2Application.isInLocalMultiPlayer || _viewer.localUser.inputPlayer.name == "PlayerMain"))
			{
				EnableMusicForCamera();
			}
		}

		private void UpdateHUD()
		{
			if (createHud)
			{
				if ((bool)hud)
				{
					UnityEngine.Object.Destroy(hud.gameObject);
				}
				string hUDPath = GetHUDPath();
				if (HudPrefab == null || hUDPath != previousHudPath)
				{
					HudPrefab = LegacyResourcesAPI.Load<GameObject>(hUDPath);
					previousHudPath = hUDPath;
				}
				GameObject gameObject = UnityEngine.Object.Instantiate(HudPrefab);
				hud = gameObject.GetComponent<HUD>();
				hud.cameraRigController = this;
				SetPostProcessVolumeExclusive(hud.scoreboardPostProcessVolume);
				hud.GetComponent<Canvas>().worldCamera = uiCam;
				hud.GetComponent<CrosshairManager>().cameraRigController = this;
				hud.localUserViewer = localUserViewer;
				OnHUDUpdated?.Invoke();
			}
		}

		[CanBeNull]
		private static string GetHUDPath()
		{
			if (NetworkUser.readOnlyLocalPlayersList == null || NetworkUser.readOnlyLocalPlayersList.Count < 1)
			{
				return "Prefabs/HUDSimple";
			}
			UserProfile userProfile = NetworkUser.readOnlyLocalPlayersList[0]?.localUser?.userProfile;
			if (userProfile != null)
			{
				switch ((HudType)userProfile.hudSizeMode)
				{
				case HudType.Default:
					return "Prefabs/HUDSimple";
				case HudType.Large:
					return "Prefabs/HUDSimple_Big";
				case HudType.Auto:
					return "Prefabs/HUDSimple_Big";
				default:
					UnityEngine.Debug.LogWarning(string.Format("Undefined {0}. Value : {1}. Resorting to default HUD.", "HudType", userProfile.hudSizeMode));
					return "Prefabs/HUDSimple";
				}
			}
			return "Prefabs/HUDSimple";
		}

		private void OnEnable()
		{
			instancesList.Add(this);
			if ((bool)uiCam)
			{
				uiCam.gameObject.SetActive(value: true);
			}
			if ((bool)hud)
			{
				hud.gameObject.SetActive(value: true);
			}
			CameraRigController.onCameraEnableGlobal?.Invoke(this);
		}

		private void OnDisable()
		{
			CameraRigController.onCameraDisableGlobal?.Invoke(this);
			if ((bool)uiCam)
			{
				uiCam.gameObject.SetActive(value: false);
			}
			if ((bool)hud)
			{
				hud.gameObject.SetActive(value: false);
			}
			instancesList.Remove(this);
		}

		private void OnDestroy()
		{
			RoR2Application.onUpdate -= EarlyUpdate;
			OnChangeHUD = (Action)Delegate.Remove(OnChangeHUD, new Action(UpdateHUD));
			cameraMode = null;
			if ((bool)uiCam)
			{
				UnityEngine.Object.Destroy(uiCam.gameObject);
			}
			if ((bool)hud)
			{
				UnityEngine.Object.Destroy(hud.gameObject);
			}
			DisableMusicForCamera();
		}

		private void EarlyUpdate()
		{
			target = nextTarget;
			if ((bool)targetBody)
			{
				targetTeamIndex = targetBody.teamComponent.teamIndex;
			}
			if (Time.deltaTime != 0f && !isCutscene)
			{
				lerpCameraTime += Time.deltaTime * lerpCameraTimeScale;
				firstPersonTarget = null;
				sceneCam.rect = viewport;
				GenerateCameraModeContext(out cameraModeContext);
				if (cameraMode != null)
				{
					cameraMode.CollectLookInput(in cameraModeContext, out var result);
					CameraModeBase cameraModeBase = cameraMode;
					ref CameraModeBase.CameraModeContext context = ref cameraModeContext;
					CameraModeBase.ApplyLookInputArgs args = new CameraModeBase.ApplyLookInputArgs
					{
						lookInput = result.lookInput
					};
					cameraModeBase.ApplyLookInput(in context, in args);
				}
			}
		}

		private void LateUpdate()
		{
			if (Time.deltaTime == 0f || isCutscene)
			{
				return;
			}
			CameraState cameraState = currentCameraState;
			if (cameraMode != null && cameraModeContext.cameraInfo.cameraRigController != null && !doNotOverrideCameraState)
			{
				cameraMode.Update(in cameraModeContext, out var result);
				cameraState = result.cameraState;
				firstPersonTarget = result.firstPersonTarget;
				crosshairWorldPosition = result.crosshairWorldPosition;
				SetParticleSystemActive(result.showSprintParticles, sprintingParticleSystem);
				SetParticleSystemActive(result.showDisabledSkillsParticles, disabledSkillsParticleSystem);
			}
			if ((bool)hud)
			{
				CharacterMaster targetMaster = (targetBody ? targetBody.master : null);
				hud.targetMaster = targetMaster;
			}
			CameraState cameraState2 = cameraState;
			if (overrideCam != null)
			{
				if (!(overrideCam is UnityEngine.Object @object) || (bool)@object)
				{
					overrideCam.GetCameraState(this, ref cameraState2);
				}
				else
				{
					overrideCam = null;
				}
			}
			if (lerpCameraTime >= 1f)
			{
				currentCameraState = cameraState2;
			}
			else
			{
				currentCameraState = CameraState.Lerp(ref lerpCameraState, ref cameraState2, RemapLerpTime(lerpCameraTime));
			}
			SetCameraState(currentCameraState);
		}

		public void UpdatePreviousCameraState(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			cameraModeContext.cameraInfo.previousCameraState.position = position;
			cameraModeContext.cameraInfo.previousCameraState.rotation = rotation;
		}

		private void GenerateCameraModeContext(out CameraModeBase.CameraModeContext result)
		{
			result.cameraInfo = default(CameraModeBase.CameraInfo);
			result.targetInfo = default(CameraModeBase.TargetInfo);
			result.viewerInfo = default(CameraModeBase.ViewerInfo);
			ref CameraModeBase.CameraInfo cameraInfo = ref result.cameraInfo;
			ref CameraModeBase.TargetInfo targetInfo = ref result.targetInfo;
			ref CameraModeBase.ViewerInfo viewerInfo = ref result.viewerInfo;
			cameraInfo.cameraRigController = this;
			cameraInfo.sceneCam = sceneCam;
			cameraInfo.overrideCam = overrideCam;
			cameraInfo.previousCameraState = currentCameraState;
			cameraInfo.baseFov = baseFov;
			targetInfo.target = (target ? target : null);
			targetInfo.body = targetBody;
			targetInfo.inputBank = targetInfo.target?.GetComponent<InputBankTest>();
			if (targetBody != null && targetBody.currentVehicle != null && targetBody.currentVehicle.targetParams != null)
			{
				targetInfo.targetParams = targetBody.currentVehicle.targetParams;
			}
			else
			{
				targetInfo.targetParams = targetParams;
			}
			targetInfo.teamIndex = targetInfo.target?.GetComponent<TeamComponent>()?.teamIndex ?? TeamIndex.None;
			targetInfo.isSprinting = (bool)targetInfo.body && targetInfo.body.isSprinting;
			targetInfo.skillsAreDisabled = (bool)targetInfo.body && targetInfo.body.allSkillsDisabled;
			targetInfo.master = targetInfo.body?.master;
			targetInfo.networkUser = targetInfo.master?.playerCharacterMasterController?.networkUser;
			targetInfo.networkedViewAngles = targetInfo.networkUser?.GetComponent<NetworkedViewAngles>();
			targetInfo.isViewerControlled = (bool)targetInfo.networkUser && (object)targetInfo.networkUser == localUserViewer?.currentNetworkUser;
			viewerInfo.localUser = localUserViewer;
			viewerInfo.userProfile = localUserViewer?.userProfile;
			viewerInfo.inputPlayer = localUserViewer?.inputPlayer;
			viewerInfo.eventSystem = localUserViewer?.eventSystem;
			viewerInfo.hasCursor = (bool)viewerInfo.eventSystem && viewerInfo.eventSystem.isCursorVisible;
			viewerInfo.isUIFocused = localUserViewer?.isUIFocused ?? false;
		}

		public void CloneCameraContext(CameraRigController cloneThisCamera)
		{
			if (!(cloneThisCamera == null))
			{
				cameraModeContext = cloneThisCamera.cameraModeContext;
			}
		}

		public float Raycast(Ray ray, float maxDistance, float wallCushion)
		{
			int num = 0;
			num = HGPhysics.SphereCastAll(out var hits, ray.origin, wallCushion, ray.direction, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
			float num2 = maxDistance;
			for (int i = 0; i < num; i++)
			{
				float distance = hits[i].distance;
				if (distance < num2)
				{
					Collider collider = hits[i].collider;
					if ((bool)collider && !collider.GetComponent<NonSolidToCamera>())
					{
						num2 = distance;
					}
				}
			}
			HGPhysics.ReturnResults(hits);
			return num2;
		}

		private static float RemapLerpTime(float t)
		{
			float num = 1f;
			float num2 = 0f;
			float num3 = 1f;
			if ((t /= num / 2f) < 1f)
			{
				return num3 / 2f * t * t + num2;
			}
			return (0f - num3) / 2f * ((t -= 1f) * (t - 2f) - 1f) + num2;
		}

		public void SetCameraState(CameraState cameraState)
		{
			currentCameraState = cameraState;
			float num = ((localUserViewer == null) ? 1f : localUserViewer.userProfile.screenShakeScale);
			UnityEngine.Vector3 position = cameraState.position;
			rawScreenShakeDisplacement = ShakeEmitter.ComputeTotalShakeAtPoint(cameraState.position);
			UnityEngine.Vector3 vector = rawScreenShakeDisplacement * num;
			UnityEngine.Vector3 position2 = position + vector;
			if (vector != UnityEngine.Vector3.zero && Physics.SphereCast(position, direction: vector, radius: sceneCam.nearClipPlane, hitInfo: out var hitInfo, maxDistance: vector.magnitude, layerMask: LayerIndex.world.mask, queryTriggerInteraction: QueryTriggerInteraction.Ignore))
			{
				position2 = position + vector.normalized * hitInfo.distance;
			}
			base.transform.SetPositionAndRotation(position2, cameraState.rotation);
			if ((bool)sceneCam)
			{
				sceneCam.fieldOfView = cameraState.fov;
			}
		}

		public static Ray ModifyAimRayIfApplicable(Ray originalAimRay, GameObject target, out float extraRaycastDistance)
		{
			CameraRigController cameraRigController = null;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CameraRigController cameraRigController2 = readOnlyInstancesList[i];
				if (cameraRigController2.target == target && cameraRigController2._localUserViewer.cachedBodyObject == target && !cameraRigController2.hasOverride)
				{
					cameraRigController = cameraRigController2;
					break;
				}
			}
			if ((bool)cameraRigController)
			{
				Camera camera = cameraRigController.sceneCam;
				extraRaycastDistance = (originalAimRay.origin - camera.transform.position).magnitude;
				return camera.ViewportPointToRay(new UnityEngine.Vector2(0.5f, 0.5f));
			}
			extraRaycastDistance = 0f;
			return originalAimRay;
		}

		private void SetSprintParticlesActive(bool newSprintParticlesActive)
		{
			if (!sprintingParticleSystem)
			{
				return;
			}
			ParticleSystem.MainModule main = sprintingParticleSystem.main;
			if (newSprintParticlesActive)
			{
				main.loop = true;
				if (!sprintingParticleSystem.isPlaying)
				{
					sprintingParticleSystem.Play();
				}
			}
			else
			{
				main.loop = false;
			}
		}

		private void SetParticleSystemActive(bool newParticlesActive, ParticleSystem particleSystem)
		{
			if (!particleSystem)
			{
				return;
			}
			ParticleSystem.MainModule main = particleSystem.main;
			if (newParticlesActive)
			{
				main.loop = true;
				if (!particleSystem.isPlaying)
				{
					particleSystem.Play();
				}
			}
			else
			{
				main.loop = false;
			}
		}

		public void SetPostProcessVolumeExclusive(PostProcessVolume volume)
		{
			if (!(volume == null) && !(sceneCam == null))
			{
				volume.targetLayer = sceneCam.GetComponent<PostProcessLayer>();
			}
		}

		[InitDuringStartup]
		private static void Init()
		{
			SceneCamera.onSceneCameraPreCull += delegate(SceneCamera sceneCam)
			{
				sceneCam.cameraRigController.sprintingParticleSystem.gameObject.layer = LayerIndex.defaultLayer.intVal;
			};
			SceneCamera.onSceneCameraPostRender += delegate(SceneCamera sceneCam)
			{
				sceneCam.cameraRigController.sprintingParticleSystem.gameObject.layer = LayerIndex.noDraw.intVal;
			};
		}

		public static bool IsObjectSpectatedByAnyCamera(GameObject gameObject)
		{
			for (int i = 0; i < instancesList.Count; i++)
			{
				if (instancesList[i].target == gameObject)
				{
					return true;
				}
			}
			return false;
		}

		[ContextMenu("Print Debug Info")]
		private void PrintDebugInfo()
		{
			UnityEngine.Debug.LogFormat("hasOverride={0} overrideCam={1} isControlAllowed={2}", hasOverride, overrideCam, isControlAllowed);
		}

		public void EnableMusicForCamera(string deviceShareSet = "Music_Audio_Device")
		{
			GameObject gameObject = new GameObject("MusicListener", typeof(AkGameObj), typeof(AkAudioListener));
			Transform obj = gameObject.transform;
			obj.localPosition = UnityEngine.Vector3.zero;
			obj.localRotation = UnityEngine.Quaternion.identity;
			obj.localScale = UnityEngine.Vector3.one;
			obj.SetParent(sceneCam.transform, worldPositionStays: false);
			AkOutputSettings in_Settings = new AkOutputSettings(deviceShareSet);
			ulong[] array = new ulong[1] { AkSoundEngine.GetAkGameObjectID(gameObject) };
			AkSoundEngine.AddOutput(in_Settings, out var out_pDeviceID, array, (uint)array.Length);
			musicListenerId = out_pDeviceID;
			musicEnabled = true;
		}

		public void DisableMusicForCamera()
		{
			if (musicEnabled)
			{
				AkSoundEngine.RemoveOutput(musicListenerId);
			}
		}
	}
	[RequireComponent(typeof(CameraRigController))]
	public class CameraRigControllerSpectateControls : MonoBehaviour
	{
		private CameraRigController cameraRigController;

		private void Awake()
		{
			cameraRigController = GetComponent<CameraRigController>();
		}

		private static bool CanUserSpectateBody(NetworkUser viewer, CharacterBody body)
		{
			return Util.LookUpBodyNetworkUser(body.gameObject);
		}

		public static GameObject GetNextSpectateGameObject(NetworkUser viewer, GameObject currentGameObject)
		{
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			if (readOnlyInstancesList.Count == 0)
			{
				return null;
			}
			CharacterBody characterBody = (currentGameObject ? currentGameObject.GetComponent<CharacterBody>() : null);
			int num = (characterBody ? readOnlyInstancesList.IndexOf(characterBody) : 0);
			for (int i = num + 1; i < readOnlyInstancesList.Count; i++)
			{
				if (CanUserSpectateBody(viewer, readOnlyInstancesList[i]))
				{
					return readOnlyInstancesList[i].gameObject;
				}
			}
			for (int j = 0; j <= num; j++)
			{
				if (CanUserSpectateBody(viewer, readOnlyInstancesList[j]))
				{
					return readOnlyInstancesList[j].gameObject;
				}
			}
			return null;
		}

		public static GameObject GetPreviousSpectateGameObject(NetworkUser viewer, GameObject currentGameObject)
		{
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			if (readOnlyInstancesList.Count == 0)
			{
				return null;
			}
			CharacterBody characterBody = (currentGameObject ? currentGameObject.GetComponent<CharacterBody>() : null);
			int num = (characterBody ? readOnlyInstancesList.IndexOf(characterBody) : 0);
			for (int num2 = num - 1; num2 >= 0; num2--)
			{
				if (CanUserSpectateBody(viewer, readOnlyInstancesList[num2]))
				{
					return readOnlyInstancesList[num2].gameObject;
				}
			}
			for (int num3 = readOnlyInstancesList.Count - 1; num3 >= num; num3--)
			{
				if (CanUserSpectateBody(viewer, readOnlyInstancesList[num3]))
				{
					return readOnlyInstancesList[num3].gameObject;
				}
			}
			return null;
		}

		private void Update()
		{
			Player player = cameraRigController.localUserViewer?.inputPlayer;
			if (cameraRigController.cameraMode != null && cameraRigController.cameraMode.IsSpectating(cameraRigController) && player != null)
			{
				if (player.GetButtonDown(7))
				{
					cameraRigController.nextTarget = GetNextSpectateGameObject(cameraRigController.viewer, cameraRigController.target);
				}
				if (player.GetButtonDown(8))
				{
					cameraRigController.nextTarget = GetPreviousSpectateGameObject(cameraRigController.viewer, cameraRigController.target);
				}
			}
		}
	}
	public class CameraTargetParams : MonoBehaviour
	{
		[Serializable]
		public enum AimType
		{
			Standard,
			FirstPerson,
			Aura,
			Sprinting,
			OverTheShoulder,
			ZoomedOut,
			GroundToAir
		}

		public class AimRequest : IDisposable
		{
			public readonly AimType aimType;

			private Action<AimRequest> disposeCallback;

			public AimRequest(AimType type, Action<AimRequest> onDispose)
			{
				disposeCallback = onDispose;
				aimType = type;
			}

			public void Dispose()
			{
				disposeCallback?.Invoke(this);
				disposeCallback = null;
			}
		}

		public struct CameraParamsOverrideRequest
		{
			public CharacterCameraParamsData cameraParamsData;

			public float priority;
		}

		internal class CameraParamsOverride
		{
			public CharacterCameraParamsData cameraParamsData;

			public float priority;

			public float enterStartTime;

			public float enterEndTime;

			public float exitStartTime;

			public float exitEndTime;

			public float CalculateAlpha(float t)
			{
				float num = 1f;
				if (t < enterEndTime)
				{
					num *= Mathf.Clamp01(Mathf.InverseLerp(enterStartTime, enterEndTime, t));
				}
				if (t > exitStartTime)
				{
					num *= Mathf.Clamp01(Mathf.InverseLerp(exitEndTime, exitStartTime, t));
				}
				return easeCurve.Evaluate(num);
			}
		}

		public struct CameraParamsOverrideHandle
		{
			internal readonly CameraParamsOverride target;

			public bool isValid => target != null;

			internal CameraParamsOverrideHandle(CameraParamsOverride target)
			{
				this.target = target;
			}
		}

		public CharacterCameraParams cameraParams;

		public Transform cameraPivotTransform;

		[ShowFieldObsolete]
		[Obsolete]
		public float fovOverride;

		[HideInInspector]
		public UnityEngine.Vector2 recoil;

		[HideInInspector]
		public bool dontRaycastToPivot;

		private static float targetRecoilDampTime = 0.08f;

		private static float recoilDampTime = 0.05f;

		private UnityEngine.Vector2 targetRecoil;

		private UnityEngine.Vector2 recoilVelocity;

		private UnityEngine.Vector2 targetRecoilVelocity;

		private List<AimRequest> aimRequestStack = new List<AimRequest>();

		private static readonly AnimationCurve easeCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);

		private List<CameraParamsOverride> cameraParamsOverrides;

		private CharacterCameraParamsData _currentCameraParamsData;

		public ref CharacterCameraParamsData currentCameraParamsData => ref _currentCameraParamsData;

		public void AddRecoil(float verticalMin, float verticalMax, float horizontalMin, float horizontalMax)
		{
			targetRecoil += new UnityEngine.Vector2(UnityEngine.Random.Range(horizontalMin, horizontalMax), UnityEngine.Random.Range(verticalMin, verticalMax));
		}

		public AimRequest RequestAimType(AimType aimType)
		{
			switch (aimType)
			{
			case AimType.Aura:
			{
				CharacterCameraParamsData data3 = cameraParams.data;
				data3.idealLocalCameraPos.value += new UnityEngine.Vector3(0f, 1.5f, -7f);
				CameraParamsOverrideHandle overrideHandle = AddParamsOverride(new CameraParamsOverrideRequest
				{
					cameraParamsData = data3,
					priority = 0.1f
				}, 0.5f);
				AimRequest aimRequest4 = new AimRequest(aimType, delegate(AimRequest aimRequest)
				{
					RemoveRequest(aimRequest);
					RemoveParamsOverride(overrideHandle, 0.5f);
				});
				aimRequestStack.Add(aimRequest4);
				return aimRequest4;
			}
			case AimType.ZoomedOut:
			{
				CharacterCameraParamsData data2 = cameraParams.data;
				data2.idealLocalCameraPos.value += new UnityEngine.Vector3(0f, 2f, -20f);
				CameraParamsOverrideHandle overrideHandle2 = AddParamsOverride(new CameraParamsOverrideRequest
				{
					cameraParamsData = data2,
					priority = 0.1f
				}, 0.5f);
				AimRequest aimRequest3 = new AimRequest(aimType, delegate(AimRequest aimRequest)
				{
					RemoveRequest(aimRequest);
					RemoveParamsOverride(overrideHandle2, 0.5f);
				});
				aimRequestStack.Add(aimRequest3);
				return aimRequest3;
			}
			case AimType.GroundToAir:
			{
				CharacterCameraParamsData data = cameraParams.data;
				data.idealLocalCameraPos.value += new UnityEngine.Vector3(0f, 3f, -25f);
				CameraParamsOverrideHandle overrideHandle3 = AddParamsOverride(new CameraParamsOverrideRequest
				{
					cameraParamsData = data,
					priority = 0.1f
				}, 0.4f);
				AimRequest aimRequest2 = new AimRequest(aimType, delegate(AimRequest aimRequest)
				{
					RemoveRequest(aimRequest);
					RemoveParamsOverride(overrideHandle3, UnseenHand.cameraTransitionOutTime);
				});
				aimRequestStack.Add(aimRequest2);
				return aimRequest2;
			}
			default:
				return null;
			}
		}

		private void RemoveRequest(AimRequest request)
		{
			aimRequestStack.Remove(request);
		}

		private void Awake()
		{
			CharacterBody component = GetComponent<CharacterBody>();
			if ((bool)component && cameraPivotTransform == null)
			{
				cameraPivotTransform = component.aimOriginTransform;
			}
			cameraParamsOverrides = CollectionPool<CameraParamsOverride, List<CameraParamsOverride>>.RentCollection();
		}

		private void OnDestroy()
		{
			cameraParamsOverrides = CollectionPool<CameraParamsOverride, List<CameraParamsOverride>>.ReturnCollection(cameraParamsOverrides);
		}

		private void Update()
		{
			targetRecoil = UnityEngine.Vector2.SmoothDamp(targetRecoil, UnityEngine.Vector2.zero, ref targetRecoilVelocity, targetRecoilDampTime, 180f, Time.deltaTime);
			recoil = UnityEngine.Vector2.SmoothDamp(recoil, targetRecoil, ref recoilVelocity, recoilDampTime, 180f, Time.deltaTime);
			CalcParams(out currentCameraParamsData);
			float time = Time.time;
			for (int num = cameraParamsOverrides.Count - 1; num >= 0; num--)
			{
				if (cameraParamsOverrides[num].exitEndTime <= time)
				{
					cameraParamsOverrides.RemoveAt(num);
				}
			}
		}

		public CameraParamsOverrideHandle AddParamsOverride(CameraParamsOverrideRequest request, float transitionDuration = 0.2f)
		{
			float time = Time.time;
			CameraParamsOverride cameraParamsOverride = new CameraParamsOverride
			{
				cameraParamsData = request.cameraParamsData,
				enterStartTime = time,
				enterEndTime = time + transitionDuration,
				exitStartTime = float.PositiveInfinity,
				exitEndTime = float.PositiveInfinity,
				priority = request.priority
			};
			int i;
			for (i = 0; i < cameraParamsOverrides.Count && !(request.priority <= cameraParamsOverrides[i].priority); i++)
			{
			}
			cameraParamsOverrides.Insert(i, cameraParamsOverride);
			return new CameraParamsOverrideHandle(cameraParamsOverride);
		}

		public CameraParamsOverrideHandle RemoveParamsOverride(CameraParamsOverrideHandle handle, float transitionDuration = 0.2f)
		{
			if (cameraParamsOverrides == null)
			{
				return default(CameraParamsOverrideHandle);
			}
			CameraParamsOverride cameraParamsOverride = null;
			for (int i = 0; i < cameraParamsOverrides.Count; i++)
			{
				if (handle.target == cameraParamsOverrides[i])
				{
					cameraParamsOverride = cameraParamsOverrides[i];
					break;
				}
			}
			if (cameraParamsOverride == null || cameraParamsOverride.exitStartTime != float.PositiveInfinity)
			{
				return default(CameraParamsOverrideHandle);
			}
			cameraParamsOverride.exitEndTime = (cameraParamsOverride.exitStartTime = Time.time) + transitionDuration;
			return default(CameraParamsOverrideHandle);
		}

		public void CalcParams(out CharacterCameraParamsData dest)
		{
			dest = (cameraParams ? cameraParams.data : CharacterCameraParamsData.basic);
			float time = Time.time;
			for (int i = 0; i < cameraParamsOverrides.Count; i++)
			{
				CameraParamsOverride cameraParamsOverride = cameraParamsOverrides[i];
				if (cameraParamsOverride != null && cameraParamsOverride.cameraParamsData.overrideFirstPersonFadeDuration > 0f)
				{
					dest.overrideFirstPersonFadeDuration += cameraParamsOverride.cameraParamsData.overrideFirstPersonFadeDuration;
				}
				CharacterCameraParamsData.Blend(in cameraParamsOverride.cameraParamsData, ref dest, cameraParamsOverride.CalculateAlpha(time));
			}
		}
	}
	public class CampDirector : MonoBehaviour
	{
		private struct NodeDistanceSqrPair
		{
			public NodeGraph.NodeIndex nodeIndex;

			public float distanceSqr;
		}

		[Header("Main Properties")]
		[Tooltip("Which interactables the camp can spawn. If left blank, will fall back to the stage's.")]
		public DirectorCardCategorySelection interactableDirectorCards;

		public int baseMonsterCredit;

		public int baseInteractableCredit;

		public float campMinimumRadius;

		public float campMaximumRadius;

		public Transform campCenterTransform;

		public CombatDirector combatDirector;

		[Header("Combat Director Properties")]
		public EliteDef eliteDef;

		[Header("Optional Properties")]
		public bool scaleMonsterCreditWithDifficultyCoefficient;

		[Range(0f, 1f)]
		[Tooltip("The amount of credits to take away from the scenedirector's monster credits. A value of 1 takes away all the credits the camp spends - a value of 0 takes away none.")]
		public float monsterCreditPenaltyCoefficient = 0.5f;

		private Xoroshiro128Plus rng;

		private int monsterCredit;

		private static readonly WeightedSelection<DirectorCard> cardSelector = new WeightedSelection<DirectorCard>();

		private void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint);
				CalculateCredits();
				PopulateCamp();
			}
		}

		private void OnEnable()
		{
			SceneDirector.onPrePopulateMonstersSceneServer += OnSceneDirectorPrePopulate;
		}

		private void OnDisable()
		{
			SceneDirector.onPrePopulateMonstersSceneServer -= OnSceneDirectorPrePopulate;
		}

		private void OnSceneDirectorPrePopulate(SceneDirector sceneDirector)
		{
			CalculateCredits();
			sceneDirector.ReduceMonsterCredits((int)((float)monsterCredit * monsterCreditPenaltyCoefficient));
		}

		private WeightedSelection<DirectorCard> GenerateInteractableCardSelection()
		{
			DirectorCardCategorySelection directorCardCategorySelection = ScriptableObject.CreateInstance<DirectorCardCategorySelection>();
			if ((bool)interactableDirectorCards)
			{
				directorCardCategorySelection.CopyFrom(interactableDirectorCards);
			}
			else if ((bool)ClassicStageInfo.instance && (bool)ClassicStageInfo.instance.interactableCategories)
			{
				directorCardCategorySelection.CopyFrom(ClassicStageInfo.instance.interactableCategories);
			}
			WeightedSelection<DirectorCard> result = directorCardCategorySelection.GenerateDirectorCardWeightedSelection();
			UnityEngine.Object.Destroy(directorCardCategorySelection);
			return result;
		}

		private void PopulateCamp()
		{
			WeightedSelection<DirectorCard> deck = GenerateInteractableCardSelection();
			while (baseInteractableCredit > 0)
			{
				DirectorCard directorCard = SelectCard(deck, baseInteractableCredit);
				if (directorCard == null)
				{
					break;
				}
				if (!directorCard.IsAvailable())
				{
					continue;
				}
				baseInteractableCredit -= directorCard.cost;
				if (!Run.instance)
				{
					continue;
				}
				for (int i = 0; i < 10; i++)
				{
					DirectorPlacementRule placementRule = new DirectorPlacementRule
					{
						placementMode = DirectorPlacementRule.PlacementMode.Approximate,
						minDistance = campMinimumRadius,
						maxDistance = campMaximumRadius,
						position = campCenterTransform.position,
						spawnOnTarget = campCenterTransform
					};
					GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(directorCard.spawnCard, placementRule, rng));
					if ((bool)gameObject)
					{
						PurchaseInteraction component = gameObject.GetComponent<PurchaseInteraction>();
						if ((bool)component && component.costType == CostTypeIndex.Money)
						{
							component.Networkcost = Run.instance.GetDifficultyScaledCost(component.cost);
						}
						break;
					}
				}
			}
			if ((bool)Run.instance && CombatDirector.cvDirectorCombatDisable.value)
			{
				monsterCredit = 0;
			}
			if ((bool)combatDirector)
			{
				combatDirector.monsterCredit += monsterCredit;
				monsterCredit = 0;
				combatDirector.onSpawnedServer.AddListener(OnMonsterSpawnedServer);
				combatDirector.SpendAllCreditsOnMapSpawns(campCenterTransform);
				combatDirector.onSpawnedServer.RemoveListener(OnMonsterSpawnedServer);
			}
			void OnMonsterSpawnedServer(GameObject masterObject)
			{
				EquipmentIndex equipmentIndex = eliteDef?.eliteEquipmentDef?.equipmentIndex ?? EquipmentIndex.None;
				CharacterMaster component2 = masterObject.GetComponent<CharacterMaster>();
				GameObject bodyObject = component2.GetBodyObject();
				if ((bool)bodyObject)
				{
					EntityStateMachine[] components = bodyObject.GetComponents<EntityStateMachine>();
					foreach (EntityStateMachine obj in components)
					{
						obj.initialStateType = obj.mainStateType;
					}
				}
				if (equipmentIndex != EquipmentIndex.None)
				{
					component2.inventory.SetEquipmentIndex(equipmentIndex);
				}
			}
		}

		private DirectorCard SelectCard(WeightedSelection<DirectorCard> deck, int maxCost)
		{
			cardSelector.Clear();
			int i = 0;
			for (int count = deck.Count; i < count; i++)
			{
				WeightedSelection<DirectorCard>.ChoiceInfo choice = deck.GetChoice(i);
				if (choice.value.cost <= maxCost)
				{
					cardSelector.AddChoice(choice);
				}
			}
			if (cardSelector.Count == 0)
			{
				return null;
			}
			return cardSelector.Evaluate(rng.nextNormalizedFloat);
		}

		private void CalculateCredits()
		{
			if (scaleMonsterCreditWithDifficultyCoefficient)
			{
				monsterCredit = Mathf.CeilToInt((float)baseMonsterCredit * Run.instance.difficultyCoefficient);
			}
			else
			{
				monsterCredit = baseMonsterCredit;
			}
		}
	}
	public class CaptainDefenseMatrixController : MonoBehaviour
	{
		public int defenseMatrixToGrantPlayer = 1;

		public int defenseMatrixToGrantMechanicalAllies = 1;

		private CharacterBody characterBody;

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				TryGrantItem();
			}
		}

		private void OnEnable()
		{
			if (NetworkServer.active)
			{
				MasterSummon.onServerMasterSummonGlobal += OnServerMasterSummonGlobal;
			}
		}

		private void OnDisable()
		{
			if (NetworkServer.active)
			{
				MasterSummon.onServerMasterSummonGlobal -= OnServerMasterSummonGlobal;
			}
		}

		private void TryGrantItem()
		{
			if ((bool)characterBody.master)
			{
				bool flag = false;
				if ((bool)characterBody.master.playerStatsComponent)
				{
					flag = characterBody.master.playerStatsComponent.currentStats.GetStatValueDouble(PerBodyStatDef.totalTimeAlive, BodyCatalog.GetBodyName(characterBody.bodyIndex)) > 0.0;
				}
				if (!flag && characterBody.master.inventory.GetItemCount(RoR2Content.Items.CaptainDefenseMatrix) <= 0)
				{
					characterBody.master.inventory.GiveItem(RoR2Content.Items.CaptainDefenseMatrix, defenseMatrixToGrantPlayer);
				}
			}
		}

		private void OnServerMasterSummonGlobal(MasterSummon.MasterSummonReport summonReport)
		{
			if (!characterBody.master || !(characterBody.master == summonReport.leaderMasterInstance))
			{
				return;
			}
			CharacterMaster summonMasterInstance = summonReport.summonMasterInstance;
			if ((bool)summonMasterInstance)
			{
				CharacterBody body = summonMasterInstance.GetBody();
				if ((bool)body && (body.bodyFlags & CharacterBody.BodyFlags.Mechanical) != 0)
				{
					summonMasterInstance.inventory.GiveItem(RoR2Content.Items.CaptainDefenseMatrix, defenseMatrixToGrantMechanicalAllies);
				}
			}
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class CaptainSupplyDropController : NetworkBehaviour
	{
		[Header("Referenced Components")]
		public GenericSkill orbitalStrikeSkill;

		public GenericSkill prepSupplyDropSkill;

		public GenericSkill supplyDrop1Skill;

		public GenericSkill supplyDrop2Skill;

		[Header("Skill Defs")]
		public SkillDef usedUpSkillDef;

		public SkillDef lostConnectionSkillDef;

		[SyncVar]
		private byte netEnabledSkillsMask;

		private byte authorityEnabledSkillsMask;

		private bool attemptSupplyDropReset;

		private CharacterBody characterBody;

		[CanBeNull]
		private SkillDef currentSupplyDrop1SkillDef;

		[CanBeNull]
		private SkillDef currentSupplyDrop2SkillDef;

		[CanBeNull]
		private SkillDef currentPrepSupplyDropSkillDef;

		[CanBeNull]
		private SkillDef currentOrbitalStrikeSkillDef;

		private static int kCmdCmdSetSkillMask;

		private bool canUseOrbitalSkills
		{
			get
			{
				if (SceneCatalog.mostRecentSceneDef.sceneType != SceneType.Stage)
				{
					return SceneCatalog.mostRecentSceneDef.sceneType == SceneType.UntimedStage;
				}
				return true;
			}
		}

		private bool hasEffectiveAuthority => characterBody.hasEffectiveAuthority;

		public byte NetworknetEnabledSkillsMask
		{
			get
			{
				return netEnabledSkillsMask;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref netEnabledSkillsMask, 1u);
			}
		}

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
			attemptSupplyDropReset = (bool)supplyDrop1Skill || (bool)supplyDrop2Skill;
			Release.onEnter += OnPodRelease;
		}

		private void OnPodRelease(Release state, CharacterBody body)
		{
			if ((object)body == characterBody && base.hasAuthority)
			{
				CheckSkillsForReset();
				if ((bool)supplyDrop1Skill && supplyDrop1Skill.stock == 0)
				{
					UnityEngine.Debug.LogError($"SupplyDrop1Skill's got no stocks, max stock = {supplyDrop1Skill.maxStock}.  Forcing one stock");
					supplyDrop1Skill.AddOneStock();
				}
				if ((bool)supplyDrop2Skill && supplyDrop2Skill.stock == 0)
				{
					UnityEngine.Debug.LogError($"SupplyDrop2Skill's got no stocks, max stock = {supplyDrop2Skill.maxStock}.  Forcing one stock");
					supplyDrop2Skill.AddOneStock();
				}
			}
		}

		private void FixedUpdate()
		{
			UpdateSkillOverrides();
			if (hasEffectiveAuthority && attemptSupplyDropReset)
			{
				CheckSkillsForReset();
				attemptSupplyDropReset = (!supplyDrop1Skill || supplyDrop1Skill.stock == 0) && (!supplyDrop2Skill || supplyDrop2Skill.stock == 0);
				_ = attemptSupplyDropReset;
			}
		}

		private void CheckSkillsForReset()
		{
			if ((bool)supplyDrop1Skill && supplyDrop1Skill.stock == 0)
			{
				if (supplyDrop1Skill.maxStock <= 0)
				{
					UnityEngine.Debug.LogError($"SupplyDrop1Skill's max stock = {supplyDrop1Skill.maxStock}.  Recalculating...");
					supplyDrop1Skill.RecalculateValues();
				}
				if (supplyDrop1Skill.maxStock > 0)
				{
					supplyDrop1Skill.Reset();
				}
			}
			if ((bool)supplyDrop2Skill && supplyDrop2Skill.stock == 0)
			{
				if (supplyDrop2Skill.maxStock <= 0)
				{
					UnityEngine.Debug.LogError($"SupplyDrop2Skill's max stock = {supplyDrop2Skill.maxStock}.  Recalculating...");
					supplyDrop2Skill.RecalculateValues();
				}
				if (supplyDrop2Skill.maxStock > 0)
				{
					supplyDrop2Skill.Reset();
				}
			}
		}

		private void OnDisable()
		{
			SetSkillOverride(ref currentSupplyDrop1SkillDef, null, supplyDrop1Skill);
			SetSkillOverride(ref currentSupplyDrop2SkillDef, null, supplyDrop2Skill);
		}

		private void SetSkillOverride([CanBeNull] ref SkillDef currentSkillDef, [CanBeNull] SkillDef newSkillDef, [NotNull] GenericSkill component)
		{
			if ((object)currentSkillDef != newSkillDef)
			{
				if ((object)currentSkillDef != null)
				{
					component.UnsetSkillOverride(this, currentSkillDef, GenericSkill.SkillOverridePriority.Contextual);
				}
				currentSkillDef = newSkillDef;
				if ((object)currentSkillDef != null)
				{
					component.SetSkillOverride(this, currentSkillDef, GenericSkill.SkillOverridePriority.Contextual);
				}
			}
		}

		private void UpdateSkillOverrides()
		{
			if (!base.enabled)
			{
				return;
			}
			byte b = 0;
			if (hasEffectiveAuthority)
			{
				byte b2 = 0;
				if (supplyDrop1Skill.stock > 0 || !supplyDrop1Skill.skillDef)
				{
					b2 = (byte)(b2 | 1u);
				}
				if (supplyDrop2Skill.stock > 0 || !supplyDrop2Skill.skillDef)
				{
					b2 = (byte)(b2 | 2u);
				}
				if (b2 != authorityEnabledSkillsMask)
				{
					authorityEnabledSkillsMask = b2;
					if (NetworkServer.active)
					{
						NetworknetEnabledSkillsMask = authorityEnabledSkillsMask;
					}
					else
					{
						CallCmdSetSkillMask(authorityEnabledSkillsMask);
					}
				}
				b = authorityEnabledSkillsMask;
			}
			else
			{
				b = netEnabledSkillsMask;
			}
			bool flag = (b & 1) != 0;
			bool flag2 = (b & 2) != 0;
			SetSkillOverride(ref currentSupplyDrop1SkillDef, flag ? null : usedUpSkillDef, supplyDrop1Skill);
			SetSkillOverride(ref currentSupplyDrop2SkillDef, flag2 ? null : usedUpSkillDef, supplyDrop2Skill);
		}

		[Command]
		private void CmdSetSkillMask(byte newMask)
		{
			NetworknetEnabledSkillsMask = newMask;
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdSetSkillMask(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetSkillMask called on client.");
			}
			else
			{
				((CaptainSupplyDropController)obj).CmdSetSkillMask((byte)reader.ReadPackedUInt32());
			}
		}

		public void CallCmdSetSkillMask(byte newMask)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetSkillMask called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetSkillMask(newMask);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetSkillMask);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32(newMask);
			SendCommandInternal(networkWriter, 0, "CmdSetSkillMask");
		}

		static CaptainSupplyDropController()
		{
			kCmdCmdSetSkillMask = 176967897;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CaptainSupplyDropController), kCmdCmdSetSkillMask, InvokeCmdCmdSetSkillMask);
			NetworkCRC.RegisterBehaviour("CaptainSupplyDropController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32(netEnabledSkillsMask);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(netEnabledSkillsMask);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				netEnabledSkillsMask = (byte)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				netEnabledSkillsMask = (byte)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[DisallowMultipleComponent]
	[RequireComponent(typeof(TeamComponent))]
	[RequireComponent(typeof(SkillLocator))]
	public class CharacterBody : NetworkBehaviour, ILifeBehavior, IDisplayNameProvider, IOnTakeDamageServerReceiver, IOnKilledOtherServerReceiver
	{
		public static class CommonAssets
		{
			public static SkillDef lunarUtilityReplacementSkillDef;

			public static SkillDef lunarPrimaryReplacementSkillDef;

			public static SkillDef lunarSecondaryReplacementSkillDef;

			public static SkillDef lunarSpecialReplacementSkillDef;

			public static NetworkSoundEventDef nullifiedBuffAppliedSound;

			public static NetworkSoundEventDef pulverizeBuildupBuffAppliedSound;

			public static NetworkSoundEventDef[] procCritAttackSpeedSounds;

			public static GameObject thornExplosionEffect;

			public static GameObject teleportOnLowHealthVFX;

			public static GameObject teleportOnLowHealthExplosion;

			public static GameObject teleportOnLowHealthExplosionNova;

			public static GameObject prayerBeadEffect;

			public static GameObject goldOnStageStartEffect;

			public static void Load()
			{
				LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseNullifiedBuffApplied", delegate(NetworkSoundEventDef asset)
				{
					nullifiedBuffAppliedSound = asset;
				});
				LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nsePulverizeBuildupBuffApplied", delegate(NetworkSoundEventDef asset)
				{
					pulverizeBuildupBuffAppliedSound = asset;
				});
				procCritAttackSpeedSounds = new NetworkSoundEventDef[3];
				LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseProcCritAttackSpeed1", delegate(NetworkSoundEventDef asset)
				{
					procCritAttackSpeedSounds[0] = asset;
				});
				LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseProcCritAttackSpeed2", delegate(NetworkSoundEventDef asset)
				{
					procCritAttackSpeedSounds[1] = asset;
				});
				LegacyResourcesAPI.LoadAsyncCallback("NetworkSoundEventDefs/nseProcCritAttackSpeed3", delegate(NetworkSoundEventDef asset)
				{
					procCritAttackSpeedSounds[2] = asset;
				});
				AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/NoxiousThornExplosion");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					thornExplosionEffect = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/TeleportOnLowHealthVFX");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					teleportOnLowHealthVFX = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/TeleportOnLowHealthExplosion");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					teleportOnLowHealthExplosion = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/VagrantNovaExplosion");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					teleportOnLowHealthExplosionNova = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ExtraStatsOnLevelUpScrapEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					prayerBeadEffect = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/GoldOnStageStartCoinGain");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					goldOnStageStartEffect = x.Result;
				};
				SkillCatalog.skillsDefined.CallWhenAvailable(delegate
				{
					lunarUtilityReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarUtilityReplacement"));
					lunarPrimaryReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarPrimaryReplacement"));
					lunarSecondaryReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarSecondaryReplacement"));
					lunarSpecialReplacementSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("LunarDetonatorSpecialReplacement"));
				});
			}
		}

		private class TimedBuff
		{
			public BuffIndex buffIndex;

			public float timer;
		}

		public delegate void JumpDelegate();

		[Flags]
		public enum BodyFlags : uint
		{
			None = 0u,
			IgnoreFallDamage = 1u,
			Mechanical = 2u,
			Masterless = 4u,
			ImmuneToGoo = 8u,
			ImmuneToExecutes = 0x10u,
			SprintAnyDirection = 0x20u,
			ResistantToAOE = 0x40u,
			HasBackstabPassive = 0x80u,
			HasBackstabImmunity = 0x100u,
			OverheatImmune = 0x200u,
			Void = 0x400u,
			ImmuneToVoidDeath = 0x800u,
			IgnoreItemUpdates = 0x1000u,
			Devotion = 0x2000u,
			IgnoreKnockback = 0x4000u,
			ImmuneToLava = 0x8000u
		}

		private struct ItemAvailability
		{
			public int helfireCount;

			public bool hasFireTrail;

			public bool hasAffixLunar;

			public bool hasAffixPoison;
		}

		[Serializable]
		public struct NetworkItemBehaviorData
		{
			public int intItemValue;

			public float floatValue;

			public ItemIndex itemIndex
			{
				get
				{
					return (ItemIndex)intItemValue;
				}
				set
				{
					intItemValue = (int)value;
				}
			}

			public NetworkItemBehaviorData(ItemIndex _index, float _floatValue)
			{
				intItemValue = (int)_index;
				floatValue = _floatValue;
			}

			public NetworkItemBehaviorData(int _index, float _floatVal)
			{
				intItemValue = _index;
				floatValue = _floatVal;
			}
		}

		public class ItemBehavior : MonoBehaviour
		{
			public CharacterBody body;

			public int stack;
		}

		public class AffixHauntedBehavior : ItemBehavior
		{
			private GameObject affixHauntedWard;

			private void FixedUpdate()
			{
				if (!NetworkServer.active)
				{
					return;
				}
				bool flag = stack > 0;
				if ((bool)affixHauntedWard != flag)
				{
					if (flag)
					{
						affixHauntedWard = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/AffixHauntedWard"));
						affixHauntedWard.GetComponent<TeamFilter>().teamIndex = body.teamComponent.teamIndex;
						affixHauntedWard.GetComponent<BuffWard>().Networkradius = 30f + body.radius;
						affixHauntedWard.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(body.gameObject);
					}
					else
					{
						UnityEngine.Object.Destroy(affixHauntedWard);
						affixHauntedWard = null;
					}
				}
			}

			private void OnDisable()
			{
				if ((bool)affixHauntedWard)
				{
					UnityEngine.Object.Destroy(affixHauntedWard);
				}
			}
		}

		public class QuestVolatileBatteryBehaviorServer : ItemBehavior
		{
			private NetworkedBodyAttachment attachment;

			private void Start()
			{
				attachment = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/QuestVolatileBatteryAttachment")).GetComponent<NetworkedBodyAttachment>();
				attachment.AttachToGameObjectAndSpawn(body.gameObject);
			}

			private void OnDestroy()
			{
				if ((bool)attachment)
				{
					UnityEngine.Object.Destroy(attachment.gameObject);
					attachment = null;
				}
			}
		}

		public class TimeBubbleItemBehaviorServer : ItemBehavior
		{
			private void OnDestroy()
			{
				if ((bool)body.timeBubbleWardInstance)
				{
					UnityEngine.Object.Destroy(body.timeBubbleWardInstance);
				}
			}
		}

		public class ElementalRingsBehavior : ItemBehavior
		{
			private void OnDisable()
			{
				if ((bool)body)
				{
					if (body.HasBuff(RoR2Content.Buffs.ElementalRingsReady))
					{
						body.RemoveBuff(RoR2Content.Buffs.ElementalRingsReady);
					}
					if (body.HasBuff(RoR2Content.Buffs.ElementalRingsCooldown))
					{
						body.RemoveBuff(RoR2Content.Buffs.ElementalRingsCooldown);
					}
				}
			}

			private void FixedUpdate()
			{
				bool flag = body.HasBuff(RoR2Content.Buffs.ElementalRingsCooldown);
				bool flag2 = body.HasBuff(RoR2Content.Buffs.ElementalRingsReady);
				if (!flag && !flag2)
				{
					body.AddBuff(RoR2Content.Buffs.ElementalRingsReady);
				}
				if (flag2 && flag)
				{
					body.RemoveBuff(RoR2Content.Buffs.ElementalRingsReady);
				}
			}
		}

		public class AffixEchoBehavior : ItemBehavior
		{
			private DeployableMinionSpawner echoSpawner1;

			private DeployableMinionSpawner echoSpawner2;

			private CharacterSpawnCard spawnCard;

			private List<CharacterMaster> spawnedEchoes = new List<CharacterMaster>();

			private void FixedUpdate()
			{
				spawnCard.nodeGraphType = (body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground);
			}

			private void Awake()
			{
				base.enabled = false;
			}

			private void OnEnable()
			{
				MasterCatalog.MasterIndex masterIndex = MasterCatalog.FindAiMasterIndexForBody(body.bodyIndex);
				spawnCard = ScriptableObject.CreateInstance<CharacterSpawnCard>();
				spawnCard.prefab = MasterCatalog.GetMasterPrefab(masterIndex);
				spawnCard.inventoryToCopy = body.inventory;
				spawnCard.equipmentToGrant = new EquipmentDef[1];
				spawnCard.itemsToGrant = new ItemCountPair[1]
				{
					new ItemCountPair
					{
						itemDef = RoR2Content.Items.SummonedEcho,
						count = 1
					}
				};
				CreateSpawners();
			}

			private void OnDisable()
			{
				UnityEngine.Object.Destroy(spawnCard);
				spawnCard = null;
				for (int num = spawnedEchoes.Count - 1; num >= 0; num--)
				{
					if ((bool)spawnedEchoes[num])
					{
						spawnedEchoes[num].TrueKill();
					}
				}
				DestroySpawners();
			}

			private void CreateSpawners()
			{
				Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.seed ^ (ulong)GetInstanceID());
				CreateSpawner(ref echoSpawner1, DeployableSlot.RoboBallRedBuddy, spawnCard);
				CreateSpawner(ref echoSpawner2, DeployableSlot.RoboBallGreenBuddy, spawnCard);
				void CreateSpawner(ref DeployableMinionSpawner buddySpawner, DeployableSlot deployableSlot, SpawnCard spawnCard)
				{
					buddySpawner = new DeployableMinionSpawner(body.master, deployableSlot, rng)
					{
						respawnInterval = 30f,
						spawnCard = spawnCard
					};
					buddySpawner.onMinionSpawnedServer += OnMinionSpawnedServer;
				}
			}

			private void DestroySpawners()
			{
				echoSpawner1?.Dispose();
				echoSpawner1 = null;
				echoSpawner2?.Dispose();
				echoSpawner2 = null;
			}

			private void OnMinionSpawnedServer(SpawnCard.SpawnResult spawnResult)
			{
				GameObject spawnedInstance = spawnResult.spawnedInstance;
				if (!spawnedInstance)
				{
					return;
				}
				CharacterMaster spawnedMaster = spawnedInstance.GetComponent<CharacterMaster>();
				if ((bool)spawnedMaster)
				{
					spawnedEchoes.Add(spawnedMaster);
					OnDestroyCallback.AddCallback(spawnedMaster.gameObject, delegate
					{
						spawnedEchoes.Remove(spawnedMaster);
					});
				}
			}
		}

		private static class AssetReferences
		{
			public static GameObject engiShieldTempEffectPrefab;

			public static GameObject bucklerShieldTempEffectPrefab;

			public static GameObject slowDownTimeTempEffectPrefab;

			public static GameObject crippleEffectPrefab;

			public static GameObject tonicBuffEffectPrefab;

			public static GameObject weakTempEffectPrefab;

			public static GameObject energizedTempEffectPrefab;

			public static GameObject barrierTempEffectPrefab;

			public static GameObject nullifyStack1EffectPrefab;

			public static GameObject nullifyStack2EffectPrefab;

			public static GameObject nullifyStack3EffectPrefab;

			public static GameObject regenBoostEffectPrefab;

			public static GameObject elephantDefenseEffectPrefab;

			public static GameObject healingDisabledEffectPrefab;

			public static GameObject noCooldownEffectPrefab;

			public static GameObject doppelgangerEffectPrefab;

			public static GameObject deathmarkEffectPrefab;

			public static GameObject crocoRegenEffectPrefab;

			public static GameObject mercExposeEffectPrefab;

			public static GameObject lifestealOnHitEffectPrefab;

			public static GameObject teamWarCryEffectPrefab;

			public static GameObject randomDamageEffectPrefab;

			public static GameObject lunarGolemShieldEffectPrefab;

			public static GameObject warbannerEffectPrefab;

			public static GameObject teslaFieldEffectPrefab;

			public static GameObject lunarSecondaryRootEffectPrefab;

			public static GameObject lunarDetonatorEffectPrefab;

			public static GameObject fruitingEffectPrefab;

			public static GameObject mushroomVoidTempEffectPrefab;

			public static GameObject bearVoidTempEffectPrefab;

			public static GameObject outOfCombatArmorEffectPrefab;

			public static GameObject voidFogMildEffectPrefab;

			public static GameObject voidFogStrongEffectPrefab;

			public static GameObject voidJailerSlowEffectPrefab;

			public static GameObject voidRaidcrabWardWipeFogEffectPrefab;

			public static GameObject aurelioniteBlessingEffectInstance;

			public static GameObject permanentDebuffEffectPrefab;

			public static void Resolve()
			{
				AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/EngiShield");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					engiShieldTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/BucklerDefense");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					bucklerShieldTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/SlowDownTime");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					slowDownTimeTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/CrippleEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					crippleEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/TonicBuffEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					tonicBuffEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/WeakEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					weakTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/EnergizedEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					energizedTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/BarrierEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					barrierTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/RegenBoostEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					regenBoostEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/ElephantDefense");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					elephantDefenseEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/HealingDisabledEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					healingDisabledEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/NoCooldownEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					noCooldownEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/DoppelgangerEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					doppelgangerEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/NullifyStack1Effect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					nullifyStack1EffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/NullifyStack2Effect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					nullifyStack2EffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/NullifyStack3Effect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					nullifyStack3EffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/DeathMarkEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					deathmarkEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/CrocoRegenEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					crocoRegenEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/MercExposeEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					mercExposeEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/LifeStealOnHitAura");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					lifestealOnHitEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/TeamWarCryAura");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					teamWarCryEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/LunarDefense");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					lunarGolemShieldEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/RandomDamageBuffEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					randomDamageEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/WarbannerBuffEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					warbannerEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/TeslaFieldBuffEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					teslaFieldEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/LunarSecondaryRootEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					lunarSecondaryRootEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/LunarDetonatorEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					lunarDetonatorEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/FruitingEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					fruitingEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/MushroomVoidEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					mushroomVoidTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/BearVoidEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					bearVoidTempEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/VoidFogMildEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					voidFogMildEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/TemporaryVisualEffects/VoidFogStrongEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					voidFogStrongEffectPrefab = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/VoidRaidCrab/VoidRaidCrabWardWipeFogEffect.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					voidRaidcrabWardWipeFogEffectPrefab = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/OutOfCombatArmor/OutOfCombatArmorEffect.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					outOfCombatArmorEffectPrefab = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/VoidJailer/VoidJailerTetherDebuff.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					voidJailerSlowEffectPrefab = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC2/Elites/EliteAurelionite/AffixAurelioniteArmorBubble.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					aurelioniteBlessingEffectInstance = x.Result;
				};
			}
		}

		private class ConstructTurretMessage : MessageBase
		{
			public GameObject builder;

			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;

			public MasterCatalog.NetworkMasterIndex turretMasterIndex;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(builder);
				writer.Write(position);
				writer.Write(rotation);
				GeneratedNetworkCode._WriteNetworkMasterIndex_MasterCatalog(writer, turretMasterIndex);
			}

			public override void Deserialize(NetworkReader reader)
			{
				builder = reader.ReadGameObject();
				position = reader.ReadVector3();
				rotation = reader.ReadQuaternion();
				turretMasterIndex = GeneratedNetworkCode._ReadNetworkMasterIndex_MasterCatalog(reader);
			}
		}

		private class DelayedDamageInfo
		{
			public DamageInfo halfDamage = new DamageInfo();

			public float timeUntilDamage = 3f;
		}

		public class TeleportOnLowHealthBehavior : ItemBehavior
		{
			private CharacterBody characterBody;

			private bool hasActivated;

			private bool hasItem;

			private bool hasBuff;

			private bool hasCooldown;

			private void Start()
			{
				if (!hasActivated)
				{
					characterBody = GetComponent<CharacterBody>();
					characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth);
					characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown);
					characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown);
					characterBody.AddBuff(DLC2Content.Buffs.TeleportOnLowHealth);
					characterBody.hasTeleported = false;
					hasActivated = true;
				}
			}

			private void Update()
			{
				hasItem = characterBody.inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth) > 0;
				hasBuff = characterBody.HasBuff(DLC2Content.Buffs.TeleportOnLowHealth);
				hasCooldown = characterBody.HasBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown);
				if (!hasItem)
				{
					if (hasBuff)
					{
						characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth);
					}
					if (hasCooldown)
					{
						characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown);
					}
				}
				else if (!hasBuff && !hasCooldown && characterBody.hasTeleported)
				{
					characterBody.AddBuff(DLC2Content.Buffs.TeleportOnLowHealth);
					characterBody.hasTeleported = false;
				}
			}

			private void OnDisable()
			{
				characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth);
				characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown);
				characterBody.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown);
			}
		}

		public class DelayedDamageBehavior : ItemBehavior
		{
			private CharacterBody characterBody;

			private bool hasActivated;

			private bool hasItem;

			private bool hasBuff;

			private bool hasCooldown;

			private void Start()
			{
				if (!hasActivated)
				{
					characterBody = GetComponent<CharacterBody>();
					hasActivated = true;
				}
			}

			private void Update()
			{
				hasItem = characterBody.inventory.GetItemCount(DLC2Content.Items.DelayedDamage) > 0;
				hasBuff = characterBody.HasBuff(DLC2Content.Buffs.DelayedDamageBuff);
				hasCooldown = characterBody.HasBuff(DLC2Content.Buffs.DelayedDamageBuff);
				if (!hasItem)
				{
					if (hasBuff)
					{
						characterBody.RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff);
						characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.DelayedDamageBuff);
					}
					if (hasCooldown)
					{
						characterBody.RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff);
						characterBody.RemoveOldestTimedBuff(DLC2Content.Buffs.DelayedDamageBuff);
						characterBody.RemoveBuff(DLC2Content.Buffs.DelayedDamageDebuff);
					}
				}
			}
		}

		public class MeteorAttackOnHighDamageBehavior : ItemBehavior
		{
			private CharacterBody characterBody;

			private bool hasActivated;

			private void FixedUpdate()
			{
				if (!hasActivated)
				{
					characterBody = GetComponent<CharacterBody>();
					hasActivated = true;
				}
				if (characterBody.runicLensMeteorReady)
				{
					characterBody.runicLensStartTime = Run.instance.time;
					if (characterBody.runicLensStartTime >= characterBody.runicLensImpactTime && characterBody.runicLensMeteorReady)
					{
						characterBody.detonateRunicLensMeteor();
						characterBody.runicLensMeteorReady = false;
					}
				}
			}
		}

		[Serializable]
		public class CharacterBodyUnityEvent : UnityEvent<CharacterBody>
		{
		}

		[HideInInspector]
		[Tooltip("This is assigned to the prefab automatically by BodyCatalog at runtime. Do not set this value manually.")]
		public BodyIndex bodyIndex = BodyIndex.None;

		public bool CharacterIsVisible;

		[Tooltip("How much the combat director paid for this character. If this enemy is culled, then we refund the combat director for the cost it paid to spawn us.")]
		public float cost = -1f;

		public bool dontCull;

		[Tooltip("The baseline importance for this character. 0 is standard, elites get a +2 modifier, bosses get +10, players get +5000. Characters of low importance are culled in some circumstances.")]
		public int BaseImportance;

		[Tooltip("The dynamically calculated level of importance for this enemy.")]
		public int Importance = -1;

		public bool inLava;

		[Tooltip("The language token to use as the base name of this character.")]
		public string baseNameToken;

		public string subtitleNameToken;

		private BuffIndex[] activeBuffsList;

		private int activeBuffsListCount;

		private int[] buffs;

		private int eliteBuffCount;

		private List<TimedBuff> timedBuffs = new List<TimedBuff>();

		[NonSerialized]
		public int pendingTonicAfflictionCount;

		public JumpDelegate onJump;

		private int previousMultiKillBuffCount;

		private GameObject warCryEffectInstance;

		[EnumMask(typeof(BodyFlags))]
		public BodyFlags bodyFlags;

		private NetworkInstanceId masterObjectId;

		private GameObject _masterObject;

		private CharacterMaster _master;

		private bool linkedToMaster;

		private bool disablingHurtBoxes;

		private EquipmentIndex previousEquipmentIndex = EquipmentIndex.None;

		private new Transform transform;

		private SfxLocator sfxLocator;

		public float lavaCooldown = 0.2f;

		private float lavaTimer;

		private ItemAvailability itemAvailability;

		private static List<CharacterBody> instancesList;

		public static readonly ReadOnlyCollection<CharacterBody> readOnlyInstancesList;

		private bool _isSprinting;

		private const float outOfCombatDelay = 5f;

		private const float outOfDangerDelay = 7f;

		private float outOfCombatStopwatch;

		private float outOfDangerStopwatch;

		private bool _outOfDanger = true;

		private UnityEngine.Vector3 previousPosition;

		private const float notMovingWait = 1f;

		private float notMovingStopwatch;

		public bool rootMotionInMainState;

		public float mainRootSpeed;

		public float baseMaxHealth;

		public float baseRegen;

		public float baseMaxShield;

		public float baseMoveSpeed;

		public float baseAcceleration;

		public float baseJumpPower;

		public float baseDamage;

		public float baseAttackSpeed;

		public float baseCrit;

		public float baseArmor;

		public float baseVisionDistance = float.PositiveInfinity;

		public int baseJumpCount = 1;

		public float sprintingSpeedMultiplier = 1.45f;

		public bool autoCalculateLevelStats;

		public float levelMaxHealth;

		public float levelRegen;

		public float levelMaxShield;

		public float levelMoveSpeed;

		public float levelJumpPower;

		public float levelDamage;

		public float levelAttackSpeed;

		public float levelCrit;

		public float levelArmor;

		private float m_surfaceSpeedBoost;

		private bool statsDirty;

		private int currentHealthLevel;

		private int oldHealthLevel;

		private float damageFromRecalculateStats;

		private int numberOfKills;

		private bool canCleanInventory = true;

		public int extraSecondaryFromSkill;

		public int extraSpecialFromSkill;

		private GameObject lowerHealthHigherDamageSteam;

		[HideInInspector]
		public LowerHealthHigherDamageEffectUpdater lowerHealthHigherDamageEffectUpdater;

		private bool boostAllStatsTimerStarted;

		private bool boostAllStatsCoolDownTimerStarted;

		private float boostAllStatsTimer;

		private float boostAllStatsTriggerTimer = 5f;

		private float boostAllStatsCoolDownTriggerTimer = 10f;

		private float boostAllStatsCoolDownStartTimer;

		private float boostAllStatsCoolDownTimer;

		private float boostAllStatsStartTimer;

		private float boostAllStatsTriggerChance;

		public bool canBoostAllStats;

		private float boostAllStatsDefaultTriggerChance = 0.25f;

		private float boostAllStatsTriggerIncrease = 0.1f;

		private float boostAllStatsMultiplier = 0.2f;

		private int extraStatsOnLevelUpCountModifier;

		[HideInInspector]
		public IncreaseDamageOnMultiKillItemDisplayUpdater increaseDamageOnMultiKillItemDisplayUpdater;

		private bool lowerPricedChestsActive;

		private bool canPurchaseLoweredPricedChests;

		public bool allSkillsDisabled;

		private ScreenDamageCalculatorDisabledSkills screenDamageSkillsDisabled;

		private int oldComboMeter;

		public bool isTeleporting;

		public int solitudeLevelCount;

		private float aimTimer;

		private const uint masterDirtyBit = 1u;

		private const uint buffsDirtyBit = 2u;

		private const uint outOfCombatBit = 4u;

		private const uint outOfDangerBit = 8u;

		private const uint sprintingBit = 16u;

		private const uint allDirtyBits = 31u;

		public Action<NetworkItemBehaviorData> OnNetworkItemBehaviorUpdate;

		private HelfireController helfireController;

		private float helfireLifetime;

		private DamageTrail fireTrail;

		public bool wasLucky;

		private const float poisonballAngle = 25f;

		private const float poisonballDamageCoefficient = 1f;

		private const float poisonballRefreshTime = 6f;

		private float poisonballTimer;

		private const float lunarMissileDamageCoefficient = 0.3f;

		private const float lunarMissileRefreshTime = 10f;

		private const float lunarMissileDelayBetweenShots = 0.1f;

		private float lunarMissileRechargeTimer = 10f;

		private float lunarMissileTimerBetweenShots;

		private int remainingMissilesToFire;

		private GameObject lunarMissilePrefab;

		private GameObject timeBubbleWardInstance;

		private TemporaryVisualEffect engiShieldTempEffectInstance;

		private TemporaryVisualEffect bucklerShieldTempEffectInstance;

		private TemporaryVisualEffect slowDownTimeTempEffectInstance;

		private TemporaryVisualEffect crippleEffectInstance;

		private TemporaryVisualEffect tonicBuffEffectInstance;

		private TemporaryVisualEffect weakTempEffectInstance;

		private TemporaryVisualEffect energizedTempEffectInstance;

		private TemporaryVisualEffect barrierTempEffectInstance;

		private TemporaryVisualEffect nullifyStack1EffectInstance;

		private TemporaryVisualEffect nullifyStack2EffectInstance;

		private TemporaryVisualEffect nullifyStack3EffectInstance;

		private TemporaryVisualEffect regenBoostEffectInstance;

		private TemporaryVisualEffect elephantDefenseEffectInstance;

		private TemporaryVisualEffect healingDisabledEffectInstance;

		private TemporaryVisualEffect noCooldownEffectInstance;

		private TemporaryVisualEffect doppelgangerEffectInstance;

		private TemporaryVisualEffect deathmarkEffectInstance;

		private TemporaryVisualEffect crocoRegenEffectInstance;

		private TemporaryVisualEffect mercExposeEffectInstance;

		private TemporaryVisualEffect lifestealOnHitEffectInstance;

		private TemporaryVisualEffect teamWarCryEffectInstance;

		private TemporaryVisualEffect randomDamageEffectInstance;

		private TemporaryVisualEffect lunarGolemShieldEffectInstance;

		private TemporaryVisualEffect warbannerEffectInstance;

		private TemporaryVisualEffect teslaFieldEffectInstance;

		private TemporaryVisualEffect lunarSecondaryRootEffectInstance;

		private TemporaryVisualEffect lunarDetonatorEffectInstance;

		private TemporaryVisualEffect fruitingEffectInstance;

		private TemporaryVisualEffect mushroomVoidTempEffectInstance;

		private TemporaryVisualEffect bearVoidTempEffectInstance;

		private TemporaryVisualEffect outOfCombatArmorEffectInstance;

		private TemporaryVisualEffect voidFogMildEffectInstance;

		private TemporaryVisualEffect voidFogStrongEffectInstance;

		private TemporaryVisualEffect voidJailerSlowEffectInstance;

		private TemporaryVisualEffect voidRaidcrabWardWipeFogEffectInstance;

		private TemporaryVisualEffect aurelioniteBlessingEffectInstance;

		[Tooltip("How long it takes for spread bloom to reset from full.")]
		public float spreadBloomDecayTime = 0.45f;

		[Tooltip("The spread bloom interpretation curve.")]
		public AnimationCurve spreadBloomCurve;

		private float spreadBloomInternal;

		[FormerlySerializedAs("crosshairPrefab")]
		[SerializeField]
		[Tooltip("The crosshair prefab used for this body.")]
		private GameObject _defaultCrosshairPrefab;

		[HideInInspector]
		public bool hideCrosshair;

		private const float multiKillMaxInterval = 1f;

		private float multiKillTimer;

		private const int multiKillThresholdForWarcry = 4;

		private const float increasedDamageMultiKillMaxInterval = 5f;

		private float increasedDamageKillTimer;

		private int oldKillcount;

		private const int multiKillThresholdForIncreasedDamage = 5;

		private int secondarySkillStacks;

		[HideInInspector]
		public IncreasePrimaryDamageEffectUpdater increasePrimaryDamageEffectUpdater;

		private float delayedDamageRefreshTime = 10f;

		private float secondHalfOfDamageTime = 3f;

		private int oldDelayedDamageCount;

		private bool halfDamageReady;

		private float halfDamageTimer;

		public bool protectFromOneShot;

		private DamageInfo secondHalfOfDamage;

		private List<DelayedDamageInfo> incomingDamageList = new List<DelayedDamageInfo>();

		public bool hasTeleported;

		private UnityEngine.Vector3 runicLensPosition;

		private EffectData runicLensEffectData = new EffectData();

		private DamageInfo runicLensDamageInfo = new DamageInfo();

		private float runicLensDamage;

		private float runicLensBlastForce;

		private float runicLensBlastRadius;

		private float runicLensStartTime;

		private float runicLensImpactTime;

		public bool runicLensMeteorReady;

		private bool hasStackableDebuff;

		private bool tamperedHeartActive;

		private float tamperedHeartRegenBonus;

		private float tamperedHeartMSpeedBonus;

		private float tamperedHeartDamageBonus;

		private float tamperedHeartAttackSpeedBonus;

		private float tamperedHeartArmorBonus;

		[Tooltip("The child transform to be used as the aiming origin.")]
		public Transform aimOriginTransform;

		[Tooltip("The hull size to use when pathfinding for this object.")]
		public HullClassification hullClassification;

		[Tooltip("The icon displayed for ally healthbars")]
		public Texture portraitIcon;

		[Tooltip("The main color of the body. Currently only used in the logbook.")]
		public UnityEngine.Color bodyColor = UnityEngine.Color.clear;

		[Tooltip("By default, players and enemies are assigned to either PlayerBody or EnemyBody, based on team. But some enemies (Gups) want a specific layer - this will skip that assignment.")]
		public bool doNotReassignToTeamBasedCollisionLayer;

		[FormerlySerializedAs("isBoss")]
		[Tooltip("Whether or not this is a boss for dropping items on death.")]
		public bool isChampion;

		public VehicleSeat currentVehicle;

		[Tooltip("The pod prefab to use for handling this character's first-time spawn animation.")]
		public GameObject preferredPodPrefab;

		[Tooltip("The preferred state to use for handling the character's first-time spawn animation. Only used with no preferred pod prefab.")]
		public SerializableEntityStateType preferredInitialStateType = new SerializableEntityStateType(typeof(Uninitialized));

		public uint skinIndex;

		public string customKillTotalStatName;

		public Transform overrideCoreTransform;

		private static int kCmdCmdAddTimedBuff;

		private static int kCmdCmdSetInLava;

		private static int kCmdCmdUpdateSprint;

		private static int kCmdCmdOnSkillActivated;

		private static int kCmdCmdTransmitItemBehavior;

		private static int kRpcRpcTransmitItemBehavior;

		private static int kCmdCmdSpawnDelayedDamageEffect;

		private static int kRpcRpcTeleportCharacterToSafety;

		private static int kRpcRpcBark;

		private static int kCmdCmdRequestVehicleEjection;

		private static int kRpcRpcUsePreferredInitialStateType;

		public CharacterMaster master
		{
			get
			{
				if (!masterObject)
				{
					return null;
				}
				return _master;
			}
		}

		public Inventory inventory { get; private set; }

		public bool isPlayerControlled { get; private set; }

		public float executeEliteHealthFraction { get; private set; }

		public GameObject masterObject
		{
			get
			{
				if (!_masterObject)
				{
					if (NetworkServer.active)
					{
						_masterObject = NetworkServer.FindLocalObject(masterObjectId);
					}
					else if (NetworkClient.active)
					{
						_masterObject = ClientScene.FindLocalObject(masterObjectId);
					}
					_master = (_masterObject ? _masterObject.GetComponent<CharacterMaster>() : null);
					if ((bool)_master)
					{
						PlayerCharacterMasterController component = _masterObject.GetComponent<PlayerCharacterMasterController>();
						isPlayerControlled = component;
						if ((bool)inventory)
						{
							inventory.onInventoryChanged -= OnInventoryChanged;
						}
						inventory = _master.inventory;
						if ((bool)inventory)
						{
							inventory.onInventoryChanged += OnInventoryChanged;
							OnInventoryChanged();
						}
						statsDirty = true;
					}
				}
				return _masterObject;
			}
			set
			{
				masterObjectId = value.GetComponent<NetworkIdentity>().netId;
				statsDirty = true;
			}
		}

		public Rigidbody rigidbody { get; private set; }

		public NetworkIdentity networkIdentity { get; private set; }

		public CharacterMotor characterMotor { get; private set; }

		public CharacterDirection characterDirection { get; private set; }

		public TeamComponent teamComponent { get; private set; }

		public HealthComponent healthComponent { get; private set; }

		public EquipmentSlot equipmentSlot { get; private set; }

		public InputBankTest inputBank { get; private set; }

		public SkillLocator skillLocator { get; private set; }

		public ModelLocator modelLocator { get; private set; }

		public HurtBoxGroup hurtBoxGroup { get; private set; }

		public HurtBox mainHurtBox { get; private set; }

		public Transform coreTransform { get; private set; }

		public bool hasEffectiveAuthority { get; private set; }

		public bool isSprinting
		{
			get
			{
				return _isSprinting;
			}
			set
			{
				if (_isSprinting != value)
				{
					_isSprinting = value;
					RecalculateStats();
					if (value)
					{
						OnSprintStart();
					}
					else
					{
						OnSprintStop();
					}
					if (NetworkServer.active)
					{
						SetDirtyBit(16u);
					}
					else if (hasEffectiveAuthority)
					{
						CallCmdUpdateSprint(value);
					}
				}
			}
		}

		public bool outOfCombat { get; private set; } = true;


		public bool outOfDanger
		{
			get
			{
				return _outOfDanger;
			}
			private set
			{
				if (_outOfDanger != value)
				{
					_outOfDanger = value;
					OnOutOfDangerChanged();
				}
			}
		}

		public float experience { get; private set; }

		public float level { get; private set; }

		public float maxHealth { get; private set; }

		public float maxBarrier { get; private set; }

		public float barrierDecayRate { get; private set; }

		public float regen { get; private set; }

		public float maxShield { get; private set; }

		public float moveSpeed { get; private set; }

		public float acceleration { get; private set; }

		public float surfaceSpeedBoost
		{
			get
			{
				return m_surfaceSpeedBoost;
			}
			set
			{
				if (!Mathf.Approximately(m_surfaceSpeedBoost, value))
				{
					m_surfaceSpeedBoost = value;
					RecalculateStats();
				}
			}
		}

		public float jumpPower { get; private set; }

		public int maxJumpCount { get; private set; }

		public float maxJumpHeight { get; private set; }

		public float damage { get; private set; }

		public float attackSpeed { get; private set; }

		public float crit { get; private set; }

		public float critMultiplier { get; private set; }

		public float bleedChance { get; private set; }

		public float armor { get; private set; }

		public float visionDistance { get; private set; }

		public float critHeal { get; private set; }

		public float cursePenalty { get; private set; }

		public bool hasOneShotProtection { get; private set; }

		public bool isGlass { get; private set; }

		public float oneShotProtectionFraction { get; private set; }

		public bool canPerformBackstab { get; private set; }

		public bool canReceiveBackstab { get; private set; }

		public float maxBonusHealth { get; private set; }

		public bool shouldAim
		{
			get
			{
				if (aimTimer > 0f)
				{
					return !isSprinting;
				}
				return false;
			}
		}

		public int killCountServer { get; private set; }

		public float bestFitRadius => Mathf.Max(radius, characterMotor ? characterMotor.capsuleHeight : 1f);

		public float bestFitActualRadius => Mathf.Max(radius, characterMotor ? (characterMotor.capsuleHeight * 0.5f) : 1f);

		public bool hasCloakBuff
		{
			get
			{
				if (!HasBuff(RoR2Content.Buffs.Cloak))
				{
					return HasBuff(RoR2Content.Buffs.AffixHauntedRecipient);
				}
				return true;
			}
		}

		public float spreadBloomAngle => spreadBloomCurve.Evaluate(spreadBloomInternal);

		public GameObject defaultCrosshairPrefab => _defaultCrosshairPrefab;

		public int multiKillCount { get; private set; }

		public int increasedDamageKillCount { get; private set; }

		public int increasedDamageKillCountBuff { get; private set; }

		public float luminousShotDamage { get; private set; }

		public bool luminousShotReady { get; private set; }

		public UnityEngine.Vector3 corePosition
		{
			get
			{
				if (!coreTransform)
				{
					return transform.position;
				}
				return coreTransform.position;
			}
		}

		public UnityEngine.Vector3 footPosition
		{
			get
			{
				UnityEngine.Vector3 position = transform.position;
				if ((bool)characterMotor)
				{
					position.y -= characterMotor.capsuleHeight * 0.5f;
				}
				return position;
			}
		}

		public float radius { get; private set; }

		public UnityEngine.Vector3 aimOrigin
		{
			get
			{
				if (!aimOriginTransform)
				{
					return corePosition;
				}
				return aimOriginTransform.position;
			}
		}

		public bool isElite { get; private set; }

		public bool isBoss
		{
			get
			{
				if ((bool)master)
				{
					return master.isBoss;
				}
				return false;
			}
		}

		public bool isFlying
		{
			get
			{
				if ((bool)characterMotor)
				{
					return characterMotor.isFlying;
				}
				return true;
			}
		}

		public Run.FixedTimeStamp localStartTime { get; private set; } = Run.FixedTimeStamp.positiveInfinity;


		public bool isEquipmentActivationAllowed
		{
			get
			{
				if ((bool)currentVehicle)
				{
					return currentVehicle.isEquipmentActivationAllowed;
				}
				return true;
			}
		}

		public event Action onInventoryChanged;

		public event Action<GenericSkill> onSkillActivatedServer;

		public event Action<GenericSkill> onSkillActivatedAuthority;

		public static event Action<CharacterBody> onBodyAwakeGlobal;

		public static event Action<CharacterBody> onBodyDestroyGlobal;

		public static event Action<CharacterBody> onBodyStartGlobal;

		public static event Action<CharacterBody> onBodyInventoryChangedGlobal;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public CharacterBody GetBody()
		{
			return this;
		}

		public void DebugDrawLine(UnityEngine.Vector3 start, UnityEngine.Vector3 end, UnityEngine.Color color)
		{
			UnityEngine.Debug.DrawLine(start, end, color, 5f);
		}

		[InitDuringStartup]
		private static void LoadCommonAssets()
		{
			CommonAssets.Load();
		}

		public string GetDisplayName()
		{
			return Language.GetString(baseNameToken);
		}

		public string GetSubtitle()
		{
			return Language.GetString(subtitleNameToken);
		}

		public string GetUserName()
		{
			string text = "";
			if ((bool)master)
			{
				PlayerCharacterMasterController component = master.GetComponent<PlayerCharacterMasterController>();
				if ((bool)component)
				{
					text = component.GetDisplayName();
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				text = GetDisplayName();
			}
			return text;
		}

		public string GetColoredUserName()
		{
			Color32 color = new Color32(127, 127, 127, byte.MaxValue);
			string text = null;
			if ((bool)master)
			{
				PlayerCharacterMasterController component = master.GetComponent<PlayerCharacterMasterController>();
				if ((bool)component)
				{
					GameObject networkUserObject = component.networkUserObject;
					if ((bool)networkUserObject)
					{
						NetworkUser component2 = networkUserObject.GetComponent<NetworkUser>();
						if ((bool)component2)
						{
							color = component2.userColor;
							text = component2.userName;
						}
					}
				}
			}
			if (text == null)
			{
				text = GetDisplayName();
			}
			return Util.GenerateColoredString(text, color);
		}

		[Server]
		private void WriteBuffs(NetworkWriter writer)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::WriteBuffs(UnityEngine.Networking.NetworkWriter)' called on client");
				return;
			}
			writer.Write((byte)activeBuffsListCount);
			for (int i = 0; i < activeBuffsListCount; i++)
			{
				BuffIndex buffIndex = activeBuffsList[i];
				BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex);
				writer.WriteBuffIndex(buffIndex);
				if (buffDef.canStack)
				{
					writer.WritePackedUInt32((uint)buffs[(int)buffIndex]);
				}
			}
		}

		[Client]
		private void ReadBuffs(NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.CharacterBody::ReadBuffs(UnityEngine.Networking.NetworkReader)' called on server");
				return;
			}
			if (activeBuffsList == null)
			{
				UnityEngine.Debug.LogError("Trying to ReadBuffs, but our activeBuffsList is null");
				return;
			}
			int activeBuffsIndexToCheck = 0;
			int num = reader.ReadByte();
			BuffIndex buffIndex = BuffIndex.None;
			for (int i = 0; i < num; i++)
			{
				BuffIndex buffIndex2 = reader.ReadBuffIndex();
				BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex2);
				if (buffDef != null)
				{
					int num2 = 1;
					if (buffDef.canStack)
					{
						num2 = (int)reader.ReadPackedUInt32();
					}
					if (num2 > 0 && !NetworkServer.active)
					{
						ZeroBuffIndexRange(buffIndex + 1, buffIndex2);
						SetBuffCount(buffIndex2, num2);
					}
					buffIndex = buffIndex2;
				}
				else
				{
					UnityEngine.Debug.LogErrorFormat("No BuffDef for index {0}. body={1}, netID={2}", buffIndex2, base.gameObject, base.netId);
				}
			}
			if (!NetworkServer.active)
			{
				ZeroBuffIndexRange(buffIndex + 1, (BuffIndex)BuffCatalog.buffCount);
			}
			void ZeroBuffIndexRange(BuffIndex start, BuffIndex end)
			{
				while (activeBuffsIndexToCheck < activeBuffsListCount)
				{
					BuffIndex buffIndex3 = activeBuffsList[activeBuffsIndexToCheck];
					if (end <= buffIndex3)
					{
						break;
					}
					int num3;
					if (start <= buffIndex3)
					{
						SetBuffCount(buffIndex3, 0);
						num3 = activeBuffsIndexToCheck - 1;
						activeBuffsIndexToCheck = num3;
					}
					num3 = activeBuffsIndexToCheck + 1;
					activeBuffsIndexToCheck = num3;
				}
			}
		}

		[Server]
		public void AddBuff(BuffIndex buffType)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddBuff(RoR2.BuffIndex)' called on client");
			}
			else if (buffType != BuffIndex.None)
			{
				SetBuffCount(buffType, buffs[(int)buffType] + 1);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Server]
		public void AddBuff(BuffDef buffDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddBuff(RoR2.BuffDef)' called on client");
			}
			else
			{
				AddBuff(buffDef?.buffIndex ?? BuffIndex.None);
			}
		}

		[Server]
		public void RemoveBuff(BuffIndex buffType)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveBuff(RoR2.BuffIndex)' called on client");
			}
			else
			{
				if (buffType == BuffIndex.None)
				{
					return;
				}
				SetBuffCount(buffType, buffs[(int)buffType] - 1);
				if (buffType == RoR2Content.Buffs.MedkitHeal.buffIndex)
				{
					if (GetBuffCount(RoR2Content.Buffs.MedkitHeal.buffIndex) == 0)
					{
						int itemCount = inventory.GetItemCount(RoR2Content.Items.Medkit);
						float num = 20f;
						float num2 = maxHealth * 0.05f * (float)itemCount;
						healthComponent.Heal(num + num2, default(ProcChainMask));
						EffectData effectData = new EffectData
						{
							origin = transform.position
						};
						effectData.SetNetworkedObjectReference(base.gameObject);
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/MedkitHealEffect"), effectData, transmit: true);
					}
				}
				else if (buffType == RoR2Content.Buffs.TonicBuff.buffIndex)
				{
					if ((bool)inventory && GetBuffCount(RoR2Content.Buffs.TonicBuff) == 0 && pendingTonicAfflictionCount > 0)
					{
						inventory.GiveItem(RoR2Content.Items.TonicAffliction, pendingTonicAfflictionCount);
						PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(RoR2Content.Items.TonicAffliction.itemIndex);
						GenericPickupController.SendPickupMessage(master, pickupIndex);
						pendingTonicAfflictionCount = 0;
					}
				}
				else if (buffType == DLC2Content.Buffs.SoulCost.buffIndex)
				{
					cursePenalty -= 0.1f * (float)GetBuffCount(DLC2Content.Buffs.SoulCost);
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Server]
		public void RemoveBuff(BuffDef buffDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveBuff(RoR2.BuffDef)' called on client");
			}
			else
			{
				RemoveBuff(buffDef?.buffIndex ?? BuffIndex.None);
			}
		}

		public void SetBuffCount(BuffIndex buffType, int newCount)
		{
			newCount = Mathf.Max(newCount, 0);
			ref int reference = ref buffs[(int)buffType];
			if (newCount == reference)
			{
				return;
			}
			int num = reference;
			reference = newCount;
			BuffDef buffDef = BuffCatalog.GetBuffDef(buffType);
			bool flag = true;
			if (!buffDef.canStack)
			{
				flag = num == 0 != (newCount == 0);
			}
			if (flag)
			{
				if (newCount == 0)
				{
					ArrayUtils.ArrayRemoveAt(activeBuffsList, ref activeBuffsListCount, Array.IndexOf(activeBuffsList, buffType));
					OnBuffFinalStackLost(buffDef);
				}
				else if (num == 0)
				{
					int i;
					for (i = 0; i < activeBuffsListCount && buffType >= activeBuffsList[i]; i++)
					{
					}
					ArrayUtils.ArrayInsert(ref activeBuffsList, ref activeBuffsListCount, i, in buffType);
					OnBuffFirstStackGained(buffDef);
				}
				if (NetworkServer.active)
				{
					SetDirtyBit(2u);
				}
			}
			statsDirty = true;
			if (NetworkClient.active)
			{
				OnClientBuffsChanged();
			}
			UpdateItemAvailability();
		}

		private void OnBuffFirstStackGained(BuffDef buffDef)
		{
			if (buffDef.isElite)
			{
				eliteBuffCount++;
			}
			if (buffDef == RoR2Content.Buffs.Intangible)
			{
				UpdateHurtBoxesEnabled();
			}
			else if (buffDef == RoR2Content.Buffs.WarCryBuff)
			{
				if (HasBuff(RoR2Content.Buffs.TeamWarCry))
				{
					ClearTimedBuffs(RoR2Content.Buffs.TeamWarCry);
				}
			}
			else if (buffDef == RoR2Content.Buffs.TeamWarCry)
			{
				if (HasBuff(RoR2Content.Buffs.WarCryBuff))
				{
					ClearTimedBuffs(RoR2Content.Buffs.WarCryBuff);
				}
			}
			else if (buffDef == RoR2Content.Buffs.AffixEcho && NetworkServer.active)
			{
				AddItemBehavior<AffixEchoBehavior>(1);
			}
		}

		private void OnBuffFinalStackLost(BuffDef buffDef)
		{
			if (buffDef.isElite)
			{
				eliteBuffCount--;
			}
			if (buffDef.buffIndex == RoR2Content.Buffs.Intangible.buffIndex)
			{
				UpdateHurtBoxesEnabled();
			}
			else if (buffDef == RoR2Content.Buffs.AffixEcho && NetworkServer.active)
			{
				AddItemBehavior<AffixEchoBehavior>(0);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public int GetBuffCount(BuffIndex buffType)
		{
			return ArrayUtils.GetSafe(buffs, (int)buffType);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public int GetBuffCount(BuffDef buffDef)
		{
			return GetBuffCount(buffDef?.buffIndex ?? BuffIndex.None);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool HasBuff(BuffIndex buffType)
		{
			return GetBuffCount(buffType) > 0;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool HasBuff(BuffDef buffDef)
		{
			return HasBuff(buffDef?.buffIndex ?? BuffIndex.None);
		}

		public void AddTimedBuffAuthority(BuffIndex buffType, float duration)
		{
			if (NetworkServer.active)
			{
				AddTimedBuff(buffType, duration);
			}
			else
			{
				CallCmdAddTimedBuff(buffType, duration);
			}
		}

		[Command]
		public void CmdAddTimedBuff(BuffIndex buffType, float duration)
		{
			AddTimedBuff(buffType, duration);
		}

		[Server]
		public void AddTimedBuff(BuffDef buffDef, float duration, int maxStacks)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddTimedBuff(RoR2.BuffDef,System.Single,System.Int32)' called on client");
			}
			else
			{
				if (ImmuneToDebuffBehavior.OverrideDebuff(buffDef, this))
				{
					return;
				}
				if (GetBuffCount(buffDef) < maxStacks)
				{
					AddTimedBuff(buffDef, duration);
					return;
				}
				int num = -1;
				float num2 = duration;
				for (int i = 0; i < timedBuffs.Count; i++)
				{
					if (timedBuffs[i].buffIndex == buffDef.buffIndex && timedBuffs[i].timer < num2)
					{
						num = i;
						num2 = timedBuffs[i].timer;
					}
				}
				if (num >= 0)
				{
					timedBuffs[num].timer = duration;
				}
			}
		}

		[Server]
		public void AddTimedBuff(BuffDef buffDef, float duration)
		{
			BuffIndex buffType;
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddTimedBuff(RoR2.BuffDef,System.Single)' called on client");
			}
			else
			{
				if ((object)buffDef == null || ImmuneToDebuffBehavior.OverrideDebuff(buffDef, this))
				{
					return;
				}
				buffType = buffDef.buffIndex;
				if (buffType == BuffIndex.None)
				{
					return;
				}
				if (buffDef == RoR2Content.Buffs.AttackSpeedOnCrit)
				{
					int num = (inventory ? inventory.GetItemCount(RoR2Content.Items.AttackSpeedOnCrit) : 0);
					int num2 = 1 + num * 2;
					int num3 = 0;
					int num4 = -1;
					float num5 = 999f;
					for (int i = 0; i < timedBuffs.Count; i++)
					{
						if (timedBuffs[i].buffIndex == buffType)
						{
							num3++;
							if (timedBuffs[i].timer < num5)
							{
								num4 = i;
								num5 = timedBuffs[i].timer;
							}
						}
					}
					if (num3 < num2)
					{
						timedBuffs.Add(new TimedBuff
						{
							buffIndex = buffType,
							timer = duration
						});
						AddBuff(buffType);
						ChildLocator component = modelLocator.modelTransform.GetComponent<ChildLocator>();
						if ((bool)component)
						{
							Transform obj = component.FindChild("HandL");
							Transform transform = component.FindChild("HandR");
							GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/WolfProcEffect");
							if ((bool)obj)
							{
								EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "HandL", transmit: true);
							}
							if ((bool)transform)
							{
								EffectManager.SimpleMuzzleFlash(effectPrefab, base.gameObject, "HandR", transmit: true);
							}
						}
					}
					else if (num4 > -1)
					{
						timedBuffs[num4].timer = duration;
					}
					EntitySoundManager.EmitSoundServer(CommonAssets.procCritAttackSpeedSounds[Mathf.Min(CommonAssets.procCritAttackSpeedSounds.Length - 1, num3)].index, networkIdentity);
				}
				else if (buffDef == RoR2Content.Buffs.BeetleJuice)
				{
					if (RefreshStacks() < 10)
					{
						timedBuffs.Add(new TimedBuff
						{
							buffIndex = buffType,
							timer = duration
						});
						AddBuff(buffType);
					}
				}
				else if (buffDef == RoR2Content.Buffs.NullifyStack)
				{
					if (HasBuff(RoR2Content.Buffs.Nullified))
					{
						return;
					}
					int num6 = 0;
					for (int j = 0; j < timedBuffs.Count; j++)
					{
						if (timedBuffs[j].buffIndex == buffType)
						{
							num6++;
							if (timedBuffs[j].timer < duration)
							{
								timedBuffs[j].timer = duration;
							}
						}
					}
					if (num6 < 2)
					{
						timedBuffs.Add(new TimedBuff
						{
							buffIndex = buffType,
							timer = duration
						});
						AddBuff(buffType);
					}
					else
					{
						ClearTimedBuffs(RoR2Content.Buffs.NullifyStack.buffIndex);
						AddTimedBuff(RoR2Content.Buffs.Nullified.buffIndex, 3f);
					}
				}
				else if (buffDef == RoR2Content.Buffs.AffixHauntedRecipient)
				{
					if (!HasBuff(RoR2Content.Buffs.AffixHaunted))
					{
						DefaultBehavior();
					}
				}
				else if (buffDef == DLC2Content.Buffs.EliteBeadCorruption)
				{
					if (!HasBuff(DLC2Content.Buffs.EliteBead))
					{
						DefaultBehavior();
					}
				}
				else if (buffDef == RoR2Content.Buffs.LunarDetonationCharge)
				{
					RefreshStacks();
					DefaultBehavior();
				}
				else if (buffDef == RoR2Content.Buffs.Overheat)
				{
					RefreshStacks();
					DefaultBehavior();
				}
				else if (buffDef == DLC2Content.Buffs.BoostAllStatsBuff)
				{
					RefreshStacks();
					DefaultBehavior();
				}
				else
				{
					DefaultBehavior();
				}
			}
			void DefaultBehavior()
			{
				bool flag = false;
				if (!buffDef.canStack)
				{
					for (int k = 0; k < timedBuffs.Count; k++)
					{
						if (timedBuffs[k].buffIndex == buffType)
						{
							flag = true;
							timedBuffs[k].timer = Mathf.Max(timedBuffs[k].timer, duration);
							break;
						}
					}
				}
				if (!flag)
				{
					timedBuffs.Add(new TimedBuff
					{
						buffIndex = buffType,
						timer = duration
					});
					AddBuff(buffType);
				}
				if ((bool)buffDef.startSfx)
				{
					EntitySoundManager.EmitSoundServer(buffDef.startSfx.index, networkIdentity);
				}
			}
			int RefreshStacks()
			{
				int num7 = 0;
				for (int l = 0; l < timedBuffs.Count; l++)
				{
					TimedBuff timedBuff = timedBuffs[l];
					if (timedBuff.buffIndex == buffType)
					{
						num7++;
						if (timedBuff.timer < duration)
						{
							timedBuff.timer = duration;
						}
					}
				}
				return num7;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Server]
		public void AddTimedBuff(BuffIndex buffIndex, float duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddTimedBuff(RoR2.BuffIndex,System.Single)' called on client");
			}
			else
			{
				AddTimedBuff(BuffCatalog.GetBuffDef(buffIndex), duration);
			}
		}

		[Server]
		public void ClearTimedBuffs(BuffIndex buffType)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ClearTimedBuffs(RoR2.BuffIndex)' called on client");
				return;
			}
			for (int num = timedBuffs.Count - 1; num >= 0; num--)
			{
				TimedBuff timedBuff = timedBuffs[num];
				if (timedBuff.buffIndex == buffType)
				{
					timedBuffs.RemoveAt(num);
					RemoveBuff(timedBuff.buffIndex);
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Server]
		public void ClearTimedBuffs(BuffDef buffDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ClearTimedBuffs(RoR2.BuffDef)' called on client");
			}
			else
			{
				ClearTimedBuffs(buffDef?.buffIndex ?? BuffIndex.None);
			}
		}

		[Server]
		public void RemoveOldestTimedBuff(BuffIndex buffType)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveOldestTimedBuff(RoR2.BuffIndex)' called on client");
				return;
			}
			float num = float.NegativeInfinity;
			int num2 = -1;
			for (int num3 = timedBuffs.Count - 1; num3 >= 0; num3--)
			{
				TimedBuff timedBuff = timedBuffs[num3];
				if (timedBuff.buffIndex == buffType && num < timedBuff.timer)
				{
					num = timedBuff.timer;
					num2 = num3;
				}
			}
			if (num2 > 0)
			{
				timedBuffs.RemoveAt(num2);
				RemoveBuff(buffType);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Server]
		public void RemoveOldestTimedBuff(BuffDef buffDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::RemoveOldestTimedBuff(RoR2.BuffDef)' called on client");
			}
			else
			{
				RemoveOldestTimedBuff(buffDef?.buffIndex ?? BuffIndex.None);
			}
		}

		[Server]
		private void UpdateBuffs(float deltaTime)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateBuffs(System.Single)' called on client");
				return;
			}
			for (int num = timedBuffs.Count - 1; num >= 0; num--)
			{
				TimedBuff timedBuff = timedBuffs[num];
				timedBuff.timer -= deltaTime;
				if (timedBuff.timer <= 0f)
				{
					timedBuffs.RemoveAt(num);
					RemoveBuff(timedBuff.buffIndex);
				}
			}
		}

		[Client]
		private void OnClientBuffsChanged()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.CharacterBody::OnClientBuffsChanged()' called on server");
				return;
			}
			bool num = HasBuff(RoR2Content.Buffs.WarCryBuff);
			if (!num && (bool)warCryEffectInstance)
			{
				UnityEngine.Object.Destroy(warCryEffectInstance);
			}
			if (num && !warCryEffectInstance)
			{
				Transform transform = (mainHurtBox ? mainHurtBox.transform : this.transform);
				if ((bool)transform)
				{
					warCryEffectInstance = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/WarCryEffect"), transform.position, UnityEngine.Quaternion.identity, transform);
				}
			}
			if ((bool)inventory && inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill) > 0)
			{
				int buffCount = GetBuffCount(DLC2Content.Buffs.IncreaseDamageBuff);
				if ((bool)increaseDamageOnMultiKillItemDisplayUpdater)
				{
					increaseDamageOnMultiKillItemDisplayUpdater.UpdateKillCounterText(buffCount);
				}
				if (previousMultiKillBuffCount < buffCount)
				{
					Util.PlaySound("Play_item_proc_increaseDamageMultiKill", base.gameObject);
				}
				previousMultiKillBuffCount = buffCount;
			}
		}

		public NetworkInstanceId GetMasterObjectId()
		{
			return masterObjectId;
		}

		private void GetSelectedCharacterType()
		{
		}

		private void UpdateHurtBoxesEnabled()
		{
			bool flag = ((bool)inventory && inventory.GetItemCount(RoR2Content.Items.Ghost) > 0) || HasBuff(RoR2Content.Buffs.Intangible);
			if (flag == disablingHurtBoxes)
			{
				return;
			}
			if ((bool)hurtBoxGroup)
			{
				if (flag)
				{
					HurtBoxGroup obj = hurtBoxGroup;
					int hurtBoxesDeactivatorCounter = obj.hurtBoxesDeactivatorCounter + 1;
					obj.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
				else
				{
					HurtBoxGroup obj2 = hurtBoxGroup;
					int hurtBoxesDeactivatorCounter = obj2.hurtBoxesDeactivatorCounter - 1;
					obj2.hurtBoxesDeactivatorCounter = hurtBoxesDeactivatorCounter;
				}
			}
			disablingHurtBoxes = flag;
		}

		private void OnInventoryChanged()
		{
			EquipmentIndex currentEquipmentIndex = inventory.currentEquipmentIndex;
			if (currentEquipmentIndex != previousEquipmentIndex)
			{
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(previousEquipmentIndex);
				EquipmentDef equipmentDef2 = EquipmentCatalog.GetEquipmentDef(currentEquipmentIndex);
				if (equipmentDef != null)
				{
					OnEquipmentLost(equipmentDef);
				}
				if (equipmentDef2 != null)
				{
					OnEquipmentGained(equipmentDef2);
				}
				previousEquipmentIndex = currentEquipmentIndex;
			}
			statsDirty = true;
			UpdateHurtBoxesEnabled();
			AddItemBehavior<AffixHauntedBehavior>(HasBuff(RoR2Content.Buffs.AffixHaunted) ? 1 : 0);
			AddItemBehavior<AffixEarthBehavior>(HasBuff(DLC1Content.Buffs.EliteEarth) ? 1 : 0);
			AddItemBehavior<AffixVoidBehavior>(HasBuff(DLC1Content.Buffs.EliteVoid) ? 1 : 0);
			AddItemBehavior<AffixBeadBehavior>(HasBuff(DLC2Content.Buffs.EliteBead) ? 1 : 0);
			AddItemBehavior<AffixAurelioniteBehavior>(HasBuff(DLC2Content.Buffs.EliteAurelionite) ? 1 : 0);
			if (NetworkServer.active)
			{
				AddItemBehavior<QuestVolatileBatteryBehaviorServer>((inventory.GetEquipment(inventory.activeEquipmentSlot).equipmentDef == RoR2Content.Equipment.QuestVolatileBattery) ? 1 : 0);
				AddItemBehavior<ElementalRingsBehavior>(inventory.GetItemCount(RoR2Content.Items.IceRing) + inventory.GetItemCount(RoR2Content.Items.FireRing));
				AddItemBehavior<ElementalRingVoidBehavior>(inventory.GetItemCount(DLC1Content.Items.ElementalRingVoid));
				AddItemBehavior<OutOfCombatArmorBehavior>(inventory.GetItemCount(DLC1Content.Items.OutOfCombatArmor));
				AddItemBehavior<PrimarySkillShurikenBehavior>(inventory.GetItemCount(DLC1Content.Items.PrimarySkillShuriken));
				AddItemBehavior<MushroomVoidBehavior>(inventory.GetItemCount(DLC1Content.Items.MushroomVoid));
				AddItemBehavior<BearVoidBehavior>(inventory.GetItemCount(DLC1Content.Items.BearVoid));
				AddItemBehavior<LunarSunBehavior>(inventory.GetItemCount(DLC1Content.Items.LunarSun));
				AddItemBehavior<VoidMegaCrabItemBehavior>(inventory.GetItemCount(DLC1Content.Items.VoidMegaCrabItem));
				AddItemBehavior<DroneWeaponsBehavior>(inventory.GetItemCount(DLC1Content.Items.DroneWeapons));
				AddItemBehavior<DroneWeaponsBoostBehavior>(inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost));
				AddItemBehavior<MeteorAttackOnHighDamageBehavior>(inventory.GetItemCount(DLC2Content.Items.MeteorAttackOnHighDamage));
				AddItemBehavior<TeleportOnLowHealthBehavior>(inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth));
			}
			executeEliteHealthFraction = Util.ConvertAmplificationPercentageIntoReductionPercentage(13f * (float)inventory.GetItemCount(RoR2Content.Items.ExecuteLowHealthElite)) / 100f;
			if ((bool)skillLocator)
			{
				ReplaceSkillIfItemPresent(skillLocator.primary, RoR2Content.Items.LunarPrimaryReplacement.itemIndex, CommonAssets.lunarPrimaryReplacementSkillDef);
				ReplaceSkillIfItemPresent(skillLocator.secondary, RoR2Content.Items.LunarSecondaryReplacement.itemIndex, CommonAssets.lunarSecondaryReplacementSkillDef);
				ReplaceSkillIfItemPresent(skillLocator.special, RoR2Content.Items.LunarSpecialReplacement.itemIndex, CommonAssets.lunarSpecialReplacementSkillDef);
				ReplaceSkillIfItemPresent(skillLocator.utility, RoR2Content.Items.LunarUtilityReplacement.itemIndex, CommonAssets.lunarUtilityReplacementSkillDef);
			}
			this.onInventoryChanged?.Invoke();
			CharacterBody.onBodyInventoryChangedGlobal?.Invoke(this);
			UpdateItemAvailability();
		}

		private void ReplaceSkillIfItemPresent(GenericSkill skill, ItemIndex itemIndex, SkillDef skillDef)
		{
			if ((bool)skill)
			{
				if (inventory.GetItemCount(itemIndex) > 0 && (bool)skillDef)
				{
					skill.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Replacement);
				}
				else
				{
					skill.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Replacement);
				}
			}
		}

		private void OnEquipmentLost(EquipmentDef equipmentDef)
		{
			if (NetworkServer.active && (object)equipmentDef.passiveBuffDef != null)
			{
				RemoveBuff(equipmentDef.passiveBuffDef);
			}
		}

		private void OnEquipmentGained(EquipmentDef equipmentDef)
		{
			if (NetworkServer.active && (object)equipmentDef.passiveBuffDef != null)
			{
				AddBuff(equipmentDef.passiveBuffDef);
			}
		}

		private void UpdateMasterLink()
		{
			if (!linkedToMaster && (bool)master && (bool)master)
			{
				master.OnBodyStart(this);
				linkedToMaster = true;
				skinIndex = master.loadout.bodyLoadoutManager.GetSkinIndex(bodyIndex);
			}
		}

		public static void Init()
		{
			AssetReferences.Resolve();
		}

		private void Awake()
		{
			transform = base.transform;
			rigidbody = GetComponent<Rigidbody>();
			networkIdentity = GetComponent<NetworkIdentity>();
			teamComponent = GetComponent<TeamComponent>();
			healthComponent = GetComponent<HealthComponent>();
			equipmentSlot = GetComponent<EquipmentSlot>();
			skillLocator = GetComponent<SkillLocator>();
			modelLocator = GetComponent<ModelLocator>();
			characterMotor = GetComponent<CharacterMotor>();
			characterDirection = GetComponent<CharacterDirection>();
			inputBank = GetComponent<InputBankTest>();
			sfxLocator = GetComponent<SfxLocator>();
			activeBuffsList = BuffCatalog.GetPerBuffBuffer<BuffIndex>();
			buffs = BuffCatalog.GetPerBuffBuffer<int>();
			if ((bool)modelLocator)
			{
				modelLocator.onModelChanged += OnModelChanged;
				OnModelChanged(modelLocator.modelTransform);
			}
			radius = 1f;
			CapsuleCollider component = GetComponent<CapsuleCollider>();
			if ((bool)component)
			{
				radius = component.radius;
			}
			else
			{
				SphereCollider component2 = GetComponent<SphereCollider>();
				if ((bool)component2)
				{
					radius = component2.radius;
				}
			}
			try
			{
				CharacterBody.onBodyAwakeGlobal?.Invoke(this);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private void OnModelChanged(Transform modelTransform)
		{
			hurtBoxGroup = null;
			mainHurtBox = null;
			coreTransform = transform;
			if ((bool)modelTransform)
			{
				hurtBoxGroup = modelTransform.GetComponent<HurtBoxGroup>();
				if ((bool)hurtBoxGroup)
				{
					mainHurtBox = hurtBoxGroup.mainHurtBox;
					if ((bool)mainHurtBox)
					{
						coreTransform = mainHurtBox.transform;
					}
				}
			}
			if ((bool)overrideCoreTransform)
			{
				coreTransform = overrideCoreTransform;
			}
		}

		private void Start()
		{
			UpdateAuthority();
			localStartTime = Run.FixedTimeStamp.now;
			bool num = (bodyFlags & BodyFlags.Masterless) != 0;
			outOfCombatStopwatch = float.PositiveInfinity;
			outOfDangerStopwatch = float.PositiveInfinity;
			notMovingStopwatch = 0f;
			if (NetworkServer.active)
			{
				outOfCombat = true;
				outOfDanger = true;
			}
			RecalculateStats();
			UpdateMasterLink();
			if (num)
			{
				healthComponent.Networkhealth = maxHealth;
			}
			if ((bool)sfxLocator && healthComponent.alive)
			{
				Util.PlaySound(sfxLocator.aliveLoopStart, base.gameObject);
			}
			if (!doNotReassignToTeamBasedCollisionLayer)
			{
				base.gameObject.layer = LayerIndex.GetAppropriateLayerForTeam(teamComponent.teamIndex);
				if (characterMotor != null)
				{
					characterMotor.Motor.RebuildCollidableLayers();
				}
			}
			CharacterBody.onBodyStartGlobal?.Invoke(this);
			if ((bool)master && NetworkServer.active)
			{
				if (master.devotionInventoryPrefab == null)
				{
					_ = master.isDevotedMinion;
				}
				if (isPlayerControlled && (bool)master.devotionInventoryPrefab)
				{
					_ = master.devotionInventoryPrefab != null;
				}
				int num2 = ((inventory != null) ? inventory.GetItemCount(DLC2Content.Items.GoldOnStageStart) : 0);
				if (num2 > 0)
				{
					TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.GoldOnStageStart.itemIndex, 0f));
					uint difficultyScaledCost = (uint)Run.instance.GetDifficultyScaledCost((int)(50f + level * 1.5f * (float)num2));
					master.GiveMoney(difficultyScaledCost);
				}
			}
		}

		public void Update()
		{
			float deltaTime = Time.deltaTime;
			outOfCombatStopwatch += deltaTime;
			outOfDangerStopwatch += deltaTime;
			aimTimer = Mathf.Max(aimTimer - deltaTime, 0f);
			UpdateOutOfCombatAndDanger();
			UpdateSpreadBloom(deltaTime);
			DoItemUpdates(deltaTime);
			UpdateNotMoving(deltaTime);
			HandleLavaDamage(deltaTime);
		}

		private void UpdateNotMoving(float deltaTime)
		{
			if (NetworkServer.active)
			{
				UnityEngine.Vector3 position = transform.position;
				float num = 0.1f * deltaTime;
				if ((position - previousPosition).sqrMagnitude <= num * num)
				{
					notMovingStopwatch += deltaTime;
				}
				else
				{
					notMovingStopwatch = 0f;
				}
				previousPosition = position;
			}
		}

		private void DoItemUpdates(float deltaTime)
		{
			if ((bodyFlags & BodyFlags.IgnoreItemUpdates) == 0)
			{
				if (NetworkServer.active)
				{
					UpdateMultiKill(deltaTime);
					UpdateHelfire(deltaTime);
					UpdateAffixPoison(deltaTime);
					UpdateAffixLunar(deltaTime);
					UpdateLowerHealthHigherDamage();
					UpdateDelayedDamage(deltaTime);
					UpdateSecondHalfOfDamage(deltaTime);
				}
				UpdateFireTrail();
			}
		}

		private void UpdateOutOfCombatAndDanger()
		{
			bool active = NetworkServer.active;
			bool flag = outOfCombat;
			bool flag2 = flag;
			if (active || hasEffectiveAuthority)
			{
				flag2 = outOfCombatStopwatch >= 5f;
				if (outOfCombat != flag2)
				{
					if (NetworkServer.active)
					{
						SetDirtyBit(4u);
					}
					outOfCombat = flag2;
					statsDirty = true;
				}
			}
			if (active)
			{
				bool flag3 = outOfDangerStopwatch >= 7f;
				bool flag4 = outOfDanger;
				bool flag5 = flag && flag4;
				bool num = flag2 && flag3;
				if (outOfDanger != flag3)
				{
					SetDirtyBit(8u);
					outOfDanger = flag3;
					statsDirty = true;
				}
				if (num && !flag5)
				{
					OnOutOfCombatAndDangerServer();
				}
			}
		}

		[Command]
		public void CmdSetInLava(bool b)
		{
			inLava = b;
		}

		public void SetInLava(bool b)
		{
			if (inLava != b)
			{
				if (!NetworkServer.active && base.hasAuthority)
				{
					CallCmdSetInLava(b);
				}
				inLava = b;
			}
		}

		public void InflictLavaDamage()
		{
			DamageInfo damageInfo = new DamageInfo();
			damageInfo.damage = 10f;
			if (isChampion || isBoss)
			{
				damageInfo.damage = healthComponent.fullCombinedHealth / 100f;
			}
			else if (teamComponent.teamIndex == TeamIndex.Monster || teamComponent.teamIndex == TeamIndex.Void)
			{
				damageInfo.damage = healthComponent.fullCombinedHealth / 50f;
			}
			else
			{
				damageInfo.damage = healthComponent.fullCombinedHealth / 10f;
			}
			damageInfo.damageType = DamageType.IgniteOnHit;
			damageInfo.position = footPosition;
			healthComponent.TakeDamage(damageInfo);
		}

		public void HandleLavaDamage(float deltaTime)
		{
			bool flag = (bodyFlags & BodyFlags.ImmuneToLava) != 0;
			if (inLava && NetworkServer.active)
			{
				lavaTimer -= deltaTime;
				if (lavaTimer <= 0f && !flag)
				{
					InflictLavaDamage();
					lavaTimer = lavaCooldown;
				}
			}
			else
			{
				lavaTimer = 0f;
			}
		}

		private void UpdateItemAvailability()
		{
			if ((bool)inventory)
			{
				itemAvailability.helfireCount = inventory.GetItemCount(JunkContent.Items.BurnNearby);
			}
			itemAvailability.hasFireTrail = HasBuff(RoR2Content.Buffs.AffixRed);
			itemAvailability.hasAffixLunar = HasBuff(RoR2Content.Buffs.AffixLunar);
			itemAvailability.hasAffixPoison = HasBuff(RoR2Content.Buffs.AffixPoison);
		}

		public void FixedUpdate()
		{
			float fixedDeltaTime = Time.fixedDeltaTime;
			bool flag = (bodyFlags & BodyFlags.IgnoreItemUpdates) == 0;
			if (NetworkServer.active)
			{
				if (flag)
				{
					UpdateBuffs(fixedDeltaTime);
				}
				UpdateOutOfCombatAndDanger();
			}
			if (statsDirty)
			{
				RecalculateStats();
			}
		}

		public void OnDeathStart()
		{
			base.enabled = false;
			if ((bool)sfxLocator)
			{
				Util.PlaySound(sfxLocator.aliveLoopStop, base.gameObject);
			}
			if (NetworkServer.active && (bool)currentVehicle)
			{
				currentVehicle.EjectPassenger(base.gameObject);
			}
			if ((bool)master)
			{
				master.OnBodyDeath(this);
			}
			ModelLocator component = GetComponent<ModelLocator>();
			if (!component)
			{
				return;
			}
			Transform modelTransform = component.modelTransform;
			if ((bool)modelTransform)
			{
				CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
				if ((bool)component2)
				{
					component2.OnDeath();
				}
			}
		}

		public void OnTakeDamageServer(DamageReport damageReport)
		{
			if (damageReport.damageDealt > 0f)
			{
				outOfDangerStopwatch = 0f;
			}
			if ((bool)master)
			{
				master.OnBodyDamaged(damageReport);
			}
		}

		public void OnSkillActivated(GenericSkill skill)
		{
			if (skill.isCombatSkill)
			{
				outOfCombatStopwatch = 0f;
			}
			if (hasEffectiveAuthority)
			{
				this.onSkillActivatedAuthority?.Invoke(skill);
			}
			if (NetworkServer.active)
			{
				this.onSkillActivatedServer?.Invoke(skill);
				if (inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage) <= 0)
				{
					return;
				}
				if (bodyIndex == BodyCatalog.SpecialCases.RailGunner())
				{
					if ((object)skillLocator.primary == skill)
					{
						if (GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0 && !EntityStates.Railgunner.Scope.BaseScopeState.inScope)
						{
							luminousShotReady = true;
						}
					}
					else
					{
						luminousShotReady = false;
					}
					if ((object)skillLocator.primary == skill && EntityStates.Railgunner.Scope.BaseScopeState.inScope)
					{
						AddIncreasePrimaryDamageStack();
					}
				}
				else
				{
					if (!skill.skillDef.autoHandleLuminousShot)
					{
						return;
					}
					if ((object)skillLocator.secondary == skill)
					{
						AddIncreasePrimaryDamageStack();
					}
					else if ((object)skillLocator.primary == skill)
					{
						if (GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0)
						{
							luminousShotReady = true;
						}
						else
						{
							luminousShotReady = false;
						}
					}
				}
			}
			else
			{
				CallCmdOnSkillActivated((sbyte)skillLocator.FindSkillSlot(skill));
			}
		}

		public void OnDestroy()
		{
			try
			{
				CharacterBody.onBodyDestroyGlobal?.Invoke(this);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			if ((bool)sfxLocator)
			{
				Util.PlaySound(sfxLocator.aliveLoopStop, base.gameObject);
			}
			if ((object)modelLocator != null)
			{
				modelLocator.onModelChanged -= OnModelChanged;
			}
			if ((bool)inventory)
			{
				inventory.onInventoryChanged -= OnInventoryChanged;
			}
			if ((bool)master)
			{
				master.OnBodyDestroyed(this);
			}
		}

		public float GetNormalizedThreatValue()
		{
			if ((bool)Run.instance)
			{
				return (master ? ((float)master.money) : 0f) * Run.instance.oneOverCompensatedDifficultyCoefficientSquared;
			}
			return 0f;
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void OnValidate()
		{
			if (autoCalculateLevelStats)
			{
				PerformAutoCalculateLevelStats();
			}
			if (!Application.isPlaying && bodyIndex != BodyIndex.None)
			{
				bodyIndex = BodyIndex.None;
			}
		}

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
		}

		public override void OnStartAuthority()
		{
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			UpdateAuthority();
		}

		private void OnSprintStart()
		{
			if ((bool)sfxLocator)
			{
				Util.PlaySound(sfxLocator.sprintLoopStart, base.gameObject);
			}
		}

		private void OnSprintStop()
		{
			if ((bool)sfxLocator)
			{
				Util.PlaySound(sfxLocator.sprintLoopStop, base.gameObject);
			}
		}

		[Command]
		private void CmdUpdateSprint(bool newIsSprinting)
		{
			isSprinting = newIsSprinting;
		}

		[Command]
		private void CmdOnSkillActivated(sbyte skillIndex)
		{
			OnSkillActivated(skillLocator.GetSkill((SkillSlot)skillIndex));
		}

		private void OnOutOfDangerChanged()
		{
			if (outOfDanger && healthComponent.shield != healthComponent.fullShield)
			{
				Util.PlaySound("Play_item_proc_personal_shield_recharge", base.gameObject);
			}
		}

		[Server]
		private void OnOutOfCombatAndDangerServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::OnOutOfCombatAndDangerServer()' called on client");
			}
		}

		[Server]
		public bool GetNotMoving()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterBody::GetNotMoving()' called on client");
				return false;
			}
			return notMovingStopwatch >= 1f;
		}

		public void PerformAutoCalculateLevelStats()
		{
			levelMaxHealth = Mathf.Round(baseMaxHealth * 0.3f);
			levelMaxShield = Mathf.Round(baseMaxShield * 0.3f);
			levelRegen = baseRegen * 0.2f;
			levelMoveSpeed = 0f;
			levelJumpPower = 0f;
			levelDamage = baseDamage * 0.2f;
			levelAttackSpeed = 0f;
			levelCrit = 0f;
			levelArmor = 0f;
		}

		public void MarkAllStatsDirty()
		{
			statsDirty = true;
		}

		private void UpdateLowerHealthHigherDamageVFX()
		{
			if ((bool)lowerHealthHigherDamageSteam)
			{
				ParticleSystem.EmissionModule emission = lowerHealthHigherDamageSteam.GetComponent<ParticleSystem>().emission;
				emission.rateOverTime = 35f;
			}
		}

		public void UpdateLowerHealthHigherDamage()
		{
			if (!inventory)
			{
				return;
			}
			int itemCount = inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage);
			if (NetworkServer.active)
			{
				if (itemCount > 0)
				{
					if ((bool)inventory && healthComponent.health > 0f && teamComponent.teamIndex == TeamIndex.Player)
					{
						float normalizedHealth = healthComponent.GetNormalizedHealth();
						if ((double)normalizedHealth <= 0.5 && !HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff))
						{
							AddBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff);
							Util.PlaySound("Play_item_proc_lowerHealthHigherDamage_proc", base.gameObject);
							TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 1f));
						}
						else if (HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff) && (double)normalizedHealth > 0.5)
						{
							RemoveBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff);
							TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 0f));
						}
					}
				}
				else if (HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff))
				{
					RemoveBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff);
					TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 0f));
				}
			}
			else if (itemCount == 0 && HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff) && healthComponent.health > 0f && teamComponent.teamIndex == TeamIndex.Player && (double)healthComponent.GetNormalizedHealth() > 0.5)
			{
				RemoveBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff);
				TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.LowerHealthHigherDamage.itemIndex, 0f));
			}
		}

		private void SetBoostAllStatsStartTimer(float t)
		{
			if (!boostAllStatsTimerStarted)
			{
				boostAllStatsStartTimer = t;
				boostAllStatsTimer = boostAllStatsStartTimer;
				boostAllStatsTimerStarted = true;
			}
		}

		private void SetBoostAllStatsCoolDownTimer(float t)
		{
			if (boostAllStatsCoolDownTimerStarted)
			{
				boostAllStatsCoolDownStartTimer = t;
				boostAllStatsCoolDownTimer = boostAllStatsCoolDownStartTimer;
			}
		}

		private float CalculateBoostAllStatsTriggerChance(int i)
		{
			boostAllStatsTriggerChance = boostAllStatsDefaultTriggerChance + boostAllStatsTriggerIncrease * (float)(i - 1);
			if ((double)boostAllStatsTriggerChance >= 0.5)
			{
				boostAllStatsTriggerChance = 0.5f;
			}
			return boostAllStatsTriggerChance;
		}

		private void UpdateBoostAllStatsTimer(float t)
		{
			if (!NetworkServer.active || !inventory)
			{
				return;
			}
			int itemCount = inventory.GetItemCount(DLC2Content.Items.BoostAllStats);
			if (!boostAllStatsCoolDownTimerStarted && itemCount > 0)
			{
				SetBoostAllStatsStartTimer(t);
				boostAllStatsTimer += t;
				if (boostAllStatsTimer >= boostAllStatsStartTimer + boostAllStatsTriggerTimer)
				{
					if (RoR2Application.rng.RangeFloat(0f, 1f) <= CalculateBoostAllStatsTriggerChance(inventory.GetItemCount(DLC2Content.Items.BoostAllStats)))
					{
						AddBuff(DLC2Content.Buffs.BoostAllStatsBuff);
						RecalculateStats();
						boostAllStatsTimerStarted = false;
						boostAllStatsCoolDownTimerStarted = true;
						SetBoostAllStatsCoolDownTimer(t);
					}
					else
					{
						boostAllStatsTimerStarted = false;
						boostAllStatsCoolDownTimerStarted = false;
					}
				}
			}
			else if (boostAllStatsCoolDownTimerStarted)
			{
				boostAllStatsCoolDownTimer += t;
				if (boostAllStatsCoolDownTimer >= boostAllStatsStartTimer + boostAllStatsCoolDownTriggerTimer)
				{
					RemoveBuff(DLC2Content.Buffs.BoostAllStatsBuff);
					RecalculateStats();
					boostAllStatsCoolDownTimerStarted = false;
				}
			}
		}

		public void RecalculateStats()
		{
			if (!Run.instance)
			{
				return;
			}
			float num = level;
			TeamManager.instance.GetTeamExperience(teamComponent.teamIndex);
			float num2 = TeamManager.instance.GetTeamLevel(teamComponent.teamIndex);
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			int num7 = 0;
			int num8 = 0;
			int num9 = 0;
			int num10 = 0;
			int num11 = 0;
			int num12 = 0;
			int num13 = 0;
			int num14 = 0;
			int num15 = 0;
			int num16 = 0;
			int num17 = 0;
			int num18 = 0;
			int num19 = 0;
			int num20 = 0;
			int num21 = 0;
			int num22 = 0;
			int num23 = 0;
			int num24 = 0;
			int num25 = 0;
			int num26 = 0;
			int num27 = 0;
			int num28 = 0;
			int num29 = 0;
			int num30 = 0;
			int num31 = 0;
			int num32 = 0;
			int num33 = 0;
			int num34 = 0;
			int num35 = 0;
			int num36 = 0;
			int num37 = 0;
			int num38 = 0;
			int num39 = 0;
			int num40 = 0;
			int num41 = 0;
			int num42 = 0;
			int num43 = 0;
			int num44 = 0;
			int num45 = 0;
			int num46 = 0;
			int num47 = 0;
			int num48 = 0;
			int num49 = 0;
			int num50 = 0;
			EquipmentIndex equipmentIndex = EquipmentIndex.None;
			uint num51 = 0u;
			int num52 = 0;
			int num53 = 0;
			int num54 = 0;
			int num55 = 0;
			if ((bool)inventory)
			{
				num3 = inventory.GetItemCount(RoR2Content.Items.LevelBonus);
				num4 = inventory.GetItemCount(RoR2Content.Items.Infusion);
				num5 = inventory.GetItemCount(RoR2Content.Items.HealWhileSafe);
				num6 = inventory.GetItemCount(RoR2Content.Items.PersonalShield);
				num7 = inventory.GetItemCount(RoR2Content.Items.Hoof);
				num8 = inventory.GetItemCount(RoR2Content.Items.SprintOutOfCombat);
				num9 = inventory.GetItemCount(RoR2Content.Items.Feather);
				num10 = inventory.GetItemCount(RoR2Content.Items.Syringe);
				num11 = inventory.GetItemCount(RoR2Content.Items.CritGlasses);
				num12 = inventory.GetItemCount(RoR2Content.Items.AttackSpeedOnCrit);
				num13 = inventory.GetItemCount(JunkContent.Items.CooldownOnCrit);
				num14 = inventory.GetItemCount(RoR2Content.Items.HealOnCrit);
				num15 = inventory.GetItemCount(RoR2Content.Items.ShieldOnly);
				num16 = inventory.GetItemCount(RoR2Content.Items.AlienHead);
				num17 = inventory.GetItemCount(RoR2Content.Items.Knurl);
				num18 = inventory.GetItemCount(RoR2Content.Items.BoostHp);
				num19 = inventory.GetItemCount(JunkContent.Items.CritHeal);
				num20 = inventory.GetItemCount(RoR2Content.Items.SprintBonus);
				num21 = inventory.GetItemCount(RoR2Content.Items.SecondarySkillMagazine);
				num23 = inventory.GetItemCount(RoR2Content.Items.SprintArmor);
				num24 = inventory.GetItemCount(RoR2Content.Items.UtilitySkillMagazine);
				num25 = inventory.GetItemCount(RoR2Content.Items.HealthDecay);
				num27 = inventory.GetItemCount(RoR2Content.Items.TonicAffliction);
				num28 = inventory.GetItemCount(RoR2Content.Items.LunarDagger);
				num26 = inventory.GetItemCount(RoR2Content.Items.DrizzlePlayerHelper);
				num29 = inventory.GetItemCount(RoR2Content.Items.MonsoonPlayerHelper);
				num30 = inventory.GetItemCount(RoR2Content.Items.Pearl);
				num31 = inventory.GetItemCount(RoR2Content.Items.ShinyPearl);
				num32 = inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger);
				num33 = inventory.GetItemCount(RoR2Content.Items.CutHp);
				num34 = inventory.GetItemCount(RoR2Content.Items.BoostAttackSpeed);
				num35 = inventory.GetItemCount(RoR2Content.Items.BleedOnHitAndExplode);
				num36 = inventory.GetItemCount(RoR2Content.Items.LunarBadLuck);
				num37 = inventory.GetItemCount(RoR2Content.Items.FlatHealth);
				num38 = inventory.GetItemCount(RoR2Content.Items.TeamSizeDamageBonus);
				num39 = inventory.GetItemCount(RoR2Content.Items.SummonedEcho);
				num40 = inventory.GetItemCount(RoR2Content.Items.UseAmbientLevel);
				num22 = inventory.GetItemCount(DLC1Content.Items.EquipmentMagazineVoid);
				num44 = inventory.GetItemCount(DLC1Content.Items.HalfAttackSpeedHalfCooldowns);
				num45 = inventory.GetItemCount(DLC1Content.Items.HalfSpeedDoubleHealth);
				num41 = inventory.GetItemCount(RoR2Content.Items.BleedOnHit);
				num42 = inventory.GetItemCount(DLC1Content.Items.AttackSpeedAndMoveSpeed);
				num43 = inventory.GetItemCount(DLC1Content.Items.CritDamage);
				num46 = inventory.GetItemCount(DLC1Content.Items.ConvertCritChanceToCritDamage);
				num47 = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost);
				num48 = inventory.GetItemCount(DLC1Content.Items.MissileVoid);
				equipmentIndex = inventory.currentEquipmentIndex;
				num51 = inventory.infusionBonus;
				num49 = ((equipmentIndex == DLC1Content.Equipment.EliteVoidEquipment.equipmentIndex) ? 1 : 0);
				num50 = inventory.GetItemCount(DLC1Content.Items.OutOfCombatArmor);
				inventory.GetItemCount(DLC1Content.Items.VoidmanPassiveItem);
				num52 = inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage);
				num53 = inventory.GetItemCount(DLC2Content.Items.BoostAllStats);
				inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth);
				num54 = inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill);
				inventory.GetItemCount(DLC2Content.Items.GoldOnStageStart);
				num55 = inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp);
			}
			level = num2;
			if (num40 > 0)
			{
				level = Math.Max(level, Run.instance.ambientLevelFloor);
			}
			level += num3;
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
			float num56 = level - 1f;
			isElite = eliteBuffCount > 0;
			bool flag = HasBuff(RoR2Content.Buffs.TonicBuff);
			bool num57 = HasBuff(RoR2Content.Buffs.Entangle);
			bool flag2 = HasBuff(RoR2Content.Buffs.Nullified);
			bool flag3 = HasBuff(RoR2Content.Buffs.LunarSecondaryRoot);
			bool flag4 = teamComponent.teamIndex == TeamIndex.Player && RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.glassArtifactDef);
			bool num58 = num15 > 0 || HasBuff(RoR2Content.Buffs.AffixLunar);
			bool flag5 = (object)equipmentDef != null && (object)equipmentDef == JunkContent.Equipment.EliteYellowEquipment;
			hasOneShotProtection = isPlayerControlled;
			int buffCount = GetBuffCount(RoR2Content.Buffs.BeetleJuice);
			int buffCount2 = GetBuffCount(DLC2Content.Buffs.RevitalizeBuff);
			isGlass = flag4 || num28 > 0;
			canPerformBackstab = (bodyFlags & BodyFlags.HasBackstabPassive) == BodyFlags.HasBackstabPassive;
			canReceiveBackstab = (bodyFlags & BodyFlags.HasBackstabImmunity) != BodyFlags.HasBackstabImmunity;
			float num59 = maxHealth;
			float num60 = maxShield;
			if (num55 > extraStatsOnLevelUpCountModifier && num55 > 0)
			{
				extraStatsOnLevelUpCountModifier = num55;
			}
			if (num55 < extraStatsOnLevelUpCountModifier && (bool)inventory)
			{
				UnityEngine.Object.Instantiate(CommonAssets.prayerBeadEffect, base.gameObject.transform.position, UnityEngine.Quaternion.identity).transform.parent = base.gameObject.transform;
				extraStatsOnLevelUpCountModifier -= num55;
				float beadAppliedHealth = inventory.beadAppliedHealth;
				prayerBeadCalculateAppliedStats(levelMaxHealth);
				prayerBeadCalculateAppliedStats(levelMaxShield);
				prayerBeadCalculateAppliedStats(levelRegen);
				prayerBeadCalculateAppliedStats(levelDamage);
				extraStatsOnLevelUpCountModifier = num55;
				if (HasBuff(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff))
				{
					SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, 0);
					bool gainedStats = inventory.beadAppliedHealth > beadAppliedHealth;
					master.OnBeadReset(gainedStats);
				}
			}
			HandleDisableAllSkillsDebuff();
			float num61 = baseMaxHealth + levelMaxHealth * num56;
			if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedHealth > 0f)
			{
				num61 += inventory.beadAppliedHealth;
			}
			float num62 = 1f;
			num62 += (float)num18 * 0.1f;
			num62 += (float)(num30 + num31) * 0.1f;
			num62 += (float)buffCount2 * 0.07f;
			num62 += (float)num49 * 0.5f;
			num62 += (float)num45 * 1f;
			if (num4 > 0)
			{
				num61 += (float)num51;
			}
			num61 += (float)num37 * 25f;
			num61 += (float)num17 * 40f;
			num61 *= num62;
			num61 /= (float)(num33 + 1);
			if (num32 > 0)
			{
				num61 *= 10f;
			}
			if (num39 > 0)
			{
				num61 *= 0.1f;
			}
			maxHealth = num61;
			float num63 = baseMaxShield + levelMaxShield * num56;
			if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedShield > 0f)
			{
				num63 += inventory.beadAppliedShield;
			}
			num63 += (float)num6 * 0.08f * maxHealth;
			if (HasBuff(RoR2Content.Buffs.EngiShield))
			{
				num63 += maxHealth * 1f;
			}
			if (HasBuff(JunkContent.Buffs.EngiTeamShield))
			{
				num63 += maxHealth * 0.5f;
			}
			if (num48 > 0)
			{
				num63 += maxHealth * 0.1f;
			}
			if (num58)
			{
				num63 += maxHealth * (1.5f + (float)(num15 - 1) * 0.25f);
				maxHealth = 1f;
			}
			if (HasBuff(RoR2Content.Buffs.AffixBlue))
			{
				float num64 = maxHealth * 0.5f;
				maxHealth -= num64;
				num63 += maxHealth;
			}
			maxShield = num63;
			float num65 = baseRegen + levelRegen * num56;
			if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedRegen > 0f)
			{
				num65 += inventory.beadAppliedRegen;
			}
			float num66 = 1f + num56 * 0.2f;
			float num67 = (float)num17 * 1.6f * num66;
			float num68 = ((outOfDanger && num5 > 0) ? (3f * (float)num5) : 0f) * num66;
			float num69 = (HasBuff(JunkContent.Buffs.MeatRegenBoost) ? 2f : 0f) * num66;
			float num70 = (float)GetBuffCount(RoR2Content.Buffs.CrocoRegen) * maxHealth * 0.1f;
			float num71 = (float)num31 * 0.1f * num66;
			float num72 = (float)buffCount2 * 0.07f * num66;
			float num73 = 1f;
			if (num26 > 0)
			{
				num73 += 0.5f;
			}
			if (num29 > 0)
			{
				num73 -= 0.4f;
			}
			float num74 = (num65 + num67 + num68 + num69 + num71 + num72) * num73;
			if (HasBuff(RoR2Content.Buffs.OnFire) || HasBuff(DLC1Content.Buffs.StrongerBurn))
			{
				num74 = Mathf.Min(0f, num74);
			}
			num74 += num70;
			if (num58)
			{
				num74 = Mathf.Max(num74, 0f);
			}
			if (num25 > 0)
			{
				num74 = Mathf.Min(num74, 0f) - maxHealth / cursePenalty / (float)num25;
			}
			if (tamperedHeartActive)
			{
				num74 += tamperedHeartRegenBonus;
			}
			if (HasBuff(DLC2Content.Buffs.HealAndReviveRegenBuff))
			{
				num74 += num74 * 0.5f;
			}
			regen = num74;
			float num75 = baseMoveSpeed + levelMoveSpeed * num56;
			num75 += surfaceSpeedBoost;
			float num76 = 1f;
			if (flag5)
			{
				num75 += 2f;
			}
			if (isSprinting)
			{
				num75 *= sprintingSpeedMultiplier;
			}
			num76 += (float)num7 * 0.14f;
			num76 += (float)num42 * 0.07f;
			num76 += (float)num31 * 0.1f;
			num76 += (float)buffCount2 * 0.07f;
			num76 += 0.25f * (float)GetBuffCount(DLC1Content.Buffs.KillMoveSpeed);
			if (teamComponent.teamIndex == TeamIndex.Monster && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse4)
			{
				num76 += 0.4f;
			}
			if (isSprinting && num20 > 0)
			{
				num76 += 0.25f * (float)num20 / sprintingSpeedMultiplier;
			}
			if (num8 > 0 && HasBuff(RoR2Content.Buffs.WhipBoost))
			{
				num76 += (float)num8 * 0.3f;
			}
			if (num39 > 0)
			{
				num76 += 0.66f;
			}
			if (HasBuff(RoR2Content.Buffs.BugWings))
			{
				num76 += 0.2f;
			}
			if (HasBuff(RoR2Content.Buffs.Warbanner))
			{
				num76 += 0.3f;
			}
			if (HasBuff(JunkContent.Buffs.EnrageAncientWisp))
			{
				num76 += 0.4f;
			}
			if (HasBuff(RoR2Content.Buffs.CloakSpeed))
			{
				num76 += 0.4f;
			}
			if (HasBuff(RoR2Content.Buffs.WarCryBuff) || HasBuff(RoR2Content.Buffs.TeamWarCry))
			{
				num76 += 0.5f;
			}
			if (HasBuff(JunkContent.Buffs.EngiTeamShield))
			{
				num76 += 0.3f;
			}
			if (HasBuff(RoR2Content.Buffs.AffixLunar))
			{
				num76 += 0.3f;
			}
			if (tamperedHeartActive)
			{
				num75 += num75 * tamperedHeartMSpeedBonus;
			}
			float num77 = 1f;
			if (HasBuff(RoR2Content.Buffs.Slow50))
			{
				num77 += 0.5f;
			}
			if (HasBuff(RoR2Content.Buffs.Slow60))
			{
				num77 += 0.6f;
			}
			if (HasBuff(RoR2Content.Buffs.Slow80))
			{
				num77 += 0.8f;
			}
			if (HasBuff(RoR2Content.Buffs.ClayGoo))
			{
				num77 += 0.5f;
			}
			if (HasBuff(JunkContent.Buffs.Slow30))
			{
				num77 += 0.3f;
			}
			if (HasBuff(RoR2Content.Buffs.Cripple))
			{
				num77 += 1f;
			}
			if (HasBuff(DLC1Content.Buffs.JailerSlow))
			{
				num77 += 1f;
			}
			num77 += (float)num45 * 1f;
			num75 *= num76 / num77;
			if (buffCount > 0)
			{
				num75 *= 1f - 0.05f * (float)buffCount;
			}
			moveSpeed = num75;
			acceleration = ((baseMoveSpeed == 0f) ? 0f : (moveSpeed / baseMoveSpeed * baseAcceleration));
			if (num57 || flag2 || flag3)
			{
				moveSpeed = 0f;
				acceleration = 80f;
			}
			float num78 = baseJumpPower + levelJumpPower * num56;
			jumpPower = num78;
			maxJumpHeight = Trajectory.CalculateApex(jumpPower);
			maxJumpCount = baseJumpCount + num9;
			oneShotProtectionFraction = 0.1f;
			float num79 = baseDamage + levelDamage * num56;
			if (teamComponent.teamIndex == TeamIndex.Player && (bool)inventory && inventory.beadAppliedDamage > 0f)
			{
				num79 += inventory.beadAppliedDamage;
			}
			float num80 = 1f;
			int num81 = (inventory ? inventory.GetItemCount(RoR2Content.Items.BoostDamage) : 0);
			if (num81 > 0)
			{
				num80 += (float)num81 * 0.1f;
			}
			if (num38 > 0)
			{
				int num82 = Math.Max(TeamComponent.GetTeamMembers(teamComponent.teamIndex).Count - 1, 0);
				num80 += (float)(num82 * num38) * 1f;
			}
			if (buffCount > 0)
			{
				num80 -= 0.05f * (float)buffCount;
			}
			if (HasBuff(JunkContent.Buffs.GoldEmpowered))
			{
				num80 += 1f;
			}
			if (HasBuff(RoR2Content.Buffs.PowerBuff))
			{
				num80 += 0.5f;
			}
			num80 += (float)num31 * 0.1f;
			num80 += (float)buffCount2 * 0.07f;
			num80 += Mathf.Pow(2f, num28) - 1f;
			num80 -= (float)num49 * 0.3f;
			num79 *= num80;
			if (num32 > 0)
			{
				num79 *= 0.04f;
			}
			if (flag4)
			{
				num79 *= 5f;
			}
			damage = num79;
			damageFromRecalculateStats = damage;
			if (HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff))
			{
				damage += baseDamage * (float)currentHealthLevel * 0.1f * (float)num52 * 0.5f;
			}
			_ = tamperedHeartActive;
			if (HasBuff(DLC2Content.Buffs.IncreaseDamageBuff))
			{
				int buffCount3 = GetBuffCount(DLC2Content.Buffs.IncreaseDamageBuff);
				float num83 = 0f;
				if (buffCount3 >= 2)
				{
					num83 = (float)(buffCount3 * (buffCount3 + num54 * 5)) * 0.01f;
				}
				else if (buffCount3 == 1)
				{
					num83 = (float)(1 + num54 * 5) * 0.01f;
				}
				damage += baseDamage * num83;
				if (oldComboMeter < buffCount3)
				{
					oldComboMeter = buffCount3;
				}
			}
			float num84 = baseAttackSpeed + levelAttackSpeed * num56;
			float num85 = 1f;
			num85 += (float)num34 * 0.1f;
			num85 += (float)num10 * 0.15f;
			num85 += (float)num42 * 0.075f;
			num85 += (float)num47 * 0.5f;
			if (flag5)
			{
				num85 += 0.5f;
			}
			num85 += (float)GetBuffCount(RoR2Content.Buffs.AttackSpeedOnCrit) * 0.12f;
			if (HasBuff(RoR2Content.Buffs.Warbanner))
			{
				num85 += 0.3f;
			}
			if (HasBuff(RoR2Content.Buffs.Energized))
			{
				num85 += 0.7f;
			}
			if (HasBuff(RoR2Content.Buffs.WarCryBuff) || HasBuff(RoR2Content.Buffs.TeamWarCry))
			{
				num85 += 1f;
			}
			num85 += (float)num31 * 0.1f;
			num85 += (float)buffCount2 * 0.07f;
			num85 /= (float)(num44 + 1);
			num85 = Mathf.Max(num85, 0.1f);
			num84 *= num85;
			if (buffCount > 0)
			{
				num84 *= 1f - 0.05f * (float)buffCount;
			}
			if (tamperedHeartActive)
			{
				num84 += num84 * tamperedHeartAttackSpeedBonus;
			}
			attackSpeed = num84;
			critMultiplier = 2f + 1f * (float)num43;
			float num86 = baseCrit + levelCrit * num56;
			num86 += (float)num11 * 10f;
			if (num12 > 0)
			{
				num86 += 5f;
			}
			if (num35 > 0)
			{
				num86 += 5f;
			}
			if (num13 > 0)
			{
				num86 += 5f;
			}
			if (num14 > 0)
			{
				num86 += 5f;
			}
			if (num19 > 0)
			{
				num86 += 5f;
			}
			if (HasBuff(RoR2Content.Buffs.FullCrit))
			{
				num86 += 100f;
			}
			num86 += (float)num31 * 10f;
			num86 += (float)buffCount2 * 7f;
			if (num46 == 0)
			{
				crit = num86;
			}
			else
			{
				critMultiplier += num86 * 0.01f;
				crit = 0f;
			}
			armor = baseArmor + levelArmor * num56;
			armor *= 1f + 0.1f * (float)num31;
			armor *= 1f + 0.07f * (float)buffCount2;
			armor += (float)num26 * 70f;
			armor += (HasBuff(RoR2Content.Buffs.ArmorBoost) ? 200f : 0f);
			armor += (HasBuff(RoR2Content.Buffs.SmallArmorBoost) ? 100f : 0f);
			armor += (HasBuff(DLC1Content.Buffs.OutOfCombatArmorBuff) ? (100f * (float)num50) : 0f);
			armor += (HasBuff(RoR2Content.Buffs.ElephantArmorBoost) ? 500f : 0f);
			armor += (HasBuff(DLC1Content.Buffs.VoidSurvivorCorruptMode) ? 100f : 0f);
			armor += (HasBuff(DLC2Content.Buffs.AurelioniteBlessing) ? (60f + 0.1f * (float)master.money) : 0f);
			if (HasBuff(RoR2Content.Buffs.Cripple))
			{
				armor -= 20f;
			}
			if (HasBuff(RoR2Content.Buffs.Pulverized))
			{
				armor -= 60f;
			}
			if (isSprinting && num23 > 0)
			{
				armor += num23 * 30;
			}
			if (tamperedHeartActive)
			{
				armor += tamperedHeartArmorBonus;
			}
			int buffCount4 = GetBuffCount(DLC1Content.Buffs.PermanentDebuff);
			armor -= (float)buffCount4 * 2f;
			float num87 = 0f;
			if (num36 > 0)
			{
				num87 += 2f + 1f * (float)(num36 - 1);
			}
			float num88 = 1f;
			if (HasBuff(JunkContent.Buffs.GoldEmpowered))
			{
				num88 *= 0.25f;
			}
			for (int i = 0; i < num16; i++)
			{
				num88 *= 0.75f;
			}
			for (int j = 0; j < num44; j++)
			{
				num88 *= 0.5f;
			}
			for (int k = 0; k < num47; k++)
			{
				num88 *= 0.5f;
			}
			if (teamComponent.teamIndex == TeamIndex.Monster && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse7)
			{
				num88 *= 0.5f;
			}
			if (HasBuff(RoR2Content.Buffs.NoCooldowns))
			{
				num88 = 0f;
			}
			if ((bool)skillLocator.primary)
			{
				skillLocator.primary.cooldownScale = num88;
				skillLocator.primary.flatCooldownReduction = num87;
			}
			if ((bool)skillLocator.secondaryBonusStockSkill)
			{
				skillLocator.secondaryBonusStockSkill.cooldownScale = num88;
				skillLocator.secondaryBonusStockSkill.SetBonusStockFromBody(num21 + extraSecondaryFromSkill);
				skillLocator.secondaryBonusStockSkill.flatCooldownReduction = num87;
			}
			if ((bool)skillLocator.utilityBonusStockSkill)
			{
				float num89 = num88;
				if (num24 > 0)
				{
					num89 *= 2f / 3f;
				}
				skillLocator.utilityBonusStockSkill.cooldownScale = num89;
				skillLocator.utilityBonusStockSkill.flatCooldownReduction = num87;
				skillLocator.utilityBonusStockSkill.SetBonusStockFromBody(num24 * 2);
			}
			if ((bool)skillLocator.specialBonusStockSkill)
			{
				skillLocator.specialBonusStockSkill.cooldownScale = num88;
				if (num22 > 0)
				{
					skillLocator.specialBonusStockSkill.cooldownScale *= 0.67f;
				}
				skillLocator.specialBonusStockSkill.flatCooldownReduction = num87;
				skillLocator.specialBonusStockSkill.SetBonusStockFromBody(num22 + extraSpecialFromSkill);
			}
			critHeal = 0f;
			if (num19 > 0)
			{
				float num90 = crit;
				crit /= num19 + 1;
				critHeal = num90 - crit;
			}
			cursePenalty = 1f;
			if (num28 > 0)
			{
				cursePenalty = Mathf.Pow(2f, num28);
			}
			if (flag4)
			{
				cursePenalty *= 10f;
			}
			int buffCount5 = GetBuffCount(RoR2Content.Buffs.PermanentCurse);
			if (buffCount5 > 0)
			{
				cursePenalty += (float)buffCount5 * 0.01f;
			}
			if (HasBuff(RoR2Content.Buffs.Weak))
			{
				armor -= 30f;
				damage *= 0.6f;
				moveSpeed *= 0.6f;
			}
			if (HasBuff(DLC2Content.Buffs.lunarruin))
			{
				moveSpeed *= 0.8f;
			}
			if (flag)
			{
				maxHealth *= 1.5f;
				maxShield *= 1.5f;
				attackSpeed *= 1.7f;
				moveSpeed *= 1.3f;
				armor += 20f;
				damage *= 2f;
				regen *= 4f;
			}
			if (HasBuff(DLC2Content.Buffs.BoostAllStatsBuff))
			{
				float num91 = (float)num53 * boostAllStatsMultiplier;
				_ = maxHealth;
				_ = moveSpeed;
				_ = damage;
				_ = attackSpeed;
				_ = crit;
				_ = regen;
				maxHealth += maxHealth * num91;
				moveSpeed += moveSpeed * num91;
				damage += damage * num91;
				attackSpeed += attackSpeed * num91;
				crit += crit * num91;
				regen += regen * num91;
			}
			maxBonusHealth = maxHealth;
			if (num27 > 0 && !flag)
			{
				float num92 = Mathf.Pow(0.95f, num27);
				attackSpeed *= num92;
				moveSpeed *= num92;
				damage *= num92;
				regen *= num92;
				cursePenalty += 0.1f * (float)num27;
			}
			if (HasBuff(DLC2Content.Buffs.SoulCost))
			{
				cursePenalty += 0.1f * (float)GetBuffCount(DLC2Content.Buffs.SoulCost);
			}
			maxHealth /= cursePenalty;
			maxShield /= cursePenalty;
			oneShotProtectionFraction = Mathf.Max(0f, oneShotProtectionFraction - (1f - 1f / cursePenalty));
			maxBarrier = maxHealth + maxShield;
			barrierDecayRate = maxBarrier / 30f;
			if (NetworkServer.active)
			{
				float num93 = maxHealth - num59;
				float num94 = maxShield - num60;
				if (num93 > 0f)
				{
					healthComponent.Heal(num93, default(ProcChainMask), nonRegen: false);
				}
				else if (healthComponent.health > maxHealth)
				{
					healthComponent.Networkhealth = Mathf.Max(healthComponent.health + num93, maxHealth);
				}
				if (num94 > 0f)
				{
					healthComponent.RechargeShield(num94);
				}
				else if (healthComponent.shield > maxShield)
				{
					healthComponent.Networkshield = Mathf.Max(healthComponent.shield + num94, maxShield);
				}
			}
			bleedChance = 10f * (float)num41;
			visionDistance = baseVisionDistance;
			if (HasBuff(DLC1Content.Buffs.Blinded))
			{
				visionDistance = Mathf.Min(visionDistance, 15f);
			}
			if (level != num)
			{
				OnCalculatedLevelChanged(num, level);
			}
			int num95 = 0;
			if (num53 > 0 && !HasBuff(DLC2Content.Buffs.BoostAllStatsBuff))
			{
				BuffIndex[] nonHiddenBuffIndices = BuffCatalog.nonHiddenBuffIndices;
				foreach (BuffIndex buffIndex in nonHiddenBuffIndices)
				{
					if (HasBuff(buffIndex) && buffIndex != DLC2Content.Buffs.BoostAllStatsBuff.buffIndex && !BuffCatalog.ignoreGrowthNectarIndices.Contains(buffIndex))
					{
						num95++;
						if (num95 >= 5 && !HasBuff(DLC2Content.Buffs.BoostAllStatsBuff))
						{
							AddTimedBuff(DLC2Content.Buffs.BoostAllStatsBuff, 5f);
						}
					}
				}
			}
			UpdateAllTemporaryVisualEffects();
			statsDirty = false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void HandleDisableAllSkillsDebuff()
		{
			bool flag = HasBuff(DLC2Content.Buffs.DisableAllSkills);
			if (flag != allSkillsDisabled)
			{
				if (flag)
				{
					HandleSkillDisableState(_disable: true);
					allSkillsDisabled = true;
				}
				else
				{
					HandleSkillDisableState(_disable: false);
					allSkillsDisabled = false;
				}
			}
			void HandleSkillDisableState(bool _disable)
			{
				if (base.hasAuthority)
				{
					SkillDef skillDef = LegacyResourcesAPI.Load<SkillDef>("Skills/DisabledSkills");
					if (!skillDef)
					{
						UnityEngine.Debug.LogWarning("Could not find disabledSkill for DisableAllSkills.");
					}
					else if (_disable)
					{
						skillLocator.primary.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						skillLocator.secondary.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						skillLocator.utility.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						skillLocator.special.SetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						inventory.SetEquipmentDisabled(_active: true);
						Util.PlaySound("Play_env_meridian_primeDevestator_debuff", base.gameObject);
						screenDamageSkillsDisabled = new ScreenDamageCalculatorDisabledSkills();
						healthComponent.screenDamageCalculator = screenDamageSkillsDisabled;
					}
					else
					{
						skillLocator.primary.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						skillLocator.secondary.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						skillLocator.utility.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						skillLocator.special.UnsetSkillOverride(this, skillDef, GenericSkill.SkillOverridePriority.Contextual);
						inventory.SetEquipmentDisabled(_active: false);
						if (screenDamageSkillsDisabled != null)
						{
							if (healthComponent.screenDamageCalculator == screenDamageSkillsDisabled)
							{
								healthComponent.screenDamageCalculator = null;
							}
							screenDamageSkillsDisabled.End();
						}
					}
				}
			}
		}

		public void OnTeamLevelChanged()
		{
			statsDirty = true;
		}

		private void OnCalculatedLevelChanged(float oldLevel, float newLevel)
		{
			if (newLevel > oldLevel)
			{
				int num = Mathf.FloorToInt(oldLevel);
				if (Mathf.FloorToInt(newLevel) > num && num != 0)
				{
					OnLevelUp();
				}
			}
		}

		private void OnLevelUp()
		{
			GlobalEventManager.OnCharacterLevelUp(this);
			if (inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock) > 0)
			{
				solitudeLevelCount++;
				AddFreeChestBuff();
				Util.PlaySound("Play_item_proc_onLevelUpFreeUnlock_activate", base.gameObject);
			}
		}

		public void SetAimTimer(float duration)
		{
			aimTimer = duration;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			byte num = reader.ReadByte();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				NetworkInstanceId networkInstanceId = reader.ReadNetworkId();
				if (networkInstanceId != masterObjectId)
				{
					masterObjectId = networkInstanceId;
					statsDirty = true;
				}
			}
			if ((num & 2u) != 0)
			{
				ReadBuffs(reader);
			}
			if ((num & 4u) != 0)
			{
				bool flag = reader.ReadBoolean();
				if (!hasEffectiveAuthority && flag != outOfCombat)
				{
					outOfCombat = flag;
					statsDirty = true;
				}
			}
			if ((num & 8u) != 0)
			{
				bool flag2 = reader.ReadBoolean();
				if (flag2 != outOfDanger)
				{
					outOfDanger = flag2;
					statsDirty = true;
				}
			}
			if ((num & 0x10u) != 0)
			{
				bool flag3 = reader.ReadBoolean();
				if (flag3 != isSprinting && !hasEffectiveAuthority)
				{
					statsDirty = true;
					isSprinting = flag3;
				}
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 31u;
			}
			bool num2 = (num & 1) != 0;
			bool flag = (num & 2) != 0;
			bool flag2 = (num & 4) != 0;
			bool flag3 = (num & 8) != 0;
			bool flag4 = (num & 0x10) != 0;
			writer.Write((byte)num);
			if (num2)
			{
				writer.Write(masterObjectId);
			}
			if (flag)
			{
				WriteBuffs(writer);
			}
			if (flag2)
			{
				writer.Write(outOfCombat);
			}
			if (flag3)
			{
				writer.Write(outOfDanger);
			}
			if (flag4)
			{
				writer.Write(isSprinting);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public void TransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData)
		{
			if (!NetworkServer.active)
			{
				InternalTransmitItemBehavior(itemBehaviorData);
				CallCmdTransmitItemBehavior(itemBehaviorData);
			}
			else
			{
				ServerTransmitItemBehavior(itemBehaviorData);
			}
		}

		[Server]
		private void ServerTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ServerTransmitItemBehavior(RoR2.CharacterBody/NetworkItemBehaviorData)' called on client");
				return;
			}
			CallRpcTransmitItemBehavior(itemBehaviorData);
			InternalTransmitItemBehavior(itemBehaviorData);
		}

		[Command]
		private void CmdTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData)
		{
			ServerTransmitItemBehavior(itemBehaviorData);
		}

		[ClientRpc(channel = 1)]
		private void RpcTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData)
		{
			if (!NetworkServer.active)
			{
				InternalTransmitItemBehavior(itemBehaviorData);
			}
		}

		private void InternalTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData)
		{
			OnNetworkItemBehaviorUpdate?.Invoke(itemBehaviorData);
		}

		public T AddItemBehavior<T>(int stack) where T : ItemBehavior
		{
			T val = GetComponent<T>();
			if (stack > 0)
			{
				if (!val)
				{
					val = base.gameObject.AddComponent<T>();
					val.body = this;
					val.enabled = true;
				}
				val.stack = stack;
				return val;
			}
			if ((bool)val)
			{
				UnityEngine.Object.Destroy(val);
			}
			return null;
		}

		public void HandleOnKillEffectsServer(DamageReport damageReport)
		{
			int num = killCountServer + 1;
			killCountServer = num;
			AddMultiKill(1);
		}

		public void OnKilledOtherServer(DamageReport damageReport)
		{
		}

		public void AddHelfireDuration(float duration)
		{
			helfireLifetime = duration;
		}

		[Server]
		private void UpdateHelfire(float deltaTime)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateHelfire(System.Single)' called on client");
				return;
			}
			helfireLifetime -= deltaTime;
			bool flag = false;
			if ((bool)inventory)
			{
				flag = itemAvailability.helfireCount > 0 || helfireLifetime > 0f;
			}
			if ((bool)helfireController != flag)
			{
				if (flag)
				{
					helfireController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/HelfireController")).GetComponent<HelfireController>();
					helfireController.networkedBodyAttachment.AttachToGameObjectAndSpawn(base.gameObject);
				}
				else
				{
					UnityEngine.Object.Destroy(helfireController.gameObject);
					helfireController = null;
				}
			}
		}

		private void UpdateFireTrail()
		{
			bool hasFireTrail = itemAvailability.hasFireTrail;
			if (hasFireTrail != (bool)fireTrail)
			{
				if (hasFireTrail)
				{
					fireTrail = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/FireTrail"), transform).GetComponent<DamageTrail>();
					fireTrail.transform.position = footPosition;
					fireTrail.owner = base.gameObject;
					fireTrail.radius *= radius;
				}
				else
				{
					UnityEngine.Object.Destroy(fireTrail.gameObject);
					fireTrail = null;
				}
			}
			if ((bool)fireTrail)
			{
				fireTrail.damagePerSecond = damage * 1.5f;
			}
		}

		private void UpdateAffixPoison(float deltaTime)
		{
			if (!itemAvailability.hasAffixPoison)
			{
				return;
			}
			poisonballTimer += deltaTime;
			if (poisonballTimer >= 6f)
			{
				int num = 3 + (int)radius;
				poisonballTimer = 0f;
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				float num2 = 360f / (float)num;
				UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(transform.forward, up).normalized;
				UnityEngine.Vector3 vector = UnityEngine.Vector3.RotateTowards(up, normalized, 0.43633232f, float.PositiveInfinity);
				for (int i = 0; i < num; i++)
				{
					UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(num2 * (float)i, up) * vector;
					ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/PoisonOrbProjectile"), corePosition, Util.QuaternionSafeLookRotation(forward), base.gameObject, damage * 1f, 0f, Util.CheckRoll(crit, master));
				}
			}
		}

		private void UpdateAffixLunar(float deltaTime)
		{
			if (!outOfCombat && itemAvailability.hasAffixLunar)
			{
				lunarMissileRechargeTimer += deltaTime;
				lunarMissileTimerBetweenShots += deltaTime;
				int num = 4;
				if (!lunarMissilePrefab)
				{
					lunarMissilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/LunarMissileProjectile");
				}
				if (lunarMissileRechargeTimer >= 10f)
				{
					lunarMissileRechargeTimer = 0f;
					remainingMissilesToFire += num;
				}
				if (remainingMissilesToFire > 0 && lunarMissileTimerBetweenShots > 0.1f)
				{
					lunarMissileTimerBetweenShots = 0f;
					UnityEngine.Vector3 vector = (inputBank ? inputBank.aimDirection : transform.forward);
					float num2 = 180f / (float)num;
					float num3 = 3f + (float)(int)radius * 1f;
					float num4 = damage * 0.3f;
					UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(vector);
					UnityEngine.Vector3 vector2 = UnityEngine.Quaternion.AngleAxis((float)(remainingMissilesToFire - 1) * num2 - num2 * (float)(num - 1) / 2f, vector) * UnityEngine.Vector3.up * num3;
					UnityEngine.Vector3 position = aimOrigin + vector2;
					FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
					fireProjectileInfo.projectilePrefab = lunarMissilePrefab;
					fireProjectileInfo.position = position;
					fireProjectileInfo.rotation = rotation;
					fireProjectileInfo.owner = base.gameObject;
					fireProjectileInfo.damage = num4;
					fireProjectileInfo.crit = Util.CheckRoll(crit, master);
					fireProjectileInfo.force = 200f;
					FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
					ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
					remainingMissilesToFire--;
				}
			}
		}

		private void UpdateAllTemporaryVisualEffects()
		{
			int buffCount = GetBuffCount(RoR2Content.Buffs.NullifyStack);
			UpdateSingleTemporaryVisualEffect(ref engiShieldTempEffectInstance, AssetReferences.engiShieldTempEffectPrefab, bestFitRadius, healthComponent.shield > 0f && HasBuff(RoR2Content.Buffs.EngiShield));
			ref TemporaryVisualEffect tempEffect = ref bucklerShieldTempEffectInstance;
			GameObject bucklerShieldTempEffectPrefab = AssetReferences.bucklerShieldTempEffectPrefab;
			float effectRadius = radius;
			int active;
			if (isSprinting)
			{
				Inventory obj = inventory;
				active = (((object)obj != null && obj.GetItemCount(RoR2Content.Items.SprintArmor) > 0) ? 1 : 0);
			}
			else
			{
				active = 0;
			}
			UpdateSingleTemporaryVisualEffect(ref tempEffect, bucklerShieldTempEffectPrefab, effectRadius, (byte)active != 0);
			UpdateSingleTemporaryVisualEffect(ref slowDownTimeTempEffectInstance, AssetReferences.slowDownTimeTempEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Slow60));
			UpdateSingleTemporaryVisualEffect(ref crippleEffectInstance, AssetReferences.crippleEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Cripple));
			UpdateSingleTemporaryVisualEffect(ref tonicBuffEffectInstance, AssetReferences.tonicBuffEffectPrefab, radius, HasBuff(RoR2Content.Buffs.TonicBuff));
			UpdateSingleTemporaryVisualEffect(ref weakTempEffectInstance, AssetReferences.weakTempEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Weak));
			UpdateSingleTemporaryVisualEffect(ref energizedTempEffectInstance, AssetReferences.energizedTempEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Energized));
			UpdateSingleTemporaryVisualEffect(ref barrierTempEffectInstance, AssetReferences.barrierTempEffectPrefab, bestFitRadius, healthComponent.barrier > 0f);
			UpdateSingleTemporaryVisualEffect(ref regenBoostEffectInstance, AssetReferences.regenBoostEffectPrefab, bestFitRadius, HasBuff(JunkContent.Buffs.MeatRegenBoost));
			UpdateSingleTemporaryVisualEffect(ref elephantDefenseEffectInstance, AssetReferences.elephantDefenseEffectPrefab, radius, HasBuff(RoR2Content.Buffs.ElephantArmorBoost));
			UpdateSingleTemporaryVisualEffect(ref healingDisabledEffectInstance, AssetReferences.healingDisabledEffectPrefab, radius, HasBuff(RoR2Content.Buffs.HealingDisabled));
			UpdateSingleTemporaryVisualEffect(ref noCooldownEffectInstance, AssetReferences.noCooldownEffectPrefab, radius, HasBuff(RoR2Content.Buffs.NoCooldowns), "Head");
			ref TemporaryVisualEffect tempEffect2 = ref doppelgangerEffectInstance;
			GameObject doppelgangerEffectPrefab = AssetReferences.doppelgangerEffectPrefab;
			float effectRadius2 = radius;
			Inventory obj2 = inventory;
			UpdateSingleTemporaryVisualEffect(ref tempEffect2, doppelgangerEffectPrefab, effectRadius2, (object)obj2 != null && obj2.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0, "Head");
			UpdateSingleTemporaryVisualEffect(ref nullifyStack1EffectInstance, AssetReferences.nullifyStack1EffectPrefab, radius, buffCount == 1);
			UpdateSingleTemporaryVisualEffect(ref nullifyStack2EffectInstance, AssetReferences.nullifyStack2EffectPrefab, radius, buffCount == 2);
			UpdateSingleTemporaryVisualEffect(ref nullifyStack3EffectInstance, AssetReferences.nullifyStack3EffectPrefab, radius, HasBuff(RoR2Content.Buffs.Nullified));
			UpdateSingleTemporaryVisualEffect(ref deathmarkEffectInstance, AssetReferences.deathmarkEffectPrefab, radius, HasBuff(RoR2Content.Buffs.DeathMark));
			UpdateSingleTemporaryVisualEffect(ref crocoRegenEffectInstance, AssetReferences.crocoRegenEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.CrocoRegen));
			UpdateSingleTemporaryVisualEffect(ref mercExposeEffectInstance, AssetReferences.mercExposeEffectPrefab, radius, HasBuff(RoR2Content.Buffs.MercExpose));
			UpdateSingleTemporaryVisualEffect(ref lifestealOnHitEffectInstance, AssetReferences.lifestealOnHitEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.LifeSteal));
			UpdateSingleTemporaryVisualEffect(ref teamWarCryEffectInstance, AssetReferences.teamWarCryEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.TeamWarCry), "HeadCenter");
			UpdateSingleTemporaryVisualEffect(ref lunarGolemShieldEffectInstance, AssetReferences.lunarGolemShieldEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.LunarShell));
			UpdateSingleTemporaryVisualEffect(ref randomDamageEffectInstance, AssetReferences.randomDamageEffectPrefab, radius, HasBuff(RoR2Content.Buffs.PowerBuff));
			UpdateSingleTemporaryVisualEffect(ref warbannerEffectInstance, AssetReferences.warbannerEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Warbanner));
			UpdateSingleTemporaryVisualEffect(ref teslaFieldEffectInstance, AssetReferences.teslaFieldEffectPrefab, bestFitRadius, HasBuff(RoR2Content.Buffs.TeslaField));
			UpdateSingleTemporaryVisualEffect(ref lunarSecondaryRootEffectInstance, AssetReferences.lunarSecondaryRootEffectPrefab, radius, HasBuff(RoR2Content.Buffs.LunarSecondaryRoot));
			UpdateSingleTemporaryVisualEffect(ref lunarDetonatorEffectInstance, AssetReferences.lunarDetonatorEffectPrefab, radius, HasBuff(RoR2Content.Buffs.LunarDetonationCharge));
			UpdateSingleTemporaryVisualEffect(ref fruitingEffectInstance, AssetReferences.fruitingEffectPrefab, radius, HasBuff(RoR2Content.Buffs.Fruiting));
			UpdateSingleTemporaryVisualEffect(ref mushroomVoidTempEffectInstance, AssetReferences.mushroomVoidTempEffectPrefab, radius, HasBuff(DLC1Content.Buffs.MushroomVoidActive));
			UpdateSingleTemporaryVisualEffect(ref bearVoidTempEffectInstance, AssetReferences.bearVoidTempEffectPrefab, radius, HasBuff(DLC1Content.Buffs.BearVoidReady));
			UpdateSingleTemporaryVisualEffect(ref outOfCombatArmorEffectInstance, AssetReferences.outOfCombatArmorEffectPrefab, radius, HasBuff(DLC1Content.Buffs.OutOfCombatArmorBuff));
			UpdateSingleTemporaryVisualEffect(ref voidFogMildEffectInstance, AssetReferences.voidFogMildEffectPrefab, radius, HasBuff(RoR2Content.Buffs.VoidFogMild));
			UpdateSingleTemporaryVisualEffect(ref voidFogStrongEffectInstance, AssetReferences.voidFogStrongEffectPrefab, radius, HasBuff(RoR2Content.Buffs.VoidFogStrong));
			UpdateSingleTemporaryVisualEffect(ref voidRaidcrabWardWipeFogEffectInstance, AssetReferences.voidRaidcrabWardWipeFogEffectPrefab, radius, HasBuff(DLC1Content.Buffs.VoidRaidCrabWardWipeFog));
			UpdateSingleTemporaryVisualEffect(ref voidJailerSlowEffectInstance, AssetReferences.voidJailerSlowEffectPrefab, radius, HasBuff(DLC1Content.Buffs.JailerSlow));
			UpdateSingleTemporaryVisualEffect(ref aurelioniteBlessingEffectInstance, AssetReferences.aurelioniteBlessingEffectInstance, bestFitActualRadius, HasBuff(DLC2Content.Buffs.AurelioniteBlessing), "Pelvis");
			if ((bool)mushroomVoidTempEffectInstance && !HasBuff(DLC1Content.Buffs.MushroomVoidActive))
			{
				UnityEngine.Object.Destroy(mushroomVoidTempEffectInstance.gameObject);
			}
		}

		private void UpdateSingleTemporaryVisualEffect(ref TemporaryVisualEffect tempEffect, string resourceString, float effectRadius, bool active, string childLocatorOverride = "")
		{
			bool flag = tempEffect != null;
			if (flag == active)
			{
				return;
			}
			if (active)
			{
				if (flag)
				{
					return;
				}
				GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>(resourceString), corePosition, UnityEngine.Quaternion.identity);
				tempEffect = gameObject.GetComponent<TemporaryVisualEffect>();
				tempEffect.parentTransform = coreTransform;
				tempEffect.visualState = TemporaryVisualEffect.VisualState.Enter;
				tempEffect.healthComponent = healthComponent;
				tempEffect.radius = effectRadius;
				LocalCameraEffect component = gameObject.GetComponent<LocalCameraEffect>();
				if ((bool)component)
				{
					component.targetCharacter = base.gameObject;
				}
				if (string.IsNullOrEmpty(childLocatorOverride))
				{
					return;
				}
				ChildLocator childLocator = modelLocator?.modelTransform?.GetComponent<ChildLocator>();
				if ((bool)childLocator)
				{
					Transform transform = childLocator.FindChild(childLocatorOverride);
					if ((bool)transform)
					{
						tempEffect.parentTransform = transform;
					}
				}
			}
			else if ((bool)tempEffect)
			{
				tempEffect.visualState = TemporaryVisualEffect.VisualState.Exit;
			}
		}

		private void UpdateSingleTemporaryVisualEffect(ref TemporaryVisualEffect tempEffect, GameObject tempEffectPrefab, float effectRadius, bool active, string childLocatorOverride = "")
		{
			bool flag = tempEffect != null;
			if (flag == active)
			{
				return;
			}
			if (active)
			{
				if (flag)
				{
					return;
				}
				if ((bool)tempEffectPrefab)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(tempEffectPrefab, corePosition, UnityEngine.Quaternion.identity);
					tempEffect = gameObject.GetComponent<TemporaryVisualEffect>();
					tempEffect.parentTransform = coreTransform;
					tempEffect.visualState = TemporaryVisualEffect.VisualState.Enter;
					tempEffect.healthComponent = healthComponent;
					tempEffect.radius = effectRadius;
					LocalCameraEffect component = gameObject.GetComponent<LocalCameraEffect>();
					if ((bool)component)
					{
						component.targetCharacter = base.gameObject;
					}
					if (string.IsNullOrEmpty(childLocatorOverride))
					{
						return;
					}
					ChildLocator childLocator = modelLocator?.modelTransform?.GetComponent<ChildLocator>();
					if ((bool)childLocator)
					{
						Transform transform = childLocator.FindChild(childLocatorOverride);
						if ((bool)transform)
						{
							tempEffect.parentTransform = transform;
						}
					}
				}
				else
				{
					UnityEngine.Debug.LogError("Can't instantiate null temporary visual effect");
				}
			}
			else if ((bool)tempEffect)
			{
				tempEffect.visualState = TemporaryVisualEffect.VisualState.Exit;
			}
		}

		public VisibilityLevel GetVisibilityLevel(CharacterBody observer)
		{
			return GetVisibilityLevel(observer ? observer.teamComponent.teamIndex : TeamIndex.None);
		}

		public VisibilityLevel GetVisibilityLevel(TeamIndex observerTeam)
		{
			if (!hasCloakBuff)
			{
				return VisibilityLevel.Visible;
			}
			if (teamComponent.teamIndex != observerTeam)
			{
				return VisibilityLevel.Cloaked;
			}
			return VisibilityLevel.Revealed;
		}

		public void AddSpreadBloom(float value)
		{
			spreadBloomInternal = Mathf.Min(spreadBloomInternal + value, 1f);
		}

		public void SetSpreadBloom(float value, bool canOnlyIncreaseBloom = true)
		{
			if (canOnlyIncreaseBloom)
			{
				spreadBloomInternal = Mathf.Clamp(value, spreadBloomInternal, 1f);
			}
			else
			{
				spreadBloomInternal = Mathf.Min(value, 1f);
			}
		}

		private void UpdateSpreadBloom(float dt)
		{
			float num = 1f / spreadBloomDecayTime;
			spreadBloomInternal = Mathf.Max(spreadBloomInternal - num * dt, 0f);
		}

		[Client]
		public void SendConstructTurret(CharacterBody builder, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, MasterCatalog.MasterIndex masterIndex)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.CharacterBody::SendConstructTurret(RoR2.CharacterBody,UnityEngine.Vector3,UnityEngine.Quaternion,RoR2.MasterCatalog/MasterIndex)' called on server");
				return;
			}
			ConstructTurretMessage msg = new ConstructTurretMessage
			{
				builder = builder.gameObject,
				position = position,
				rotation = rotation,
				turretMasterIndex = masterIndex
			};
			ClientScene.readyConnection.Send(62, msg);
		}

		[NetworkMessageHandler(msgType = 62, server = true)]
		private static void HandleConstructTurret(NetworkMessage netMsg)
		{
			ConstructTurretMessage constructTurretMessage = netMsg.ReadMessage<ConstructTurretMessage>();
			if (!constructTurretMessage.builder)
			{
				return;
			}
			CharacterBody component = constructTurretMessage.builder.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				CharacterMaster characterMaster = component.master;
				if ((bool)characterMaster)
				{
					CharacterMaster characterMaster2 = new MasterSummon
					{
						masterPrefab = MasterCatalog.GetMasterPrefab(constructTurretMessage.turretMasterIndex),
						position = constructTurretMessage.position,
						rotation = constructTurretMessage.rotation,
						summonerBodyObject = component.gameObject,
						ignoreTeamMemberLimit = true,
						inventoryToCopy = characterMaster.inventory
					}.Perform();
					Deployable deployable = characterMaster2.gameObject.AddComponent<Deployable>();
					deployable.onUndeploy = new UnityEvent();
					deployable.onUndeploy.AddListener(characterMaster2.TrueKill);
					characterMaster.AddDeployable(deployable, DeployableSlot.EngiTurret);
				}
			}
		}

		public void AddIncreasedDamageMultiKillTime()
		{
			increasedDamageKillTimer = 5f;
		}

		[Server]
		public void AddMultiKill(int kills)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::AddMultiKill(System.Int32)' called on client");
				return;
			}
			multiKillTimer = 1f;
			multiKillCount += kills;
			int num = (inventory ? inventory.GetItemCount(RoR2Content.Items.WarCryOnMultiKill) : 0);
			if (num > 0 && multiKillCount >= 4)
			{
				AddTimedBuff(RoR2Content.Buffs.WarCryBuff, 2f + 4f * (float)num);
			}
			increasedDamageKillTimer = 5f;
			increasedDamageKillCount += kills;
			increasedDamageKillCountBuff += kills;
			if ((((bool)inventory && inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill) != 0) ? 1 : 0) > (false ? 1 : 0))
			{
				if (increasedDamageKillCountBuff >= 5)
				{
					AddBuff(DLC2Content.Buffs.IncreaseDamageBuff);
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/IncreaseDamageOnMultiKillVFX"), new EffectData
					{
						origin = base.gameObject.transform.position
					}, transmit: true);
					increasedDamageKillCountBuff = 0;
				}
				if (increasedDamageKillCount > oldKillcount)
				{
					oldKillcount = increasedDamageKillCount;
				}
			}
		}

		[Server]
		private void UpdateMultiKill(float deltaTime)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateMultiKill(System.Single)' called on client");
				return;
			}
			multiKillTimer -= deltaTime;
			if (multiKillTimer <= 0f)
			{
				multiKillTimer = 0f;
				multiKillCount = 0;
			}
			increasedDamageKillTimer -= deltaTime;
			if (increasedDamageKillTimer <= 0f)
			{
				increasedDamageKillTimer = 0f;
				increasedDamageKillCount = 0;
				increasedDamageKillCountBuff = 0;
				oldKillcount = 0;
				oldComboMeter = 0;
				if (HasBuff(DLC2Content.Buffs.IncreaseDamageBuff))
				{
					RemoveBuff(DLC2Content.Buffs.IncreaseDamageBuff);
				}
			}
		}

		public void AddIncreasePrimaryDamageStack()
		{
			int buffCount = GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff);
			int itemCount = inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage);
			int num = 4 + itemCount;
			if (buffCount < num)
			{
				AddBuff(DLC2Content.Buffs.IncreasePrimaryDamageBuff);
			}
			buffCount = GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff);
			TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.IncreasePrimaryDamage.itemIndex, buffCount));
			float num2 = baseDamage + levelDamage * (level - 1f);
			luminousShotDamage = num2 * (1.25f + 0.25f * (float)itemCount) * (float)buffCount;
		}

		public void IncreasePrimaryDamageReset()
		{
			if (GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0)
			{
				SetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff.buffIndex, 0);
				TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.IncreasePrimaryDamage.itemIndex, 0f));
			}
			luminousShotReady = false;
		}

		[Server]
		private void UpdateDelayedDamage(float deltaTime)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateDelayedDamage(System.Single)' called on client");
				return;
			}
			int num = (inventory ? inventory.GetItemCount(DLC2Content.Items.DelayedDamage) : 0);
			if (num > 0)
			{
				int buffCount = GetBuffCount(DLC2Content.Buffs.DelayedDamageBuff);
				if (oldDelayedDamageCount < num)
				{
					int num2 = num - oldDelayedDamageCount;
					for (int i = 0; i < num2; i++)
					{
						AddBuff(DLC2Content.Buffs.DelayedDamageBuff);
					}
					oldDelayedDamageCount = num;
				}
				else if (oldDelayedDamageCount > num)
				{
					oldDelayedDamageCount = num;
				}
				if (buffCount < num)
				{
					delayedDamageRefreshTime -= deltaTime;
					if (delayedDamageRefreshTime <= 0f)
					{
						AddBuff(DLC2Content.Buffs.DelayedDamageBuff);
						delayedDamageRefreshTime = 10f;
					}
				}
			}
			else
			{
				delayedDamageRefreshTime = 10f;
				oldDelayedDamageCount = 0;
				RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff);
				RemoveBuff(DLC2Content.Buffs.DelayedDamageDebuff);
				RemoveOldestTimedBuff(DLC2Content.Buffs.DelayedDamageDebuff);
			}
		}

		public void SpawnDelayedDamageEffect()
		{
			if (NetworkServer.active)
			{
				ServerSpawnDelayedDamageEffect();
			}
			else
			{
				CallCmdSpawnDelayedDamageEffect();
			}
		}

		[Server]
		private void ServerSpawnDelayedDamageEffect()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::ServerSpawnDelayedDamageEffect()' called on client");
			}
			else
			{
				UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/DelayedDamageIndicator"), mainHurtBox ? mainHurtBox.transform.position : transform.position, UnityEngine.Quaternion.identity, mainHurtBox ? mainHurtBox.transform : transform);
			}
		}

		[Command]
		private void CmdSpawnDelayedDamageEffect()
		{
			ServerSpawnDelayedDamageEffect();
		}

		public void SecondHalfOfDelayedDamage(DamageInfo halfDamage)
		{
			RemoveBuff(DLC2Content.Buffs.DelayedDamageBuff);
			AddBuff(DLC2Content.Buffs.DelayedDamageDebuff);
			TransmitItemBehavior(new NetworkItemBehaviorData(DLC2Content.Items.DelayedDamage.itemIndex, 0f));
			DelayedDamageInfo delayedDamageInfo = new DelayedDamageInfo();
			delayedDamageInfo.halfDamage = halfDamage;
			incomingDamageList.Add(delayedDamageInfo);
			if (incomingDamageList.Count == 0)
			{
				halfDamageReady = false;
			}
			else
			{
				halfDamageReady = true;
			}
		}

		[Server]
		private void UpdateSecondHalfOfDamage(float deltaTime)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::UpdateSecondHalfOfDamage(System.Single)' called on client");
			}
			else
			{
				if (!halfDamageReady)
				{
					return;
				}
				for (int i = 0; i < incomingDamageList.Count; i++)
				{
					DelayedDamageInfo delayedDamageInfo = incomingDamageList[i];
					DamageInfo halfDamage = delayedDamageInfo.halfDamage;
					halfDamage.position = GetBody().corePosition;
					if (protectFromOneShot)
					{
						halfDamage.damageType = DamageType.NonLethal;
					}
					delayedDamageInfo.timeUntilDamage -= deltaTime;
					if (delayedDamageInfo.timeUntilDamage <= 0f)
					{
						Util.PlaySound("Play_item_proc_delayedDamage_2ndHit", base.gameObject);
						healthComponent.TakeDamage(halfDamage);
						RemoveBuff(DLC2Content.Buffs.DelayedDamageDebuff);
						incomingDamageList.RemoveAt(i);
						protectFromOneShot = false;
					}
				}
			}
		}

		[ClientRpc]
		public void RpcTeleportCharacterToSafety()
		{
			if (!hasEffectiveAuthority)
			{
				return;
			}
			Transform transform = modelLocator?.modelTransform;
			if (!(transform == null))
			{
				CharacterModel component = transform.GetComponent<CharacterModel>();
				UnityEngine.Vector3 position = coreTransform.position;
				int itemCount = inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealth);
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = base.gameObject;
				blastAttack.baseDamage = damage * ((float)itemCount * 3.5f);
				blastAttack.baseForce = 2000f;
				blastAttack.bonusForce = UnityEngine.Vector3.zero;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.crit = RollCrit();
				blastAttack.damageColorIndex = DamageColorIndex.Item;
				blastAttack.damageType = DamageType.Generic;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.inflictor = base.gameObject;
				blastAttack.position = position;
				blastAttack.procChainMask = default(ProcChainMask);
				blastAttack.procCoefficient = 1f;
				blastAttack.radius = 25f;
				blastAttack.losType = BlastAttack.LoSType.None;
				blastAttack.teamIndex = TeamIndex.Player;
				blastAttack.Fire();
				EffectManager.SpawnEffect(CommonAssets.teleportOnLowHealthExplosion, new EffectData
				{
					origin = position,
					scale = 50f,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: true);
				Util.PlaySound("Play_item_proc_teleportOnLowHealth", base.gameObject);
				NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
				List<NodeGraph.NodeIndex> source = nodeGraph.FindNodesInRange(corePosition, 100f, 200f, HullMask.Human);
				nodeGraph.GetNodePosition(source.First(), out var position2);
				TeleportHelper.TeleportBody(this, position2);
				TeleportOutController.AddTPOutEffect(component, 1f, 0f, 1f);
				EffectManager.SpawnEffect(CommonAssets.teleportOnLowHealthVFX, new EffectData
				{
					origin = this.transform.position,
					rotation = UnityEngine.Quaternion.identity
				}, transmit: true);
				UnityEngine.Vector3 normalized = (position - position2).normalized;
				if ((bool)characterDirection)
				{
					characterDirection.forward = normalized;
				}
				if ((bool)master && (bool)master.playerCharacterMasterController)
				{
					master.playerCharacterMasterController.RedirectCamera(UnityEngine.Quaternion.LookRotation(normalized).eulerAngles);
				}
			}
		}

		private void prayerBeadCalculateAppliedStats(float levelStat)
		{
			if (teamComponent.teamIndex == TeamIndex.Player)
			{
				float num = (float)GetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff) * levelStat * (0.2f + 0.05f * (float)(inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp) - 1));
				if (levelStat == levelMaxHealth)
				{
					_ = inventory.beadAppliedHealth;
					inventory.beadAppliedHealth += num;
				}
				else if (levelStat == levelMaxShield)
				{
					_ = inventory.beadAppliedShield;
					inventory.beadAppliedShield += num;
				}
				else if (levelStat == levelRegen)
				{
					_ = inventory.beadAppliedRegen;
					inventory.beadAppliedRegen += num;
				}
				else if (levelStat == levelDamage)
				{
					_ = inventory.beadAppliedDamage;
					inventory.beadAppliedDamage += num;
				}
			}
		}

		[HideInInspector]
		public void runicLensUpdateVariables(float damage, UnityEngine.Vector3 position, DamageInfo damageInfo, float blastForce, float blastRadius)
		{
			runicLensPosition = position;
			runicLensImpactTime = Run.instance.time + 2f;
			runicLensMeteorReady = true;
			runicLensDamage = damage;
			runicLensDamageInfo = damageInfo;
			runicLensBlastForce = blastForce;
			runicLensBlastRadius = blastRadius;
		}

		public void detonateRunicLensMeteor()
		{
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/RunicMeteorStrikeImpact");
			Util.PlaySound("Play_item_proc_meteorAttackOnHighDamage_impact", base.gameObject);
			EffectData effectData = new EffectData
			{
				origin = runicLensPosition
			};
			EffectManager.SpawnEffect(gameObject, effectData, transmit: true);
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.inflictor = gameObject;
			blastAttack.baseDamage = runicLensDamage;
			blastAttack.baseForce = runicLensBlastForce;
			blastAttack.attackerFiltering = AttackerFiltering.Default;
			blastAttack.crit = runicLensDamageInfo.crit;
			blastAttack.attacker = runicLensDamageInfo.attacker;
			blastAttack.bonusForce = UnityEngine.Vector3.zero;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.position = runicLensPosition;
			blastAttack.procChainMask = default(ProcChainMask);
			blastAttack.procCoefficient = 0.5f;
			blastAttack.teamIndex = TeamIndex.Player;
			blastAttack.radius = runicLensBlastRadius;
			blastAttack.Fire();
		}

		public void TriggerEnemyDebuffs(DamageInfo damageInfo)
		{
			SphereSearch sphereSearch = new SphereSearch();
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.origin = base.gameObject.transform.position;
			sphereSearch.radius = 30f;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamComponent.teamIndex));
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			sphereSearch.GetHurtBoxes(list);
			sphereSearch.ClearCandidates();
			EffectManager.SpawnEffect(CommonAssets.thornExplosionEffect, new EffectData
			{
				origin = coreTransform.position,
				scale = 60f,
				rotation = UnityEngine.Quaternion.identity
			}, transmit: true);
			Util.PlaySound("Play_item_proc_triggerEnemyDebuffs", base.gameObject);
			for (int i = 0; i < list.Count; i++)
			{
				HurtBox hurtBox = list[i];
				if (!hurtBox || !hurtBox.healthComponent || !hurtBox.healthComponent.alive)
				{
					continue;
				}
				CharacterBody body = hurtBox.healthComponent.body;
				int itemCount = inventory.GetItemCount(DLC2Content.Items.TriggerEnemyDebuffs);
				int num = 1;
				if (!body.hasStackableDebuff)
				{
					DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Bleed, 3f * damageInfo.procCoefficient);
					continue;
				}
				int buffCount = body.GetBuffCount(RoR2Content.Buffs.OnFire);
				if (buffCount > 0)
				{
					float num2 = 0.5f;
					int num3 = num * itemCount;
					InflictDotInfo inflictDotInfo = default(InflictDotInfo);
					inflictDotInfo.attackerObject = damageInfo.attacker;
					inflictDotInfo.victimObject = body.gameObject;
					inflictDotInfo.totalDamage = damageInfo.damage * num2;
					inflictDotInfo.damageMultiplier = 1f;
					inflictDotInfo.dotIndex = DotController.DotIndex.Burn;
					InflictDotInfo inflictDotInfo2 = inflictDotInfo;
					for (int j = 0; j < num3; j++)
					{
						DotController.InflictDot(ref inflictDotInfo2);
					}
				}
				buffCount = body.GetBuffCount(RoR2Content.Buffs.BeetleJuice);
				if (buffCount > 0)
				{
					int newCount = buffCount + num * itemCount;
					body.SetBuffCount(RoR2Content.Buffs.BeetleJuice.buffIndex, newCount);
				}
				buffCount = body.GetBuffCount(RoR2Content.Buffs.NullifyStack);
				if (buffCount > 0)
				{
					int newCount2 = buffCount + num * itemCount;
					body.SetBuffCount(RoR2Content.Buffs.NullifyStack.buffIndex, newCount2);
				}
				buffCount = body.GetBuffCount(RoR2Content.Buffs.Bleeding);
				if (buffCount > 0)
				{
					int num4 = num * itemCount;
					for (int k = 0; k < num4; k++)
					{
						DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Bleed, 3f * damageInfo.procCoefficient);
					}
				}
				buffCount = body.GetBuffCount(RoR2Content.Buffs.SuperBleed);
				if (buffCount > 0)
				{
					int num5 = num * itemCount;
					for (int l = 0; l < num5; l++)
					{
						DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.SuperBleed, 15f * damageInfo.procCoefficient);
					}
				}
				buffCount = body.GetBuffCount(RoR2Content.Buffs.Blight);
				if (buffCount > 0)
				{
					int num6 = num * itemCount;
					for (int m = 0; m < num6; m++)
					{
						DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Blight, 5f * damageInfo.procCoefficient);
					}
				}
				buffCount = body.GetBuffCount(RoR2Content.Buffs.Overheat);
				if (buffCount > 0)
				{
					int newCount3 = buffCount + num * itemCount;
					body.SetBuffCount(RoR2Content.Buffs.Overheat.buffIndex, newCount3);
				}
				buffCount = body.GetBuffCount(RoR2Content.Buffs.PulverizeBuildup);
				if (buffCount > 0)
				{
					int newCount4 = buffCount + num * itemCount;
					body.SetBuffCount(RoR2Content.Buffs.PulverizeBuildup.buffIndex, newCount4);
				}
				buffCount = body.GetBuffCount(DLC1Content.Buffs.StrongerBurn);
				if (buffCount > 0)
				{
					int num7 = num * itemCount;
					for (int n = 0; n < num7; n++)
					{
						DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.StrongerBurn, 3f * damageInfo.procCoefficient);
					}
				}
				buffCount = body.GetBuffCount(DLC1Content.Buffs.Fracture);
				if (buffCount > 0)
				{
					int num8 = num * itemCount;
					DotController.DotDef dotDef = DotController.GetDotDef(DotController.DotIndex.Fracture);
					for (int num9 = 0; num9 < num8; num9++)
					{
						DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.Fracture, dotDef.interval);
					}
				}
				buffCount = body.GetBuffCount(DLC1Content.Buffs.PermanentDebuff);
				if (buffCount > 0)
				{
					int newCount5 = buffCount + num * itemCount;
					body.SetBuffCount(DLC1Content.Buffs.PermanentDebuff.buffIndex, newCount5);
				}
				buffCount = body.GetBuffCount(DLC2Content.Buffs.lunarruin);
				if (buffCount > 0)
				{
					int num10 = buffCount + num * itemCount;
					body.SetBuffCount(DLC2Content.Buffs.lunarruin.buffIndex, num10);
					for (int num11 = 0; num11 < num10; num11++)
					{
						DotController.InflictDot(body.gameObject, damageInfo.attacker, DotController.DotIndex.LunarRuin, 5f);
					}
				}
			}
		}

		private void IncreaseStunPierceDamage(int kills)
		{
		}

		public void ApplyTamperedHeartPassive(float heartRegen, float heartMSpeed, float heartDamage, float armor, float attackSpeed)
		{
			tamperedHeartActive = true;
			tamperedHeartRegenBonus = heartRegen;
			tamperedHeartMSpeedBonus = heartMSpeed;
			tamperedHeartDamageBonus = heartDamage;
			tamperedHeartAttackSpeedBonus = attackSpeed;
			tamperedHeartArmorBonus = armor;
		}

		public void AddFreeChestBuff()
		{
			int itemCount = inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock);
			for (int i = 0; i < itemCount; i++)
			{
				AddBuff(DLC2Content.Buffs.FreeUnlocks.buffIndex);
			}
		}

		[ClientRpc]
		public void RpcBark()
		{
			if ((bool)sfxLocator)
			{
				Util.PlaySound(sfxLocator.barkSound, base.gameObject);
			}
		}

		[Command]
		public void CmdRequestVehicleEjection()
		{
			if ((bool)currentVehicle)
			{
				currentVehicle.EjectPassenger(base.gameObject);
			}
		}

		public bool RollCrit()
		{
			if ((bool)master)
			{
				return Util.CheckRoll(crit, master);
			}
			return false;
		}

		public bool IsCullable()
		{
			if (!dontCull && Importance - TeamComponent.GetTeamAverageImportance(teamComponent) < 3 && teamComponent.teamIndex != TeamIndex.Player && !isBoss)
			{
				return TeamComponent.GetTeamMembers(TeamIndex.Monster).Count >= 10;
			}
			return false;
		}

		public bool IsActivelyCullable()
		{
			if (!isBoss)
			{
				if (!NearAnyPlayers(75f))
				{
					return !CharacterIsVisible;
				}
				return false;
			}
			return false;
		}

		public bool NearAnyPlayers(float checkRadius)
		{
			float num = checkRadius * checkRadius;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if ((bool)instance.master && (bool)instance.master.GetBody() && (transform.position - instance.master.GetBody().transform.position).sqrMagnitude < num)
				{
					return true;
				}
			}
			return false;
		}

		[ClientRpc]
		private void RpcUsePreferredInitialStateType()
		{
			if (hasEffectiveAuthority)
			{
				SetBodyStateToPreferredInitialState();
			}
		}

		public void SetBodyStateToPreferredInitialState()
		{
			if (!hasEffectiveAuthority)
			{
				if (NetworkServer.active)
				{
					CallRpcUsePreferredInitialStateType();
				}
				return;
			}
			Type stateType = preferredInitialStateType.stateType;
			if (!(stateType == null) && !(stateType == typeof(Uninitialized)))
			{
				EntityStateMachine.FindByCustomName(base.gameObject, "Body")?.SetState(EntityStateCatalog.InstantiateState(stateType));
			}
		}

		[Server]
		public void SetLoadoutServer(Loadout loadout)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterBody::SetLoadoutServer(RoR2.Loadout)' called on client");
			}
			else
			{
				skillLocator.ApplyLoadoutServer(loadout, bodyIndex);
			}
		}

		static CharacterBody()
		{
			instancesList = new List<CharacterBody>();
			readOnlyInstancesList = new ReadOnlyCollection<CharacterBody>(instancesList);
			kCmdCmdAddTimedBuff = -160178508;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdAddTimedBuff, InvokeCmdCmdAddTimedBuff);
			kCmdCmdSetInLava = 234733148;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdSetInLava, InvokeCmdCmdSetInLava);
			kCmdCmdUpdateSprint = -1006016914;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdUpdateSprint, InvokeCmdCmdUpdateSprint);
			kCmdCmdOnSkillActivated = 384138986;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdOnSkillActivated, InvokeCmdCmdOnSkillActivated);
			kCmdCmdTransmitItemBehavior = 394448000;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdTransmitItemBehavior, InvokeCmdCmdTransmitItemBehavior);
			kCmdCmdSpawnDelayedDamageEffect = 1860577938;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdSpawnDelayedDamageEffect, InvokeCmdCmdSpawnDelayedDamageEffect);
			kCmdCmdRequestVehicleEjection = 1803737791;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterBody), kCmdCmdRequestVehicleEjection, InvokeCmdCmdRequestVehicleEjection);
			kRpcRpcTransmitItemBehavior = -729896618;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcTransmitItemBehavior, InvokeRpcRpcTransmitItemBehavior);
			kRpcRpcTeleportCharacterToSafety = -245876694;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcTeleportCharacterToSafety, InvokeRpcRpcTeleportCharacterToSafety);
			kRpcRpcBark = -76716871;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcBark, InvokeRpcRpcBark);
			kRpcRpcUsePreferredInitialStateType = 638695010;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterBody), kRpcRpcUsePreferredInitialStateType, InvokeRpcRpcUsePreferredInitialStateType);
			NetworkCRC.RegisterBehaviour("CharacterBody", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdAddTimedBuff(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdAddTimedBuff called on client.");
			}
			else
			{
				((CharacterBody)obj).CmdAddTimedBuff((BuffIndex)reader.ReadInt32(), reader.ReadSingle());
			}
		}

		protected static void InvokeCmdCmdSetInLava(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetInLava called on client.");
			}
			else
			{
				((CharacterBody)obj).CmdSetInLava(reader.ReadBoolean());
			}
		}

		protected static void InvokeCmdCmdUpdateSprint(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdUpdateSprint called on client.");
			}
			else
			{
				((CharacterBody)obj).CmdUpdateSprint(reader.ReadBoolean());
			}
		}

		protected static void InvokeCmdCmdOnSkillActivated(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdOnSkillActivated called on client.");
			}
			else
			{
				((CharacterBody)obj).CmdOnSkillActivated((sbyte)reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeCmdCmdTransmitItemBehavior(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdTransmitItemBehavior called on client.");
			}
			else
			{
				((CharacterBody)obj).CmdTransmitItemBehavior(GeneratedNetworkCode._ReadNetworkItemBehaviorData_CharacterBody(reader));
			}
		}

		protected static void InvokeCmdCmdSpawnDelayedDamageEffect(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSpawnDelayedDamageEffect called on client.");
			}
			else
			{
				((CharacterBody)obj).CmdSpawnDelayedDamageEffect();
			}
		}

		protected static void InvokeCmdCmdRequestVehicleEjection(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdRequestVehicleEjection called on client.");
			}
			else
			{
				((CharacterBody)obj).CmdRequestVehicleEjection();
			}
		}

		public void CallCmdAddTimedBuff(BuffIndex buffType, float duration)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdAddTimedBuff called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdAddTimedBuff(buffType, duration);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdAddTimedBuff);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)buffType);
			networkWriter.Write(duration);
			SendCommandInternal(networkWriter, 0, "CmdAddTimedBuff");
		}

		public void CallCmdSetInLava(bool b)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetInLava called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetInLava(b);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetInLava);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(b);
			SendCommandInternal(networkWriter, 0, "CmdSetInLava");
		}

		public void CallCmdUpdateSprint(bool newIsSprinting)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdUpdateSprint called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdUpdateSprint(newIsSprinting);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdUpdateSprint);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(newIsSprinting);
			SendCommandInternal(networkWriter, 0, "CmdUpdateSprint");
		}

		public void CallCmdOnSkillActivated(sbyte skillIndex)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdOnSkillActivated called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdOnSkillActivated(skillIndex);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdOnSkillActivated);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)skillIndex);
			SendCommandInternal(networkWriter, 0, "CmdOnSkillActivated");
		}

		public void CallCmdTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdTransmitItemBehavior called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdTransmitItemBehavior(itemBehaviorData);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdTransmitItemBehavior);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteNetworkItemBehaviorData_CharacterBody(networkWriter, itemBehaviorData);
			SendCommandInternal(networkWriter, 0, "CmdTransmitItemBehavior");
		}

		public void CallCmdSpawnDelayedDamageEffect()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSpawnDelayedDamageEffect called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSpawnDelayedDamageEffect();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSpawnDelayedDamageEffect);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdSpawnDelayedDamageEffect");
		}

		public void CallCmdRequestVehicleEjection()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdRequestVehicleEjection called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdRequestVehicleEjection();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdRequestVehicleEjection);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdRequestVehicleEjection");
		}

		protected static void InvokeRpcRpcTransmitItemBehavior(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcTransmitItemBehavior called on server.");
			}
			else
			{
				((CharacterBody)obj).RpcTransmitItemBehavior(GeneratedNetworkCode._ReadNetworkItemBehaviorData_CharacterBody(reader));
			}
		}

		protected static void InvokeRpcRpcTeleportCharacterToSafety(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcTeleportCharacterToSafety called on server.");
			}
			else
			{
				((CharacterBody)obj).RpcTeleportCharacterToSafety();
			}
		}

		protected static void InvokeRpcRpcBark(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcBark called on server.");
			}
			else
			{
				((CharacterBody)obj).RpcBark();
			}
		}

		protected static void InvokeRpcRpcUsePreferredInitialStateType(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcUsePreferredInitialStateType called on server.");
			}
			else
			{
				((CharacterBody)obj).RpcUsePreferredInitialStateType();
			}
		}

		public void CallRpcTransmitItemBehavior(NetworkItemBehaviorData itemBehaviorData)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcTransmitItemBehavior called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcTransmitItemBehavior);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteNetworkItemBehaviorData_CharacterBody(networkWriter, itemBehaviorData);
			SendRPCInternal(networkWriter, 1, "RpcTransmitItemBehavior");
		}

		public void CallRpcTeleportCharacterToSafety()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcTeleportCharacterToSafety called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcTeleportCharacterToSafety);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcTeleportCharacterToSafety");
		}

		public void CallRpcBark()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcBark called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcBark);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcBark");
		}

		public void CallRpcUsePreferredInitialStateType()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcUsePreferredInitialStateType called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcUsePreferredInitialStateType);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcUsePreferredInitialStateType");
		}

		public override void PreStartClient()
		{
		}
	}
	public class CharacterDeathBehavior : MonoBehaviour
	{
		[Tooltip("The state machine to set the state of when this character is killed.")]
		public EntityStateMachine deathStateMachine;

		[Tooltip("The state to enter when this character is killed.")]
		public SerializableEntityStateType deathState;

		[Tooltip("The state machine(s) to set to idle when this character is killed.")]
		public EntityStateMachine[] idleStateMachine;

		[Tooltip("Be default, dead characters are set to the debris layer. Check this to bypass that.")]
		[SerializeField]
		private bool bypassDeathLayerChange;

		public void OnDeath()
		{
			if (Util.HasEffectiveAuthority(base.gameObject))
			{
				if ((bool)deathStateMachine)
				{
					deathStateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref deathState));
				}
				EntityStateMachine[] array = idleStateMachine;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetNextState(new EntityStates.Idle());
				}
			}
			if (!bypassDeathLayerChange)
			{
				base.gameObject.layer = LayerIndex.debris.intVal;
				CharacterMotor component = GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					component.Motor.RebuildCollidableLayers();
				}
			}
			ILifeBehavior[] components = GetComponents<ILifeBehavior>();
			for (int i = 0; i < components.Length; i++)
			{
				components[i].OnDeathStart();
			}
			ModelLocator component2 = GetComponent<ModelLocator>();
			if (!component2)
			{
				return;
			}
			Transform modelTransform = component2.modelTransform;
			if ((bool)modelTransform)
			{
				components = modelTransform.GetComponents<ILifeBehavior>();
				for (int i = 0; i < components.Length; i++)
				{
					components[i].OnDeathStart();
				}
			}
		}
	}
	public class CharacterDirection : NetworkBehaviour, ILifeBehavior
	{
		private struct TurnAnimatorParamsSet
		{
			public float angleMin;

			public float angleMax;

			public bool turnRight45;

			public bool turnRight90;

			public bool turnRight135;

			public bool turnLeft45;

			public bool turnLeft90;

			public bool turnLeft135;

			private static readonly int turnRight45ParamHash = Animator.StringToHash("turnRight45");

			private static readonly int turnRight90ParamHash = Animator.StringToHash("turnRight90");

			private static readonly int turnRight135ParamHash = Animator.StringToHash("turnRight135");

			private static readonly int turnLeft45ParamHash = Animator.StringToHash("turnLeft45");

			private static readonly int turnLeft90ParamHash = Animator.StringToHash("turnLeft90");

			private static readonly int turnLeft135ParamHash = Animator.StringToHash("turnLeft135");

			public void Apply(Animator animator)
			{
				animator.SetBool(turnRight45ParamHash, turnRight45);
				animator.SetBool(turnRight90ParamHash, turnRight90);
				animator.SetBool(turnRight135ParamHash, turnRight135);
				animator.SetBool(turnLeft45ParamHash, turnLeft45);
				animator.SetBool(turnLeft90ParamHash, turnLeft90);
				animator.SetBool(turnLeft135ParamHash, turnLeft135);
			}
		}

		[HideInInspector]
		public UnityEngine.Vector3 moveVector;

		[Tooltip("The transform to rotate.")]
		public Transform targetTransform;

		[Tooltip("The transform to take the rotation from for animator purposes. Commonly the root node.")]
		public Transform overrideAnimatorForwardTransform;

		public RootMotionAccumulator rootMotionAccumulator;

		public Animator modelAnimator;

		[Tooltip("The character direction is set by root rotation, rather than moveVector.")]
		public bool driveFromRootRotation;

		[Tooltip("The maximum turn rate in degrees/second.")]
		public float turnSpeed = 360f;

		[SerializeField]
		private string turnSoundName;

		private int previousParamsIndex = -1;

		private float yRotationVelocity;

		private float _yaw;

		private UnityEngine.Vector3 targetVector = UnityEngine.Vector3.zero;

		private const float offset = 22.5f;

		private static readonly TurnAnimatorParamsSet[] turnAnimatorParamsSets = new TurnAnimatorParamsSet[7]
		{
			new TurnAnimatorParamsSet
			{
				angleMin = -180f,
				angleMax = -112.5f,
				turnRight45 = false,
				turnRight90 = false,
				turnRight135 = false,
				turnLeft45 = false,
				turnLeft90 = false,
				turnLeft135 = true
			},
			new TurnAnimatorParamsSet
			{
				angleMin = -112.5f,
				angleMax = -67.5f,
				turnRight45 = false,
				turnRight90 = false,
				turnRight135 = false,
				turnLeft45 = false,
				turnLeft90 = true,
				turnLeft135 = false
			},
			new TurnAnimatorParamsSet
			{
				angleMin = -67.5f,
				angleMax = -22.5f,
				turnRight45 = false,
				turnRight90 = false,
				turnRight135 = false,
				turnLeft45 = true,
				turnLeft90 = false,
				turnLeft135 = false
			},
			new TurnAnimatorParamsSet
			{
				turnRight45 = false,
				turnRight90 = false,
				turnRight135 = false,
				turnLeft45 = false,
				turnLeft90 = false,
				turnLeft135 = false
			},
			new TurnAnimatorParamsSet
			{
				angleMin = 22.5f,
				angleMax = 67.5f,
				turnRight45 = true,
				turnRight90 = false,
				turnRight135 = false,
				turnLeft45 = false,
				turnLeft90 = false,
				turnLeft135 = false
			},
			new TurnAnimatorParamsSet
			{
				angleMin = 67.5f,
				angleMax = 112.5f,
				turnRight45 = false,
				turnRight90 = true,
				turnRight135 = false,
				turnLeft45 = false,
				turnLeft90 = false,
				turnLeft135 = false
			},
			new TurnAnimatorParamsSet
			{
				angleMin = 112.5f,
				angleMax = 180f,
				turnRight45 = false,
				turnRight90 = false,
				turnRight135 = true,
				turnLeft45 = false,
				turnLeft90 = false,
				turnLeft135 = false
			}
		};

		private static readonly int paramsMidIndex = turnAnimatorParamsSets.Length >> 1;

		public float yaw
		{
			get
			{
				return _yaw;
			}
			set
			{
				_yaw = value;
				if ((bool)targetTransform)
				{
					targetTransform.rotation = UnityEngine.Quaternion.Euler(0f, _yaw, 0f);
				}
			}
		}

		public UnityEngine.Vector3 animatorForward
		{
			get
			{
				if (!overrideAnimatorForwardTransform)
				{
					return forward;
				}
				float y = overrideAnimatorForwardTransform.eulerAngles.y;
				return UnityEngine.Quaternion.Euler(0f, y, 0f) * UnityEngine.Vector3.forward;
			}
		}

		public UnityEngine.Vector3 forward
		{
			get
			{
				return UnityEngine.Quaternion.Euler(0f, yaw, 0f) * UnityEngine.Vector3.forward;
			}
			set
			{
				value.y = 0f;
				yaw = Util.QuaternionSafeLookRotation(value, UnityEngine.Vector3.up).eulerAngles.y;
			}
		}

		public bool hasEffectiveAuthority { get; private set; }

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
		}

		public override void OnStartAuthority()
		{
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			UpdateAuthority();
		}

		private void Start()
		{
			UpdateAuthority();
			ModelLocator component = GetComponent<ModelLocator>();
			if ((bool)component)
			{
				modelAnimator = component.modelTransform.GetComponent<Animator>();
			}
		}

		private void Update()
		{
			Simulate(Time.deltaTime);
		}

		public void OnDeathStart()
		{
			base.enabled = false;
		}

		private static int PickIndex(float angle)
		{
			float num = Mathf.Sign(angle);
			int num2 = Mathf.CeilToInt((angle * num - 22.5f) * (1f / 45f));
			return Mathf.Clamp(paramsMidIndex + num2 * (int)num, 0, turnAnimatorParamsSets.Length - 1);
		}

		private void Simulate(float deltaTime)
		{
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, yaw, 0f);
			if (!hasEffectiveAuthority)
			{
				return;
			}
			if (driveFromRootRotation)
			{
				UnityEngine.Quaternion quaternion2 = rootMotionAccumulator.ExtractRootRotation();
				if ((bool)targetTransform)
				{
					targetTransform.rotation = quaternion * quaternion2;
					float y = targetTransform.rotation.eulerAngles.y;
					yaw = y;
					float angle = 0f;
					if (moveVector.sqrMagnitude > 0f)
					{
						angle = Util.AngleSigned(UnityEngine.Vector3.ProjectOnPlane(moveVector, UnityEngine.Vector3.up), targetTransform.forward, -UnityEngine.Vector3.up);
					}
					int num = PickIndex(angle);
					if (turnSoundName != null && num != previousParamsIndex)
					{
						Util.PlaySound(turnSoundName, base.gameObject);
					}
					previousParamsIndex = num;
					turnAnimatorParamsSets[num].Apply(modelAnimator);
				}
			}
			targetVector = moveVector;
			targetVector.y = 0f;
			if (targetVector != UnityEngine.Vector3.zero && deltaTime != 0f)
			{
				targetVector.Normalize();
				UnityEngine.Quaternion quaternion3 = Util.QuaternionSafeLookRotation(targetVector, UnityEngine.Vector3.up);
				float y2 = Mathf.SmoothDampAngle(yaw, quaternion3.eulerAngles.y, ref yRotationVelocity, 360f / turnSpeed * 0.25f, float.PositiveInfinity, deltaTime);
				quaternion = UnityEngine.Quaternion.Euler(0f, y2, 0f);
				yaw = y2;
			}
			if ((bool)targetTransform)
			{
				targetTransform.rotation = quaternion;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class CharacterEmoteDefinitions : MonoBehaviour
	{
		[Serializable]
		public struct EmoteDef
		{
			public string name;

			public string displayName;

			public EntityStateMachine targetStateMachine;

			public SerializableEntityStateType state;
		}

		public EmoteDef[] emoteDefinitions;

		public int FindEmoteIndex(string name)
		{
			for (int i = 0; i < emoteDefinitions.Length; i++)
			{
				if (emoteDefinitions[i].name == name)
				{
					return i;
				}
			}
			return -1;
		}
	}
	[RequireComponent(typeof(MinionOwnership))]
	[RequireComponent(typeof(Inventory))]
	[DisallowMultipleComponent]
	public class CharacterMaster : NetworkBehaviour
	{
		private static class CommonAssets
		{
			public static GameObject goldOnStageStartEffect;

			public static void Resolve()
			{
				AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/GoldOnStageStartCoinGain");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					goldOnStageStartEffect = x.Result;
				};
			}
		}

		public enum SEEKER_REVIVE_STATUS
		{
			UNUSED,
			USED,
			BURNED
		}

		[Tooltip("This is assigned to the prefab automatically by MasterCatalog at runtime. Do not set this value manually.")]
		[HideInInspector]
		[SerializeField]
		private int _masterIndex;

		[Tooltip("The prefab of this character's body.")]
		public GameObject bodyPrefab;

		[Tooltip("Whether or not to spawn the body at the position of this manager object as soon as Start runs.")]
		public bool spawnOnStart;

		[Tooltip("The team of the body.")]
		[FormerlySerializedAs("teamIndex")]
		[SerializeField]
		private TeamIndex _teamIndex;

		public UnityEvent onBodyDeath;

		[Tooltip("Whether or not to destroy this master when the body dies.")]
		public bool destroyOnBodyDeath = true;

		private static List<CharacterMaster> instancesList;

		private static ReadOnlyCollection<CharacterMaster> _readOnlyInstancesList;

		private BaseAI[] aiComponents;

		private const uint bodyDirtyBit = 1u;

		private const uint moneyDirtyBit = 2u;

		private const uint survivalTimeDirtyBit = 4u;

		private const uint teamDirtyBit = 8u;

		private const uint loadoutDirtyBit = 16u;

		private const uint miscFlagsDirtyBit = 32u;

		private const uint voidCoinsDirtyBit = 64u;

		private const uint allDirtyBits = 127u;

		public readonly Loadout loadout = new Loadout();

		private NetworkInstanceId _bodyInstanceId = NetworkInstanceId.Invalid;

		private GameObject resolvedBodyInstance;

		private bool bodyResolved;

		private ulong beadExperience;

		private int numberOfBeadStatsGained;

		private uint oldBeadLevel = 1u;

		private uint newBeadLevel;

		private ulong beadXPNeededForCurrentLevel = 20uL;

		private uint _money;

		public uint lssMoneyExp;

		private uint _voidCoins;

		public bool isBoss;

		private Xoroshiro128Plus cloverVoidRng;

		[NonSerialized]
		private List<DeployableInfo> deployablesList;

		public bool preventGameOver = true;

		private UnityEngine.Vector3 deathAimVector = UnityEngine.Vector3.zero;

		private bool killedByUnsafeArea;

		private const float respawnDelayDuration = 2f;

		private float _internalSurvivalTime;

		private BodyIndex killerBodyIndex = BodyIndex.None;

		private bool preventRespawnUntilNextStageServer;

		private SEEKER_REVIVE_STATUS seekerUsedRevive;

		[HideInInspector]
		public GameObject devotionInventoryPrefab;

		[HideInInspector]
		public DevotionInventoryController devotionInventoryUpdaterRef;

		[HideInInspector]
		public ItemIndex devotionItem;

		[HideInInspector]
		public int devotedEvolutionTracker;

		[HideInInspector]
		public bool isDevotedMinion;

		[HideInInspector]
		public Interactor summonerRef;

		private bool godMode;

		private uint lostBodyToDeathFlag = 1u;

		private uint _miscFlags;

		private static int kRpcRpcOnPlayerBodyDamaged;

		private static int kCmdCmdRespawn;

		private static int kRpcRpcSetSeekerRevive;

		public MasterCatalog.MasterIndex masterIndex
		{
			get
			{
				return (MasterCatalog.MasterIndex)_masterIndex;
			}
			set
			{
				_masterIndex = (int)value;
			}
		}

		public NetworkIdentity networkIdentity { get; private set; }

		public bool hasEffectiveAuthority { get; private set; }

		public TeamIndex teamIndex
		{
			get
			{
				return _teamIndex;
			}
			set
			{
				if (_teamIndex != value)
				{
					_teamIndex = value;
					if (NetworkServer.active)
					{
						SetDirtyBit(8u);
					}
				}
			}
		}

		public static ReadOnlyCollection<CharacterMaster> readOnlyInstancesList => _readOnlyInstancesList;

		public Inventory inventory { get; private set; }

		public PlayerCharacterMasterController playerCharacterMasterController { get; private set; }

		public PlayerStatsComponent playerStatsComponent { get; private set; }

		public MinionOwnership minionOwnership { get; private set; }

		private NetworkInstanceId bodyInstanceId
		{
			get
			{
				return _bodyInstanceId;
			}
			set
			{
				if (!(value == _bodyInstanceId))
				{
					SetDirtyBit(1u);
					_bodyInstanceId = value;
				}
			}
		}

		public BodyIndex backupBodyIndex { get; private set; }

		private GameObject bodyInstanceObject
		{
			get
			{
				if (!bodyResolved)
				{
					resolvedBodyInstance = Util.FindNetworkObject(bodyInstanceId);
					if ((bool)resolvedBodyInstance)
					{
						bodyResolved = true;
						StoreBackupBodyIndex();
					}
				}
				return resolvedBodyInstance;
			}
			set
			{
				NetworkInstanceId invalid = NetworkInstanceId.Invalid;
				resolvedBodyInstance = null;
				bodyResolved = true;
				if ((bool)value)
				{
					NetworkIdentity component = value.GetComponent<NetworkIdentity>();
					if ((bool)component)
					{
						invalid = component.netId;
						resolvedBodyInstance = value;
						StoreBackupBodyIndex();
					}
				}
				bodyInstanceId = invalid;
			}
		}

		public uint money
		{
			get
			{
				return _money;
			}
			set
			{
				if (value != _money)
				{
					SetDirtyBit(2u);
					_money = value;
				}
			}
		}

		public uint voidCoins
		{
			get
			{
				return _voidCoins;
			}
			set
			{
				if (value != _voidCoins)
				{
					SetDirtyBit(64u);
					_voidCoins = value;
				}
			}
		}

		public float luck { get; set; }

		public bool hasBody => bodyInstanceObject;

		public UnityEngine.Vector3 deathFootPosition { get; private set; } = UnityEngine.Vector3.zero;


		private float internalSurvivalTime
		{
			get
			{
				return _internalSurvivalTime;
			}
			set
			{
				if (value != _internalSurvivalTime)
				{
					SetDirtyBit(4u);
					_internalSurvivalTime = value;
				}
			}
		}

		public float currentLifeStopwatch
		{
			get
			{
				if (internalSurvivalTime <= 0f)
				{
					return 0f - internalSurvivalTime;
				}
				if ((bool)Run.instance)
				{
					return Run.instance.GetRunStopwatch() - internalSurvivalTime;
				}
				return 0f;
			}
		}

		private uint miscFlags
		{
			get
			{
				return _miscFlags;
			}
			set
			{
				if (value != _miscFlags)
				{
					_miscFlags = value;
					if (NetworkServer.active)
					{
						SetDirtyBit(32u);
					}
				}
			}
		}

		public bool lostBodyToDeath
		{
			get
			{
				return (miscFlags & lostBodyToDeathFlag) != 0;
			}
			private set
			{
				if (value)
				{
					miscFlags |= lostBodyToDeathFlag;
				}
				else
				{
					miscFlags &= ~lostBodyToDeathFlag;
				}
			}
		}

		public static event Action<CharacterMaster> onStartGlobal;

		public static event Action<CharacterMaster> onCharacterMasterDiscovered;

		public static event Action<CharacterMaster> onCharacterMasterLost;

		public event Action<CharacterBody> onBodyStart;

		public event Action<CharacterBody> onBodyDestroyed;

		public event Action<PlayerCharacterMasterController> onPlayerBodyDamaged;

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity);
		}

		public override void OnStartAuthority()
		{
			base.OnStartAuthority();
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			UpdateAuthority();
			base.OnStopAuthority();
		}

		[Server]
		public void SetLoadoutServer(Loadout newLoadout)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::SetLoadoutServer(RoR2.Loadout)' called on client");
				return;
			}
			newLoadout.Copy(loadout);
			SetDirtyBit(16u);
		}

		private void StoreBackupBodyIndex()
		{
			if ((bool)resolvedBodyInstance)
			{
				CharacterBody component = resolvedBodyInstance.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					backupBodyIndex = component.bodyIndex;
				}
			}
		}

		private void OnSyncBodyInstanceId(NetworkInstanceId value)
		{
			resolvedBodyInstance = null;
			bodyResolved = value == NetworkInstanceId.Invalid;
			_bodyInstanceId = value;
		}

		public void TrackBeadExperience(ulong amount)
		{
			if (!inventory)
			{
				return;
			}
			int itemCount = inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp);
			if (itemCount <= 0)
			{
				return;
			}
			ulong num = amount * (ulong)(0.25f * (float)(itemCount - 1));
			ulong num2 = amount * (ulong)(0.025f * (float)numberOfBeadStatsGained);
			if (num2 >= num + amount)
			{
				num2 = (ulong)(0.8f * (float)(num + amount));
			}
			beadExperience += amount + num - num2;
			newBeadLevel = TeamManager.instance.FindLevelForBeadExperience(beadExperience);
			if (beadExperience >= beadXPNeededForCurrentLevel)
			{
				CharacterBody body = GetBody();
				body.SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, (int)oldBeadLevel);
				float num3 = body.GetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff);
				float num4 = 1f;
				switch (body.hullClassification)
				{
				case HullClassification.Golem:
					num4 = 2f;
					break;
				case HullClassification.BeetleQueen:
					num4 = 3f;
					break;
				}
				num4 += num3 / (num3 * 0.25f + 1f);
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ExtraStatsOnLevelUpEffect"), new EffectData
				{
					origin = body.footPosition,
					scale = num4
				}, transmit: true);
				Util.PlaySound("Play_item_proc_extraStatsOnLevelUp", body.gameObject);
				oldBeadLevel = newBeadLevel;
				beadXPNeededForCurrentLevel = TeamManager.GetExperienceForLevel(oldBeadLevel + 1);
			}
		}

		public void OnBeadReset(bool gainedStats)
		{
			if (gainedStats)
			{
				numberOfBeadStatsGained += (int)oldBeadLevel;
			}
			oldBeadLevel = 1u;
			beadExperience = 0uL;
			beadXPNeededForCurrentLevel = 20uL;
		}

		[Server]
		public void GiveExperience(ulong amount)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::GiveExperience(System.UInt64)' called on client");
			}
			else
			{
				TeamManager.instance.GiveTeamExperience(teamIndex, amount);
			}
		}

		public void GiveMoney(uint amount)
		{
			int itemCount = inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock);
			int num = TeamManager.LongstandingSolitudesInParty();
			if (itemCount > 0)
			{
				double num2 = TeamManager.GetExperienceForLevel((uint)GetBody().level + 1);
				uint difficultyScaledCost = (uint)Run.instance.GetDifficultyScaledCost(25, Run.instance.difficultyCoefficient);
				lssMoneyExp += amount;
				if ((float)lssMoneyExp >= (float)(difficultyScaledCost * num) + GetBody().level)
				{
					GiveExperience((ulong)(num2 / (double)(10 + (itemCount - 1) * 15)));
					lssMoneyExp = 0u;
				}
			}
			else
			{
				money += amount;
				StatManager.OnGoldCollected(this, amount);
			}
		}

		public void GiveVoidCoins(uint amount)
		{
			voidCoins += amount;
		}

		public int GetDeployableSameSlotLimit(DeployableSlot slot)
		{
			int result = 0;
			int num = 1;
			if (RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.swarmsArtifactDef))
			{
				num = 2;
			}
			switch (slot)
			{
			case DeployableSlot.EngiMine:
				result = 4;
				if ((bool)bodyInstanceObject)
				{
					result = bodyInstanceObject.GetComponent<SkillLocator>().secondary.maxStock;
				}
				break;
			case DeployableSlot.EngiTurret:
				result = ((inventory.GetItemCount(DLC1Content.Items.EquipmentMagazineVoid) <= 0) ? 2 : 3);
				break;
			case DeployableSlot.BeetleGuardAlly:
				result = inventory.GetItemCount(RoR2Content.Items.BeetleGland) * num;
				break;
			case DeployableSlot.EngiBubbleShield:
				result = 1;
				break;
			case DeployableSlot.LoaderPylon:
				result = 3;
				break;
			case DeployableSlot.EngiSpiderMine:
				result = 4;
				if ((bool)bodyInstanceObject)
				{
					result = bodyInstanceObject.GetComponent<SkillLocator>().secondary.maxStock;
				}
				break;
			case DeployableSlot.RoboBallMini:
				result = 3;
				break;
			case DeployableSlot.ParentPodAlly:
				result = inventory.GetItemCount(JunkContent.Items.Incubator) * num;
				break;
			case DeployableSlot.ParentAlly:
				result = inventory.GetItemCount(JunkContent.Items.Incubator) * num;
				break;
			case DeployableSlot.PowerWard:
				result = 1;
				break;
			case DeployableSlot.CrippleWard:
				result = 5;
				break;
			case DeployableSlot.DeathProjectile:
				result = 3;
				break;
			case DeployableSlot.RoboBallRedBuddy:
			case DeployableSlot.RoboBallGreenBuddy:
				result = num;
				break;
			case DeployableSlot.GummyClone:
				result = 3;
				break;
			case DeployableSlot.LunarSunBomb:
				result = LunarSunBehavior.GetMaxProjectiles(inventory);
				break;
			case DeployableSlot.VendingMachine:
				result = 1;
				break;
			case DeployableSlot.VoidMegaCrabItem:
				result = VoidMegaCrabItemBehavior.GetMaxProjectiles(inventory);
				break;
			case DeployableSlot.DroneWeaponsDrone:
				result = 1;
				break;
			case DeployableSlot.MinorConstructOnKill:
				result = inventory.GetItemCount(DLC1Content.Items.MinorConstructOnKill) * 4;
				break;
			case DeployableSlot.CaptainSupplyDrop:
				result = 2;
				break;
			}
			return result;
		}

		[Server]
		public void AddDeployable(Deployable deployable, DeployableSlot slot)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::AddDeployable(RoR2.Deployable,RoR2.DeployableSlot)' called on client");
				return;
			}
			if ((bool)deployable.ownerMaster)
			{
				UnityEngine.Debug.LogErrorFormat("Attempted to add deployable {0} which already belongs to master {1} to master {2}.", deployable.gameObject, deployable.ownerMaster.gameObject, base.gameObject);
			}
			if (deployablesList == null)
			{
				deployablesList = new List<DeployableInfo>();
			}
			int num = 0;
			int deployableSameSlotLimit = GetDeployableSameSlotLimit(slot);
			for (int num2 = deployablesList.Count - 1; num2 >= 0; num2--)
			{
				if (deployablesList[num2].slot == slot)
				{
					num++;
					if (num >= deployableSameSlotLimit)
					{
						Deployable deployable2 = deployablesList[num2].deployable;
						deployablesList.RemoveAt(num2);
						deployable2.ownerMaster = null;
						deployable2.onUndeploy.Invoke();
					}
				}
			}
			deployablesList.Add(new DeployableInfo
			{
				deployable = deployable,
				slot = slot
			});
			deployable.ownerMaster = this;
		}

		[Server]
		public int GetDeployableCount(DeployableSlot slot)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Int32 RoR2.CharacterMaster::GetDeployableCount(RoR2.DeployableSlot)' called on client");
				return 0;
			}
			if (deployablesList == null)
			{
				return 0;
			}
			int num = 0;
			for (int num2 = deployablesList.Count - 1; num2 >= 0; num2--)
			{
				if (deployablesList[num2].slot == slot)
				{
					num++;
				}
			}
			return num;
		}

		[Server]
		public bool IsDeployableLimited(DeployableSlot slot)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeployableLimited(RoR2.DeployableSlot)' called on client");
				return false;
			}
			return GetDeployableCount(slot) >= GetDeployableSameSlotLimit(slot);
		}

		[Server]
		public void RemoveDeployable(Deployable deployable)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::RemoveDeployable(RoR2.Deployable)' called on client");
			}
			else
			{
				if (deployablesList == null || deployable.ownerMaster != this)
				{
					return;
				}
				for (int num = deployablesList.Count - 1; num >= 0; num--)
				{
					if (deployablesList[num].deployable == deployable)
					{
						deployablesList.RemoveAt(num);
					}
				}
				deployable.ownerMaster = null;
			}
		}

		[Server]
		public bool IsDeployableSlotAvailable(DeployableSlot deployableSlot)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeployableSlotAvailable(RoR2.DeployableSlot)' called on client");
				return false;
			}
			return GetDeployableCount(deployableSlot) < GetDeployableSameSlotLimit(deployableSlot);
		}

		[Server]
		public CharacterBody SpawnBody(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.CharacterMaster::SpawnBody(UnityEngine.Vector3,UnityEngine.Quaternion)' called on client");
				return null;
			}
			if ((bool)bodyInstanceObject)
			{
				UnityEngine.Debug.LogError("Character cannot have more than one body at this time.");
				return null;
			}
			if (!bodyPrefab)
			{
				UnityEngine.Debug.LogErrorFormat("Attempted to spawn body of character master {0} with no body prefab.", base.gameObject);
			}
			if (!bodyPrefab.GetComponent<CharacterBody>())
			{
				UnityEngine.Debug.LogErrorFormat("Attempted to spawn body of character master {0} with a body prefab that has no {1} component attached.", base.gameObject, typeof(CharacterBody).Name);
			}
			bool flag = bodyPrefab.GetComponent<CharacterDirection>();
			GameObject gameObject = UnityEngine.Object.Instantiate(bodyPrefab, position, flag ? UnityEngine.Quaternion.identity : rotation);
			CharacterBody component = gameObject.GetComponent<CharacterBody>();
			component.masterObject = base.gameObject;
			component.teamComponent.teamIndex = teamIndex;
			component.SetLoadoutServer(loadout);
			if (flag)
			{
				CharacterDirection component2 = gameObject.GetComponent<CharacterDirection>();
				float y = rotation.eulerAngles.y;
				component2.yaw = y;
			}
			NetworkConnection clientAuthorityOwner = GetComponent<NetworkIdentity>().clientAuthorityOwner;
			if (clientAuthorityOwner != null)
			{
				clientAuthorityOwner.isReady = true;
				NetworkServer.SpawnWithClientAuthority(gameObject, clientAuthorityOwner);
			}
			else
			{
				NetworkServer.Spawn(gameObject);
			}
			bodyInstanceObject = gameObject;
			Run.instance.OnServerCharacterBodySpawned(component);
			return component;
		}

		[Server]
		public void DestroyBody()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::DestroyBody()' called on client");
			}
			else if ((bool)bodyInstanceObject)
			{
				CharacterBody body = GetBody();
				UnityEngine.Object.Destroy(bodyInstanceObject);
				OnBodyDestroyed(body);
				bodyInstanceObject = null;
			}
		}

		public GameObject GetBodyObject()
		{
			return bodyInstanceObject;
		}

		public CharacterBody GetBody()
		{
			GameObject bodyObject = GetBodyObject();
			if (!bodyObject)
			{
				return null;
			}
			return bodyObject.GetComponent<CharacterBody>();
		}

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			inventory = GetComponent<Inventory>();
			aiComponents = (NetworkServer.active ? GetComponents<BaseAI>() : Array.Empty<BaseAI>());
			playerCharacterMasterController = GetComponent<PlayerCharacterMasterController>();
			playerStatsComponent = GetComponent<PlayerStatsComponent>();
			minionOwnership = GetComponent<MinionOwnership>();
			inventory.onInventoryChanged += OnInventoryChanged;
			inventory.onItemAddedClient += OnItemAddedClient;
			inventory.onEquipmentExternalRestockServer += OnInventoryEquipmentExternalRestockServer;
			OnInventoryChanged();
			Stage.onServerStageBegin += OnServerStageBegin;
		}

		private void OnItemAddedClient(ItemIndex itemIndex)
		{
			StartCoroutine(HighlightNewItem(itemIndex));
		}

		private IEnumerator HighlightNewItem(ItemIndex itemIndex)
		{
			yield return new WaitForSeconds(0.05f);
			GameObject bodyObject = GetBodyObject();
			if (!bodyObject)
			{
				yield break;
			}
			ModelLocator component = bodyObject.GetComponent<ModelLocator>();
			if (!component)
			{
				yield break;
			}
			Transform modelTransform = component.modelTransform;
			if ((bool)modelTransform)
			{
				CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
				if ((bool)component2)
				{
					component2.HighlightItemDisplay(itemIndex);
				}
			}
		}

		private void Start()
		{
			UpdateAuthority();
			if (NetworkServer.active && spawnOnStart && !bodyInstanceObject)
			{
				SpawnBodyHere();
			}
			CharacterMaster.onStartGlobal?.Invoke(this);
		}

		public void SetAIUpdateFrequency(bool updateEveryFrame)
		{
			BaseAI[] array = aiComponents;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].forceUpdateEveryFrame = updateEveryFrame;
			}
		}

		private void OnInventoryChanged()
		{
			luck = 0f;
			luck += inventory.GetItemCount(RoR2Content.Items.Clover);
			luck -= inventory.GetItemCount(RoR2Content.Items.LunarBadLuck);
			if (NetworkServer.active && (bool)inventory)
			{
				CharacterBody body = GetBody();
				if ((bool)body && body.bodyIndex != BodyCatalog.SpecialCases.HereticBody() && inventory.GetItemCount(RoR2Content.Items.LunarPrimaryReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarSecondaryReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarSpecialReplacement.itemIndex) > 0 && inventory.GetItemCount(RoR2Content.Items.LunarUtilityReplacement.itemIndex) > 0)
				{
					TransformBody("HereticBody");
				}
				if (inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock) > 0 && money != 0)
				{
					GiveMoney(money);
					money = 0u;
				}
			}
			SetUpGummyClone();
		}

		private void OnInventoryEquipmentExternalRestockServer()
		{
			CharacterBody body = GetBody();
			if ((bool)body)
			{
				EffectData effectData = new EffectData();
				effectData.origin = body.corePosition;
				effectData.SetNetworkedObjectReference(body.gameObject);
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/EquipmentRestockEffect"), effectData, transmit: true);
			}
		}

		[Server]
		public void SpawnBodyHere()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::SpawnBodyHere()' called on client");
			}
			else
			{
				SpawnBody(base.transform.position, base.transform.rotation);
			}
		}

		private void OnEnable()
		{
			instancesList.Add(this);
			CharacterMaster.onCharacterMasterDiscovered?.Invoke(this);
		}

		private void OnDisable()
		{
			try
			{
				CharacterMaster.onCharacterMasterLost?.Invoke(this);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			instancesList.Remove(this);
		}

		private void OnDestroy()
		{
			if (isBoss)
			{
				isBoss = false;
			}
			Stage.onServerStageBegin -= OnServerStageBegin;
		}

		public void OnBodyStart(CharacterBody body)
		{
			if (NetworkServer.active)
			{
				lostBodyToDeath = false;
			}
			preventGameOver = true;
			killerBodyIndex = BodyIndex.None;
			killedByUnsafeArea = false;
			body.RecalculateStats();
			if (NetworkServer.active)
			{
				BaseAI[] array = aiComponents;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].OnBodyStart(body);
				}
			}
			if ((bool)playerCharacterMasterController)
			{
				if ((bool)playerCharacterMasterController.networkUserObject)
				{
					_ = playerCharacterMasterController.networkUserObject.GetComponent<NetworkIdentity>().isLocalPlayer;
				}
				playerCharacterMasterController.OnBodyStart();
			}
			if (inventory.GetItemCount(RoR2Content.Items.Ghost) > 0)
			{
				Util.PlaySound("Play_item_proc_ghostOnKill", body.gameObject);
			}
			if (NetworkServer.active)
			{
				HealthComponent healthComponent = body.healthComponent;
				if ((bool)healthComponent)
				{
					if (teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse1)
					{
						healthComponent.Networkhealth = healthComponent.fullHealth * 0.5f;
					}
					else
					{
						healthComponent.Networkhealth = healthComponent.fullHealth;
					}
				}
				UpdateBodyGodMode();
				StartLifeStopwatch();
			}
			SetUpGummyClone();
			this.onBodyStart?.Invoke(body);
			if (inventory.GetItemCount(DLC2Content.Items.ExtraStatsOnLevelUp) > 0)
			{
				uint num = TeamManager.instance.FindLevelForBeadExperience(beadExperience);
				body.SetBuffCount(DLC2Content.Buffs.ExtraStatsOnLevelUpBuff.buffIndex, (int)(num - 1));
			}
		}

		[Server]
		public bool IsExtraLifePendingServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsExtraLifePendingServer()' called on client");
				return false;
			}
			if (!IsInvoking("RespawnExtraLife") && !IsInvoking("RespawnExtraLifeVoid") && !IsInvoking("RespawnExtraLifeShrine"))
			{
				return IsInvoking("RespawnExtraLifeHealAndRevive");
			}
			return true;
		}

		[Server]
		public bool IsDeadAndOutOfLivesServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.CharacterMaster::IsDeadAndOutOfLivesServer()' called on client");
				return false;
			}
			CharacterBody body = GetBody();
			if (body != null)
			{
				if (body.healthComponent.alive)
				{
					return false;
				}
				if (body.HasBuff(DLC2Content.Buffs.ExtraLifeBuff))
				{
					return false;
				}
				bool flag = false;
				if (body.equipmentSlot != null && body.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex)
				{
					flag = true;
				}
				if (flag)
				{
					return false;
				}
			}
			return inventory.GetItemCount(RoR2Content.Items.ExtraLife) <= 0 && inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) <= 0 && !IsExtraLifePendingServer();
		}

		public void OnBodyDeath(CharacterBody body)
		{
			if (NetworkServer.active)
			{
				lostBodyToDeath = true;
				deathFootPosition = body.footPosition;
				BaseAI[] array = aiComponents;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].OnBodyDeath(body);
				}
				if ((bool)playerCharacterMasterController)
				{
					playerCharacterMasterController.OnBodyDeath();
				}
				if (body.HasBuff(DLC2Content.Buffs.ExtraLifeBuff))
				{
					body.RemoveBuff(DLC2Content.Buffs.ExtraLifeBuff);
					Invoke("RespawnExtraLifeShrine", 2f);
					Invoke("PlayExtraLifeSFX", 1f);
				}
				else
				{
					bool flag = false;
					if ((bool)body.equipmentSlot && body.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex)
					{
						flag = true;
					}
					if (flag)
					{
						CharacterMasterNotificationQueue.SendTransformNotification(this, inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default);
						inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex);
						Invoke("RespawnExtraLifeHealAndRevive", 2f);
						Invoke("PlayExtraLifeSFX", 1f);
					}
					else if (inventory.GetItemCount(RoR2Content.Items.ExtraLife) > 0)
					{
						inventory.RemoveItem(RoR2Content.Items.ExtraLife);
						Invoke("RespawnExtraLife", 2f);
						Invoke("PlayExtraLifeSFX", 1f);
					}
					else if (inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) > 0)
					{
						inventory.RemoveItem(DLC1Content.Items.ExtraLifeVoid);
						Invoke("RespawnExtraLifeVoid", 2f);
						Invoke("PlayExtraLifeVoidSFX", 1f);
					}
					else
					{
						if (destroyOnBodyDeath)
						{
							UnityEngine.Object.Destroy(base.gameObject, 1f);
						}
						preventGameOver = false;
						preventRespawnUntilNextStageServer = true;
					}
				}
				if (TryGetComponent<DevotedLemurianController>(out var component))
				{
					component.OnDevotedBodyDead();
				}
				if ((bool)devotionInventoryPrefab)
				{
					devotionInventoryPrefab.GetComponent<Inventory>().RemoveItem(devotionItem, devotedEvolutionTracker + 1);
					devotionInventoryUpdaterRef.DropScrapOnDeath(devotionItem, body);
					devotionInventoryUpdaterRef.UpdateAllMinions();
				}
				ResetLifeStopwatch();
			}
			onBodyDeath?.Invoke();
		}

		public void TrueKill()
		{
			TrueKill(null, null, DamageType.Generic);
		}

		public void TrueKill(GameObject killerOverride = null, GameObject inflictorOverride = null, DamageTypeCombo damageTypeOverride = default(DamageTypeCombo))
		{
			int itemCount = inventory.GetItemCount(RoR2Content.Items.ExtraLife);
			if (itemCount > 0)
			{
				inventory.ResetItem(RoR2Content.Items.ExtraLife);
				inventory.GiveItem(RoR2Content.Items.ExtraLifeConsumed, itemCount);
				CharacterMasterNotificationQueue.SendTransformNotification(this, RoR2Content.Items.ExtraLife.itemIndex, RoR2Content.Items.ExtraLifeConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default);
			}
			if (inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) > 0)
			{
				inventory.ResetItem(DLC1Content.Items.ExtraLifeVoid);
				inventory.GiveItem(DLC1Content.Items.ExtraLifeVoidConsumed, itemCount);
				CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.ExtraLifeVoid.itemIndex, DLC1Content.Items.ExtraLifeVoidConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default);
			}
			if (GetBody().HasBuff(DLC2Content.Buffs.ExtraLifeBuff))
			{
				GetBody().RemoveBuff(DLC2Content.Buffs.ExtraLifeBuff);
			}
			bool flag = false;
			if ((bool)GetBody().equipmentSlot && GetBody().equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex)
			{
				flag = true;
			}
			if (flag)
			{
				CharacterMasterNotificationQueue.SendTransformNotification(this, inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default);
				inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex);
			}
			CancelInvoke("RespawnExtraLife");
			CancelInvoke("PlayExtraLifeSFX");
			CancelInvoke("RespawnExtraLifeVoid");
			CancelInvoke("PlayExtraLifeVoidSFX");
			CancelInvoke("RespawnExtraLifeShrine");
			CharacterBody body = GetBody();
			if ((bool)body)
			{
				body.healthComponent.Suicide(killerOverride, inflictorOverride, damageTypeOverride);
			}
		}

		private void PlayExtraLifeSFX()
		{
			GameObject gameObject = bodyInstanceObject;
			if ((bool)gameObject)
			{
				Util.PlaySound("Play_item_proc_extraLife", gameObject);
			}
		}

		private void PlayExtraLifeVoidSFX()
		{
			GameObject gameObject = bodyInstanceObject;
			if ((bool)gameObject)
			{
				Util.PlaySound("Play_item_void_extraLife", gameObject);
			}
		}

		public void RespawnExtraLife()
		{
			inventory.GiveItem(RoR2Content.Items.ExtraLifeConsumed);
			CharacterMasterNotificationQueue.SendTransformNotification(this, RoR2Content.Items.ExtraLife.itemIndex, RoR2Content.Items.ExtraLifeConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default);
			UnityEngine.Vector3 vector = deathFootPosition;
			if (killedByUnsafeArea)
			{
				vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent<CharacterBody>(), RoR2Application.rng) ?? deathFootPosition;
			}
			Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true);
			GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
			if (NetworkServer.active)
			{
				inventory.SetEquipmentDisabled(_active: false);
			}
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/HippoRezEffect");
			if ((bool)bodyInstanceObject)
			{
				EntityStateMachine[] components = bodyInstanceObject.GetComponents<EntityStateMachine>();
				foreach (EntityStateMachine obj in components)
				{
					obj.initialStateType = obj.mainStateType;
				}
				if ((bool)gameObject)
				{
					EffectManager.SpawnEffect(gameObject, new EffectData
					{
						origin = vector,
						rotation = bodyInstanceObject.transform.rotation
					}, transmit: true);
				}
			}
		}

		public void RespawnExtraLifeVoid()
		{
			inventory.GiveItem(DLC1Content.Items.ExtraLifeVoidConsumed);
			CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.ExtraLifeVoid.itemIndex, DLC1Content.Items.ExtraLifeVoidConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default);
			UnityEngine.Vector3 vector = deathFootPosition;
			if (killedByUnsafeArea)
			{
				vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent<CharacterBody>(), RoR2Application.rng) ?? deathFootPosition;
			}
			Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true);
			GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
			if (NetworkServer.active)
			{
				inventory.SetEquipmentDisabled(_active: false);
			}
			if ((bool)bodyInstanceObject)
			{
				EntityStateMachine[] components = bodyInstanceObject.GetComponents<EntityStateMachine>();
				foreach (EntityStateMachine obj in components)
				{
					obj.initialStateType = obj.mainStateType;
				}
				if ((bool)ExtraLifeVoidManager.rezEffectPrefab)
				{
					EffectManager.SpawnEffect(ExtraLifeVoidManager.rezEffectPrefab, new EffectData
					{
						origin = vector,
						rotation = bodyInstanceObject.transform.rotation
					}, transmit: true);
				}
			}
			foreach (ContagiousItemManager.TransformationInfo transformationInfo in ContagiousItemManager.transformationInfos)
			{
				ContagiousItemManager.TryForceReplacement(inventory, transformationInfo.originalItem);
			}
		}

		public void RespawnExtraLifeShrine()
		{
			UnityEngine.Vector3 vector = deathFootPosition;
			if (killedByUnsafeArea)
			{
				vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent<CharacterBody>(), RoR2Application.rng) ?? deathFootPosition;
			}
			Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true);
			GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/fxHealAndReviveGold");
			if ((bool)bodyInstanceObject)
			{
				EntityStateMachine[] components = bodyInstanceObject.GetComponents<EntityStateMachine>();
				foreach (EntityStateMachine obj in components)
				{
					obj.initialStateType = obj.mainStateType;
				}
				if ((bool)gameObject)
				{
					EffectManager.SpawnEffect(gameObject, new EffectData
					{
						origin = vector,
						rotation = bodyInstanceObject.transform.rotation
					}, transmit: true);
					Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject);
				}
			}
		}

		public void RespawnExtraLifeHealAndRevive()
		{
			UnityEngine.Vector3 vector = deathFootPosition;
			if (killedByUnsafeArea)
			{
				vector = TeleportHelper.FindSafeTeleportDestination(deathFootPosition, bodyPrefab.GetComponent<CharacterBody>(), RoR2Application.rng) ?? deathFootPosition;
			}
			Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true);
			GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/fxHealAndReviveGold");
			if ((bool)bodyInstanceObject)
			{
				EntityStateMachine[] components = bodyInstanceObject.GetComponents<EntityStateMachine>();
				foreach (EntityStateMachine obj in components)
				{
					obj.initialStateType = obj.mainStateType;
				}
				if ((bool)gameObject)
				{
					EffectManager.SpawnEffect(gameObject, new EffectData
					{
						origin = vector,
						rotation = bodyInstanceObject.transform.rotation
					}, transmit: true);
					Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject);
				}
			}
		}

		public void OnBodyDamaged(DamageReport damageReport)
		{
			BaseAI[] array = aiComponents;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].OnBodyDamaged(damageReport);
			}
			if ((bool)playerCharacterMasterController)
			{
				HandleOnPlayerBodyDamaged();
				CallRpcOnPlayerBodyDamaged();
			}
		}

		[ClientRpc]
		private void RpcOnPlayerBodyDamaged()
		{
			HandleOnPlayerBodyDamaged();
		}

		private void HandleOnPlayerBodyDamaged()
		{
			this.onPlayerBodyDamaged?.Invoke(playerCharacterMasterController);
		}

		public void OnBodyDestroyed(CharacterBody characterBody)
		{
			if ((object)characterBody != GetBody())
			{
				return;
			}
			if (NetworkServer.active)
			{
				BaseAI[] array = aiComponents;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].OnBodyDestroyed(characterBody);
				}
				PauseLifeStopwatch();
			}
			this.onBodyDestroyed?.Invoke(characterBody);
		}

		[Server]
		private void StartLifeStopwatch()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::StartLifeStopwatch()' called on client");
			}
			else if (!(internalSurvivalTime > 0f))
			{
				internalSurvivalTime = Run.instance.GetRunStopwatch() - currentLifeStopwatch;
			}
		}

		[Server]
		private void PauseLifeStopwatch()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::PauseLifeStopwatch()' called on client");
			}
			else if (!(internalSurvivalTime <= 0f))
			{
				internalSurvivalTime = 0f - currentLifeStopwatch;
			}
		}

		[Server]
		private void ResetLifeStopwatch()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::ResetLifeStopwatch()' called on client");
			}
			else
			{
				internalSurvivalTime = 0f;
			}
		}

		[Server]
		public BodyIndex GetKillerBodyIndex()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.BodyIndex RoR2.CharacterMaster::GetKillerBodyIndex()' called on client");
				return default(BodyIndex);
			}
			return killerBodyIndex;
		}

		[InitDuringStartup]
		private static void Init()
		{
			GlobalEventManager.onCharacterDeathGlobal += delegate(DamageReport damageReport)
			{
				CharacterMaster victimMaster = damageReport.victimMaster;
				if ((bool)victimMaster)
				{
					victimMaster.killerBodyIndex = BodyCatalog.FindBodyIndex(damageReport.damageInfo.attacker);
					victimMaster.killedByUnsafeArea = (bool)damageReport.damageInfo.inflictor && (bool)damageReport.damageInfo.inflictor.GetComponent<MapZone>();
				}
			};
			Stage.onServerStageBegin += delegate
			{
				foreach (CharacterMaster instances in instancesList)
				{
					instances.preventRespawnUntilNextStageServer = false;
				}
			};
			CommonAssets.Resolve();
		}

		[Command]
		public void CmdRespawn(string bodyName)
		{
			if (preventRespawnUntilNextStageServer)
			{
				return;
			}
			if (!string.IsNullOrEmpty(bodyName))
			{
				bodyPrefab = BodyCatalog.FindBodyPrefab(bodyName);
				if (!bodyPrefab)
				{
					UnityEngine.Debug.LogError("CmdRespawn failed to find bodyPrefab for name '" + bodyName + "'.");
				}
			}
			if ((bool)Stage.instance)
			{
				Stage.instance.RespawnCharacter(this);
			}
		}

		[Server]
		public void TransformBody(string bodyName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TransformBody(System.String)' called on client");
			}
			else if (!string.IsNullOrEmpty(bodyName))
			{
				bodyPrefab = BodyCatalog.FindBodyPrefab(bodyName);
				if (bodyPrefab != null)
				{
					Transform component = bodyInstanceObject.GetComponent<Transform>();
					UnityEngine.Vector3 position = component.position;
					UnityEngine.Quaternion rotation = component.rotation;
					DestroyBody();
					CharacterBody component2 = bodyPrefab.GetComponent<CharacterBody>();
					if ((bool)component2)
					{
						position = CalculateSafeGroundPosition(position, component2);
						SpawnBody(position, rotation).GetComponent<HereticInitialStateHelper>()?.PrepareTransformation();
					}
					else
					{
						UnityEngine.Debug.LogErrorFormat("Trying to respawn as object {0} who has no Character Body!", bodyPrefab);
					}
				}
				else
				{
					UnityEngine.Debug.LogError("Can't TransformBody because there's no prefab for body named '" + bodyName + "'");
				}
			}
			else
			{
				UnityEngine.Debug.LogError("Can't TransformBody with null or empty body name.");
			}
		}

		[Server]
		private void OnServerStageBegin(Stage stage)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::OnServerStageBegin(RoR2.Stage)' called on client");
				return;
			}
			TryCloverVoidUpgrades();
			TryRegenerateScrap();
			TrySaleStar();
		}

		[ClientRpc]
		public void RpcSetSeekerRevive(SEEKER_REVIVE_STATUS s)
		{
			seekerUsedRevive = s;
		}

		public SEEKER_REVIVE_STATUS getSeekerUsedRevive()
		{
			return seekerUsedRevive;
		}

		private void TryRegenerateScrap()
		{
			int itemCount = inventory.GetItemCount(DLC1Content.Items.RegeneratingScrapConsumed);
			if (itemCount > 0)
			{
				inventory.RemoveItem(DLC1Content.Items.RegeneratingScrapConsumed, itemCount);
				inventory.GiveItem(DLC1Content.Items.RegeneratingScrap, itemCount);
				CharacterMasterNotificationQueue.SendTransformNotification(this, DLC1Content.Items.RegeneratingScrapConsumed.itemIndex, DLC1Content.Items.RegeneratingScrap.itemIndex, CharacterMasterNotificationQueue.TransformationType.RegeneratingScrapRegen);
			}
		}

		private void TrySaleStar()
		{
			int itemCount = inventory.GetItemCount(DLC2Content.Items.LowerPricedChestsConsumed);
			if (itemCount > 0)
			{
				inventory.RemoveItem(DLC2Content.Items.LowerPricedChestsConsumed, itemCount);
				inventory.GiveItem(DLC2Content.Items.LowerPricedChests, itemCount);
				CharacterMasterNotificationQueue.SendTransformNotification(this, DLC2Content.Items.LowerPricedChestsConsumed.itemIndex, DLC2Content.Items.LowerPricedChests.itemIndex, CharacterMasterNotificationQueue.TransformationType.SaleStarRegen);
			}
		}

		private void TryTeleportOnLowHealthRegen()
		{
			int itemCount = inventory.GetItemCount(DLC2Content.Items.TeleportOnLowHealthConsumed);
			if (itemCount > 0)
			{
				inventory.RemoveItem(DLC2Content.Items.TeleportOnLowHealthConsumed, itemCount);
				inventory.GiveItem(DLC2Content.Items.TeleportOnLowHealth, itemCount);
				CharacterMasterNotificationQueue.SendTransformNotification(this, DLC2Content.Items.TeleportOnLowHealthConsumed.itemIndex, DLC2Content.Items.TeleportOnLowHealth.itemIndex, CharacterMasterNotificationQueue.TransformationType.TeleportOnLowHealthRegen);
			}
		}

		[Server]
		public void TrackDevotionItem(ItemIndex itemIndex, Interactor summoner, GameObject devotedInventoryRef, DevotionInventoryController devotionInventoryUpdater)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TrackDevotionItem(RoR2.ItemIndex,RoR2.Interactor,UnityEngine.GameObject,RoR2.DevotionInventoryController)' called on client");
				return;
			}
			_ = summoner == null;
			devotionItem = itemIndex;
			summonerRef = summoner;
			devotionInventoryPrefab = devotedInventoryRef;
			isDevotedMinion = true;
			devotionInventoryUpdaterRef = devotionInventoryUpdater;
		}

		[Server]
		private void TryCloverVoidUpgrades()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterMaster::TryCloverVoidUpgrades()' called on client");
				return;
			}
			if (cloverVoidRng == null)
			{
				cloverVoidRng = new Xoroshiro128Plus(Run.instance.seed);
			}
			int itemCount = inventory.GetItemCount(DLC1Content.Items.CloverVoid);
			List<PickupIndex> list = new List<PickupIndex>(Run.instance.availableTier2DropList);
			List<PickupIndex> list2 = new List<PickupIndex>(Run.instance.availableTier3DropList);
			List<ItemIndex> list3 = new List<ItemIndex>(inventory.itemAcquisitionOrder);
			Util.ShuffleList(list3, cloverVoidRng);
			int num = itemCount * 3;
			int num2 = 0;
			int num3 = 0;
			while (num2 < num && num3 < list3.Count)
			{
				ItemDef startingItemDef = ItemCatalog.GetItemDef(list3[num3]);
				ItemDef itemDef = null;
				List<PickupIndex> list4 = null;
				switch (startingItemDef.tier)
				{
				case ItemTier.Tier1:
					list4 = list;
					break;
				case ItemTier.Tier2:
					list4 = list2;
					break;
				}
				if (list4 != null && list4.Count > 0)
				{
					Util.ShuffleList(list4, cloverVoidRng);
					list4.Sort(CompareTags);
					itemDef = ItemCatalog.GetItemDef(list4[0].itemIndex);
				}
				if (itemDef != null)
				{
					if (inventory.GetItemCount(itemDef.itemIndex) == 0)
					{
						list3.Add(itemDef.itemIndex);
					}
					num2++;
					int itemCount2 = inventory.GetItemCount(startingItemDef.itemIndex);
					inventory.RemoveItem(startingItemDef.itemIndex, itemCount2);
					inventory.GiveItem(itemDef.itemIndex, itemCount2);
					CharacterMasterNotificationQueue.SendTransformNotification(this, startingItemDef.itemIndex, itemDef.itemIndex, CharacterMasterNotificationQueue.TransformationType.CloverVoid);
				}
				num3++;
				int CompareTags(PickupIndex lhs, PickupIndex rhs)
				{
					int num4 = 0;
					int num5 = 0;
					ItemDef itemDef2 = ItemCatalog.GetItemDef(lhs.itemIndex);
					ItemDef itemDef3 = ItemCatalog.GetItemDef(rhs.itemIndex);
					if (startingItemDef.ContainsTag(ItemTag.Damage))
					{
						if (itemDef2.ContainsTag(ItemTag.Damage))
						{
							num4 = 1;
						}
						if (itemDef3.ContainsTag(ItemTag.Damage))
						{
							num5 = 1;
						}
					}
					if (startingItemDef.ContainsTag(ItemTag.Healing))
					{
						if (itemDef2.ContainsTag(ItemTag.Healing))
						{
							num4 = 1;
						}
						if (itemDef3.ContainsTag(ItemTag.Healing))
						{
							num5 = 1;
						}
					}
					if (startingItemDef.ContainsTag(ItemTag.Utility))
					{
						if (itemDef2.ContainsTag(ItemTag.Utility))
						{
							num4 = 1;
						}
						if (itemDef3.ContainsTag(ItemTag.Utility))
						{
							num5 = 1;
						}
					}
					return num5 - num4;
				}
			}
			if (num2 > 0)
			{
				GameObject gameObject = bodyInstanceObject;
				if ((bool)gameObject)
				{
					Util.PlaySound("Play_item_proc_extraLife", gameObject);
				}
			}
		}

		private static GameObject PickRandomSurvivorBodyPrefab(Xoroshiro128Plus rng, NetworkUser networkUser, bool allowHidden)
		{
			SurvivorDef[] array = SurvivorCatalog.allSurvivorDefs.Where(SurvivorIsUnlockedAndAvailable).ToArray();
			return rng.NextElementUniform(array).bodyPrefab;
			bool SurvivorIsUnlockedAndAvailable(SurvivorDef survivorDef)
			{
				if (allowHidden || !survivorDef.hidden)
				{
					if (!survivorDef.CheckRequiredExpansionEnabled(networkUser))
					{
						return false;
					}
					UnlockableDef unlockableDef = survivorDef.unlockableDef;
					if ((object)unlockableDef != null)
					{
						return networkUser.unlockables.Contains(unlockableDef);
					}
					return true;
				}
				return false;
			}
		}

		[Server]
		public CharacterBody Respawn(UnityEngine.Vector3 footPosition, UnityEngine.Quaternion rotation, bool wasRevivedMidStage = false)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.CharacterMaster::Respawn(UnityEngine.Vector3,UnityEngine.Quaternion,System.Boolean)' called on client");
				return null;
			}
			if (!wasRevivedMidStage)
			{
				CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS.UNUSED);
			}
			else if (seekerUsedRevive == SEEKER_REVIVE_STATUS.USED)
			{
				CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS.BURNED);
			}
			DestroyBody();
			if ((bool)playerCharacterMasterController && RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.randomSurvivorOnRespawnArtifactDef))
			{
				bodyPrefab = PickRandomSurvivorBodyPrefab(Run.instance.randomSurvivorOnRespawnRng, playerCharacterMasterController.networkUser, allowHidden: false);
			}
			if ((bool)bodyPrefab)
			{
				CharacterBody component = bodyPrefab.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					UnityEngine.Vector3 position = footPosition;
					if (true)
					{
						position = CalculateSafeGroundPosition(footPosition, component);
					}
					return SpawnBody(position, rotation);
				}
				UnityEngine.Debug.LogErrorFormat("Trying to respawn as object {0} who has no Character Body!", bodyPrefab);
			}
			else
			{
				UnityEngine.Debug.LogErrorFormat("CharacterMaster.Respawn failed. {0} does not have a valid body prefab assigned.", base.gameObject.name);
			}
			return null;
		}

		private UnityEngine.Vector3 CalculateSafeGroundPosition(UnityEngine.Vector3 desiredFootPos, CharacterBody body)
		{
			if ((bool)body)
			{
				UnityEngine.Vector3 result = desiredFootPos;
				RaycastHit hitInfo = default(RaycastHit);
				Ray ray = new Ray(desiredFootPos + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down);
				float maxDistance = 4f;
				if (Physics.SphereCast(ray, body.radius, out hitInfo, maxDistance, LayerIndex.world.mask))
				{
					result.y = ray.origin.y - hitInfo.distance;
				}
				float bodyPrefabFootOffset = Util.GetBodyPrefabFootOffset(bodyPrefab);
				result.y += bodyPrefabFootOffset;
				return result;
			}
			UnityEngine.Debug.LogError("Can't calculate safe ground position if the CharacterBody is null");
			return desiredFootPos;
		}

		private void SetUpGummyClone()
		{
			if (!NetworkServer.active || !inventory || inventory.GetItemCount(DLC1Content.Items.GummyCloneIdentifier.itemIndex) <= 0)
			{
				return;
			}
			if (!base.gameObject.GetComponent<MasterSuicideOnTimer>())
			{
				base.gameObject.AddComponent<MasterSuicideOnTimer>().lifeTimer = 30f;
			}
			CharacterBody body = GetBody();
			if ((bool)body)
			{
				CharacterDeathBehavior component = body.GetComponent<CharacterDeathBehavior>();
				if ((bool)component && component.deathState.stateType != typeof(GummyCloneDeathState))
				{
					component.deathState = new SerializableEntityStateType(typeof(GummyCloneDeathState));
				}
				body.portraitIcon = LegacyResourcesAPI.Load<Texture>("Textures/BodyIcons/texGummyCloneBody");
			}
		}

		public void SetMasterBodyDirtyBit()
		{
			SetDirtyBit(1u);
		}

		private void ToggleGod()
		{
			godMode = !godMode;
			UpdateBodyGodMode();
		}

		private void UpdateBodyGodMode()
		{
			if ((bool)bodyInstanceObject)
			{
				HealthComponent component = bodyInstanceObject.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					component.godMode = godMode;
				}
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 127u;
			}
			bool num2 = (num & 1) != 0;
			bool flag = (num & 2) != 0;
			bool flag2 = (num & 0x40) != 0;
			bool flag3 = (num & 4) != 0;
			bool flag4 = (num & 8) != 0;
			bool flag5 = (num & 0x10) != 0;
			bool flag6 = (num & 0x20) != 0;
			writer.Write((byte)num);
			if (num2)
			{
				writer.Write(_bodyInstanceId);
			}
			if (flag)
			{
				writer.WritePackedUInt32(_money);
			}
			if (flag2)
			{
				writer.WritePackedUInt32(_voidCoins);
			}
			if (flag3)
			{
				writer.Write(_internalSurvivalTime);
			}
			if (flag4)
			{
				writer.Write(teamIndex);
			}
			if (flag5)
			{
				loadout.Serialize(writer);
			}
			if (flag6)
			{
				writer.WritePackedUInt32(miscFlags);
			}
			return num != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			byte num = reader.ReadByte();
			bool flag = (num & 1) != 0;
			bool flag2 = (num & 2) != 0;
			bool flag3 = (num & 0x40) != 0;
			bool flag4 = (num & 4) != 0;
			bool flag5 = (num & 8) != 0;
			bool flag6 = (num & 0x10) != 0;
			bool num2 = (num & 0x20) != 0;
			if (flag)
			{
				NetworkInstanceId value = reader.ReadNetworkId();
				OnSyncBodyInstanceId(value);
			}
			if (flag2)
			{
				_money = reader.ReadPackedUInt32();
			}
			if (flag3)
			{
				_voidCoins = reader.ReadPackedUInt32();
			}
			if (flag4)
			{
				_internalSurvivalTime = reader.ReadSingle();
			}
			if (flag5)
			{
				teamIndex = reader.ReadTeamIndex();
			}
			if (flag6)
			{
				loadout.Deserialize(reader);
			}
			if (num2)
			{
				miscFlags = reader.ReadPackedUInt32();
			}
		}

		static CharacterMaster()
		{
			instancesList = new List<CharacterMaster>();
			_readOnlyInstancesList = new ReadOnlyCollection<CharacterMaster>(instancesList);
			kCmdCmdRespawn = 1097984413;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterMaster), kCmdCmdRespawn, InvokeCmdCmdRespawn);
			kRpcRpcOnPlayerBodyDamaged = -1070481806;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMaster), kRpcRpcOnPlayerBodyDamaged, InvokeRpcRpcOnPlayerBodyDamaged);
			kRpcRpcSetSeekerRevive = 458435899;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMaster), kRpcRpcSetSeekerRevive, InvokeRpcRpcSetSeekerRevive);
			NetworkCRC.RegisterBehaviour("CharacterMaster", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdRespawn(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdRespawn called on client.");
			}
			else
			{
				((CharacterMaster)obj).CmdRespawn(reader.ReadString());
			}
		}

		public void CallCmdRespawn(string bodyName)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdRespawn called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdRespawn(bodyName);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdRespawn);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(bodyName);
			SendCommandInternal(networkWriter, 0, "CmdRespawn");
		}

		protected static void InvokeRpcRpcOnPlayerBodyDamaged(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnPlayerBodyDamaged called on server.");
			}
			else
			{
				((CharacterMaster)obj).RpcOnPlayerBodyDamaged();
			}
		}

		protected static void InvokeRpcRpcSetSeekerRevive(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetSeekerRevive called on server.");
			}
			else
			{
				((CharacterMaster)obj).RpcSetSeekerRevive((SEEKER_REVIVE_STATUS)reader.ReadInt32());
			}
		}

		public void CallRpcOnPlayerBodyDamaged()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnPlayerBodyDamaged called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnPlayerBodyDamaged);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnPlayerBodyDamaged");
		}

		public void CallRpcSetSeekerRevive(SEEKER_REVIVE_STATUS s)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetSeekerRevive called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetSeekerRevive);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)s);
			SendRPCInternal(networkWriter, 0, "RpcSetSeekerRevive");
		}

		public override void PreStartClient()
		{
		}
	}
	[Serializable]
	public class CharacterMasterUnityEvent : UnityEvent<CharacterMaster>
	{
	}
	public class CharacterMasterNotificationQueue : MonoBehaviour
	{
		public enum TransformationType
		{
			Default,
			ContagiousVoid,
			CloverVoid,
			Suppressed,
			LunarSun,
			RegeneratingScrapRegen,
			SaleStarRegen,
			TeleportOnLowHealthRegen
		}

		public class TransformationInfo
		{
			public readonly TransformationType transformationType;

			public readonly object previousData;

			public static bool operator ==(TransformationInfo lhs, TransformationInfo rhs)
			{
				bool flag = (object)lhs == null;
				bool flag2 = (object)rhs == null;
				if (!(flag && flag2))
				{
					if (!flag && !flag2 && lhs.previousData == rhs.previousData)
					{
						return lhs.transformationType == rhs.transformationType;
					}
					return false;
				}
				return true;
			}

			public static bool operator !=(TransformationInfo lhs, TransformationInfo rhs)
			{
				return !(lhs == rhs);
			}

			public TransformationInfo(TransformationType transformationType, object previousData)
			{
				this.transformationType = transformationType;
				this.previousData = previousData;
			}
		}

		public class NotificationInfo
		{
			public readonly object data;

			public readonly TransformationInfo transformation;

			public static bool operator ==(NotificationInfo lhs, NotificationInfo rhs)
			{
				bool flag = (object)lhs == null;
				bool flag2 = (object)rhs == null;
				if (!(flag && flag2))
				{
					if (!flag && !flag2 && lhs.data == rhs.data)
					{
						return lhs.transformation == rhs.transformation;
					}
					return false;
				}
				return true;
			}

			public static bool operator !=(NotificationInfo lhs, NotificationInfo rhs)
			{
				return !(lhs == rhs);
			}

			public NotificationInfo(object data, TransformationInfo transformation = null)
			{
				this.data = data;
				this.transformation = transformation;
			}
		}

		private class TimedNotificationInfo
		{
			public NotificationInfo notification;

			public float startTime;

			public float duration;
		}

		private class TransformNotificationMessage : MessageBase
		{
			public GameObject masterGameObject;

			public PickupIndex oldIndex;

			public PickupIndex newIndex;

			public TransformationType transformationType;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(masterGameObject);
				GeneratedNetworkCode._WritePickupIndex_None(writer, oldIndex);
				GeneratedNetworkCode._WritePickupIndex_None(writer, newIndex);
				writer.Write((int)transformationType);
			}

			public override void Deserialize(NetworkReader reader)
			{
				masterGameObject = reader.ReadGameObject();
				oldIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				newIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				transformationType = (TransformationType)reader.ReadInt32();
			}
		}

		public const float firstNotificationLengthSeconds = 6f;

		public const float repeatNotificationLengthSeconds = 6f;

		private static readonly TransformNotificationMessage transformNotificationMessageInstance = new TransformNotificationMessage();

		private CharacterMaster master;

		private List<TimedNotificationInfo> notifications = new List<TimedNotificationInfo>();

		public event Action<CharacterMasterNotificationQueue> onCurrentNotificationChanged;

		public static void PushPickupNotification(CharacterMaster characterMaster, PickupIndex pickupIndex)
		{
			if (!characterMaster.hasAuthority)
			{
				UnityEngine.Debug.LogError("Can't PushPickupNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local.");
				return;
			}
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			ItemIndex itemIndex = pickupDef.itemIndex;
			if (itemIndex != ItemIndex.None)
			{
				PushItemNotification(characterMaster, itemIndex);
				return;
			}
			EquipmentIndex equipmentIndex = pickupDef.equipmentIndex;
			if (equipmentIndex != EquipmentIndex.None)
			{
				PushEquipmentNotification(characterMaster, equipmentIndex);
			}
		}

		public static void PushItemNotification(CharacterMaster characterMaster, ItemIndex itemIndex)
		{
			if (!characterMaster.hasAuthority)
			{
				UnityEngine.Debug.LogError("Can't PushItemNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local.");
				return;
			}
			CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster);
			if (!notificationQueueForMaster || itemIndex == ItemIndex.None)
			{
				return;
			}
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if (!(itemDef == null) && !itemDef.hidden)
			{
				float duration = 6f;
				if (characterMaster.inventory.GetItemCount(itemIndex) > 1)
				{
					duration = 6f;
				}
				notificationQueueForMaster.PushNotification(new NotificationInfo(ItemCatalog.GetItemDef(itemIndex)), duration);
			}
		}

		public static void PushEquipmentNotification(CharacterMaster characterMaster, EquipmentIndex equipmentIndex)
		{
			if (!characterMaster.hasAuthority)
			{
				UnityEngine.Debug.LogError("Can't PushEquipmentNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local.");
				return;
			}
			CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster);
			if ((bool)notificationQueueForMaster && equipmentIndex != EquipmentIndex.None)
			{
				notificationQueueForMaster.PushNotification(new NotificationInfo(EquipmentCatalog.GetEquipmentDef(equipmentIndex)), 6f);
			}
		}

		public static void PushArtifactNotification(CharacterMaster characterMaster, ArtifactDef artifactDef)
		{
			if (!characterMaster.hasAuthority)
			{
				UnityEngine.Debug.LogError("Can't PushArtifactNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local.");
				return;
			}
			CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster);
			if ((bool)notificationQueueForMaster)
			{
				notificationQueueForMaster.PushNotification(new NotificationInfo(artifactDef), 6f);
			}
		}

		public static void PushEquipmentTransformNotification(CharacterMaster characterMaster, EquipmentIndex oldIndex, EquipmentIndex newIndex, TransformationType transformationType)
		{
			if (!characterMaster.hasAuthority)
			{
				UnityEngine.Debug.LogError("Can't PushEquipmentTransformNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local.");
				return;
			}
			CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster);
			if ((bool)notificationQueueForMaster && oldIndex != EquipmentIndex.None && newIndex != EquipmentIndex.None)
			{
				object equipmentDef = EquipmentCatalog.GetEquipmentDef(oldIndex);
				TransformationInfo transformation = new TransformationInfo(transformationType, equipmentDef);
				NotificationInfo info = new NotificationInfo(EquipmentCatalog.GetEquipmentDef(newIndex), transformation);
				notificationQueueForMaster.PushNotification(info, 6f);
			}
		}

		public static void PushItemTransformNotification(CharacterMaster characterMaster, ItemIndex oldIndex, ItemIndex newIndex, TransformationType transformationType)
		{
			if (!characterMaster.hasAuthority)
			{
				UnityEngine.Debug.LogError("Can't PushItemTransformNotification for " + Util.GetBestMasterName(characterMaster) + " because they aren't local.");
				return;
			}
			CharacterMasterNotificationQueue notificationQueueForMaster = GetNotificationQueueForMaster(characterMaster);
			if ((bool)notificationQueueForMaster && oldIndex != ItemIndex.None && newIndex != ItemIndex.None)
			{
				object itemDef = ItemCatalog.GetItemDef(oldIndex);
				TransformationInfo transformation = new TransformationInfo(transformationType, itemDef);
				NotificationInfo info = new NotificationInfo(ItemCatalog.GetItemDef(newIndex), transformation);
				notificationQueueForMaster.PushNotification(info, 6f);
			}
		}

		public static CharacterMasterNotificationQueue GetNotificationQueueForMaster(CharacterMaster master)
		{
			if (master != null)
			{
				CharacterMasterNotificationQueue characterMasterNotificationQueue = master.GetComponent<CharacterMasterNotificationQueue>();
				if (!characterMasterNotificationQueue)
				{
					characterMasterNotificationQueue = master.gameObject.AddComponent<CharacterMasterNotificationQueue>();
					characterMasterNotificationQueue.master = master;
				}
				return characterMasterNotificationQueue;
			}
			return null;
		}

		public static void SendTransformNotification(CharacterMaster characterMaster, ItemIndex oldIndex, ItemIndex newIndex, TransformationType transformationType)
		{
			SendTransformNotificationInternal(characterMaster, PickupCatalog.FindPickupIndex(oldIndex), PickupCatalog.FindPickupIndex(newIndex), transformationType);
		}

		public static void SendTransformNotification(CharacterMaster characterMaster, EquipmentIndex oldIndex, EquipmentIndex newIndex, TransformationType transformationType)
		{
			SendTransformNotificationInternal(characterMaster, PickupCatalog.FindPickupIndex(oldIndex), PickupCatalog.FindPickupIndex(newIndex), transformationType);
		}

		private static void SendTransformNotificationInternal(CharacterMaster characterMaster, PickupIndex oldIndex, PickupIndex newIndex, TransformationType transformationType)
		{
			if (NetworkServer.active)
			{
				TransformNotificationMessage msg = new TransformNotificationMessage
				{
					masterGameObject = characterMaster.gameObject,
					oldIndex = oldIndex,
					newIndex = newIndex,
					transformationType = transformationType
				};
				NetworkServer.SendByChannelToAll(78, msg, QosChannelIndex.chat.intVal);
			}
			else
			{
				UnityEngine.Debug.LogError("Can't SendTransformNotification if this isn't the server.");
			}
		}

		[NetworkMessageHandler(msgType = 78, client = true)]
		private static void HandleTransformNotification(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(transformNotificationMessageInstance);
			if ((bool)transformNotificationMessageInstance.masterGameObject)
			{
				CharacterMaster component = transformNotificationMessageInstance.masterGameObject.GetComponent<CharacterMaster>();
				if ((bool)component && component.hasAuthority)
				{
					PickupDef pickupDef = PickupCatalog.GetPickupDef(transformNotificationMessageInstance.oldIndex);
					PickupDef pickupDef2 = PickupCatalog.GetPickupDef(transformNotificationMessageInstance.newIndex);
					if (pickupDef != null && pickupDef2 != null)
					{
						if (pickupDef2.equipmentIndex != EquipmentIndex.None)
						{
							PushEquipmentTransformNotification(component, pickupDef.equipmentIndex, pickupDef2.equipmentIndex, transformNotificationMessageInstance.transformationType);
						}
						else if (pickupDef2.itemIndex != ItemIndex.None)
						{
							PushItemTransformNotification(component, pickupDef.itemIndex, pickupDef2.itemIndex, transformNotificationMessageInstance.transformationType);
						}
					}
					else
					{
						UnityEngine.Debug.LogError($"Can't handle transform notification for pickup indices:  {transformNotificationMessageInstance.oldIndex} -> {transformNotificationMessageInstance.newIndex}");
					}
				}
			}
			transformNotificationMessageInstance.masterGameObject = null;
		}

		public void FixedUpdate()
		{
			if (GetCurrentNotificationT() > 1f)
			{
				notifications.RemoveAt(0);
				if (notifications.Count > 0)
				{
					notifications[0].startTime = Run.instance.fixedTime;
				}
				this.onCurrentNotificationChanged?.Invoke(this);
			}
		}

		public NotificationInfo GetCurrentNotification()
		{
			if (notifications.Count > 0)
			{
				return notifications[0].notification;
			}
			return null;
		}

		private void PushNotification(NotificationInfo info, float duration)
		{
			if (notifications.Count == 0 || notifications[notifications.Count - 1].notification != info)
			{
				notifications.Add(new TimedNotificationInfo
				{
					notification = info,
					startTime = Run.instance.fixedTime,
					duration = duration
				});
				if (notifications.Count == 1)
				{
					this.onCurrentNotificationChanged?.Invoke(this);
				}
			}
		}

		public float GetCurrentNotificationT()
		{
			if (notifications.Count > 0)
			{
				TimedNotificationInfo timedNotificationInfo = notifications[0];
				return (Run.instance.fixedTime - timedNotificationInfo.startTime) / timedNotificationInfo.duration;
			}
			return 0f;
		}
	}
	public class CharacterModel : MonoBehaviour
	{
		[Serializable]
		public struct RendererInfo : IEquatable<RendererInfo>
		{
			[PrefabReference]
			public Renderer renderer;

			public Material defaultMaterial;

			public ShadowCastingMode defaultShadowCastingMode;

			public bool ignoreOverlays;

			public bool hideOnDeath;

			public bool Equals(RendererInfo other)
			{
				if ((object)renderer == other.renderer && (object)defaultMaterial == other.defaultMaterial && object.Equals(defaultShadowCastingMode, other.defaultShadowCastingMode) && object.Equals(ignoreOverlays, other.ignoreOverlays))
				{
					return object.Equals(hideOnDeath, other.hideOnDeath);
				}
				return false;
			}
		}

		[Serializable]
		public struct LightInfo
		{
			public Light light;

			public UnityEngine.Color defaultColor;

			public LightInfo(Light light)
			{
				this.light = light;
				defaultColor = light.color;
			}
		}

		private struct HurtBoxInfo
		{
			public readonly Transform transform;

			public readonly float estimatedRadius;

			public HurtBoxInfo(HurtBox hurtBox)
			{
				transform = hurtBox.transform;
				estimatedRadius = Util.SphereVolumeToRadius(hurtBox.volume);
			}
		}

		private struct ParentedPrefabDisplay
		{
			public ItemIndex itemIndex;

			public EquipmentIndex equipmentIndex;

			public GameObject instance { get; private set; }

			public ItemDisplay itemDisplay { get; private set; }

			public void Apply(CharacterModel characterModel, GameObject prefab, Transform parent, UnityEngine.Vector3 localPosition, UnityEngine.Quaternion localRotation, UnityEngine.Vector3 localScale)
			{
				instance = UnityEngine.Object.Instantiate(prefab.gameObject, parent);
				instance.transform.localPosition = localPosition;
				instance.transform.localRotation = localRotation;
				instance.transform.localScale = localScale;
				LimbMatcher component = instance.GetComponent<LimbMatcher>();
				if ((bool)component && (bool)characterModel.childLocator)
				{
					component.SetChildLocator(characterModel.childLocator);
				}
				itemDisplay = instance.GetComponent<ItemDisplay>();
			}

			public void Undo()
			{
				if ((bool)instance)
				{
					UnityEngine.Object.Destroy(instance);
					instance = null;
				}
			}
		}

		private struct LimbMaskDisplay
		{
			public ItemIndex itemIndex;

			public EquipmentIndex equipmentIndex;

			public LimbFlags maskValue;

			public void Apply(CharacterModel characterModel, LimbFlags mask)
			{
				maskValue = mask;
				characterModel.limbFlagSet.AddFlags(mask);
			}

			public void Undo(CharacterModel characterModel)
			{
				characterModel.limbFlagSet.RemoveFlags(maskValue);
			}
		}

		[Serializable]
		private class LimbFlagSet
		{
			private readonly byte[] flagCounts = new byte[5];

			private LimbFlags flags;

			private static readonly int[] primeConversionTable;

			public int materialMaskValue { get; private set; }

			public LimbFlagSet()
			{
				materialMaskValue = 1;
			}

			static LimbFlagSet()
			{
				int[] array = new int[5] { 2, 3, 5, 11, 17 };
				primeConversionTable = new int[31];
				for (int i = 0; i < primeConversionTable.Length; i++)
				{
					int num = 1;
					for (int j = 0; j < 5; j++)
					{
						if ((i & (1 << j)) != 0)
						{
							num *= array[j];
						}
					}
					primeConversionTable[i] = num;
				}
			}

			private static int ConvertLimbFlagsToMaterialMask(LimbFlags limbFlags)
			{
				return primeConversionTable[(int)limbFlags];
			}

			public void AddFlags(LimbFlags addedFlags)
			{
				LimbFlags limbFlags = flags;
				flags |= addedFlags;
				for (int i = 0; i < 5; i++)
				{
					if (((uint)addedFlags & (uint)(1 << i)) != 0)
					{
						flagCounts[i]++;
					}
				}
				if (flags != limbFlags)
				{
					materialMaskValue = ConvertLimbFlagsToMaterialMask(flags);
				}
			}

			public void RemoveFlags(LimbFlags removedFlags)
			{
				LimbFlags limbFlags = flags;
				for (int i = 0; i < 5; i++)
				{
					if (((uint)removedFlags & (uint)(1 << i)) != 0 && --flagCounts[i] == 0)
					{
						flags &= (LimbFlags)(~(1 << i));
					}
				}
				if (flags != limbFlags)
				{
					materialMaskValue = ConvertLimbFlagsToMaterialMask(flags);
				}
			}
		}

		public CharacterBody body;

		public ItemDisplayRuleSet itemDisplayRuleSet;

		public bool autoPopulateLightInfos = true;

		public List<Transform> gameObjectActivationTransforms = new List<Transform>();

		[FormerlySerializedAs("rendererInfos")]
		public RendererInfo[] baseRendererInfos = Array.Empty<RendererInfo>();

		public LightInfo[] baseLightInfos = Array.Empty<LightInfo>();

		private ChildLocator childLocator;

		private GameObject goldAffixEffect;

		private HurtBoxInfo[] hurtBoxInfos = Array.Empty<HurtBoxInfo>();

		private Transform coreTransform;

		private static readonly UnityEngine.Color hitFlashBaseColor;

		private static readonly UnityEngine.Color hitFlashShieldColor;

		private static readonly UnityEngine.Color healFlashColor;

		private static readonly float hitFlashDuration;

		private static readonly float healFlashDuration;

		private VisibilityLevel _visibility = VisibilityLevel.Visible;

		private bool _isGhost;

		private bool _isDoppelganger;

		private bool _isEcho;

		[NonSerialized]
		[HideInInspector]
		public int invisibilityCount;

		[NonSerialized]
		public List<TemporaryOverlayInstance> temporaryOverlays = new List<TemporaryOverlayInstance>();

		private bool materialsDirty = true;

		private MaterialPropertyBlock propertyStorage;

		private EquipmentIndex inventoryEquipmentIndex = EquipmentIndex.None;

		private EliteIndex myEliteIndex = EliteIndex.None;

		private float fade = 1f;

		private float firstPersonFade = 1f;

		public float corpseFade = 1f;

		public bool CharacterOnScreen;

		private SkinnedMeshRenderer mainSkinnedMeshRenderer;

		public RendererVisiblity visibilityChecker;

		private static readonly UnityEngine.Color poisonEliteLightColor;

		private static readonly UnityEngine.Color hauntedEliteLightColor;

		private static readonly UnityEngine.Color lunarEliteLightColor;

		private static readonly UnityEngine.Color voidEliteLightColor;

		private UnityEngine.Color? lightColorOverride;

		private Material particleMaterialOverride;

		private GameObject poisonAffixEffect;

		private GameObject hauntedAffixEffect;

		private GameObject voidAffixEffect;

		private float affixHauntedCloakLockoutDuration = 3f;

		private EquipmentIndex currentEquipmentDisplayIndex = EquipmentIndex.None;

		private ItemMask enabledItemDisplays;

		private List<ParentedPrefabDisplay> parentedPrefabDisplays = new List<ParentedPrefabDisplay>();

		private List<LimbMaskDisplay> limbMaskDisplays = new List<LimbMaskDisplay>();

		private LimbFlagSet limbFlagSet = new LimbFlagSet();

		public static Material revealedMaterial;

		public static Material cloakedMaterial;

		public static Material ghostMaterial;

		public static Material bellBuffMaterial;

		public static Material wolfhatMaterial;

		public static Material energyShieldMaterial;

		public static Material fullCritMaterial;

		public static Material beetleJuiceMaterial;

		public static Material brittleMaterial;

		public static Material clayGooMaterial;

		public static Material slow80Material;

		public static Material immuneMaterial;

		public static Material elitePoisonOverlayMaterial;

		public static Material elitePoisonParticleReplacementMaterial;

		public static Material eliteHauntedOverlayMaterial;

		public static Material eliteJustHauntedOverlayMaterial;

		public static Material eliteHauntedParticleReplacementMaterial;

		public static Material eliteLunarParticleReplacementMaterial;

		public static Material eliteVoidParticleReplacementMaterial;

		public static Material eliteVoidOverlayMaterial;

		public static Material weakMaterial;

		public static Material pulverizedMaterial;

		public static Material doppelgangerMaterial;

		public static Material ghostParticleReplacementMaterial;

		public static Material lunarGolemShieldMaterial;

		public static Material echoMaterial;

		public static Material gummyCloneMaterial;

		public static Material voidSurvivorCorruptMaterial;

		public static Material voidShieldMaterial;

		public static Material growthNectarMaterial;

		public static Material eliteAurelioniteAffixOverlay;

		public static Material yesChefHeatMaterial;

		private static readonly int maxOverlays;

		private Material[] currentOverlays = new Material[maxOverlays];

		private int activeOverlayCount;

		private bool wasPreviouslyClayGooed;

		private bool wasPreviouslyHaunted;

		private RtpcSetter rtpcEliteEnemy;

		private int shaderEliteRampIndex = -1;

		private bool eliteChanged;

		public int activeOverlays;

		public int oldOverlays;

		public float hitFlashValue;

		public float healFlashValue;

		public float oldHit;

		public float oldHeal;

		public float oldFade;

		private EliteIndex oldEliteIndex = EliteIndex.None;

		public bool forceUpdate;

		private static Material[][] sharedMaterialArrays;

		private static readonly int maxMaterials;

		public VisibilityLevel visibility
		{
			get
			{
				return _visibility;
			}
			set
			{
				if (_visibility != value)
				{
					_visibility = value;
					materialsDirty = true;
				}
			}
		}

		public bool isGhost
		{
			get
			{
				return _isGhost;
			}
			set
			{
				if (_isGhost != value)
				{
					_isGhost = value;
					materialsDirty = true;
				}
			}
		}

		public bool isDoppelganger
		{
			get
			{
				return _isDoppelganger;
			}
			set
			{
				if (_isDoppelganger != value)
				{
					_isDoppelganger = value;
					materialsDirty = true;
				}
			}
		}

		public bool isEcho
		{
			get
			{
				return _isEcho;
			}
			set
			{
				if (_isEcho != value)
				{
					_isEcho = value;
					materialsDirty = true;
				}
			}
		}

		private void Awake()
		{
			enabledItemDisplays = ItemMask.Rent();
			childLocator = GetComponent<ChildLocator>();
			HurtBoxGroup component = GetComponent<HurtBoxGroup>();
			coreTransform = base.transform;
			if ((bool)component)
			{
				coreTransform = component.mainHurtBox?.transform ?? coreTransform;
				HurtBox[] hurtBoxes = component.hurtBoxes;
				if (hurtBoxes.Length != 0)
				{
					hurtBoxInfos = new HurtBoxInfo[hurtBoxes.Length];
					for (int i = 0; i < hurtBoxes.Length; i++)
					{
						hurtBoxInfos[i] = new HurtBoxInfo(hurtBoxes[i]);
					}
				}
			}
			propertyStorage = new MaterialPropertyBlock();
			RendererInfo[] array = baseRendererInfos;
			for (int j = 0; j < array.Length; j++)
			{
				RendererInfo rendererInfo = array[j];
				if (rendererInfo.renderer is SkinnedMeshRenderer)
				{
					mainSkinnedMeshRenderer = (SkinnedMeshRenderer)rendererInfo.renderer;
					break;
				}
			}
			if ((bool)body && Util.IsPrefab(body.gameObject) && !Util.IsPrefab(base.gameObject))
			{
				body = null;
			}
		}

		private void Start()
		{
			forceUpdate = true;
			visibility = VisibilityLevel.Invisible;
			UpdateMaterials();
		}

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			if ((object)body != null)
			{
				rtpcEliteEnemy = new RtpcSetter("eliteEnemy", body.gameObject);
				body.onInventoryChanged += OnInventoryChanged;
			}
		}

		private void OnDisable()
		{
			InstanceUpdate();
			if ((object)body != null)
			{
				body.onInventoryChanged -= OnInventoryChanged;
			}
			InstanceTracker.Remove(this);
		}

		public void SetVisible(bool visible)
		{
			if ((bool)body)
			{
				body.CharacterIsVisible = (CharacterOnScreen = visible);
			}
		}

		private void OnDestroy()
		{
			ItemMask.Return(enabledItemDisplays);
		}

		private void OnInventoryChanged()
		{
			if ((bool)body)
			{
				Inventory inventory = body.inventory;
				if ((bool)inventory)
				{
					UpdateItemDisplay(inventory);
					inventoryEquipmentIndex = inventory.GetEquipmentIndex();
					SetEquipmentDisplay(inventoryEquipmentIndex);
					forceUpdate = true;
				}
			}
		}

		private void InstanceUpdate()
		{
			if (isGhost)
			{
				particleMaterialOverride = ghostParticleReplacementMaterial;
			}
			else if (myEliteIndex == RoR2Content.Elites.Poison.eliteIndex)
			{
				lightColorOverride = poisonEliteLightColor;
				particleMaterialOverride = elitePoisonParticleReplacementMaterial;
			}
			else if (myEliteIndex == RoR2Content.Elites.Haunted.eliteIndex)
			{
				lightColorOverride = hauntedEliteLightColor;
				particleMaterialOverride = eliteHauntedParticleReplacementMaterial;
			}
			else if (myEliteIndex == RoR2Content.Elites.Lunar.eliteIndex)
			{
				lightColorOverride = lunarEliteLightColor;
				particleMaterialOverride = eliteLunarParticleReplacementMaterial;
			}
			else if (myEliteIndex == DLC1Content.Elites.Void.eliteIndex && (bool)body && body.healthComponent.alive)
			{
				lightColorOverride = voidEliteLightColor;
				particleMaterialOverride = eliteVoidParticleReplacementMaterial;
			}
			else
			{
				lightColorOverride = null;
				particleMaterialOverride = null;
			}
			UpdateGoldAffix();
			UpdatePoisonAffix();
			UpdateHauntedAffix();
			UpdateVoidAffix();
			UpdateLights();
		}

		private void UpdateLights()
		{
			LightInfo[] array = baseLightInfos;
			if (array.Length == 0)
			{
				return;
			}
			if (lightColorOverride.HasValue)
			{
				UnityEngine.Color value = lightColorOverride.Value;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].light.color = value;
				}
			}
			else
			{
				for (int j = 0; j < array.Length; j++)
				{
					ref LightInfo reference = ref array[j];
					reference.light.color = reference.defaultColor;
				}
			}
		}

		[InitDuringStartup]
		private static void Init()
		{
			RoR2Application.onLateUpdate += StaticUpdate;
		}

		private static void StaticUpdate()
		{
			foreach (CharacterModel instances in InstanceTracker.GetInstancesList<CharacterModel>())
			{
				instances.InstanceUpdate();
			}
		}

		public void AddTempOverlay(TemporaryOverlayInstance overlay)
		{
			temporaryOverlays.Add(overlay);
			materialsDirty = true;
		}

		public void RemoveTempOverlay(TemporaryOverlayInstance overlay)
		{
			temporaryOverlays.Remove(overlay);
			materialsDirty = true;
		}

		private bool IsCurrentEliteType(EliteDef eliteDef)
		{
			if ((object)eliteDef == null || eliteDef.eliteIndex == EliteIndex.None)
			{
				return false;
			}
			return eliteDef.eliteIndex == myEliteIndex;
		}

		private void UpdateGoldAffix()
		{
			if (IsCurrentEliteType(JunkContent.Elites.Gold) == (bool)goldAffixEffect)
			{
				return;
			}
			if (!goldAffixEffect)
			{
				goldAffixEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/GoldAffixEffect"), base.transform);
				ParticleSystem.ShapeModule shape = goldAffixEffect.GetComponent<ParticleSystem>().shape;
				if ((bool)mainSkinnedMeshRenderer)
				{
					shape.shapeType = ParticleSystemShapeType.SkinnedMeshRenderer;
					shape.skinnedMeshRenderer = mainSkinnedMeshRenderer;
				}
			}
			else
			{
				UnityEngine.Object.Destroy(goldAffixEffect);
				goldAffixEffect = null;
			}
		}

		private void UpdatePoisonAffix()
		{
			if ((myEliteIndex == RoR2Content.Elites.Poison.eliteIndex && body.healthComponent.alive) == (bool)poisonAffixEffect)
			{
				return;
			}
			if (!poisonAffixEffect)
			{
				poisonAffixEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/PoisonAffixEffect"), base.transform);
				if ((bool)mainSkinnedMeshRenderer)
				{
					JitterBones[] components = poisonAffixEffect.GetComponents<JitterBones>();
					for (int i = 0; i < components.Length; i++)
					{
						components[i].skinnedMeshRenderer = mainSkinnedMeshRenderer;
					}
				}
			}
			else
			{
				UnityEngine.Object.Destroy(poisonAffixEffect);
				poisonAffixEffect = null;
			}
		}

		private void UpdateHauntedAffix()
		{
			if ((myEliteIndex == RoR2Content.Elites.Haunted.eliteIndex && body.healthComponent.alive) == (bool)hauntedAffixEffect)
			{
				return;
			}
			if (!hauntedAffixEffect)
			{
				hauntedAffixEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/HauntedAffixEffect"), base.transform);
				if ((bool)mainSkinnedMeshRenderer)
				{
					JitterBones[] components = hauntedAffixEffect.GetComponents<JitterBones>();
					for (int i = 0; i < components.Length; i++)
					{
						components[i].skinnedMeshRenderer = mainSkinnedMeshRenderer;
					}
				}
			}
			else
			{
				UnityEngine.Object.Destroy(hauntedAffixEffect);
				hauntedAffixEffect = null;
			}
		}

		private void UpdateVoidAffix()
		{
			if ((myEliteIndex == DLC1Content.Elites.Void.eliteIndex && body.healthComponent.alive) == (bool)voidAffixEffect)
			{
				return;
			}
			if (!voidAffixEffect)
			{
				voidAffixEffect = UnityEngine.Object.Instantiate(Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/EliteVoid/VoidAffixEffect.prefab").WaitForCompletion(), base.transform);
				if ((bool)mainSkinnedMeshRenderer)
				{
					JitterBones[] components = voidAffixEffect.GetComponents<JitterBones>();
					for (int i = 0; i < components.Length; i++)
					{
						components[i].skinnedMeshRenderer = mainSkinnedMeshRenderer;
					}
				}
			}
			else
			{
				UnityEngine.Object.Destroy(voidAffixEffect);
				voidAffixEffect = null;
			}
		}

		private void OnValidate()
		{
			if (Application.isPlaying)
			{
				return;
			}
			for (int i = 0; i < baseLightInfos.Length; i++)
			{
				ref LightInfo reference = ref baseLightInfos[i];
				if ((bool)reference.light)
				{
					reference.defaultColor = reference.light.color;
				}
			}
			_ = (bool)itemDisplayRuleSet;
			if (autoPopulateLightInfos)
			{
				LightInfo[] first = (from light in GetComponentsInChildren<Light>()
					select new LightInfo(light)).ToArray();
				if (!first.SequenceEqual(baseLightInfos))
				{
					baseLightInfos = first;
				}
			}
		}

		private static void RefreshObstructorsForCamera(CameraRigController cameraRigController)
		{
			UnityEngine.Vector3 position = cameraRigController.transform.position;
			foreach (CharacterModel instances in InstanceTracker.GetInstancesList<CharacterModel>())
			{
				if (cameraRigController.enableFading)
				{
					float nearestHurtBoxDistance = instances.GetNearestHurtBoxDistance(position);
					instances.fade = Mathf.Clamp01(Util.Remap(nearestHurtBoxDistance, cameraRigController.fadeStartDistance, cameraRigController.fadeEndDistance, 0f, 1f));
				}
				else
				{
					instances.fade = 1f;
				}
			}
		}

		private float GetNearestHurtBoxDistance(UnityEngine.Vector3 cameraPosition)
		{
			float num = float.PositiveInfinity;
			for (int i = 0; i < hurtBoxInfos.Length; i++)
			{
				float num2 = UnityEngine.Vector3.Distance(hurtBoxInfos[i].transform.position, cameraPosition) - hurtBoxInfos[i].estimatedRadius;
				if (num2 < num)
				{
					num = Mathf.Min(num2, num);
				}
			}
			return num;
		}

		private void UpdateForCamera(CameraRigController cameraRigController)
		{
			VisibilityLevel num = visibility;
			visibility = VisibilityLevel.Visible;
			float target = 1f;
			if ((bool)body)
			{
				if ((object)cameraRigController.firstPersonTarget == body.gameObject)
				{
					target = 0f;
				}
				visibility = body.GetVisibilityLevel(cameraRigController.targetTeamIndex);
			}
			float num2 = 0.25f;
			if ((bool)cameraRigController.targetParams && cameraRigController.targetParams.currentCameraParamsData.overrideFirstPersonFadeDuration > 0f)
			{
				num2 = cameraRigController.targetParams.currentCameraParamsData.overrideFirstPersonFadeDuration;
			}
			firstPersonFade = Mathf.MoveTowards(firstPersonFade, target, Time.deltaTime / num2);
			fade *= firstPersonFade * corpseFade;
			if (fade <= 0f || invisibilityCount > 0)
			{
				visibility = VisibilityLevel.Invisible;
			}
			if (num != visibility)
			{
				forceUpdate = true;
			}
			bool flag = forceUpdate;
			if (!flag)
			{
				for (int i = 0; i < baseRendererInfos.Length; i++)
				{
					if ((bool)baseRendererInfos[i].renderer && baseRendererInfos[i].renderer.isVisible)
					{
						flag = true;
						break;
					}
				}
			}
			if (flag)
			{
				UpdateOverlays();
				if (materialsDirty)
				{
					UpdateMaterials();
					materialsDirty = false;
				}
			}
		}

		static CharacterModel()
		{
			hitFlashBaseColor = new Color32(193, 108, 51, byte.MaxValue);
			hitFlashShieldColor = new Color32(132, 159, byte.MaxValue, byte.MaxValue);
			healFlashColor = new Color32(104, 196, 49, byte.MaxValue);
			hitFlashDuration = 0.15f;
			healFlashDuration = 0.35f;
			poisonEliteLightColor = new Color32(90, byte.MaxValue, 193, 204);
			hauntedEliteLightColor = new Color32(152, 228, 217, 204);
			lunarEliteLightColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 127);
			voidEliteLightColor = new Color32(151, 78, 132, 204);
			maxOverlays = 6;
			maxMaterials = 1 + maxOverlays;
			SceneCamera.onSceneCameraPreRender += OnSceneCameraPreRender;
		}

		private static void OnSceneCameraPreRender(SceneCamera sceneCamera)
		{
			if ((bool)sceneCamera.cameraRigController)
			{
				RefreshObstructorsForCamera(sceneCamera.cameraRigController);
			}
			if (!sceneCamera.cameraRigController)
			{
				return;
			}
			foreach (CharacterModel instances in InstanceTracker.GetInstancesList<CharacterModel>())
			{
				instances.UpdateForCamera(sceneCamera.cameraRigController);
			}
		}

		private void InstantiateDisplayRuleGroup(DisplayRuleGroup displayRuleGroup, ItemIndex itemIndex, EquipmentIndex equipmentIndex)
		{
			if (displayRuleGroup.rules == null)
			{
				return;
			}
			for (int i = 0; i < displayRuleGroup.rules.Length; i++)
			{
				ItemDisplayRule itemDisplayRule = displayRuleGroup.rules[i];
				switch (itemDisplayRule.ruleType)
				{
				case ItemDisplayRuleType.ParentedPrefab:
					if ((bool)childLocator)
					{
						Transform transform = childLocator.FindChild(itemDisplayRule.childName);
						if ((bool)transform)
						{
							ParentedPrefabDisplay parentedPrefabDisplay = default(ParentedPrefabDisplay);
							parentedPrefabDisplay.itemIndex = itemIndex;
							parentedPrefabDisplay.equipmentIndex = equipmentIndex;
							ParentedPrefabDisplay item2 = parentedPrefabDisplay;
							item2.Apply(this, itemDisplayRule.followerPrefab, transform, itemDisplayRule.localPos, UnityEngine.Quaternion.Euler(itemDisplayRule.localAngles), itemDisplayRule.localScale);
							parentedPrefabDisplays.Add(item2);
						}
					}
					break;
				case ItemDisplayRuleType.LimbMask:
				{
					LimbMaskDisplay limbMaskDisplay = default(LimbMaskDisplay);
					limbMaskDisplay.itemIndex = itemIndex;
					limbMaskDisplay.equipmentIndex = equipmentIndex;
					LimbMaskDisplay item = limbMaskDisplay;
					item.Apply(this, itemDisplayRule.limbMask);
					limbMaskDisplays.Add(item);
					break;
				}
				}
			}
		}

		private void SetEquipmentDisplay(EquipmentIndex newEquipmentIndex)
		{
			if (newEquipmentIndex == currentEquipmentDisplayIndex)
			{
				return;
			}
			for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--)
			{
				if (parentedPrefabDisplays[num].equipmentIndex != EquipmentIndex.None)
				{
					parentedPrefabDisplays[num].Undo();
					parentedPrefabDisplays.RemoveAt(num);
				}
			}
			for (int num2 = limbMaskDisplays.Count - 1; num2 >= 0; num2--)
			{
				if (limbMaskDisplays[num2].equipmentIndex != EquipmentIndex.None)
				{
					limbMaskDisplays[num2].Undo(this);
					limbMaskDisplays.RemoveAt(num2);
				}
			}
			currentEquipmentDisplayIndex = newEquipmentIndex;
			if ((bool)itemDisplayRuleSet)
			{
				DisplayRuleGroup equipmentDisplayRuleGroup = itemDisplayRuleSet.GetEquipmentDisplayRuleGroup(newEquipmentIndex);
				InstantiateDisplayRuleGroup(equipmentDisplayRuleGroup, ItemIndex.None, newEquipmentIndex);
			}
		}

		private void EnableItemDisplay(ItemIndex itemIndex)
		{
			if (!enabledItemDisplays.Contains(itemIndex))
			{
				enabledItemDisplays.Add(itemIndex);
				if ((bool)itemDisplayRuleSet)
				{
					DisplayRuleGroup itemDisplayRuleGroup = itemDisplayRuleSet.GetItemDisplayRuleGroup(itemIndex);
					InstantiateDisplayRuleGroup(itemDisplayRuleGroup, itemIndex, EquipmentIndex.None);
				}
			}
		}

		public void DisableAllItemDisplays()
		{
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				DisableItemDisplay(itemIndex);
			}
		}

		private void DisableItemDisplay(ItemIndex itemIndex)
		{
			if (!enabledItemDisplays.Contains(itemIndex))
			{
				return;
			}
			enabledItemDisplays.Remove(itemIndex);
			for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--)
			{
				if (parentedPrefabDisplays[num].itemIndex == itemIndex)
				{
					parentedPrefabDisplays[num].Undo();
					parentedPrefabDisplays.RemoveAt(num);
				}
			}
			for (int num2 = limbMaskDisplays.Count - 1; num2 >= 0; num2--)
			{
				if (limbMaskDisplays[num2].itemIndex == itemIndex)
				{
					limbMaskDisplays[num2].Undo(this);
					limbMaskDisplays.RemoveAt(num2);
				}
			}
		}

		public void UpdateItemDisplay(Inventory inventory)
		{
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				if (inventory.GetItemCount(itemIndex) > 0)
				{
					EnableItemDisplay(itemIndex);
				}
				else
				{
					DisableItemDisplay(itemIndex);
				}
			}
		}

		public void HighlightItemDisplay(ItemIndex itemIndex)
		{
			if (!enabledItemDisplays.Contains(itemIndex))
			{
				return;
			}
			ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(ItemCatalog.GetItemDef(itemIndex).tier);
			GameObject gameObject = null;
			gameObject = ((!itemTierDef || !itemTierDef.highlightPrefab) ? LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/HighlightTier1Item") : itemTierDef.highlightPrefab);
			for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--)
			{
				if (parentedPrefabDisplays[num].itemIndex == itemIndex)
				{
					GameObject instance = parentedPrefabDisplays[num].instance;
					if ((bool)instance)
					{
						Renderer componentInChildren = instance.GetComponentInChildren<Renderer>();
						if ((bool)componentInChildren && (bool)body)
						{
							HighlightRect.CreateHighlight(body.gameObject, componentInChildren, gameObject);
						}
					}
				}
			}
		}

		public List<GameObject> GetEquipmentDisplayObjects(EquipmentIndex equipmentIndex)
		{
			List<GameObject> list = new List<GameObject>();
			for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--)
			{
				if (parentedPrefabDisplays[num].equipmentIndex == equipmentIndex)
				{
					GameObject instance = parentedPrefabDisplays[num].instance;
					list.Add(instance);
				}
			}
			return list;
		}

		public List<GameObject> GetItemDisplayObjects(ItemIndex itemIndex)
		{
			List<GameObject> list = new List<GameObject>();
			for (int num = parentedPrefabDisplays.Count - 1; num >= 0; num--)
			{
				if (parentedPrefabDisplays[num].itemIndex == itemIndex)
				{
					GameObject instance = parentedPrefabDisplays[num].instance;
					list.Add(instance);
				}
			}
			return list;
		}

		[InitDuringStartup]
		private static void InitMaterials()
		{
			AsyncOperationHandle<Material> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matEliteAurelioniteAffixOverlay");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				eliteAurelioniteAffixOverlay = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matRevealedEffect");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				revealedMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matCloakedEffect");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				cloakedMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matGhostEffect");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				ghostMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matGhostParticleReplacement");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				ghostParticleReplacementMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matWolfhatOverlay");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				wolfhatMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matEnergyShield");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				energyShieldMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matBeetleJuice");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				beetleJuiceMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matBrittle");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				brittleMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matFullCrit");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				fullCritMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matClayGooDebuff");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				clayGooMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matSlow80Debuff");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				slow80Material = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matImmune");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				immuneMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matBellBuff");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				bellBuffMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matElitePoisonOverlay");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				elitePoisonOverlayMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matElitePoisonParticleReplacement");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				elitePoisonParticleReplacementMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matEliteHauntedOverlay");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				eliteHauntedOverlayMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matEliteHauntedParticleReplacement");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				eliteHauntedParticleReplacementMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matEliteJustHauntedOverlay");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				eliteJustHauntedOverlayMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matEliteLunarParticleReplacement");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				eliteLunarParticleReplacementMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matDoppelganger");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				doppelgangerMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matWeakOverlay");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				weakMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matPulverizedOverlay");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				pulverizedMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matLunarGolemShield");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				lunarGolemShieldMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matEcho");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				echoMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matGummyClone");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				gummyCloneMaterial = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Material>("Materials/matGrowthNectarGlow");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				growthNectarMaterial = x.Result;
			};
			asyncOperationHandle = Addressables.LoadAssetAsync<Material>("RoR2/DLC1/EliteVoid/matEliteVoidParticleReplacement.mat");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				eliteVoidParticleReplacementMaterial = x.Result;
			};
			asyncOperationHandle = Addressables.LoadAssetAsync<Material>("RoR2/DLC1/EliteVoid/matEliteVoidOverlay.mat");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				eliteVoidOverlayMaterial = x.Result;
			};
			asyncOperationHandle = Addressables.LoadAssetAsync<Material>("RoR2/DLC1/VoidSurvivor/matVoidSurvivorCorruptOverlay.mat");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				voidSurvivorCorruptMaterial = x.Result;
			};
			asyncOperationHandle = Addressables.LoadAssetAsync<Material>("RoR2/DLC1/MissileVoid/matEnergyShieldVoid.mat");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				voidShieldMaterial = x.Result;
			};
			asyncOperationHandle = Addressables.LoadAssetAsync<Material>("RoR2/DLC2/Chef/matYesChefOverlay.mat");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Material> x)
			{
				yesChefHeatMaterial = x.Result;
			};
		}

		private bool UpdateOverlayStates()
		{
			oldOverlays = activeOverlays;
			activeOverlays = 0;
			if ((bool)body)
			{
				bool condition2 = body.HasBuff(RoR2Content.Buffs.ClayGoo);
				Inventory inventory = body.inventory;
				isGhost = (object)inventory != null && inventory.GetItemCount(RoR2Content.Items.Ghost) > 0;
				myEliteIndex = EquipmentCatalog.GetEquipmentDef(inventoryEquipmentIndex)?.passiveBuffDef?.eliteDef?.eliteIndex ?? EliteIndex.None;
				oldHit = hitFlashValue;
				oldHeal = healFlashValue;
				if ((bool)body.healthComponent)
				{
					hitFlashValue = Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHit / hitFlashDuration);
					healFlashValue = Mathf.Pow(Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHeal / healFlashDuration), 0.5f);
				}
				eliteChanged = myEliteIndex != oldEliteIndex;
				int num = 0;
				SetOverlayFlag(num++, eliteChanged);
				SetOverlayFlag(num++, hitFlashValue != oldHit || healFlashValue != oldHeal);
				SetOverlayFlag(num++, isGhost);
				SetOverlayFlag(num++, condition2);
				SetOverlayFlag(num++, myEliteIndex == RoR2Content.Elites.Poison.eliteIndex || body.HasBuff(RoR2Content.Buffs.HealingDisabled));
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Weak));
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.FullCrit));
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.AttackSpeedOnCrit));
				SetOverlayFlag(num++, (bool)body.healthComponent && body.healthComponent.shield > 0f);
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.BeetleJuice));
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Immune));
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Slow80));
				SetOverlayFlag(num++, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.LunarDagger) > 0);
				SetOverlayFlag(num++, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0);
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.AffixHaunted));
				SetOverlayFlag(num++, body.HasBuff(DLC1Content.Buffs.EliteVoid) && (bool)body.healthComponent && body.healthComponent.alive);
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.Pulverized));
				SetOverlayFlag(num++, body.HasBuff(RoR2Content.Buffs.LunarShell));
				SetOverlayFlag(num++, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.SummonedEcho) > 0);
				SetOverlayFlag(num++, IsGummyClone());
				SetOverlayFlag(num++, body.HasBuff(DLC1Content.Buffs.VoidSurvivorCorruptMode));
				SetOverlayFlag(num++, IsAurelioniteAffix());
				SetOverlayFlag(num++, body.HasBuff(DLC2Content.Buffs.BoostAllStatsBuff));
				SetOverlayFlag(num++, body.HasBuff(DLC2Content.Buffs.boostedFireEffect));
				for (int i = 0; i < baseRendererInfos.Length; i++)
				{
					SetOverlayFlag(num + i, baseRendererInfos[i].ignoreOverlays);
				}
			}
			bool flag = fade != oldFade;
			oldEliteIndex = myEliteIndex;
			oldFade = fade;
			return oldOverlays != activeOverlays || flag;
			void SetOverlayFlag(int index, bool condition)
			{
				if (condition)
				{
					activeOverlays |= 1 << index;
				}
			}
		}

		private void UpdateOverlays()
		{
			if (visibility == VisibilityLevel.Invisible || (!UpdateOverlayStates() && !forceUpdate))
			{
				return;
			}
			forceUpdate = false;
			for (int i = 0; i < activeOverlayCount; i++)
			{
				currentOverlays[i] = null;
			}
			activeOverlayCount = 0;
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(inventoryEquipmentIndex);
			myEliteIndex = equipmentDef?.passiveBuffDef?.eliteDef?.eliteIndex ?? EliteIndex.None;
			shaderEliteRampIndex = equipmentDef?.passiveBuffDef?.eliteDef?.shaderEliteRampIndex ?? (-1);
			bool flag = false;
			bool flag2 = false;
			if ((bool)body)
			{
				flag = body.HasBuff(RoR2Content.Buffs.ClayGoo);
				flag2 = body.HasBuff(RoR2Content.Buffs.AffixHauntedRecipient);
				rtpcEliteEnemy.value = ((myEliteIndex != EliteIndex.None) ? 1f : 0f);
				rtpcEliteEnemy.FlushIfChanged();
				Inventory inventory = body.inventory;
				isGhost = (object)inventory != null && inventory.GetItemCount(RoR2Content.Items.Ghost) > 0;
				Inventory inventory2 = body.inventory;
				isDoppelganger = (object)inventory2 != null && inventory2.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0;
				Inventory inventory3 = body.inventory;
				isEcho = (object)inventory3 != null && inventory3.GetItemCount(RoR2Content.Items.SummonedEcho) > 0;
				Inventory inventory4 = body.inventory;
				bool flag3 = (object)inventory4 != null && inventory4.GetItemCount(DLC1Content.Items.MissileVoid) > 0;
				AddOverlay(ghostMaterial, isGhost);
				AddOverlay(doppelgangerMaterial, isDoppelganger);
				AddOverlay(clayGooMaterial, flag);
				AddOverlay(elitePoisonOverlayMaterial, myEliteIndex == RoR2Content.Elites.Poison.eliteIndex || body.HasBuff(RoR2Content.Buffs.HealingDisabled));
				AddOverlay(eliteHauntedOverlayMaterial, body.HasBuff(RoR2Content.Buffs.AffixHaunted));
				AddOverlay(eliteVoidOverlayMaterial, body.HasBuff(DLC1Content.Buffs.EliteVoid) && (bool)body.healthComponent && body.healthComponent.alive);
				AddOverlay(pulverizedMaterial, body.HasBuff(RoR2Content.Buffs.Pulverized));
				AddOverlay(weakMaterial, body.HasBuff(RoR2Content.Buffs.Weak));
				AddOverlay(fullCritMaterial, body.HasBuff(RoR2Content.Buffs.FullCrit));
				AddOverlay(wolfhatMaterial, body.HasBuff(RoR2Content.Buffs.AttackSpeedOnCrit));
				AddOverlay(flag3 ? voidShieldMaterial : energyShieldMaterial, (bool)body.healthComponent && body.healthComponent.shield > 0f);
				AddOverlay(beetleJuiceMaterial, body.HasBuff(RoR2Content.Buffs.BeetleJuice));
				AddOverlay(immuneMaterial, body.HasBuff(RoR2Content.Buffs.Immune));
				AddOverlay(slow80Material, body.HasBuff(RoR2Content.Buffs.Slow80));
				AddOverlay(brittleMaterial, (bool)body.inventory && body.inventory.GetItemCount(RoR2Content.Items.LunarDagger) > 0);
				AddOverlay(lunarGolemShieldMaterial, body.HasBuff(RoR2Content.Buffs.LunarShell));
				AddOverlay(echoMaterial, isEcho);
				AddOverlay(gummyCloneMaterial, IsGummyClone());
				AddOverlay(voidSurvivorCorruptMaterial, body.HasBuff(DLC1Content.Buffs.VoidSurvivorCorruptMode));
				AddOverlay(growthNectarMaterial, body.HasBuff(DLC2Content.Buffs.BoostAllStatsBuff));
				AddOverlay(eliteAurelioniteAffixOverlay, IsAurelioniteAffix());
				AddOverlay(lunarGolemShieldMaterial, body.HasBuff(DLC2Content.Buffs.EliteBead));
				AddOverlay(brittleMaterial, body.HasBuff(DLC2Content.Buffs.EliteBeadCorruption));
				AddOverlay(yesChefHeatMaterial, body.HasBuff(DLC2Content.Buffs.boostedFireEffect));
			}
			if (wasPreviouslyClayGooed && !flag)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(base.gameObject);
				temporaryOverlayInstance.duration = 0.6f;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = clayGooMaterial;
				temporaryOverlayInstance.AddToCharacterModel(this);
			}
			if (wasPreviouslyHaunted != flag2)
			{
				TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(base.gameObject);
				temporaryOverlayInstance2.duration = 0.5f;
				temporaryOverlayInstance2.animateShaderAlpha = true;
				temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
				temporaryOverlayInstance2.destroyComponentOnEnd = true;
				temporaryOverlayInstance2.originalMaterial = eliteJustHauntedOverlayMaterial;
				temporaryOverlayInstance2.AddToCharacterModel(this);
			}
			wasPreviouslyClayGooed = flag;
			wasPreviouslyHaunted = flag2;
			for (int j = 0; j < temporaryOverlays.Count; j++)
			{
				if (activeOverlayCount >= maxOverlays)
				{
					break;
				}
				currentOverlays[activeOverlayCount++] = temporaryOverlays[j].materialInstance;
			}
			wasPreviouslyClayGooed = flag;
			wasPreviouslyHaunted = flag2;
			materialsDirty = true;
			void AddOverlay(Material overlayMaterial, bool condition)
			{
				if (activeOverlayCount < maxOverlays && condition)
				{
					currentOverlays[activeOverlayCount++] = overlayMaterial;
				}
			}
		}

		[InitDuringStartup]
		private static void InitSharedMaterialsArrays()
		{
			sharedMaterialArrays = new Material[maxMaterials + 1][];
			if (maxMaterials > 0)
			{
				sharedMaterialArrays[0] = Array.Empty<Material>();
				for (int i = 1; i < sharedMaterialArrays.Length; i++)
				{
					sharedMaterialArrays[i] = new Material[i];
				}
			}
		}

		private void UpdateRendererMaterials(Renderer renderer, Material defaultMaterial, bool ignoreOverlays)
		{
			Material material = null;
			switch (visibility)
			{
			case VisibilityLevel.Invisible:
				renderer.sharedMaterial = null;
				return;
			case VisibilityLevel.Cloaked:
				if (!ignoreOverlays)
				{
					ignoreOverlays = true;
					material = cloakedMaterial;
				}
				break;
			case VisibilityLevel.Revealed:
				if (!ignoreOverlays)
				{
					material = revealedMaterial;
				}
				break;
			case VisibilityLevel.Visible:
				material = (ignoreOverlays ? (particleMaterialOverride ? particleMaterialOverride : defaultMaterial) : ((!isDoppelganger) ? ((!isGhost) ? ((!IsGummyClone()) ? ((!IsAurelioniteAffix()) ? defaultMaterial : eliteAurelioniteAffixOverlay) : gummyCloneMaterial) : ghostMaterial) : doppelgangerMaterial));
				break;
			}
			int num = ((!ignoreOverlays) ? activeOverlayCount : 0);
			if ((bool)material)
			{
				num++;
			}
			Material material2 = null;
			Material[] array = sharedMaterialArrays[num];
			int num2 = 0;
			if ((bool)material)
			{
				array[num2++] = material;
			}
			if (!ignoreOverlays)
			{
				for (int i = 0; i < activeOverlayCount; i++)
				{
					array[num2++] = currentOverlays[i];
				}
			}
			if (material2 != null)
			{
				array[num2++] = material2;
			}
			if (num2 != array.Length)
			{
				UnityEngine.Debug.LogError("Materials are going to be pink or something!?");
			}
			renderer.sharedMaterials = array;
		}

		private void UpdateMaterials()
		{
			UnityEngine.Color value = UnityEngine.Color.black;
			if ((bool)body && (bool)body.healthComponent)
			{
				float num = Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHit / hitFlashDuration);
				float num2 = Mathf.Pow(Mathf.Clamp01(1f - body.healthComponent.timeSinceLastHeal / healFlashDuration), 0.5f);
				value = ((!(num2 > num)) ? (((body.healthComponent.shield > 0f) ? hitFlashShieldColor : hitFlashBaseColor) * num) : (healFlashColor * num2));
			}
			if (visibility == VisibilityLevel.Invisible)
			{
				for (int num3 = baseRendererInfos.Length - 1; num3 >= 0; num3--)
				{
					RendererInfo rendererInfo = baseRendererInfos[num3];
					rendererInfo.renderer.shadowCastingMode = ShadowCastingMode.Off;
					rendererInfo.renderer.enabled = false;
				}
			}
			else
			{
				for (int num4 = baseRendererInfos.Length - 1; num4 >= 0; num4--)
				{
					RendererInfo rendererInfo2 = baseRendererInfos[num4];
					Renderer renderer = rendererInfo2.renderer;
					UpdateRendererMaterials(renderer, baseRendererInfos[num4].defaultMaterial, baseRendererInfos[num4].ignoreOverlays);
					renderer.shadowCastingMode = rendererInfo2.defaultShadowCastingMode;
					renderer.enabled = true;
					renderer.GetPropertyBlock(propertyStorage);
					propertyStorage.SetColor(CommonShaderProperties._FlashColor, value);
					propertyStorage.SetFloat(CommonShaderProperties._EliteIndex, shaderEliteRampIndex + 1);
					propertyStorage.SetInt(CommonShaderProperties._LimbPrimeMask, limbFlagSet.materialMaskValue);
					propertyStorage.SetFloat(CommonShaderProperties._Fade, fade);
					renderer.SetPropertyBlock(propertyStorage);
				}
			}
			for (int i = 0; i < parentedPrefabDisplays.Count; i++)
			{
				ItemDisplay itemDisplay = parentedPrefabDisplays[i].itemDisplay;
				itemDisplay.SetVisibilityLevel(visibility);
				for (int j = 0; j < itemDisplay.rendererInfos.Length; j++)
				{
					Renderer renderer2 = itemDisplay.rendererInfos[j].renderer;
					renderer2.GetPropertyBlock(propertyStorage);
					propertyStorage.SetColor(CommonShaderProperties._FlashColor, value);
					propertyStorage.SetFloat(CommonShaderProperties._Fade, fade);
					renderer2.SetPropertyBlock(propertyStorage);
				}
			}
		}

		private bool IsGummyClone()
		{
			CharacterBody characterBody = body;
			if ((object)characterBody == null)
			{
				return false;
			}
			return characterBody.inventory?.GetItemCount(DLC1Content.Items.GummyCloneIdentifier) > 0;
		}

		private bool IsAurelioniteAffix()
		{
			bool result = false;
			if ((bool)body)
			{
				result = body.HasBuff(DLC2Content.Buffs.EliteAurelionite);
			}
			return result;
		}

		public void OnDeath()
		{
			for (int i = 0; i < parentedPrefabDisplays.Count; i++)
			{
				parentedPrefabDisplays[i].itemDisplay.OnDeath();
			}
			InstanceUpdate();
			UpdateOverlays();
			UpdateMaterials();
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class CharacterMotor : BaseCharacterController, IPhysMotor, ILifeBehavior, IDisplacementReceiver, ICharacterGravityParameterProvider, ICharacterFlightParameterProvider
	{
		[Serializable]
		public struct HitGroundInfo
		{
			public UnityEngine.Vector3 velocity;

			public UnityEngine.Vector3 position;

			public bool isValidForEffect;

			public override string ToString()
			{
				return $"velocity={velocity} position={position}";
			}
		}

		public delegate void HitGroundDelegate(ref HitGroundInfo hitGroundInfo);

		public struct MovementHitInfo
		{
			public UnityEngine.Vector3 velocity;

			public Collider hitCollider;
		}

		public delegate void MovementHitDelegate(ref MovementHitInfo movementHitInfo);

		[HideInInspector]
		public float walkSpeedPenaltyCoefficient = 1f;

		[Tooltip("The character direction component to supply a move vector to.")]
		public CharacterDirection characterDirection;

		[Tooltip("Whether or not a move vector supplied to this component can cause movement. Use this when the object is driven by root motion.")]
		public bool muteWalkMotion;

		[Tooltip("The mass of this character.")]
		public float mass = 1f;

		[Tooltip("The air control value of this character as a fraction of ground control.")]
		public float airControl = 0.25f;

		[Tooltip("Disables Air Control for things like jumppads")]
		public bool disableAirControlUntilCollision;

		[Tooltip("Auto-assigns parameters skin width, slope angle, and step offset as a function of the Character Motor's radius and height")]
		public bool generateParametersOnAwake = true;

		[Tooltip("Ignores JumpVolumes")]
		public bool doNotTriggerJumpVolumes;

		private NetworkIdentity networkIdentity;

		private CharacterBody body;

		private CapsuleCollider capsuleCollider;

		private static readonly bool enableMotorWithoutAuthority;

		private bool alive = true;

		private const float restDuration = 1f;

		private const float restVelocityThreshold = 0.025f;

		private const float restVelocityThresholdSqr = 0.00062500004f;

		public const float slipStartAngle = 70f;

		public const float slipEndAngle = 55f;

		private float restStopwatch;

		private UnityEngine.Vector3 previousPosition;

		private bool isAirControlForced;

		[NonSerialized]
		public int jumpCount;

		[NonSerialized]
		public bool netIsGrounded;

		[NonSerialized]
		public UnityEngine.Vector3 netGroundNormal;

		[NonSerialized]
		public UnityEngine.Vector3 velocity;

		private UnityEngine.Vector3 lastVelocity;

		[NonSerialized]
		public UnityEngine.Vector3 rootMotion;

		private UnityEngine.Vector3 _moveDirection;

		private static readonly FloatConVar cvCMotorSafeCollisionStepThreshold;

		private int _safeCollisionEnableCount;

		[SerializeField]
		[Tooltip("Determins how gravity affects this character.")]
		private CharacterGravityParameters _gravityParameters;

		[Tooltip("Determines whether this character has three-dimensional or two-dimensional movement capabilities.")]
		[SerializeField]
		private CharacterFlightParameters _flightParameters;

		private static int kRpcRpcApplyForceImpulse;

		private static int kRpcRpcOnHitGroundSFX;

		private static int kCmdCmdReportHitGround;

		public float walkSpeed => body.moveSpeed * walkSpeedPenaltyCoefficient;

		public float acceleration => body.acceleration;

		public bool atRest => restStopwatch > 1f;

		public bool hasEffectiveAuthority { get; private set; }

		public UnityEngine.Vector3 estimatedGroundNormal
		{
			get
			{
				if (!hasEffectiveAuthority)
				{
					return netGroundNormal;
				}
				return base.Motor.GroundingStatus.GroundNormal;
			}
		}

		private bool canWalk
		{
			get
			{
				if (!muteWalkMotion)
				{
					return alive;
				}
				return false;
			}
		}

		public bool isGrounded
		{
			get
			{
				if (!hasEffectiveAuthority)
				{
					return netIsGrounded;
				}
				return base.Motor.GroundingStatus.IsStableOnGround;
			}
		}

		float IPhysMotor.mass => mass;

		UnityEngine.Vector3 IPhysMotor.velocity => velocity;

		UnityEngine.Vector3 IPhysMotor.velocityAuthority
		{
			get
			{
				return velocity;
			}
			set
			{
				velocity = value;
			}
		}

		public UnityEngine.Vector3 moveDirection
		{
			get
			{
				return _moveDirection;
			}
			set
			{
				_moveDirection = value;
			}
		}

		private float slopeLimit
		{
			get
			{
				return base.Motor.MaxStableSlopeAngle;
			}
			set
			{
				base.Motor.MaxStableSlopeAngle = value;
			}
		}

		public float stepOffset
		{
			get
			{
				return base.Motor.MaxStepHeight;
			}
			set
			{
				base.Motor.MaxStepHeight = value;
			}
		}

		public float capsuleHeight => capsuleCollider.height;

		public float capsuleRadius => capsuleCollider.radius;

		public StepHandlingMethod stepHandlingMethod
		{
			get
			{
				return base.Motor.StepHandling = StepHandlingMethod.None;
			}
			set
			{
				base.Motor.StepHandling = value;
			}
		}

		public bool ledgeHandling
		{
			get
			{
				return base.Motor.LedgeAndDenivelationHandling;
			}
			set
			{
				base.Motor.LedgeAndDenivelationHandling = value;
			}
		}

		public bool interactiveRigidbodyHandling
		{
			get
			{
				return base.Motor.InteractiveRigidbodyHandling;
			}
			set
			{
				base.Motor.InteractiveRigidbodyHandling = value;
			}
		}

		public Run.FixedTimeStamp lastGroundedTime { get; private set; } = Run.FixedTimeStamp.negativeInfinity;


		public CharacterGravityParameters gravityParameters
		{
			get
			{
				return _gravityParameters;
			}
			set
			{
				if (!_gravityParameters.Equals(value))
				{
					_gravityParameters = value;
					useGravity = _gravityParameters.CheckShouldUseGravity();
				}
			}
		}

		public bool useGravity { get; private set; }

		public CharacterFlightParameters flightParameters
		{
			get
			{
				return _flightParameters;
			}
			set
			{
				if (!_flightParameters.Equals(value))
				{
					_flightParameters = value;
					isFlying = _flightParameters.CheckShouldUseFlight();
				}
			}
		}

		public bool isFlying { get; private set; }

		[Obsolete("Use '.onHitGroundAuthority' instead, which this is just a backwards-compatibility wrapper for. Or, use '.onHitGroundAuthority' if that is more appropriate to your use case.", false)]
		public event HitGroundDelegate onHitGround
		{
			add
			{
				onHitGroundAuthority += value;
			}
			remove
			{
				onHitGroundAuthority -= value;
			}
		}

		public event HitGroundDelegate onHitGroundAuthority;

		public event Action<CharacterBody> onMotorStart;

		public event MovementHitDelegate onMovementHit;

		private void UpdateInnerMotorEnabled()
		{
			base.Motor.enabled = enableMotorWithoutAuthority || hasEffectiveAuthority;
		}

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
			UpdateInnerMotorEnabled();
		}

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			body = GetComponent<CharacterBody>();
			capsuleCollider = GetComponent<CapsuleCollider>();
		}

		private void Start()
		{
			previousPosition = base.transform.position;
			if (base.Motor == null)
			{
				SetupCharacterMotor(GetComponent<KinematicCharacterMotor>());
			}
			if (base.Motor.AttachedRigidbody != null)
			{
				base.Motor.AttachedRigidbody.mass = mass;
			}
			base.Motor.MaxStableSlopeAngle = 70f;
			base.Motor.MaxStableDenivelationAngle = 55f;
			base.Motor.RebuildCollidableLayers();
			if (generateParametersOnAwake)
			{
				GenerateParameters();
			}
			useGravity = gravityParameters.CheckShouldUseGravity();
			isFlying = flightParameters.CheckShouldUseFlight();
			UpdateAuthority();
			this.onMotorStart?.Invoke(body);
		}

		public override void OnStartAuthority()
		{
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			UpdateAuthority();
		}

		private void OnEnable()
		{
			UpdateInnerMotorEnabled();
		}

		private void OnDisable()
		{
			base.Motor.enabled = false;
		}

		private void PreMove(float deltaTime)
		{
			if (!hasEffectiveAuthority)
			{
				return;
			}
			float num = acceleration;
			if (isAirControlForced || !isGrounded)
			{
				num *= (disableAirControlUntilCollision ? 0f : airControl);
			}
			UnityEngine.Vector3 vector = moveDirection;
			if (!isFlying)
			{
				vector.y = 0f;
			}
			if (body.isSprinting)
			{
				float magnitude = vector.magnitude;
				if (magnitude < 1f && magnitude > 0f)
				{
					float num2 = 1f / vector.magnitude;
					vector *= num2;
				}
			}
			UnityEngine.Vector3 target = vector * walkSpeed;
			if (!isFlying)
			{
				target.y = velocity.y;
			}
			velocity = UnityEngine.Vector3.MoveTowards(velocity, target, num * deltaTime);
			if (useGravity)
			{
				ref float y = ref velocity.y;
				y += Physics.gravity.y * deltaTime;
				if (isGrounded)
				{
					y = Mathf.Max(y, 0f);
				}
			}
		}

		public void OnDeathStart()
		{
			alive = false;
		}

		private void FixedUpdate()
		{
			float fixedDeltaTime = Time.fixedDeltaTime;
			if (fixedDeltaTime != 0f)
			{
				UnityEngine.Vector3 position = base.transform.position;
				if ((previousPosition - position).sqrMagnitude < 0.00062500004f * fixedDeltaTime)
				{
					restStopwatch += fixedDeltaTime;
				}
				else
				{
					restStopwatch = 0f;
				}
				previousPosition = position;
				if (netIsGrounded)
				{
					lastGroundedTime = Run.FixedTimeStamp.now;
				}
			}
		}

		private void GenerateParameters()
		{
			slopeLimit = 70f;
			stepOffset = Mathf.Min(capsuleHeight * 0.1f, 0.2f);
			stepHandlingMethod = StepHandlingMethod.None;
			ledgeHandling = false;
			interactiveRigidbodyHandling = true;
		}

		public void ApplyForce(UnityEngine.Vector3 force, bool alwaysApply = false, bool disableAirControlUntilCollision = false)
		{
			PhysForceInfo forceInfo = PhysForceInfo.Create();
			forceInfo.force = force;
			forceInfo.ignoreGroundStick = alwaysApply;
			forceInfo.disableAirControlUntilCollision = disableAirControlUntilCollision;
			forceInfo.massIsOne = false;
			ApplyForceImpulse(in forceInfo);
		}

		public void ApplyForceImpulse(in PhysForceInfo forceInfo)
		{
			if (NetworkServer.active && !hasEffectiveAuthority)
			{
				CallRpcApplyForceImpulse(forceInfo);
				return;
			}
			UnityEngine.Vector3 force = forceInfo.force;
			if (!forceInfo.massIsOne)
			{
				_ = force.magnitude;
				force *= 1f / mass;
			}
			if (mass != 0f)
			{
				if (force.y < 6f && isGrounded && !forceInfo.ignoreGroundStick)
				{
					force.y = 0f;
				}
				if (force.y > 0f)
				{
					base.Motor.ForceUnground();
				}
				velocity += force;
				if (forceInfo.disableAirControlUntilCollision)
				{
					disableAirControlUntilCollision = true;
				}
			}
		}

		[ClientRpc]
		private void RpcApplyForceImpulse(PhysForceInfo physForceInfo)
		{
			if (!NetworkServer.active)
			{
				ApplyForceImpulse(in physForceInfo);
			}
		}

		public override void UpdateRotation(ref UnityEngine.Quaternion currentRotation, float deltaTime)
		{
			currentRotation = UnityEngine.Quaternion.identity;
		}

		public override void UpdateVelocity(ref UnityEngine.Vector3 currentVelocity, float deltaTime)
		{
			currentVelocity = velocity;
		}

		public override void BeforeCharacterUpdate(float deltaTime)
		{
			_ = cvCMotorSafeCollisionStepThreshold.value;
			_ = cvCMotorSafeCollisionStepThreshold.value;
			if (rootMotion != UnityEngine.Vector3.zero)
			{
				UnityEngine.Vector3 vector = rootMotion;
				rootMotion = UnityEngine.Vector3.zero;
				base.Motor.MoveCharacter(base.transform.position + vector);
			}
			PreMove(deltaTime);
			_ = (velocity * deltaTime).sqrMagnitude;
		}

		public override void PostGroundingUpdate(float deltaTime)
		{
			if (base.Motor.GroundingStatus.IsStableOnGround != base.Motor.LastGroundingStatus.IsStableOnGround)
			{
				netIsGrounded = base.Motor.GroundingStatus.IsStableOnGround;
				if (base.Motor.GroundingStatus.IsStableOnGround)
				{
					OnLanded();
				}
				else
				{
					OnLeaveStableGround();
				}
			}
		}

		private void OnLanded()
		{
			jumpCount = 0;
			HitGroundInfo hitGroundInfo = default(HitGroundInfo);
			hitGroundInfo.velocity = lastVelocity;
			hitGroundInfo.position = base.Motor.GroundingStatus.GroundPoint;
			hitGroundInfo.isValidForEffect = Run.FixedTimeStamp.now - lastGroundedTime > 0.2f;
			HitGroundInfo hitGroundInfo2 = hitGroundInfo;
			if (hasEffectiveAuthority)
			{
				try
				{
					this.onHitGroundAuthority?.Invoke(ref hitGroundInfo2);
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
				if (NetworkServer.active)
				{
					GlobalEventManager.instance.OnCharacterHitGroundServer(body, hitGroundInfo2);
				}
				else
				{
					CallCmdReportHitGround(hitGroundInfo2);
				}
			}
		}

		[ClientRpc]
		public void RpcOnHitGroundSFX(HitGroundInfo hitGroundInfo, bool tookFallDamage)
		{
			if (!NetworkServer.active)
			{
				GlobalEventManager.instance.OnCharacterHitGroundSFX(body, hitGroundInfo, tookFallDamage);
			}
		}

		[Command]
		private void CmdReportHitGround(HitGroundInfo hitGroundInfo)
		{
			GlobalEventManager.instance.OnCharacterHitGroundServer(body, hitGroundInfo);
		}

		private void OnLeaveStableGround()
		{
			if (jumpCount < 1)
			{
				jumpCount = 1;
			}
			body.SetInLava(b: false);
		}

		public override void AfterCharacterUpdate(float deltaTime)
		{
			lastVelocity = velocity;
			velocity = base.Motor.BaseVelocity;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override bool IsColliderValidForCollisions(Collider coll)
		{
			if (!coll.isTrigger)
			{
				return coll != base.Motor.Capsule;
			}
			return false;
		}

		public override void OnGroundHit(Collider hitCollider, UnityEngine.Vector3 hitNormal, UnityEngine.Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
		{
			isAirControlForced = false;
			SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitCollider, hitPoint);
			if ((bool)objectSurfaceDef)
			{
				isAirControlForced = objectSurfaceDef.isSlippery;
				body.SetInLava(objectSurfaceDef.isLava);
			}
		}

		public override void OnMovementHit(Collider hitCollider, UnityEngine.Vector3 hitNormal, UnityEngine.Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
		{
			disableAirControlUntilCollision = false;
			if (this.onMovementHit != null)
			{
				MovementHitInfo movementHitInfo = default(MovementHitInfo);
				movementHitInfo.velocity = velocity;
				movementHitInfo.hitCollider = hitCollider;
				MovementHitInfo movementHitInfo2 = movementHitInfo;
				this.onMovementHit(ref movementHitInfo2);
				SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitCollider, hitPoint);
				if ((bool)objectSurfaceDef)
				{
					body.SetInLava(objectSurfaceDef.isLava);
				}
			}
		}

		public override void ProcessHitStabilityReport(Collider hitCollider, UnityEngine.Vector3 hitNormal, UnityEngine.Vector3 hitPoint, UnityEngine.Vector3 atCharacterPosition, UnityEngine.Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
		{
		}

		public void Jump(float horizontalMultiplier, float verticalMultiplier, bool vault = false)
		{
			UnityEngine.Vector3 vector = moveDirection;
			if (vault)
			{
				velocity = vector;
			}
			else
			{
				vector.y = 0f;
				float magnitude = vector.magnitude;
				if (magnitude > 0f)
				{
					vector /= magnitude;
				}
				UnityEngine.Vector3 vector2 = vector * body.moveSpeed * horizontalMultiplier;
				vector2.y = body.jumpPower * verticalMultiplier;
				velocity = vector2;
			}
			base.Motor.ForceUnground();
		}

		public void AddDisplacement(UnityEngine.Vector3 displacement)
		{
			rootMotion += displacement;
		}

		static CharacterMotor()
		{
			enableMotorWithoutAuthority = false;
			cvCMotorSafeCollisionStepThreshold = new FloatConVar("cmotor_safe_collision_step_threshold", ConVarFlags.Cheat, 1.0833334f.ToString(CultureInfo.InvariantCulture), "How large of a movement in meters/fixedTimeStep is needed to trigger more expensive \"safe\" collisions to prevent tunneling.");
			kCmdCmdReportHitGround = 1796547162;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CharacterMotor), kCmdCmdReportHitGround, InvokeCmdCmdReportHitGround);
			kRpcRpcApplyForceImpulse = 1042934326;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMotor), kRpcRpcApplyForceImpulse, InvokeRpcRpcApplyForceImpulse);
			kRpcRpcOnHitGroundSFX = -1661136052;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CharacterMotor), kRpcRpcOnHitGroundSFX, InvokeRpcRpcOnHitGroundSFX);
			NetworkCRC.RegisterBehaviour("CharacterMotor", 0);
		}

		void IPhysMotor.ApplyForceImpulse(in PhysForceInfo physForceInfo)
		{
			ApplyForceImpulse(in physForceInfo);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdReportHitGround(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdReportHitGround called on client.");
			}
			else
			{
				((CharacterMotor)obj).CmdReportHitGround(GeneratedNetworkCode._ReadHitGroundInfo_CharacterMotor(reader));
			}
		}

		public void CallCmdReportHitGround(HitGroundInfo hitGroundInfo)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdReportHitGround called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdReportHitGround(hitGroundInfo);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdReportHitGround);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteHitGroundInfo_CharacterMotor(networkWriter, hitGroundInfo);
			SendCommandInternal(networkWriter, 0, "CmdReportHitGround");
		}

		protected static void InvokeRpcRpcApplyForceImpulse(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcApplyForceImpulse called on server.");
			}
			else
			{
				((CharacterMotor)obj).RpcApplyForceImpulse(GeneratedNetworkCode._ReadPhysForceInfo_None(reader));
			}
		}

		protected static void InvokeRpcRpcOnHitGroundSFX(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnHitGroundSFX called on server.");
			}
			else
			{
				((CharacterMotor)obj).RpcOnHitGroundSFX(GeneratedNetworkCode._ReadHitGroundInfo_CharacterMotor(reader), reader.ReadBoolean());
			}
		}

		public void CallRpcApplyForceImpulse(PhysForceInfo physForceInfo)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcApplyForceImpulse called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcApplyForceImpulse);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WritePhysForceInfo_None(networkWriter, physForceInfo);
			SendRPCInternal(networkWriter, 0, "RpcApplyForceImpulse");
		}

		public void CallRpcOnHitGroundSFX(HitGroundInfo hitGroundInfo, bool tookFallDamage)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnHitGroundSFX called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnHitGroundSFX);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteHitGroundInfo_CharacterMotor(networkWriter, hitGroundInfo);
			networkWriter.Write(tookFallDamage);
			SendRPCInternal(networkWriter, 0, "RpcOnHitGroundSFX");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class CharacterSelectSurvivorPreviewDisplayController : MonoBehaviour
	{
		[Serializable]
		public struct SkillChangeResponse
		{
			public SkillFamily triggerSkillFamily;

			public SkillDef triggerSkill;

			public UnityEvent response;
		}

		[Serializable]
		public struct SkinChangeResponse
		{
			public SkinDef triggerSkin;

			public UnityEvent response;
		}

		public GameObject bodyPrefab;

		public SkillChangeResponse[] skillChangeResponses;

		public SkinChangeResponse[] skinChangeResponses;

		private Loadout currentLoadout;

		public NetworkUser networkUser { get; set; }

		private void OnEnable()
		{
			currentLoadout = Loadout.RequestInstance();
			NetworkUser.onLoadoutChangedGlobal += OnLoadoutChangedGlobal;
			RoR2Application.onNextUpdate += Refresh;
			RunDefaultResponses();
		}

		private void OnDisable()
		{
			NetworkUser.onLoadoutChangedGlobal -= OnLoadoutChangedGlobal;
			currentLoadout = Loadout.ReturnInstance(currentLoadout);
		}

		private static int FindSkillSlotIndex(BodyIndex bodyIndex, SkillFamily skillFamily)
		{
			GenericSkill[] bodyPrefabSkillSlots = BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex);
			for (int i = 0; i < bodyPrefabSkillSlots.Length; i++)
			{
				if (bodyPrefabSkillSlots[i].skillFamily == skillFamily)
				{
					return i;
				}
			}
			return -1;
		}

		private static int FindVariantIndex(SkillFamily skillFamily, SkillDef skillDef)
		{
			SkillFamily.Variant[] variants = skillFamily.variants;
			for (int i = 0; i < variants.Length; i++)
			{
				if (variants[i].skillDef == skillDef)
				{
					return i;
				}
			}
			return -1;
		}

		private static bool HasSkillVariantEnabled(Loadout loadout, BodyIndex bodyIndex, SkillFamily skillFamily, SkillDef skillDef)
		{
			int num = FindSkillSlotIndex(bodyIndex, skillFamily);
			int num2 = FindVariantIndex(skillFamily, skillDef);
			if (num == -1 || num2 == -1)
			{
				return false;
			}
			return loadout.bodyLoadoutManager.GetSkillVariant(bodyIndex, num) == num2;
		}

		private void Refresh()
		{
			if ((bool)this && (bool)networkUser)
			{
				OnLoadoutChangedGlobal(networkUser);
			}
		}

		private void OnLoadoutChangedGlobal(NetworkUser changedNetworkUser)
		{
			if (changedNetworkUser != networkUser)
			{
				return;
			}
			Loadout loadout = Loadout.RequestInstance();
			changedNetworkUser.networkLoadout.CopyLoadout(loadout);
			BodyIndex bodyIndex = BodyCatalog.FindBodyIndex(bodyPrefab);
			if (bodyIndex == BodyIndex.None)
			{
				return;
			}
			SkillChangeResponse[] array = skillChangeResponses;
			for (int i = 0; i < array.Length; i++)
			{
				SkillChangeResponse skillChangeResponse = array[i];
				bool num = HasSkillVariantEnabled(currentLoadout, bodyIndex, skillChangeResponse.triggerSkillFamily, skillChangeResponse.triggerSkill);
				bool flag = HasSkillVariantEnabled(loadout, bodyIndex, skillChangeResponse.triggerSkillFamily, skillChangeResponse.triggerSkill);
				if (!num && flag)
				{
					skillChangeResponse.response?.Invoke();
				}
			}
			SkinChangeResponse[] array2 = skinChangeResponses;
			for (int i = 0; i < array2.Length; i++)
			{
				SkinChangeResponse skinChangeResponse = array2[i];
				uint num2 = (uint)SkinCatalog.FindLocalSkinIndexForBody(bodyIndex, skinChangeResponse.triggerSkin);
				uint skinIndex = currentLoadout.bodyLoadoutManager.GetSkinIndex(bodyIndex);
				uint skinIndex2 = loadout.bodyLoadoutManager.GetSkinIndex(bodyIndex);
				if (skinIndex != skinIndex2 && skinIndex2 == num2)
				{
					skinChangeResponse.response?.Invoke();
				}
			}
			loadout.Copy(currentLoadout);
			Loadout.ReturnInstance(loadout);
		}

		private void RunDefaultResponses()
		{
			BodyIndex bodyIndex = BodyCatalog.FindBodyIndex(bodyPrefab);
			if (bodyIndex == BodyIndex.None)
			{
				return;
			}
			SkillChangeResponse[] array = skillChangeResponses;
			for (int i = 0; i < array.Length; i++)
			{
				SkillChangeResponse skillChangeResponse = array[i];
				if (HasSkillVariantEnabled(currentLoadout, bodyIndex, skillChangeResponse.triggerSkillFamily, skillChangeResponse.triggerSkill))
				{
					skillChangeResponse.response?.Invoke();
				}
			}
			SkinChangeResponse[] array2 = skinChangeResponses;
			for (int i = 0; i < array2.Length; i++)
			{
				SkinChangeResponse skinChangeResponse = array2[i];
				uint num = (uint)SkinCatalog.FindLocalSkinIndexForBody(bodyIndex, skinChangeResponse.triggerSkin);
				if (currentLoadout.bodyLoadoutManager.GetSkinIndex(bodyIndex) == num)
				{
					skinChangeResponse.response?.Invoke();
				}
			}
		}
	}
	public interface IChestBehavior
	{
		bool HasRolledPickup(PickupIndex pickupIndex);

		void Roll();

		void ItemDrop();
	}
	public class ChestBehavior : NetworkBehaviour, IChestBehavior
	{
		public PickupDropTable dropTable;

		public Transform dropTransform;

		public float dropUpVelocityStrength = 20f;

		public float dropForwardVelocityStrength = 2f;

		public int minDropCount = 1;

		public int maxDropCount = 1;

		public SerializableEntityStateType openState = new SerializableEntityStateType(typeof(EntityStates.Barrel.Opening));

		public SerializableEntityStateType closingState = new SerializableEntityStateType(typeof(Closing));

		[Tooltip("Deprecated.  Use DropTable instead.")]
		[Header("Deprecated")]
		public float tier1Chance = 0.8f;

		[Tooltip("Deprecated.  Use DropTable instead.")]
		public float tier2Chance = 0.2f;

		[Tooltip("Deprecated.  Use DropTable instead.")]
		public float tier3Chance = 0.01f;

		[Tooltip("Deprecated.  Use DropTable instead.")]
		public float lunarChance;

		[Tooltip("Deprecated.  Use DropTable instead.")]
		public ItemTag requiredItemTag;

		[Tooltip("Deprecated.  Use DropTable instead.")]
		public float lunarCoinChance;

		[Tooltip("Deprecated.  Use DropTable instead.")]
		public UnityEvent dropRoller;

		private Xoroshiro128Plus rng;

		public int dropCount;

		[SyncVar]
		public bool isCommandChest;

		[SyncVar]
		private bool isChestOpened;

		[HideInInspector]
		public PickupPickerController ppc;

		private static int kRpcRpcResetChests;

		private static int kRpcRpcSetDelusionPickupIndex;

		public PickupIndex dropPickup { get; private set; } = PickupIndex.none;


		public bool NetworkisCommandChest
		{
			get
			{
				return isCommandChest;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref isCommandChest, 1u);
			}
		}

		public bool NetworkisChestOpened
		{
			get
			{
				return isChestOpened;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref isChestOpened, 2u);
			}
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		[Server]
		public void Roll()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::Roll()' called on client");
			}
			else if ((bool)dropTable)
			{
				dropPickup = dropTable.GenerateDrop(rng);
			}
			else
			{
				dropRoller?.Invoke();
			}
		}

		public PickupIndex GetRandomPickupIndex()
		{
			return dropTable.GenerateDrop(rng);
		}

		[Server]
		private void PickFromList(List<PickupIndex> dropList)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::PickFromList(System.Collections.Generic.List`1<RoR2.PickupIndex>)' called on client");
				return;
			}
			dropPickup = PickupIndex.none;
			if (dropList != null && dropList.Count > 0)
			{
				dropPickup = rng.NextElementUniform(dropList);
			}
		}

		[Server]
		[Obsolete("Just use a drop table")]
		public void RollItem()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::RollItem()' called on client");
				return;
			}
			WeightedSelection<List<PickupIndex>> selector = new WeightedSelection<List<PickupIndex>>();
			List<PickupIndex> sourceDropList2 = new List<PickupIndex> { PickupCatalog.FindPickupIndex(RoR2Content.MiscPickups.LunarCoin.miscPickupIndex) };
			Add(Run.instance.availableTier1DropList, tier1Chance);
			Add(Run.instance.availableTier2DropList, tier2Chance);
			Add(Run.instance.availableTier3DropList, tier3Chance);
			Add(Run.instance.availableLunarCombinedDropList, lunarChance);
			Add(sourceDropList2, lunarCoinChance);
			List<PickupIndex> dropList = selector.Evaluate(rng.nextNormalizedFloat);
			PickFromList(dropList);
			void Add(List<PickupIndex> sourceDropList, float chance)
			{
				if (!(chance <= 0f))
				{
					selector.AddChoice(sourceDropList.Where(PassesFilter).ToList(), chance);
				}
			}
			bool PassesFilter(PickupIndex pickupIndex)
			{
				if (requiredItemTag == ItemTag.Any)
				{
					return true;
				}
				PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
				if (pickupDef.itemIndex != ItemIndex.None)
				{
					return ItemCatalog.GetItemDef(pickupDef.itemIndex).ContainsTag(requiredItemTag);
				}
				return true;
			}
		}

		[Server]
		[Obsolete("Just use a drop table")]
		public void RollEquipment()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::RollEquipment()' called on client");
			}
			else
			{
				PickFromList(Run.instance.availableEquipmentDropList);
			}
		}

		private void Awake()
		{
			if (dropTransform == null)
			{
				dropTransform = base.transform;
			}
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
				dropCount = rng.RangeInt(minDropCount, Math.Max(minDropCount + 1, maxDropCount + 1));
				Roll();
			}
		}

		public void OnEnable()
		{
			InstanceTracker.Add(this);
		}

		public void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		[Server]
		public void Open()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::Open()' called on client");
				return;
			}
			EntityStateMachine component = GetComponent<EntityStateMachine>();
			if ((bool)component)
			{
				component.SetNextState(EntityStateCatalog.InstantiateState(ref openState));
			}
		}

		[ClientRpc]
		public void RpcResetChests()
		{
			if (TryGetComponent<DelusionChestController>(out var component) && isChestOpened)
			{
				component.ResetChestForDelusion();
			}
		}

		[ClientRpc]
		public void RpcSetDelusionPickupIndex(PickupIndex pickupIndex)
		{
			if (TryGetComponent<DelusionChestController>(out var component))
			{
				component.DelusionPickupIndex = pickupIndex;
			}
		}

		[Server]
		public void ItemDrop()
		{
			DelusionChestController component;
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ChestBehavior::ItemDrop()' called on client");
			}
			else if (DelusionChestController.isDelusionEnable && TryGetComponent<DelusionChestController>(out component) && component.SelectedPickupIndex != PickupIndex.none)
			{
				if (component.IsSelectedCorrectly())
				{
					Util.PlaySound("Play_ui_artifact_delusion_success", base.gameObject);
					DelusionItemDrop();
				}
				else
				{
					Util.PlaySound("Play_ui_artifact_delusion_failure", base.gameObject);
					component.RemoveDelusionChoice();
				}
			}
			else
			{
				BaseItemDrop();
			}
		}

		private void DelusionItemDrop(DelusionChestController delusionChestController)
		{
			if (delusionChestController.isDelusionSelected)
			{
				if (delusionChestController.IsSelectedCorrectly())
				{
					UnityEngine.Vector3 velocity = UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength;
					GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
					createPickupInfo.pickupIndex = delusionChestController.DelusionPickupIndex;
					createPickupInfo.position = dropTransform.position + UnityEngine.Vector3.up * 1.5f;
					createPickupInfo.chest = this;
					createPickupInfo.artifactFlag = GenericPickupController.PickupArtifactFlag.DELUSION;
					GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo;
					PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, velocity);
					Util.PlaySound("Play_ui_artifact_delusion_success", base.gameObject);
				}
				else
				{
					Util.PlaySound("Play_ui_artifact_delusion_failure", base.gameObject);
					delusionChestController.RemoveDelusionChoice();
				}
			}
		}

		private void DelusionItemDrop()
		{
			if (TryGetComponent<DelusionChestController>(out var component) && component.SelectedPickupIndex == component.DelusionPickupIndex)
			{
				UnityEngine.Vector3 velocity = UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength;
				PickupDropletController.CreatePickupDroplet(component.DelusionPickupIndex, dropTransform.position + UnityEngine.Vector3.up * 1.5f, velocity);
			}
		}

		private void BaseItemDrop()
		{
			if (!(dropPickup == PickupIndex.none) && dropCount >= 1)
			{
				float angle = 360f / (float)dropCount;
				UnityEngine.Vector3 vector = UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength;
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				GetComponent<DelusionChestController>();
				for (int i = 0; i < dropCount; i++)
				{
					GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
					createPickupInfo.pickupIndex = dropPickup;
					createPickupInfo.position = dropTransform.position + UnityEngine.Vector3.up * 1.5f;
					createPickupInfo.chest = this;
					createPickupInfo.artifactFlag = (isCommandChest ? GenericPickupController.PickupArtifactFlag.COMMAND : GenericPickupController.PickupArtifactFlag.NONE);
					GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo;
					PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector);
					vector = quaternion * vector;
					Roll();
				}
				dropPickup = PickupIndex.none;
				NetworkisChestOpened = true;
			}
		}

		public bool HasRolledPickup(PickupIndex pickupIndex)
		{
			return dropPickup == pickupIndex;
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcResetChests(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcResetChests called on server.");
			}
			else
			{
				((ChestBehavior)obj).RpcResetChests();
			}
		}

		protected static void InvokeRpcRpcSetDelusionPickupIndex(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetDelusionPickupIndex called on server.");
			}
			else
			{
				((ChestBehavior)obj).RpcSetDelusionPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader));
			}
		}

		public void CallRpcResetChests()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcResetChests called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcResetChests);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcResetChests");
		}

		public void CallRpcSetDelusionPickupIndex(PickupIndex pickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetDelusionPickupIndex called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetDelusionPickupIndex);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WritePickupIndex_None(networkWriter, pickupIndex);
			SendRPCInternal(networkWriter, 0, "RpcSetDelusionPickupIndex");
		}

		static ChestBehavior()
		{
			kRpcRpcResetChests = -115962472;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ChestBehavior), kRpcRpcResetChests, InvokeRpcRpcResetChests);
			kRpcRpcSetDelusionPickupIndex = -2130336578;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ChestBehavior), kRpcRpcSetDelusionPickupIndex, InvokeRpcRpcSetDelusionPickupIndex);
			NetworkCRC.RegisterBehaviour("ChestBehavior", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(isCommandChest);
				writer.Write(isChestOpened);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(isCommandChest);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(isChestOpened);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				isCommandChest = reader.ReadBoolean();
				isChestOpened = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				isCommandChest = reader.ReadBoolean();
			}
			if (((uint)num & 2u) != 0)
			{
				isChestOpened = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class ChestRevealer : NetworkBehaviour
	{
		private struct PendingReveal : IComparable<PendingReveal>
		{
			public GameObject gameObject;

			public Run.FixedTimeStamp time;

			public float duration;

			public int CompareTo(PendingReveal other)
			{
				return time.CompareTo(other.time);
			}
		}

		private class RevealedObject : MonoBehaviour
		{
			private float lifetime;

			private static readonly Dictionary<GameObject, RevealedObject> currentlyRevealedObjects = new Dictionary<GameObject, RevealedObject>();

			private PositionIndicator positionIndicator;

			public static void RevealObject(GameObject gameObject, float duration)
			{
				if (!currentlyRevealedObjects.TryGetValue(gameObject, out var value))
				{
					value = gameObject.AddComponent<RevealedObject>();
				}
				if (value.lifetime < duration)
				{
					value.lifetime = duration;
				}
			}

			private void OnEnable()
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/PositionIndicators/PoiPositionIndicator"), base.transform.position, base.transform.rotation);
				positionIndicator = gameObject.GetComponent<PositionIndicator>();
				positionIndicator.insideViewObject.GetComponent<SpriteRenderer>().sprite = PingIndicator.GetInteractableIcon(base.gameObject);
				positionIndicator.targetTransform = base.transform;
				currentlyRevealedObjects[base.gameObject] = this;
			}

			private void OnDisable()
			{
				currentlyRevealedObjects.Remove(base.gameObject);
				if ((bool)positionIndicator)
				{
					UnityEngine.Object.Destroy(positionIndicator.gameObject);
				}
				positionIndicator = null;
			}

			private void FixedUpdate()
			{
				lifetime -= Time.fixedDeltaTime;
				if (lifetime <= 0f)
				{
					UnityEngine.Object.Destroy(this);
				}
			}
		}

		[SyncVar]
		public float radius;

		public float pulseTravelSpeed = 10f;

		public float revealDuration = 10f;

		public float pulseInterval = 1f;

		private Run.FixedTimeStamp nextPulse = Run.FixedTimeStamp.negativeInfinity;

		public GameObject pulseEffectPrefab;

		public float pulseEffectScale = 1f;

		private static readonly List<PendingReveal> pendingReveals = new List<PendingReveal>();

		private static Type[] typesToCheck;

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 1u);
			}
		}

		[InitDuringStartup]
		private static void Init()
		{
			RoR2Application.onFixedUpdate += StaticFixedUpdate;
			typesToCheck = (from t in typeof(ChestRevealer).Assembly.GetTypes()
				where typeof(IInteractable).IsAssignableFrom(t)
				select t).ToArray();
		}

		private static void StaticFixedUpdate()
		{
			pendingReveals.Sort();
			while (pendingReveals.Count > 0)
			{
				PendingReveal pendingReveal = pendingReveals[0];
				if (pendingReveal.time.hasPassed)
				{
					if ((bool)pendingReveal.gameObject)
					{
						RevealedObject.RevealObject(pendingReveal.gameObject, pendingReveal.duration);
					}
					pendingReveals.RemoveAt(0);
					continue;
				}
				break;
			}
		}

		public void Pulse()
		{
			UnityEngine.Vector3 origin = base.transform.position;
			float radiusSqr = radius * radius;
			float invPulseTravelSpeed = 1f / pulseTravelSpeed;
			Type[] array = typesToCheck;
			for (int i = 0; i < array.Length; i++)
			{
				foreach (MonoBehaviour item2 in InstanceTracker.FindInstancesEnumerable(array[i]))
				{
					if (((IInteractable)item2).ShouldShowOnScanner())
					{
						TryAddRevealable(item2.transform);
					}
				}
			}
			EffectManager.SpawnEffect(pulseEffectPrefab, new EffectData
			{
				origin = origin,
				scale = radius * pulseEffectScale
			}, transmit: false);
			void TryAddRevealable(Transform revealableTransform)
			{
				float sqrMagnitude = (revealableTransform.position - origin).sqrMagnitude;
				if (!(sqrMagnitude > radiusSqr))
				{
					float num = Mathf.Sqrt(sqrMagnitude) * invPulseTravelSpeed;
					PendingReveal pendingReveal = default(PendingReveal);
					pendingReveal.gameObject = revealableTransform.gameObject;
					pendingReveal.time = Run.FixedTimeStamp.now + num;
					pendingReveal.duration = revealDuration;
					PendingReveal item = pendingReveal;
					pendingReveals.Add(item);
				}
			}
		}

		private void FixedUpdate()
		{
			if (nextPulse.hasPassed)
			{
				Pulse();
				nextPulse = Run.FixedTimeStamp.now + pulseInterval;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(radius);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(radius);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				radius = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				radius = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class ChildLocatorMirrorController : MonoBehaviour
	{
		private class MirrorPair
		{
			public Transform referenceTransform;

			public Transform targetTransform;
		}

		[SerializeField]
		[Tooltip("The ChildLocator we are using are a reference to GET the transform information")]
		private ChildLocator _referenceLocator;

		[SerializeField]
		[Tooltip("The ChildLocator we are targeting to SET the transform information")]
		private ChildLocator _targetLocator;

		private List<MirrorPair> mirrorPairs = new List<MirrorPair>();

		public ChildLocator referenceLocator
		{
			get
			{
				return _referenceLocator;
			}
			set
			{
				_referenceLocator = value;
				mirrorPairs.Clear();
				if ((bool)_referenceLocator && (bool)_targetLocator)
				{
					RebuildMirrorPairs();
				}
			}
		}

		public ChildLocator targetLocator
		{
			get
			{
				return _targetLocator;
			}
			set
			{
				_targetLocator = value;
				mirrorPairs.Clear();
				if ((bool)_referenceLocator && (bool)_targetLocator)
				{
					RebuildMirrorPairs();
				}
			}
		}

		private void Start()
		{
			if ((bool)_referenceLocator && (bool)_targetLocator)
			{
				RebuildMirrorPairs();
			}
		}

		private void FixedUpdate()
		{
			foreach (MirrorPair mirrorPair in mirrorPairs)
			{
				if ((bool)mirrorPair.referenceTransform && (bool)mirrorPair.targetTransform)
				{
					mirrorPair.targetTransform.position = mirrorPair.referenceTransform.position;
					mirrorPair.targetTransform.rotation = mirrorPair.referenceTransform.rotation;
				}
			}
		}

		private void RebuildMirrorPairs()
		{
			mirrorPairs.Clear();
			for (int i = 0; i < _targetLocator.Count; i++)
			{
				string childName = _targetLocator.FindChildName(i);
				Transform transform = _targetLocator.FindChild(i);
				Transform transform2 = _referenceLocator.FindChild(childName);
				if ((bool)transform && (bool)transform2)
				{
					mirrorPairs.Add(new MirrorPair
					{
						targetTransform = transform,
						referenceTransform = transform2
					});
				}
			}
		}
	}
	[RequireComponent(typeof(SceneInfo))]
	public class ClassicStageInfo : MonoBehaviour
	{
		[Serializable]
		public struct BonusInteractibleCreditObject
		{
			public GameObject objectThatGrantsPointsIfEnabled;

			public int points;
		}

		[Serializable]
		public struct MonsterFamily
		{
			[SerializeField]
			public DirectorCardCategorySelection monsterFamilyCategories;

			public string familySelectionChatString;

			public float selectionWeight;

			public int minimumStageCompletion;

			public int maximumStageCompletion;
		}

		private DirectorCardCategorySelection modifiableMonsterCategories;

		[Tooltip("We'll select a single DCCS from this pool when we enter the stage to determine which monsters can spawn.")]
		[SerializeField]
		private DccsPool monsterDccsPool;

		[Tooltip("We'll select a single DCCS from this pool when we enter the stage to determine which interactables can spawn.")]
		[SerializeField]
		private DccsPool interactableDccsPool;

		private ulong seedServer;

		private Xoroshiro128Plus rng;

		public int sceneDirectorInteractibleCredits = 200;

		public int sceneDirectorMonsterCredits = 20;

		public BonusInteractibleCreditObject[] bonusInteractibleCreditObjects;

		public static float monsterFamilyChance = 0.02f;

		[SerializeField]
		[HideInInspector]
		private DirectorCard[] monsterCards;

		[SerializeField]
		[HideInInspector]
		public DirectorCard[] interactableCards;

		[CanBeNull]
		[ShowFieldObsolete]
		[Tooltip("Deprecated.  Use MonsterDccsPool instead.")]
		public DirectorCardCategorySelection interactableCategories;

		[ShowFieldObsolete]
		[CanBeNull]
		[SerializeField]
		[Tooltip("Deprecated.  Use MonsterDccsPool instead.")]
		private DirectorCardCategorySelection monsterCategories;

		[ShowFieldObsolete]
		[Tooltip("Deprecated.  Use MonsterDccsPool instead.")]
		public MonsterFamily[] possibleMonsterFamilies;

		public WeightedSelection<DirectorCard> monsterSelection { get; private set; }

		public static ClassicStageInfo instance { get; private set; }

		internal DccsPool GetMonsterDccsPool => monsterDccsPool;

		internal DccsPool GetInteractableDccsPool => interactableDccsPool;

		private static void HandleSingleMonsterTypeArtifact(DirectorCardCategorySelection monsterCategories, Xoroshiro128Plus rng)
		{
			ScriptableObject.CreateInstance<DirectorCardCategorySelection>().CopyFrom(monsterCategories);
			float baseCredits = 40f * Run.instance.difficultyCoefficient;
			int maximumNumberToSpawnBeforeSkipping = 5;
			int minimumToSpawn = 1;
			if (SceneCatalog.mostRecentSceneDef == SceneCatalog.FindSceneDef("arena"))
			{
				baseCredits = 50f * Run.instance.difficultyCoefficient;
				maximumNumberToSpawnBeforeSkipping = 6;
				minimumToSpawn = 2;
			}
			WeightedSelection<DirectorCard> candidatesSelection = new WeightedSelection<DirectorCard>();
			AddCardsWhichPassCondition(CardIsAffordable);
			if (candidatesSelection.Count == 0)
			{
				AddCardsWhichPassCondition(ReturnTrue);
			}
			if (candidatesSelection.Count == 0)
			{
				UnityEngine.Debug.LogWarning("Could not collapse director card selection down to one, no cards passed the filters!");
				return;
			}
			DirectorCard directorCard = candidatesSelection.Evaluate(rng.nextNormalizedFloat);
			monsterCategories.Clear();
			int categoryIndex = monsterCategories.AddCategory("Basic Monsters", 1f);
			monsterCategories.AddCard(categoryIndex, directorCard);
			BodyIndex bodyIndex = directorCard.spawnCard.prefab.GetComponent<CharacterMaster>().bodyPrefab.GetComponent<CharacterBody>().bodyIndex;
			if ((bool)Stage.instance)
			{
				SetStageSingleMonsterType(Stage.instance);
			}
			else
			{
				Stage.onServerStageBegin += SetStageSingleMonsterType;
			}
			void AddCardsWhichPassCondition(Predicate<DirectorCard> predicate)
			{
				for (int i = 0; i < monsterCategories.categories.Length; i++)
				{
					ref DirectorCardCategorySelection.Category reference = ref monsterCategories.categories[i];
					DirectorCard[] cards = reference.cards;
					float selectionWeight = reference.selectionWeight;
					for (int j = 0; j < cards.Length; j++)
					{
						DirectorCard directorCard2 = cards[j];
						if (predicate(directorCard2))
						{
							candidatesSelection.AddChoice(cards[j], selectionWeight * (float)directorCard2.selectionWeight);
						}
					}
				}
			}
			bool CardIsAffordable(DirectorCard card)
			{
				return Util.DirectorCardIsReasonableChoice(baseCredits, maximumNumberToSpawnBeforeSkipping, minimumToSpawn, card, CombatDirector.CalcHighestEliteCostMultiplier(card.spawnCard.eliteRules));
			}
			static bool ReturnTrue(DirectorCard card)
			{
				return true;
			}
			void SetStageSingleMonsterType(Stage stage)
			{
				Stage.instance.singleMonsterTypeBodyIndex = bodyIndex;
				Stage.onServerStageBegin -= SetStageSingleMonsterType;
			}
		}

		private static void HandleMixEnemyArtifact(DirectorCardCategorySelection monsterCategories, Xoroshiro128Plus rng)
		{
			monsterCategories.CopyFrom(RoR2Content.mixEnemyMonsterCards);
			if (monsterCategories.categories.Length == 0)
			{
				UnityEngine.Debug.LogError("MixEnemy monster cards are size 0!");
			}
			TrimCategory("Basic Monsters", 3);
			TrimCategory("Minibosses", 3);
			TrimCategory("Champions", 3);
			void TrimCategory(string categoryName, int requiredCount)
			{
				DirectorCardCategorySelection.Category[] categories = monsterCategories.categories;
				for (int j = 0; j < categories.Length; j++)
				{
					if (string.CompareOrdinal(categoryName, categories[j].name) == 0)
					{
						UnityEngine.Debug.LogFormat("Trimming {0} from {1} to {2}", categoryName, categories[j].cards.Length, requiredCount);
						TrimSelection(ref categories[j].cards, requiredCount);
					}
				}
			}
			void TrimSelection(ref DirectorCard[] cards, int requiredCount)
			{
				if (cards.Length > requiredCount)
				{
					DirectorCard[] array = ArrayUtils.Clone(cards);
					Util.ShuffleArray(array, rng);
					int num = array.Length - 1;
					while (num >= 0 && array.Length > requiredCount)
					{
						if (!array[num].IsAvailable())
						{
							ArrayUtils.ArrayRemoveAtAndResize(ref array, num);
						}
						num--;
					}
					if (array.Length > requiredCount)
					{
						Array.Resize(ref array, requiredCount);
					}
					cards = array;
					DirectorCard[] array2 = cards;
					foreach (DirectorCard directorCard in array2)
					{
						UnityEngine.Debug.LogFormat("Selected {0}", directorCard.spawnCard.name);
					}
				}
			}
		}

		private static bool DirectorCardDoesNotForbidElite(DirectorCard directorCard)
		{
			CharacterSpawnCard characterSpawnCard = directorCard.spawnCard as CharacterSpawnCard;
			if (!characterSpawnCard)
			{
				return true;
			}
			return !characterSpawnCard.noElites;
		}

		private void Awake()
		{
			if (NetworkServer.active)
			{
				seedServer = Run.instance.stageRng.nextUlong;
				rng = new Xoroshiro128Plus(seedServer);
			}
		}

		private void Start()
		{
			RebuildCards();
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
		}

		private void OnDestroy()
		{
			RunArtifactManager.onArtifactEnabledGlobal -= OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal -= OnArtifactDisabled;
			if ((bool)modifiableMonsterCategories)
			{
				UnityEngine.Object.Destroy(modifiableMonsterCategories);
			}
		}

		public IEnumerator BroadcastFamilySelection(string familySelectionChatString)
		{
			yield return new WaitForSeconds(1f);
			Chat.SendBroadcastChat(new Chat.SimpleChatMessage
			{
				baseToken = familySelectionChatString
			});
		}

		private void OnEnable()
		{
			instance = this;
		}

		private void OnDisable()
		{
			instance = null;
		}

		private static float CalculateTotalWeight(DirectorCard[] cards)
		{
			float num = 0f;
			foreach (DirectorCard directorCard in cards)
			{
				num += (float)directorCard.selectionWeight;
			}
			return num;
		}

		internal void RebuildCards(DirectorCardCategorySelection forcedMonsterCategory = null, DirectorCardCategorySelection forcedInteractableCategory = null)
		{
			Xoroshiro128Plus xoroshiro128Plus = new Xoroshiro128Plus(seedServer);
			Xoroshiro128Plus xoroshiro128Plus2 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong);
			Xoroshiro128Plus xoroshiro128Plus3 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong);
			Xoroshiro128Plus xoroshiro128Plus4 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong);
			Xoroshiro128Plus xoroshiro128Plus5 = new Xoroshiro128Plus(xoroshiro128Plus.nextUlong);
			if (forcedInteractableCategory != null)
			{
				forcedInteractableCategory.OnSelected(this);
				interactableCategories = forcedInteractableCategory;
			}
			else if ((bool)interactableDccsPool)
			{
				DirectorCardCategorySelection directorCardCategorySelection = interactableDccsPool.GenerateWeightedSelection().Evaluate(xoroshiro128Plus5.nextNormalizedFloat);
				if (directorCardCategorySelection != null)
				{
					directorCardCategorySelection.OnSelected(this);
					interactableCategories = directorCardCategorySelection;
				}
			}
			DirectorCardCategorySelection directorCardCategorySelection2 = null;
			if ((bool)monsterDccsPool)
			{
				DirectorCardCategorySelection directorCardCategorySelection3 = monsterDccsPool.GenerateWeightedSelection().Evaluate(xoroshiro128Plus5.nextNormalizedFloat);
				if (directorCardCategorySelection3 != null)
				{
					directorCardCategorySelection3.OnSelected(this);
					directorCardCategorySelection2 = UnityEngine.Object.Instantiate(directorCardCategorySelection3);
				}
			}
			else if ((bool)monsterCategories)
			{
				directorCardCategorySelection2 = UnityEngine.Object.Instantiate(monsterCategories);
			}
			if (!directorCardCategorySelection2)
			{
				return;
			}
			UnityEngine.Object.Destroy(modifiableMonsterCategories);
			bool flag = RunArtifactManager.instance?.IsArtifactEnabled(RoR2Content.Artifacts.singleMonsterTypeArtifactDef) ?? false;
			bool num = RunArtifactManager.instance?.IsArtifactEnabled(RoR2Content.Artifacts.mixEnemyArtifactDef) ?? false;
			bool flag2 = RunArtifactManager.instance?.IsArtifactEnabled(RoR2Content.Artifacts.eliteOnlyArtifactDef) ?? false;
			modifiableMonsterCategories = directorCardCategorySelection2;
			if (num)
			{
				HandleMixEnemyArtifact(modifiableMonsterCategories, xoroshiro128Plus3);
			}
			else if (forcedMonsterCategory != null)
			{
				forcedMonsterCategory.OnSelected(this);
				modifiableMonsterCategories.CopyFrom(forcedMonsterCategory);
			}
			else if (!monsterDccsPool && xoroshiro128Plus4.nextNormalizedFloat <= monsterFamilyChance && possibleMonsterFamilies != null)
			{
				Run run = Run.instance;
				if ((object)run == null || run.canFamilyEventTrigger)
				{
					WeightedSelection<MonsterFamily> weightedSelection = new WeightedSelection<MonsterFamily>();
					for (int i = 0; i < possibleMonsterFamilies.Length; i++)
					{
						MonsterFamily value = possibleMonsterFamilies[i];
						if (Run.instance != null && value.minimumStageCompletion <= Run.instance.stageClearCount && value.maximumStageCompletion > Run.instance.stageClearCount)
						{
							weightedSelection.AddChoice(value, value.selectionWeight);
						}
					}
					if (weightedSelection.Count > 0)
					{
						MonsterFamily monsterFamily = weightedSelection.Evaluate(xoroshiro128Plus.nextNormalizedFloat);
						modifiableMonsterCategories.CopyFrom(monsterFamily.monsterFamilyCategories);
						StartCoroutine("BroadcastFamilySelection", monsterFamily.familySelectionChatString);
					}
				}
			}
			if (flag2)
			{
				modifiableMonsterCategories.RemoveCardsThatFailFilter(DirectorCardDoesNotForbidElite);
			}
			if (flag)
			{
				HandleSingleMonsterTypeArtifact(modifiableMonsterCategories, xoroshiro128Plus2);
			}
			monsterSelection = modifiableMonsterCategories.GenerateDirectorCardWeightedSelection();
		}

		private void OnArtifactDisabled([NotNull] RunArtifactManager runArtifactManager, [NotNull] ArtifactDef artifactDef)
		{
			if ((object)artifactDef == RoR2Content.Artifacts.mixEnemyArtifactDef || (object)artifactDef == RoR2Content.Artifacts.singleMonsterTypeArtifactDef)
			{
				RebuildCards();
			}
		}

		private void OnArtifactEnabled([NotNull] RunArtifactManager runArtifactManager, [NotNull] ArtifactDef artifactDef)
		{
			if ((object)artifactDef == RoR2Content.Artifacts.mixEnemyArtifactDef || (object)artifactDef == RoR2Content.Artifacts.singleMonsterTypeArtifactDef)
			{
				RebuildCards();
			}
		}
	}
	public class CloverEffect : MonoBehaviour
	{
		public GameObject triggerEffect;

		private CharacterBody characterBody;

		private GameObject triggerEffectInstance;

		private bool trigger;

		private void Start()
		{
			CharacterBody body = GetComponentInParent<CharacterModel>().body;
			characterBody = body.GetComponent<CharacterBody>();
		}

		private void FixedUpdate()
		{
			if ((bool)characterBody && characterBody.wasLucky)
			{
				characterBody.wasLucky = false;
				EffectData effectData = new EffectData();
				effectData.origin = base.transform.position;
				effectData.rotation = base.transform.rotation;
				EffectManager.SpawnEffect(triggerEffect, effectData, transmit: true);
			}
		}
	}
	[RequireComponent(typeof(EffectComponent))]
	public class CoinBehavior : MonoBehaviour
	{
		[Serializable]
		public struct CoinTier
		{
			public ParticleSystem particleSystem;

			public int valuePerCoin;
		}

		public int originalCoinCount;

		public CoinTier[] coinTiers;

		private void Start()
		{
			originalCoinCount = (int)GetComponent<EffectComponent>().effectData.genericFloat;
			int num = originalCoinCount;
			for (int i = 0; i < coinTiers.Length; i++)
			{
				CoinTier coinTier = coinTiers[i];
				int num2 = 0;
				while (num >= coinTier.valuePerCoin)
				{
					num -= coinTier.valuePerCoin;
					num2++;
				}
				if (num2 > 0)
				{
					ParticleSystem.EmissionModule emission = coinTier.particleSystem.emission;
					emission.enabled = true;
					emission.SetBursts(new ParticleSystem.Burst[1]
					{
						new ParticleSystem.Burst(0f, num2)
					});
					coinTier.particleSystem.gameObject.SetActive(value: true);
				}
			}
		}
	}
	public class CombatDirector : MonoBehaviour
	{
		[Serializable]
		public class OnSpawnedServer : UnityEvent<GameObject>
		{
		}

		public class EliteTierDef
		{
			public float costMultiplier;

			public EliteDef[] eliteTypes;

			public Func<SpawnCard.EliteRules, bool> isAvailable = (SpawnCard.EliteRules rules) => true;

			public bool canSelectWithoutAvailableEliteDef;

			private List<EliteDef> availableDefs = new List<EliteDef>();

			public bool CanSelect(SpawnCard.EliteRules rules)
			{
				if (isAvailable(rules))
				{
					if (!canSelectWithoutAvailableEliteDef)
					{
						return HasAnyAvailableEliteDefs();
					}
					return true;
				}
				return false;
			}

			public bool HasAnyAvailableEliteDefs()
			{
				EliteDef[] array = eliteTypes;
				foreach (EliteDef eliteDef in array)
				{
					if ((bool)eliteDef && eliteDef.IsAvailable())
					{
						return true;
					}
				}
				return false;
			}

			public EliteDef GetRandomAvailableEliteDef(Xoroshiro128Plus rng)
			{
				availableDefs.Clear();
				EliteDef[] array = eliteTypes;
				foreach (EliteDef eliteDef in array)
				{
					if ((bool)eliteDef && eliteDef.IsAvailable())
					{
						availableDefs.Add(eliteDef);
					}
				}
				if (availableDefs.Count > 0)
				{
					return rng.NextElementUniform(availableDefs);
				}
				return null;
			}
		}

		private class DirectorMoneyWave
		{
			public float interval;

			public float timer;

			public float multiplier;

			private float accumulatedAward;

			public float Update(float deltaTime, float difficultyCoefficient)
			{
				timer += deltaTime;
				if (timer > interval)
				{
					float num = 0.5f + (float)Run.instance.participatingPlayerCount * 0.5f;
					timer -= interval;
					float num2 = 1f;
					float num3 = 0.4f;
					accumulatedAward += interval * multiplier * (num2 + num3 * difficultyCoefficient) * num;
				}
				float num4 = Mathf.FloorToInt(accumulatedAward);
				accumulatedAward -= num4;
				return num4;
			}
		}

		[Header("Core Director Values")]
		public string customName;

		public float monsterCredit;

		[Tooltip("Monster credit that's been refunded from culling non-elite enemies. Can only be used to buy non-elite enemies.")]
		public float refundedMonsterCredit;

		public float expRewardCoefficient = 0.2f;

		public float goldRewardCoefficient = 1f;

		public float minSeriesSpawnInterval = 0.1f;

		public float maxSeriesSpawnInterval = 1f;

		public float minRerollSpawnInterval = 2.3333333f;

		public float maxRerollSpawnInterval = 4.3333335f;

		public RangeFloat[] moneyWaveIntervals;

		public TeamIndex teamIndex = TeamIndex.Monster;

		[Tooltip("How much to multiply money wave yield by.")]
		[Header("Optional Behaviors")]
		public float creditMultiplier = 1f;

		[Tooltip("The coefficient to multiply spawn distances. Used for combat shrines, to keep spawns nearby.")]
		public float spawnDistanceMultiplier = 1f;

		[Tooltip("The maximum distance at which enemies will spawn.")]
		public float maxSpawnDistance = float.PositiveInfinity;

		[Tooltip("Ensure that the minimum spawn distance is at least this many units away from the maxSpawnDistance")]
		public float minSpawnRange;

		public bool shouldSpawnOneWave;

		public bool targetPlayers = true;

		public bool skipSpawnIfTooCheap = true;

		[Tooltip("If skipSpawnIfTooCheap is true, we'll behave as though it's not set after this many consecutive skips")]
		public int maxConsecutiveCheapSkips = int.MaxValue;

		public bool resetMonsterCardIfFailed = true;

		public int maximumNumberToSpawnBeforeSkipping = 6;

		public float eliteBias = 1f;

		public OnSpawnedServer onSpawnedServer;

		[FormerlySerializedAs("_combatSquad")]
		public CombatSquad combatSquad;

		[Tooltip("A special effect for when a monster appears will be instantiated at its position. Used for combat shrine.")]
		public GameObject spawnEffectPrefab;

		public bool ignoreTeamSizeLimit;

		[SerializeField]
		private DirectorCardCategorySelection _monsterCards;

		public bool fallBackToStageMonsterCards = true;

		public static readonly List<CombatDirector> instancesList = new List<CombatDirector>();

		private bool hasStartedWave;

		private Xoroshiro128Plus rng;

		private DirectorCard currentMonsterCard;

		private EliteTierDef currentActiveEliteTier;

		private EliteDef currentActiveEliteDef;

		private int currentMonsterCardCost;

		private WeightedSelection<DirectorCard> monsterCardsSelection;

		private int consecutiveCheapSkips;

		public GameObject currentSpawnTarget;

		private float playerRetargetTimer;

		private static readonly float baseEliteCostMultiplier = 6f;

		private static EliteTierDef[] eliteTiers;

		private int spawnCountInCurrentWave;

		public static readonly BoolConVar cvDirectorCombatDisable = new BoolConVar("director_combat_disable", ConVarFlags.SenderMustBeServer | ConVarFlags.Cheat, "0", "Disables all combat directors.");

		private static readonly BoolConVar cvDirectorCombatEnableInternalLogs = new BoolConVar("director_combat_enable_internal_logs", ConVarFlags.None, "0", "Enables all combat directors to print internal logging.");

		private DirectorMoneyWave[] moneyWaves;

		private bool isHalcyonShrineSpawn;

		private int shrineHalcyoniteDifficultyLevel;

		public float monsterSpawnTimer { get; set; }

		public DirectorCard lastAttemptedMonsterCard { get; set; }

		public float totalCreditsSpent { get; private set; }

		private WeightedSelection<DirectorCard> finalMonsterCardsSelection
		{
			get
			{
				WeightedSelection<DirectorCard> monsterSelection = monsterCardsSelection;
				if (monsterSelection == null)
				{
					ClassicStageInfo instance = ClassicStageInfo.instance;
					if ((object)instance == null)
					{
						return null;
					}
					monsterSelection = instance.monsterSelection;
				}
				return monsterSelection;
			}
		}

		private DirectorCardCategorySelection monsterCards
		{
			get
			{
				return _monsterCards;
			}
			set
			{
				if (_monsterCards != value)
				{
					_monsterCards = value;
					monsterCardsSelection = _monsterCards?.GenerateDirectorCardWeightedSelection();
				}
			}
		}

		public static float lowestEliteCostMultiplier => eliteTiers[1].costMultiplier;

		private int mostExpensiveMonsterCostInDeck
		{
			get
			{
				int num = 0;
				for (int i = 0; i < finalMonsterCardsSelection.Count; i++)
				{
					DirectorCard value = finalMonsterCardsSelection.GetChoice(i).value;
					int num2 = value.cost;
					if (!(value.spawnCard as CharacterSpawnCard).noElites)
					{
						num2 = (int)((float)num2 * CalcHighestEliteCostMultiplier(value.spawnCard.eliteRules));
					}
					num = Mathf.Max(num, num2);
				}
				return num;
			}
		}

		private void Awake()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint);
				moneyWaves = new DirectorMoneyWave[moneyWaveIntervals.Length];
				for (int i = 0; i < moneyWaveIntervals.Length; i++)
				{
					moneyWaves[i] = new DirectorMoneyWave
					{
						interval = rng.RangeFloat(moneyWaveIntervals[i].min, moneyWaveIntervals[i].max),
						multiplier = creditMultiplier
					};
				}
				monsterCardsSelection = monsterCards?.GenerateDirectorCardWeightedSelection();
			}
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
			if (NetworkServer.active && instancesList.Count > 0)
			{
				float num = 0.4f;
				CombatDirector combatDirector = rng.NextElementUniform(instancesList);
				monsterCredit *= num;
				combatDirector.monsterCredit += monsterCredit;
				UnityEngine.Debug.LogFormat("Transfered {0} monster credits from {1} to {2}", monsterCredit, base.gameObject, combatDirector.gameObject);
				monsterCredit = 0f;
			}
		}

		private void GenerateAmbush(UnityEngine.Vector3 victimPosition)
		{
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			NodeGraph.NodeIndex nodeIndex = groundNodes.FindClosestNode(victimPosition, HullClassification.Human);
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human);
			nodeGraphSpider.AddNodeForNextStep(nodeIndex);
			List<NodeGraphSpider.StepInfo> list = new List<NodeGraphSpider.StepInfo>();
			int num = 0;
			List<NodeGraphSpider.StepInfo> collectedSteps = nodeGraphSpider.collectedSteps;
			while (nodeGraphSpider.PerformStep() && num < 8)
			{
				num++;
				for (int i = 0; i < collectedSteps.Count; i++)
				{
					if (IsAcceptableAmbushSpiderStep(groundNodes, nodeIndex, collectedSteps[i]))
					{
						list.Add(collectedSteps[i]);
					}
				}
				collectedSteps.Clear();
			}
			for (int j = 0; j < list.Count; j++)
			{
				groundNodes.GetNodePosition(list[j].node, out var position);
				LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/scLemurian").DoSpawn(position, UnityEngine.Quaternion.identity, null);
			}
		}

		private static bool IsAcceptableAmbushSpiderStep(NodeGraph nodeGraph, NodeGraph.NodeIndex startNode, NodeGraphSpider.StepInfo stepInfo)
		{
			int num = 0;
			while (stepInfo.previousStep != null)
			{
				if (nodeGraph.TestNodeLineOfSight(startNode, stepInfo.node))
				{
					return false;
				}
				stepInfo = stepInfo.previousStep;
				num++;
				if (num > 2)
				{
					return true;
				}
			}
			return false;
		}

		public void OverrideCurrentMonsterCard(DirectorCard overrideMonsterCard)
		{
			PrepareNewMonsterWave(overrideMonsterCard);
		}

		public void SetNextSpawnAsBoss()
		{
			WeightedSelection<DirectorCard> weightedSelection = new WeightedSelection<DirectorCard>();
			int i = 0;
			for (int count = finalMonsterCardsSelection.Count; i < count; i++)
			{
				WeightedSelection<DirectorCard>.ChoiceInfo choice = finalMonsterCardsSelection.GetChoice(i);
				SpawnCard spawnCard = choice.value.spawnCard;
				bool isChampion = spawnCard.prefab.GetComponent<CharacterMaster>().bodyPrefab.GetComponent<CharacterBody>().isChampion;
				bool flag = (spawnCard as CharacterSpawnCard)?.forbiddenAsBoss ?? false;
				if (isChampion && !flag && choice.value.IsAvailable())
				{
					weightedSelection.AddChoice(choice);
				}
			}
			if (weightedSelection.Count > 0)
			{
				DirectorCard monsterCard = weightedSelection.Evaluate(rng.nextNormalizedFloat);
				PrepareNewMonsterWave(monsterCard);
			}
			monsterSpawnTimer = -600f;
		}

		private void PickPlayerAsSpawnTarget()
		{
			ReadOnlyCollection<PlayerCharacterMasterController> instances = PlayerCharacterMasterController.instances;
			List<PlayerCharacterMasterController> list = new List<PlayerCharacterMasterController>();
			foreach (PlayerCharacterMasterController item in instances)
			{
				if (item.master.hasBody)
				{
					list.Add(item);
				}
			}
			if (list.Count > 0)
			{
				currentSpawnTarget = rng.NextElementUniform(list).master.GetBodyObject();
			}
		}

		public void SpendAllCreditsOnMapSpawns(Transform mapSpawnTarget)
		{
			int num = 0;
			int num2 = 10;
			while (monsterCredit > 0f)
			{
				PrepareNewMonsterWave(finalMonsterCardsSelection.Evaluate(rng.nextNormalizedFloat));
				bool flag = false;
				if ((!mapSpawnTarget) ? AttemptSpawnOnTarget(null, SceneInfo.instance.approximateMapBoundMesh ? DirectorPlacementRule.PlacementMode.RandomNormalized : DirectorPlacementRule.PlacementMode.Random) : AttemptSpawnOnTarget(mapSpawnTarget))
				{
					num = 0;
					continue;
				}
				num++;
				if (num < num2)
				{
					continue;
				}
				break;
			}
		}

		public void ToggleAllCombatDirectorsOnThisObject(bool newValue)
		{
			CombatDirector[] components = GetComponents<CombatDirector>();
			for (int i = 0; i < components.Length; i++)
			{
				components[i].enabled = newValue;
			}
		}

		private void Simulate(float deltaTime)
		{
			if (targetPlayers)
			{
				playerRetargetTimer -= deltaTime;
				if (playerRetargetTimer <= 0f)
				{
					playerRetargetTimer = rng.RangeFloat(1f, 10f);
					PickPlayerAsSpawnTarget();
				}
			}
			monsterSpawnTimer -= deltaTime;
			if (!(monsterSpawnTimer <= 0f))
			{
				return;
			}
			if (AttemptSpawnOnTarget(currentSpawnTarget ? currentSpawnTarget.transform : null))
			{
				if (shouldSpawnOneWave)
				{
					hasStartedWave = true;
				}
				monsterSpawnTimer += rng.RangeFloat(minSeriesSpawnInterval, maxSeriesSpawnInterval);
				return;
			}
			monsterSpawnTimer += rng.RangeFloat(minRerollSpawnInterval, maxRerollSpawnInterval);
			if (resetMonsterCardIfFailed)
			{
				currentMonsterCard = null;
			}
			if (shouldSpawnOneWave && hasStartedWave)
			{
				base.enabled = false;
			}
		}

		public static bool IsEliteOnlyArtifactActive()
		{
			return RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.eliteOnlyArtifactDef);
		}

		private static bool NotEliteOnlyArtifactActive()
		{
			return !IsEliteOnlyArtifactActive();
		}

		[SystemInitializer(new Type[] { typeof(EliteCatalog) })]
		private static void Init()
		{
			eliteTiers = new EliteTierDef[6]
			{
				new EliteTierDef
				{
					costMultiplier = 1f,
					eliteTypes = new EliteDef[1],
					isAvailable = (SpawnCard.EliteRules rules) => NotEliteOnlyArtifactActive(),
					canSelectWithoutAvailableEliteDef = true
				},
				new EliteTierDef
				{
					costMultiplier = baseEliteCostMultiplier,
					eliteTypes = new EliteDef[4]
					{
						RoR2Content.Elites.Lightning,
						RoR2Content.Elites.Ice,
						RoR2Content.Elites.Fire,
						DLC1Content.Elites.Earth
					},
					isAvailable = (SpawnCard.EliteRules rules) => NotEliteOnlyArtifactActive() && rules == SpawnCard.EliteRules.Default,
					canSelectWithoutAvailableEliteDef = false
				},
				new EliteTierDef
				{
					costMultiplier = Mathf.LerpUnclamped(1f, baseEliteCostMultiplier, 0.5f),
					eliteTypes = new EliteDef[4]
					{
						RoR2Content.Elites.LightningHonor,
						RoR2Content.Elites.IceHonor,
						RoR2Content.Elites.FireHonor,
						DLC1Content.Elites.EarthHonor
					},
					isAvailable = (SpawnCard.EliteRules rules) => IsEliteOnlyArtifactActive(),
					canSelectWithoutAvailableEliteDef = false
				},
				new EliteTierDef
				{
					costMultiplier = Mathf.LerpUnclamped(1f, baseEliteCostMultiplier, 0.5f),
					eliteTypes = new EliteDef[5]
					{
						RoR2Content.Elites.Lightning,
						RoR2Content.Elites.Ice,
						RoR2Content.Elites.Fire,
						DLC1Content.Elites.Earth,
						DLC2Content.Elites.Aurelionite
					},
					isAvailable = (SpawnCard.EliteRules rules) => NotEliteOnlyArtifactActive() && rules == SpawnCard.EliteRules.Default && Run.instance.stageClearCount >= 2,
					canSelectWithoutAvailableEliteDef = false
				},
				new EliteTierDef
				{
					costMultiplier = baseEliteCostMultiplier * 6f,
					eliteTypes = new EliteDef[3]
					{
						RoR2Content.Elites.Poison,
						RoR2Content.Elites.Haunted,
						DLC2Content.Elites.Bead
					},
					isAvailable = (SpawnCard.EliteRules rules) => Run.instance.loopClearCount > 0 && rules == SpawnCard.EliteRules.Default,
					canSelectWithoutAvailableEliteDef = false
				},
				new EliteTierDef
				{
					costMultiplier = baseEliteCostMultiplier,
					eliteTypes = new EliteDef[1] { RoR2Content.Elites.Lunar },
					isAvailable = (SpawnCard.EliteRules rules) => rules == SpawnCard.EliteRules.Lunar,
					canSelectWithoutAvailableEliteDef = false
				}
			};
		}

		public static float CalcHighestEliteCostMultiplier(SpawnCard.EliteRules eliteRules)
		{
			float num = 1f;
			for (int i = 1; i < eliteTiers.Length; i++)
			{
				if (eliteTiers[i].CanSelect(eliteRules))
				{
					num = Mathf.Max(num, eliteTiers[i].costMultiplier);
				}
			}
			return num;
		}

		private void ResetEliteType()
		{
			currentActiveEliteTier = eliteTiers[0];
			for (int i = 0; i < eliteTiers.Length; i++)
			{
				if (eliteTiers[i].CanSelect(currentMonsterCard.spawnCard.eliteRules))
				{
					currentActiveEliteTier = eliteTiers[i];
					break;
				}
			}
			currentActiveEliteDef = currentActiveEliteTier.GetRandomAvailableEliteDef(rng);
		}

		private void PrepareNewMonsterWave(DirectorCard monsterCard)
		{
			if (cvDirectorCombatEnableInternalLogs.value)
			{
				UnityEngine.Debug.LogFormat("Preparing monster wave {0}", monsterCard.spawnCard);
			}
			currentMonsterCard = monsterCard;
			ResetEliteType();
			if (!(currentMonsterCard.spawnCard as CharacterSpawnCard).noElites)
			{
				for (int i = 1; i < eliteTiers.Length; i++)
				{
					EliteTierDef eliteTierDef = eliteTiers[i];
					if (!eliteTierDef.CanSelect(currentMonsterCard.spawnCard.eliteRules))
					{
						if (cvDirectorCombatEnableInternalLogs.value)
						{
							UnityEngine.Debug.LogFormat("Elite tier index {0} is unavailable", i);
						}
						continue;
					}
					float num = (float)currentMonsterCard.cost * eliteTierDef.costMultiplier * eliteBias;
					if (num <= monsterCredit)
					{
						currentActiveEliteTier = eliteTierDef;
						if (cvDirectorCombatEnableInternalLogs.value)
						{
							UnityEngine.Debug.LogFormat("Found valid elite tier index {0}", i);
						}
					}
					else if (cvDirectorCombatEnableInternalLogs.value)
					{
						UnityEngine.Debug.LogFormat("Elite tier index {0} is too expensive ({1}/{2})", i, num, monsterCredit);
					}
				}
			}
			else if (cvDirectorCombatEnableInternalLogs.value)
			{
				UnityEngine.Debug.LogFormat("Card {0} cannot be elite. Skipping elite procedure.", currentMonsterCard.spawnCard);
			}
			currentActiveEliteDef = currentActiveEliteTier.GetRandomAvailableEliteDef(rng);
			if (cvDirectorCombatEnableInternalLogs.value)
			{
				UnityEngine.Debug.LogFormat("Assigned elite index {0}", currentActiveEliteDef);
			}
			lastAttemptedMonsterCard = currentMonsterCard;
			spawnCountInCurrentWave = 0;
		}

		private bool AttemptSpawnOnTarget(Transform spawnTarget, DirectorPlacementRule.PlacementMode placementMode = DirectorPlacementRule.PlacementMode.Approximate)
		{
			if (currentMonsterCard == null)
			{
				_ = cvDirectorCombatEnableInternalLogs.value;
				if (finalMonsterCardsSelection == null)
				{
					return false;
				}
				PrepareNewMonsterWave(finalMonsterCardsSelection.Evaluate(rng.nextNormalizedFloat));
			}
			if (spawnCountInCurrentWave >= maximumNumberToSpawnBeforeSkipping)
			{
				spawnCountInCurrentWave = 0;
				if (cvDirectorCombatEnableInternalLogs.value)
				{
					UnityEngine.Debug.LogFormat("Spawn count has hit the max ({0}/{1}). Aborting spawn.", spawnCountInCurrentWave, maximumNumberToSpawnBeforeSkipping);
				}
				return false;
			}
			int num = currentMonsterCard.cost;
			int cost = currentMonsterCard.cost;
			float num2 = 1f;
			EliteDef eliteDef = currentActiveEliteDef;
			cost = (int)((float)num * currentActiveEliteTier.costMultiplier);
			if ((float)cost <= monsterCredit)
			{
				num = cost;
				num2 = currentActiveEliteTier.costMultiplier;
			}
			else
			{
				ResetEliteType();
				eliteDef = currentActiveEliteDef;
			}
			if (!currentMonsterCard.IsAvailable())
			{
				if (cvDirectorCombatEnableInternalLogs.value)
				{
					UnityEngine.Debug.LogFormat("Spawn card {0} is invalid, aborting spawn.", currentMonsterCard.spawnCard);
				}
				return false;
			}
			if (monsterCredit < (float)num)
			{
				if (cvDirectorCombatEnableInternalLogs.value)
				{
					UnityEngine.Debug.LogFormat("Spawn card {0} is too expensive, aborting spawn.", currentMonsterCard.spawnCard);
				}
				return false;
			}
			if (skipSpawnIfTooCheap && consecutiveCheapSkips < maxConsecutiveCheapSkips && (float)(cost * maximumNumberToSpawnBeforeSkipping) < monsterCredit)
			{
				if (cvDirectorCombatEnableInternalLogs.value)
				{
					UnityEngine.Debug.LogFormat("Card {0} seems too cheap ({1}/{2}). Comparing against most expensive possible ({3})", currentMonsterCard.spawnCard, num * maximumNumberToSpawnBeforeSkipping, monsterCredit, mostExpensiveMonsterCostInDeck);
				}
				if (mostExpensiveMonsterCostInDeck > num)
				{
					consecutiveCheapSkips++;
					if (cvDirectorCombatEnableInternalLogs.value)
					{
						UnityEngine.Debug.LogFormat("Spawn card {0} is too cheap, aborting spawn.", currentMonsterCard.spawnCard);
					}
					return false;
				}
			}
			SpawnCard spawnCard = currentMonsterCard.spawnCard;
			if (Spawn(spawnCard, eliteDef, spawnTarget, valueMultiplier: num2, placementMode: placementMode, preventOverhead: currentMonsterCard.preventOverhead, spawnDistance: currentMonsterCard.spawnDistance))
			{
				monsterCredit -= num;
				totalCreditsSpent += num;
				spawnCountInCurrentWave++;
				consecutiveCheapSkips = 0;
				return true;
			}
			return false;
		}

		public bool Spawn(SpawnCard spawnCard, EliteDef eliteDef, Transform spawnTarget, DirectorCore.MonsterSpawnDistance spawnDistance, bool preventOverhead, float valueMultiplier = 1f, DirectorPlacementRule.PlacementMode placementMode = DirectorPlacementRule.PlacementMode.Approximate)
		{
			DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule
			{
				placementMode = placementMode,
				spawnOnTarget = spawnTarget,
				preventOverhead = preventOverhead
			};
			DirectorCore.GetMonsterSpawnDistance(spawnDistance, out directorPlacementRule.minDistance, out directorPlacementRule.maxDistance);
			directorPlacementRule.maxDistance = Mathf.Min(maxSpawnDistance, directorPlacementRule.maxDistance * spawnDistanceMultiplier);
			directorPlacementRule.minDistance = Mathf.Max(0f, Mathf.Min(directorPlacementRule.maxDistance - minSpawnRange, directorPlacementRule.minDistance * spawnDistanceMultiplier));
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, directorPlacementRule, rng);
			directorSpawnRequest.ignoreTeamMemberLimit = ignoreTeamSizeLimit;
			directorSpawnRequest.teamIndexOverride = teamIndex;
			directorSpawnRequest.onSpawnedServer = OnCardSpawned;
			if (!DirectorCore.instance.TrySpawnObject(directorSpawnRequest))
			{
				UnityEngine.Debug.LogFormat("Spawn card {0} failed to spawn. Aborting cost procedures.", spawnCard);
				return false;
			}
			return true;
			void OnCardSpawned(SpawnCard.SpawnResult result)
			{
				if (result.success)
				{
					float num = 1f;
					float num2 = 1f;
					CharacterMaster component = result.spawnedInstance.GetComponent<CharacterMaster>();
					GameObject bodyObject = component.GetBodyObject();
					CharacterBody component2 = bodyObject.GetComponent<CharacterBody>();
					if ((bool)component2)
					{
						component2.cost = valueMultiplier * (float)spawnCard.directorCreditCost;
					}
					if ((bool)combatSquad)
					{
						combatSquad.AddMember(component);
					}
					num = eliteDef?.healthBoostCoefficient ?? 1f;
					num2 = eliteDef?.damageBoostCoefficient ?? 1f;
					if (isHalcyonShrineSpawn)
					{
						if (shrineHalcyoniteDifficultyLevel > 20)
						{
							shrineHalcyoniteDifficultyLevel = 20 + shrineHalcyoniteDifficultyLevel / 100;
						}
						num += (float)shrineHalcyoniteDifficultyLevel * 0.6f;
						num2 += (float)shrineHalcyoniteDifficultyLevel * 0.25f;
						eliteDef = DLC2Content.Elites.Aurelionite;
					}
					EquipmentIndex equipmentIndex = eliteDef?.eliteEquipmentDef?.equipmentIndex ?? EquipmentIndex.None;
					if (equipmentIndex != EquipmentIndex.None)
					{
						component.inventory.SetEquipmentIndex(equipmentIndex);
					}
					if ((bool)combatSquad && combatSquad.grantBonusHealthInMultiplayer)
					{
						int livingPlayerCount = Run.instance.livingPlayerCount;
						num *= Mathf.Pow(livingPlayerCount, 1f);
					}
					component.inventory.GiveItem(RoR2Content.Items.BoostHp, Mathf.RoundToInt((num - 1f) * 10f));
					component.inventory.GiveItem(RoR2Content.Items.BoostDamage, Mathf.RoundToInt((num2 - 1f) * 10f));
					DeathRewards component3 = bodyObject.GetComponent<DeathRewards>();
					if ((bool)component3)
					{
						float num3 = (float)spawnCard.directorCreditCost * valueMultiplier * expRewardCoefficient;
						component3.spawnValue = (int)Mathf.Max(1f, num3);
						if (num3 > Mathf.Epsilon)
						{
							component3.expReward = (uint)Mathf.Max(1f, num3 * Run.instance.compensatedDifficultyCoefficient);
							component3.goldReward = (uint)Mathf.Max(1f, num3 * goldRewardCoefficient * 2f * Run.instance.compensatedDifficultyCoefficient);
						}
						else
						{
							component3.expReward = 0u;
							component3.goldReward = 0u;
						}
					}
					if ((bool)spawnEffectPrefab && NetworkServer.active)
					{
						UnityEngine.Vector3 origin = result.position;
						CharacterBody characterBody = component2;
						if ((bool)characterBody)
						{
							origin = characterBody.corePosition;
						}
						EffectManager.SpawnEffect(spawnEffectPrefab, new EffectData
						{
							origin = origin
						}, transmit: true);
					}
					onSpawnedServer?.Invoke(result.spawnedInstance);
				}
			}
		}

		private void FixedUpdate()
		{
			if (!cvDirectorCombatDisable.value && NetworkServer.active && (bool)Run.instance)
			{
				float compensatedDifficultyCoefficient = Run.instance.compensatedDifficultyCoefficient;
				for (int i = 0; i < moneyWaves.Length; i++)
				{
					float num = moneyWaves[i].Update(Time.fixedDeltaTime, compensatedDifficultyCoefficient);
					monsterCredit += num;
				}
				Simulate(Time.fixedDeltaTime);
			}
		}

		public void CombatShrineActivation(Interactor interactor, float monsterCredit, DirectorCard chosenDirectorCard)
		{
			base.enabled = true;
			this.monsterCredit += monsterCredit;
			OverrideCurrentMonsterCard(chosenDirectorCard);
			monsterSpawnTimer = 0f;
			CharacterMaster component = chosenDirectorCard.spawnCard.prefab.GetComponent<CharacterMaster>();
			if ((bool)component)
			{
				CharacterBody component2 = component.bodyPrefab.GetComponent<CharacterBody>();
				if ((bool)component2)
				{
					Chat.SubjectFormatChatMessage subjectFormatChatMessage = new Chat.SubjectFormatChatMessage();
					subjectFormatChatMessage.subjectAsCharacterBody = interactor.GetComponent<CharacterBody>();
					subjectFormatChatMessage.baseToken = "SHRINE_COMBAT_USE_MESSAGE";
					subjectFormatChatMessage.paramTokens = new string[1] { component2.baseNameToken };
					Chat.SendBroadcastChat(subjectFormatChatMessage);
				}
			}
		}

		public DirectorCard SelectMonsterCardForCombatShrine(float monsterCredit)
		{
			WeightedSelection<DirectorCard> weightedSelection = Util.CreateReasonableDirectorCardSpawnList(monsterCredit, maximumNumberToSpawnBeforeSkipping, 1);
			if (weightedSelection.Count == 0)
			{
				return null;
			}
			return weightedSelection.Evaluate(rng.nextNormalizedFloat);
		}

		public void HalcyoniteShrineActivation(float monsterCredit, DirectorCard chosenDirectorCard, int difficultyLevel, Transform shrineTransform)
		{
			base.enabled = true;
			this.monsterCredit += monsterCredit;
			isHalcyonShrineSpawn = true;
			shrineHalcyoniteDifficultyLevel = difficultyLevel;
			OverrideCurrentMonsterCard(chosenDirectorCard);
			monsterSpawnTimer = 0f;
			Util.PlaySound("Play_halcyonite_spawn", shrineTransform.gameObject);
		}

		public void SetMonsterCredit(float newMonsterCredit)
		{
			monsterCredit = newMonsterCredit;
		}
	}
	public class CombatSquad : NetworkBehaviour
	{
		private List<CharacterMaster> membersList = new List<CharacterMaster>();

		private List<NetworkInstanceId> memberHistory = new List<NetworkInstanceId>();

		public bool propagateMembershipToSummons;

		[Tooltip("Grants a bonus health boost to members of the combat squad, depending on the number of players in the game.")]
		public bool grantBonusHealthInMultiplayer = true;

		private List<OnDestroyCallback> onDestroyCallbacksServer;

		private bool defeatedServer;

		private const uint membersListDirtyBit = 1u;

		private const uint allDirtyBits = 1u;

		[NonSerialized]
		public Run.FixedTimeStamp awakeTime;

		public UnityEvent onDefeatedClientLogicEvent;

		public UnityEvent onDefeatedServerLogicEvent;

		private static int kRpcRpcOnDefeatedClient;

		public ReadOnlyCollection<CharacterMaster> readOnlyMembersList { get; private set; }

		public int memberCount => membersList.Count;

		public event Action onDefeatedServer;

		public event Action<CharacterMaster, DamageReport> onMemberDeathServer;

		public event Action<CharacterMaster, DamageReport> onMemberDefeatedServer;

		public event Action<CharacterMaster> onMemberAddedServer;

		public event Action<CharacterMaster> onMemberDiscovered;

		public event Action<CharacterMaster> onMemberLost;

		private void Awake()
		{
			if (NetworkServer.active)
			{
				onDestroyCallbacksServer = new List<OnDestroyCallback>();
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathCallback;
				MasterSummon.onServerMasterSummonGlobal += OnServerMasterSummonGlobal;
			}
			readOnlyMembersList = new ReadOnlyCollection<CharacterMaster>(membersList);
			awakeTime = Run.FixedTimeStamp.now;
			InstanceTracker.Add(this);
		}

		private void OnEnable()
		{
			if (NetworkServer.active)
			{
				SetDirtyBit(1u);
			}
		}

		private void OnDestroy()
		{
			InstanceTracker.Remove(this);
			if (NetworkServer.active)
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathCallback;
				MasterSummon.onServerMasterSummonGlobal -= OnServerMasterSummonGlobal;
			}
			for (int num = membersList.Count - 1; num >= 0; num--)
			{
				RemoveMemberAt(num);
			}
			onDestroyCallbacksServer = null;
		}

		[Server]
		private void OnServerMasterSummonGlobal(MasterSummon.MasterSummonReport report)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::OnServerMasterSummonGlobal(RoR2.MasterSummon/MasterSummonReport)' called on client");
			}
			else if (propagateMembershipToSummons && (bool)report.leaderMasterInstance && HasContainedMember(report.leaderMasterInstance.netId))
			{
				AddMember(report.summonMasterInstance);
			}
		}

		[Server]
		public void AddMember(CharacterMaster memberMaster)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::AddMember(RoR2.CharacterMaster)' called on client");
				return;
			}
			if (membersList.Count >= 255)
			{
				UnityEngine.Debug.LogFormat("Cannot add character {0} to CombatGroup! Limit of {1} members already reached.", memberMaster, byte.MaxValue);
				return;
			}
			membersList.Add(memberMaster);
			memberHistory.Add(memberMaster.netId);
			SetDirtyBit(1u);
			onDestroyCallbacksServer.Add(OnDestroyCallback.AddCallback(memberMaster.gameObject, OnMemberDestroyedServer));
			this.onMemberAddedServer?.Invoke(memberMaster);
			this.onMemberDiscovered?.Invoke(memberMaster);
		}

		[Server]
		private void OnCharacterDeathCallback(DamageReport damageReport)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::OnCharacterDeathCallback(RoR2.DamageReport)' called on client");
				return;
			}
			CharacterMaster victimMaster = damageReport.victimMaster;
			if (!victimMaster)
			{
				return;
			}
			int num = membersList.IndexOf(victimMaster);
			if (num < 0)
			{
				return;
			}
			this.onMemberDeathServer?.Invoke(victimMaster, damageReport);
			if (victimMaster.IsDeadAndOutOfLivesServer())
			{
				this.onMemberDefeatedServer?.Invoke(victimMaster, damageReport);
				RemoveMemberAt(num);
				if (!defeatedServer && membersList.Count == 0)
				{
					TriggerDefeat();
				}
			}
		}

		[Server]
		private void RemoveMember(CharacterMaster memberMaster)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::RemoveMember(RoR2.CharacterMaster)' called on client");
				return;
			}
			int num = membersList.IndexOf(memberMaster);
			if (num != -1)
			{
				RemoveMemberAt(num);
			}
		}

		private void RemoveMemberAt(int memberIndex)
		{
			CharacterMaster obj = membersList[memberIndex];
			membersList.RemoveAt(memberIndex);
			if (onDestroyCallbacksServer != null)
			{
				onDestroyCallbacksServer.RemoveAt(memberIndex);
			}
			SetDirtyBit(1u);
			this.onMemberLost?.Invoke(obj);
		}

		[Server]
		public void OnMemberDestroyedServer(OnDestroyCallback onDestroyCallback)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CombatSquad::OnMemberDestroyedServer(RoR2.OnDestroyCallback)' called on client");
			}
			else
			{
				if (!onDestroyCallback)
				{
					return;
				}
				GameObject gameObject = onDestroyCallback.gameObject;
				CharacterMaster characterMaster = (gameObject ? gameObject.GetComponent<CharacterMaster>() : null);
				for (int i = 0; i < membersList.Count; i++)
				{
					if ((object)membersList[i] == characterMaster)
					{
						RemoveMemberAt(i);
						break;
					}
				}
			}
		}

		public bool ContainsMember(CharacterMaster master)
		{
			for (int i = 0; i < membersList.Count; i++)
			{
				if ((object)membersList[i] == master)
				{
					return true;
				}
			}
			return false;
		}

		public bool HasContainedMember(NetworkInstanceId id)
		{
			return memberHistory.Contains(id);
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 1u;
			}
			bool num2 = (num & 1) != 0;
			writer.Write((byte)num);
			if (num2)
			{
				writer.Write((byte)membersList.Count);
				for (int i = 0; i < membersList.Count; i++)
				{
					CharacterMaster characterMaster = membersList[i];
					GameObject value = (characterMaster ? characterMaster.gameObject : null);
					writer.Write(value);
				}
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if ((reader.ReadByte() & 1) == 0)
			{
				return;
			}
			List<CharacterMaster> list = CollectionPool<CharacterMaster, List<CharacterMaster>>.RentCollection();
			List<CharacterMaster> list2 = CollectionPool<CharacterMaster, List<CharacterMaster>>.RentCollection();
			List<CharacterMaster> a = CollectionPool<CharacterMaster, List<CharacterMaster>>.RentCollection();
			byte b = reader.ReadByte();
			for (byte b2 = 0; b2 < b; b2++)
			{
				GameObject gameObject = reader.ReadGameObject();
				CharacterMaster item = (gameObject ? gameObject.GetComponent<CharacterMaster>() : null);
				a.Add(item);
			}
			ListUtils.FindExclusiveEntriesByReference(membersList, a, list, list2);
			Util.Swap(ref a, ref membersList);
			CollectionPool<CharacterMaster, List<CharacterMaster>>.ReturnCollection(a);
			for (int i = 0; i < list.Count; i++)
			{
				CharacterMaster characterMaster = list[i];
				if ((bool)characterMaster)
				{
					try
					{
						this.onMemberLost?.Invoke(characterMaster);
					}
					catch (Exception message)
					{
						UnityEngine.Debug.LogError(message);
					}
				}
			}
			for (int j = 0; j < list2.Count; j++)
			{
				CharacterMaster characterMaster2 = list2[j];
				if ((bool)characterMaster2)
				{
					try
					{
						this.onMemberDiscovered?.Invoke(characterMaster2);
					}
					catch (Exception message2)
					{
						UnityEngine.Debug.LogError(message2);
					}
				}
			}
			CollectionPool<CharacterMaster, List<CharacterMaster>>.ReturnCollection(list2);
			CollectionPool<CharacterMaster, List<CharacterMaster>>.ReturnCollection(list);
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active || defeatedServer || memberHistory.Count <= 0)
			{
				return;
			}
			bool flag = false;
			foreach (CharacterMaster members in membersList)
			{
				if (members.hasBody || members.IsExtraLifePendingServer())
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				UnityEngine.Debug.LogError("CombatSquad has no living members.  Triggering defeat...");
				while (membersList.Count > 0)
				{
					RemoveMember(membersList[0]);
				}
				TriggerDefeat();
			}
		}

		private void TriggerDefeat()
		{
			defeatedServer = true;
			this.onDefeatedServer?.Invoke();
			onDefeatedServerLogicEvent?.Invoke();
			membersList?.Clear();
			CallRpcOnDefeatedClient();
		}

		[ClientRpc]
		private void RpcOnDefeatedClient()
		{
			onDefeatedClientLogicEvent?.Invoke();
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcOnDefeatedClient(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnDefeatedClient called on server.");
			}
			else
			{
				((CombatSquad)obj).RpcOnDefeatedClient();
			}
		}

		public void CallRpcOnDefeatedClient()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnDefeatedClient called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnDefeatedClient);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnDefeatedClient");
		}

		static CombatSquad()
		{
			kRpcRpcOnDefeatedClient = -1235734536;
			NetworkBehaviour.RegisterRpcDelegate(typeof(CombatSquad), kRpcRpcOnDefeatedClient, InvokeRpcRpcOnDefeatedClient);
			NetworkCRC.RegisterBehaviour("CombatSquad", 0);
		}

		public override void PreStartClient()
		{
		}
	}
	public class CombineMesh : MonoBehaviour
	{
		private void Start()
		{
			Renderer component = GetComponent<Renderer>();
			MeshFilter[] componentsInChildren = GetComponentsInChildren<MeshFilter>();
			CombineInstance[] array = new CombineInstance[componentsInChildren.Length];
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				array[i].mesh = componentsInChildren[i].sharedMesh;
				array[i].transform = componentsInChildren[i].transform.localToWorldMatrix;
				componentsInChildren[i].gameObject.SetActive(value: false);
			}
			MeshFilter meshFilter = base.gameObject.AddComponent<MeshFilter>();
			meshFilter.mesh = new Mesh();
			meshFilter.mesh.CombineMeshes(array, mergeSubMeshes: true, useMatrices: true, hasLightmapData: true);
			component.material = componentsInChildren[0].GetComponent<Renderer>().sharedMaterial;
			base.gameObject.SetActive(value: true);
		}
	}
	[Flags]
	public enum ConVarFlags
	{
		None = 0,
		ExecuteOnServer = 1,
		SenderMustBeServer = 2,
		Archive = 4,
		Cheat = 8,
		Engine = 0x10
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
	public class ConCommandAttribute : HG.Reflection.SearchableAttribute
	{
		public string commandName;

		public ConVarFlags flags;

		public string helpText = "";
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
	public class ConVarProviderAttribute : System.Attribute
	{
	}
	public struct ConCommandArgs
	{
		public List<string> userArgs;

		public NetworkUser sender;

		public LocalUser localUserSender;

		public string commandName;

		public string this[int i] => userArgs[i];

		public int Count => userArgs.Count;

		public GameObject senderMasterObject
		{
			get
			{
				if (!sender)
				{
					return null;
				}
				return sender.masterObject;
			}
		}

		public CharacterMaster senderMaster
		{
			get
			{
				if (!sender)
				{
					return null;
				}
				return sender.master;
			}
		}

		public CharacterBody senderBody
		{
			get
			{
				if (!sender)
				{
					return null;
				}
				return sender.GetCurrentBody();
			}
		}

		public void CheckArgumentCount(int count)
		{
			ConCommandException.CheckArgumentCount(userArgs, count);
		}

		public string TryGetArgString(int index)
		{
			if ((uint)index < (uint)userArgs.Count)
			{
				return userArgs[index];
			}
			return null;
		}

		public string GetArgString(int index)
		{
			return TryGetArgString(index) ?? throw new ConCommandException($"Argument {index} must be a string.");
		}

		public ulong? TryGetArgUlong(int index)
		{
			if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out ulong result))
			{
				return result;
			}
			return null;
		}

		public ulong GetArgULong(int index)
		{
			ulong? num = TryGetArgUlong(index);
			if (!num.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be an unsigned integer.");
			}
			return num.Value;
		}

		public int? TryGetArgInt(int index)
		{
			if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out int result))
			{
				return result;
			}
			return null;
		}

		public int GetArgInt(int index)
		{
			int? num = TryGetArgInt(index);
			if (!num.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be an integer.");
			}
			return num.Value;
		}

		public bool? TryGetArgBool(int index)
		{
			int? num = TryGetArgInt(index);
			if (num.HasValue)
			{
				return num > 0;
			}
			return null;
		}

		public bool GetArgBool(int index)
		{
			int? num = TryGetArgInt(index);
			if (!num.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be a boolean.");
			}
			return num.Value > 0;
		}

		public float? TryGetArgFloat(int index)
		{
			if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out float result))
			{
				return result;
			}
			return null;
		}

		public float GetArgFloat(int index)
		{
			float? num = TryGetArgFloat(index);
			if (!num.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be a number.");
			}
			return num.Value;
		}

		public double? TryGetArgDouble(int index)
		{
			if ((uint)index < (uint)userArgs.Count && TextSerialization.TryParseInvariant(userArgs[index], out double result))
			{
				return result;
			}
			return null;
		}

		public double GetArgDouble(int index)
		{
			double? num = TryGetArgDouble(index);
			if (!num.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be a number.");
			}
			return num.Value;
		}

		public T? TryGetArgEnum<T>(int index) where T : struct
		{
			if ((uint)index < (uint)userArgs.Count && Enum.TryParse<T>(userArgs[index], ignoreCase: true, out var result))
			{
				return result;
			}
			return null;
		}

		public T GetArgEnum<T>(int index) where T : struct
		{
			T? val = TryGetArgEnum<T>(index);
			if (!val.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be one of the values of {typeof(T).Name}.");
			}
			return val.Value;
		}

		public PlatformID? TryGetArgPlatformID(int index)
		{
			if ((uint)index < (uint)userArgs.Count && PlatformID.TryParse(userArgs[index], out var result))
			{
				return result;
			}
			return null;
		}

		public PlatformID GetArgPlatformID(int index)
		{
			PlatformID? platformID = TryGetArgPlatformID(index);
			if (!platformID.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be a valid Steam ID.");
			}
			return platformID.Value;
		}

		public AddressPortPair? TryGetArgAddressPortPair(int index)
		{
			if ((uint)index < (uint)userArgs.Count && AddressPortPair.TryParse(userArgs[index], out var addressPortPair))
			{
				return addressPortPair;
			}
			return null;
		}

		public AddressPortPair GetArgAddressPortPair(int index)
		{
			AddressPortPair? addressPortPair = TryGetArgAddressPortPair(index);
			if (!addressPortPair.HasValue)
			{
				throw new ConCommandException($"Argument {index} must be a valid address and port pair in the format \"address:port\" (e.g. \"127.0.0.1:27015\"). Given value: {TryGetArgString(index)}");
			}
			return addressPortPair.Value;
		}

		public PickupIndex GetArgPickupIndex(int index)
		{
			PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(TryGetArgString(index) ?? string.Empty);
			if (pickupIndex == PickupIndex.none)
			{
				throw new ConCommandException($"Argument {index} must be a valid pickup name.");
			}
			return pickupIndex;
		}

		public LocalUser GetSenderLocalUser()
		{
			return localUserSender ?? throw new ConCommandException($"Command requires a local user that is not available.");
		}

		public CharacterBody TryGetSenderBody()
		{
			if (!sender)
			{
				return null;
			}
			return sender.GetCurrentBody();
		}

		public CharacterBody GetSenderBody()
		{
			CharacterBody characterBody = TryGetSenderBody();
			if ((bool)characterBody)
			{
				return characterBody;
			}
			throw new ConCommandException("Command requires the sender to have a body.");
		}

		public CharacterMaster GetSenderMaster()
		{
			if (!senderMaster)
			{
				throw new ConCommandException("Command requires the sender to have a CharacterMaster. The game must be in an active run and the sender must be a participating player.");
			}
			return senderMaster;
		}

		public void Log(string message)
		{
		}
	}
	[Serializable]
	public class ConCommandException : Exception
	{
		public ConCommandException()
		{
		}

		public ConCommandException(string message)
			: base(message)
		{
		}

		public ConCommandException(string message, Exception inner)
			: base(message, inner)
		{
		}

		protected ConCommandException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public static void CheckArgumentCount(List<string> args, int requiredArgCount)
		{
			if (args.Count < requiredArgCount)
			{
				throw new ConCommandException($"{requiredArgCount} argument(s) required, {args.Count} argument(s) provided.");
			}
		}
	}
	public class Console : MonoBehaviour
	{
		public struct Log
		{
			public string message;

			public string stackTrace;

			public LogType logType;
		}

		public delegate void LogReceivedDelegate(Log log);

		private class Lexer
		{
			private enum TokenType
			{
				Identifier,
				NestedString
			}

			private string srcString;

			private int readIndex;

			private StringBuilder stringBuilder = new StringBuilder();

			public Lexer(string srcString)
			{
				this.srcString = srcString;
				readIndex = 0;
			}

			private static bool IsIgnorableCharacter(char character)
			{
				if (!IsSeparatorCharacter(character) && !IsQuoteCharacter(character) && !IsIdentifierCharacter(character))
				{
					return character != '/';
				}
				return false;
			}

			private static bool IsSeparatorCharacter(char character)
			{
				if (character != ';')
				{
					return character == '\n';
				}
				return true;
			}

			private static bool IsQuoteCharacter(char character)
			{
				if (character != '\'')
				{
					return character == '"';
				}
				return true;
			}

			private static bool IsIdentifierCharacter(char character)
			{
				if (!char.IsLetterOrDigit(character) && character != '_' && character != '.' && character != '-')
				{
					return character == ':';
				}
				return true;
			}

			private bool TrimComment()
			{
				if (readIndex >= srcString.Length)
				{
					return false;
				}
				if (srcString[readIndex] == '/')
				{
					if (readIndex + 1 < srcString.Length)
					{
						char c = srcString[readIndex + 1];
						if (c == '/')
						{
							while (readIndex < srcString.Length)
							{
								if (srcString[readIndex] == '\n')
								{
									readIndex++;
									return true;
								}
								readIndex++;
							}
							return true;
						}
						if (c == '*')
						{
							while (readIndex < srcString.Length - 1)
							{
								if (srcString[readIndex] == '*' && srcString[readIndex + 1] == '/')
								{
									readIndex += 2;
									return true;
								}
								readIndex++;
							}
							return true;
						}
					}
					readIndex++;
				}
				return false;
			}

			private void TrimWhitespace()
			{
				while (readIndex < srcString.Length && IsIgnorableCharacter(srcString[readIndex]))
				{
					readIndex++;
				}
			}

			private void TrimUnused()
			{
				do
				{
					TrimWhitespace();
				}
				while (TrimComment());
			}

			private static int UnescapeNext(string srcString, int startPos, out char result)
			{
				result = '\\';
				int num = startPos;
				num++;
				if (num < srcString.Length)
				{
					char c = srcString[num];
					switch (c)
					{
					case '"':
					case '\'':
					case '\\':
						result = c;
						return 2;
					case 'n':
						result = '\n';
						return 2;
					}
				}
				return 1;
			}

			public string NextToken()
			{
				TrimUnused();
				if (readIndex == srcString.Length)
				{
					return null;
				}
				TokenType tokenType = TokenType.Identifier;
				char c = srcString[readIndex];
				char c2 = '\0';
				if (IsQuoteCharacter(c))
				{
					tokenType = TokenType.NestedString;
					c2 = c;
					readIndex++;
				}
				else if (IsSeparatorCharacter(c))
				{
					readIndex++;
					return ";";
				}
				char result;
				for (; readIndex < srcString.Length; stringBuilder.Append(result), readIndex++)
				{
					result = srcString[readIndex];
					switch (tokenType)
					{
					case TokenType.Identifier:
						if (IsIdentifierCharacter(result))
						{
							continue;
						}
						break;
					case TokenType.NestedString:
						if (result == '\\')
						{
							readIndex += UnescapeNext(srcString, readIndex, out result) - 1;
							continue;
						}
						if (result != c2)
						{
							continue;
						}
						readIndex++;
						break;
					default:
						continue;
					}
					break;
				}
				string result2 = stringBuilder.ToString();
				stringBuilder.Length = 0;
				return result2;
			}

			public Queue<string> GetTokens()
			{
				Queue<string> queue = new Queue<string>();
				for (string text = NextToken(); text != null; text = NextToken())
				{
					queue.Enqueue(text);
				}
				queue.Enqueue(";");
				return queue;
			}
		}

		private class Substring
		{
			public string srcString;

			public int startIndex;

			public int length;

			public int endIndex => startIndex + length;

			public string str => srcString.Substring(startIndex, length);

			public Substring nextToken => new Substring
			{
				srcString = srcString,
				startIndex = startIndex + length,
				length = 0
			};
		}

		private class ConCommand
		{
			public ConVarFlags flags;

			public ConCommandDelegate action;

			public string helpText;
		}

		public delegate void ConCommandDelegate(ConCommandArgs args);

		private class ConvarClass
		{
			public string containerAssemblyName;

			public List<string> convars = new List<string>();
		}

		public readonly struct CmdSender
		{
			public readonly LocalUser localUser;

			public readonly NetworkUser networkUser;

			public CmdSender(LocalUser localUser)
			{
				this.localUser = localUser;
				networkUser = localUser?.currentNetworkUser;
			}

			public CmdSender(NetworkUser networkUser)
			{
				localUser = networkUser?.localUser;
				this.networkUser = networkUser;
			}

			public static implicit operator CmdSender(LocalUser localUser)
			{
				return new CmdSender(localUser);
			}

			public static implicit operator CmdSender(NetworkUser networkUser)
			{
				return new CmdSender(networkUser);
			}
		}

		private enum SystemConsoleType
		{
			None,
			Attach,
			Alloc
		}

		public class AutoComplete
		{
			private struct MatchInfo
			{
				public string str;

				public int similarity;
			}

			private List<string> searchableStrings = new List<string>();

			private string searchString;

			public List<string> resultsList = new List<string>();

			public List<string> GetSearchableStrings => searchableStrings;

			public AutoComplete(Console console)
			{
				HashSet<string> hashSet = new HashSet<string>();
				for (int i = 0; i < userCmdHistory.Count; i++)
				{
					hashSet.Add(userCmdHistory[i]);
				}
				foreach (KeyValuePair<string, BaseConVar> allConVar in console.allConVars)
				{
					hashSet.Add(allConVar.Key);
				}
				foreach (KeyValuePair<string, ConCommand> item in console.concommandCatalog)
				{
					hashSet.Add(item.Key);
				}
				foreach (string item2 in hashSet)
				{
					searchableStrings.Add(item2);
				}
				searchableStrings.Sort();
			}

			public bool SetSearchString(string newSearchString)
			{
				newSearchString = newSearchString.ToLower(CultureInfo.InvariantCulture);
				if (newSearchString == searchString)
				{
					return false;
				}
				searchString = newSearchString;
				List<MatchInfo> list = new List<MatchInfo>();
				for (int i = 0; i < searchableStrings.Count; i++)
				{
					string text = searchableStrings[i];
					int num = Math.Min(text.Length, searchString.Length);
					int j;
					for (j = 0; j < num && char.ToLower(text[j]) == searchString[j]; j++)
					{
					}
					if (j > 1)
					{
						list.Add(new MatchInfo
						{
							str = text,
							similarity = j
						});
					}
				}
				list.Sort(delegate(MatchInfo a, MatchInfo b)
				{
					if (a.similarity == b.similarity)
					{
						return string.CompareOrdinal(a.str, b.str);
					}
					return (a.similarity <= b.similarity) ? 1 : (-1);
				});
				resultsList = new List<string>();
				for (int k = 0; k < list.Count; k++)
				{
					resultsList.Add(list[k].str);
				}
				return true;
			}
		}

		public class CheatsConVar : BaseConVar
		{
			public static readonly CheatsConVar instance = new CheatsConVar("cheats", ConVarFlags.ExecuteOnServer, "0", "Enable cheats. Achievements, unlock progression, and stat tracking will be disabled until the application is restarted.");

			private bool _boolValue;

			public bool boolValue
			{
				get
				{
					return _boolValue;
				}
				private set
				{
					if (_boolValue)
					{
						sessionCheatsEnabled = true;
					}
				}
			}

			public CheatsConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					boolValue = result != 0;
				}
			}

			public override string GetString()
			{
				if (!boolValue)
				{
					return "0";
				}
				return "1";
			}
		}

		public static List<Log> logs = new List<Log>();

		private Dictionary<string, string> vstrs = new Dictionary<string, string>();

		private Dictionary<string, ConCommand> concommandCatalog = new Dictionary<string, ConCommand>();

		private Dictionary<string, BaseConVar> allConVars;

		private List<BaseConVar> archiveConVars;

		public static List<string> userCmdHistory = new List<string>();

		private const int VK_RETURN = 13;

		private const int WM_KEYDOWN = 256;

		private static byte[] inputStreamBuffer = new byte[256];

		private static Queue<string> stdInQueue = new Queue<string>();

		private static Thread stdInReaderThread = null;

		private static SystemConsoleType systemConsoleType = SystemConsoleType.None;

		public static bool loadingIsComplete = false;

		private int maxPassesBeforeYielding = 25;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		private const string configFolder = "/Config/";

		private const string archiveConVarsPath = "/Config/config.cfg";

		private static IntConVar maxMessages = new IntConVar("max_messages", ConVarFlags.Archive, "25", "Maximum number of messages that can be held in the console log.");

		public static Console instance { get; private set; }

		public static bool sessionCheatsEnabled { get; private set; } = false;


		public static event LogReceivedDelegate onLogReceived;

		public static event Action onClear;

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
		private static void RegisterLogHandler()
		{
			Application.logMessageReceived += HandleLog;
		}

		private static void HandleLog(string message, string stackTrace, LogType logType)
		{
			switch (logType)
			{
			case LogType.Error:
				message = string.Format(CultureInfo.InvariantCulture, "<color=#FF0000>{0}</color>", message);
				break;
			case LogType.Warning:
				message = string.Format(CultureInfo.InvariantCulture, "<color=#FFFF00>{0}</color>", message);
				break;
			}
			Log log = default(Log);
			log.message = message;
			log.stackTrace = stackTrace;
			log.logType = logType;
			Log log2 = log;
			logs.Add(log2);
			if (maxMessages.value > 0)
			{
				while (logs.Count > maxMessages.value)
				{
					logs.RemoveAt(0);
				}
			}
			if (Console.onLogReceived != null)
			{
				Console.onLogReceived(log2);
			}
		}

		private string GetVstrValue(LocalUser user, string identifier)
		{
			if (user == null)
			{
				if (vstrs.TryGetValue(identifier, out var value))
				{
					return value;
				}
				return "";
			}
			return "";
		}

		public void CacheConVars()
		{
			_ = typeof(BaseConVar).Assembly;
			List<ConvarClass> list = new List<ConvarClass>();
			Type[] types = typeof(BaseConVar).Assembly.GetTypes();
			foreach (Type type in types)
			{
				bool flag = false;
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.FieldType.IsSubclassOf(typeof(BaseConVar)))
					{
						continue;
					}
					if (fieldInfo.IsStatic)
					{
						BaseConVar conVar = (BaseConVar)fieldInfo.GetValue(null);
						RegisterConVarInternal(conVar);
						if (!flag)
						{
							flag = true;
							list.Add(new ConvarClass
							{
								containerAssemblyName = type.FullName
							});
						}
						list[list.Count - 1].convars.Add(fieldInfo.Name);
					}
					else if (CustomAttributeExtensions.GetCustomAttribute<CompilerGeneratedAttribute>(type) == null)
					{
						UnityEngine.Debug.LogErrorFormat("ConVar defined as {0}.{1} could not be registered. ConVars must be static fields.", type.Name, fieldInfo.Name);
					}
				}
				MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (CustomAttributeExtensions.GetCustomAttribute<ConVarProviderAttribute>(methodInfo) == null)
					{
						continue;
					}
					UnityEngine.Debug.LogErrorFormat("ConVarProviderAttribute on method {0}.{1}", type.Name, methodInfo.Name);
					if (methodInfo.ReturnType != typeof(IEnumerable<BaseConVar>) || methodInfo.GetParameters().Length != 0)
					{
						UnityEngine.Debug.LogErrorFormat("ConVar provider {0}.{1} does not match the signature \"static IEnumerable<ConVar.BaseConVar>()\".", type.Name, methodInfo.Name);
						continue;
					}
					if (!methodInfo.IsStatic)
					{
						UnityEngine.Debug.LogErrorFormat("ConVar provider {0}.{1} could not be invoked. Methods marked with the ConVarProvider attribute must be static.", type.Name, methodInfo.Name);
						continue;
					}
					foreach (BaseConVar item in (IEnumerable<BaseConVar>)methodInfo.Invoke(null, Array.Empty<object>()))
					{
						RegisterConVarInternal(item);
					}
				}
			}
			if (list.Count <= 0)
			{
				return;
			}
			StreamWriter streamWriter = new StreamWriter(Application.streamingAssetsPath + "/ConVarNames.txt");
			foreach (ConvarClass item2 in list)
			{
				streamWriter.WriteLine(item2.containerAssemblyName);
				streamWriter.WriteLine(item2.convars.Count);
				foreach (string convar in item2.convars)
				{
					streamWriter.WriteLine(convar);
				}
			}
			streamWriter.Close();
		}

		private IEnumerator InternalInitConVarsCoroutine()
		{
			CacheConVars();
			yield return null;
			string path = Application.streamingAssetsPath + "/ConVarNames.txt";
			string[] fileLines;
			int curLine;
			if (File.Exists(path))
			{
				fileLines = File.ReadAllLines(path);
				curLine = 0;
				StringBuilder sb = new StringBuilder(256);
				string assemblyName = typeof(BaseConVar).Assembly.FullName;
				int currentPass = 0;
				while (!EndOfStream())
				{
					string text = ReadLine();
					if (!string.IsNullOrEmpty(text))
					{
						int num = int.Parse(ReadLine());
						sb.Clear();
						sb.AppendFormat("{0}, {1}", text, assemblyName);
						Type type = Type.GetType(sb.ToString());
						if (type != null)
						{
							for (int i = 0; i < num; i++)
							{
								string text2 = ReadLine();
								FieldInfo field = type.GetField(text2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
								if (field != null)
								{
									BaseConVar conVar = (BaseConVar)field.GetValue(null);
									RegisterConVarInternal(conVar);
								}
								else
								{
									UnityEngine.Debug.LogError("Failed to find convar " + text2);
								}
							}
						}
						else
						{
							UnityEngine.Debug.LogErrorFormat("Failed to get type {0} (Full name: {1})", text, sb.ToString());
							for (int j = 0; j < num; j++)
							{
								ReadLine();
							}
						}
					}
					currentPass++;
					if (currentPass >= maxPassesBeforeYielding)
					{
						currentPass = 0;
						yield return null;
					}
				}
			}
			else
			{
				UnityEngine.Debug.LogError("ERROR: Failed to load StreamingAssets/ConVarNames.txt");
			}
			bool EndOfStream()
			{
				return curLine >= fileLines.Length;
			}
			string ReadLine()
			{
				return fileLines[curLine++];
			}
		}

		private void InternalInitConVars()
		{
			string path = Application.streamingAssetsPath + "/ConVarNames.txt";
			string[] fileLines;
			int curLine;
			if (File.Exists(path))
			{
				fileLines = File.ReadAllLines(path);
				curLine = 0;
				StringBuilder stringBuilder = new StringBuilder(256);
				string fullName = typeof(BaseConVar).Assembly.FullName;
				while (!EndOfStream())
				{
					string text = ReadLine();
					if (string.IsNullOrEmpty(text))
					{
						continue;
					}
					int num = int.Parse(ReadLine());
					stringBuilder.Clear();
					stringBuilder.AppendFormat("{0}, {1}", text, fullName);
					Type type = Type.GetType(stringBuilder.ToString());
					if (type != null)
					{
						for (int i = 0; i < num; i++)
						{
							string text2 = ReadLine();
							FieldInfo field = type.GetField(text2, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
							if (field != null)
							{
								BaseConVar conVar = (BaseConVar)field.GetValue(null);
								RegisterConVarInternal(conVar);
							}
							else
							{
								UnityEngine.Debug.LogError("Failed to find convar " + text2);
							}
						}
					}
					else
					{
						UnityEngine.Debug.LogErrorFormat("Failed to get type {0} (Full name: {1})", text, stringBuilder.ToString());
						for (int j = 0; j < num; j++)
						{
							ReadLine();
						}
					}
				}
			}
			else
			{
				UnityEngine.Debug.LogError("ERROR: Failed to load StreamingAssets/ConVarNames.txt");
			}
			bool EndOfStream()
			{
				return curLine >= fileLines.Length;
			}
			string ReadLine()
			{
				return fileLines[curLine++];
			}
		}

		public IEnumerator InitConVarsCoroutine()
		{
			allConVars = new Dictionary<string, BaseConVar>();
			archiveConVars = new List<BaseConVar>();
			yield return InternalInitConVarsCoroutine();
			int currentPass = 0;
			foreach (KeyValuePair<string, BaseConVar> allConVar in allConVars)
			{
				try
				{
					BaseConVar value = allConVar.Value;
					if ((value.flags & ConVarFlags.Engine) != 0)
					{
						value.defaultValue = value.GetString();
					}
					else if (value.defaultValue != null)
					{
						value.AttemptSetString(value.defaultValue);
					}
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
				currentPass++;
				if (currentPass >= maxPassesBeforeYielding)
				{
					currentPass = 0;
					yield return null;
				}
			}
		}

		public void InitConVars()
		{
			allConVars = new Dictionary<string, BaseConVar>();
			archiveConVars = new List<BaseConVar>();
			InternalInitConVars();
			foreach (KeyValuePair<string, BaseConVar> allConVar in allConVars)
			{
				try
				{
					BaseConVar value = allConVar.Value;
					if ((value.flags & ConVarFlags.Engine) != 0)
					{
						value.defaultValue = value.GetString();
					}
					else if (value.defaultValue != null)
					{
						value.AttemptSetString(value.defaultValue);
					}
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
		}

		private void RegisterConVarInternal(BaseConVar conVar)
		{
			if (conVar == null)
			{
				UnityEngine.Debug.LogWarning("Attempted to register null ConVar");
				return;
			}
			allConVars[conVar.name] = conVar;
			if ((conVar.flags & ConVarFlags.Archive) != 0)
			{
				archiveConVars.Add(conVar);
			}
		}

		public BaseConVar FindConVar(string name)
		{
			if (allConVars.TryGetValue(name, out var value))
			{
				return value;
			}
			return null;
		}

		public void SubmitCmd(NetworkUser sender, string cmd, bool recordSubmit = false)
		{
			SubmitCmd((CmdSender)sender, cmd, recordSubmit);
		}

		public void SubmitCmd(CmdSender sender, string cmd, bool recordSubmit = false)
		{
			if (recordSubmit)
			{
				Log log = default(Log);
				log.message = string.Format(CultureInfo.InvariantCulture, "<color=#C0C0C0>] {0}</color>", cmd);
				log.stackTrace = "";
				log.logType = LogType.Log;
				Log log2 = log;
				logs.Add(log2);
				if (Console.onLogReceived != null)
				{
					Console.onLogReceived(log2);
				}
				userCmdHistory.Add(cmd);
			}
			Queue<string> tokens = new Lexer(cmd).GetTokens();
			List<string> list = new List<string>();
			bool flag = false;
			while (tokens.Count != 0)
			{
				string text = tokens.Dequeue();
				if (text == ";")
				{
					flag = false;
					if (list.Count > 0)
					{
						string concommandName = list[0].ToLower(CultureInfo.InvariantCulture);
						list.RemoveAt(0);
						RunCmd(sender, concommandName, list);
						list.Clear();
					}
				}
				else
				{
					if (flag)
					{
						text = GetVstrValue(sender.localUser, text);
						flag = false;
					}
					if (text == "vstr")
					{
						flag = true;
					}
					else
					{
						list.Add(text);
					}
				}
			}
		}

		private void ForwardCmdToServer(ConCommandArgs args)
		{
			if ((bool)args.sender)
			{
				args.sender.CallCmdSendConsoleCommand(args.commandName, args.userArgs.ToArray());
			}
		}

		public void RunClientCmd(NetworkUser sender, string concommandName, string[] args)
		{
			RunCmd(sender, concommandName, new List<string>(args));
		}

		private void RunCmd(CmdSender sender, string concommandName, List<string> userArgs)
		{
			bool flag = !(sender.networkUser?.isLocalPlayer ?? true);
			ConVarFlags conVarFlags = ConVarFlags.None;
			ConCommand value = null;
			BaseConVar baseConVar = null;
			if (concommandCatalog.TryGetValue(concommandName, out value))
			{
				conVarFlags = value.flags;
			}
			else
			{
				baseConVar = FindConVar(concommandName);
				if (baseConVar == null)
				{
					UnityEngine.Debug.LogFormat("\"{0}\" is not a recognized ConCommand or ConVar.", concommandName);
					return;
				}
				conVarFlags = baseConVar.flags;
			}
			bool flag2 = (conVarFlags & ConVarFlags.ExecuteOnServer) != 0;
			if (!NetworkServer.active && flag2)
			{
				ForwardCmdToServer(new ConCommandArgs
				{
					sender = sender.networkUser,
					commandName = concommandName,
					userArgs = userArgs
				});
				return;
			}
			if (flag && (conVarFlags & ConVarFlags.SenderMustBeServer) != 0)
			{
				UnityEngine.Debug.LogFormat("Blocked server-only command {0} from remote user {1}.", concommandName, sender.networkUser.userName);
				return;
			}
			if (flag && !flag2)
			{
				UnityEngine.Debug.LogFormat("Blocked non-transmittable command {0} from remote user {1}.", concommandName, sender.networkUser.userName);
				return;
			}
			if ((conVarFlags & ConVarFlags.Cheat) != 0 && !CheatsConVar.instance.boolValue)
			{
				UnityEngine.Debug.LogFormat("Command \"{0}\" cannot be used while cheats are disabled.", concommandName);
				return;
			}
			if (value != null)
			{
				try
				{
					value.action(new ConCommandArgs
					{
						sender = sender.networkUser,
						localUserSender = sender.localUser,
						commandName = concommandName,
						userArgs = userArgs
					});
					return;
				}
				catch (ConCommandException ex)
				{
					UnityEngine.Debug.LogFormat("Command \"{0}\" failed: {1}", concommandName, ex.Message);
					return;
				}
			}
			if (baseConVar != null)
			{
				if (userArgs.Count > 0)
				{
					baseConVar.AttemptSetString(userArgs[0]);
					return;
				}
				UnityEngine.Debug.LogFormat("\"{0}\" = \"{1}\"\n{2}", concommandName, baseConVar.GetString(), baseConVar.helpText);
			}
		}

		[DllImport("kernel32.dll")]
		private static extern bool AllocConsole();

		[DllImport("kernel32.dll")]
		private static extern bool FreeConsole();

		[DllImport("kernel32.dll")]
		private static extern bool AttachConsole(int processId);

		[DllImport("user32.dll")]
		private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

		[DllImport("kernel32.dll")]
		private static extern IntPtr GetConsoleWindow();

		private static string ReadInputStream()
		{
			if (stdInQueue.Count > 0)
			{
				return stdInQueue.Dequeue();
			}
			return null;
		}

		private static void ThreadedInputQueue()
		{
			string item;
			while (systemConsoleType != 0 && (item = System.Console.ReadLine()) != null)
			{
				stdInQueue.Enqueue(item);
			}
		}

		private static void SetupSystemConsole()
		{
			bool flag = false;
			bool flag2 = false;
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			for (int i = 0; i < commandLineArgs.Length; i++)
			{
				if (commandLineArgs[i] == "-console")
				{
					flag = flag || true;
				}
				if (commandLineArgs[i] == "-console_detach")
				{
					flag2 = flag2 || true;
				}
			}
			if (flag)
			{
				systemConsoleType = SystemConsoleType.Attach;
				if (flag2)
				{
					systemConsoleType = SystemConsoleType.Alloc;
				}
			}
			switch (systemConsoleType)
			{
			case SystemConsoleType.Attach:
				AttachConsole(-1);
				break;
			case SystemConsoleType.Alloc:
				AllocConsole();
				break;
			}
			if (systemConsoleType != 0)
			{
				System.Console.SetIn(new StreamReader(System.Console.OpenStandardInput()));
				stdInReaderThread = new Thread(ThreadedInputQueue);
				stdInReaderThread.Start();
			}
		}

		private void Awake()
		{
			instance = this;
			loadingIsComplete = false;
			StartCoroutine(AwakeCoroutine());
		}

		private IEnumerator AwakeCoroutine()
		{
			SetupSystemConsole();
			yield return InitConVarsCoroutine();
			List<HG.Reflection.SearchableAttribute> instances = HG.Reflection.SearchableAttribute.GetInstances<ConCommandAttribute>();
			int currentPass = 0;
			foreach (ConCommandAttribute item in instances)
			{
				concommandCatalog[item.commandName.ToLower(CultureInfo.InvariantCulture)] = new ConCommand
				{
					flags = item.flags,
					action = (ConCommandDelegate)Delegate.CreateDelegate(typeof(ConCommandDelegate), item.target as MethodInfo),
					helpText = item.helpText
				};
				currentPass++;
				if (currentPass >= maxPassesBeforeYielding)
				{
					currentPass = 0;
					yield return null;
				}
			}
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			stringBuilder.AppendLine("Launch Parameters: ");
			for (int i = 0; i < commandLineArgs.Length; i++)
			{
				stringBuilder.Append("  arg[").AppendInt(i).Append("]=\"")
					.Append(commandLineArgs[i])
					.Append("\"")
					.AppendLine();
			}
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			MPEventSystemManager.availability.CallWhenAvailable(LoadStartupConfigs);
			loadingIsComplete = true;
		}

		private void LoadStartupConfigs()
		{
			try
			{
				SubmitCmd(null, "exec config");
				SubmitCmd(null, "exec autoexec");
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private void Update()
		{
			string cmd;
			while ((cmd = ReadInputStream()) != null)
			{
				SubmitCmd(null, cmd, recordSubmit: true);
			}
		}

		private void OnDestroy()
		{
			if (stdInReaderThread != null)
			{
				stdInReaderThread = null;
			}
			if (systemConsoleType != 0)
			{
				systemConsoleType = SystemConsoleType.None;
				IntPtr consoleWindow = GetConsoleWindow();
				if (consoleWindow != IntPtr.Zero)
				{
					PostMessage(consoleWindow, 256u, 13, 0);
				}
				if (stdInReaderThread != null)
				{
					stdInReaderThread.Join();
					stdInReaderThread = null;
				}
				FreeConsole();
			}
		}

		private static string LoadConfig(string fileName)
		{
			string text = sharedStringBuilder.Clear().Append("/Config/").Append(fileName)
				.Append(".cfg")
				.ToString();
			try
			{
				return PlatformSystems.textDataManager.GetConfFile(fileName, text);
			}
			catch (IOException ex)
			{
				UnityEngine.Debug.LogFormat("Could not load config {0}: {1}", text, ex.Message);
			}
			return null;
		}

		public void SaveArchiveConVars()
		{
			using MemoryStream memoryStream = new MemoryStream();
			using TextWriter textWriter = new StreamWriter(memoryStream, Encoding.UTF8);
			for (int i = 0; i < archiveConVars.Count; i++)
			{
				BaseConVar baseConVar = archiveConVars[i];
				textWriter.Write(baseConVar.name);
				textWriter.Write(" ");
				textWriter.Write(baseConVar.GetString());
				textWriter.Write(";\r\n");
			}
			textWriter.Write("echo \"Loaded archived convars.\";");
			textWriter.Flush();
			RoR2Application.fileSystem.CreateDirectory("/Config/");
			try
			{
				using Stream stream = RoR2Application.fileSystem.OpenFile("/Config/config.cfg", FileMode.Create, FileAccess.Write);
				if (stream != null)
				{
					stream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
					stream.Close();
				}
			}
			catch (IOException ex)
			{
				UnityEngine.Debug.LogFormat("Failed to write archived convars: {0}", ex.Message);
			}
		}

		[ConCommand(commandName = "set_vstr", flags = ConVarFlags.None, helpText = "Sets the specified vstr to the specified value.")]
		private static void CCSetVstr(ConCommandArgs args)
		{
			args.CheckArgumentCount(2);
			instance.vstrs.Add(args[0], args[1]);
		}

		[ConCommand(commandName = "exec", flags = ConVarFlags.None, helpText = "Executes a named config from the \"Config/\" folder.")]
		private static void CCExec(ConCommandArgs args)
		{
			if (args.Count > 0)
			{
				string text = LoadConfig(args[0]);
				if (text != null)
				{
					instance.SubmitCmd(args.sender, text);
				}
			}
		}

		[ConCommand(commandName = "echo", flags = ConVarFlags.None, helpText = "Echoes the given text to the console.")]
		private static void CCEcho(ConCommandArgs args)
		{
			if (args.Count <= 0)
			{
				ShowHelpText(args.commandName);
			}
		}

		[ConCommand(commandName = "cvarlist", flags = ConVarFlags.None, helpText = "Print all available convars and concommands.")]
		private static void CCCvarList(ConCommandArgs args)
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, BaseConVar> allConVar in instance.allConVars)
			{
				list.Add(allConVar.Key);
			}
			foreach (KeyValuePair<string, ConCommand> item in instance.concommandCatalog)
			{
				list.Add(item.Key);
			}
			list.Sort();
		}

		[ConCommand(commandName = "help", flags = ConVarFlags.None, helpText = "Show help text for the named convar or concommand.")]
		private static void CCHelp(ConCommandArgs args)
		{
			if (args.Count == 0)
			{
				instance.SubmitCmd(args.sender, "find \"*\"");
			}
			else
			{
				ShowHelpText(args[0]);
			}
		}

		[ConCommand(commandName = "find", flags = ConVarFlags.None, helpText = "Find all concommands and convars with the specified substring.")]
		private static void CCFind(ConCommandArgs args)
		{
			if (args.Count == 0)
			{
				ShowHelpText("find");
			}
			else
			{
				Find(args[0].ToLower(CultureInfo.InvariantCulture));
			}
		}

		private static string Find(string searchString)
		{
			bool flag = searchString == "*";
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, BaseConVar> allConVar in instance.allConVars)
			{
				if (flag || allConVar.Key.ToLower(CultureInfo.InvariantCulture).Contains(searchString) || allConVar.Value.helpText.ToLower(CultureInfo.InvariantCulture).Contains(searchString))
				{
					list.Add(allConVar.Key);
				}
			}
			foreach (KeyValuePair<string, ConCommand> item in instance.concommandCatalog)
			{
				if (flag || item.Key.ToLower(CultureInfo.InvariantCulture).Contains(searchString) || item.Value.helpText.ToLower(CultureInfo.InvariantCulture).Contains(searchString))
				{
					list.Add(item.Key);
				}
			}
			list.Sort();
			string[] array = new string[list.Count];
			for (int i = 0; i < list.Count; i++)
			{
				array[i] = GetHelpText(list[i]);
			}
			return string.Join("\n", array);
		}

		[ConCommand(commandName = "clear", flags = ConVarFlags.None, helpText = "Clears the console output.")]
		private static void CCClear(ConCommandArgs args)
		{
			logs.Clear();
			Console.onClear?.Invoke();
		}

		private static string GetHelpText(string commandName)
		{
			if (instance.concommandCatalog.TryGetValue(commandName, out var value))
			{
				return string.Format(CultureInfo.InvariantCulture, "<color=#FF7F7F>\"{0}\"</color>\n- {1}", commandName, value.helpText);
			}
			BaseConVar baseConVar = instance.FindConVar(commandName);
			if (baseConVar != null)
			{
				return string.Format(CultureInfo.InvariantCulture, "<color=#FF7F7F>\"{0}\" = \"{1}\"</color>\n - {2}", commandName, baseConVar.GetString(), baseConVar.helpText);
			}
			return Find(commandName) + "\nExact Match not found. Use `find \"" + commandName + "\" instead";
		}

		public static void ShowHelpText(string commandName)
		{
		}
	}
	public class ConstrainToScreen : MonoBehaviour
	{
		private static float boundaryUVSize;

		private static List<Transform> instanceTransformsList;

		static ConstrainToScreen()
		{
			boundaryUVSize = 0.05f;
			instanceTransformsList = new List<Transform>();
			SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull;
		}

		private static void OnSceneCameraPreCull(SceneCamera sceneCamera)
		{
			Camera camera = sceneCamera.camera;
			for (int i = 0; i < instanceTransformsList.Count; i++)
			{
				Transform transform = instanceTransformsList[i];
				UnityEngine.Vector3 position = camera.WorldToViewportPoint(transform.position);
				position.x = Mathf.Clamp(position.x, boundaryUVSize, 1f - boundaryUVSize);
				position.y = Mathf.Clamp(position.y, boundaryUVSize, 1f - boundaryUVSize);
				transform.position = camera.ViewportToWorldPoint(position);
			}
		}

		private void OnEnable()
		{
			instanceTransformsList.Add(base.transform);
		}

		private void OnDisable()
		{
			instanceTransformsList.Remove(base.transform);
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class ContactDamage : MonoBehaviour
	{
		protected static FloatConVar cvContactDamageUpdateInterval = new FloatConVar("contact_damage_update_interval", ConVarFlags.Cheat, "0.1", "Frequency that the contact damage fires.");

		public float damagePerSecondCoefficient = 2f;

		[Tooltip("The frequency that this can hurt the same target. Is NOT the frequency that it checks for targets!")]
		public float damageInterval = 0.25f;

		public float pushForcePerSecond = 4000f;

		public HitBoxGroup hitBoxGroup;

		public DamageTypeCombo damageType;

		public bool doBlastAttackInstead;

		private OverlapAttack overlapAttack;

		private CharacterBody characterBody;

		private TeamComponent teamComponent;

		private float refreshTimer;

		private float fireTimer;

		private bool hasFiredThisUpdate;

		private void Start()
		{
			characterBody = GetComponent<CharacterBody>();
			teamComponent = GetComponent<TeamComponent>();
			InitOverlapAttack();
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				hasFiredThisUpdate = false;
				refreshTimer -= Time.fixedDeltaTime;
				fireTimer -= Time.fixedDeltaTime;
				if (refreshTimer <= 0f)
				{
					refreshTimer = damageInterval;
					overlapAttack.ResetIgnoredHealthComponents();
					overlapAttack.teamIndex = teamComponent.teamIndex;
					FireOverlaps();
				}
				if (fireTimer <= 0f)
				{
					FireOverlaps();
				}
			}
		}

		private void InitOverlapAttack()
		{
			overlapAttack = new OverlapAttack
			{
				attacker = base.gameObject,
				inflictor = base.gameObject,
				hitBoxGroup = hitBoxGroup,
				teamIndex = teamComponent.teamIndex
			};
		}

		private void FireOverlaps()
		{
			if (!hasFiredThisUpdate)
			{
				if (overlapAttack == null)
				{
					InitOverlapAttack();
				}
				hasFiredThisUpdate = true;
				fireTimer = cvContactDamageUpdateInterval.value;
				overlapAttack.damage = characterBody.damage * damagePerSecondCoefficient * damageInterval;
				overlapAttack.pushAwayForce = pushForcePerSecond * damageInterval;
				overlapAttack.damageType = damageType;
				overlapAttack.Fire();
			}
		}
	}
	public class ConvertPlayerMoneyToExperience : MonoBehaviour
	{
		private Dictionary<GameObject, uint> burstSizes = new Dictionary<GameObject, uint>();

		private float burstTimer;

		public float burstInterval = 0.25f;

		public int burstCount = 8;

		private void Start()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogErrorFormat("Component {0} can only be added on the server!", GetType().Name);
				UnityEngine.Object.Destroy(this);
			}
			else
			{
				burstTimer = 0f;
			}
		}

		private void FixedUpdate()
		{
			burstTimer -= Time.fixedDeltaTime;
			if (!(burstTimer <= 0f))
			{
				return;
			}
			bool flag = false;
			ReadOnlyCollection<PlayerCharacterMasterController> instances = PlayerCharacterMasterController.instances;
			for (int i = 0; i < instances.Count; i++)
			{
				GameObject gameObject = instances[i].gameObject;
				CharacterMaster component = gameObject.GetComponent<CharacterMaster>();
				if (!burstSizes.TryGetValue(gameObject, out var value))
				{
					value = (uint)Mathf.CeilToInt((float)component.money / (float)burstCount);
					burstSizes[gameObject] = value;
				}
				if (value > component.money)
				{
					value = component.money;
				}
				component.money -= value;
				GameObject bodyObject = component.GetBodyObject();
				ulong num = (ulong)((float)value / 2f / (float)instances.Count);
				if (value != 0)
				{
					flag = true;
				}
				if ((bool)bodyObject)
				{
					ExperienceManager.instance.AwardExperience(base.transform.position, bodyObject.GetComponent<CharacterBody>(), num);
				}
				else
				{
					TeamManager.instance.GiveTeamExperience(component.teamIndex, num);
				}
			}
			if (flag)
			{
				burstTimer = burstInterval;
			}
			else if (burstTimer < -2.5f)
			{
				UnityEngine.Object.Destroy(this);
			}
		}
	}
	public class Corpse : MonoBehaviour
	{
		private class CorpsesMaxConVar : BaseConVar
		{
			private static CorpsesMaxConVar instance = new CorpsesMaxConVar("corpses_max", ConVarFlags.Archive | ConVarFlags.Engine, "25", "The maximum number of corpses allowed.");

			private CorpsesMaxConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					maxCorpses = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(maxCorpses);
			}
		}

		public enum DisposalMode
		{
			Hard,
			OutOfSight,
			Soft
		}

		private class CorpseDisposalConVar : BaseConVar
		{
			private static CorpseDisposalConVar instance = new CorpseDisposalConVar("corpses_disposal", ConVarFlags.Archive | ConVarFlags.Engine, null, "The corpse disposal mode. Choices are Hard and OutOfSight.");

			private CorpseDisposalConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				try
				{
					DisposalMode disposalMode = (DisposalMode)Enum.Parse(typeof(DisposalMode), newValue, ignoreCase: true);
					if (disposalMode == Corpse.disposalMode)
					{
						return;
					}
					Corpse.disposalMode = disposalMode;
					if (disposalMode == DisposalMode.Hard || disposalMode != DisposalMode.OutOfSight)
					{
						return;
					}
					foreach (Corpse instances in instancesList)
					{
						instances.CollectRenderers();
					}
				}
				catch (ArgumentException)
				{
					Console.ShowHelpText(name);
				}
			}

			public override string GetString()
			{
				return disposalMode.ToString();
			}
		}

		private static readonly List<Corpse> instancesList = new List<Corpse>();

		private Renderer[] renderers;

		public bool dissolve;

		public bool forceCulled;

		public float lifeTime;

		public static float corpseLifeTime = 6f;

		public static float dissolveTime = 1f;

		private CharacterModel dm;

		private static int maxCorpses = 25;

		private static DisposalMode disposalMode = DisposalMode.OutOfSight;

		private static int maxChecksPerUpdate = 3;

		private static int currentCheckIndex = 0;

		private void CollectRenderers()
		{
			if (renderers == null)
			{
				renderers = GetComponentsInChildren<Renderer>();
			}
		}

		private void OnEnable()
		{
			instancesList.Add(this);
			if (disposalMode != 0)
			{
				CollectRenderers();
			}
		}

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		[InitDuringStartup]
		private static void StaticInit()
		{
			RoR2Application.onUpdate += StaticUpdate;
		}

		private static void IncrementCurrentCheckIndex()
		{
			currentCheckIndex++;
			if (currentCheckIndex >= instancesList.Count)
			{
				currentCheckIndex = 0;
			}
		}

		private static bool CheckCorpseOutOfSight(Corpse corpse)
		{
			Renderer[] array = corpse.renderers;
			foreach (Renderer renderer in array)
			{
				if ((bool)renderer && renderer.isVisible)
				{
					return false;
				}
			}
			return true;
		}

		private void GrabDitherController()
		{
			dm = GetComponent<CharacterModel>();
		}

		public void UpdateDissolve()
		{
			lifeTime -= Time.deltaTime;
			float corpseFade = Mathf.Clamp01(lifeTime / dissolveTime);
			if ((bool)dm)
			{
				dm.corpseFade = corpseFade;
			}
			if (lifeTime <= 0f)
			{
				DestroyCorpse(this);
			}
		}

		private static void StaticUpdate()
		{
			if (maxCorpses < 0)
			{
				return;
			}
			int num = instancesList.Count - maxCorpses;
			int num2 = Math.Min(instancesList.Count, maxChecksPerUpdate);
			if (disposalMode == DisposalMode.OutOfSight)
			{
				num2 = Math.Min(num2, num);
			}
			switch (disposalMode)
			{
			case DisposalMode.Hard:
			{
				for (int num3 = num - 1; num3 >= 0; num3--)
				{
					DestroyCorpse(instancesList[num3]);
				}
				break;
			}
			case DisposalMode.OutOfSight:
			{
				for (int k = 0; k < num2; k++)
				{
					IncrementCurrentCheckIndex();
					if (CheckCorpseOutOfSight(instancesList[currentCheckIndex]))
					{
						DestroyCorpse(instancesList[currentCheckIndex]);
					}
				}
				break;
			}
			case DisposalMode.Soft:
			{
				for (int i = 0; i < num2; i++)
				{
					IncrementCurrentCheckIndex();
					Corpse corpse = instancesList[currentCheckIndex];
					if (corpse.forceCulled)
					{
						DestroyCorpse(corpse);
						if (num > 0)
						{
							num--;
						}
					}
					else if (!corpse.dissolve)
					{
						if (num > 0)
						{
							num--;
							corpse.lifeTime = dissolveTime;
						}
						else
						{
							corpse.lifeTime = corpseLifeTime;
						}
						corpse.dissolve = true;
					}
				}
				for (int j = 0; j < instancesList.Count; j++)
				{
					if (instancesList[j].dissolve)
					{
						instancesList[j].UpdateDissolve();
					}
				}
				break;
			}
			}
		}

		private static void DestroyCorpse(Corpse corpse)
		{
			if ((bool)corpse)
			{
				UnityEngine.Object.Destroy(corpse.gameObject);
			}
		}
	}
	public class CostHologramContent : MonoBehaviour
	{
		public int displayValue;

		public TextMeshPro targetTextMesh;

		public CostTypeIndex costType;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		private int oldDisplayValue;

		private void FixedUpdate()
		{
			if ((bool)targetTextMesh && oldDisplayValue != displayValue)
			{
				oldDisplayValue = displayValue;
				sharedStringBuilder.Clear();
				UnityEngine.Color color = UnityEngine.Color.white;
				CostTypeDef costTypeDef = CostTypeCatalog.GetCostTypeDef(costType);
				if (costTypeDef != null)
				{
					costTypeDef.BuildCostStringStyled(displayValue, sharedStringBuilder, forWorldDisplay: true, includeColor: false);
					color = costTypeDef.GetCostColor(forWorldDisplay: true);
				}
				targetTextMesh.SetText(sharedStringBuilder);
				targetTextMesh.color = color;
			}
		}
	}
	[RequireComponent(typeof(VoteController))]
	public class CreditsController : MonoBehaviour
	{
		private CreditsPanelController creditsPanelController;

		private VoteController voteController;

		private static GameObject creditsPanelPrefab => LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Credits/CreditsPanel");

		private void Awake()
		{
			voteController = GetComponent<VoteController>();
		}

		private void OnEnable()
		{
			creditsPanelController = UnityEngine.Object.Instantiate(creditsPanelPrefab, RoR2Application.instance.mainCanvas.transform).GetComponent<CreditsPanelController>();
			creditsPanelController.voteInfoPanel.voteController = voteController;
			creditsPanelController.skipButton.onClick.AddListener(SubmitLocalVotesToEnd);
			PauseManager.IsAbleToPause = false;
		}

		private void OnDisable()
		{
			PauseManager.IsAbleToPause = true;
			if ((bool)creditsPanelController)
			{
				UnityEngine.Object.Destroy(creditsPanelController.gameObject);
			}
		}

		private void Update()
		{
			if (!creditsPanelController)
			{
				SubmitLocalVotesToEnd();
				base.enabled = false;
			}
		}

		private void SubmitLocalVotesToEnd()
		{
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				readOnlyLocalPlayers.CallCmdSubmitVote(base.gameObject, 0);
			}
		}
	}
	public class CrocoDamageTypeController : MonoBehaviour
	{
		public SkillDef poisonSkillDef;

		public SkillDef blightSkillDef;

		public GenericSkill passiveSkillSlot;

		public DamageTypeCombo GetDamageType()
		{
			if ((bool)passiveSkillSlot)
			{
				if (passiveSkillSlot.skillDef == poisonSkillDef)
				{
					return DamageType.PoisonOnHit;
				}
				if (passiveSkillSlot.skillDef == blightSkillDef)
				{
					return DamageType.BlightOnHit;
				}
			}
			return DamageType.Generic;
		}
	}
	public class DamageDisplay : MonoBehaviour
	{
		private static List<DamageDisplay> instancesList;

		private static ReadOnlyCollection<DamageDisplay> _readOnlyInstancesList;

		public TextMeshPro textMeshComponent;

		public AnimationCurve magnitudeCurve;

		public float maxLife = 3f;

		public float gravity = 9.81f;

		public float magnitude = 3f;

		public float offset = 20f;

		private UnityEngine.Vector3 velocity;

		public float textMagnitude = 0.01f;

		private float vel;

		private float life;

		private float scale = 1f;

		[HideInInspector]
		public UnityEngine.Color baseColor = UnityEngine.Color.white;

		[HideInInspector]
		public UnityEngine.Color baseOutlineColor = UnityEngine.Color.gray;

		private GameObject victim;

		private GameObject attacker;

		private TeamIndex victimTeam;

		private TeamIndex attackerTeam;

		private bool crit;

		private bool heal;

		private UnityEngine.Vector3 internalPosition;

		public static ReadOnlyCollection<DamageDisplay> readOnlyInstancesList => _readOnlyInstancesList;

		static DamageDisplay()
		{
			instancesList = new List<DamageDisplay>();
			_readOnlyInstancesList = new ReadOnlyCollection<DamageDisplay>(instancesList);
			UICamera.onUICameraPreCull += OnUICameraPreCull;
			RoR2Application.onUpdate += UpdateAll;
		}

		private void Start()
		{
			velocity = UnityEngine.Vector3.Normalize(UnityEngine.Vector3.up + new UnityEngine.Vector3(UnityEngine.Random.Range(0f - offset, offset), 0f, UnityEngine.Random.Range(0f - offset, offset))) * magnitude;
			instancesList.Add(this);
			internalPosition = base.transform.position;
		}

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

		public void SetValues(GameObject victim, GameObject attacker, float damage, bool crit, DamageColorIndex damageColorIndex)
		{
			victimTeam = TeamIndex.Neutral;
			attackerTeam = TeamIndex.Neutral;
			scale = 1f;
			this.victim = victim;
			this.attacker = attacker;
			this.crit = crit;
			baseColor = DamageColor.FindColor(damageColorIndex);
			string text = Mathf.CeilToInt(Mathf.Abs(damage)).ToString();
			heal = damage < 0f;
			if (heal)
			{
				damage = 0f - damage;
				base.transform.parent = victim.transform;
				text = "+" + text;
				baseColor = DamageColor.FindColor(DamageColorIndex.Heal);
				baseOutlineColor = baseColor * UnityEngine.Color.gray;
			}
			if ((bool)victim)
			{
				TeamComponent component = victim.GetComponent<TeamComponent>();
				if ((bool)component)
				{
					victimTeam = component.teamIndex;
				}
			}
			if ((bool)attacker)
			{
				TeamComponent component2 = attacker.GetComponent<TeamComponent>();
				if ((bool)component2)
				{
					attackerTeam = component2.teamIndex;
				}
			}
			if (crit)
			{
				text += "!";
				baseOutlineColor = UnityEngine.Color.red;
			}
			textMeshComponent.text = text;
			UpdateMagnitude();
		}

		private void UpdateMagnitude()
		{
			float fontSize = magnitudeCurve.Evaluate(life / maxLife) * textMagnitude * scale;
			textMeshComponent.fontSize = fontSize;
		}

		private static void UpdateAll()
		{
			for (int num = instancesList.Count - 1; num >= 0; num--)
			{
				instancesList[num].DoUpdate();
			}
		}

		private void DoUpdate()
		{
			UpdateMagnitude();
			life += Time.deltaTime;
			if (life >= maxLife)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			velocity += gravity * UnityEngine.Vector3.down * Time.deltaTime;
			internalPosition += velocity * Time.deltaTime;
		}

		private static void OnUICameraPreCull(UICamera uiCamera)
		{
			GameObject gameObject = null;
			TeamIndex teamIndex = TeamIndex.Neutral;
			Camera camera = uiCamera.camera;
			Camera sceneCam = uiCamera.cameraRigController.sceneCam;
			gameObject = uiCamera.cameraRigController.target;
			teamIndex = uiCamera.cameraRigController.targetTeamIndex;
			for (int i = 0; i < instancesList.Count; i++)
			{
				DamageDisplay damageDisplay = instancesList[i];
				UnityEngine.Color color = UnityEngine.Color.white;
				if (!damageDisplay.heal)
				{
					if (teamIndex == damageDisplay.victimTeam)
					{
						color = new UnityEngine.Color(0.5568628f, 0.29411766f, 0.6039216f);
					}
					else if (teamIndex == damageDisplay.attackerTeam && gameObject != damageDisplay.attacker)
					{
						color = UnityEngine.Color.gray;
					}
				}
				damageDisplay.textMeshComponent.color = UnityEngine.Color.Lerp(UnityEngine.Color.white, damageDisplay.baseColor * color, damageDisplay.life / 0.2f);
				damageDisplay.textMeshComponent.outlineColor = UnityEngine.Color.Lerp(UnityEngine.Color.white, damageDisplay.baseOutlineColor * color, damageDisplay.life / 0.2f);
				UnityEngine.Vector3 position = damageDisplay.internalPosition;
				UnityEngine.Vector3 position2 = sceneCam.WorldToScreenPoint(position);
				position2.z = ((position2.z > 0f) ? 1f : (-1f));
				UnityEngine.Vector3 position3 = camera.ScreenToWorldPoint(position2);
				damageDisplay.transform.position = position3;
			}
		}
	}
	[ExecuteAlways]
	public class DamageNumberManager : MonoBehaviour
	{
		private List<UnityEngine.Vector4> customData = new List<UnityEngine.Vector4>();

		private ParticleSystem ps;

		private const int maxDamageNums = int.MaxValue;

		public static DamageNumberManager instance { get; private set; }

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void Awake()
		{
			ps = GetComponent<ParticleSystem>();
		}

		private void Update()
		{
		}

		public void SpawnDamageNumber(float amount, UnityEngine.Vector3 position, bool crit, TeamIndex teamIndex, DamageColorIndex damageColorIndex)
		{
			UnityEngine.Color color = DamageColor.FindColor(damageColorIndex);
			UnityEngine.Color color2 = UnityEngine.Color.white;
			switch (teamIndex)
			{
			case TeamIndex.None:
				color2 = UnityEngine.Color.gray;
				break;
			case TeamIndex.Monster:
				color2 = new UnityEngine.Color(0.5568628f, 0.29411766f, 0.6039216f);
				break;
			}
			ps.Emit(new ParticleSystem.EmitParams
			{
				position = position,
				startColor = color * color2,
				applyShapeToPosition = true
			}, 1);
			ps.GetCustomParticleData(customData, ParticleSystemCustomData.Custom1);
			customData[customData.Count - 1] = new UnityEngine.Vector4(1f, 0f, amount, crit ? 1f : 0f);
			ps.SetCustomParticleData(customData, ParticleSystemCustomData.Custom1);
		}
	}
	public class DamageTrail : MonoBehaviour
	{
		private struct TrailPoint
		{
			public UnityEngine.Vector3 position;

			public float localStartTime;

			public float localEndTime;

			public Transform segmentTransform;
		}

		[FormerlySerializedAs("updateInterval")]
		[Tooltip("How often to drop a new point onto the trail.")]
		public float pointUpdateInterval = 0.2f;

		[Tooltip("How often the damage trail should deal damage.")]
		public float damageUpdateInterval = 0.2f;

		[Tooltip("How large the radius, or width, of the damage detection should be.")]
		public float radius = 0.5f;

		[Tooltip("How large the height of the damage detection should be.")]
		public float height = 0.5f;

		[Tooltip("How long a point on the trail should last.")]
		public float pointLifetime = 3f;

		[Tooltip("The line renderer to use for display.")]
		public LineRenderer lineRenderer;

		public bool active = true;

		[Tooltip("Prefab to use per segment.")]
		public GameObject segmentPrefab;

		public bool destroyTrailSegments;

		public float damagePerSecond;

		public GameObject owner;

		private HashSet<GameObject> ignoredObjects = new HashSet<GameObject>();

		private TeamIndex teamIndex;

		private new Transform transform;

		private List<TrailPoint> pointsList;

		private float localTime;

		private float nextTrailPointUpdate;

		private float nextTrailDamageUpdate;

		private static float optimizedDamageUpdateinterval;

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
		private static void Init()
		{
			RoR2Application.onUpdate += UpdateOptimizedDamageUpdateInterval;
		}

		private void Awake()
		{
			pointsList = new List<TrailPoint>();
			transform = base.transform;
		}

		private void Start()
		{
			localTime = 0f;
			AddPoint();
			AddPoint();
		}

		private static void UpdateOptimizedDamageUpdateInterval()
		{
			float b = 0.4f;
			float a = 0.2f;
			float num = 60f;
			float num2 = 1f / Time.deltaTime;
			if (num2 > num)
			{
				optimizedDamageUpdateinterval = a;
				return;
			}
			float a2 = (num - num2) / 30f;
			a2 = Mathf.Min(a2, 1f);
			optimizedDamageUpdateinterval = Mathf.Lerp(a, b, a2);
		}

		private void OnDisable()
		{
			if (!EffectManager.UsePools)
			{
				return;
			}
			for (int num = pointsList.Count - 1; num >= 0; num--)
			{
				if ((bool)pointsList[num].segmentTransform)
				{
					GameObject gameObject = pointsList[num].segmentTransform.gameObject;
					EffectManagerHelper component = gameObject.GetComponent<EffectManagerHelper>();
					if (component != null && component.OwningPool != null)
					{
						component.OwningPool.ReturnObject(component);
					}
					else
					{
						UnityEngine.Debug.LogFormat("DamageTrail.OnDestroy: No EFH on {0} ({1})", gameObject.name, gameObject.GetInstanceID());
					}
				}
				pointsList.RemoveAt(num);
			}
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.fixedDeltaTime);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			localTime += deltaTime;
			if (localTime >= nextTrailPointUpdate)
			{
				nextTrailPointUpdate += pointUpdateInterval;
				UpdateTrail(active);
			}
			if (localTime >= nextTrailDamageUpdate)
			{
				nextTrailDamageUpdate += optimizedDamageUpdateinterval;
				DoDamage(optimizedDamageUpdateinterval);
			}
			if (pointsList.Count > 0)
			{
				TrailPoint value = pointsList[pointsList.Count - 1];
				value.position = transform.position;
				value.localEndTime = localTime + pointLifetime;
				pointsList[pointsList.Count - 1] = value;
				if ((bool)value.segmentTransform)
				{
					value.segmentTransform.position = transform.position;
				}
				if ((bool)lineRenderer)
				{
					lineRenderer.SetPosition(pointsList.Count - 1, value.position);
				}
			}
			if (!segmentPrefab)
			{
				return;
			}
			UnityEngine.Vector3 position = transform.position;
			for (int num = pointsList.Count - 1; num >= 0; num--)
			{
				Transform segmentTransform = pointsList[num].segmentTransform;
				if ((bool)segmentTransform)
				{
					segmentTransform.LookAt(position, UnityEngine.Vector3.up);
					UnityEngine.Vector3 vector = pointsList[num].position - position;
					segmentTransform.position = position + vector * 0.5f;
					float num2 = Mathf.Clamp01(Mathf.InverseLerp(pointsList[num].localStartTime, pointsList[num].localEndTime, localTime));
					UnityEngine.Vector3 localScale = new UnityEngine.Vector3(radius * (1f - num2), radius * (1f - num2), vector.magnitude);
					segmentTransform.localScale = localScale;
					position = pointsList[num].position;
				}
			}
		}

		private void UpdateTrail(bool addPoint)
		{
			while (pointsList.Count > 0 && pointsList[0].localEndTime <= localTime)
			{
				RemovePoint(0);
			}
			if (addPoint)
			{
				AddPoint();
			}
			if ((bool)lineRenderer)
			{
				UpdateLineRenderer(lineRenderer);
			}
		}

		private void DoDamage(float damageInterval)
		{
			if (!NetworkServer.active || pointsList.Count == 0)
			{
				return;
			}
			UnityEngine.Vector3 vector = pointsList[pointsList.Count - 1].position;
			ignoredObjects.Clear();
			TeamIndex attackerTeamIndex = TeamIndex.Neutral;
			float damage = damagePerSecond * damageInterval;
			if ((bool)owner)
			{
				ignoredObjects.Add(owner);
				attackerTeamIndex = TeamComponent.GetObjectTeam(owner);
			}
			DamageInfo damageInfo = new DamageInfo();
			damageInfo.attacker = owner;
			damageInfo.inflictor = base.gameObject;
			damageInfo.crit = false;
			damageInfo.damage = damage;
			damageInfo.damageColorIndex = DamageColorIndex.Item;
			damageInfo.damageType = DamageType.Generic;
			damageInfo.force = UnityEngine.Vector3.zero;
			damageInfo.procCoefficient = 0f;
			for (int num = pointsList.Count - 2; num >= 0; num--)
			{
				UnityEngine.Vector3 position = pointsList[num].position;
				UnityEngine.Vector3 forward = position - vector;
				UnityEngine.Vector3 halfExtents = new UnityEngine.Vector3(radius, height, forward.magnitude);
				UnityEngine.Vector3 center = UnityEngine.Vector3.Lerp(position, vector, 0.5f);
				UnityEngine.Quaternion orientation = Util.QuaternionSafeLookRotation(forward);
				Collider[] colliders;
				int num2 = HGPhysics.OverlapBox(out colliders, center, halfExtents, orientation, LayerIndex.entityPrecise.mask);
				for (int i = 0; i < num2; i++)
				{
					HurtBox component = colliders[i].GetComponent<HurtBox>();
					if (!component)
					{
						continue;
					}
					HealthComponent healthComponent = component.healthComponent;
					if ((bool)healthComponent)
					{
						GameObject item = healthComponent.gameObject;
						if (!ignoredObjects.Contains(item) && FriendlyFireManager.ShouldSplashHitProceed(healthComponent, attackerTeamIndex))
						{
							ignoredObjects.Add(item);
							damageInfo.position = colliders[i].transform.position;
							healthComponent.TakeDamage(damageInfo);
						}
					}
				}
				HGPhysics.ReturnResults(colliders);
				vector = position;
			}
		}

		private void UpdateLineRenderer(LineRenderer lineRenderer)
		{
			lineRenderer.positionCount = pointsList.Count;
			for (int i = 0; i < pointsList.Count; i++)
			{
				lineRenderer.SetPosition(i, pointsList[i].position);
			}
		}

		private void AddPoint()
		{
			TrailPoint trailPoint = default(TrailPoint);
			trailPoint.position = transform.position;
			trailPoint.localStartTime = localTime;
			trailPoint.localEndTime = localTime + pointLifetime;
			TrailPoint item = trailPoint;
			if ((bool)segmentPrefab)
			{
				if (!EffectManager.ShouldUsePooledEffect(segmentPrefab))
				{
					item.segmentTransform = UnityEngine.Object.Instantiate(segmentPrefab, transform).transform;
				}
				else
				{
					EffectManagerHelper andActivatePooledEffect = EffectManager.GetAndActivatePooledEffect(segmentPrefab, transform, inResetLocal: true);
					item.segmentTransform = andActivatePooledEffect.gameObject.transform;
				}
			}
			pointsList.Add(item);
		}

		private void RemovePoint(int pointIndex)
		{
			if (destroyTrailSegments)
			{
				if ((bool)pointsList[pointIndex].segmentTransform)
				{
					if (!EffectManager.UsePools)
					{
						UnityEngine.Object.Destroy(pointsList[pointIndex].segmentTransform.gameObject);
					}
					else
					{
						GameObject gameObject = pointsList[pointIndex].segmentTransform.gameObject;
						EffectManagerHelper component = gameObject.GetComponent<EffectManagerHelper>();
						if (component != null && component.OwningPool != null)
						{
							component.OwningPool.ReturnObject(component);
						}
						else
						{
							UnityEngine.Debug.LogFormat("DamageTrail.RemovePoint: No EFH on {0} ({1})", gameObject.name, gameObject.GetInstanceID());
							UnityEngine.Object.Destroy(gameObject);
						}
					}
				}
			}
			else if (EffectManager.UsePools && (bool)pointsList[pointIndex].segmentTransform)
			{
				pointsList[pointIndex].segmentTransform.gameObject.transform.SetParent(null);
			}
			pointsList.RemoveAt(pointIndex);
		}

		private void OnDrawGizmos()
		{
			UnityEngine.Vector3 vector = pointsList[pointsList.Count - 1].position;
			for (int num = pointsList.Count - 2; num >= 0; num--)
			{
				UnityEngine.Vector3 position = pointsList[num].position;
				UnityEngine.Vector3 forward = position - vector;
				UnityEngine.Vector3 s = new UnityEngine.Vector3(radius, 0.5f, forward.magnitude);
				UnityEngine.Vector3 pos = UnityEngine.Vector3.Lerp(position, vector, 0.5f);
				UnityEngine.Quaternion q = Util.QuaternionSafeLookRotation(forward);
				Gizmos.matrix = UnityEngine.Matrix4x4.TRS(pos, q, s);
				Gizmos.color = UnityEngine.Color.blue;
				Gizmos.DrawWireCube(UnityEngine.Vector3.zero, UnityEngine.Vector3.one);
				Gizmos.matrix = UnityEngine.Matrix4x4.identity;
				vector = position;
			}
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class DeathRewards : MonoBehaviour, IOnKilledServerReceiver
	{
		[Obsolete("'logUnlockableName' is discontinued. Use 'logUnlockableDef' instead.", true)]
		[Tooltip("'logUnlockableName' is discontinued. Use 'logUnlockableDef' instead.")]
		public string logUnlockableName = "";

		public UnlockableDef logUnlockableDef;

		public PickupDropTable bossDropTable;

		private uint fallbackGold;

		private CharacterBody characterBody;

		private static GameObject coinEffectPrefab;

		private static GameObject logbookPrefab;

		[Header("Deprecated")]
		public SerializablePickupIndex bossPickup;

		public uint goldReward
		{
			get
			{
				if (!characterBody.master)
				{
					return fallbackGold;
				}
				return characterBody.master.money;
			}
			set
			{
				if ((bool)characterBody.master)
				{
					characterBody.master.money = value;
				}
				else
				{
					fallbackGold = value;
				}
			}
		}

		public uint expReward { get; set; }

		public int spawnValue { get; set; }

		[InitDuringStartup]
		private static void LoadAssets()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/CoinEmitter");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				coinEffectPrefab = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/NetworkedObjects/LogPickup");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				logbookPrefab = x.Result;
			};
		}

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
		}

		public void OnKilledServer(DamageReport damageReport)
		{
			CharacterBody attackerBody = damageReport.attackerBody;
			if (!attackerBody)
			{
				return;
			}
			UnityEngine.Vector3 corePosition = characterBody.corePosition;
			uint num = goldReward;
			if (Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse6)
			{
				num = (uint)((float)num * 0.8f);
			}
			TeamManager.instance.GiveTeamMoney(damageReport.attackerTeamIndex, num);
			EffectManager.SpawnEffect(coinEffectPrefab, new EffectData
			{
				origin = corePosition,
				genericFloat = goldReward,
				scale = characterBody.radius
			}, transmit: true);
			float num2 = 1f + (characterBody.level - 1f) * 0.3f;
			int num3 = 0;
			double num4 = 0.0;
			if (attackerBody.GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff) > 0 && attackerBody.luminousShotReady)
			{
				int itemCount = attackerBody.inventory.GetItemCount(DLC2Content.Items.IncreasePrimaryDamage);
				num3 = attackerBody.GetBuffCount(DLC2Content.Buffs.IncreasePrimaryDamageBuff);
				num4 = (float)expReward * num2 * (0.1f * (float)itemCount) * (float)num3;
				num4 = Math.Round(num4);
				if (num4 < 1.0)
				{
					num4 = 1.0;
				}
				_ = expReward;
			}
			ExperienceManager.instance.AwardExperience(corePosition, attackerBody, (uint)((double)((float)expReward * num2) + num4));
			_ = expReward;
			if ((bool)logUnlockableDef && Run.instance.CanUnlockableBeGrantedThisRun(logUnlockableDef) && Util.CheckRoll(characterBody.isChampion ? 3f : 1f, damageReport.attackerMaster))
			{
				GameObject obj = UnityEngine.Object.Instantiate(logbookPrefab, corePosition, UnityEngine.Random.rotation);
				obj.GetComponentInChildren<UnlockPickup>().unlockableDef = logUnlockableDef;
				obj.GetComponent<TeamFilter>().teamIndex = TeamIndex.Player;
				NetworkServer.Spawn(obj);
			}
		}

		[ConCommand(commandName = "migrate_death_rewards_unlockables", flags = ConVarFlags.Cheat, helpText = "Migrates CharacterDeath component .logUnlockableName to .LogUnlockableDef for all instances.")]
		private static void CCMigrateDeathRewardUnlockables(ConCommandArgs args)
		{
			DeathRewards[] array = Resources.FindObjectsOfTypeAll<DeathRewards>();
			foreach (DeathRewards deathRewards in array)
			{
				FieldInfo field = typeof(DeathRewards).GetField("logUnlockableName");
				string text = ((string)field.GetValue(deathRewards)) ?? string.Empty;
				UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(text);
				if (!unlockableDef && text != string.Empty)
				{
					args.Log("DeathRewards component on object " + deathRewards.gameObject.name + " has a defined value for 'logUnlockableName' but it doesn't map to any known unlockable. Migration skipped. logUnlockableName='logUnlockableName'");
				}
				else if (deathRewards.logUnlockableDef == unlockableDef)
				{
					field.SetValue(deathRewards, string.Empty);
					EditorUtil.SetDirty(deathRewards);
					EditorUtil.SetDirty(deathRewards.gameObject);
				}
				else if ((bool)deathRewards.logUnlockableDef)
				{
					args.Log($"DeathRewards component on object {deathRewards.gameObject.name} has a 'logUnlockableDef' field value which differs from the 'logUnlockableName' lookup. Migration skipped. logUnlockableDef={deathRewards.logUnlockableDef} logUnlockableName={text}");
				}
				else
				{
					deathRewards.logUnlockableDef = unlockableDef;
					field.SetValue(deathRewards, string.Empty);
					EditorUtil.SetDirty(deathRewards);
					EditorUtil.SetDirty(deathRewards.gameObject);
					args.Log($"DeathRewards component on object {deathRewards.gameObject.name} migrated. logUnlockableDef={deathRewards.logUnlockableDef} logUnlockableName={text}");
				}
			}
		}
	}
	internal class DeathZone : MonoBehaviour
	{
		public void OnTriggerEnter(Collider other)
		{
			if (NetworkServer.active)
			{
				HealthComponent component = other.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.position = other.transform.position;
					damageInfo.attacker = null;
					damageInfo.inflictor = base.gameObject;
					damageInfo.damage = 999999f;
					component.TakeDamage(damageInfo);
				}
			}
		}
	}
	public class DebuffZone : MonoBehaviour
	{
		[Tooltip("The buff type to grant")]
		public BuffDef buffType;

		[Tooltip("The buff duration")]
		public float buffDuration;

		public string buffApplicationSoundString;

		public GameObject buffApplicationEffectPrefab;

		private void Awake()
		{
		}

		private void OnTriggerEnter(Collider other)
		{
			if (!NetworkServer.active || !buffType)
			{
				return;
			}
			CharacterBody component = other.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				component.AddTimedBuff(buffType.buffIndex, buffDuration);
				Util.PlaySound(buffApplicationSoundString, component.gameObject);
				if ((bool)buffApplicationEffectPrefab)
				{
					EffectManager.SpawnEffect(buffApplicationEffectPrefab, new EffectData
					{
						origin = component.mainHurtBox.transform.position,
						scale = component.radius
					}, transmit: true);
				}
			}
		}
	}
	public class DebugOverlay : MonoBehaviour
	{
		public class MeshDrawer : IDisposable
		{
			private GameObject gameObject;

			private MeshFilter meshFilter;

			private MeshRenderer meshRenderer;

			public bool hasMeshOwnership;

			public Transform transform { get; private set; }

			public bool enabled
			{
				get
				{
					if ((bool)gameObject)
					{
						return gameObject.activeSelf;
					}
					return false;
				}
				set
				{
					if ((bool)gameObject)
					{
						gameObject.SetActive(value);
					}
				}
			}

			public Mesh mesh
			{
				get
				{
					return meshFilter.sharedMesh;
				}
				set
				{
					if (!(meshFilter.sharedMesh == value))
					{
						if ((bool)meshFilter.sharedMesh && hasMeshOwnership)
						{
							UnityEngine.Object.Destroy(meshFilter.sharedMesh);
						}
						meshFilter.sharedMesh = value;
					}
				}
			}

			public Material material
			{
				get
				{
					return meshRenderer.sharedMaterial;
				}
				set
				{
					meshRenderer.sharedMaterial = value;
				}
			}

			public MeshDrawer(Transform parent)
			{
				gameObject = new GameObject("MeshDrawer");
				transform = gameObject.transform;
				transform.SetParent(parent);
				meshFilter = gameObject.AddComponent<MeshFilter>();
				meshRenderer = gameObject.AddComponent<MeshRenderer>();
				material = defaultWireMaterial;
			}

			public void Dispose()
			{
				mesh = null;
				UnityEngine.Object.Destroy(gameObject);
				gameObject = null;
				transform = null;
				meshFilter = null;
				meshRenderer = null;
			}
		}

		private static DebugOverlay instance;

		private new Transform transform;

		public static Material defaultWireMaterial;

		private void Awake()
		{
			transform = base.transform;
		}

		[InitDuringStartup]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("Materials/UI/matDebugUI", delegate(Material operationResult)
			{
				defaultWireMaterial = operationResult;
			});
			GameObject obj = new GameObject("DebugOverlay");
			instance = obj.AddComponent<DebugOverlay>();
			UnityEngine.Object.DontDestroyOnLoad(obj);
		}

		public static MeshDrawer GetMeshDrawer()
		{
			return new MeshDrawer(instance.transform);
		}
	}
	public class Debug_CombatOptimizationCommands : MonoBehaviour
	{
		public void SubmitCombatOptimizationCommands()
		{
			Console.instance.SubmitCmd(null, "give_item BleedOnHit 50");
			Console.instance.SubmitCmd(null, "give_item BleedOnHitAndExplode 50");
			StartCoroutine(GenerateEnemies());
		}

		private IEnumerator GenerateEnemies()
		{
			for (int q = 0; q < 12; q++)
			{
				Console.instance.SubmitCmd(null, "create_master BeetleMaster");
				yield return 0;
				Console.instance.SubmitCmd(null, "create_master LemurianMaster");
				yield return 0;
			}
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	public class DelayBlast : MonoBehaviour
	{
		[HideInInspector]
		public UnityEngine.Vector3 position;

		[HideInInspector]
		public GameObject attacker;

		[HideInInspector]
		public GameObject inflictor;

		[HideInInspector]
		public float baseDamage;

		[HideInInspector]
		public bool crit;

		[HideInInspector]
		public float baseForce;

		[HideInInspector]
		public float radius;

		[HideInInspector]
		public UnityEngine.Vector3 bonusForce;

		[HideInInspector]
		public float maxTimer;

		[HideInInspector]
		public DamageColorIndex damageColorIndex;

		[HideInInspector]
		public BlastAttack.FalloffModel falloffModel;

		[HideInInspector]
		public DamageTypeCombo damageType = DamageType.Generic;

		[HideInInspector]
		public float procCoefficient = 1f;

		public GameObject explosionEffect;

		public GameObject delayEffect;

		public float timerStagger;

		private float timer;

		private bool hasSpawnedDelayEffect;

		private TeamFilter teamFilter;

		private void Awake()
		{
			teamFilter = GetComponent<TeamFilter>();
			if (!NetworkServer.active)
			{
				base.enabled = false;
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				timer += Time.fixedDeltaTime;
				if ((bool)delayEffect && !hasSpawnedDelayEffect && timer > timerStagger)
				{
					hasSpawnedDelayEffect = true;
					EffectManager.SpawnEffect(delayEffect, new EffectData
					{
						origin = base.transform.position,
						rotation = Util.QuaternionSafeLookRotation(base.transform.forward),
						scale = radius
					}, transmit: true);
				}
				if (timer >= maxTimer + timerStagger)
				{
					Detonate();
				}
			}
		}

		public void Detonate()
		{
			EffectManager.SpawnEffect(explosionEffect, new EffectData
			{
				origin = base.transform.position,
				rotation = Util.QuaternionSafeLookRotation(base.transform.forward),
				scale = radius
			}, transmit: true);
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.position = position;
			blastAttack.baseDamage = baseDamage;
			blastAttack.baseForce = baseForce;
			blastAttack.bonusForce = bonusForce;
			blastAttack.radius = radius;
			blastAttack.attacker = attacker;
			blastAttack.inflictor = inflictor;
			blastAttack.teamIndex = teamFilter.teamIndex;
			blastAttack.crit = crit;
			blastAttack.damageColorIndex = damageColorIndex;
			blastAttack.damageType = damageType;
			blastAttack.falloffModel = falloffModel;
			blastAttack.procCoefficient = procCoefficient;
			blastAttack.Fire();
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}
	public class DelusionChestController : MonoBehaviour
	{
		private const int DELUSION_PICKUP_INDEXES_NUMBER = 3;

		public ChestBehavior delusionChest;

		private PickupIndex _delusionPickupIndex = PickupIndex.none;

		private Dictionary<Interactor, PickupIndex[]> _delusionPickupIndexesTable;

		private NetworkUIPromptController _netUIPromptController;

		private PickupPickerController _pickupPickerController;

		private PickupIndex _selectedPickupIndex = PickupIndex.none;

		private Interactor interactor;

		private Inventory interactorInventory;

		private Interactor previousInteractor;

		private bool hasBeenReset;

		public PickupIndex DelusionPickupIndex
		{
			get
			{
				return _delusionPickupIndex;
			}
			set
			{
				_delusionPickupIndex = value;
			}
		}

		public PickupIndex SelectedPickupIndex
		{
			get
			{
				return _selectedPickupIndex;
			}
			set
			{
				_selectedPickupIndex = value;
			}
		}

		public bool IsDelusionChoiceReady => _delusionPickupIndex != PickupIndex.none;

		public bool isDelusionSelected => _selectedPickupIndex != PickupIndex.none;

		public static bool isDelusionEnable => RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion);

		private void Start()
		{
			delusionChest = GetComponent<ChestBehavior>();
			_netUIPromptController = GetComponent<NetworkUIPromptController>();
			_pickupPickerController = GetComponent<PickupPickerController>();
			_netUIPromptController.enabled = false;
			_pickupPickerController.enabled = false;
			_pickupPickerController.SetAvailable(newAvailable: false);
			_delusionPickupIndexesTable = new Dictionary<Interactor, PickupIndex[]>();
			base.enabled = isDelusionEnable;
			hasBeenReset = false;
		}

		public void ResetChestForDelusion()
		{
			if (!hasBeenReset)
			{
				UnityEngine.Debug.LogError("reset chest for delusion");
				EntityStateMachine component = GetComponent<EntityStateMachine>();
				PurchaseInteraction component2 = GetComponent<PurchaseInteraction>();
				if ((bool)component)
				{
					component.SetNextState(new Closing());
					UnityEngine.Object.Destroy(component2);
					_netUIPromptController.enabled = true;
					_pickupPickerController.enabled = true;
					_pickupPickerController.SetAvailable(newAvailable: true);
					Util.PlaySound("Play_ui_artifact_delusion_reset", base.gameObject);
					hasBeenReset = true;
				}
			}
		}

		public void GenerateDelusionPickupIndexes(Interactor activator)
		{
			if (_delusionPickupIndexesTable.TryGetValue(activator, out var value))
			{
				return;
			}
			value = new PickupIndex[3]
			{
				_delusionPickupIndex,
				default(PickupIndex),
				default(PickupIndex)
			};
			interactorInventory = activator.GetComponent<CharacterBody>()?.inventory;
			interactor = activator;
			if ((bool)interactorInventory)
			{
				List<ItemIndex> availableItems = GetAvailableItems(interactorInventory.itemAcquisitionOrder);
				if (availableItems.Count < 2)
				{
					AppendAvailableItems(ref availableItems);
				}
				for (int i = 1; i < 3; i++)
				{
					int maxExclusive = availableItems.Count - 1;
					int index = UnityEngine.Random.Range(0, maxExclusive);
					value[i] = PickupCatalog.FindPickupIndex(availableItems[index]);
					availableItems.RemoveAt(index);
				}
				GenerateRandomPickupIndexes(value);
				_delusionPickupIndexesTable[activator] = value;
			}
		}

		private void AppendAvailableItems(ref List<ItemIndex> availableItems)
		{
			for (int i = availableItems.Count; i < 2; i++)
			{
				ItemIndex itemIndex = delusionChest.GetRandomPickupIndex().itemIndex;
				if (IsItemValid(itemIndex))
				{
					availableItems.Add(itemIndex);
				}
			}
		}

		private List<ItemIndex> GetRandomAvailableItems()
		{
			List<ItemIndex> list = new List<ItemIndex>();
			for (int i = 0; i < 10; i++)
			{
				ItemIndex itemIndex = delusionChest.GetRandomPickupIndex().itemIndex;
				if (IsItemValid(itemIndex))
				{
					list.Add(itemIndex);
				}
			}
			return list;
		}

		private bool IsItemValid(ItemIndex item)
		{
			bool flag = false;
			bool flag2 = true;
			bool flag3 = false;
			ItemDef itemDef = ItemCatalog.GetItemDef(item);
			ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(itemDef.tier);
			if ((!itemTierDef || itemTierDef.canScrap) && itemDef.canRemove && !itemDef.hidden && itemDef.DoesNotContainTag(ItemTag.Scrap) && itemDef.DoesNotContainTag(ItemTag.WorldUnique) && _delusionPickupIndex.itemIndex != item)
			{
				flag = true;
			}
			BasicPickupDropTable basicPickupDropTable = delusionChest.dropTable as BasicPickupDropTable;
			if ((bool)basicPickupDropTable && itemTierDef != null)
			{
				if (basicPickupDropTable.IsFilterRequired())
				{
					flag2 = basicPickupDropTable.PassesFilter(PickupCatalog.FindPickupIndex(item));
				}
				if (basicPickupDropTable.tier1Weight != 0f && itemTierDef.tier == ItemTier.Tier1 && Util.CheckRoll(basicPickupDropTable.tier1Weight * 100f))
				{
					flag3 = true;
				}
				else if (itemTierDef.tier == ItemTier.Tier2 && Util.CheckRoll(basicPickupDropTable.tier2Weight * 100f))
				{
					flag3 = true;
				}
				else if (itemTierDef.tier == ItemTier.Tier3 && Util.CheckRoll(basicPickupDropTable.tier3Weight * 100f))
				{
					flag3 = true;
				}
			}
			return flag && flag2 && flag3;
		}

		private List<ItemIndex> GetAvailableItems(List<ItemIndex> items)
		{
			List<ItemIndex> list = new List<ItemIndex>();
			for (int i = 0; i < items.Count; i++)
			{
				if (IsItemValid(items[i]))
				{
					list.Add(items[i]);
				}
			}
			return list;
		}

		private void GenerateRandomPickupIndexes(PickupIndex[] indexes)
		{
			for (int i = 0; i < 2; i++)
			{
				int num = UnityEngine.Random.Range(i, 3);
				PickupIndex pickupIndex = indexes[i];
				indexes[i] = indexes[num];
				indexes[num] = pickupIndex;
			}
		}

		public bool IsSelectedCorrectly()
		{
			return _delusionPickupIndex == SelectedPickupIndex;
		}

		public void RemoveDelusionChoice()
		{
			if ((bool)interactorInventory)
			{
				GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/DelusionItemDissolveVFX");
				EffectData effectData = new EffectData
				{
					origin = interactor.transform.position,
					genericFloat = 1.5f,
					genericUInt = (uint)(_selectedPickupIndex.itemIndex + 1)
				};
				effectData.SetNetworkedObjectReference(base.gameObject);
				EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
				interactorInventory.RemoveItem(_selectedPickupIndex.itemIndex);
			}
		}

		public PickupIndex[] GetPickupIndexes(Interactor activator)
		{
			if (_delusionPickupIndexesTable.TryGetValue(activator, out var value))
			{
				return value;
			}
			return null;
		}
	}
	public struct DeployableInfo
	{
		public Deployable deployable;

		public DeployableSlot slot;
	}
	public enum DeployableSlot
	{
		EngiMine,
		EngiTurret,
		BeetleGuardAlly,
		EngiBubbleShield,
		LoaderPylon,
		EngiSpiderMine,
		RoboBallMini,
		ParentPodAlly,
		ParentAlly,
		PowerWard,
		CrippleWard,
		DeathProjectile,
		RoboBallRedBuddy,
		RoboBallGreenBuddy,
		GummyClone,
		RailgunnerBomb,
		LunarSunBomb,
		VendingMachine,
		VoidMegaCrabItem,
		DroneWeaponsDrone,
		MinorConstructOnKill,
		CaptainSupplyDrop,
		None
	}
	public class Deployable : MonoBehaviour
	{
		[NonSerialized]
		public CharacterMaster ownerMaster;

		public UnityEvent onUndeploy;

		private void OnDestroy()
		{
			if (NetworkServer.active && (bool)ownerMaster)
			{
				ownerMaster.RemoveDeployable(this);
			}
		}

		public void DestroyGameObject()
		{
			if (NetworkServer.active)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	public class DeskPlantController : MonoBehaviour
	{
		private abstract class DeskPlantBaseState : BaseState
		{
			protected DeskPlantController controller;

			protected abstract bool showSeedObject { get; }

			protected abstract bool showPlantObject { get; }

			protected abstract float CalcScale();

			public override void OnEnter()
			{
				base.OnEnter();
				controller = GetComponent<DeskPlantController>();
				controller.seedObject.SetActive(showSeedObject);
				controller.plantObject.SetActive(showPlantObject);
			}

			public override void Update()
			{
				base.Update();
				if (showPlantObject)
				{
					float num = CalcScale();
					UnityEngine.Vector3 vector = new UnityEngine.Vector3(num, num, num);
					Transform transform = controller.plantObject.transform;
					if (transform.localScale != vector)
					{
						transform.localScale = vector;
					}
				}
			}
		}

		private class SeedState : DeskPlantBaseState
		{
			protected override bool showSeedObject => true;

			protected override bool showPlantObject => false;

			protected override float CalcScale()
			{
				return 1f;
			}

			public override void OnEnter()
			{
				base.OnEnter();
				Util.PlaySound("Play_item_proc_interstellarDeskPlant_grow", base.gameObject);
				GetComponent<Animation>().Play();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= seedDuration)
				{
					outer.SetNextState(new SproutState());
				}
			}
		}

		private class SproutState : DeskPlantBaseState
		{
			protected override bool showSeedObject => false;

			protected override bool showPlantObject => true;

			protected override float CalcScale()
			{
				float time = Mathf.Clamp01(base.age / scaleDuration);
				return linearRampUp.Evaluate(time) * easeUp.Evaluate(time);
			}

			public override void OnEnter()
			{
				base.OnEnter();
				Util.PlaySound("Play_item_proc_interstellarDeskPlant_bloom", base.gameObject);
			}

			public override void OnExit()
			{
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= scaleDuration)
				{
					outer.SetNextState(new MainState());
				}
			}
		}

		private class MainState : DeskPlantBaseState
		{
			private GameObject deskplantWard;

			protected override bool showSeedObject => false;

			protected override bool showPlantObject => true;

			protected override float CalcScale()
			{
				return 1f;
			}

			public override void OnEnter()
			{
				base.OnEnter();
				if (NetworkServer.active && !deskplantWard)
				{
					deskplantWard = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/DeskplantWard"), controller.plantObject.transform.position, UnityEngine.Quaternion.identity);
					deskplantWard.GetComponent<TeamFilter>().teamIndex = controller.teamFilter.teamIndex;
					if ((bool)deskplantWard)
					{
						HealingWard component = deskplantWard.GetComponent<HealingWard>();
						component.healFraction = 0.05f;
						component.healPoints = 0f;
						component.Networkradius = controller.healingRadius + controller.radiusIncreasePerStack * (float)controller.itemCount;
						component.enabled = true;
					}
					NetworkServer.Spawn(deskplantWard);
				}
			}

			public override void OnExit()
			{
				if ((bool)deskplantWard)
				{
					EntityState.Destroy(deskplantWard);
				}
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= mainDuration)
				{
					outer.SetNextState(new DeathState());
				}
			}
		}

		private class DeathState : DeskPlantBaseState
		{
			protected override bool showSeedObject => false;

			protected override bool showPlantObject => true;

			protected override float CalcScale()
			{
				float time = Mathf.Clamp01(base.age / scaleDuration);
				return linearRampDown.Evaluate(time) * easeDown.Evaluate(time);
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= scaleDuration)
				{
					EntityState.Destroy(base.gameObject);
				}
			}
		}

		public GameObject plantObject;

		public GameObject seedObject;

		public GameObject groundFX;

		public float healingRadius;

		public float radiusIncreasePerStack = 5f;

		private static readonly float seedDuration = 5f;

		private static readonly float mainDuration = 10f;

		private static readonly float scaleDuration = 0.5f;

		private static readonly AnimationCurve linearRampUp = AnimationCurve.Linear(0f, 0f, 1f, 1f);

		private static readonly AnimationCurve linearRampDown = AnimationCurve.Linear(0f, 1f, 1f, 0f);

		private static readonly AnimationCurve easeUp = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);

		private static readonly AnimationCurve easeDown = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);

		public TeamFilter teamFilter { get; private set; }

		public int itemCount { get; set; }

		private void Awake()
		{
			teamFilter = GetComponent<TeamFilter>();
			plantObject.SetActive(value: false);
			seedObject.SetActive(value: false);
			if (NetworkServer.active && Physics.Raycast(base.transform.position, UnityEngine.Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask))
			{
				base.transform.position = hitInfo.point;
				base.transform.up = hitInfo.normal;
			}
		}

		public void SeedPlanting()
		{
			EffectManager.SimpleEffect(groundFX, base.transform.position, UnityEngine.Quaternion.identity, transmit: false);
		}
	}
	public class DestroyOnDestroy : MonoBehaviour
	{
		[Tooltip("The GameObject to destroy when this object is destroyed.")]
		public GameObject target;

		private void OnDestroy()
		{
			UnityEngine.Object.Destroy(target);
		}
	}
	public class DestroyOnTimer : MonoBehaviour
	{
		public float duration;

		public bool resetAgeOnDisable;

		private float age;

		private EffectManagerHelper efh;

		private void Start()
		{
			if (!efh)
			{
				efh = GetComponent<EffectManagerHelper>();
			}
		}

		private void FixedUpdate()
		{
			age += Time.fixedDeltaTime;
			if (age > duration)
			{
				if ((bool)efh && efh.OwningPool != null)
				{
					efh.OwningPool.ReturnObject(efh);
				}
				else
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}

		private void OnDisable()
		{
			if (resetAgeOnDisable || ((bool)efh && efh.OwningPool != null))
			{
				age = 0f;
			}
		}
	}
	public class DestroyOnUnseen : MonoBehaviour
	{
		public bool cull;

		private Renderer rend;

		private void Start()
		{
			rend = GetComponentInChildren<Renderer>();
		}

		private void Update()
		{
			if (cull && (bool)rend && !rend.isVisible)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	public class DetachParticleOnDestroyAndEndEmission : MonoBehaviour
	{
		public ParticleSystem particleSystem;

		private void OnDisable()
		{
			if ((bool)particleSystem)
			{
				ParticleSystem.EmissionModule emission = particleSystem.emission;
				emission.enabled = false;
				ParticleSystem.MainModule main = particleSystem.main;
				main.stopAction = ParticleSystemStopAction.Destroy;
				particleSystem.Stop();
				particleSystem.transform.SetParent(null);
				if (particleSystem.isStopped)
				{
					UnityEngine.Object.Destroy(particleSystem.gameObject);
				}
			}
		}
	}
	public class DetachTrailOnDestroy : MonoBehaviour
	{
		[FormerlySerializedAs("trail")]
		public TrailRenderer[] targetTrailRenderers;

		[SerializeField]
		[Tooltip("Use this to disable the script from functioning.")]
		private bool IgnoreDestroy;

		private void OnDestroy()
		{
			if (IgnoreDestroy)
			{
				return;
			}
			for (int i = 0; i < targetTrailRenderers.Length; i++)
			{
				TrailRenderer trailRenderer = targetTrailRenderers[i];
				if ((bool)trailRenderer)
				{
					trailRenderer.transform.SetParent(null);
					trailRenderer.autodestruct = true;
				}
			}
			targetTrailRenderers = null;
		}
	}
	public class DirectorSpawnRequest
	{
		public SpawnCard spawnCard;

		public DirectorPlacementRule placementRule;

		public Xoroshiro128Plus rng;

		public GameObject summonerBodyObject;

		public TeamIndex? teamIndexOverride;

		public bool ignoreTeamMemberLimit;

		public Action<SpawnCard.SpawnResult> onSpawnedServer;

		public DirectorSpawnRequest(SpawnCard spawnCard, DirectorPlacementRule placementRule, Xoroshiro128Plus rng)
		{
			this.spawnCard = spawnCard;
			this.placementRule = placementRule;
			this.rng = rng;
		}
	}
	public class DirectorCore : MonoBehaviour
	{
		private struct NodeReference : IEquatable<NodeReference>
		{
			public readonly NodeGraph nodeGraph;

			public readonly NodeGraph.NodeIndex nodeIndex;

			public NodeReference(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex)
			{
				this.nodeGraph = nodeGraph;
				this.nodeIndex = nodeIndex;
			}

			public bool Equals(NodeReference other)
			{
				if (object.Equals(nodeGraph, other.nodeGraph))
				{
					return nodeIndex.Equals(other.nodeIndex);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is NodeReference other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((nodeGraph != null) ? nodeGraph.GetHashCode() : 0) * 397) ^ nodeIndex.GetHashCode();
			}
		}

		public enum MonsterSpawnDistance
		{
			Standard,
			Close,
			Far
		}

		public static List<GameObject> spawnedObjects = new List<GameObject>();

		private NodeReference[] occupiedNodes = Array.Empty<NodeReference>();

		public static DirectorCore instance { get; private set; }

		public GameObject[] GetObjectsOfTeam(TeamIndex _teamIndex)
		{
			List<GameObject> list = new List<GameObject>();
			for (int i = 0; i < spawnedObjects.Count; i++)
			{
				CharacterMaster component = spawnedObjects[i].GetComponent<CharacterMaster>();
				if ((bool)component && component.teamIndex == _teamIndex)
				{
					spawnedObjects.Add(spawnedObjects[i]);
				}
			}
			return list.ToArray();
		}

		private void OnEnable()
		{
			if (!instance)
			{
				instance = this;
				return;
			}
			UnityEngine.Debug.LogErrorFormat(this, "Duplicate instance of singleton class {0}. Only one should exist at a time.", GetType().Name);
		}

		private void OnDisable()
		{
			if (instance == this)
			{
				instance = null;
			}
		}

		public void AddOccupiedNode(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex)
		{
			Array.Resize(ref occupiedNodes, occupiedNodes.Length + 1);
			occupiedNodes[occupiedNodes.Length - 1] = new NodeReference(nodeGraph, nodeIndex);
		}

		private bool CheckPositionFree(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex, SpawnCard spawnCard)
		{
			if (Array.IndexOf(value: new NodeReference(nodeGraph, nodeIndex), array: occupiedNodes) != -1)
			{
				return false;
			}
			float num = HullDef.Find(spawnCard.hullSize).radius * 0.7f;
			nodeGraph.GetNodePosition(nodeIndex, out var position);
			if (spawnCard.nodeGraphType == MapNodeGroup.GraphType.Ground)
			{
				position += UnityEngine.Vector3.up * (num + 0.25f);
			}
			return !HGPhysics.DoesOverlapSphere(position, num, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault | (int)LayerIndex.CommonMasks.fakeActorLayers);
		}

		public GameObject TrySpawnObject([NotNull] DirectorSpawnRequest directorSpawnRequest)
		{
			SpawnCard spawnCard = directorSpawnRequest.spawnCard;
			DirectorPlacementRule placementRule = directorSpawnRequest.placementRule;
			Xoroshiro128Plus rng = directorSpawnRequest.rng;
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(spawnCard.nodeGraphType);
			if (nodeGraph == null)
			{
				UnityEngine.Debug.LogError($"Unable to find nodegraph for {SceneInfo.instance.sceneDef.cachedName} of type {spawnCard.nodeGraphType}.");
				return null;
			}
			GameObject result = null;
			switch (placementRule.placementMode)
			{
			case DirectorPlacementRule.PlacementMode.Direct:
			{
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(0f, rng.nextNormalizedFloat * 360f, 0f);
				result = spawnCard.DoSpawn(placementRule.spawnOnTarget ? placementRule.spawnOnTarget.position : directorSpawnRequest.placementRule.position, placementRule.spawnOnTarget ? placementRule.spawnOnTarget.rotation : quaternion, directorSpawnRequest).spawnedInstance;
				break;
			}
			case DirectorPlacementRule.PlacementMode.Approximate:
			{
				List<NodeGraph.NodeIndex> list = nodeGraph.FindNodesInRangeWithFlagConditions(placementRule.targetPosition, placementRule.minDistance, placementRule.maxDistance, (HullMask)(1 << (int)spawnCard.hullSize), spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead);
				if (list.Count == 0)
				{
				}
				while (list.Count > 0)
				{
					int index = rng.RangeInt(0, list.Count);
					NodeGraph.NodeIndex nodeIndex4 = list[index];
					if (nodeGraph.GetNodePosition(nodeIndex4, out var position4) && CheckPositionFree(nodeGraph, nodeIndex4, spawnCard))
					{
						UnityEngine.Quaternion rotation4 = GetRotationFacingTargetPositionFromPoint(position4);
						result = spawnCard.DoSpawn(position4, rotation4, directorSpawnRequest).spawnedInstance;
						if (spawnCard.occupyPosition)
						{
							AddOccupiedNode(nodeGraph, nodeIndex4);
						}
						break;
					}
					list.RemoveAt(index);
				}
				break;
			}
			case DirectorPlacementRule.PlacementMode.NearestNode:
			{
				NodeGraph.NodeIndex nodeIndex3 = nodeGraph.FindClosestNodeWithFlagConditions(placementRule.targetPosition, spawnCard.hullSize, spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead);
				if (nodeGraph.GetNodePosition(nodeIndex3, out var position3))
				{
					UnityEngine.Quaternion rotation3 = GetRotationFacingTargetPositionFromPoint(position3);
					result = spawnCard.DoSpawn(position3, rotation3, directorSpawnRequest).spawnedInstance;
					if (spawnCard.occupyPosition)
					{
						AddOccupiedNode(nodeGraph, nodeIndex3);
					}
				}
				break;
			}
			case DirectorPlacementRule.PlacementMode.ApproximateSimple:
			{
				NodeGraph.NodeIndex nodeIndex2 = nodeGraph.FindClosestNodeWithFlagConditions(placementRule.targetPosition, spawnCard.hullSize, spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead);
				if (nodeGraph.GetNodePosition(nodeIndex2, out var position2) && CheckPositionFree(nodeGraph, nodeIndex2, spawnCard))
				{
					UnityEngine.Quaternion rotation2 = GetRotationFacingTargetPositionFromPoint(position2);
					result = spawnCard.DoSpawn(position2, rotation2, directorSpawnRequest).spawnedInstance;
					if (spawnCard.occupyPosition)
					{
						AddOccupiedNode(nodeGraph, nodeIndex2);
					}
				}
				break;
			}
			case DirectorPlacementRule.PlacementMode.Random:
			{
				List<NodeGraph.NodeIndex> activeNodesForHullMaskWithFlagConditions = nodeGraph.GetActiveNodesForHullMaskWithFlagConditions((HullMask)(1 << (int)spawnCard.hullSize), spawnCard.requiredFlags, spawnCard.forbiddenFlags);
				if (activeNodesForHullMaskWithFlagConditions.Count == 0)
				{
				}
				while (activeNodesForHullMaskWithFlagConditions.Count > 0)
				{
					int index2 = rng.RangeInt(0, activeNodesForHullMaskWithFlagConditions.Count);
					NodeGraph.NodeIndex nodeIndex5 = activeNodesForHullMaskWithFlagConditions[index2];
					if (nodeGraph.GetNodePosition(nodeIndex5, out var position5) && CheckPositionFree(nodeGraph, nodeIndex5, spawnCard))
					{
						UnityEngine.Quaternion rotation5 = UnityEngine.Quaternion.Euler(0f, rng.nextNormalizedFloat * 360f, 0f);
						result = spawnCard.DoSpawn(position5, rotation5, directorSpawnRequest).spawnedInstance;
						if (spawnCard.occupyPosition)
						{
							AddOccupiedNode(nodeGraph, nodeIndex5);
						}
						break;
					}
					activeNodesForHullMaskWithFlagConditions.RemoveAt(index2);
				}
				break;
			}
			case DirectorPlacementRule.PlacementMode.RandomNormalized:
			{
				if (SceneInfo.instance.approximateMapBoundMesh == null)
				{
					break;
				}
				Bounds bounds = SceneInfo.instance.approximateMapBoundMesh.bounds;
				UnityEngine.Vector3 position = new UnityEngine.Vector3(rng.RangeFloat(bounds.min.x, bounds.max.x), rng.RangeFloat(bounds.min.y, bounds.max.y), rng.RangeFloat(bounds.min.z, bounds.max.z));
				NodeGraph.NodeIndex nodeIndex = nodeGraph.FindClosestNodeWithFlagConditions(position, spawnCard.hullSize, spawnCard.requiredFlags, spawnCard.forbiddenFlags, placementRule.preventOverhead);
				if (nodeGraph.GetNodePosition(nodeIndex, out position) && CheckPositionFree(nodeGraph, nodeIndex, spawnCard))
				{
					UnityEngine.Quaternion rotation = GetRotationFacingTargetPositionFromPoint(position);
					result = spawnCard.DoSpawn(position, rotation, directorSpawnRequest).spawnedInstance;
					if (spawnCard.occupyPosition)
					{
						AddOccupiedNode(nodeGraph, nodeIndex);
					}
				}
				break;
			}
			}
			return result;
			UnityEngine.Quaternion GetRotationFacingTargetPositionFromPoint(UnityEngine.Vector3 point)
			{
				point.y = placementRule.targetPosition.y;
				return Util.QuaternionSafeLookRotation(placementRule.targetPosition - point);
			}
		}

		public static void GetMonsterSpawnDistance(MonsterSpawnDistance input, out float minimumDistance, out float maximumDistance)
		{
			minimumDistance = 0f;
			maximumDistance = 0f;
			switch (input)
			{
			case MonsterSpawnDistance.Close:
				minimumDistance = 8f;
				maximumDistance = 20f;
				break;
			case MonsterSpawnDistance.Standard:
				minimumDistance = 25f;
				maximumDistance = 40f;
				break;
			case MonsterSpawnDistance.Far:
				minimumDistance = 70f;
				maximumDistance = 120f;
				break;
			}
		}
	}
	public class DirectorPlacementRule
	{
		public enum PlacementMode
		{
			Direct,
			Approximate,
			ApproximateSimple,
			NearestNode,
			Random,
			RandomNormalized
		}

		public Transform spawnOnTarget;

		public UnityEngine.Vector3 position;

		public PlacementMode placementMode;

		public float minDistance;

		public float maxDistance;

		public bool preventOverhead;

		public UnityEngine.Vector3 targetPosition
		{
			get
			{
				if (!spawnOnTarget)
				{
					return position;
				}
				return spawnOnTarget.position;
			}
		}
	}
	[Serializable]
	public class DirectorCard
	{
		public SpawnCard spawnCard;

		public int selectionWeight;

		public DirectorCore.MonsterSpawnDistance spawnDistance;

		public bool preventOverhead;

		public int minimumStageCompletions;

		[Tooltip("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.")]
		[Obsolete("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.", false)]
		public string requiredUnlockable;

		[Tooltip("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.")]
		[Obsolete("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.", false)]
		public string forbiddenUnlockable;

		public UnlockableDef requiredUnlockableDef;

		public UnlockableDef forbiddenUnlockableDef;

		public int cost => spawnCard.directorCreditCost;

		[Obsolete("'CardIsValid' is confusingly named. Use 'IsAvailable' instead.", false)]
		public bool CardIsValid()
		{
			return IsAvailable();
		}

		public bool IsAvailable()
		{
			ref string reference = ref requiredUnlockable;
			ref string reference2 = ref forbiddenUnlockable;
			if (!requiredUnlockableDef && !string.IsNullOrEmpty(reference))
			{
				requiredUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference);
				reference = null;
			}
			if (!forbiddenUnlockableDef && !string.IsNullOrEmpty(reference2))
			{
				forbiddenUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference2);
				reference2 = null;
			}
			bool flag = !requiredUnlockableDef || Run.instance.IsUnlockableUnlocked(requiredUnlockableDef);
			bool flag2 = (bool)forbiddenUnlockableDef && Run.instance.DoesEveryoneHaveThisUnlockableUnlocked(forbiddenUnlockableDef);
			if ((bool)Run.instance && Run.instance.stageClearCount >= minimumStageCompletions && flag && !flag2 && (bool)spawnCard && (bool)spawnCard.prefab)
			{
				ExpansionRequirementComponent component = spawnCard.prefab.GetComponent<ExpansionRequirementComponent>();
				if (!component)
				{
					CharacterMaster component2 = spawnCard.prefab.GetComponent<CharacterMaster>();
					if ((bool)component2 && (bool)component2.bodyPrefab)
					{
						component = component2.bodyPrefab.GetComponent<ExpansionRequirementComponent>();
					}
				}
				if ((bool)component)
				{
					return Run.instance.IsExpansionEnabled(component.requiredExpansion);
				}
				return true;
			}
			return false;
		}
	}
	public class DisableCollisionsBetweenColliders : MonoBehaviour
	{
		public Collider[] collidersA;

		public Collider[] collidersB;

		public void Awake()
		{
			Collider[] array = collidersA;
			foreach (Collider collider in array)
			{
				Collider[] array2 = collidersB;
				foreach (Collider collider2 in array2)
				{
					Physics.IgnoreCollision(collider, collider2);
				}
			}
		}
	}
	[RequireComponent(typeof(SphereCollider))]
	public class DisableCollisionsIfInTrigger : MonoBehaviour
	{
		public Collider colliderToIgnore;

		private SphereCollider trigger;

		public void Awake()
		{
			trigger = GetComponent<SphereCollider>();
		}

		private void OnTriggerEnter(Collider other)
		{
			if ((bool)trigger)
			{
				UnityEngine.Vector3 position = base.transform.position;
				UnityEngine.Vector3 position2 = other.transform.position;
				float num = trigger.radius * Mathf.Max(base.transform.lossyScale.x, base.transform.lossyScale.y, base.transform.lossyScale.z);
				float num2 = num * num;
				if ((position - position2).sqrMagnitude < num2)
				{
					Physics.IgnoreCollision(colliderToIgnore, other);
				}
			}
		}
	}
	public class DisableIfGameModded : MonoBehaviour
	{
		public void OnEnable()
		{
			if (RoR2Application.isModded)
			{
				base.gameObject.SetActive(value: false);
			}
		}
	}
	public class DisableIfNoExpansion : MonoBehaviour
	{
		[SerializeField]
		private ExpansionDef expansionDef;

		private void Awake()
		{
			EntitlementManager.onEntitlementsUpdated += Reset;
			Reset();
		}

		private void OnDestroy()
		{
			EntitlementManager.onEntitlementsUpdated -= Reset;
		}

		private void Reset()
		{
			if ((bool)expansionDef && !EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(expansionDef.requiredEntitlement))
			{
				base.gameObject.SetActive(value: false);
			}
			else
			{
				base.gameObject.SetActive(value: true);
			}
		}
	}
	public class DisableParticleEmissionAndDestroyOnTimer : MonoBehaviour
	{
		[Tooltip("How long to wait before destroying or repooling the object")]
		public float waitDuration = 3f;

		[Tooltip("Particle systems to be stopped.")]
		public List<ParticleSystem> particleSystems;

		public bool StartParticleEmissionOnEnable = true;

		private bool countdownStarted;

		private float timeRemaining;

		private EffectManagerHelper efh;

		private void Awake()
		{
			efh = GetComponent<EffectManagerHelper>();
		}

		public void DisableParticlesStartTimer()
		{
			countdownStarted = true;
			timeRemaining = waitDuration;
			foreach (ParticleSystem particleSystem in particleSystems)
			{
				particleSystem.Stop();
			}
		}

		private void Update()
		{
			if (countdownStarted)
			{
				timeRemaining -= Time.deltaTime;
				if (timeRemaining < 0f)
				{
					DestroyOrRepoolObject();
				}
			}
		}

		private void DestroyOrRepoolObject()
		{
			if ((bool)efh && efh.OwningPool != null)
			{
				efh.OwningPool.ReturnObject(efh);
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void OnEnable()
		{
			countdownStarted = false;
			if (!StartParticleEmissionOnEnable)
			{
				return;
			}
			foreach (ParticleSystem particleSystem in particleSystems)
			{
				particleSystem.Play();
			}
		}
	}
	public class DitherModel : MonoBehaviour
	{
		[HideInInspector]
		public float fade = 1f;

		public float oldFade = 1f;

		public Collider bounds;

		public Renderer[] renderers;

		private MaterialPropertyBlock propertyStorage;

		private static List<DitherModel> instancesList;

		static DitherModel()
		{
			instancesList = new List<DitherModel>();
			SceneCamera.onSceneCameraPreRender += OnSceneCameraPreRender;
		}

		private static void OnSceneCameraPreRender(SceneCamera sceneCamera)
		{
			if ((bool)sceneCamera.cameraRigController)
			{
				RefreshObstructorsForCamera(sceneCamera.cameraRigController);
			}
		}

		private static void RefreshObstructorsForCamera(CameraRigController cameraRigController)
		{
			UnityEngine.Vector3 position = cameraRigController.transform.position;
			for (int i = 0; i < instancesList.Count; i++)
			{
				DitherModel ditherModel = instancesList[i];
				if ((bool)ditherModel.bounds)
				{
					UnityEngine.Vector3 a = ditherModel.bounds.ClosestPointOnBounds(position);
					if (cameraRigController.enableFading)
					{
						ditherModel.fade = Mathf.Clamp01(Util.Remap(UnityEngine.Vector3.Distance(a, position), cameraRigController.fadeStartDistance, cameraRigController.fadeEndDistance, 0f, 1f));
					}
					else
					{
						ditherModel.fade = 1f;
					}
					ditherModel.UpdateDither();
				}
				else
				{
					UnityEngine.Debug.LogFormat("{0} has missing collider for dither model", ditherModel.gameObject);
				}
			}
		}

		private void UpdateDither()
		{
			if (fade != oldFade)
			{
				for (int num = renderers.Length - 1; num >= 0; num--)
				{
					Renderer obj = renderers[num];
					obj.GetPropertyBlock(propertyStorage);
					propertyStorage.SetFloat("_Fade", fade);
					obj.SetPropertyBlock(propertyStorage);
				}
			}
			oldFade = fade;
		}

		private void Awake()
		{
			propertyStorage = new MaterialPropertyBlock();
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}
	}
	public class DotController : NetworkBehaviour
	{
		public enum DotIndex
		{
			None = -1,
			Bleed,
			Burn,
			Helfire,
			PercentBurn,
			Poison,
			Blight,
			SuperBleed,
			StrongerBurn,
			Fracture,
			LunarRuin,
			Count
		}

		public class DotDef
		{
			public float interval;

			public float damageCoefficient;

			public DamageColorIndex damageColorIndex;

			public BuffDef associatedBuff;

			public BuffDef terminalTimedBuff;

			public float terminalTimedBuffDuration;

			public bool resetTimerOnAdd;
		}

		private class DotStack
		{
			public DotIndex dotIndex;

			public DotDef dotDef;

			public GameObject attackerObject;

			public TeamIndex attackerTeam;

			public float timer;

			public float damage;

			public DamageTypeCombo damageType;

			public void Reset()
			{
				dotIndex = DotIndex.Bleed;
				dotDef = null;
				attackerObject = null;
				attackerTeam = TeamIndex.Neutral;
				timer = 0f;
				damage = 0f;
				damageType = default(DamageTypeCombo);
			}
		}

		private sealed class DotStackPool : BasePool<DotStack>
		{
			protected override void ResetItem(DotStack item)
			{
				item.Reset();
			}
		}

		private class PendingDamage
		{
			public GameObject attackerObject;

			public float totalDamage;

			public DamageTypeCombo damageType;

			public void Reset()
			{
				attackerObject = null;
				totalDamage = 0f;
				damageType = default(DamageTypeCombo);
			}
		}

		private sealed class PendingDamagePool : BasePool<PendingDamage>
		{
			protected override void ResetItem(PendingDamage item)
			{
				item.Reset();
			}
		}

		public delegate void OnDotInflictedServerGlobalDelegate(DotController dotController, ref InflictDotInfo inflictDotInfo);

		public const float minDamagePerTick = 1f;

		private static DotDef[] dotDefs;

		private static readonly Dictionary<int, DotController> dotControllerLocator = new Dictionary<int, DotController>();

		private static readonly List<DotController> instancesList = new List<DotController>();

		public static readonly ReadOnlyCollection<DotController> readOnlyInstancesList = instancesList.AsReadOnly();

		public static GameObject FractureImpactEffectPrefab;

		public static GameObject HelfireIgniteEffectPrefab;

		public static GameObject DotControllerPrefab;

		[SyncVar]
		private NetworkInstanceId victimObjectId;

		private GameObject _victimObject;

		private CharacterBody _victimBody;

		private BurnEffectController burnEffectController;

		private BurnEffectController strongerBurnEffectController;

		private BurnEffectController helfireEffectController;

		private BurnEffectController poisonEffectController;

		private BurnEffectController blightEffectController;

		private EffectManagerHelper bleedEffect;

		private EffectManagerHelper superBleedEffect;

		private EffectManagerHelper preFractureEffect;

		[SyncVar]
		private uint activeDotFlags;

		private static readonly DotStackPool dotStackPool = new DotStackPool();

		private List<DotStack> dotStackList;

		private float[] dotTimers;

		private static readonly PendingDamagePool pendingDamagePool = new PendingDamagePool();

		private int recordedVictimInstanceId = -1;

		public GameObject victimObject
		{
			get
			{
				if (!_victimObject)
				{
					if (NetworkServer.active)
					{
						_victimObject = NetworkServer.FindLocalObject(victimObjectId);
					}
					else if (NetworkClient.active)
					{
						_victimObject = ClientScene.FindLocalObject(victimObjectId);
					}
				}
				return _victimObject;
			}
			set
			{
				NetworkvictimObjectId = value.GetComponent<NetworkIdentity>().netId;
			}
		}

		private CharacterBody victimBody
		{
			get
			{
				if (!_victimBody && (bool)victimObject)
				{
					_victimBody = victimObject.GetComponent<CharacterBody>();
				}
				return _victimBody;
			}
		}

		private HealthComponent victimHealthComponent => victimBody?.healthComponent;

		private TeamIndex victimTeam
		{
			get
			{
				if (!victimBody)
				{
					return TeamIndex.None;
				}
				return victimBody.teamComponent.teamIndex;
			}
		}

		public NetworkInstanceId NetworkvictimObjectId
		{
			get
			{
				return victimObjectId;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref victimObjectId, 1u);
			}
		}

		public uint NetworkactiveDotFlags
		{
			get
			{
				return activeDotFlags;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref activeDotFlags, 2u);
			}
		}

		public static event OnDotInflictedServerGlobalDelegate onDotInflictedServerGlobal;

		public static DotDef GetDotDef(DotIndex dotIndex)
		{
			if (dotIndex < DotIndex.Bleed || dotIndex >= DotIndex.Count)
			{
				return null;
			}
			return dotDefs[(int)dotIndex];
		}

		[SystemInitializer(new Type[] { typeof(BuffCatalog) })]
		private static void InitDotCatalog()
		{
			dotDefs = new DotDef[10];
			dotDefs[0] = new DotDef
			{
				interval = 0.25f,
				damageCoefficient = 0.2f,
				damageColorIndex = DamageColorIndex.Bleed,
				associatedBuff = RoR2Content.Buffs.Bleeding
			};
			dotDefs[1] = new DotDef
			{
				interval = 0.2f,
				damageCoefficient = 0.1f,
				damageColorIndex = DamageColorIndex.Item,
				associatedBuff = RoR2Content.Buffs.OnFire,
				terminalTimedBuff = RoR2Content.Buffs.OnFire,
				terminalTimedBuffDuration = 1f
			};
			dotDefs[7] = new DotDef
			{
				interval = 0.2f,
				damageCoefficient = 0.1f,
				damageColorIndex = DamageColorIndex.Item,
				associatedBuff = DLC1Content.Buffs.StrongerBurn,
				terminalTimedBuff = DLC1Content.Buffs.StrongerBurn,
				terminalTimedBuffDuration = 1f
			};
			dotDefs[3] = new DotDef
			{
				interval = 0.2f,
				damageCoefficient = 0.1f,
				damageColorIndex = DamageColorIndex.Item,
				associatedBuff = RoR2Content.Buffs.OnFire
			};
			dotDefs[2] = new DotDef
			{
				interval = 0.2f,
				damageCoefficient = 0.02f,
				damageColorIndex = DamageColorIndex.Item
			};
			dotDefs[4] = new DotDef
			{
				interval = 0.333f,
				damageCoefficient = 0.333f,
				damageColorIndex = DamageColorIndex.Poison,
				associatedBuff = RoR2Content.Buffs.Poisoned
			};
			dotDefs[5] = new DotDef
			{
				interval = 0.333f,
				damageCoefficient = 0.2f,
				damageColorIndex = DamageColorIndex.Poison,
				associatedBuff = RoR2Content.Buffs.Blight
			};
			dotDefs[6] = new DotDef
			{
				interval = 0.25f,
				damageCoefficient = 0.333f,
				damageColorIndex = DamageColorIndex.SuperBleed,
				associatedBuff = RoR2Content.Buffs.SuperBleed
			};
			dotDefs[8] = new DotDef
			{
				interval = 3f,
				damageCoefficient = 4f,
				damageColorIndex = DamageColorIndex.Void,
				associatedBuff = DLC1Content.Buffs.Fracture,
				resetTimerOnAdd = false
			};
			dotDefs[9] = new DotDef
			{
				interval = 3f,
				damageCoefficient = 0f,
				damageColorIndex = DamageColorIndex.Default,
				associatedBuff = DLC2Content.Buffs.lunarruin,
				resetTimerOnAdd = true
			};
		}

		public bool HasDotActive(DotIndex dotIndex)
		{
			return (activeDotFlags & (1 << (int)dotIndex)) != 0;
		}

		private void Awake()
		{
			if (NetworkServer.active)
			{
				dotStackList = new List<DotStack>();
				dotTimers = new float[10];
			}
			instancesList.Add(this);
		}

		private void OnDestroy()
		{
			if (NetworkServer.active)
			{
				for (int num = dotStackList.Count - 1; num >= 0; num--)
				{
					RemoveDotStackAtServer(num);
				}
			}
			instancesList.Remove(this);
			if (recordedVictimInstanceId != -1)
			{
				dotControllerLocator.Remove(recordedVictimInstanceId);
			}
		}

		private void FixedUpdate()
		{
			if (!victimObject)
			{
				if (NetworkServer.active)
				{
					HandleDestroy();
				}
				return;
			}
			UpdateDotVisuals();
			if (!NetworkServer.active)
			{
				return;
			}
			for (DotIndex dotIndex = DotIndex.Bleed; dotIndex < DotIndex.Count; dotIndex++)
			{
				uint num = (uint)(1 << (int)dotIndex);
				if ((activeDotFlags & num) == 0)
				{
					continue;
				}
				DotDef dotDef = GetDotDef(dotIndex);
				float num2 = dotTimers[(int)dotIndex] - Time.fixedDeltaTime;
				if (num2 <= 0f)
				{
					num2 += dotDef.interval;
					int remainingActive = 0;
					EvaluateDotStacksForType(dotIndex, dotDef.interval, out remainingActive);
					NetworkactiveDotFlags = activeDotFlags & ~num;
					if (remainingActive != 0)
					{
						NetworkactiveDotFlags = activeDotFlags | num;
					}
				}
				dotTimers[(int)dotIndex] = num2;
			}
			if (dotStackList.Count == 0)
			{
				HandleDestroy();
			}
		}

		private void HandleDestroy()
		{
			RepoolEffect(ref bleedEffect);
			RepoolEffect(ref superBleedEffect);
			RepoolEffect(ref preFractureEffect);
			UnityEngine.Object.Destroy(base.gameObject);
		}

		private EffectManagerHelper GetPooledEffect(string _path)
		{
			return EffectManager.GetAndActivatePooledEffect(LegacyResourcesAPI.Load<GameObject>(_path), base.transform, inResetLocal: true);
		}

		private void RepoolEffect(ref EffectManagerHelper emh)
		{
			if ((bool)emh)
			{
				if (emh.OwningPool != null)
				{
					emh.transform.SetParent(null);
					emh.ReturnToPool();
				}
				else
				{
					UnityEngine.Object.Destroy(emh.gameObject);
				}
				emh = null;
			}
		}

		private void UpdateDotVisuals()
		{
			if (!victimBody)
			{
				return;
			}
			ModelLocator modelLocator = null;
			base.transform.position = victimBody.corePosition;
			if ((activeDotFlags & (true ? 1u : 0u)) != 0)
			{
				if (!bleedEffect)
				{
					bleedEffect = GetPooledEffect("Prefabs/BleedEffect");
				}
			}
			else if ((bool)bleedEffect)
			{
				RepoolEffect(ref bleedEffect);
			}
			if ((activeDotFlags & 2u) != 0 || (activeDotFlags & 8u) != 0)
			{
				if (!burnEffectController)
				{
					modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent<ModelLocator>());
					if ((bool)modelLocator && (bool)modelLocator.modelTransform)
					{
						burnEffectController = base.gameObject.AddComponent<BurnEffectController>();
						burnEffectController.effectType = BurnEffectController.normalEffect;
						burnEffectController.target = modelLocator.modelTransform.gameObject;
					}
				}
			}
			else if ((bool)burnEffectController)
			{
				burnEffectController.HandleDestroy();
				burnEffectController = null;
			}
			if ((activeDotFlags & 0x80u) != 0)
			{
				if (!strongerBurnEffectController)
				{
					modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent<ModelLocator>());
					if ((bool)modelLocator && (bool)modelLocator.modelTransform)
					{
						strongerBurnEffectController = base.gameObject.AddComponent<BurnEffectController>();
						strongerBurnEffectController.effectType = BurnEffectController.strongerBurnEffect;
						strongerBurnEffectController.target = modelLocator.modelTransform.gameObject;
					}
				}
			}
			else if ((bool)strongerBurnEffectController)
			{
				strongerBurnEffectController.HandleDestroy();
				strongerBurnEffectController = null;
			}
			if ((activeDotFlags & 4u) != 0)
			{
				if (!helfireEffectController)
				{
					modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent<ModelLocator>());
					if ((bool)modelLocator && (bool)modelLocator.modelTransform)
					{
						helfireEffectController = base.gameObject.AddComponent<BurnEffectController>();
						helfireEffectController.effectType = BurnEffectController.helfireEffect;
						helfireEffectController.target = modelLocator.modelTransform.gameObject;
					}
				}
			}
			else if ((bool)helfireEffectController)
			{
				helfireEffectController.HandleDestroy();
				helfireEffectController = null;
			}
			if ((activeDotFlags & 0x10u) != 0)
			{
				if (!poisonEffectController)
				{
					modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent<ModelLocator>());
					if ((bool)modelLocator && (bool)modelLocator.modelTransform)
					{
						poisonEffectController = base.gameObject.AddComponent<BurnEffectController>();
						poisonEffectController.effectType = BurnEffectController.poisonEffect;
						poisonEffectController.target = modelLocator.modelTransform.gameObject;
					}
				}
			}
			else if ((bool)poisonEffectController)
			{
				poisonEffectController.HandleDestroy();
				poisonEffectController = null;
			}
			if ((activeDotFlags & 0x20u) != 0)
			{
				if (!blightEffectController)
				{
					modelLocator = (modelLocator ? modelLocator : victimObject.GetComponent<ModelLocator>());
					if ((bool)modelLocator && (bool)modelLocator.modelTransform)
					{
						blightEffectController = base.gameObject.AddComponent<BurnEffectController>();
						blightEffectController.effectType = BurnEffectController.blightEffect;
						blightEffectController.target = modelLocator.modelTransform.gameObject;
					}
				}
			}
			else if ((bool)blightEffectController)
			{
				blightEffectController.HandleDestroy();
				blightEffectController = null;
			}
			if ((activeDotFlags & 0x40u) != 0)
			{
				if (!superBleedEffect)
				{
					superBleedEffect = GetPooledEffect("Prefabs/SuperBleedEffect");
				}
			}
			else if ((bool)superBleedEffect)
			{
				RepoolEffect(ref superBleedEffect);
			}
			if ((activeDotFlags & 0x100u) != 0)
			{
				if (!preFractureEffect)
				{
					preFractureEffect = GetPooledEffect("Prefabs/PreFractureEffect");
				}
			}
			else if ((bool)preFractureEffect)
			{
				RepoolEffect(ref preFractureEffect);
			}
		}

		private void LateUpdate()
		{
			if ((bool)victimObject)
			{
				base.transform.position = victimObject.transform.position;
			}
		}

		private static void AddPendingDamageEntry(List<PendingDamage> pendingDamages, GameObject attackerObject, float damage, DamageTypeCombo damageType)
		{
			for (int i = 0; i < pendingDamages.Count; i++)
			{
				if (pendingDamages[i].attackerObject == attackerObject)
				{
					pendingDamages[i].totalDamage += damage;
					return;
				}
			}
			PendingDamage pendingDamage = pendingDamagePool.Request();
			pendingDamage.attackerObject = attackerObject;
			pendingDamage.totalDamage = damage;
			pendingDamage.damageType = damageType;
			pendingDamages.Add(pendingDamage);
		}

		private void OnDotStackAddedServer(DotStack dotStack)
		{
			DotDef dotDef = dotStack.dotDef;
			if (dotDef.associatedBuff != null && (bool)victimBody)
			{
				victimBody.AddBuff(dotDef.associatedBuff.buffIndex);
			}
		}

		private void OnDotStackRemovedServer(DotStack dotStack)
		{
			DotDef dotDef = dotStack.dotDef;
			if ((bool)victimBody)
			{
				if (dotDef.associatedBuff != null)
				{
					victimBody.RemoveBuff(dotDef.associatedBuff.buffIndex);
				}
				if (dotDef.terminalTimedBuff != null)
				{
					victimBody.AddTimedBuff(dotDef.terminalTimedBuff, dotDef.terminalTimedBuffDuration);
				}
			}
		}

		private void RemoveDotStackAtServer(int i)
		{
			DotStack dotStack = dotStackList[i];
			dotStackList.RemoveAt(i);
			OnDotStackRemovedServer(dotStack);
			dotStackPool.Return(dotStack);
		}

		private void EvaluateDotStacksForType(DotIndex dotIndex, float dt, out int remainingActive)
		{
			List<PendingDamage> list = CollectionPool<PendingDamage, List<PendingDamage>>.RentCollection();
			remainingActive = 0;
			DotDef dotDef = GetDotDef(dotIndex);
			for (int num = dotStackList.Count - 1; num >= 0; num--)
			{
				DotStack dotStack = dotStackList[num];
				if (dotStack.dotIndex == dotIndex)
				{
					dotStack.timer -= dt;
					AddPendingDamageEntry(list, dotStack.attackerObject, dotStack.damage, dotStack.damageType);
					if (dotStack.timer <= 0f)
					{
						RemoveDotStackAtServer(num);
					}
					else
					{
						remainingActive++;
					}
				}
			}
			if ((bool)victimObject)
			{
				if ((bool)victimBody && dotIndex == DotIndex.Fracture && list.Count > 0)
				{
					if (FractureImpactEffectPrefab == null)
					{
						FractureImpactEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/FractureImpactEffect");
					}
					EffectManager.SpawnEffect(FractureImpactEffectPrefab, new EffectData
					{
						origin = victimBody.corePosition
					}, transmit: true);
				}
				if ((bool)victimHealthComponent)
				{
					UnityEngine.Vector3 corePosition = victimBody.corePosition;
					for (int i = 0; i < list.Count; i++)
					{
						DamageInfo damageInfo = new DamageInfo();
						damageInfo.attacker = list[i].attackerObject;
						damageInfo.crit = false;
						damageInfo.damage = list[i].totalDamage;
						damageInfo.force = UnityEngine.Vector3.zero;
						damageInfo.inflictor = base.gameObject;
						damageInfo.position = corePosition;
						damageInfo.procCoefficient = 0f;
						damageInfo.damageColorIndex = dotDef.damageColorIndex;
						damageInfo.damageType = list[i].damageType | DamageType.DoT;
						damageInfo.dotIndex = dotIndex;
						victimHealthComponent.TakeDamage(damageInfo);
					}
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				pendingDamagePool.Return(list[j]);
			}
			CollectionPool<PendingDamage, List<PendingDamage>>.ReturnCollection(list);
		}

		[Server]
		private void AddDot(GameObject attackerObject, float duration, DotIndex dotIndex, float damageMultiplier, uint? maxStacksFromAttacker, float? totalDamage, DotIndex? preUpgradeDotIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::AddDot(UnityEngine.GameObject,System.Single,RoR2.DotController/DotIndex,System.Single,System.Nullable`1<System.UInt32>,System.Nullable`1<System.Single>,System.Nullable`1<RoR2.DotController/DotIndex>)' called on client");
				return;
			}
			TeamIndex attackerTeam = TeamIndex.Neutral;
			float num = 0f;
			TeamComponent component = attackerObject.GetComponent<TeamComponent>();
			if ((bool)component)
			{
				attackerTeam = component.teamIndex;
			}
			CharacterBody component2 = attackerObject.GetComponent<CharacterBody>();
			if ((bool)component2)
			{
				num = component2.damage;
			}
			DotDef dotDef = dotDefs[(int)dotIndex];
			DotStack dotStack = dotStackPool.Request();
			dotStack.dotIndex = dotIndex;
			dotStack.dotDef = dotDef;
			dotStack.attackerObject = attackerObject;
			dotStack.attackerTeam = attackerTeam;
			dotStack.timer = duration;
			dotStack.damage = dotDef.damageCoefficient * num * damageMultiplier;
			dotStack.damageType = DamageType.Generic;
			int num2 = 0;
			int i = 0;
			for (int count = dotStackList.Count; i < count; i++)
			{
				if (dotStackList[i].dotIndex == dotIndex)
				{
					num2++;
				}
			}
			switch (dotIndex)
			{
			case DotIndex.Bleed:
			case DotIndex.SuperBleed:
			case DotIndex.Fracture:
			case DotIndex.LunarRuin:
			{
				int k = 0;
				for (int count3 = dotStackList.Count; k < count3; k++)
				{
					if (dotStackList[k].dotIndex == dotIndex)
					{
						dotStackList[k].timer = Mathf.Max(dotStackList[k].timer, duration);
					}
				}
				break;
			}
			case DotIndex.Burn:
			case DotIndex.StrongerBurn:
				dotStack.damage = Mathf.Min(dotStack.damage, victimBody.healthComponent.fullCombinedHealth * 0.01f * damageMultiplier);
				break;
			case DotIndex.PercentBurn:
				dotStack.damage = Mathf.Min(dotStack.damage, victimBody.healthComponent.fullCombinedHealth * 0.01f);
				break;
			case DotIndex.Helfire:
			{
				if (!component2)
				{
					return;
				}
				HealthComponent healthComponent = component2.healthComponent;
				if (!healthComponent)
				{
					return;
				}
				dotStack.damage = Mathf.Min(healthComponent.fullCombinedHealth * 0.01f * damageMultiplier, victimBody.healthComponent.fullCombinedHealth * 0.01f * damageMultiplier);
				if ((bool)victimBody)
				{
					if (HelfireIgniteEffectPrefab == null)
					{
						HelfireIgniteEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/HelfireIgniteEffect");
					}
					EffectManager.SpawnEffect(HelfireIgniteEffectPrefab, new EffectData
					{
						origin = victimBody.corePosition
					}, transmit: true);
				}
				break;
			}
			case DotIndex.Poison:
			{
				float a = victimHealthComponent.fullCombinedHealth / 100f * 1f * dotDef.interval;
				dotStack.damage = Mathf.Min(Mathf.Max(a, dotStack.damage), dotStack.damage * 50f);
				dotStack.damageType = DamageType.NonLethal;
				int j = 0;
				for (int count2 = dotStackList.Count; j < count2; j++)
				{
					if (dotStackList[j].dotIndex == DotIndex.Poison)
					{
						dotStackList[j].timer = Mathf.Max(dotStackList[j].timer, duration);
						dotStackList[j].damage = dotStack.damage;
						return;
					}
				}
				if (num2 == 0)
				{
					component2?.master?.playerStatsComponent?.currentStats.PushStatValue(StatDef.totalCrocoInfectionsInflicted, 1uL);
				}
				break;
			}
			}
			if ((dotIndex == DotIndex.Helfire || (preUpgradeDotIndex.HasValue && preUpgradeDotIndex.Value == DotIndex.Helfire)) && victimObject == attackerObject)
			{
				dotStack.damageType |= (DamageTypeCombo)(DamageType.NonLethal | DamageType.Silent);
			}
			dotStack.damage = Mathf.Max(1f, dotStack.damage);
			if (totalDamage.HasValue && dotStack.damage != 0f)
			{
				duration = totalDamage.Value * dotDef.interval / dotStack.damage;
				dotStack.timer = duration;
			}
			if (maxStacksFromAttacker.HasValue)
			{
				DotStack dotStack2 = null;
				int num3 = 0;
				int l = 0;
				for (int count4 = dotStackList.Count; l < count4; l++)
				{
					DotStack dotStack3 = dotStackList[l];
					if (dotStack3.dotIndex == dotIndex && dotStack3.attackerObject == attackerObject)
					{
						num3++;
						if (dotStack2 == null || dotStack3.timer < dotStack2.timer)
						{
							dotStack2 = dotStack3;
						}
					}
				}
				if (num3 >= maxStacksFromAttacker.Value && dotStack2 != null)
				{
					if (dotStack2.timer < duration)
					{
						dotStack2.timer = duration;
						dotStack2.damage = dotStack.damage;
						dotStack2.damageType = dotStack.damageType;
					}
					return;
				}
			}
			if (num2 == 0 || dotDef.resetTimerOnAdd)
			{
				NetworkactiveDotFlags = activeDotFlags | (uint)(1 << (int)dotIndex);
				dotTimers[(int)dotIndex] = dotDef.interval;
			}
			dotStackList.Add(dotStack);
			OnDotStackAddedServer(dotStack);
		}

		[Server]
		public static void InflictDot(ref InflictDotInfo inflictDotInfo)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::InflictDot(RoR2.InflictDotInfo&)' called on client");
			}
			else
			{
				if (inflictDotInfo.dotIndex < DotIndex.Bleed || inflictDotInfo.dotIndex >= DotIndex.Count || ImmuneToDebuffBehavior.OverrideDot(inflictDotInfo) || !inflictDotInfo.victimObject || !inflictDotInfo.attackerObject)
				{
					return;
				}
				if (!dotControllerLocator.TryGetValue(inflictDotInfo.victimObject.GetInstanceID(), out var value))
				{
					if (DotControllerPrefab == null)
					{
						DotControllerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/DotController");
					}
					GameObject obj = UnityEngine.Object.Instantiate(DotControllerPrefab);
					value = obj.GetComponent<DotController>();
					value.victimObject = inflictDotInfo.victimObject;
					value.recordedVictimInstanceId = inflictDotInfo.victimObject.GetInstanceID();
					dotControllerLocator.Add(value.recordedVictimInstanceId, value);
					NetworkServer.Spawn(obj);
				}
				value.AddDot(inflictDotInfo.attackerObject, inflictDotInfo.duration, inflictDotInfo.dotIndex, inflictDotInfo.damageMultiplier, inflictDotInfo.maxStacksFromAttacker, inflictDotInfo.totalDamage, inflictDotInfo.preUpgradeDotIndex);
				DotController.onDotInflictedServerGlobal?.Invoke(value, ref inflictDotInfo);
			}
		}

		[Server]
		public static void InflictDot(GameObject victimObject, GameObject attackerObject, DotIndex dotIndex, float duration = 8f, float damageMultiplier = 1f, uint? maxStacksFromAttacker = null)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::InflictDot(UnityEngine.GameObject,UnityEngine.GameObject,RoR2.DotController/DotIndex,System.Single,System.Single,System.Nullable`1<System.UInt32>)' called on client");
				return;
			}
			InflictDotInfo inflictDotInfo = default(InflictDotInfo);
			inflictDotInfo.victimObject = victimObject;
			inflictDotInfo.attackerObject = attackerObject;
			inflictDotInfo.dotIndex = dotIndex;
			inflictDotInfo.duration = duration;
			inflictDotInfo.damageMultiplier = damageMultiplier;
			inflictDotInfo.maxStacksFromAttacker = maxStacksFromAttacker;
			InflictDotInfo inflictDotInfo2 = inflictDotInfo;
			InflictDot(ref inflictDotInfo2);
		}

		[Server]
		public static void RemoveAllDots(GameObject victimObject)
		{
			DotController value;
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.DotController::RemoveAllDots(UnityEngine.GameObject)' called on client");
			}
			else if (dotControllerLocator.TryGetValue(victimObject.GetInstanceID(), out value))
			{
				value.HandleDestroy();
			}
		}

		[Server]
		public static DotController FindDotController(GameObject victimObject)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.DotController RoR2.DotController::FindDotController(UnityEngine.GameObject)' called on client");
				return null;
			}
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				if ((object)victimObject == instancesList[i]._victimObject)
				{
					return instancesList[i];
				}
			}
			return null;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(victimObjectId);
				writer.WritePackedUInt32(activeDotFlags);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(victimObjectId);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(activeDotFlags);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				victimObjectId = reader.ReadNetworkId();
				activeDotFlags = reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				victimObjectId = reader.ReadNetworkId();
			}
			if (((uint)num & 2u) != 0)
			{
				activeDotFlags = reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public struct InflictDotInfo
	{
		public GameObject victimObject;

		public GameObject attackerObject;

		public DotController.DotIndex dotIndex;

		public float duration;

		public float damageMultiplier;

		public uint? maxStacksFromAttacker;

		public float? totalDamage;

		public DotController.DotIndex? preUpgradeDotIndex;
	}
	[RequireComponent(typeof(NetworkIdentity))]
	public sealed class DummyPingableInteraction : MonoBehaviour, IInteractable, IDisplayNameProvider
	{
		public string displayNameToken = "DUMMYINTERACTION_NAME";

		public string contextToken = "DUMMYINTERACTION_CONTEXT";

		public Interactability interactability = Interactability.ConditionsNotMet;

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextToken);
		}

		public Interactability GetInteractability(Interactor activator)
		{
			return interactability;
		}

		public void OnInteractionBegin(Interactor activator)
		{
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return true;
		}

		public void OnEnable()
		{
			InstanceTracker.Add(this);
		}

		public void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			return interactability != Interactability.Disabled;
		}

		public bool ShouldProximityHighlight()
		{
			return false;
		}
	}
	[DisallowMultipleComponent]
	public class EffectComponent : MonoBehaviour
	{
		[HideInInspector]
		[Tooltip("This is assigned to the prefab automatically by EffectCatalog at runtime. Do not set this value manually.")]
		public EffectIndex effectIndex = EffectIndex.Invalid;

		[NonSerialized]
		public EffectData effectData;

		[Tooltip("Positions the effect at the transform referenced by the effect data if available.")]
		public bool positionAtReferencedTransform;

		[Tooltip("Parents the effect to the transform object referenced by the effect data if available.")]
		public bool parentToReferencedTransform;

		[Tooltip("Indicates that this is a special effect that won't use effectdata (mostly used to hide errors and warnings for specific effects that cannot be created with SpawnEffect)")]
		public bool noEffectData;

		[Tooltip("Causes this object to adopt the scale received in the effectdata.")]
		public bool applyScale;

		[Tooltip("The sound to play whenever this effect is dispatched, regardless of whether or not it actually ends up spawning.")]
		public string soundName;

		[Tooltip("Ignore Z scale when adopting scale values from effectdata.")]
		public bool disregardZScale;

		private bool didResolveReferencedObject;

		private GameObject referencedObject;

		private bool didResolveReferencedChildTransform;

		private Transform referencedChildTransform;

		private bool didResolveReferencedHurtBox;

		private GameObject referencedHurtBoxGameObject;

		public void Reset()
		{
			if (noEffectData || effectData == null)
			{
				return;
			}
			Transform transform = null;
			if (positionAtReferencedTransform | parentToReferencedTransform)
			{
				transform = effectData.ResolveChildLocatorTransformReference();
			}
			if ((bool)transform)
			{
				if (positionAtReferencedTransform)
				{
					base.transform.position = transform.position;
					base.transform.rotation = transform.rotation;
				}
				if (parentToReferencedTransform)
				{
					base.transform.SetParent(transform, worldPositionStays: true);
				}
			}
			if (applyScale)
			{
				float scale = effectData.scale;
				base.transform.localScale = new UnityEngine.Vector3(scale, scale, scale);
			}
		}

		private void Start()
		{
			if (effectData == null)
			{
				UnityEngine.Debug.LogErrorFormat(base.gameObject, "Object {0} should not be instantiated by means other than EffectManager.SpawnEffect. This WILL result in an NRE!!! Use EffectManager.SpawnEffect or don't use EffectComponent!!!!!", base.gameObject);
			}
			Reset();
		}

		[ContextMenu("Attempt to Upgrade Sfx Setup")]
		private void AttemptToUpgradeSfxSetup()
		{
			AkEvent[] components = GetComponents<AkEvent>();
			int num = 1281810935;
			if (components.Length == 1 && components[0].triggerList.Count == 1 && components[0].triggerList[0] == num)
			{
				string objectName = components[0].data.WwiseObjectReference.ObjectName;
				soundName = objectName;
				UnityEngine.Object.DestroyImmediate(components[0]);
				UnityEngine.Object.DestroyImmediate(GetComponent<AkGameObj>());
				Rigidbody component = GetComponent<Rigidbody>();
				if (component.isKinematic)
				{
					UnityEngine.Object.DestroyImmediate(component);
				}
				EditorUtil.SetDirty(this);
				EditorUtil.SetDirty(base.gameObject);
			}
		}

		private void OnValidate()
		{
			if (!Application.isPlaying && effectIndex != EffectIndex.Invalid)
			{
				effectIndex = EffectIndex.Invalid;
			}
			if (Application.isPlaying)
			{
				return;
			}
			bool num = GetComponent<AkGameObj>();
			bool flag = GetComponent<OrbEffect>();
			if (num && !flag)
			{
				AkEvent[] components = GetComponents<AkEvent>();
				int item = 1281810935;
				if (components.Length == 1 && components[0].triggerList.Contains(item))
				{
					UnityEngine.Debug.LogWarningFormat(base.gameObject, "Effect {0} has an attached AkGameObj. You probably want to use the soundName field of its EffectComponent instead.", Util.GetGameObjectHierarchyName(base.gameObject));
				}
			}
		}

		public GameObject GetReferencedObject()
		{
			if (!didResolveReferencedObject)
			{
				referencedObject = effectData.ResolveNetworkedObjectReference();
				didResolveReferencedObject = true;
			}
			return referencedObject;
		}

		public Transform GetReferencedChildTransform()
		{
			if (!didResolveReferencedChildTransform)
			{
				referencedChildTransform = effectData.ResolveChildLocatorTransformReference();
				didResolveReferencedChildTransform = true;
			}
			return referencedChildTransform;
		}

		public GameObject GetReferencedHurtBoxGameObject()
		{
			if (!didResolveReferencedHurtBox)
			{
				referencedHurtBoxGameObject = effectData.ResolveHurtBoxReference();
				didResolveReferencedHurtBox = true;
			}
			return referencedHurtBoxGameObject;
		}
	}
	public class ElementalRingController : MonoBehaviour
	{
		public GameObject elementalRingAvailableObject;

		private CharacterBody characterBody;

		private void Start()
		{
			CharacterModel componentInParent = GetComponentInParent<CharacterModel>();
			if ((bool)componentInParent)
			{
				characterBody = componentInParent.body;
			}
		}

		private void FixedUpdate()
		{
			if ((bool)characterBody)
			{
				bool flag = characterBody.HasBuff(RoR2Content.Buffs.ElementalRingsReady);
				if (flag != elementalRingAvailableObject.activeSelf)
				{
					elementalRingAvailableObject.SetActive(flag);
				}
			}
		}
	}
	public class EnableOnMecanimFloat : MonoBehaviour
	{
		public Animator animator;

		[Tooltip("The name of the mecanim variable to compare against")]
		public string animatorString;

		[Tooltip("The minimum value at which the objects are enabled")]
		public float minFloatValue;

		[Tooltip("The maximum value at which the objects are enabled")]
		public float maxFloatValue;

		public GameObject[] objectsToEnable;

		public GameObject[] objectsToDisable;

		private bool wasWithinRange;

		private void Update()
		{
			if (!animator)
			{
				return;
			}
			float @float = animator.GetFloat(animatorString);
			bool flag = Mathf.Clamp(@float, minFloatValue, maxFloatValue) == @float;
			if (flag != wasWithinRange)
			{
				GameObject[] array = objectsToEnable;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(flag);
				}
				array = objectsToDisable;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(!flag);
				}
				wasWithinRange = flag;
			}
		}
	}
	public class EnableWithPhase : MonoBehaviour
	{
		[Serializable]
		public struct PhaseInfo
		{
			public int minimumPhaseThreshold;

			public int maximumPhaseThreshold;

			public GameObject[] gameObjectsToEnable;
		}

		public PhaseInfo[] phaseInfos;

		private void FixedUpdate()
		{
			if (!PhaseCounter.instance)
			{
				return;
			}
			int phase = PhaseCounter.instance.phase;
			for (int i = 0; i < phaseInfos.Length; i++)
			{
				bool active = true;
				PhaseInfo phaseInfo = phaseInfos[i];
				if (phaseInfo.minimumPhaseThreshold > phase || phaseInfo.maximumPhaseThreshold < phase)
				{
					active = false;
				}
				GameObject[] gameObjectsToEnable = phaseInfo.gameObjectsToEnable;
				for (int j = 0; j < gameObjectsToEnable.Length; j++)
				{
					gameObjectsToEnable[j].SetActive(active);
				}
			}
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	[RequireComponent(typeof(Inventory))]
	public class EnemyInfoPanelInventoryProvider : MonoBehaviour
	{
		private static bool isDirty;

		public Inventory inventory { get; private set; }

		public TeamFilter teamFilter { get; private set; }

		public static event Action onInventoriesChanged;

		private void Awake()
		{
			inventory = GetComponent<Inventory>();
			teamFilter = GetComponent<TeamFilter>();
			inventory.onInventoryChanged += OnInventoryChanged;
		}

		private void OnInventoryChanged()
		{
			MarkAsDirty();
		}

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			MarkAsDirty();
		}

		private void OnDisable()
		{
			MarkAsDirty();
			InstanceTracker.Remove(this);
		}

		private void MarkAsDirty()
		{
			if (!isDirty)
			{
				isDirty = true;
				RoR2Application.onNextUpdate += Refresh;
			}
		}

		private void Refresh()
		{
			EnemyInfoPanelInventoryProvider.onInventoriesChanged?.Invoke();
			isDirty = false;
		}
	}
	public class EngiMineAnimator : MonoBehaviour
	{
		private Transform projectileTransform;

		public Animator animator;

		private EntityStateMachine armingStateMachine;

		private void Start()
		{
			ProjectileGhostController component = GetComponent<ProjectileGhostController>();
			if ((bool)component)
			{
				projectileTransform = component.authorityTransform;
				if ((bool)projectileTransform)
				{
					armingStateMachine = EntityStateMachine.FindByCustomName(projectileTransform.gameObject, "Arming");
				}
			}
		}

		private bool IsArmed()
		{
			return ((armingStateMachine?.state as BaseMineArmingState)?.damageScale ?? 0f) > 1f;
		}

		private void Update()
		{
			if (IsArmed())
			{
				animator.SetTrigger("Arming");
			}
		}
	}
	[DisallowMultipleComponent]
	public class EntityLocator : MonoBehaviour
	{
		[Tooltip("The root gameobject of the entity.")]
		public GameObject entity;

		[SerializeField]
		private int entityZoneIndex;

		public int EntityZoneIndex => entityZoneIndex;

		public static bool HasEntityLocator(GameObject gameObject, out EntityLocator foundLocator)
		{
			if (gameObject == null)
			{
				foundLocator = null;
				return false;
			}
			foundLocator = gameObject.GetComponent<EntityLocator>();
			if (!foundLocator)
			{
				return false;
			}
			return true;
		}

		public static GameObject GetEntity(GameObject gameObject)
		{
			if (gameObject == null)
			{
				return null;
			}
			EntityLocator component = gameObject.GetComponent<EntityLocator>();
			if (!component)
			{
				return null;
			}
			return component.entity;
		}
	}
	public class EntityStateMachine : MonoBehaviour, IManagedMonoBehaviour
	{
		public struct CommonComponentCache
		{
			public readonly Transform transform;

			public readonly CharacterBody characterBody;

			public readonly CharacterMotor characterMotor;

			public readonly CharacterDirection characterDirection;

			public readonly Rigidbody rigidbody;

			public readonly RigidbodyMotor rigidbodyMotor;

			public readonly RigidbodyDirection rigidbodyDirection;

			public readonly RailMotor railMotor;

			public readonly ModelLocator modelLocator;

			public readonly InputBankTest inputBank;

			public readonly TeamComponent teamComponent;

			public readonly HealthComponent healthComponent;

			public readonly SkillLocator skillLocator;

			public readonly CharacterEmoteDefinitions characterEmoteDefinitions;

			public readonly CameraTargetParams cameraTargetParams;

			public readonly SfxLocator sfxLocator;

			public readonly BodyAnimatorSmoothingParameters bodyAnimatorSmoothingParameters;

			public readonly ProjectileController projectileController;

			public CommonComponentCache(GameObject gameObject)
			{
				transform = gameObject.transform;
				characterBody = gameObject.GetComponent<CharacterBody>();
				characterMotor = gameObject.GetComponent<CharacterMotor>();
				characterDirection = gameObject.GetComponent<CharacterDirection>();
				rigidbody = gameObject.GetComponent<Rigidbody>();
				rigidbodyMotor = gameObject.GetComponent<RigidbodyMotor>();
				rigidbodyDirection = gameObject.GetComponent<RigidbodyDirection>();
				railMotor = gameObject.GetComponent<RailMotor>();
				modelLocator = gameObject.GetComponent<ModelLocator>();
				inputBank = gameObject.GetComponent<InputBankTest>();
				teamComponent = gameObject.GetComponent<TeamComponent>();
				healthComponent = gameObject.GetComponent<HealthComponent>();
				skillLocator = gameObject.GetComponent<SkillLocator>();
				characterEmoteDefinitions = gameObject.GetComponent<CharacterEmoteDefinitions>();
				cameraTargetParams = gameObject.GetComponent<CameraTargetParams>();
				sfxLocator = gameObject.GetComponent<SfxLocator>();
				bodyAnimatorSmoothingParameters = gameObject.GetComponent<BodyAnimatorSmoothingParameters>();
				projectileController = gameObject.GetComponent<ProjectileController>();
			}
		}

		public delegate void ModifyNextStateDelegate(EntityStateMachine entityStateMachine, ref EntityState newNextState);

		private EntityState nextState;

		[Tooltip("The name of this state machine.")]
		public string customName;

		[Tooltip("The type of the state to enter when this component is first activated.")]
		public SerializableEntityStateType initialStateType = new SerializableEntityStateType(typeof(TestState1));

		[Tooltip("The preferred main state of this state machine.")]
		public SerializableEntityStateType mainStateType;

		public CommonComponentCache commonComponents;

		[NonSerialized]
		public int networkIndex = -1;

		[NonSerialized]
		public bool AllowStartWithoutNetworker;

		[NonSerialized]
		public bool ShouldStateTransitionOnUpdate;

		public ModifyNextStateDelegate nextStateModifier;

		public bool debug;

		public EntityState state { get; private set; }

		public NetworkStateMachine networker { get; set; }

		public NetworkIdentity networkIdentity { get; set; }

		public bool AlwaysUpdate => false;

		public bool destroying { get; private set; }

		public void SetNextState(EntityState newNextState)
		{
			nextStateModifier?.Invoke(this, ref newNextState);
			nextState = newNextState;
		}

		public void SetNextStateToMain()
		{
			SetNextState(EntityStateCatalog.InstantiateState(ref mainStateType));
		}

		public bool CanInterruptState(InterruptPriority interruptPriority)
		{
			return (nextState ?? state).GetMinimumInterruptPriority() <= interruptPriority;
		}

		public bool SetInterruptState(EntityState newNextState, InterruptPriority interruptPriority)
		{
			if (CanInterruptState(interruptPriority))
			{
				_ = debug;
				SetNextState(newNextState);
				return true;
			}
			return false;
		}

		public bool HasPendingState()
		{
			return nextState != null;
		}

		public bool IsInMainState()
		{
			if (state != null)
			{
				return state.GetType() == mainStateType.stateType;
			}
			return false;
		}

		public bool IsInInitialState()
		{
			if (state != null)
			{
				return state.GetType() == initialStateType.stateType;
			}
			return false;
		}

		public void SetState([NotNull] EntityState newState)
		{
			nextState = null;
			newState.outer = this;
			if (state == null)
			{
				UnityEngine.Debug.LogErrorFormat("State machine {0} on object {1} does not have a state!", customName, base.gameObject);
			}
			state.ModifyNextState(newState);
			state.OnExit();
			_ = debug;
			state = newState;
			state.OnEnter();
			if (networkIndex != -1)
			{
				if (!networker)
				{
					UnityEngine.Debug.LogErrorFormat("State machine {0} on object {1} does not have a networker assigned!", customName, base.gameObject);
				}
				networker.SendSetEntityState(networkIndex);
			}
		}

		private void Awake()
		{
			if (!networker)
			{
				networker = GetComponent<NetworkStateMachine>();
			}
			if (!networkIdentity)
			{
				networkIdentity = GetComponent<NetworkIdentity>();
			}
			commonComponents = new CommonComponentCache(base.gameObject);
			state = new Uninitialized();
			state.outer = this;
		}

		private void Start()
		{
			if (nextState != null && (AllowStartWithoutNetworker || ((bool)networker && !networker.hasAuthority)))
			{
				SetState(nextState);
				return;
			}
			Type stateType = initialStateType.stateType;
			if (state is Uninitialized && stateType != null && stateType.IsSubclassOf(typeof(EntityState)))
			{
				SetState(EntityStateCatalog.InstantiateState(stateType));
			}
		}

		public void Update()
		{
			ManagedUpdate();
		}

		public void FixedUpdate()
		{
			ManagedFixedUpdate(Time.deltaTime);
		}

		public void ManagedUpdate()
		{
			state.Update();
			if (ShouldStateTransitionOnUpdate)
			{
				TryStateTransition();
			}
		}

		public void ManagedFixedUpdate(float deltaTime)
		{
			if (!destroying)
			{
				if (!ShouldStateTransitionOnUpdate)
				{
					TryStateTransition();
				}
				state.FixedUpdate();
			}
		}

		private void TryStateTransition()
		{
			if (nextState != null)
			{
				SetState(nextState);
			}
		}

		private void OnDestroy()
		{
			destroying = true;
			if (state != null)
			{
				state.OnExit();
				state = null;
			}
		}

		private void OnValidate()
		{
			if (!(mainStateType.stateType == null))
			{
				return;
			}
			if (customName == "Body")
			{
				if ((bool)GetComponent<CharacterMotor>())
				{
					mainStateType = new SerializableEntityStateType(typeof(GenericCharacterMain));
				}
				else if ((bool)GetComponent<RigidbodyMotor>())
				{
					mainStateType = new SerializableEntityStateType(typeof(FlyState));
				}
			}
			else if (customName == "Weapon")
			{
				mainStateType = new SerializableEntityStateType(typeof(EntityStates.Idle));
			}
			else if (customName == "AI")
			{
				BaseAI component = GetComponent<BaseAI>();
				if ((bool)component)
				{
					mainStateType = component.scanState;
				}
			}
		}

		public static EntityStateMachine FindByCustomName(GameObject gameObject, string customName)
		{
			List<EntityStateMachine> gameObjectComponents = GetComponentsCache<EntityStateMachine>.GetGameObjectComponents(gameObject);
			EntityStateMachine result = null;
			int i = 0;
			for (int count = gameObjectComponents.Count; i < count; i++)
			{
				if (string.CompareOrdinal(customName, gameObjectComponents[i].customName) == 0)
				{
					result = gameObjectComponents[i];
					break;
				}
			}
			GetComponentsCache<EntityStateMachine>.ReturnBuffer(gameObjectComponents);
			return result;
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class EquipmentSlot : NetworkBehaviour
	{
		private struct UserTargetInfo
		{
			public readonly HurtBox hurtBox;

			public readonly GameObject rootObject;

			public readonly GenericPickupController pickupController;

			public readonly Transform transformToIndicateAt;

			public UserTargetInfo(HurtBox source)
			{
				hurtBox = source;
				rootObject = (hurtBox ? hurtBox.healthComponent.gameObject : null);
				pickupController = null;
				transformToIndicateAt = (hurtBox ? hurtBox.transform : null);
			}

			public UserTargetInfo(GenericPickupController source)
			{
				pickupController = source;
				hurtBox = null;
				rootObject = (pickupController ? pickupController.gameObject : null);
				transformToIndicateAt = (pickupController ? pickupController.pickupDisplay.transform : null);
			}
		}

		private Inventory inventory;

		private Run.FixedTimeStamp _rechargeTime;

		private bool hasEffectiveAuthority;

		private Xoroshiro128Plus rng;

		private HealthComponent healthComponent;

		private InputBankTest inputBank;

		private TeamComponent teamComponent;

		private const float fullCritDuration = 8f;

		private static readonly float tonicBuffDuration;

		public static string equipmentActivateString;

		private float missileTimer;

		private float bfgChargeTimer;

		private float subcooldownTimer;

		private const float missileInterval = 0.125f;

		private int remainingMissiles;

		private HealingFollowerController passiveHealingFollower;

		private GameObject goldgatControllerObject;

		private static int activeParamHash;

		private static int activeDurationParamHash;

		private static int activeStopwatchParamHash;

		private Indicator targetIndicator;

		private BullseyeSearch targetFinder = new BullseyeSearch();

		private UserTargetInfo currentTarget;

		private PickupSearch pickupSearch;

		private Transform sproutSpawnTransform;

		private GameObject playerRespawnEffectPrefab;

		private bool sproutIsSpawned;

		private GameObject sprout;

		private static int kRpcRpcOnClientEquipmentActivationRecieved;

		private static int kCmdCmdExecuteIfReady;

		private static int kCmdCmdOnEquipmentExecuted;

		public byte activeEquipmentSlot { get; private set; }

		public EquipmentIndex equipmentIndex { get; private set; }

		public int stock { get; private set; }

		public int maxStock { get; private set; }

		private bool equipmentDisabled
		{
			get
			{
				if (!inventory)
				{
					return false;
				}
				return inventory.GetEquipmentDisabled();
			}
		}

		public CharacterBody characterBody { get; private set; }

		public float cooldownTimer => _rechargeTime.timeUntil;

		public static event Action<EquipmentSlot, EquipmentIndex> onServerEquipmentActivated;

		public override void OnStartServer()
		{
			base.OnStartServer();
			UpdateAuthority();
		}

		public override void OnStartAuthority()
		{
			base.OnStartAuthority();
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			base.OnStopAuthority();
			UpdateAuthority();
		}

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
		}

		private void UpdateInventory()
		{
			inventory = characterBody.inventory;
			if ((bool)inventory)
			{
				activeEquipmentSlot = inventory.activeEquipmentSlot;
				equipmentIndex = inventory.GetEquipmentIndex();
				stock = inventory.GetEquipment(inventory.activeEquipmentSlot).charges;
				maxStock = inventory.GetActiveEquipmentMaxCharges();
				_rechargeTime = inventory.GetEquipment(inventory.activeEquipmentSlot).chargeFinishTime;
			}
			else
			{
				activeEquipmentSlot = 0;
				equipmentIndex = EquipmentIndex.None;
				stock = 0;
				maxStock = 0;
				_rechargeTime = Run.FixedTimeStamp.positiveInfinity;
			}
		}

		[Server]
		private void UpdateGoldGat()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.EquipmentSlot::UpdateGoldGat()' called on client");
				return;
			}
			bool flag = equipmentIndex == RoR2Content.Equipment.GoldGat.equipmentIndex;
			if (flag != (bool)goldgatControllerObject)
			{
				if (flag)
				{
					goldgatControllerObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/GoldGatController"));
					goldgatControllerObject.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.gameObject);
				}
				else
				{
					UnityEngine.Object.Destroy(goldgatControllerObject);
				}
			}
		}

		public Transform FindActiveEquipmentDisplay()
		{
			ModelLocator component = GetComponent<ModelLocator>();
			if ((bool)component)
			{
				Transform modelTransform = component.modelTransform;
				if ((bool)modelTransform)
				{
					CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
					if ((bool)component2)
					{
						List<GameObject> equipmentDisplayObjects = component2.GetEquipmentDisplayObjects(equipmentIndex);
						if (equipmentDisplayObjects.Count > 0)
						{
							return equipmentDisplayObjects[0].transform;
						}
					}
				}
			}
			return null;
		}

		[ClientRpc]
		private void RpcOnClientEquipmentActivationRecieved()
		{
			Util.PlaySound(equipmentActivateString, base.gameObject);
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
			if (equipmentDef == RoR2Content.Equipment.DroneBackup)
			{
				Util.PlaySound("Play_item_use_radio", base.gameObject);
			}
			else if (equipmentDef == RoR2Content.Equipment.BFG)
			{
				Transform transform = FindActiveEquipmentDisplay();
				if ((bool)transform)
				{
					Animator componentInChildren = transform.GetComponentInChildren<Animator>();
					if ((bool)componentInChildren)
					{
						componentInChildren.SetTrigger("Fire");
					}
				}
			}
			else if (equipmentDef == RoR2Content.Equipment.Blackhole)
			{
				Transform transform2 = FindActiveEquipmentDisplay();
				if ((bool)transform2)
				{
					GravCubeController component = transform2.GetComponent<GravCubeController>();
					if ((bool)component)
					{
						component.ActivateCube(9f);
					}
				}
			}
			else if (equipmentDef == RoR2Content.Equipment.CritOnUse)
			{
				Transform transform3 = FindActiveEquipmentDisplay();
				if ((bool)transform3)
				{
					Animator componentInChildren2 = transform3.GetComponentInChildren<Animator>();
					if ((bool)componentInChildren2)
					{
						componentInChildren2.SetBool(activeParamHash, value: true);
						componentInChildren2.SetFloat(activeDurationParamHash, 8f);
						componentInChildren2.SetFloat(activeStopwatchParamHash, 0f);
					}
				}
			}
			else if (equipmentDef == RoR2Content.Equipment.GainArmor)
			{
				Util.PlaySound("Play_item_use_gainArmor", base.gameObject);
			}
		}

		private void Start()
		{
			characterBody = GetComponent<CharacterBody>();
			healthComponent = GetComponent<HealthComponent>();
			inputBank = GetComponent<InputBankTest>();
			teamComponent = GetComponent<TeamComponent>();
			targetIndicator = new Indicator(base.gameObject, null);
			rng = new Xoroshiro128Plus(Run.instance.seed ^ (ulong)Run.instance.stageClearCount);
		}

		private void OnDestroy()
		{
			if (targetIndicator != null)
			{
				targetIndicator.active = false;
			}
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.fixedDeltaTime);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			UpdateInventory();
			if (NetworkServer.active && !equipmentDisabled)
			{
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
				subcooldownTimer -= deltaTime;
				if (missileTimer > 0f)
				{
					missileTimer = Mathf.Max(missileTimer - deltaTime, 0f);
				}
				if (missileTimer == 0f && remainingMissiles > 0)
				{
					remainingMissiles--;
					missileTimer = 0.125f;
					FireMissile();
				}
				UpdateGoldGat();
				if (bfgChargeTimer > 0f)
				{
					bfgChargeTimer -= deltaTime;
					if (bfgChargeTimer < 0f)
					{
						_ = base.transform.position;
						Ray aimRay = GetAimRay();
						Transform transform = FindActiveEquipmentDisplay();
						if ((bool)transform)
						{
							ChildLocator componentInChildren = transform.GetComponentInChildren<ChildLocator>();
							if ((bool)componentInChildren)
							{
								Transform transform2 = componentInChildren.FindChild("Muzzle");
								if ((bool)transform2)
								{
									aimRay.origin = transform2.position;
								}
							}
						}
						healthComponent.TakeDamageForce(aimRay.direction * -1500f, alwaysApply: true);
						ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/BeamSphere"), aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, characterBody.damage * 2f, 0f, Util.CheckRoll(characterBody.crit, characterBody.master), DamageColorIndex.Item);
						bfgChargeTimer = 0f;
					}
				}
				if (equipmentDef == RoR2Content.Equipment.PassiveHealing != (bool)passiveHealingFollower)
				{
					if (!passiveHealingFollower)
					{
						GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/HealingFollower"), base.transform.position, UnityEngine.Quaternion.identity);
						passiveHealingFollower = gameObject.GetComponent<HealingFollowerController>();
						passiveHealingFollower.NetworkownerBodyObject = base.gameObject;
						NetworkServer.Spawn(gameObject);
					}
					else
					{
						UnityEngine.Object.Destroy(passiveHealingFollower.gameObject);
						passiveHealingFollower = null;
					}
				}
			}
			bool num = inputBank.activateEquipment.justPressed || (inventory?.GetItemCount(RoR2Content.Items.AutoCastEquipment) ?? 0) > 0;
			bool isEquipmentActivationAllowed = characterBody.isEquipmentActivationAllowed;
			if (num && isEquipmentActivationAllowed && hasEffectiveAuthority)
			{
				if (NetworkServer.active)
				{
					ExecuteIfReady();
				}
				else
				{
					CallCmdExecuteIfReady();
				}
			}
		}

		[Command]
		private void CmdExecuteIfReady()
		{
			ExecuteIfReady();
		}

		[Server]
		public bool ExecuteIfReady()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.EquipmentSlot::ExecuteIfReady()' called on client");
				return false;
			}
			if (equipmentIndex != EquipmentIndex.None && stock > 0)
			{
				Execute();
				return true;
			}
			return false;
		}

		[Server]
		private void Execute()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.EquipmentSlot::Execute()' called on client");
				return;
			}
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
			if ((object)equipmentDef != null && subcooldownTimer <= 0f && PerformEquipmentAction(equipmentDef))
			{
				OnEquipmentExecuted();
			}
		}

		[Command]
		public void CmdOnEquipmentExecuted()
		{
			OnEquipmentExecuted();
		}

		[Server]
		public void OnEquipmentExecuted()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.EquipmentSlot::OnEquipmentExecuted()' called on client");
				return;
			}
			EquipmentIndex arg = this.equipmentIndex;
			inventory.DeductEquipmentCharges(activeEquipmentSlot, 1);
			UpdateInventory();
			CallRpcOnClientEquipmentActivationRecieved();
			EquipmentSlot.onServerEquipmentActivated?.Invoke(this, arg);
			if (!characterBody || !inventory)
			{
				return;
			}
			int itemCount = inventory.GetItemCount(RoR2Content.Items.EnergizedOnEquipmentUse);
			if (itemCount > 0)
			{
				characterBody.AddTimedBuff(RoR2Content.Buffs.Energized, 8 + 4 * (itemCount - 1));
			}
			int itemCount2 = inventory.GetItemCount(DLC1Content.Items.RandomEquipmentTrigger);
			if (itemCount2 <= 0 || EquipmentCatalog.randomTriggerEquipmentList.Count <= 0)
			{
				return;
			}
			List<EquipmentIndex> list = new List<EquipmentIndex>(EquipmentCatalog.randomTriggerEquipmentList);
			if (inventory.currentEquipmentIndex != EquipmentIndex.None)
			{
				list.Remove(inventory.currentEquipmentIndex);
			}
			Util.ShuffleList(list, rng);
			if (inventory.currentEquipmentIndex != EquipmentIndex.None)
			{
				list.Add(inventory.currentEquipmentIndex);
			}
			int num = 0;
			bool flag = false;
			bool flag2 = false;
			for (int i = 0; i < itemCount2; i++)
			{
				if (flag2)
				{
					break;
				}
				EquipmentIndex equipmentIndex = EquipmentIndex.None;
				do
				{
					if (num >= list.Count)
					{
						if (!flag)
						{
							flag2 = true;
							break;
						}
						flag = false;
						num %= list.Count;
					}
					equipmentIndex = list[num];
					num++;
				}
				while (!PerformEquipmentAction(EquipmentCatalog.GetEquipmentDef(equipmentIndex)));
				if (equipmentIndex == RoR2Content.Equipment.BFG.equipmentIndex)
				{
					ModelLocator component = GetComponent<ModelLocator>();
					if ((bool)component)
					{
						Transform modelTransform = component.modelTransform;
						if ((bool)modelTransform)
						{
							CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
							if ((bool)component2)
							{
								List<GameObject> itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.RandomEquipmentTrigger.itemIndex);
								if (itemDisplayObjects.Count > 0)
								{
									UnityEngine.Object.Instantiate(Addressables.LoadAssetAsync<GameObject>("RoR2/Base/BFG/ChargeBFG.prefab").WaitForCompletion(), itemDisplayObjects[0].transform);
								}
							}
						}
					}
				}
				flag = true;
			}
			EffectData effectData = new EffectData();
			effectData.origin = characterBody.corePosition;
			effectData.SetNetworkedObjectReference(base.gameObject);
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/RandomEquipmentTriggerProcEffect"), effectData, transmit: true);
		}

		private void FireMissile()
		{
			GameObject projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/MissileProjectile");
			float num = 3f;
			bool isCrit = Util.CheckRoll(characterBody.crit, characterBody.master);
			MissileUtils.FireMissile(characterBody.corePosition, characterBody, default(ProcChainMask), null, characterBody.damage * num, isCrit, projectilePrefab, DamageColorIndex.Item, addMissileProc: false);
		}

		[Server]
		private bool PerformEquipmentAction(EquipmentDef equipmentDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.EquipmentSlot::PerformEquipmentAction(RoR2.EquipmentDef)' called on client");
				return false;
			}
			if (equipmentDisabled)
			{
				return false;
			}
			Func<bool> func = null;
			if (equipmentDef == RoR2Content.Equipment.CommandMissile)
			{
				func = FireCommandMissile;
			}
			else if (equipmentDef == RoR2Content.Equipment.Fruit)
			{
				func = FireFruit;
			}
			else if (equipmentDef == RoR2Content.Equipment.DroneBackup)
			{
				func = FireDroneBackup;
			}
			else if (equipmentDef == RoR2Content.Equipment.Meteor)
			{
				func = FireMeteor;
			}
			else if (equipmentDef == RoR2Content.Equipment.Blackhole)
			{
				func = FireBlackhole;
			}
			else if (equipmentDef == RoR2Content.Equipment.Saw)
			{
				func = FireSaw;
			}
			else if (equipmentDef == JunkContent.Equipment.OrbitalLaser)
			{
				func = FireOrbitalLaser;
			}
			else if (equipmentDef == JunkContent.Equipment.GhostGun)
			{
				func = FireGhostGun;
			}
			else if (equipmentDef == RoR2Content.Equipment.CritOnUse)
			{
				func = FireCritOnUse;
			}
			else if (equipmentDef == RoR2Content.Equipment.BFG)
			{
				func = FireBfg;
			}
			else if (equipmentDef == RoR2Content.Equipment.Jetpack)
			{
				func = FireJetpack;
			}
			else if (equipmentDef == RoR2Content.Equipment.Lightning)
			{
				func = FireLightning;
			}
			else if (equipmentDef == RoR2Content.Equipment.PassiveHealing)
			{
				func = FirePassiveHealing;
			}
			else if (equipmentDef == RoR2Content.Equipment.BurnNearby)
			{
				func = FireBurnNearby;
			}
			else if (equipmentDef == JunkContent.Equipment.SoulCorruptor)
			{
				func = FireSoulCorruptor;
			}
			else if (equipmentDef == RoR2Content.Equipment.Scanner)
			{
				func = FireScanner;
			}
			else if (equipmentDef == RoR2Content.Equipment.CrippleWard)
			{
				func = FireCrippleWard;
			}
			else if (equipmentDef == RoR2Content.Equipment.Gateway)
			{
				func = FireGateway;
			}
			else if (equipmentDef == RoR2Content.Equipment.Tonic)
			{
				func = FireTonic;
			}
			else if (equipmentDef == RoR2Content.Equipment.Cleanse)
			{
				func = FireCleanse;
			}
			else if (equipmentDef == RoR2Content.Equipment.FireBallDash)
			{
				func = FireFireBallDash;
			}
			else if (equipmentDef == RoR2Content.Equipment.Recycle)
			{
				func = FireRecycle;
			}
			else if (equipmentDef == RoR2Content.Equipment.GainArmor)
			{
				func = FireGainArmor;
			}
			else if (equipmentDef == RoR2Content.Equipment.LifestealOnHit)
			{
				func = FireLifeStealOnHit;
			}
			else if (equipmentDef == RoR2Content.Equipment.TeamWarCry)
			{
				func = FireTeamWarCry;
			}
			else if (equipmentDef == RoR2Content.Equipment.DeathProjectile)
			{
				func = FireDeathProjectile;
			}
			else if (equipmentDef == DLC1Content.Equipment.Molotov)
			{
				func = FireMolotov;
			}
			else if (equipmentDef == DLC1Content.Equipment.VendingMachine)
			{
				func = FireVendingMachine;
			}
			else if (equipmentDef == DLC1Content.Equipment.BossHunter)
			{
				func = FireBossHunter;
			}
			else if (equipmentDef == DLC1Content.Equipment.BossHunterConsumed)
			{
				func = FireBossHunterConsumed;
			}
			else if (equipmentDef == DLC1Content.Equipment.GummyClone)
			{
				func = FireGummyClone;
			}
			else if (equipmentDef == DLC1Content.Equipment.LunarPortalOnUse)
			{
				func = FireLunarPortalOnUse;
			}
			else if (equipmentDef == DLC2Content.Equipment.HealAndRevive)
			{
				func = FireHealAndRevive;
			}
			else if (equipmentDef == DLC2Content.Equipment.HealAndReviveConsumed)
			{
				func = FireSproutOfLife;
			}
			return func?.Invoke() ?? false;
		}

		private Ray GetAimRay()
		{
			Ray result = default(Ray);
			result.direction = inputBank.aimDirection;
			result.origin = inputBank.aimOrigin;
			return result;
		}

		[CanBeNull]
		[Server]
		private CharacterMaster SummonMaster([NotNull] GameObject masterPrefab, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterMaster RoR2.EquipmentSlot::SummonMaster(UnityEngine.GameObject,UnityEngine.Vector3,UnityEngine.Quaternion)' called on client");
				return null;
			}
			return new MasterSummon
			{
				masterPrefab = masterPrefab,
				position = position,
				rotation = rotation,
				summonerBodyObject = base.gameObject,
				ignoreTeamMemberLimit = false
			}.Perform();
		}

		private void ConfigureTargetFinderBase()
		{
			targetFinder.teamMaskFilter = TeamMask.allButNeutral;
			targetFinder.teamMaskFilter.RemoveTeam(teamComponent.teamIndex);
			targetFinder.sortMode = BullseyeSearch.SortMode.Angle;
			targetFinder.filterByLoS = true;
			float extraRaycastDistance;
			Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance);
			targetFinder.searchOrigin = ray.origin;
			targetFinder.searchDirection = ray.direction;
			targetFinder.maxAngleFilter = 10f;
			targetFinder.viewer = characterBody;
		}

		private void ConfigureTargetFinderForEnemies()
		{
			ConfigureTargetFinderBase();
			targetFinder.teamMaskFilter = TeamMask.GetUnprotectedTeams(teamComponent.teamIndex);
			targetFinder.RefreshCandidates();
			targetFinder.FilterOutGameObject(base.gameObject);
		}

		private void ConfigureTargetFinderForBossesWithRewards()
		{
			ConfigureTargetFinderBase();
			targetFinder.teamMaskFilter = TeamMask.GetUnprotectedTeams(teamComponent.teamIndex);
			targetFinder.RefreshCandidates();
			targetFinder.FilterOutGameObject(base.gameObject);
		}

		private void ConfigureTargetFinderForFriendlies()
		{
			ConfigureTargetFinderBase();
			targetFinder.teamMaskFilter = TeamMask.none;
			targetFinder.teamMaskFilter.AddTeam(teamComponent.teamIndex);
			targetFinder.RefreshCandidates();
			targetFinder.FilterOutGameObject(base.gameObject);
		}

		private void InvalidateCurrentTarget()
		{
			currentTarget = default(UserTargetInfo);
		}

		private void UpdateTargets(EquipmentIndex targetingEquipmentIndex, bool userShouldAnticipateTarget)
		{
			bool flag = targetingEquipmentIndex == DLC1Content.Equipment.BossHunter.equipmentIndex;
			bool flag2 = (targetingEquipmentIndex == RoR2Content.Equipment.Lightning.equipmentIndex || targetingEquipmentIndex == JunkContent.Equipment.SoulCorruptor.equipmentIndex || flag) && userShouldAnticipateTarget;
			bool flag3 = targetingEquipmentIndex == RoR2Content.Equipment.PassiveHealing.equipmentIndex && userShouldAnticipateTarget;
			bool num = flag2 || flag3;
			bool flag4 = targetingEquipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex;
			if (num)
			{
				if (flag2)
				{
					ConfigureTargetFinderForEnemies();
				}
				if (flag3)
				{
					ConfigureTargetFinderForFriendlies();
				}
				HurtBox source = null;
				if (flag)
				{
					foreach (HurtBox result in targetFinder.GetResults())
					{
						if ((bool)result && (bool)result.healthComponent && (bool)result.healthComponent.body)
						{
							DeathRewards component = result.healthComponent.body.gameObject.GetComponent<DeathRewards>();
							if ((bool)component && (bool)component.bossDropTable && !result.healthComponent.body.HasBuff(RoR2Content.Buffs.Immune))
							{
								source = result;
								break;
							}
						}
					}
				}
				else
				{
					source = targetFinder.GetResults().FirstOrDefault();
				}
				currentTarget = new UserTargetInfo(source);
			}
			else if (flag4)
			{
				currentTarget = new UserTargetInfo(FindPickupController(GetAimRay(), 10f, 30f, requireLoS: true, targetingEquipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex));
			}
			else
			{
				currentTarget = default(UserTargetInfo);
			}
			GenericPickupController pickupController = currentTarget.pickupController;
			bool flag5 = currentTarget.transformToIndicateAt;
			if (flag5)
			{
				if (targetingEquipmentIndex == RoR2Content.Equipment.Lightning.equipmentIndex)
				{
					targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/LightningIndicator");
				}
				else if (targetingEquipmentIndex == RoR2Content.Equipment.PassiveHealing.equipmentIndex)
				{
					targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/WoodSpriteIndicator");
				}
				else if (targetingEquipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex)
				{
					if (!pickupController.Recycled)
					{
						targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/RecyclerIndicator");
					}
					else
					{
						targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/RecyclerBadIndicator");
					}
				}
				else if (targetingEquipmentIndex == DLC1Content.Equipment.BossHunter.equipmentIndex)
				{
					targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/BossHunterIndicator");
				}
				else
				{
					targetIndicator.visualizerPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/LightningIndicator");
				}
			}
			targetIndicator.active = flag5;
			targetIndicator.targetTransform = (flag5 ? currentTarget.transformToIndicateAt : null);
		}

		private GenericPickupController FindPickupController(Ray aimRay, float maxAngle, float maxDistance, bool requireLoS, bool requireTransmutable)
		{
			if (pickupSearch == null)
			{
				pickupSearch = new PickupSearch();
			}
			aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out var extraRaycastDistance);
			pickupSearch.searchOrigin = aimRay.origin;
			pickupSearch.searchDirection = aimRay.direction;
			pickupSearch.minAngleFilter = 0f;
			pickupSearch.maxAngleFilter = maxAngle;
			pickupSearch.minDistanceFilter = 0f;
			pickupSearch.maxDistanceFilter = maxDistance + extraRaycastDistance;
			pickupSearch.filterByDistinctEntity = false;
			pickupSearch.filterByLoS = requireLoS;
			pickupSearch.sortMode = SortMode.DistanceAndAngle;
			pickupSearch.requireTransmutable = requireTransmutable;
			return pickupSearch.SearchCandidatesForSingleTarget(InstanceTracker.GetInstancesList<GenericPickupController>());
		}

		private void Update()
		{
			if (!equipmentDisabled)
			{
				UpdateTargets(equipmentIndex, stock > 0);
			}
		}

		private bool FireCommandMissile()
		{
			remainingMissiles += 12;
			return true;
		}

		private bool FireFruit()
		{
			if ((bool)healthComponent)
			{
				EffectData effectData = new EffectData();
				effectData.origin = base.transform.position;
				effectData.SetNetworkedObjectReference(base.gameObject);
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/FruitHealEffect"), effectData, transmit: true);
				healthComponent.HealFraction(0.5f, default(ProcChainMask));
			}
			return true;
		}

		private bool FireDroneBackup()
		{
			int sliceCount = 4;
			float num = 25f;
			if (NetworkServer.active)
			{
				float y = UnityEngine.Quaternion.LookRotation(GetAimRay().direction).eulerAngles.y;
				float num2 = 3f;
				foreach (float item in new DegreeSlices(sliceCount, 0.5f))
				{
					UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(-30f, y + item, 0f);
					UnityEngine.Quaternion rotation = UnityEngine.Quaternion.Euler(0f, y + item + 180f, 0f);
					UnityEngine.Vector3 position = base.transform.position + quaternion * (UnityEngine.Vector3.forward * num2);
					CharacterMaster characterMaster = SummonMaster(LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterMasters/DroneBackupMaster"), position, rotation);
					if ((bool)characterMaster)
					{
						characterMaster.gameObject.AddComponent<MasterSuicideOnTimer>().lifeTimer = num + UnityEngine.Random.Range(0f, 3f);
					}
				}
			}
			subcooldownTimer = 0.5f;
			return true;
		}

		private bool FireMeteor()
		{
			MeteorStormController component = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/MeteorStorm"), characterBody.corePosition, UnityEngine.Quaternion.identity).GetComponent<MeteorStormController>();
			component.owner = base.gameObject;
			component.ownerDamage = characterBody.damage;
			component.isCrit = Util.CheckRoll(characterBody.crit, characterBody.master);
			NetworkServer.Spawn(component.gameObject);
			return true;
		}

		private bool FireBlackhole()
		{
			UnityEngine.Vector3 position = base.transform.position;
			Ray aimRay = GetAimRay();
			ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/GravSphere"), position, Util.QuaternionSafeLookRotation(aimRay.direction), base.gameObject, 0f, 0f, crit: false);
			return true;
		}

		private bool FireSaw()
		{
			Ray aimRay = GetAimRay();
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.LookRotation(aimRay.direction);
			float num = 15f;
			FireSingleSaw(characterBody, aimRay.origin, quaternion * UnityEngine.Quaternion.Euler(0f, 0f - num, 0f));
			FireSingleSaw(characterBody, aimRay.origin, quaternion);
			FireSingleSaw(characterBody, aimRay.origin, quaternion * UnityEngine.Quaternion.Euler(0f, num, 0f));
			return true;
			void FireSingleSaw(CharacterBody firingCharacterBody, UnityEngine.Vector3 origin, UnityEngine.Quaternion rotation)
			{
				GameObject projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/Sawmerang");
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.crit = characterBody.RollCrit();
				fireProjectileInfo.damage = characterBody.damage;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.position = origin;
				fireProjectileInfo.rotation = rotation;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
		}

		private bool FireOrbitalLaser()
		{
			UnityEngine.Vector3 position = base.transform.position;
			if (Physics.Raycast(GetAimRay(), out var hitInfo, 900f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault))
			{
				position = hitInfo.point;
			}
			GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/OrbitalLaser"), position, UnityEngine.Quaternion.identity);
			obj.GetComponent<OrbitalLaserController>().ownerBody = characterBody;
			NetworkServer.Spawn(obj);
			return true;
		}

		private bool FireGhostGun()
		{
			GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/GhostGun"), base.transform.position, UnityEngine.Quaternion.identity);
			obj.GetComponent<GhostGunController>().owner = base.gameObject;
			NetworkServer.Spawn(obj);
			return true;
		}

		private bool FireCritOnUse()
		{
			characterBody.AddTimedBuff(RoR2Content.Buffs.FullCrit, 8f);
			return true;
		}

		private bool FireBfg()
		{
			bfgChargeTimer = 2f;
			subcooldownTimer = 2.2f;
			return true;
		}

		private bool FireJetpack()
		{
			JetpackController jetpackController = JetpackController.FindJetpackController(base.gameObject);
			if (!jetpackController)
			{
				UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/BodyAttachments/JetpackController")).GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.gameObject);
			}
			else
			{
				jetpackController.ResetTimer();
			}
			return true;
		}

		private bool FireLightning()
		{
			UpdateTargets(RoR2Content.Equipment.Lightning.equipmentIndex, userShouldAnticipateTarget: true);
			HurtBox hurtBox = currentTarget.hurtBox;
			if ((bool)hurtBox)
			{
				subcooldownTimer = 0.2f;
				OrbManager.instance.AddOrb(new LightningStrikeOrb
				{
					attacker = base.gameObject,
					damageColorIndex = DamageColorIndex.Item,
					damageValue = characterBody.damage * 30f,
					isCrit = Util.CheckRoll(characterBody.crit, characterBody.master),
					procChainMask = default(ProcChainMask),
					procCoefficient = 1f,
					target = hurtBox
				});
				InvalidateCurrentTarget();
				return true;
			}
			return false;
		}

		private bool FireBossHunter()
		{
			UpdateTargets(DLC1Content.Equipment.BossHunter.equipmentIndex, userShouldAnticipateTarget: true);
			HurtBox hurtBox = currentTarget.hurtBox;
			DeathRewards deathRewards = hurtBox?.healthComponent?.body?.gameObject?.GetComponent<DeathRewards>();
			if ((bool)hurtBox && (bool)deathRewards)
			{
				UnityEngine.Vector3 vector = (hurtBox.transform ? hurtBox.transform.position : UnityEngine.Vector3.zero);
				UnityEngine.Vector3 normalized = (vector - characterBody.corePosition).normalized;
				PickupDropletController.CreatePickupDroplet(deathRewards.bossDropTable.GenerateDrop(rng), vector, normalized * 15f);
				if ((bool)hurtBox?.healthComponent?.body?.master)
				{
					hurtBox.healthComponent.body.master.TrueKill(base.gameObject);
				}
				CharacterModel component = hurtBox.hurtBoxGroup.GetComponent<CharacterModel>();
				if ((bool)component)
				{
					TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(component.gameObject);
					temporaryOverlayInstance.duration = 0.1f;
					temporaryOverlayInstance.animateShaderAlpha = true;
					temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance.destroyComponentOnEnd = true;
					temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matHuntressFlashBright");
					temporaryOverlayInstance.AddToCharacterModel(component);
					TemporaryOverlayInstance temporaryOverlayInstance2 = TemporaryOverlayManager.AddOverlay(component.gameObject);
					temporaryOverlayInstance2.duration = 1.2f;
					temporaryOverlayInstance2.animateShaderAlpha = true;
					temporaryOverlayInstance2.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
					temporaryOverlayInstance2.destroyComponentOnEnd = true;
					temporaryOverlayInstance2.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matGhostEffect");
					temporaryOverlayInstance2.AddToCharacterModel(component);
				}
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.attacker = base.gameObject;
				damageInfo.force = -normalized * 2500f;
				healthComponent.TakeDamageForce(damageInfo, alwaysApply: true);
				GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/BossHunterKillEffect");
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(normalized, UnityEngine.Vector3.up);
				EffectManager.SpawnEffect(effectPrefab, new EffectData
				{
					origin = vector,
					rotation = rotation
				}, transmit: true);
				CharacterModel characterModel = base.gameObject.GetComponent<ModelLocator>()?.modelTransform?.GetComponent<CharacterModel>();
				if ((bool)characterModel)
				{
					foreach (GameObject equipmentDisplayObject in characterModel.GetEquipmentDisplayObjects(DLC1Content.Equipment.BossHunter.equipmentIndex))
					{
						if (equipmentDisplayObject.name.Contains("DisplayTricorn"))
						{
							EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/BossHunterHatEffect"), new EffectData
							{
								origin = equipmentDisplayObject.transform.position,
								rotation = equipmentDisplayObject.transform.rotation,
								scale = equipmentDisplayObject.transform.localScale.x
							}, transmit: true);
						}
						else
						{
							EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/BossHunterGunEffect"), new EffectData
							{
								origin = equipmentDisplayObject.transform.position,
								rotation = Util.QuaternionSafeLookRotation(vector - equipmentDisplayObject.transform.position, UnityEngine.Vector3.up),
								scale = equipmentDisplayObject.transform.localScale.x
							}, transmit: true);
						}
					}
				}
				if ((bool)characterBody?.inventory)
				{
					CharacterMasterNotificationQueue.SendTransformNotification(characterBody.master, characterBody.inventory.currentEquipmentIndex, DLC1Content.Equipment.BossHunterConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default);
					characterBody.inventory.SetEquipmentIndex(DLC1Content.Equipment.BossHunterConsumed.equipmentIndex);
				}
				InvalidateCurrentTarget();
				return true;
			}
			return false;
		}

		private bool FireBossHunterConsumed()
		{
			if ((bool)characterBody)
			{
				Chat.SendBroadcastChat(new Chat.BodyChatMessage
				{
					bodyObject = characterBody.gameObject,
					token = "EQUIPMENT_BOSSHUNTERCONSUMED_CHAT"
				});
				subcooldownTimer = 1f;
			}
			return true;
		}

		private bool FirePassiveHealing()
		{
			UpdateTargets(RoR2Content.Equipment.PassiveHealing.equipmentIndex, userShouldAnticipateTarget: true);
			CharacterBody characterBody = currentTarget.rootObject?.GetComponent<CharacterBody>() ?? this.characterBody;
			if ((bool)characterBody)
			{
				EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/WoodSpriteHeal"), characterBody.corePosition, UnityEngine.Vector3.up, transmit: true);
				characterBody.healthComponent?.HealFraction(0.1f, default(ProcChainMask));
			}
			if ((bool)passiveHealingFollower)
			{
				passiveHealingFollower.AssignNewTarget(currentTarget.rootObject);
				InvalidateCurrentTarget();
			}
			return true;
		}

		private bool FireBurnNearby()
		{
			if ((bool)characterBody)
			{
				characterBody.AddHelfireDuration(12f);
			}
			return true;
		}

		private bool FireSoulCorruptor()
		{
			UpdateTargets(JunkContent.Equipment.SoulCorruptor.equipmentIndex, userShouldAnticipateTarget: true);
			HurtBox hurtBox = currentTarget.hurtBox;
			if (!hurtBox)
			{
				return false;
			}
			if (!hurtBox.healthComponent || hurtBox.healthComponent.combinedHealthFraction > 0.25f)
			{
				return false;
			}
			Util.TryToCreateGhost(hurtBox.healthComponent.body, characterBody, 30);
			hurtBox.healthComponent.Suicide(base.gameObject);
			InvalidateCurrentTarget();
			return true;
		}

		private bool FireScanner()
		{
			NetworkServer.Spawn(UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/ChestScanner"), characterBody.corePosition, UnityEngine.Quaternion.identity));
			return true;
		}

		private bool FireCrippleWard()
		{
			characterBody.master.GetDeployableCount(DeployableSlot.PowerWard);
			Ray aimRay = GetAimRay();
			float maxDistance = 1000f;
			if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/CrippleWard"), hitInfo.point, Util.QuaternionSafeLookRotation(hitInfo.normal, UnityEngine.Vector3.forward));
				Deployable component = obj.GetComponent<Deployable>();
				characterBody.master.AddDeployable(component, DeployableSlot.CrippleWard);
				NetworkServer.Spawn(obj);
				return true;
			}
			return true;
		}

		private bool FireTonic()
		{
			characterBody.AddTimedBuff(RoR2Content.Buffs.TonicBuff, tonicBuffDuration);
			if (!Util.CheckRoll(80f, characterBody.master))
			{
				characterBody.pendingTonicAfflictionCount++;
			}
			return true;
		}

		private bool FireCleanse()
		{
			UnityEngine.Vector3 corePosition = characterBody.corePosition;
			EffectData effectData = new EffectData
			{
				origin = corePosition
			};
			effectData.SetHurtBoxReference(characterBody.mainHurtBox);
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/CleanseEffect"), effectData, transmit: true);
			Util.CleanseBody(characterBody, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: true, removeDots: true, removeStun: true, removeNearbyProjectiles: true);
			return true;
		}

		private bool FireFireBallDash()
		{
			Ray aimRay = GetAimRay();
			GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/FireballVehicle"), aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction));
			gameObject.GetComponent<VehicleSeat>().AssignPassenger(base.gameObject);
			NetworkUser networkUser = characterBody?.master?.playerCharacterMasterController?.networkUser;
			if ((bool)networkUser)
			{
				NetworkServer.SpawnWithClientAuthority(gameObject, networkUser.gameObject);
			}
			else
			{
				NetworkServer.Spawn(gameObject);
			}
			subcooldownTimer = 2f;
			return true;
		}

		private bool FireGainArmor()
		{
			characterBody.AddTimedBuff(RoR2Content.Buffs.ElephantArmorBoost, 5f);
			return true;
		}

		private bool FireRecycle()
		{
			UpdateTargets(RoR2Content.Equipment.Recycle.equipmentIndex, userShouldAnticipateTarget: false);
			GenericPickupController pickupController = currentTarget.pickupController;
			if ((bool)pickupController && !pickupController.Recycled)
			{
				PickupIndex initialPickupIndex = pickupController.pickupIndex;
				subcooldownTimer = 0.2f;
				PickupIndex[] array = (from pickupIndex in PickupTransmutationManager.GetAvailableGroupFromPickupIndex(pickupController.pickupIndex)
					where pickupIndex != initialPickupIndex
					select pickupIndex).ToArray();
				if (array == null)
				{
					return false;
				}
				if (array.Length == 0)
				{
					return false;
				}
				pickupController.NetworkpickupIndex = Run.instance.treasureRng.NextElementUniform(array);
				EffectManager.SimpleEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OmniEffect/OmniRecycleEffect"), pickupController.pickupDisplay.transform.position, UnityEngine.Quaternion.identity, transmit: true);
				pickupController.NetworkRecycled = true;
				InvalidateCurrentTarget();
				return true;
			}
			return false;
		}

		private bool FireGateway()
		{
			_ = characterBody.footPosition;
			Ray aimRay = GetAimRay();
			float num = 2f;
			float num2 = num * 2f;
			float maxDistance = 1000f;
			Rigidbody component = GetComponent<Rigidbody>();
			if (!component)
			{
				return false;
			}
			UnityEngine.Vector3 position = base.transform.position;
			if (Physics.Raycast(aimRay, out var hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				UnityEngine.Vector3 vector = hitInfo.point + hitInfo.normal * num;
				UnityEngine.Vector3 vector2 = vector - position;
				UnityEngine.Vector3 normalized = vector2.normalized;
				UnityEngine.Vector3 pointBPosition = vector;
				if (component.SweepTest(normalized, out var hitInfo2, vector2.magnitude))
				{
					if (hitInfo2.distance < num2)
					{
						return false;
					}
					pointBPosition = position + normalized * hitInfo2.distance;
				}
				GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/Zipline"));
				ZiplineController component2 = obj.GetComponent<ZiplineController>();
				component2.SetPointAPosition(position + normalized * num);
				component2.SetPointBPosition(pointBPosition);
				obj.AddComponent<DestroyOnTimer>().duration = 30f;
				NetworkServer.Spawn(obj);
				return true;
			}
			return false;
		}

		private bool FireLifeStealOnHit()
		{
			EffectData effectData = new EffectData
			{
				origin = characterBody.corePosition
			};
			effectData.SetHurtBoxReference(characterBody.gameObject);
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/LifeStealOnHitActivation"), effectData, transmit: false);
			characterBody.AddTimedBuff(RoR2Content.Buffs.LifeSteal, 8f);
			return true;
		}

		private bool FireTeamWarCry()
		{
			Util.PlaySound("Play_teamWarCry_activate", characterBody.gameObject);
			UnityEngine.Vector3 corePosition = characterBody.corePosition;
			EffectData effectData = new EffectData
			{
				origin = corePosition
			};
			effectData.SetNetworkedObjectReference(characterBody.gameObject);
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/TeamWarCryActivation"), effectData, transmit: true);
			characterBody.AddTimedBuff(RoR2Content.Buffs.TeamWarCry, 7f);
			TeamComponent[] array = UnityEngine.Object.FindObjectsOfType<TeamComponent>();
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].teamIndex == teamComponent.teamIndex)
				{
					array[i].GetComponent<CharacterBody>().AddTimedBuff(RoR2Content.Buffs.TeamWarCry, 7f);
				}
			}
			return true;
		}

		private bool FireDeathProjectile()
		{
			CharacterMaster master = characterBody.master;
			if (!master)
			{
				return false;
			}
			if (master.IsDeployableLimited(DeployableSlot.DeathProjectile))
			{
				return false;
			}
			Ray aimRay = GetAimRay();
			UnityEngine.Quaternion rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction);
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/DeathProjectile");
			gameObject.GetComponent<DeathProjectile>().teamIndex = teamComponent.teamIndex;
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = gameObject;
			fireProjectileInfo.crit = characterBody.RollCrit();
			fireProjectileInfo.damage = characterBody.damage;
			fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
			fireProjectileInfo.force = 0f;
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.position = aimRay.origin;
			fireProjectileInfo.rotation = rotation;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			return true;
		}

		private bool FireMolotov()
		{
			Ray aimRay = GetAimRay();
			GameObject prefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/MolotovClusterProjectile");
			ProjectileManager.instance.FireProjectile(prefab, aimRay.origin, UnityEngine.Quaternion.LookRotation(aimRay.direction), base.gameObject, characterBody.damage, 0f, Util.CheckRoll(characterBody.crit, characterBody.master));
			return true;
		}

		private bool FireVendingMachine()
		{
			Ray ray = new Ray(GetAimRay().origin, UnityEngine.Vector3.down);
			if (Util.CharacterRaycast(base.gameObject, ray, out var hitInfo, 1000f, LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal))
			{
				GameObject prefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/VendingMachineProjectile");
				ProjectileManager.instance.FireProjectile(prefab, hitInfo.point, UnityEngine.Quaternion.identity, base.gameObject, characterBody.damage, 0f, Util.CheckRoll(characterBody.crit, characterBody.master));
				subcooldownTimer = 0.5f;
				return true;
			}
			return false;
		}

		private bool FireGummyClone()
		{
			CharacterMaster characterMaster = characterBody?.master;
			if (!characterMaster || characterMaster.IsDeployableLimited(DeployableSlot.GummyClone))
			{
				return false;
			}
			Ray aimRay = GetAimRay();
			UnityEngine.Quaternion rotation = UnityEngine.Quaternion.LookRotation(aimRay.direction);
			GameObject projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/GummyCloneProjectile");
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.crit = characterBody.RollCrit();
			fireProjectileInfo.damage = 0f;
			fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
			fireProjectileInfo.force = 0f;
			fireProjectileInfo.owner = base.gameObject;
			fireProjectileInfo.position = aimRay.origin;
			fireProjectileInfo.rotation = rotation;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			return true;
		}

		private bool FireLunarPortalOnUse()
		{
			TeleporterInteraction.instance.shouldAttemptToSpawnShopPortal = true;
			return true;
		}

		private bool FireHealAndRevive()
		{
			bool flag = false;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (!instance.isConnected || !master.IsDeadAndOutOfLivesServer())
				{
					continue;
				}
				flag = true;
				UnityEngine.Vector3 deathFootPosition = master.deathFootPosition;
				master.Respawn(deathFootPosition, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f));
				CharacterBody body = master.GetBody();
				if ((bool)body)
				{
					body.AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
					EntityStateMachine[] components = body.GetComponents<EntityStateMachine>();
					foreach (EntityStateMachine obj in components)
					{
						obj.initialStateType = obj.mainStateType;
					}
					playerRespawnEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/fxHealAndReviveGold");
					if ((bool)playerRespawnEffectPrefab)
					{
						EffectManager.SpawnEffect(playerRespawnEffectPrefab, new EffectData
						{
							origin = deathFootPosition,
							rotation = body.transform.rotation
						}, transmit: true);
						Util.PlaySound("Play_item_use_healAndRevive_activate", base.gameObject);
					}
				}
			}
			if (flag)
			{
				bool flag2 = false;
				if (characterBody?.equipmentSlot != null && characterBody?.equipmentSlot.equipmentIndex == DLC2Content.Equipment.HealAndRevive.equipmentIndex)
				{
					flag2 = true;
				}
				if ((bool)characterBody?.inventory && flag2)
				{
					CharacterMasterNotificationQueue.SendTransformNotification(characterBody.master, characterBody.inventory.currentEquipmentIndex, DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex, CharacterMasterNotificationQueue.TransformationType.Default);
					characterBody.inventory.SetEquipmentIndex(DLC2Content.Equipment.HealAndReviveConsumed.equipmentIndex);
				}
			}
			if (!flag)
			{
				return false;
			}
			return true;
		}

		private bool FireSproutOfLife()
		{
			if (sproutIsSpawned && (bool)sprout)
			{
				sproutIsSpawned = false;
				NetworkServer.Destroy(sprout);
			}
			Ray aimRay = GetAimRay();
			UnityEngine.Quaternion.LookRotation(aimRay.direction);
			sproutSpawnTransform = characterBody.transform;
			UnityEngine.Vector3 position = characterBody.transform.position;
			characterBody.transform.TransformDirection(UnityEngine.Vector3.forward);
			new UnityEngine.Quaternion(0f, UnityEngine.Random.Range(0f, 360f), 0f, 1f);
			if (Physics.Raycast(position, aimRay.direction, out var hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				sproutSpawnTransform.position = hitInfo.point;
				sproutSpawnTransform.up = hitInfo.normal;
				sprout = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/SproutOfLifeHealing"), sproutSpawnTransform.position, UnityEngine.Quaternion.identity);
				sprout.transform.up = sproutSpawnTransform.up;
				sprout.transform.rotation *= UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 360f), UnityEngine.Vector3.up);
				NetworkServer.Spawn(sprout);
				sproutIsSpawned = true;
				return true;
			}
			return false;
		}

		static EquipmentSlot()
		{
			tonicBuffDuration = 20f;
			equipmentActivateString = "Play_UI_equipment_activate";
			activeParamHash = Animator.StringToHash("active");
			activeDurationParamHash = Animator.StringToHash("activeDuration");
			activeStopwatchParamHash = Animator.StringToHash("activeStopwatch");
			kCmdCmdExecuteIfReady = -303452611;
			NetworkBehaviour.RegisterCommandDelegate(typeof(EquipmentSlot), kCmdCmdExecuteIfReady, InvokeCmdCmdExecuteIfReady);
			kCmdCmdOnEquipmentExecuted = 1725820338;
			NetworkBehaviour.RegisterCommandDelegate(typeof(EquipmentSlot), kCmdCmdOnEquipmentExecuted, InvokeCmdCmdOnEquipmentExecuted);
			kRpcRpcOnClientEquipmentActivationRecieved = 1342577121;
			NetworkBehaviour.RegisterRpcDelegate(typeof(EquipmentSlot), kRpcRpcOnClientEquipmentActivationRecieved, InvokeRpcRpcOnClientEquipmentActivationRecieved);
			NetworkCRC.RegisterBehaviour("EquipmentSlot", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdExecuteIfReady(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdExecuteIfReady called on client.");
			}
			else
			{
				((EquipmentSlot)obj).CmdExecuteIfReady();
			}
		}

		protected static void InvokeCmdCmdOnEquipmentExecuted(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdOnEquipmentExecuted called on client.");
			}
			else
			{
				((EquipmentSlot)obj).CmdOnEquipmentExecuted();
			}
		}

		public void CallCmdExecuteIfReady()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdExecuteIfReady called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdExecuteIfReady();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdExecuteIfReady);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdExecuteIfReady");
		}

		public void CallCmdOnEquipmentExecuted()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdOnEquipmentExecuted called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdOnEquipmentExecuted();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdOnEquipmentExecuted);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdOnEquipmentExecuted");
		}

		protected static void InvokeRpcRpcOnClientEquipmentActivationRecieved(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnClientEquipmentActivationRecieved called on server.");
			}
			else
			{
				((EquipmentSlot)obj).RpcOnClientEquipmentActivationRecieved();
			}
		}

		public void CallRpcOnClientEquipmentActivationRecieved()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnClientEquipmentActivationRecieved called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnClientEquipmentActivationRecieved);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnClientEquipmentActivationRecieved");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class EscapeSequenceController : NetworkBehaviour
	{
		[Serializable]
		public struct ScheduledEvent
		{
			public float minSecondsRemaining;

			public float maxSecondsRemaining;

			public UnityEvent onEnter;

			public UnityEvent onExit;

			[NonSerialized]
			public bool inEvent;
		}

		public class EscapeSequenceBaseState : BaseState
		{
			protected EscapeSequenceController escapeSequenceController { get; private set; }

			public override void OnEnter()
			{
				base.OnEnter();
				escapeSequenceController = GetComponent<EscapeSequenceController>();
			}
		}

		public class EscapeSequenceMainState : EscapeSequenceBaseState
		{
			private Run.FixedTimeStamp startTime;

			private Run.FixedTimeStamp endTime;

			public override void OnEnter()
			{
				base.OnEnter();
				if (base.isAuthority)
				{
					startTime = Run.FixedTimeStamp.now;
					endTime = startTime + base.escapeSequenceController.countdownDuration;
				}
				base.escapeSequenceController.onEnterMainEscapeSequence?.Invoke();
			}

			public override void OnExit()
			{
				foreach (HUD readOnlyInstance in HUD.readOnlyInstanceList)
				{
					base.escapeSequenceController.SetHudCountdownEnabled(readOnlyInstance, shouldEnableCountdownPanel: false);
				}
				base.OnExit();
			}

			public override void Update()
			{
				base.Update();
				foreach (HUD readOnlyInstance in HUD.readOnlyInstanceList)
				{
					base.escapeSequenceController.SetHudCountdownEnabled(readOnlyInstance, readOnlyInstance.targetBodyObject);
				}
				base.escapeSequenceController.SetCountdownTime(endTime.timeUntilClamped);
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				base.escapeSequenceController.UpdateScheduledEvents(endTime.timeUntil);
				if (base.isAuthority && endTime.hasPassed && !SceneExitController.isRunning)
				{
					outer.SetNextState(new EscapeSequenceFailureState());
				}
			}

			public override void OnSerialize(NetworkWriter writer)
			{
				base.OnSerialize(writer);
				writer.Write(startTime);
				writer.Write(endTime);
			}

			public override void OnDeserialize(NetworkReader reader)
			{
				base.OnDeserialize(reader);
				startTime = reader.ReadFixedTimeStamp();
				endTime = reader.ReadFixedTimeStamp();
			}
		}

		public class EscapeSequenceFailureState : EscapeSequenceBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				if (NetworkServer.active)
				{
					base.escapeSequenceController.onFailEscapeSequenceServer?.Invoke();
				}
			}
		}

		public class EscapeSequenceSuccessState : EscapeSequenceBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				if (NetworkServer.active)
				{
					base.escapeSequenceController.onCompleteEscapeSequenceServer?.Invoke();
				}
			}
		}

		public EntityStateMachine mainStateMachine;

		[Tooltip("How long the player has to escape, in seconds.")]
		public float countdownDuration;

		public UnityEvent onEnterMainEscapeSequence;

		public UnityEvent onCompleteEscapeSequenceServer;

		public UnityEvent onFailEscapeSequenceServer;

		public ScheduledEvent[] scheduledEvents;

		private Dictionary<HUD, GameObject> hudPanels;

		public void BeginEscapeSequence()
		{
			if (Util.HasEffectiveAuthority(base.gameObject))
			{
				mainStateMachine.SetNextState(new EscapeSequenceMainState());
			}
		}

		public void CompleteEscapeSequence()
		{
			if (Util.HasEffectiveAuthority(base.gameObject))
			{
				mainStateMachine.SetNextState(new EscapeSequenceSuccessState());
			}
		}

		private void UpdateScheduledEvents(float secondsRemaining)
		{
			for (int i = 0; i < scheduledEvents.Length; i++)
			{
				ref ScheduledEvent reference = ref scheduledEvents[i];
				bool flag = reference.minSecondsRemaining <= secondsRemaining && secondsRemaining <= reference.maxSecondsRemaining;
				if (flag != reference.inEvent)
				{
					if (flag)
					{
						reference.onEnter?.Invoke();
					}
					else
					{
						reference.onExit?.Invoke();
					}
					reference.inEvent = flag;
				}
			}
		}

		private void SetHudCountdownEnabled(HUD hud, bool shouldEnableCountdownPanel)
		{
			shouldEnableCountdownPanel &= base.enabled;
			hudPanels.TryGetValue(hud, out var value);
			if ((bool)value == shouldEnableCountdownPanel)
			{
				return;
			}
			if (shouldEnableCountdownPanel)
			{
				RectTransform rectTransform = hud.GetComponent<ChildLocator>().FindChild("TopCenterCluster") as RectTransform;
				if ((bool)rectTransform)
				{
					GameObject value2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/HudModules/HudCountdownPanel"), rectTransform);
					hudPanels[hud] = value2;
				}
			}
			else
			{
				UnityEngine.Object.Destroy(value);
				hudPanels.Remove(hud);
			}
		}

		private void SetCountdownTime(double secondsRemaining)
		{
			foreach (KeyValuePair<HUD, GameObject> hudPanel in hudPanels)
			{
				hudPanel.Value.GetComponent<TimerText>().seconds = secondsRemaining;
			}
			AkSoundEngine.SetRTPCValue("EscapeTimer", Util.Remap((float)secondsRemaining, 0f, countdownDuration, 0f, 100f));
		}

		private void OnEnable()
		{
			hudPanels = new Dictionary<HUD, GameObject>();
		}

		private void OnDisable()
		{
			foreach (HUD readOnlyInstance in HUD.readOnlyInstanceList)
			{
				SetHudCountdownEnabled(readOnlyInstance, shouldEnableCountdownPanel: false);
			}
			hudPanels = null;
		}

		public void DestroyAllBodies()
		{
			List<CharacterBody> list = new List<CharacterBody>(CharacterBody.readOnlyInstancesList);
			for (int i = 0; i < list.Count; i++)
			{
				CharacterBody characterBody = list[i];
				if ((bool)characterBody)
				{
					UnityEngine.Object.Destroy(characterBody.gameObject);
				}
			}
		}

		public void KillAllCharacters()
		{
			List<CharacterMaster> list = new List<CharacterMaster>(CharacterMaster.readOnlyInstancesList);
			for (int i = 0; i < list.Count; i++)
			{
				CharacterMaster characterMaster = list[i];
				if ((bool)characterMaster)
				{
					characterMaster.TrueKill(null, null, DamageType.Silent | DamageType.VoidDeath);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class EscapeSequenceExtractionZone : MonoBehaviour
	{
		private class EscapeSequenceExtractionZoneObjectiveTracker : ObjectivePanelController.ObjectiveTracker
		{
			private int cachedLivingPlayersCount;

			private int cachedPlayersInRadiusCount;

			private EscapeSequenceExtractionZone extractionZone => (EscapeSequenceExtractionZone)sourceDescriptor.source;

			public override string ToString()
			{
				cachedLivingPlayersCount = extractionZone.livingPlayerCount;
				cachedPlayersInRadiusCount = extractionZone.playersInRadius.Count;
				string text = Language.GetString(extractionZone.objectiveToken);
				if (cachedLivingPlayersCount >= 1)
				{
					text = Language.GetStringFormatted("OBJECTIVE_FRACTION_PROGRESS_FORMAT", text, cachedPlayersInRadiusCount, cachedLivingPlayersCount);
				}
				return text;
			}

			protected override bool IsDirty()
			{
				if (cachedLivingPlayersCount != extractionZone.livingPlayerCount)
				{
					return cachedPlayersInRadiusCount != extractionZone.playersInRadius.Count;
				}
				return false;
			}
		}

		public float radius;

		public string objectiveToken;

		public GameEndingDef successEnding;

		private int livingPlayerCount;

		private List<CharacterBody> playersInRadius;

		private TeamIndex teamIndex = TeamIndex.Player;

		private void Awake()
		{
			playersInRadius = new List<CharacterBody>();
		}

		private void FixedUpdate()
		{
			livingPlayerCount = CountLivingPlayers(teamIndex);
			playersInRadius.Clear();
			GetPlayersInRadius(base.transform.position, radius * radius, teamIndex, playersInRadius);
			if (NetworkServer.active && livingPlayerCount > 0 && playersInRadius.Count >= livingPlayerCount)
			{
				HandleEndingServer();
			}
		}

		private void OnEnable()
		{
			if (InstanceTracker.GetInstancesList<EscapeSequenceExtractionZone>().Count == 0)
			{
				ObjectivePanelController.collectObjectiveSources += ReportObjectives;
			}
			InstanceTracker.Add(this);
		}

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
			if (InstanceTracker.GetInstancesList<EscapeSequenceExtractionZone>().Count == 0)
			{
				ObjectivePanelController.collectObjectiveSources -= ReportObjectives;
			}
		}

		private void OnDrawGizmos()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			Gizmos.DrawSphere(base.transform.position, radius);
		}

		public void KillAllStragglers()
		{
			List<CharacterMaster> list = new List<CharacterMaster>(CharacterMaster.readOnlyInstancesList);
			for (int i = 0; i < list.Count; i++)
			{
				CharacterMaster characterMaster = list[i];
				if ((bool)characterMaster && !playersInRadius.Contains(characterMaster.GetBody()))
				{
					characterMaster.TrueKill(null, null, DamageType.Silent | DamageType.VoidDeath);
				}
			}
		}

		public void HandleEndingServer()
		{
			if (!Run.instance.isGameOverServer)
			{
				KillAllStragglers();
				if (playersInRadius.Count > 0)
				{
					Run.instance.BeginGameOver(successEnding);
				}
			}
		}

		private static void ReportObjectives(CharacterMaster characterMaster, List<ObjectivePanelController.ObjectiveSourceDescriptor> dest)
		{
			List<EscapeSequenceExtractionZone> instancesList = InstanceTracker.GetInstancesList<EscapeSequenceExtractionZone>();
			for (int i = 0; i < instancesList.Count; i++)
			{
				EscapeSequenceExtractionZone escapeSequenceExtractionZone = instancesList[i];
				if (characterMaster.teamIndex == escapeSequenceExtractionZone.teamIndex)
				{
					ObjectivePanelController.ObjectiveSourceDescriptor objectiveSourceDescriptor = default(ObjectivePanelController.ObjectiveSourceDescriptor);
					objectiveSourceDescriptor.master = characterMaster;
					objectiveSourceDescriptor.objectiveType = typeof(EscapeSequenceExtractionZoneObjectiveTracker);
					objectiveSourceDescriptor.source = escapeSequenceExtractionZone;
				}
			}
		}

		private static bool IsPointInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, UnityEngine.Vector3 point)
		{
			if ((point - origin).sqrMagnitude <= chargingRadiusSqr)
			{
				return true;
			}
			return false;
		}

		private static bool IsBodyInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, CharacterBody characterBody)
		{
			return IsPointInRadius(origin, chargingRadiusSqr, characterBody.corePosition);
		}

		private static int CountLivingPlayers(TeamIndex teamIndex)
		{
			int num = 0;
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				if (teamMembers[i].body.isPlayerControlled)
				{
					num++;
				}
			}
			return num;
		}

		public int CountPlayersInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, TeamIndex teamIndex)
		{
			int num = 0;
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				TeamComponent teamComponent = teamMembers[i];
				if (teamComponent.body.isPlayerControlled && IsBodyInRadius(origin, chargingRadiusSqr, teamComponent.body))
				{
					num++;
				}
			}
			return num;
		}

		private int GetPlayersInRadius(UnityEngine.Vector3 origin, float chargingRadiusSqr, TeamIndex teamIndex, List<CharacterBody> dest)
		{
			int result = 0;
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				TeamComponent teamComponent = teamMembers[i];
				if (teamComponent.body.isPlayerControlled && IsBodyInRadius(origin, chargingRadiusSqr, teamComponent.body))
				{
					dest.Add(teamComponent.body);
				}
			}
			return result;
		}

		public bool IsBodyInRadius(CharacterBody body)
		{
			if (!body)
			{
				return false;
			}
			return IsBodyInRadius(base.transform.position, radius * radius, body);
		}
	}
	public class EventFunctions : MonoBehaviour
	{
		public void DestroySelf()
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}

		public void DestroyGameObject(GameObject obj)
		{
			UnityEngine.Object.Destroy(obj);
		}

		public void UnparentTransform(Transform transform)
		{
			if ((bool)transform)
			{
				transform.SetParent(null);
			}
		}

		public void ToggleGameObjectActive(GameObject obj)
		{
			obj.SetActive(!obj.activeSelf);
		}

		public void CreateLocalEffect(GameObject effectObj)
		{
			EffectData effectData = new EffectData();
			effectData.origin = base.transform.position;
			EffectManager.SpawnEffect(effectObj, effectData, transmit: false);
		}

		public void CreateNetworkedEffect(GameObject effectObj)
		{
			EffectData effectData = new EffectData();
			effectData.origin = base.transform.position;
			EffectManager.SpawnEffect(effectObj, effectData, transmit: true);
		}

		public void OpenURL(string url)
		{
			Application.OpenURL(url);
		}

		public void PlaySound(string soundString)
		{
			Util.PlaySound(soundString, base.gameObject);
		}

		public void PlayUISound(string soundString)
		{
			Util.PlaySound(soundString, RoR2Application.instance.gameObject);
		}

		public void PlayNetworkedUISound(NetworkSoundEventDef nseDef)
		{
			if ((bool)nseDef)
			{
				EffectManager.SimpleSoundEffect(nseDef.index, UnityEngine.Vector3.zero, transmit: true);
			}
		}

		public void RunSetFlag(string flagName)
		{
			if (NetworkServer.active)
			{
				Run.instance?.SetEventFlag(flagName);
			}
		}

		public void RunResetFlag(string flagName)
		{
			if (NetworkServer.active)
			{
				Run.instance?.ResetEventFlag(flagName);
			}
		}

		public void DisableAllChildren()
		{
			for (int num = base.transform.childCount - 1; num >= 0; num--)
			{
				base.transform.GetChild(num).gameObject.SetActive(value: false);
			}
		}

		public void DisableAllChildrenExcept(GameObject objectToEnable)
		{
			for (int num = base.transform.childCount - 1; num >= 0; num--)
			{
				GameObject gameObject = base.transform.GetChild(num).gameObject;
				if (!(gameObject == objectToEnable))
				{
					gameObject.SetActive(value: false);
				}
			}
			objectToEnable.SetActive(value: true);
		}

		public void BeginEnding(GameEndingDef gameEndingDef)
		{
			if (NetworkServer.active)
			{
				Run.instance.BeginGameOver(gameEndingDef);
			}
		}
	}
	public class EventOnBodyDeaths : MonoBehaviour
	{
		public string[] bodyNames;

		private int currentDeathCount;

		public int targetDeathCount;

		public UnityEvent onAchieved;

		private void OnEnable()
		{
			GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
		}

		private void OnDisable()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
		}

		private void OnCharacterDeath(DamageReport damageReport)
		{
			if ((bool)damageReport.victimBody)
			{
				for (int i = 0; i < bodyNames.Length; i++)
				{
					if (damageReport.victimBody.name.Contains(bodyNames[i]))
					{
						currentDeathCount++;
						break;
					}
				}
			}
			if (currentDeathCount >= targetDeathCount)
			{
				onAchieved?.Invoke();
			}
		}
	}
	public class ExperienceManager : MonoBehaviour
	{
		[Serializable]
		private struct TimedExpAward
		{
			public float awardTime;

			public ulong awardAmount;

			public TeamIndex recipient;
		}

		private class CreateExpEffectMessage : MessageBase
		{
			public UnityEngine.Vector3 origin;

			public GameObject targetBody;

			public ulong awardAmount;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(origin);
				writer.Write(targetBody);
				writer.WritePackedUInt64(awardAmount);
			}

			public override void Deserialize(NetworkReader reader)
			{
				origin = reader.ReadVector3();
				targetBody = reader.ReadGameObject();
				awardAmount = reader.ReadPackedUInt64();
			}
		}

		private static GameObject experienceOrbPrefab;

		private float localTime;

		private List<TimedExpAward> pendingAwards = new List<TimedExpAward>();

		private float nextAward;

		private bool shouldPool;

		private const float minOrbTravelTime = 0.5f;

		public const float maxOrbTravelTime = 2f;

		public static readonly float[] orbTimeOffsetSequence = new float[16]
		{
			0.841f, 0.394f, 0.783f, 0.799f, 0.912f, 0.197f, 0.335f, 0.768f, 0.278f, 0.554f,
			0.477f, 0.629f, 0.365f, 0.513f, 0.953f, 0.917f
		};

		private static CreateExpEffectMessage currentOutgoingCreateExpEffectMessage = new CreateExpEffectMessage();

		private static CreateExpEffectMessage currentIncomingCreateExpEffectMessage = new CreateExpEffectMessage();

		public static ExperienceManager instance { get; private set; }

		private static float CalcOrbTravelTime(float timeOffset)
		{
			return 0.5f + 1.5f * timeOffset;
		}

		private void OnEnable()
		{
			if ((bool)instance && instance != this)
			{
				UnityEngine.Debug.LogError("Only one ExperienceManager can exist at a time.");
				return;
			}
			instance = this;
			if (!experienceOrbPrefab)
			{
				LegacyResourcesAPI.LoadAsyncCallback("Prefabs/ExpOrb", delegate(GameObject x)
				{
					experienceOrbPrefab = x;
					shouldPool = EffectManager.ShouldUsePooledEffect(experienceOrbPrefab);
				});
			}
		}

		private void OnDisable()
		{
			if (instance == this)
			{
				instance = null;
			}
		}

		private void Start()
		{
			localTime = 0f;
			nextAward = float.PositiveInfinity;
		}

		private void FixedUpdate()
		{
			localTime += Time.fixedDeltaTime;
			if (pendingAwards.Count <= 0 || !(nextAward <= localTime))
			{
				return;
			}
			nextAward = float.PositiveInfinity;
			for (int num = pendingAwards.Count - 1; num >= 0; num--)
			{
				if (pendingAwards[num].awardTime <= localTime)
				{
					if ((bool)TeamManager.instance)
					{
						TeamManager.instance.GiveTeamExperience(pendingAwards[num].recipient, pendingAwards[num].awardAmount);
					}
					pendingAwards.RemoveAt(num);
				}
				else if (pendingAwards[num].awardTime < nextAward)
				{
					nextAward = pendingAwards[num].awardTime;
				}
			}
		}

		public void AwardExperience(UnityEngine.Vector3 origin, CharacterBody body, ulong amount)
		{
			CharacterMaster master = body.master;
			if (!master)
			{
				return;
			}
			TeamIndex teamIndex = master.teamIndex;
			List<ulong> list = CalculateDenominations(amount);
			uint num = 0u;
			for (int i = 0; i < list.Count; i++)
			{
				AddPendingAward(localTime + 0.5f + 1.5f * orbTimeOffsetSequence[num], teamIndex, list[i]);
				num++;
				if (num >= orbTimeOffsetSequence.Length)
				{
					num = 0u;
				}
			}
			currentOutgoingCreateExpEffectMessage.awardAmount = amount;
			currentOutgoingCreateExpEffectMessage.origin = origin;
			currentOutgoingCreateExpEffectMessage.targetBody = body.gameObject;
			NetworkServer.SendToAll(55, currentOutgoingCreateExpEffectMessage);
		}

		private void AddPendingAward(float awardTime, TeamIndex recipient, ulong awardAmount)
		{
			pendingAwards.Add(new TimedExpAward
			{
				awardTime = awardTime,
				recipient = recipient,
				awardAmount = awardAmount
			});
			if (nextAward > awardTime)
			{
				nextAward = awardTime;
			}
		}

		public List<ulong> CalculateDenominations(ulong total)
		{
			List<ulong> list = new List<ulong>();
			while (total != 0)
			{
				ulong num = (ulong)Math.Pow(6.0, Mathf.Floor(Mathf.Log(total, 6f)));
				total = Math.Max(total - num, 0uL);
				list.Add(num);
			}
			return list;
		}

		[NetworkMessageHandler(msgType = 55, client = true)]
		private static void HandleCreateExpEffect(NetworkMessage netMsg)
		{
			if ((bool)instance)
			{
				instance.HandleCreateExpEffectInternal(netMsg);
			}
		}

		private void HandleCreateExpEffectInternal(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(currentIncomingCreateExpEffectMessage);
			if (!SettingsConVars.cvExpAndMoneyEffects.value)
			{
				return;
			}
			GameObject targetBody = currentIncomingCreateExpEffectMessage.targetBody;
			if (!targetBody)
			{
				return;
			}
			HurtBox hurtBox = Util.FindBodyMainHurtBox(targetBody);
			Transform targetTransform = (hurtBox ? hurtBox.transform : targetBody.transform);
			List<ulong> list = CalculateDenominations(currentIncomingCreateExpEffectMessage.awardAmount);
			uint num = 0u;
			ExperienceOrbBehavior experienceOrbBehavior = null;
			for (int i = 0; i < list.Count; i++)
			{
				if (!shouldPool)
				{
					experienceOrbBehavior = UnityEngine.Object.Instantiate(experienceOrbPrefab, currentIncomingCreateExpEffectMessage.origin, UnityEngine.Quaternion.identity).GetComponent<ExperienceOrbBehavior>();
				}
				else
				{
					EffectManagerHelper pooledEffect = EffectManager.GetPooledEffect(experienceOrbPrefab, currentIncomingCreateExpEffectMessage.origin, UnityEngine.Quaternion.identity);
					experienceOrbBehavior = pooledEffect.GetComponent<ExperienceOrbBehavior>();
					pooledEffect.Reset(inActivate: true);
					pooledEffect.gameObject.SetActive(value: true);
					pooledEffect.ResetPostActivate();
				}
				experienceOrbBehavior.targetTransform = targetTransform;
				experienceOrbBehavior.travelTime = CalcOrbTravelTime(orbTimeOffsetSequence[num]);
				experienceOrbBehavior.exp = list[i];
				experienceOrbBehavior.SetupStartingValues();
				num++;
				if (num >= orbTimeOffsetSequence.Length)
				{
					num = 0u;
				}
			}
		}
	}
	public class ExperienceOrbBehavior : MonoBehaviour
	{
		public GameObject hitEffectPrefab;

		private EffectManagerHelper efh;

		private new Transform transform;

		private TrailRenderer trail;

		private Light light;

		private float localTime;

		private UnityEngine.Vector3 startPos;

		private UnityEngine.Vector3 previousPos;

		private UnityEngine.Vector3 initialVelocity;

		private float scale;

		private bool consumed;

		private static readonly string expSoundString = "Play_UI_xp_gain";

		public Transform targetTransform { get; set; }

		public float travelTime { get; set; }

		public ulong exp { get; set; }

		private void Awake()
		{
			transform = base.transform;
			trail = GetComponent<TrailRenderer>();
			light = GetComponent<Light>();
			efh = GetComponent<EffectManagerHelper>();
		}

		private void Start()
		{
			SetupStartingValues();
		}

		public void SetupStartingValues()
		{
			localTime = 0f;
			consumed = false;
			startPos = transform.position;
			previousPos = startPos;
			scale = 2f * Mathf.Log((float)exp + 1f, 6f);
			initialVelocity = (UnityEngine.Vector3.up * 4f + UnityEngine.Random.insideUnitSphere * 1f) * scale;
			transform.localScale = new UnityEngine.Vector3(scale, scale, scale);
			if ((bool)trail)
			{
				trail.startWidth = 0.05f * scale;
			}
			if ((bool)light)
			{
				light.range = 1f * scale;
			}
		}

		private void Update()
		{
			localTime += Time.deltaTime;
			if (!targetTransform)
			{
				HandleEnd();
				return;
			}
			float num = Mathf.Clamp01(localTime / travelTime);
			previousPos = transform.position;
			transform.position = CalculatePosition(startPos, initialVelocity, targetTransform.position, num);
			if (num >= 1f)
			{
				OnHitTarget();
			}
		}

		private static UnityEngine.Vector3 CalculatePosition(UnityEngine.Vector3 startPos, UnityEngine.Vector3 initialVelocity, UnityEngine.Vector3 targetPos, float t)
		{
			UnityEngine.Vector3 a = startPos + initialVelocity * t;
			float t2 = t * t * t;
			return UnityEngine.Vector3.LerpUnclamped(a, targetPos, t2);
		}

		private void OnTriggerStay(Collider other)
		{
			if (other.transform == targetTransform)
			{
				OnHitTarget();
			}
		}

		private void OnHitTarget()
		{
			if (!consumed)
			{
				consumed = true;
				Util.PlaySound(expSoundString, targetTransform.gameObject);
				GameObject gameObject;
				if (!EffectManager.ShouldUsePooledEffect(hitEffectPrefab))
				{
					gameObject = UnityEngine.Object.Instantiate(hitEffectPrefab, transform.position, Util.QuaternionSafeLookRotation(previousPos - startPos));
				}
				else
				{
					EffectManagerHelper pooledEffect = EffectManager.GetPooledEffect(hitEffectPrefab, transform.position, Util.QuaternionSafeLookRotation(previousPos - startPos));
					pooledEffect.Reset(inActivate: true);
					gameObject = pooledEffect.gameObject;
					gameObject.SetActive(value: true);
					pooledEffect.ResetPostActivate();
				}
				gameObject.transform.localScale *= scale;
				HandleEnd();
			}
		}

		private void HandleEnd()
		{
			if (efh != null)
			{
				efh.ReturnToPool();
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	public class ExplodeRigidbodiesOnStart : MonoBehaviour
	{
		public Rigidbody[] bodies;

		public float force;

		public float explosionRadius;

		private void Start()
		{
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < bodies.Length; i++)
			{
				bodies[i].AddExplosionForce(force, position, explosionRadius);
			}
		}
	}
	public class EyeFlare : MonoBehaviour
	{
		[Tooltip("The transform whose forward vector will be tested against the camera angle to determine scaling. This is usually the parent, and never this object since billboarding will affect the direction.")]
		public Transform directionSource;

		public float localScale = 1f;

		private static List<EyeFlare> instancesList;

		private new Transform transform;

		static EyeFlare()
		{
			instancesList = new List<EyeFlare>();
			SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull;
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private static void OnSceneCameraPreCull(SceneCamera sceneCamera)
		{
			Transform obj = Camera.current.transform;
			UnityEngine.Quaternion rotation = obj.rotation;
			UnityEngine.Vector3 forward = obj.forward;
			for (int i = 0; i < instancesList.Count; i++)
			{
				EyeFlare eyeFlare = instancesList[i];
				float num = eyeFlare.localScale;
				if ((bool)eyeFlare.directionSource)
				{
					float num2 = UnityEngine.Vector3.Dot(forward, eyeFlare.directionSource.forward) * -0.5f + 0.5f;
					num *= num2 * num2;
				}
				eyeFlare.transform.localScale = new UnityEngine.Vector3(num, num, num);
				eyeFlare.transform.rotation = rotation;
			}
		}

		private void Awake()
		{
			transform = base.transform;
		}
	}
	public class FadeToBlackOffset : MonoBehaviour
	{
		public float value;

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}
	}
	public class FallBootsLights : MonoBehaviour
	{
		public GameObject readyEffect;

		public GameObject triggerEffect;

		public GameObject chargingEffect;

		private GameObject readyEffectInstance;

		private GameObject triggerEffectInstance;

		private GameObject chargingEffectInstance;

		private bool isReady;

		private bool isTriggered;

		private bool isCharging;

		private CharacterModel characterModel;

		private EntityStateMachine sourceStateMachine;

		private void Start()
		{
			characterModel = GetComponentInParent<CharacterModel>();
			FindSourceStateMachine();
		}

		private void FindSourceStateMachine()
		{
			if ((bool)characterModel && (bool)characterModel.body)
			{
				sourceStateMachine = BaseHeadstompersState.FindForBody(characterModel.body)?.outer;
			}
		}

		private void Update()
		{
			if (!sourceStateMachine)
			{
				FindSourceStateMachine();
			}
			bool flag = (bool)sourceStateMachine && !(sourceStateMachine.state is HeadstompersCooldown);
			if (flag != isReady)
			{
				if (flag)
				{
					readyEffectInstance = UnityEngine.Object.Instantiate(readyEffect, base.transform.position, base.transform.rotation, base.transform);
					Util.PlaySound("Play_item_proc_fallboots_activate", base.gameObject);
				}
				else if ((bool)readyEffectInstance)
				{
					UnityEngine.Object.Destroy(readyEffectInstance);
				}
				isReady = flag;
			}
			bool flag2 = (bool)sourceStateMachine && sourceStateMachine.state is HeadstompersFall;
			if (flag2 != isTriggered)
			{
				if (flag2)
				{
					triggerEffectInstance = UnityEngine.Object.Instantiate(triggerEffect, base.transform.position, base.transform.rotation, base.transform);
					Util.PlaySound("Play_item_proc_fallboots_activate", base.gameObject);
				}
				else if ((bool)triggerEffectInstance)
				{
					UnityEngine.Object.Destroy(triggerEffectInstance);
				}
				isTriggered = flag2;
			}
			bool flag3 = (bool)sourceStateMachine && sourceStateMachine.state is HeadstompersCharge;
			if (flag3 != isCharging)
			{
				if (flag3)
				{
					chargingEffectInstance = UnityEngine.Object.Instantiate(chargingEffect, base.transform.position, base.transform.rotation, base.transform);
				}
				else if ((bool)chargingEffectInstance)
				{
					UnityEngine.Object.Destroy(chargingEffectInstance);
				}
				isCharging = flag3;
			}
		}
	}
	public class FireAuraController : NetworkBehaviour
	{
		private const float fireAttackRadiusMin = 0.5f;

		private const float fireAttackRadiusMax = 6f;

		private const float fireDamageCoefficient = 1f;

		private const float fireProcCoefficient = 0.1f;

		private const float maxTimer = 8f;

		private float timer;

		private float attackStopwatch;

		[SyncVar]
		public GameObject owner;

		private NetworkInstanceId ___ownerNetId;

		public GameObject Networkowner
		{
			get
			{
				return owner;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref owner, 1u, ref ___ownerNetId);
			}
		}

		private void FixedUpdate()
		{
			timer += Time.fixedDeltaTime;
			CharacterBody characterBody = null;
			float num = 0f;
			if ((bool)owner)
			{
				characterBody = owner.GetComponent<CharacterBody>();
				num = (characterBody ? Mathf.Lerp(characterBody.radius * 0.5f, characterBody.radius * 6f, 1f - Mathf.Abs(-1f + 2f * timer / 8f)) : 0f);
				base.transform.position = owner.transform.position;
				base.transform.localScale = new UnityEngine.Vector3(num, num, num);
			}
			if (!NetworkServer.active)
			{
				return;
			}
			if (!owner)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			attackStopwatch += Time.fixedDeltaTime;
			if ((bool)characterBody && attackStopwatch >= 0.25f)
			{
				attackStopwatch = 0f;
				BlastAttack obj = new BlastAttack
				{
					attacker = owner,
					inflictor = base.gameObject
				};
				obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
				obj.position = base.transform.position;
				obj.procCoefficient = 0.1f;
				obj.radius = num;
				obj.baseForce = 0f;
				obj.baseDamage = 1f * characterBody.damage;
				obj.bonusForce = UnityEngine.Vector3.zero;
				obj.crit = false;
				obj.damageType = DamageType.Generic;
				obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
				obj.Fire();
			}
			if (timer >= 8f)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(owner);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(owner);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___ownerNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				owner = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___ownerNetId.IsEmpty())
			{
				Networkowner = ClientScene.FindLocalObject(___ownerNetId);
			}
		}
	}
	[RequireComponent(typeof(VehicleSeat))]
	[RequireComponent(typeof(Rigidbody))]
	public class FireballVehicle : MonoBehaviour, ICameraStateProvider
	{
		[Header("Vehicle Parameters")]
		public float duration = 3f;

		public float initialSpeed = 120f;

		public float targetSpeed = 40f;

		public float acceleration = 20f;

		public float cameraLerpTime = 1f;

		[Header("Blast Parameters")]
		public bool detonateOnCollision;

		public GameObject explosionEffectPrefab;

		public float blastDamageCoefficient;

		public float blastRadius;

		public float blastForce;

		public BlastAttack.FalloffModel blastFalloffModel;

		public DamageTypeCombo blastDamageType;

		public UnityEngine.Vector3 blastBonusForce;

		public float blastProcCoefficient;

		public string explosionSoundString;

		[Header("Overlap Parameters")]
		public float overlapDamageCoefficient;

		public float overlapProcCoefficient;

		public float overlapForce;

		public float overlapFireFrequency;

		public float overlapResetFrequency;

		public float overlapVehicleDurationBonusPerHit;

		public GameObject overlapHitEffectPrefab;

		private float age;

		private bool hasDetonatedServer;

		private VehicleSeat vehicleSeat;

		private Rigidbody rigidbody;

		private OverlapAttack overlapAttack;

		private float overlapFireAge;

		private float overlapResetAge;

		private void Awake()
		{
			vehicleSeat = GetComponent<VehicleSeat>();
			vehicleSeat.onPassengerEnter += OnPassengerEnter;
			vehicleSeat.onPassengerExit += OnPassengerExit;
			rigidbody = GetComponent<Rigidbody>();
		}

		private void OnPassengerExit(GameObject passenger)
		{
			if (NetworkServer.active)
			{
				DetonateServer();
			}
			foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList)
			{
				if (readOnlyInstances.target == passenger)
				{
					readOnlyInstances.SetOverrideCam(this, 0f);
					readOnlyInstances.SetOverrideCam(null, cameraLerpTime);
				}
			}
		}

		private void OnPassengerEnter(GameObject passenger)
		{
			if ((bool)vehicleSeat.currentPassengerInputBank)
			{
				UnityEngine.Vector3 aimDirection = vehicleSeat.currentPassengerInputBank.aimDirection;
				rigidbody.rotation = UnityEngine.Quaternion.LookRotation(aimDirection);
				rigidbody.velocity = aimDirection * initialSpeed;
				CharacterBody currentPassengerBody = vehicleSeat.currentPassengerBody;
				overlapAttack = new OverlapAttack
				{
					attacker = currentPassengerBody.gameObject,
					damage = overlapDamageCoefficient * currentPassengerBody.damage,
					pushAwayForce = overlapForce,
					isCrit = currentPassengerBody.RollCrit(),
					damageColorIndex = DamageColorIndex.Item,
					inflictor = base.gameObject,
					procChainMask = default(ProcChainMask),
					procCoefficient = overlapProcCoefficient,
					teamIndex = currentPassengerBody.teamComponent.teamIndex,
					hitBoxGroup = base.gameObject.GetComponent<HitBoxGroup>(),
					hitEffectPrefab = overlapHitEffectPrefab
				};
			}
		}

		private void DetonateServer()
		{
			if (!hasDetonatedServer)
			{
				hasDetonatedServer = true;
				CharacterBody currentPassengerBody = vehicleSeat.currentPassengerBody;
				if ((bool)currentPassengerBody)
				{
					EffectData effectData = new EffectData
					{
						origin = base.transform.position,
						scale = blastRadius
					};
					EffectManager.SpawnEffect(explosionEffectPrefab, effectData, transmit: true);
					BlastAttack blastAttack = new BlastAttack();
					blastAttack.attacker = currentPassengerBody.gameObject;
					blastAttack.baseDamage = blastDamageCoefficient * currentPassengerBody.damage;
					blastAttack.baseForce = blastForce;
					blastAttack.bonusForce = blastBonusForce;
					blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
					blastAttack.crit = currentPassengerBody.RollCrit();
					blastAttack.damageColorIndex = DamageColorIndex.Item;
					blastAttack.damageType = blastDamageType;
					blastAttack.falloffModel = blastFalloffModel;
					blastAttack.inflictor = base.gameObject;
					blastAttack.position = base.transform.position;
					blastAttack.procChainMask = default(ProcChainMask);
					blastAttack.procCoefficient = blastProcCoefficient;
					blastAttack.radius = blastRadius;
					blastAttack.teamIndex = currentPassengerBody.teamComponent.teamIndex;
					blastAttack.Fire();
				}
				Util.PlaySound(explosionSoundString, base.gameObject);
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void FixedUpdate()
		{
			if (!vehicleSeat || !vehicleSeat.currentPassengerInputBank)
			{
				return;
			}
			age += Time.fixedDeltaTime;
			overlapFireAge += Time.fixedDeltaTime;
			overlapResetAge += Time.fixedDeltaTime;
			if (NetworkServer.active)
			{
				if (overlapFireAge > 1f / overlapFireFrequency)
				{
					if (overlapAttack.Fire())
					{
						age = Mathf.Max(0f, age - overlapVehicleDurationBonusPerHit);
					}
					overlapFireAge = 0f;
				}
				if (overlapResetAge >= 1f / overlapResetFrequency)
				{
					overlapAttack.ResetIgnoredHealthComponents();
					overlapResetAge = 0f;
				}
			}
			Ray aimRay = vehicleSeat.currentPassengerInputBank.GetAimRay();
			aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, base.gameObject, out var _);
			UnityEngine.Vector3 velocity = rigidbody.velocity;
			UnityEngine.Vector3 target = aimRay.direction * targetSpeed;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.MoveTowards(velocity, target, acceleration * Time.fixedDeltaTime);
			rigidbody.MoveRotation(UnityEngine.Quaternion.LookRotation(aimRay.direction));
			rigidbody.AddForce(vector - velocity, ForceMode.VelocityChange);
			if (NetworkServer.active && duration <= age)
			{
				DetonateServer();
			}
		}

		private void OnCollisionEnter(Collision collision)
		{
			if (detonateOnCollision && NetworkServer.active)
			{
				DetonateServer();
			}
		}

		public void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState)
		{
		}

		public bool IsUserLookAllowed(CameraRigController cameraRigController)
		{
			return true;
		}

		public bool IsUserControlAllowed(CameraRigController cameraRigController)
		{
			return true;
		}

		public bool IsHudAllowed(CameraRigController cameraRigController)
		{
			return true;
		}
	}
	public class FireworkLauncher : MonoBehaviour
	{
		public GameObject projectilePrefab;

		public float launchInterval = 0.1f;

		public float damageCoefficient = 3f;

		public float coneAngle = 10f;

		public float randomCircleRange;

		[HideInInspector]
		public GameObject owner;

		[HideInInspector]
		public TeamIndex team;

		[HideInInspector]
		public int remaining;

		[HideInInspector]
		public bool crit;

		private float nextFireTimer;

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if (remaining <= 0 || !owner)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			nextFireTimer -= Time.fixedDeltaTime;
			if (nextFireTimer <= 0f)
			{
				remaining--;
				nextFireTimer += launchInterval;
				FireMissile();
			}
		}

		private void FireMissile()
		{
			CharacterBody component = owner.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				ProcChainMask procChainMask = default(ProcChainMask);
				UnityEngine.Vector2 vector = UnityEngine.Random.insideUnitCircle * randomCircleRange;
				MissileUtils.FireMissile(base.transform.position + new UnityEngine.Vector3(vector.x, 0f, vector.y), component, procChainMask, null, component.damage * damageCoefficient, crit, projectilePrefab, DamageColorIndex.Item, addMissileProc: false);
			}
		}
	}
	public class FlashEmission : MonoBehaviour
	{
		[Tooltip("The strength of a single flash (off,on,off)")]
		[SerializeField]
		private AnimationCurve flashCurve;

		[Tooltip("The duration of a single flash (off,on,off)")]
		[SerializeField]
		private float flashDuration;

		[SerializeField]
		private Renderer targetRenderer;

		private Material[] materials;

		[HideInInspector]
		public float time;

		private MaterialPropertyBlock propBlock;

		private bool active;

		private void OnEnable()
		{
			Initialize();
		}

		private void OnDisable()
		{
			active = false;
		}

		private void Initialize()
		{
			if (targetRenderer == null)
			{
				targetRenderer = GetComponent<Renderer>();
			}
			if (targetRenderer == null)
			{
				UnityEngine.Debug.LogWarning("FlashEmission on " + base.gameObject.name + " couldn't find a Renderer, shutting down.");
				base.enabled = false;
			}
			else if (materials == null)
			{
				materials = targetRenderer.materials;
			}
		}

		private void Update()
		{
			if (!active)
			{
				return;
			}
			float deltaTime = Time.deltaTime;
			if (deltaTime != 0f)
			{
				time = (time + deltaTime) % flashDuration;
				float value = flashCurve.Evaluate(time / flashDuration);
				Material[] array = materials;
				for (int i = 0; i < array.Length; i++)
				{
					_ = array[i];
					propBlock = new MaterialPropertyBlock();
					targetRenderer.GetPropertyBlock(propBlock);
					propBlock.SetFloat("_EmPower", value);
					targetRenderer.SetPropertyBlock(propBlock);
				}
			}
		}

		public void StartFlash()
		{
			active = true;
		}

		public void StopFlash()
		{
			active = false;
		}
	}
	public class FlickerLight : MonoBehaviour
	{
		public Light light;

		public Wave[] sinWaves;

		private float initialLightIntensity;

		private float workingLightIntensity;

		private float stopwatch;

		private float randomPhase;

		private void Start()
		{
			initialLightIntensity = light.intensity;
			workingLightIntensity = initialLightIntensity;
			randomPhase = UnityEngine.Random.Range(0f, MathF.PI * 2f);
			for (int i = 0; i < sinWaves.Length; i++)
			{
				sinWaves[i].cycleOffset += randomPhase;
			}
		}

		private void OnEnable()
		{
			workingLightIntensity = initialLightIntensity;
		}

		private void Update()
		{
			stopwatch += Time.deltaTime;
			float num = workingLightIntensity;
			for (int i = 0; i < sinWaves.Length; i++)
			{
				num *= 1f + sinWaves[i].Evaluate(stopwatch);
			}
			light.intensity = num;
		}

		public void UpdateLightIntensityMultiplier(float multiplier)
		{
			workingLightIntensity = initialLightIntensity * multiplier;
		}
	}
	public class FogDamageController : NetworkBehaviour
	{
		[Tooltip("Used to control which teams to damage.  If it's null, it damages ALL teams")]
		[SerializeField]
		private TeamFilter teamFilter;

		[Tooltip("If true, it damages all OTHER teams than the one specified.  If false, it damages the specified team.")]
		[SerializeField]
		private bool invertTeamFilter;

		[Tooltip("The period in seconds in between each tick")]
		[SerializeField]
		private float tickPeriodSeconds;

		[Range(0f, 1f)]
		[SerializeField]
		[Tooltip("The fraction of combined health to deduct per second.  Note that damage is actually applied per tick, not per second.")]
		private float healthFractionPerSecond;

		[SerializeField]
		[Tooltip("The coefficient to increase the damage by, for every tick they take outside the zone.")]
		private float healthFractionRampCoefficientPerSecond;

		[Tooltip("The buff to apply when in danger, i.e not in the safe zone.")]
		[SerializeField]
		private BuffDef dangerBuffDef;

		[SerializeField]
		private float dangerBuffDuration;

		[Tooltip("An initial list of safe zones behaviors which protect bodies from the fog")]
		[SerializeField]
		private BaseZoneBehavior[] initialSafeZones;

		private float dictionaryValidationTimer;

		private float damageTimer;

		private List<IZone> safeZones = new List<IZone>();

		private Dictionary<CharacterBody, int> characterBodyToStacks = new Dictionary<CharacterBody, int>();

		private void Start()
		{
			BaseZoneBehavior[] array = initialSafeZones;
			foreach (BaseZoneBehavior zone in array)
			{
				AddSafeZone(zone);
			}
		}

		public void AddSafeZone(IZone zone)
		{
			safeZones.Add(zone);
		}

		public void RemoveSafeZone(IZone zone)
		{
			safeZones.Remove(zone);
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.fixedDeltaTime);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			damageTimer += deltaTime;
			dictionaryValidationTimer += deltaTime;
			if (dictionaryValidationTimer > 60f)
			{
				dictionaryValidationTimer = 0f;
				CharacterBody[] array = new CharacterBody[characterBodyToStacks.Keys.Count];
				characterBodyToStacks.Keys.CopyTo(array, 0);
				for (int i = 0; i < array.Length; i++)
				{
					if (!array[i])
					{
						characterBodyToStacks.Remove(array[i]);
					}
				}
			}
			while (damageTimer > tickPeriodSeconds)
			{
				damageTimer -= tickPeriodSeconds;
				if ((bool)teamFilter)
				{
					if (invertTeamFilter)
					{
						for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
						{
							if (teamIndex != teamFilter.teamIndex && teamIndex != TeamIndex.None && teamIndex != 0)
							{
								EvaluateTeam(teamIndex);
							}
						}
					}
					else
					{
						EvaluateTeam(teamFilter.teamIndex);
					}
				}
				else
				{
					for (TeamIndex teamIndex2 = TeamIndex.Neutral; teamIndex2 < TeamIndex.Count; teamIndex2++)
					{
						EvaluateTeam(teamIndex2);
					}
				}
				foreach (KeyValuePair<CharacterBody, int> characterBodyToStack in characterBodyToStacks)
				{
					CharacterBody key = characterBodyToStack.Key;
					if (!key || !key.transform || !key.healthComponent)
					{
						continue;
					}
					int num = characterBodyToStack.Value - 1;
					float num2 = healthFractionPerSecond * (1f + (float)num * healthFractionRampCoefficientPerSecond * tickPeriodSeconds) * tickPeriodSeconds * key.healthComponent.fullCombinedHealth;
					if (num2 > 0f)
					{
						if (key.master != null && (bool)key.master.GetComponent<DevotedLemurianController>())
						{
							num2 *= 0.5f;
						}
						key.healthComponent.TakeDamage(new DamageInfo
						{
							damage = num2,
							position = key.corePosition,
							damageType = (DamageType.BypassArmor | DamageType.BypassBlock),
							damageColorIndex = DamageColorIndex.Void
						});
					}
					if ((bool)dangerBuffDef)
					{
						key.AddTimedBuff(dangerBuffDef, dangerBuffDuration);
					}
				}
			}
		}

		public IEnumerable<CharacterBody> GetAffectedBodies()
		{
			TeamIndex currentTeam;
			if ((bool)teamFilter)
			{
				if (invertTeamFilter)
				{
					currentTeam = TeamIndex.Neutral;
					while (currentTeam < TeamIndex.Count)
					{
						IEnumerable<CharacterBody> affectedBodiesOnTeam = GetAffectedBodiesOnTeam(currentTeam);
						foreach (CharacterBody item in affectedBodiesOnTeam)
						{
							yield return item;
						}
						TeamIndex teamIndex = currentTeam + 1;
						currentTeam = teamIndex;
					}
					yield break;
				}
				IEnumerable<CharacterBody> affectedBodiesOnTeam2 = GetAffectedBodiesOnTeam(teamFilter.teamIndex);
				foreach (CharacterBody item2 in affectedBodiesOnTeam2)
				{
					yield return item2;
				}
				yield break;
			}
			currentTeam = TeamIndex.Neutral;
			while (currentTeam < TeamIndex.Count)
			{
				IEnumerable<CharacterBody> affectedBodiesOnTeam3 = GetAffectedBodiesOnTeam(currentTeam);
				foreach (CharacterBody item3 in affectedBodiesOnTeam3)
				{
					yield return item3;
				}
				TeamIndex teamIndex = currentTeam + 1;
				currentTeam = teamIndex;
			}
		}

		public IEnumerable<CharacterBody> GetAffectedBodiesOnTeam(TeamIndex teamIndex)
		{
			foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(teamIndex))
			{
				CharacterBody body = teamMember.body;
				bool flag = false;
				foreach (IZone safeZone in safeZones)
				{
					if (safeZone.IsInBounds(teamMember.transform.position))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					yield return body;
				}
			}
		}

		private void EvaluateTeam(TeamIndex teamIndex)
		{
			foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(teamIndex))
			{
				CharacterBody body = teamMember.body;
				bool flag = characterBodyToStacks.ContainsKey(body);
				bool flag2 = false;
				foreach (IZone safeZone in safeZones)
				{
					if (safeZone.IsInBounds(teamMember.transform.position))
					{
						flag2 = true;
						break;
					}
				}
				if (flag2)
				{
					if (flag)
					{
						characterBodyToStacks.Remove(body);
					}
				}
				else if (!flag)
				{
					characterBodyToStacks.Add(body, 1);
				}
				else
				{
					characterBodyToStacks[body]++;
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class FollowerItemDisplayComponent : MonoBehaviour
	{
		public Transform target;

		public UnityEngine.Vector3 localPosition;

		public UnityEngine.Quaternion localRotation;

		public UnityEngine.Vector3 localScale;

		private new Transform transform;

		private void Awake()
		{
			transform = base.transform;
		}

		private void LateUpdate()
		{
			if (!target)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			UnityEngine.Quaternion rotation = target.rotation;
			transform.position = target.position + rotation * localPosition;
			transform.rotation = rotation * localRotation;
			transform.localScale = localScale;
		}
	}
	[RequireComponent(typeof(ChildLocator))]
	public class FootstepHandler : MonoBehaviour
	{
		public string baseFootstepString;

		public string baseFootliftString;

		public string sprintFootstepOverrideString;

		public string sprintFootliftOverrideString;

		public bool enableFootstepDust;

		public GameObject footstepDustPrefab;

		private ChildLocator childLocator;

		private Inventory bodyInventory;

		private Animator animator;

		private Transform footstepDustInstanceTransform;

		private ParticleSystem footstepDustInstanceParticleSystem;

		private ShakeEmitter footstepDustInstanceShakeEmitter;

		private CharacterBody body;

		public bool inLava;

		private void Start()
		{
			childLocator = GetComponent<ChildLocator>();
			if ((bool)GetComponent<CharacterModel>())
			{
				body = GetComponent<CharacterModel>().body;
				bodyInventory = (body ? body.inventory : null);
			}
			animator = GetComponent<Animator>();
			if (enableFootstepDust)
			{
				footstepDustInstanceTransform = UnityEngine.Object.Instantiate(footstepDustPrefab, base.transform).transform;
				footstepDustInstanceParticleSystem = footstepDustInstanceTransform.GetComponent<ParticleSystem>();
				footstepDustInstanceShakeEmitter = footstepDustInstanceTransform.GetComponent<ShakeEmitter>();
			}
		}

		public void Update()
		{
		}

		public void Footstep(AnimationEvent animationEvent)
		{
			if ((double)animationEvent.animatorClipInfo.weight > 0.5)
			{
				Footstep(animationEvent.stringParameter, (GameObject)animationEvent.objectReferenceParameter);
			}
		}

		public void Footstep(string childName, GameObject footstepEffect)
		{
			if (!body)
			{
				return;
			}
			Transform transform = childLocator.FindChild(childName);
			int childIndex = childLocator.FindChildIndex(childName);
			if ((bool)transform)
			{
				UnityEngine.Color color = UnityEngine.Color.gray;
				RaycastHit hitInfo = default(RaycastHit);
				UnityEngine.Vector3 position = transform.position;
				position.y += 1.5f;
				if (Physics.Raycast(new Ray(position, UnityEngine.Vector3.down), out hitInfo, 4f, (int)LayerIndex.world.mask | (int)LayerIndex.water.mask, QueryTriggerInteraction.Collide))
				{
					if ((bool)bodyInventory && bodyInventory.GetItemCount(RoR2Content.Items.Hoof) > 0 && childName == "FootR")
					{
						Util.PlaySound("Play_item_proc_hoof", body.gameObject);
					}
					if ((bool)footstepEffect)
					{
						EffectData effectData = new EffectData();
						effectData.origin = hitInfo.point;
						effectData.rotation = Util.QuaternionSafeLookRotation(hitInfo.normal);
						effectData.SetChildLocatorTransformReference(body.gameObject, childIndex);
						EffectManager.SpawnEffect(footstepEffect, effectData, transmit: false);
					}
					SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitInfo.collider, hitInfo.point);
					bool flag = false;
					if ((bool)objectSurfaceDef)
					{
						body.surfaceSpeedBoost = objectSurfaceDef.speedBoost;
						color = objectSurfaceDef.approximateColor;
						if ((bool)objectSurfaceDef.footstepEffectPrefab)
						{
							EffectManager.SpawnEffect(objectSurfaceDef.footstepEffectPrefab, new EffectData
							{
								origin = hitInfo.point,
								scale = body.radius
							}, transmit: false);
							flag = true;
						}
						if (!string.IsNullOrEmpty(objectSurfaceDef.materialSwitchString))
						{
							AkSoundEngine.SetSwitch("material", objectSurfaceDef.materialSwitchString, body.gameObject);
						}
					}
					else
					{
						inLava = false;
					}
					if ((bool)footstepDustInstanceTransform && !flag)
					{
						footstepDustInstanceTransform.position = hitInfo.point;
						ParticleSystem.MainModule main = footstepDustInstanceParticleSystem.main;
						main.startColor = color;
						footstepDustInstanceParticleSystem.Play();
						if ((bool)footstepDustInstanceShakeEmitter)
						{
							footstepDustInstanceShakeEmitter.StartShake();
						}
					}
				}
				Util.PlaySound((!string.IsNullOrEmpty(sprintFootstepOverrideString) && body.isSprinting) ? sprintFootstepOverrideString : baseFootstepString, body.gameObject);
			}
			else
			{
				UnityEngine.Debug.LogWarningFormat("Object {0} lacks ChildLocator entry \"{1}\" to handle Footstep event!", base.gameObject.name, childName);
			}
		}

		public void Footlift(AnimationEvent animationEvent)
		{
			if ((double)animationEvent.animatorClipInfo.weight > 0.5)
			{
				Footlift();
			}
		}

		public void Footlift()
		{
			Util.PlaySound((!string.IsNullOrEmpty(sprintFootliftOverrideString) && body.isSprinting) ? sprintFootliftOverrideString : baseFootliftString, body.gameObject);
		}
	}
	public class ForcedCamera : MonoBehaviour, ICameraStateProvider
	{
		public float entryLerpDuration = 1f;

		public float exitLerpDuration = 1f;

		public float fovOverride;

		public bool allowUserLook;

		public bool allowUserHud;

		private void Update()
		{
			ReadOnlyCollection<CameraRigController> readOnlyInstancesList = CameraRigController.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CameraRigController cameraRigController = readOnlyInstancesList[i];
				if (!cameraRigController.hasOverride)
				{
					cameraRigController.SetOverrideCam(this, entryLerpDuration);
				}
			}
		}

		private void OnDisable()
		{
			ReadOnlyCollection<CameraRigController> readOnlyInstancesList = CameraRigController.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CameraRigController cameraRigController = readOnlyInstancesList[i];
				if (cameraRigController.IsOverrideCam(this))
				{
					cameraRigController.SetOverrideCam(null, exitLerpDuration);
				}
			}
		}

		public void GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState)
		{
			cameraState.position = base.transform.position;
			cameraState.rotation = base.transform.rotation;
			if (fovOverride > 0f)
			{
				cameraState.fov = fovOverride;
			}
		}

		public bool IsUserLookAllowed(CameraRigController cameraRigController)
		{
			return allowUserLook;
		}

		public bool IsUserControlAllowed(CameraRigController cameraRigController)
		{
			return false;
		}

		public bool IsHudAllowed(CameraRigController cameraRigController)
		{
			return allowUserHud;
		}

		private void OnDrawGizmosSelected()
		{
			UnityEngine.Color color = Gizmos.color;
			UnityEngine.Matrix4x4 matrix = Gizmos.matrix;
			Gizmos.color = UnityEngine.Color.yellow;
			UnityEngine.Matrix4x4 identity = UnityEngine.Matrix4x4.identity;
			identity.SetTRS(base.transform.position, base.transform.rotation, UnityEngine.Vector3.one);
			Gizmos.matrix = identity;
			Gizmos.DrawFrustum(UnityEngine.Vector3.zero, (fovOverride > 0f) ? fovOverride : 60f, 10f, 0.1f, 1.7777778f);
			Gizmos.matrix = matrix;
			Gizmos.color = color;
		}
	}
	public class ForceSpectate : NetworkBehaviour
	{
		[SyncVar]
		public GameObject target;

		private NetworkInstanceId ___targetNetId;

		public GameObject Networktarget
		{
			get
			{
				return target;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref target, 1u, ref ___targetNetId);
			}
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(target);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(target);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___targetNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				target = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___targetNetId.IsEmpty())
			{
				Networktarget = ClientScene.FindLocalObject(___targetNetId);
			}
		}
	}
	public class FrogController : MonoBehaviour
	{
		[SerializeField]
		private int maxPets;

		[SerializeField]
		private PortalSpawner portalSpawner;

		[SerializeField]
		private PurchaseInteraction purchaseInteraction;

		[SerializeField]
		private string petChatToken;

		private int petCount;

		public void Pet(Interactor interactor)
		{
			petCount++;
			if (!string.IsNullOrEmpty(petChatToken))
			{
				Chat.SendBroadcastChat(new SubjectChatMessage
				{
					subjectAsCharacterBody = interactor.GetComponent<CharacterBody>(),
					baseToken = petChatToken
				});
			}
			if (petCount >= maxPets && (bool)portalSpawner)
			{
				portalSpawner.AttemptSpawnPortalServer();
			}
		}
	}
	public class GameEndingController : NetworkBehaviour
	{
		private class GameEndingControllerBaseState : BaseState
		{
			protected GameEndingController gameEndingController { get; private set; }

			public override void OnEnter()
			{
				base.OnEnter();
				gameEndingController = GetComponent<GameEndingController>();
			}
		}

		private class EndingCutsceneState : GameEndingControllerBaseState
		{
		}

		private class CreditsState : GameEndingControllerBaseState
		{
		}

		private class PostGameReportState : GameEndingControllerBaseState
		{
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class EclipseRun : Run
	{
		public static int minEclipseLevel = 1;

		public static int maxEclipseLevel = 8;

		private static Dictionary<SurvivorDef, List<UnlockableDef>> survivorToEclipseUnlockables = new Dictionary<SurvivorDef, List<UnlockableDef>>();

		public static int minUnlockableEclipseLevel => minEclipseLevel + 1;

		public static DifficultyIndex GetEclipseDifficultyIndex(int eclipseLevel)
		{
			return (DifficultyIndex)(DifficultyCatalog.standardDifficultyCount - 1 + eclipseLevel);
		}

		private static List<UnlockableDef> GetEclipseLevelUnlockablesForSurvivor(SurvivorDef survivorDef)
		{
			if (!survivorToEclipseUnlockables.TryGetValue(survivorDef, out var value))
			{
				value = new List<UnlockableDef>();
				survivorToEclipseUnlockables[survivorDef] = value;
				if (BodyCatalog.GetBodyName(BodyCatalog.FindBodyIndex(survivorDef.bodyPrefab)) != null)
				{
					int num = minUnlockableEclipseLevel;
					StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
					while (true)
					{
						stringBuilder.Clear();
						stringBuilder.Append("Eclipse.").Append(survivorDef.cachedName).Append(".")
							.AppendInt(num);
						UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(stringBuilder.ToString());
						if (!unlockableDef)
						{
							break;
						}
						value.Add(unlockableDef);
						num++;
					}
					HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
				}
			}
			return value;
		}

		public static int GetLocalUserSurvivorCompletedEclipseLevel(LocalUser localUser, SurvivorDef survivorDef)
		{
			List<UnlockableDef> eclipseLevelUnlockablesForSurvivor = GetEclipseLevelUnlockablesForSurvivor(survivorDef);
			int num = 1;
			for (int i = 0; i < eclipseLevelUnlockablesForSurvivor.Count && localUser.userProfile.HasUnlockable(eclipseLevelUnlockablesForSurvivor[i]); i++)
			{
				num = minUnlockableEclipseLevel + i;
			}
			return Mathf.Clamp(num - 1, 0, maxEclipseLevel);
		}

		public static int GetNetworkUserSurvivorCompletedEclipseLevel(NetworkUser networkUser, SurvivorDef survivorDef)
		{
			List<UnlockableDef> eclipseLevelUnlockablesForSurvivor = GetEclipseLevelUnlockablesForSurvivor(survivorDef);
			int num = 1;
			for (int i = 0; i < eclipseLevelUnlockablesForSurvivor.Count && networkUser.unlockables.Contains(eclipseLevelUnlockablesForSurvivor[i]); i++)
			{
				num = minUnlockableEclipseLevel + i;
			}
			return Mathf.Clamp(num - 1, 0, maxEclipseLevel);
		}

		public static int GetEclipseLevelFromRuleBook(RuleBook ruleBook)
		{
			return (int)(ruleBook.FindDifficulty() - DifficultyCatalog.standardDifficultyCount + 1);
		}

		public override void OnClientGameOver(RunReport runReport)
		{
			base.OnClientGameOver(runReport);
			if (!runReport.gameEnding.isWin)
			{
				return;
			}
			int num = GetEclipseLevelFromRuleBook(base.ruleBook) + 1;
			ReadOnlyCollection<PlayerCharacterMasterController> instances = PlayerCharacterMasterController.instances;
			for (int i = 0; i < instances.Count; i++)
			{
				_ = instances[i];
				NetworkUser networkUser = instances[i].networkUser;
				if (!networkUser)
				{
					continue;
				}
				LocalUser localUser = networkUser.localUser;
				if (localUser == null)
				{
					continue;
				}
				SurvivorDef survivorPreference = networkUser.GetSurvivorPreference();
				if ((bool)survivorPreference)
				{
					UnlockableDef safe = ListUtils.GetSafe(GetEclipseLevelUnlockablesForSurvivor(survivorPreference), num - minUnlockableEclipseLevel);
					if ((bool)safe)
					{
						localUser.userProfile.GrantUnlockable(safe);
					}
				}
			}
		}

		public override void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed)
		{
			base.OverrideRuleChoices(mustInclude, mustExclude, base.seed);
			int num = 0;
			ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				NetworkUser networkUser = readOnlyInstancesList[i];
				SurvivorDef survivorPreference = networkUser.GetSurvivorPreference();
				if ((bool)survivorPreference)
				{
					int num2 = GetNetworkUserSurvivorCompletedEclipseLevel(networkUser, survivorPreference) + 1;
					num = ((num > 0) ? Math.Min(num, num2) : num2);
				}
			}
			num = Math.Min(num, maxEclipseLevel);
			ForceChoice(mustInclude, mustExclude, $"Difficulty.{GetEclipseDifficultyIndex(num).ToString()}");
			ForceChoice(mustInclude, mustExclude, "Items." + RoR2Content.Items.LunarTrinket.name + ".Off");
			for (int j = 0; j < ArtifactCatalog.artifactCount; j++)
			{
				ForceChoice(mustInclude, mustExclude, FindRuleForArtifact((ArtifactIndex)j).FindChoice("Off"));
			}
			static RuleDef FindRuleForArtifact(ArtifactIndex artifactIndex)
			{
				ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(artifactIndex);
				return RuleCatalog.FindRuleDef("Artifacts." + artifactDef.cachedName);
			}
		}

		protected override void HandlePostRunDestination()
		{
			Console.instance.SubmitCmd(null, "transition_command \"disconnect\";");
		}

		protected new void Start()
		{
			base.Start();
			if (NetworkServer.active)
			{
				SetEventFlag("NoArtifactWorld");
				SetEventFlag("NoMysterySpace");
				SetEventFlag("NoVoidStage");
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class InfiniteTowerRun : Run
	{
		[Serializable]
		public struct EnemyItemEntry
		{
			public PickupDropTable dropTable;

			public int stacks;
		}

		private const ulong waveRngSalt = 14312uL;

		private const ulong enemyItemRngSalt = 1535uL;

		private const ulong safeWardRngSalt = 769876uL;

		[SerializeField]
		[Header("Infinite Tower Settings")]
		[Tooltip("If all else fails, use this wave prefab")]
		private GameObject defaultWavePrefab;

		[Tooltip("Selects a wave from the first available category in this list")]
		[SerializeField]
		private InfiniteTowerWaveCategory[] waveCategories;

		[Tooltip("Use this indicator for enemies by default")]
		[SerializeField]
		private GameObject defaultWaveEnemyIndicatorPrefab;

		[Tooltip("The repeating pattern of drop tables to use when selecting items for the enemy team")]
		[SerializeField]
		private EnemyItemEntry[] enemyItemPattern;

		[SerializeField]
		[Tooltip("The number of waves before you give the enemy team the next item in the pattern (e.g., \"every Nth wave\")")]
		private int enemyItemPeriod;

		[SerializeField]
		[Tooltip("The reference inventory we use to store which items enemies should get")]
		private Inventory enemyInventory;

		[Tooltip("The number of waves before you transition to the next stage (e.g., \"every Nth wave\").")]
		[SerializeField]
		private int stageTransitionPeriod;

		[Tooltip("Spawn card for the stage transition portal")]
		[SerializeField]
		private InteractableSpawnCard stageTransitionPortalCard;

		[Tooltip("Maximum spawn distance for the stage transition portal.")]
		[SerializeField]
		private float stageTransitionPortalMaxDistance;

		[Tooltip("The chat message that's broadcasted when spawning the stage transition portal.")]
		[SerializeField]
		private string stageTransitionChatToken;

		[Tooltip("The prefab with the FogDamageController attached")]
		[SerializeField]
		private GameObject fogDamagePrefab;

		[SerializeField]
		[Tooltip("The maximum distance to spawn players from the safe ward")]
		private float spawnMaxRadius;

		[Tooltip("Spawn card for the safe ward that is spawned at the beginning of the run")]
		[SerializeField]
		private InteractableSpawnCard initialSafeWardCard;

		[Tooltip("Spawn card for the safe wards (after the first one)")]
		[SerializeField]
		private InteractableSpawnCard safeWardCard;

		[Tooltip("The effect to spawn when a player is revived at the end of a wave")]
		[SerializeField]
		private GameObject playerRespawnEffectPrefab;

		[Tooltip("The number of credits the SceneDirector uses to spawn interactables")]
		[SerializeField]
		private int interactableCredits;

		[Tooltip("Remove all items with these tags from the item pools")]
		[SerializeField]
		private ItemTag[] blacklistedTags;

		[Tooltip("Remove these items from the pool")]
		[SerializeField]
		private ItemDef[] blacklistedItems;

		[SyncVar]
		private int _waveIndex;

		[SyncVar]
		private NetworkInstanceId waveInstanceId;

		private InfiniteTowerWaveController _waveController;

		private Xoroshiro128Plus waveRng;

		private Xoroshiro128Plus enemyItemRng;

		private Xoroshiro128Plus safeWardRng;

		private int enemyItemPatternIndex;

		private InfiniteTowerSafeWardController safeWardController;

		private FogDamageController fogDamageController;

		public int waveIndex => _waveIndex;

		public InfiniteTowerWaveController waveController => _waveController;

		public override bool spawnWithPod => false;

		public override bool canFamilyEventTrigger => false;

		public override bool autoGenerateSpawnPoints => false;

		public GameObject waveInstance => Util.FindNetworkObject(waveInstanceId);

		public int Network_waveIndex
		{
			get
			{
				return _waveIndex;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _waveIndex, 64u);
			}
		}

		public NetworkInstanceId NetworkwaveInstanceId
		{
			get
			{
				return waveInstanceId;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref waveInstanceId, 128u);
			}
		}

		public static event Action<InfiniteTowerWaveController> onWaveInitialized;

		public static event Action<InfiniteTowerWaveController> onAllEnemiesDefeatedServer;

		public override GameObject InstantiateUi(Transform uiRoot)
		{
			GameObject gameObject = base.InstantiateUi(uiRoot);
			if ((bool)_waveController)
			{
				_waveController.InstantiateUi(gameObject.transform);
			}
			return gameObject;
		}

		public override void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed)
		{
			base.OverrideRuleChoices(mustInclude, mustExclude, base.seed);
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
				bool flag = Array.IndexOf(blacklistedItems, itemDef) != -1;
				if (!flag)
				{
					ItemTag[] array = blacklistedTags;
					foreach (ItemTag itemTag in array)
					{
						if (itemDef.ContainsTag(itemTag))
						{
							flag = true;
							break;
						}
					}
				}
				if (flag)
				{
					RuleChoiceDef ruleChoiceDef = RuleCatalog.FindRuleDef("Items." + itemDef.name)?.FindChoice("Off");
					if (ruleChoiceDef != null)
					{
						ForceChoice(mustInclude, mustExclude, ruleChoiceDef);
					}
				}
			}
		}

		[Server]
		public void ResetSafeWard()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::ResetSafeWard()' called on client");
				return;
			}
			if ((bool)safeWardController)
			{
				if ((bool)fogDamageController)
				{
					fogDamageController.RemoveSafeZone(safeWardController.safeZone);
				}
				safeWardController.SelfDestruct();
			}
			SpawnSafeWard(safeWardCard, new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Random
			});
		}

		[Server]
		public void MoveSafeWard()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::MoveSafeWard()' called on client");
			}
			else if ((bool)safeWardController)
			{
				safeWardController.RandomizeLocation(safeWardRng);
				safeWardController.onActivated += OnSafeWardActivated;
			}
		}

		public bool IsStageTransitionWave()
		{
			if (stageTransitionPeriod != 0)
			{
				return waveIndex % stageTransitionPeriod == 0;
			}
			return true;
		}

		public override UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination)
		{
			if ((bool)safeWardController && !targetDestination)
			{
				return base.FindSafeTeleportPosition(characterBody, safeWardController.transform);
			}
			return base.FindSafeTeleportPosition(characterBody, targetDestination);
		}

		public override UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination, float idealMinDistance, float idealMaxDistance)
		{
			if ((bool)safeWardController && !targetDestination)
			{
				return base.FindSafeTeleportPosition(characterBody, safeWardController.transform, idealMinDistance, idealMaxDistance);
			}
			return base.FindSafeTeleportPosition(characterBody, targetDestination, idealMinDistance, idealMaxDistance);
		}

		[Server]
		private void OnSafeWardActivated(InfiniteTowerSafeWardController safeWard)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::OnSafeWardActivated(RoR2.InfiniteTowerSafeWardController)' called on client");
				return;
			}
			safeWardController.onActivated -= OnSafeWardActivated;
			if ((bool)_waveController)
			{
				_waveController.ForceFinish();
				CleanUpCurrentWave();
			}
			BeginNextWave();
		}

		[Server]
		private void AdvanceWave()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::AdvanceWave()' called on client");
				return;
			}
			Network_waveIndex = _waveIndex + 1;
			if (_waveIndex % enemyItemPeriod != 0)
			{
				return;
			}
			EnemyItemEntry enemyItemEntry = enemyItemPattern[enemyItemPatternIndex++ % enemyItemPattern.Length];
			if (!enemyItemEntry.dropTable)
			{
				return;
			}
			PickupIndex pickupIndex = enemyItemEntry.dropTable.GenerateDrop(enemyItemRng);
			if (pickupIndex != PickupIndex.none)
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
				if (pickupDef != null)
				{
					enemyInventory.GiveItem(pickupDef.itemIndex, enemyItemEntry.stacks);
					Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage
					{
						baseToken = "INFINITETOWER_ADD_ITEM",
						pickupToken = pickupDef.nameToken,
						pickupColor = pickupDef.baseColor
					});
				}
			}
		}

		[Server]
		private void BeginNextWave()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::BeginNextWave()' called on client");
				return;
			}
			AdvanceWave();
			GameObject original = defaultWavePrefab;
			InfiniteTowerWaveCategory[] array = waveCategories;
			foreach (InfiniteTowerWaveCategory infiniteTowerWaveCategory in array)
			{
				if (infiniteTowerWaveCategory.IsAvailable(this))
				{
					original = infiniteTowerWaveCategory.SelectWavePrefab(this, waveRng);
					break;
				}
			}
			GameObject gameObject = UnityEngine.Object.Instantiate(original, base.transform);
			NetworkServer.Spawn(gameObject);
			NetworkwaveInstanceId = gameObject.GetComponent<NetworkIdentity>().netId;
			RecalculateDifficultyCoefficentInternal();
		}

		protected override void Start()
		{
			Stage.onServerStageBegin += OnServerStageBegin;
			Stage.onServerStageComplete += OnServerStageComplete;
			SceneDirector.onPrePopulateSceneServer += OnPrePopulateSceneServer;
			base.Start();
		}

		protected override void OnDestroy()
		{
			Stage.onServerStageBegin -= OnServerStageBegin;
			Stage.onServerStageComplete -= OnServerStageComplete;
			SceneDirector.onPrePopulateSceneServer -= OnPrePopulateSceneServer;
			if ((bool)safeWardController)
			{
				UnityEngine.Object.Destroy(safeWardController.gameObject);
				safeWardController = null;
			}
			CleanUpCurrentWave();
			base.OnDestroy();
		}

		private void OnServerStageBegin(Stage stage)
		{
		}

		private void OnServerStageComplete(Stage stage)
		{
			PerformStageCleanUp();
		}

		private void OnPrePopulateSceneServer(SceneDirector sceneDirector)
		{
			PerformStageCleanUp();
			if ((bool)fogDamagePrefab)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(fogDamagePrefab, Stage.instance.transform);
				NetworkServer.Spawn(gameObject);
				fogDamageController = gameObject.GetComponent<FogDamageController>();
			}
			sceneDirector.interactableCredit = interactableCredits;
			DirectorPlacementRule placementRule = new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Random
			};
			SpawnSafeWard(initialSafeWardCard, placementRule);
			if (!safeWardController)
			{
				return;
			}
			UnityEngine.Vector3 position = safeWardController.transform.position;
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			foreach (NodeGraph.NodeIndex item in nodeGraph.FindNodesInRangeWithFlagConditions(position, 0f, spawnMaxRadius, HullMask.Human, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false))
			{
				if (nodeGraph.GetNodePosition(item, out var position2))
				{
					SpawnPoint.AddSpawnPoint(position2, UnityEngine.Quaternion.LookRotation(position, UnityEngine.Vector3.up));
				}
			}
		}

		protected override void FixedUpdate()
		{
			base.FixedUpdate();
			if (NetworkServer.active && (bool)waveInstance && (bool)waveController && waveController.isFinished && !IsStageTransitionWave())
			{
				CleanUpCurrentWave();
				BeginNextWave();
			}
			if ((bool)waveInstance)
			{
				if (!_waveController)
				{
					InitializeWaveController();
				}
			}
			else
			{
				_waveController = null;
			}
		}

		protected override void RecalculateDifficultyCoefficentInternal()
		{
			DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(base.selectedDifficulty);
			float num = 1.5f * (float)waveIndex;
			float num2 = 0.0506f * difficultyDef.scalingValue;
			float num3 = Mathf.Pow(1.02f, waveIndex);
			difficultyCoefficient = (1f + num2 * num) * num3;
			compensatedDifficultyCoefficient = difficultyCoefficient;
			base.ambientLevel = Mathf.Min((difficultyCoefficient - 1f) / 0.33f + 1f, 9999f);
			int num4 = base.ambientLevelFloor;
			base.ambientLevelFloor = Mathf.FloorToInt(base.ambientLevel);
			if (num4 != base.ambientLevelFloor && num4 != 0 && base.ambientLevelFloor > num4)
			{
				OnAmbientLevelUp();
			}
		}

		private void InitializeWaveController()
		{
			_waveController = waveInstance.GetComponent<InfiniteTowerWaveController>();
			if (!_waveController)
			{
				return;
			}
			if (NetworkServer.active)
			{
				_waveController.Initialize(_waveIndex, enemyInventory, safeWardController.gameObject);
			}
			foreach (GameObject uiInstance in base.uiInstances)
			{
				_waveController.InstantiateUi(uiInstance.transform);
			}
			_waveController.PlayBeginSound();
			_waveController.defaultEnemyIndicatorPrefab = defaultWaveEnemyIndicatorPrefab;
			_waveController.onAllEnemiesDefeatedServer += OnWaveAllEnemiesDefeatedServer;
			InfiniteTowerRun.onWaveInitialized?.Invoke(_waveController);
		}

		private void OnWaveAllEnemiesDefeatedServer(InfiniteTowerWaveController wc)
		{
			InfiniteTowerRun.onAllEnemiesDefeatedServer?.Invoke(wc);
			if (base.isGameOverServer)
			{
				return;
			}
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (!instance.isConnected || !master.IsDeadAndOutOfLivesServer())
				{
					continue;
				}
				UnityEngine.Vector3 vector = master.deathFootPosition;
				if ((bool)safeWardController)
				{
					vector = TeleportHelper.FindSafeTeleportDestination(safeWardController.transform.position, master.bodyPrefab.GetComponent<CharacterBody>(), RoR2Application.rng) ?? vector;
				}
				master.Respawn(vector, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f));
				CharacterBody body = master.GetBody();
				if ((bool)body)
				{
					body.AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
					EntityStateMachine[] components = body.GetComponents<EntityStateMachine>();
					foreach (EntityStateMachine obj in components)
					{
						obj.initialStateType = obj.mainStateType;
					}
					if ((bool)playerRespawnEffectPrefab)
					{
						EffectManager.SpawnEffect(playerRespawnEffectPrefab, new EffectData
						{
							origin = vector,
							rotation = body.transform.rotation
						}, transmit: true);
					}
				}
			}
			if (IsStageTransitionWave())
			{
				PickNextStageSceneFromCurrentSceneDestinations();
				DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(stageTransitionPortalCard, new DirectorPlacementRule
				{
					minDistance = 0f,
					maxDistance = stageTransitionPortalMaxDistance,
					placementMode = DirectorPlacementRule.PlacementMode.Approximate,
					position = safeWardController.transform.position,
					spawnOnTarget = safeWardController.transform
				}, safeWardRng));
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = stageTransitionChatToken
				});
				if ((bool)safeWardController)
				{
					safeWardController.WaitForPortal();
				}
			}
		}

		protected override bool ShouldUpdateRunStopwatch()
		{
			return true;
		}

		protected override void OnSeedSet()
		{
			waveRng = new Xoroshiro128Plus(base.seed ^ 0x37E8);
			enemyItemRng = new Xoroshiro128Plus(base.seed ^ 0x5FF);
			safeWardRng = new Xoroshiro128Plus(base.seed ^ 0xBBF54);
		}

		private void CleanUpCurrentWave()
		{
			if ((bool)_waveController)
			{
				_waveController.onAllEnemiesDefeatedServer -= OnWaveAllEnemiesDefeatedServer;
				_waveController = null;
			}
			if ((bool)waveInstance)
			{
				UnityEngine.Object.Destroy(waveInstance);
			}
			NetworkwaveInstanceId = NetworkInstanceId.Invalid;
		}

		private void SpawnSafeWard(InteractableSpawnCard spawnCard, DirectorPlacementRule placementRule)
		{
			GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, placementRule, safeWardRng));
			if ((bool)gameObject)
			{
				NetworkServer.Spawn(gameObject);
				safeWardController = gameObject.GetComponent<InfiniteTowerSafeWardController>();
				if ((bool)safeWardController)
				{
					safeWardController.onActivated += OnSafeWardActivated;
				}
				HoldoutZoneController component = gameObject.GetComponent<HoldoutZoneController>();
				if ((bool)component)
				{
					component.calcAccumulatedCharge += CalcHoldoutZoneCharge;
				}
				if ((bool)fogDamageController)
				{
					fogDamageController.AddSafeZone(safeWardController.safeZone);
				}
			}
			else
			{
				UnityEngine.Debug.LogError("Unable to spawn safe ward instance.  Are there any ground nodes?");
			}
		}

		private void CalcHoldoutZoneCharge(ref float charge)
		{
			if ((bool)waveController)
			{
				float num = waveController.GetNormalizedProgress();
				if (waveController.GetSquadCount() > 0)
				{
					num = Mathf.Min(num, 0.99f);
				}
				charge = num;
			}
			else
			{
				charge = 0f;
			}
		}

		[Server]
		public override void HandlePlayerFirstEntryAnimation(CharacterBody body, UnityEngine.Vector3 spawnPosition, UnityEngine.Quaternion spawnRotation)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerRun::HandlePlayerFirstEntryAnimation(RoR2.CharacterBody,UnityEngine.Vector3,UnityEngine.Quaternion)' called on client");
			}
			else
			{
				body.SetBodyStateToPreferredInitialState();
			}
		}

		private void PerformStageCleanUp()
		{
			safeWardController = null;
			if ((bool)fogDamageController)
			{
				UnityEngine.Object.Destroy(fogDamageController.gameObject);
			}
			CleanUpCurrentWave();
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)_waveIndex);
				writer.Write(waveInstanceId);
				return true;
			}
			bool flag2 = false;
			if ((base.syncVarDirtyBits & 0x40u) != 0)
			{
				if (!flag2)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag2 = true;
				}
				writer.WritePackedUInt32((uint)_waveIndex);
			}
			if ((base.syncVarDirtyBits & 0x80u) != 0)
			{
				if (!flag2)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag2 = true;
				}
				writer.Write(waveInstanceId);
			}
			if (!flag2)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
			if (initialState)
			{
				_waveIndex = (int)reader.ReadPackedUInt32();
				waveInstanceId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & 0x40u) != 0)
			{
				_waveIndex = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x80u) != 0)
			{
				waveInstanceId = reader.ReadNetworkId();
			}
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[DisallowMultipleComponent]
	[RequireComponent(typeof(NetworkRuleBook))]
	[RequireComponent(typeof(RunArtifactManager))]
	public class Run : NetworkBehaviour
	{
		[Serializable]
		public struct RunStopwatch : IEquatable<RunStopwatch>
		{
			public float offsetFromFixedTime;

			public bool isPaused;

			public bool Equals(RunStopwatch other)
			{
				if (offsetFromFixedTime.Equals(other.offsetFromFixedTime))
				{
					return isPaused == other.isPaused;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is RunStopwatch other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (offsetFromFixedTime.GetHashCode() * 397) ^ isPaused.GetHashCode();
			}
		}

		[Serializable]
		public struct TimeStamp : IEquatable<TimeStamp>, IComparable<TimeStamp>
		{
			public readonly float t;

			private static float tNow;

			public static readonly TimeStamp zero;

			public static readonly TimeStamp positiveInfinity;

			public static readonly TimeStamp negativeInfinity;

			public float timeUntil => t - tNow;

			public float timeSince => tNow - t;

			public float timeUntilClamped => Mathf.Max(timeUntil, 0f);

			public float timeSinceClamped => Mathf.Max(timeSince, 0f);

			public bool hasPassed => t <= tNow;

			public bool isInfinity => float.IsInfinity(t);

			public bool isPositiveInfinity => float.IsPositiveInfinity(t);

			public bool isNegativeInfinity => float.IsNegativeInfinity(t);

			public static TimeStamp now => new TimeStamp(tNow);

			public override int GetHashCode()
			{
				return t.GetHashCode();
			}

			public static void Update()
			{
				tNow = instance.time;
			}

			private TimeStamp(float t)
			{
				this.t = t;
			}

			public bool Equals(TimeStamp other)
			{
				return t.Equals(other.t);
			}

			public override bool Equals(object obj)
			{
				if (obj is TimeStamp)
				{
					return Equals((TimeStamp)obj);
				}
				return false;
			}

			public int CompareTo(TimeStamp other)
			{
				return t.CompareTo(other.t);
			}

			public static TimeStamp operator +(TimeStamp a, float b)
			{
				return new TimeStamp(a.t + b);
			}

			public static TimeStamp operator -(TimeStamp a, float b)
			{
				return new TimeStamp(a.t - b);
			}

			public static float operator -(TimeStamp a, TimeStamp b)
			{
				return a.t - b.t;
			}

			public static bool operator <(TimeStamp a, TimeStamp b)
			{
				return a.t < b.t;
			}

			public static bool operator >(TimeStamp a, TimeStamp b)
			{
				return a.t > b.t;
			}

			public static bool operator <=(TimeStamp a, TimeStamp b)
			{
				return a.t <= b.t;
			}

			public static bool operator >=(TimeStamp a, TimeStamp b)
			{
				return a.t >= b.t;
			}

			public static bool operator ==(TimeStamp a, TimeStamp b)
			{
				return a.Equals(b);
			}

			public static bool operator !=(TimeStamp a, TimeStamp b)
			{
				return !a.Equals(b);
			}

			public static float operator -(TimeStamp a, FixedTimeStamp b)
			{
				return a.t - b.t;
			}

			public static TimeStamp Deserialize(NetworkReader reader)
			{
				return new TimeStamp(reader.ReadSingle());
			}

			public static void Serialize(NetworkWriter writer, TimeStamp timeStamp)
			{
				writer.Write(timeStamp.t);
			}

			public static void ToXml(XElement element, TimeStamp src)
			{
				element.Value = TextSerialization.ToStringInvariant(src.t);
			}

			public static bool FromXml(XElement element, ref TimeStamp dest)
			{
				if (TextSerialization.TryParseInvariant(element.Value, out float result))
				{
					dest = new TimeStamp(result);
					return true;
				}
				return false;
			}

			static TimeStamp()
			{
				zero = new TimeStamp(0f);
				positiveInfinity = new TimeStamp(float.PositiveInfinity);
				negativeInfinity = new TimeStamp(float.NegativeInfinity);
				HGXml.Register<TimeStamp>(ToXml, FromXml);
			}
		}

		[Serializable]
		public struct FixedTimeStamp : IEquatable<FixedTimeStamp>, IComparable<FixedTimeStamp>
		{
			public readonly float t;

			private static float tNow;

			public static readonly FixedTimeStamp zero;

			public static readonly FixedTimeStamp positiveInfinity;

			public static readonly FixedTimeStamp negativeInfinity;

			public float timeUntil => t - tNow;

			public float timeSince => tNow - t;

			public float timeUntilClamped => Mathf.Max(timeUntil, 0f);

			public float timeSinceClamped => Mathf.Max(timeSince, 0f);

			public bool hasPassed => t <= tNow;

			public bool isInfinity => float.IsInfinity(t);

			public bool isPositiveInfinity => float.IsPositiveInfinity(t);

			public bool isNegativeInfinity => float.IsNegativeInfinity(t);

			public static FixedTimeStamp now => new FixedTimeStamp(tNow);

			public override int GetHashCode()
			{
				return t.GetHashCode();
			}

			public static void Update()
			{
				tNow = instance.fixedTime;
			}

			private FixedTimeStamp(float t)
			{
				this.t = t;
			}

			public bool Equals(FixedTimeStamp other)
			{
				return t.Equals(other.t);
			}

			public override bool Equals(object obj)
			{
				if (obj is FixedTimeStamp)
				{
					return Equals((FixedTimeStamp)obj);
				}
				return false;
			}

			public int CompareTo(FixedTimeStamp other)
			{
				return t.CompareTo(other.t);
			}

			public static FixedTimeStamp operator +(FixedTimeStamp a, float b)
			{
				return new FixedTimeStamp(a.t + b);
			}

			public static FixedTimeStamp operator -(FixedTimeStamp a, float b)
			{
				return new FixedTimeStamp(a.t - b);
			}

			public static float operator -(FixedTimeStamp a, FixedTimeStamp b)
			{
				return a.t - b.t;
			}

			public static bool operator <(FixedTimeStamp a, FixedTimeStamp b)
			{
				return a.t < b.t;
			}

			public static bool operator >(FixedTimeStamp a, FixedTimeStamp b)
			{
				return a.t > b.t;
			}

			public static bool operator <=(FixedTimeStamp a, FixedTimeStamp b)
			{
				return a.t <= b.t;
			}

			public static bool operator >=(FixedTimeStamp a, FixedTimeStamp b)
			{
				return a.t >= b.t;
			}

			public static bool operator ==(FixedTimeStamp a, FixedTimeStamp b)
			{
				return a.Equals(b);
			}

			public static bool operator !=(FixedTimeStamp a, FixedTimeStamp b)
			{
				return !a.Equals(b);
			}

			public static FixedTimeStamp Deserialize(NetworkReader reader)
			{
				return new FixedTimeStamp(reader.ReadSingle());
			}

			public static void Serialize(NetworkWriter writer, FixedTimeStamp timeStamp)
			{
				writer.Write(timeStamp.t);
			}

			public static void ToXml(XElement element, FixedTimeStamp src)
			{
				element.Value = TextSerialization.ToStringInvariant(src.t);
			}

			public static bool FromXml(XElement element, ref FixedTimeStamp dest)
			{
				if (TextSerialization.TryParseInvariant(element.Value, out float result))
				{
					dest = new FixedTimeStamp(result);
					return true;
				}
				return false;
			}

			static FixedTimeStamp()
			{
				zero = new FixedTimeStamp(0f);
				positiveInfinity = new FixedTimeStamp(float.PositiveInfinity);
				negativeInfinity = new FixedTimeStamp(float.NegativeInfinity);
				HGXml.Register<FixedTimeStamp>(ToXml, FromXml);
			}
		}

		private NetworkRuleBook networkRuleBookComponent;

		[Tooltip("This is assigned to the prefab automatically by GameModeCatalog at runtime. Do not set this value manually.")]
		[HideInInspector]
		public GameModeIndex gameModeIndex = GameModeIndex.Invalid;

		public string nameToken = "";

		[Tooltip("Whether or not the user can select this game mode for play in the game mode selector UI.")]
		public bool userPickable = true;

		[Tooltip("Dictates items given when rebirth is active when the user doesn't have a stored item.")]
		public PickupDropTable rebirthDropTable;

		public static int stagesPerLoop = 5;

		public static float baseGravity = -30f;

		[SyncVar]
		private NetworkGuid _uniqueId;

		[SyncVar]
		private NetworkDateTime startTimeUtc;

		[ShowFieldObsolete]
		[Obsolete("Use startingSceneGroup instead.")]
		[Tooltip("The pool of scenes to select the first scene of the run from.")]
		public SceneDef[] startingScenes = Array.Empty<SceneDef>();

		[Tooltip("The pool of scenes to select the first scene of the run from.")]
		public SceneCollection startingSceneGroup;

		public ItemMask availableItems;

		public ItemMask expansionLockedItems;

		public EquipmentMask availableEquipment;

		public EquipmentMask expansionLockedEquipment;

		public bool isRunWeekly;

		[SyncVar]
		public float fixedTime;

		public float time;

		[HideInInspector]
		public bool isRunning;

		[SyncVar]
		private RunStopwatch runStopwatch;

		[SyncVar]
		public int stageClearCount;

		public SceneDef nextStageScene;

		public SceneDef[] blacklistedScenesForFirstScene = Array.Empty<SceneDef>();

		public GameObject gameOverPrefab;

		public GameObject lobbyBackgroundPrefab;

		public GameObject uiPrefab;

		private ulong _seed;

		public Xoroshiro128Plus runRNG;

		public Xoroshiro128Plus nextStageRng;

		public Xoroshiro128Plus stageRngGenerator;

		public Xoroshiro128Plus stageRng;

		public Xoroshiro128Plus bossRewardRng;

		public Xoroshiro128Plus treasureRng;

		public Xoroshiro128Plus spawnRng;

		public Xoroshiro128Plus randomSurvivorOnRespawnRng;

		public float difficultyCoefficient = 1f;

		public float compensatedDifficultyCoefficient = 1f;

		public float oneOverCompensatedDifficultyCoefficientSquared = 1f;

		[SyncVar]
		private int selectedDifficultyInternal = 1;

		public int shopPortalCount;

		private static int ambientLevelCap = 99;

		private bool lowerPricedChestsTimerOn;

		private float lowerPricedChestsTimer;

		private float lowerPricedChestsDuration = 10f;

		private static readonly StringConVar cvRunSceneOverride = new StringConVar("run_scene_override", ConVarFlags.Cheat, "", "Overrides the first scene to enter in a run.");

		private readonly HashSet<UnlockableDef> unlockablesUnlockedByAnyUser = new HashSet<UnlockableDef>();

		private readonly HashSet<UnlockableDef> unlockablesUnlockedByAllUsers = new HashSet<UnlockableDef>();

		private readonly HashSet<UnlockableDef> unlockablesAlreadyFullyObtained = new HashSet<UnlockableDef>();

		private bool shutdown;

		private Dictionary<NetworkUserId, CharacterMaster> userMasters = new Dictionary<NetworkUserId, CharacterMaster>();

		private bool allowNewParticipants;

		public readonly List<PickupIndex> availableTier1DropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableTier2DropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableTier3DropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableEquipmentDropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableLunarEquipmentDropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableLunarItemDropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableLunarCombinedDropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableBossDropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableVoidTier1DropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableVoidTier2DropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableVoidTier3DropList = new List<PickupIndex>();

		public readonly List<PickupIndex> availableVoidBossDropList = new List<PickupIndex>();

		public WeightedSelection<List<PickupIndex>> smallChestDropTierSelector = new WeightedSelection<List<PickupIndex>>();

		public WeightedSelection<List<PickupIndex>> mediumChestDropTierSelector = new WeightedSelection<List<PickupIndex>>();

		public WeightedSelection<List<PickupIndex>> largeChestDropTierSelector = new WeightedSelection<List<PickupIndex>>();

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

		public static Run instance { get; private set; }

		public RuleBook ruleBook => networkRuleBookComponent.ruleBook;

		public bool isRunStopwatchPaused => runStopwatch.isPaused;

		public virtual int loopClearCount => stageClearCount / stagesPerLoop;

		public virtual bool spawnWithPod => instance.stageClearCount == 0;

		public virtual bool autoGenerateSpawnPoints => true;

		public virtual bool canFamilyEventTrigger => true;

		public IList<GameObject> uiInstances { get; protected set; } = new List<GameObject>();


		public ulong seed
		{
			get
			{
				return _seed;
			}
			set
			{
				_seed = value;
				OnSeedSet();
			}
		}

		public DifficultyIndex selectedDifficulty
		{
			get
			{
				return (DifficultyIndex)selectedDifficultyInternal;
			}
			set
			{
				NetworkselectedDifficultyInternal = (int)value;
			}
		}

		public int livingPlayerCount => PlayerCharacterMasterController.GetPlayersWithBodiesCount();

		public int participatingPlayerCount => PlayerCharacterMasterController.instances.Count;

		public float ambientLevel { get; protected set; }

		public int ambientLevelFloor { get; protected set; }

		public float teamlessDamageCoefficient => difficultyCoefficient;

		public bool isGameOverServer { get; private set; }

		public NetworkGuid Network_uniqueId
		{
			get
			{
				return _uniqueId;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _uniqueId, 1u);
			}
		}

		public NetworkDateTime NetworkstartTimeUtc
		{
			get
			{
				return startTimeUtc;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref startTimeUtc, 2u);
			}
		}

		public float NetworkfixedTime
		{
			get
			{
				return fixedTime;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref fixedTime, 4u);
			}
		}

		public RunStopwatch NetworkrunStopwatch
		{
			get
			{
				return runStopwatch;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref runStopwatch, 8u);
			}
		}

		public int NetworkstageClearCount
		{
			get
			{
				return stageClearCount;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref stageClearCount, 16u);
			}
		}

		public int NetworkselectedDifficultyInternal
		{
			get
			{
				return selectedDifficultyInternal;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref selectedDifficultyInternal, 32u);
			}
		}

		public static event Action<Run, RuleBook> onServerRunSetRuleBookGlobal;

		public static event Action<Run, RuleBook> onRunSetRuleBookGlobal;

		public static event Action<Run> onRunAmbientLevelUp;

		public static event Action<Run, PlayerCharacterMasterController> onPlayerFirstCreatedServer;

		public static event Action<Run, GameEndingDef> onServerGameOver;

		public static event Action<Run, RunReport> onClientGameOverGlobal;

		public static event Action<Run> onRunStartGlobal;

		public static event Action<Run> onRunDestroyGlobal;

		public static event Action<Run> onAvailablePickupsModified;

		protected virtual void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		protected virtual void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			if (instance == null)
			{
				RewiredIntegrationManager.RefreshAfterRunFinish();
			}
		}

		protected void Awake()
		{
			networkRuleBookComponent = GetComponent<NetworkRuleBook>();
			networkRuleBookComponent.onRuleBookUpdated += OnRuleBookUpdated;
			availableItems = ItemMask.Rent();
			expansionLockedItems = ItemMask.Rent();
			availableEquipment = EquipmentMask.Rent();
			expansionLockedEquipment = EquipmentMask.Rent();
			if (NetworkServer.active)
			{
				Network_uniqueId = (NetworkGuid)Guid.NewGuid();
				NetworkstartTimeUtc = (NetworkDateTime)DateTime.UtcNow;
			}
		}

		[Server]
		public void SetRuleBook(RuleBook newRuleBook)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetRuleBook(RoR2.RuleBook)' called on client");
			}
			else
			{
				networkRuleBookComponent.SetRuleBook(newRuleBook);
			}
		}

		private void OnRuleBookUpdated(NetworkRuleBook networkRuleBookComponent)
		{
			RuleBook ruleBook = networkRuleBookComponent.ruleBook;
			selectedDifficulty = ruleBook.FindDifficulty();
			ruleBook.GenerateItemMask(availableItems);
			ruleBook.GenerateEquipmentMask(availableEquipment);
			expansionLockedItems.Clear();
			foreach (ItemDef allItemDef in ItemCatalog.allItemDefs)
			{
				if ((bool)allItemDef && (bool)allItemDef.requiredExpansion && !IsExpansionEnabled(allItemDef.requiredExpansion))
				{
					expansionLockedItems.Add(allItemDef.itemIndex);
				}
			}
			expansionLockedEquipment.Clear();
			foreach (EquipmentIndex item in EquipmentCatalog.allEquipment)
			{
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(item);
				if ((bool)equipmentDef && (bool)equipmentDef.requiredExpansion && !IsExpansionEnabled(equipmentDef.requiredExpansion))
				{
					expansionLockedEquipment.Add(equipmentDef.equipmentIndex);
				}
			}
			if (NetworkServer.active)
			{
				Run.onServerRunSetRuleBookGlobal?.Invoke(this, ruleBook);
			}
			Run.onRunSetRuleBookGlobal?.Invoke(this, ruleBook);
		}

		public Guid GetUniqueId()
		{
			return (Guid)_uniqueId;
		}

		public DateTime GetStartTimeUtc()
		{
			return (DateTime)startTimeUtc;
		}

		[Server]
		private void SetRunStopwatchPaused(bool isPaused)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetRunStopwatchPaused(System.Boolean)' called on client");
			}
			else if (isPaused != runStopwatch.isPaused)
			{
				RunStopwatch networkrunStopwatch = runStopwatch;
				networkrunStopwatch.isPaused = isPaused;
				float num = GetRunStopwatch();
				if (isPaused)
				{
					networkrunStopwatch.offsetFromFixedTime = num;
				}
				else
				{
					networkrunStopwatch.offsetFromFixedTime = num - fixedTime;
				}
				NetworkrunStopwatch = networkrunStopwatch;
			}
		}

		public float GetRunStopwatch()
		{
			if (runStopwatch.isPaused)
			{
				return runStopwatch.offsetFromFixedTime;
			}
			return fixedTime + runStopwatch.offsetFromFixedTime;
		}

		[Server]
		public void SetRunStopwatch(float t)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetRunStopwatch(System.Single)' called on client");
				return;
			}
			RunStopwatch networkrunStopwatch = runStopwatch;
			if (networkrunStopwatch.isPaused)
			{
				networkrunStopwatch.offsetFromFixedTime = t;
			}
			else
			{
				networkrunStopwatch.offsetFromFixedTime = t - fixedTime;
			}
			NetworkrunStopwatch = networkrunStopwatch;
		}

		public virtual GameObject InstantiateUi(Transform uiRoot)
		{
			GameObject gameObject = null;
			if ((bool)uiRoot && (bool)uiPrefab)
			{
				gameObject = UnityEngine.Object.Instantiate(uiPrefab, uiRoot);
				uiInstances.Add(gameObject);
			}
			return gameObject;
		}

		public void UnregisterUi(GameObject uiInstance)
		{
			uiInstances.Remove(uiInstance);
		}

		private void GenerateStageRNG()
		{
			stageRng = new Xoroshiro128Plus(stageRngGenerator.nextUlong);
			bossRewardRng = new Xoroshiro128Plus(stageRng.nextUlong);
			treasureRng = new Xoroshiro128Plus(stageRng.nextUlong);
			spawnRng = new Xoroshiro128Plus(stageRng.nextUlong);
			randomSurvivorOnRespawnRng = new Xoroshiro128Plus(stageRng.nextUlong);
		}

		protected void OnAmbientLevelUp()
		{
			Run.onRunAmbientLevelUp?.Invoke(this);
		}

		protected virtual void FixedUpdate()
		{
			NetworkfixedTime = fixedTime + Time.fixedDeltaTime;
			FixedTimeStamp.Update();
			if (NetworkServer.active)
			{
				SetRunStopwatchPaused(!ShouldUpdateRunStopwatch());
			}
			OnFixedUpdate();
		}

		public void RecalculateDifficultyCoefficent()
		{
			RecalculateDifficultyCoefficentInternal();
		}

		protected virtual void RecalculateDifficultyCoefficentInternal()
		{
			float num = GetRunStopwatch();
			DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(selectedDifficulty);
			float num2 = Mathf.Floor(num * (1f / 60f));
			float num3 = (float)participatingPlayerCount * 0.3f;
			float num4 = 0.7f + num3;
			float num5 = 0.7f + num3;
			float num6 = Mathf.Pow(participatingPlayerCount, 0.2f);
			float num7 = 0.0506f * difficultyDef.scalingValue * num6;
			float num8 = 0.0506f * difficultyDef.scalingValue * num6;
			float num9 = Mathf.Pow(1.15f, stageClearCount);
			compensatedDifficultyCoefficient = (num5 + num8 * num2) * num9;
			difficultyCoefficient = (num4 + num7 * num2) * num9;
			oneOverCompensatedDifficultyCoefficientSquared = 1f / (compensatedDifficultyCoefficient * compensatedDifficultyCoefficient);
			float num10 = (num4 + num7 * (num * (1f / 60f))) * Mathf.Pow(1.15f, stageClearCount);
			ambientLevel = Mathf.Min((num10 - num4) / 0.33f + 1f, ambientLevelCap);
			int num11 = ambientLevelFloor;
			ambientLevelFloor = Mathf.FloorToInt(ambientLevel);
			if (num11 != ambientLevelFloor && num11 != 0 && ambientLevelFloor > num11)
			{
				OnAmbientLevelUp();
			}
		}

		private void InitializeTimeStamps()
		{
			NetworkfixedTime = 0f;
			time = 0f;
			FixedTimeStamp.Update();
			TimeStamp.Update();
		}

		protected virtual void OnFixedUpdate()
		{
			RecalculateDifficultyCoefficent();
		}

		public bool GetLowerPricedChestsTimer()
		{
			return lowerPricedChestsTimerOn;
		}

		protected void Update()
		{
			time = Mathf.Clamp(time + Time.deltaTime, fixedTime, fixedTime + Time.fixedDeltaTime);
			TimeStamp.Update();
			if ((double)GetRunStopwatch() - Math.Floor(GetRunStopwatch() * (1f / 60f)) * 60.0 <= 0.1 && !lowerPricedChestsTimerOn)
			{
				lowerPricedChestsTimerOn = true;
			}
			if (lowerPricedChestsTimerOn)
			{
				lowerPricedChestsTimer += Time.fixedDeltaTime;
			}
			if (lowerPricedChestsTimer >= lowerPricedChestsDuration)
			{
				lowerPricedChestsTimerOn = false;
				lowerPricedChestsTimer = 0f;
			}
		}

		protected virtual bool ShouldUpdateRunStopwatch()
		{
			SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef;
			if (mostRecentSceneDef.sceneType != SceneType.Stage && mostRecentSceneDef.sceneType != SceneType.TimedIntermission)
			{
				return false;
			}
			return livingPlayerCount > 0;
		}

		[Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)]
		[Server]
		public bool CanUnlockableBeGrantedThisRun(string unlockableName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::CanUnlockableBeGrantedThisRun(System.String)' called on client");
				return false;
			}
			return CanUnlockableBeGrantedThisRun(UnlockableCatalog.GetUnlockableDef(unlockableName));
		}

		[Server]
		public virtual bool CanUnlockableBeGrantedThisRun(UnlockableDef unlockableDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::CanUnlockableBeGrantedThisRun(RoR2.UnlockableDef)' called on client");
				return false;
			}
			return !unlockablesAlreadyFullyObtained.Contains(unlockableDef);
		}

		[Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)]
		[Server]
		public void GrantUnlockToAllParticipatingPlayers(string unlockableName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToAllParticipatingPlayers(System.String)' called on client");
			}
			else
			{
				GrantUnlockToAllParticipatingPlayers(UnlockableCatalog.GetUnlockableDef(unlockableName));
			}
		}

		[Server]
		public void GrantUnlockToAllParticipatingPlayers(UnlockableDef unlockableDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToAllParticipatingPlayers(RoR2.UnlockableDef)' called on client");
			}
			else
			{
				if (!unlockableDef || unlockableDef.index == UnlockableIndex.None || unlockablesAlreadyFullyObtained.Contains(unlockableDef))
				{
					return;
				}
				unlockablesAlreadyFullyObtained.Add(unlockableDef);
				foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
				{
					if (readOnlyInstances.isParticipating)
					{
						readOnlyInstances.ServerHandleUnlock(unlockableDef);
					}
				}
			}
		}

		[Server]
		[Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)]
		public void GrantUnlockToSinglePlayer(string unlockableName, CharacterBody body)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToSinglePlayer(System.String,RoR2.CharacterBody)' called on client");
			}
			else
			{
				GrantUnlockToSinglePlayer(UnlockableCatalog.GetUnlockableDef(unlockableName), body);
			}
		}

		[Server]
		public void GrantUnlockToSinglePlayer(UnlockableDef unlockableDef, CharacterBody body)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::GrantUnlockToSinglePlayer(RoR2.UnlockableDef,RoR2.CharacterBody)' called on client");
			}
			else if ((bool)unlockableDef && unlockableDef.index != UnlockableIndex.None && (bool)body)
			{
				NetworkUser networkUser = Util.LookUpBodyNetworkUser(body);
				if ((bool)networkUser)
				{
					networkUser.ServerHandleUnlock(unlockableDef);
				}
			}
		}

		[Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)]
		[Server]
		public bool IsUnlockableUnlocked(string unlockableName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::IsUnlockableUnlocked(System.String)' called on client");
				return false;
			}
			return IsUnlockableUnlocked(UnlockableCatalog.GetUnlockableDef(unlockableName));
		}

		[Server]
		public virtual bool IsUnlockableUnlocked(UnlockableDef unlockableDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::IsUnlockableUnlocked(RoR2.UnlockableDef)' called on client");
				return false;
			}
			return unlockablesUnlockedByAnyUser.Contains(unlockableDef);
		}

		[Server]
		[Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)]
		public bool DoesEveryoneHaveThisUnlockableUnlocked(string unlockableName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::DoesEveryoneHaveThisUnlockableUnlocked(System.String)' called on client");
				return false;
			}
			return DoesEveryoneHaveThisUnlockableUnlocked(UnlockableCatalog.GetUnlockableDef(unlockableName));
		}

		[Server]
		public virtual bool DoesEveryoneHaveThisUnlockableUnlocked(UnlockableDef unlockableDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::DoesEveryoneHaveThisUnlockableUnlocked(RoR2.UnlockableDef)' called on client");
				return false;
			}
			return unlockablesUnlockedByAllUsers.Contains(unlockableDef);
		}

		[Server]
		[Obsolete("Use the overload that accepts an UnlockableDef instead. This method may be removed from future releases.", false)]
		public void ForceUnlockImmediate(string unlockableName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ForceUnlockImmediate(System.String)' called on client");
			}
			else
			{
				ForceUnlockImmediate(UnlockableCatalog.GetUnlockableDef(unlockableName));
			}
		}

		[Server]
		public void ForceUnlockImmediate(UnlockableDef unlockableDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ForceUnlockImmediate(RoR2.UnlockableDef)' called on client");
			}
			else
			{
				unlockablesUnlockedByAnyUser.Add(unlockableDef);
			}
		}

		public void PickNextStageSceneFromCurrentSceneDestinations()
		{
			WeightedSelection<SceneDef> weightedSelection = new WeightedSelection<SceneDef>();
			SceneCatalog.mostRecentSceneDef.AddDestinationsToWeightedSelection(weightedSelection, CanPickStage);
			PickNextStageScene(weightedSelection);
		}

		public bool CanPickStage(SceneDef sceneDef)
		{
			if ((bool)sceneDef.requiredExpansion)
			{
				return IsExpansionEnabled(sceneDef.requiredExpansion);
			}
			return true;
		}

		public void PickNextStageScene(WeightedSelection<SceneDef> choices)
		{
			if (choices.Count != 0)
			{
				if (ruleBook.stageOrder == StageOrder.Normal)
				{
					nextStageScene = choices.Evaluate(nextStageRng.nextNormalizedFloat);
					return;
				}
				SceneDef[] array = SceneCatalog.allStageSceneDefs.Where(IsValidNextStage).ToArray();
				nextStageScene = nextStageRng.NextElementUniform(array);
			}
			bool IsValidNextStage(SceneDef sceneDef)
			{
				if (nextStageScene != null && nextStageScene.baseSceneName == sceneDef.baseSceneName)
				{
					return false;
				}
				if (!sceneDef.hasAnyDestinations)
				{
					return false;
				}
				if (stageClearCount == 0 && blacklistedScenesForFirstScene.Contains(sceneDef))
				{
					return false;
				}
				return sceneDef.validForRandomSelection;
			}
		}

		public virtual ulong GenerateSeedForNewRun()
		{
			return RoR2Application.rng.nextUlong;
		}

		[Server]
		public void RefreshUnlockAvailability()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::RefreshUnlockAvailability()' called on client");
			}
			else
			{
				BuildUnlockAvailability();
			}
		}

		protected virtual void BuildUnlockAvailability()
		{
			unlockablesUnlockedByAnyUser.Clear();
			unlockablesUnlockedByAllUsers.Clear();
			unlockablesAlreadyFullyObtained.Clear();
			int num = 0;
			Dictionary<UnlockableDef, int> dictionary = new Dictionary<UnlockableDef, int>();
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (!readOnlyInstances.isParticipating)
				{
					continue;
				}
				num++;
				foreach (UnlockableDef unlockable in readOnlyInstances.unlockables)
				{
					unlockablesUnlockedByAnyUser.Add(unlockable);
					if (!dictionary.ContainsKey(unlockable))
					{
						dictionary.Add(unlockable, 0);
					}
					UnlockableDef key = unlockable;
					int value = dictionary[key] + 1;
					dictionary[key] = value;
				}
			}
			if (num <= 0)
			{
				return;
			}
			foreach (KeyValuePair<UnlockableDef, int> item in dictionary)
			{
				if (item.Value == num)
				{
					unlockablesUnlockedByAllUsers.Add(item.Key);
					unlockablesAlreadyFullyObtained.Add(item.Key);
				}
			}
		}

		protected virtual void Start()
		{
			InitializeTimeStamps();
			OnRuleBookUpdated(networkRuleBookComponent);
			if (NetworkServer.active)
			{
				runRNG = new Xoroshiro128Plus(seed);
				nextStageRng = new Xoroshiro128Plus(runRNG.nextUlong);
				stageRngGenerator = new Xoroshiro128Plus(runRNG.nextUlong);
				GenerateStageRNG();
			}
			allowNewParticipants = true;
			UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
			ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				OnUserAdded(readOnlyInstancesList[i]);
			}
			allowNewParticipants = false;
			if (NetworkServer.active)
			{
				WeightedSelection<SceneDef> weightedSelection = new WeightedSelection<SceneDef>();
				string @string = cvRunSceneOverride.GetString();
				if (@string != "")
				{
					weightedSelection.AddChoice(SceneCatalog.GetSceneDefFromSceneName(@string), 1f);
				}
				else if ((bool)startingSceneGroup)
				{
					startingSceneGroup.AddToWeightedSelection(weightedSelection, CanPickStage);
				}
				else
				{
					for (int j = 0; j < startingScenes.Length; j++)
					{
						if (CanPickStage(startingScenes[j]))
						{
							weightedSelection.AddChoice(startingScenes[j], 1f);
						}
					}
				}
				PickNextStageScene(weightedSelection);
				if (!nextStageScene)
				{
					UnityEngine.Debug.LogError("Cannot set next scene. nextStageScene is null!");
				}
				NetworkManager.singleton.ServerChangeScene(nextStageScene.cachedName);
			}
			BuildUnlockAvailability();
			BuildDropTable();
			isRunning = true;
			Run.onRunStartGlobal?.Invoke(this);
			if (NetworkServer.active && RunArtifactManager.instance.IsArtifactEnabled(DLC2Content.Artifacts.Rebirth))
			{
				ServerGiveRebirthItems();
			}
			if (!NetworkClient.active || !RunArtifactManager.instance.IsArtifactEnabled(DLC2Content.Artifacts.Rebirth))
			{
				return;
			}
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (readOnlyInstances.isLocalPlayer)
				{
					readOnlyInstances.localUser.userProfile.RebirthItem = null;
					break;
				}
			}
		}

		protected virtual void OnDestroy()
		{
			Run.onRunDestroyGlobal?.Invoke(this);
			if ((bool)GameOverController.instance)
			{
				UnityEngine.Object.Destroy(GameOverController.instance.gameObject);
			}
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int num = readOnlyInstancesList.Count - 1; num >= 0; num--)
			{
				if ((bool)readOnlyInstancesList[num])
				{
					UnityEngine.Object.Destroy(readOnlyInstancesList[num].gameObject);
				}
			}
			ReadOnlyCollection<CharacterMaster> readOnlyInstancesList2 = CharacterMaster.readOnlyInstancesList;
			for (int num2 = readOnlyInstancesList2.Count - 1; num2 >= 0; num2--)
			{
				if ((bool)readOnlyInstancesList2[num2])
				{
					UnityEngine.Object.Destroy(readOnlyInstancesList2[num2].gameObject);
				}
			}
			if ((bool)Stage.instance)
			{
				UnityEngine.Object.Destroy(Stage.instance.gameObject);
			}
			Chat.Clear();
			if (!shutdown && PlatformSystems.networkManager.isNetworkActive)
			{
				HandlePostRunDestination();
			}
			ItemMask.Return(availableItems);
			ItemMask.Return(expansionLockedItems);
			EquipmentMask.Return(availableEquipment);
			EquipmentMask.Return(expansionLockedEquipment);
			PlatformSystems.saveSystem.SaveLoggedInUserProfiles();
		}

		[Server]
		private void ServerGiveRebirthItems()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ServerGiveRebirthItems()' called on client");
			}
			else
			{
				if (!NetworkServer.active)
				{
					return;
				}
				ItemIndex itemIndex = ItemIndex.None;
				foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
				{
					Inventory inventory = instance.master.inventory;
					NetworkUser networkUser = instance.networkUser;
					if (networkUser.rebirthItem != ItemIndex.None)
					{
						if ((bool)inventory)
						{
							itemIndex = networkUser.rebirthItem;
							networkUser.NetworkrebirthItem = ItemIndex.None;
						}
					}
					else if (rebirthDropTable != null)
					{
						Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
						itemIndex = PickupCatalog.GetPickupDef(rebirthDropTable.GenerateDrop(rng)).itemIndex;
					}
					if ((bool)inventory)
					{
						inventory.GiveItem(itemIndex);
					}
				}
			}
		}

		protected virtual void HandlePostRunDestination()
		{
			if (NetworkServer.active)
			{
				NetworkManager.singleton.ServerChangeScene("lobby");
			}
		}

		protected void OnApplicationQuit()
		{
			shutdown = true;
		}

		[Server]
		public CharacterMaster GetUserMaster(NetworkUserId networkUserId)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterMaster RoR2.Run::GetUserMaster(RoR2.NetworkUserId)' called on client");
				return null;
			}
			userMasters.TryGetValue(networkUserId, out var value);
			return value;
		}

		[Server]
		public void OnServerSceneChanged(string sceneName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::OnServerSceneChanged(System.String)' called on client");
				return;
			}
			BeginStage();
			isGameOverServer = false;
		}

		[Server]
		private void BeginStage()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::BeginStage()' called on client");
			}
			else
			{
				NetworkServer.Spawn(UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Stage")));
			}
		}

		[Server]
		private void EndStage()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EndStage()' called on client");
			}
			else if ((bool)Stage.instance)
			{
				UnityEngine.Object.Destroy(Stage.instance);
			}
		}

		public void OnUserAdded(NetworkUser user)
		{
			if (NetworkServer.active)
			{
				SetupUserCharacterMaster(user);
			}
		}

		public void OnUserRemoved(NetworkUser user)
		{
		}

		public virtual bool ShouldAllowNewParticipant(NetworkUser user)
		{
			if (!allowNewParticipants)
			{
				return (bool)ruleBook.GetRuleChoice(RuleCatalog.FindRuleDef("Misc.AllowDropIn"))?.extraData;
			}
			return true;
		}

		[Server]
		private void SetupUserCharacterMaster(NetworkUser user)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetupUserCharacterMaster(RoR2.NetworkUser)' called on client");
			}
			else if (!user)
			{
				UnityEngine.Debug.LogError("SetupUserCharacterMaster user is null");
			}
			else
			{
				if ((bool)user.masterObject)
				{
					return;
				}
				CharacterMaster characterMaster = GetUserMaster(user.id);
				bool flag = !characterMaster && ShouldAllowNewParticipant(user);
				if (flag)
				{
					characterMaster = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterMasters/CommandoMaster"), UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity).GetComponent<CharacterMaster>();
					if ((bool)characterMaster)
					{
						userMasters[user.id] = characterMaster;
						if (ruleBook != null)
						{
							characterMaster.GiveMoney(ruleBook.startingMoney);
						}
						else
						{
							UnityEngine.Debug.LogError("Can't give new master money because there's no rulebook");
						}
						DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(selectedDifficulty);
						if ((bool)characterMaster.inventory)
						{
							if (selectedDifficulty == DifficultyIndex.Easy)
							{
								characterMaster.inventory.GiveItem(RoR2Content.Items.DrizzlePlayerHelper);
							}
							else if (difficultyDef.countsAsHardMode)
							{
								characterMaster.inventory.GiveItem(RoR2Content.Items.MonsoonPlayerHelper);
							}
						}
						else
						{
							UnityEngine.Debug.LogError("Instantiated master has no inventory");
						}
						NetworkServer.Spawn(characterMaster.gameObject);
					}
					else
					{
						UnityEngine.Debug.LogError("Instantiated master object has no CharacterMaster");
					}
				}
				if ((bool)characterMaster)
				{
					PlayerCharacterMasterController component = characterMaster.GetComponent<PlayerCharacterMasterController>();
					if ((bool)component)
					{
						component.LinkToNetworkUserServer(user);
					}
					else
					{
						UnityEngine.Debug.LogError("CharacterMaster has no PlayerCharacterMasterController");
					}
					if (flag)
					{
						Run.onPlayerFirstCreatedServer?.Invoke(this, component);
					}
				}
			}
		}

		[Server]
		public virtual void HandlePlayerFirstEntryAnimation(CharacterBody body, UnityEngine.Vector3 spawnPosition, UnityEngine.Quaternion spawnRotation)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::HandlePlayerFirstEntryAnimation(RoR2.CharacterBody,UnityEngine.Vector3,UnityEngine.Quaternion)' called on client");
			}
			else if ((bool)body)
			{
				if ((bool)body.preferredPodPrefab)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(body.preferredPodPrefab, body.transform.position, spawnRotation);
					VehicleSeat component = gameObject.GetComponent<VehicleSeat>();
					if ((bool)component)
					{
						component.AssignPassenger(body.gameObject);
					}
					else
					{
						UnityEngine.Debug.LogError("Body " + body.name + " has preferred pod " + body.preferredPodPrefab.name + ", but that object has no VehicleSeat.");
					}
					NetworkServer.Spawn(gameObject);
				}
				else
				{
					body.SetBodyStateToPreferredInitialState();
				}
			}
			else
			{
				UnityEngine.Debug.LogError("Can't handle player first entry animation for null body.");
			}
		}

		public virtual void OnServerBossAdded(BossGroup bossGroup, CharacterMaster characterMaster)
		{
		}

		public virtual void OnServerBossDefeated(BossGroup bossGroup)
		{
		}

		public virtual void OnServerCharacterBodySpawned(CharacterBody characterBody)
		{
		}

		public virtual void OnServerTeleporterPlaced(SceneDirector sceneDirector, GameObject teleporter)
		{
		}

		public virtual void OnPlayerSpawnPointsPlaced(SceneDirector sceneDirector)
		{
		}

		public virtual GameObject GetTeleportEffectPrefab(GameObject objectToTeleport)
		{
			return LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/TeleportOutBoom");
		}

		public int GetDifficultyScaledCost(int baseCost, float difficultyCoefficient)
		{
			return (int)((float)baseCost * Mathf.Pow(difficultyCoefficient, 1.25f));
		}

		public int GetDifficultyScaledCost(int baseCost)
		{
			return GetDifficultyScaledCost(baseCost, instance.difficultyCoefficient);
		}

		public void BuildDropTable()
		{
			availableTier1DropList.Clear();
			availableTier2DropList.Clear();
			availableTier3DropList.Clear();
			availableLunarItemDropList.Clear();
			availableEquipmentDropList.Clear();
			availableBossDropList.Clear();
			availableLunarEquipmentDropList.Clear();
			availableVoidTier1DropList.Clear();
			availableVoidTier2DropList.Clear();
			availableVoidTier3DropList.Clear();
			availableVoidBossDropList.Clear();
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				if (availableItems.Contains(itemIndex))
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
					List<PickupIndex> list = null;
					switch (itemDef.tier)
					{
					case ItemTier.Tier1:
						list = availableTier1DropList;
						break;
					case ItemTier.Tier2:
						list = availableTier2DropList;
						break;
					case ItemTier.Tier3:
						list = availableTier3DropList;
						break;
					case ItemTier.Lunar:
						list = availableLunarItemDropList;
						break;
					case ItemTier.Boss:
						list = availableBossDropList;
						break;
					case ItemTier.VoidTier1:
						list = availableVoidTier1DropList;
						break;
					case ItemTier.VoidTier2:
						list = availableVoidTier2DropList;
						break;
					case ItemTier.VoidTier3:
						list = availableVoidTier3DropList;
						break;
					case ItemTier.VoidBoss:
						list = availableVoidBossDropList;
						break;
					}
					if (list != null && itemDef.DoesNotContainTag(ItemTag.WorldUnique))
					{
						list.Add(PickupCatalog.FindPickupIndex(itemIndex));
					}
				}
			}
			EquipmentIndex equipmentIndex = (EquipmentIndex)0;
			for (EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; equipmentIndex < equipmentCount; equipmentIndex++)
			{
				if (!availableEquipment.Contains(equipmentIndex))
				{
					continue;
				}
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
				if (equipmentDef.canDrop)
				{
					if (!equipmentDef.isLunar)
					{
						availableEquipmentDropList.Add(PickupCatalog.FindPickupIndex(equipmentIndex));
					}
					else
					{
						availableLunarEquipmentDropList.Add(PickupCatalog.FindPickupIndex(equipmentIndex));
					}
				}
			}
			smallChestDropTierSelector.Clear();
			smallChestDropTierSelector.AddChoice(availableTier1DropList, 0.8f);
			smallChestDropTierSelector.AddChoice(availableTier2DropList, 0.2f);
			smallChestDropTierSelector.AddChoice(availableTier3DropList, 0.01f);
			mediumChestDropTierSelector.Clear();
			mediumChestDropTierSelector.AddChoice(availableTier2DropList, 0.8f);
			mediumChestDropTierSelector.AddChoice(availableTier3DropList, 0.2f);
			largeChestDropTierSelector.Clear();
			RefreshLunarCombinedDropList();
		}

		public bool IsItemAvailable(ItemIndex itemIndex)
		{
			return availableItems.Contains(itemIndex);
		}

		public bool IsEquipmentAvailable(EquipmentIndex equipmentIndex)
		{
			return availableEquipment.Contains(equipmentIndex);
		}

		public bool IsItemExpansionLocked(ItemIndex itemIndex)
		{
			return expansionLockedItems.Contains(itemIndex);
		}

		public bool IsEquipmentExpansionLocked(EquipmentIndex equipmentIndex)
		{
			return expansionLockedEquipment.Contains(equipmentIndex);
		}

		public bool IsPickupAvailable(PickupIndex pickupIndex)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef.itemIndex != ItemIndex.None)
			{
				return IsItemAvailable(pickupDef.itemIndex);
			}
			if (pickupDef.equipmentIndex != EquipmentIndex.None)
			{
				return IsEquipmentAvailable(pickupDef.equipmentIndex);
			}
			return true;
		}

		[Server]
		public void DisablePickupDrop(PickupIndex pickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::DisablePickupDrop(RoR2.PickupIndex)' called on client");
				return;
			}
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef.itemIndex != ItemIndex.None)
			{
				DisableItemDrop(pickupDef.itemIndex);
			}
			if (pickupDef.equipmentIndex != EquipmentIndex.None)
			{
				DisableEquipmentDrop(pickupDef.equipmentIndex);
			}
		}

		[Server]
		public void DisableItemDrop(ItemIndex itemIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::DisableItemDrop(RoR2.ItemIndex)' called on client");
				return;
			}
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			List<PickupIndex> list = null;
			bool flag = false;
			switch (itemDef.tier)
			{
			case ItemTier.Tier1:
				list = availableTier1DropList;
				break;
			case ItemTier.Tier2:
				list = availableTier2DropList;
				break;
			case ItemTier.Tier3:
				list = availableTier3DropList;
				break;
			case ItemTier.Lunar:
				list = availableLunarItemDropList;
				break;
			case ItemTier.Boss:
				list = availableBossDropList;
				break;
			case ItemTier.VoidTier1:
				list = availableVoidTier1DropList;
				break;
			case ItemTier.VoidTier2:
				list = availableVoidTier2DropList;
				break;
			case ItemTier.VoidTier3:
				list = availableVoidTier3DropList;
				break;
			case ItemTier.VoidBoss:
				list = availableVoidBossDropList;
				break;
			}
			PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(itemIndex);
			if (list != null && pickupIndex != PickupIndex.none)
			{
				list.Remove(pickupIndex);
				if (flag)
				{
					RefreshLunarCombinedDropList();
				}
				Run.onAvailablePickupsModified?.Invoke(this);
			}
		}

		[Server]
		public void DisableEquipmentDrop(EquipmentIndex equipmentIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::DisableEquipmentDrop(RoR2.EquipmentIndex)' called on client");
				return;
			}
			PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(equipmentIndex);
			if (!(pickupIndex != PickupIndex.none))
			{
				return;
			}
			List<PickupIndex> list = null;
			bool flag = false;
			if (PickupCatalog.GetPickupDef(pickupIndex).isLunar)
			{
				flag = true;
				list = availableLunarEquipmentDropList;
			}
			else
			{
				list = availableEquipmentDropList;
			}
			if (list.Contains(pickupIndex))
			{
				list.Remove(pickupIndex);
				if (flag)
				{
					RefreshLunarCombinedDropList();
				}
				Run.onAvailablePickupsModified?.Invoke(this);
			}
		}

		[Server]
		public void EnablePickupDrop(PickupIndex pickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EnablePickupDrop(RoR2.PickupIndex)' called on client");
				return;
			}
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef.itemIndex != ItemIndex.None)
			{
				EnableItemDrop(pickupDef.itemIndex);
			}
			if (pickupDef.equipmentIndex != EquipmentIndex.None)
			{
				EnableEquipmentDrop(pickupDef.equipmentIndex);
			}
		}

		[Server]
		public void EnableItemDrop(ItemIndex itemIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EnableItemDrop(RoR2.ItemIndex)' called on client");
				return;
			}
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			List<PickupIndex> list = null;
			bool flag = false;
			switch (itemDef.tier)
			{
			case ItemTier.Tier1:
				list = availableTier1DropList;
				break;
			case ItemTier.Tier2:
				list = availableTier2DropList;
				break;
			case ItemTier.Tier3:
				list = availableTier3DropList;
				break;
			case ItemTier.Lunar:
				list = availableLunarItemDropList;
				break;
			case ItemTier.Boss:
				list = availableBossDropList;
				break;
			case ItemTier.VoidTier1:
				list = availableVoidTier1DropList;
				break;
			case ItemTier.VoidTier2:
				list = availableVoidTier2DropList;
				break;
			case ItemTier.VoidTier3:
				list = availableVoidTier3DropList;
				break;
			case ItemTier.VoidBoss:
				list = availableVoidBossDropList;
				break;
			}
			PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(itemIndex);
			if (list != null && pickupIndex != PickupIndex.none && !list.Contains(pickupIndex))
			{
				list.Add(pickupIndex);
				if (flag)
				{
					RefreshLunarCombinedDropList();
				}
				Run.onAvailablePickupsModified?.Invoke(this);
			}
		}

		[Server]
		public void EnableEquipmentDrop(EquipmentIndex equipmentIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::EnableEquipmentDrop(RoR2.EquipmentIndex)' called on client");
				return;
			}
			PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(equipmentIndex);
			if (!(pickupIndex != PickupIndex.none))
			{
				return;
			}
			List<PickupIndex> list = null;
			bool flag = false;
			list = ((!PickupCatalog.GetPickupDef(pickupIndex).isLunar) ? availableEquipmentDropList : availableLunarEquipmentDropList);
			if (!list.Contains(pickupIndex))
			{
				list.Add(pickupIndex);
				if (flag)
				{
					RefreshLunarCombinedDropList();
				}
				Run.onAvailablePickupsModified?.Invoke(this);
			}
		}

		[Server]
		private void RefreshLunarCombinedDropList()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::RefreshLunarCombinedDropList()' called on client");
				return;
			}
			availableLunarCombinedDropList.Clear();
			availableLunarCombinedDropList.AddRange(availableLunarEquipmentDropList);
			availableLunarCombinedDropList.AddRange(availableLunarItemDropList);
		}

		[ConCommand(commandName = "run_end", flags = ConVarFlags.SenderMustBeServer, helpText = "Ends the current run.")]
		private static void CCRunEnd(ConCommandArgs args)
		{
			if ((bool)instance)
			{
				UnityEngine.Object.Destroy(instance.gameObject);
			}
		}

		[ConCommand(commandName = "run_print_unlockables", flags = ConVarFlags.SenderMustBeServer, helpText = "Prints all unlockables available in this run.")]
		private static void CCRunPrintUnlockables(ConCommandArgs args)
		{
			if (!instance)
			{
				throw new ConCommandException("No run is currently in progress.");
			}
			List<string> list = new List<string>();
			foreach (UnlockableDef item in instance.unlockablesUnlockedByAnyUser)
			{
				list.Add(item.cachedName);
			}
		}

		[ConCommand(commandName = "run_print_seed", flags = ConVarFlags.None, helpText = "Prints the seed of the current run.")]
		private static void CCRunPrintSeed(ConCommandArgs args)
		{
			if (!instance)
			{
				throw new ConCommandException("No run is currently in progress.");
			}
			UnityEngine.Debug.LogFormat("Current run seed: {0}", instance.seed);
		}

		[ConCommand(commandName = "run_set_stages_cleared", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Sets the current number of stages cleared in the run.")]
		private static void CCRunSetStagesCleared(ConCommandArgs args)
		{
			if (!instance)
			{
				throw new ConCommandException("No run is currently in progress.");
			}
			instance.NetworkstageClearCount = args.GetArgInt(0);
		}

		public virtual void AdvanceStage(SceneDef nextScene)
		{
			if ((bool)Stage.instance)
			{
				Stage.instance.CompleteServer();
				SceneType sceneType = SceneCatalog.GetSceneDefForCurrentScene().sceneType;
				if (sceneType == SceneType.Stage || sceneType == SceneType.UntimedStage)
				{
					NetworkstageClearCount = stageClearCount + 1;
				}
			}
			GenerateStageRNG();
			RecalculateDifficultyCoefficent();
			NetworkManager.singleton.ServerChangeScene(nextScene.cachedName);
		}

		public void BeginGameOver([NotNull] GameEndingDef gameEndingDef)
		{
			if (isGameOverServer)
			{
				return;
			}
			if ((bool)Stage.instance && gameEndingDef.isWin)
			{
				Stage.instance.CompleteServer();
			}
			isGameOverServer = true;
			if (gameEndingDef.lunarCoinReward != 0)
			{
				for (int i = 0; i < NetworkUser.readOnlyInstancesList.Count; i++)
				{
					NetworkUser networkUser = NetworkUser.readOnlyInstancesList[i];
					if ((bool)networkUser && networkUser.isParticipating)
					{
						networkUser.AwardLunarCoins(gameEndingDef.lunarCoinReward);
					}
				}
			}
			StatManager.ForceUpdate();
			GameObject obj = UnityEngine.Object.Instantiate(gameOverPrefab);
			GameOverController component = obj.GetComponent<GameOverController>();
			component.SetRunReport(RunReport.Generate(this, gameEndingDef));
			Run.onServerGameOver?.Invoke(this, gameEndingDef);
			NetworkServer.Spawn(obj);
			isRunning = false;
			component.CallRpcClientGameOver();
		}

		public virtual void OnClientGameOver(RunReport runReport)
		{
			isRunning = false;
			Run.onClientGameOverGlobal?.Invoke(this, runReport);
		}

		public virtual void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed)
		{
			ForceChoice(mustInclude, mustExclude, "Misc.KeepMoneyBetweenStages.Off");
		}

		protected void ForceChoice(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, RuleChoiceDef choiceDef)
		{
			foreach (RuleChoiceDef choice in choiceDef.ruleDef.choices)
			{
				mustInclude[choice.globalIndex] = false;
				mustExclude[choice.globalIndex] = true;
			}
			mustInclude[choiceDef.globalIndex] = true;
			mustExclude[choiceDef.globalIndex] = false;
		}

		protected void ForceChoice(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, string choiceDefGlobalName)
		{
			ForceChoice(mustInclude, mustExclude, RuleCatalog.FindChoiceDef(choiceDefGlobalName));
		}

		public virtual UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination)
		{
			return FindSafeTeleportPosition(characterBody, targetDestination, float.NegativeInfinity, float.NegativeInfinity);
		}

		public virtual UnityEngine.Vector3 FindSafeTeleportPosition(CharacterBody characterBody, Transform targetDestination, float idealMinDistance, float idealMaxDistance)
		{
			UnityEngine.Vector3 vector = (targetDestination ? targetDestination.position : characterBody.transform.position);
			SpawnCard spawnCard = ScriptableObject.CreateInstance<SpawnCard>();
			spawnCard.hullSize = characterBody.hullClassification;
			spawnCard.nodeGraphType = MapNodeGroup.GraphType.Ground;
			spawnCard.prefab = LegacyResourcesAPI.Load<GameObject>("SpawnCards/HelperPrefab");
			UnityEngine.Vector3 result = vector;
			GameObject gameObject = null;
			if (idealMaxDistance > 0f && idealMinDistance < idealMaxDistance)
			{
				gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Approximate,
					minDistance = idealMinDistance,
					maxDistance = idealMaxDistance,
					position = vector
				}, RoR2Application.rng));
			}
			if (!gameObject)
			{
				gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
					position = vector
				}, RoR2Application.rng));
				if ((bool)gameObject)
				{
					result = gameObject.transform.position;
				}
			}
			if ((bool)gameObject)
			{
				UnityEngine.Object.Destroy(gameObject);
			}
			UnityEngine.Object.Destroy(spawnCard);
			return result;
		}

		[Server]
		public void SetEventFlag(string name)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::SetEventFlag(System.String)' called on client");
			}
			else
			{
				eventFlags.Add(name);
			}
		}

		[Server]
		public bool GetEventFlag(string name)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.Run::GetEventFlag(System.String)' called on client");
				return false;
			}
			return eventFlags.Contains(name);
		}

		[Server]
		public void ResetEventFlag(string name)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Run::ResetEventFlag(System.String)' called on client");
			}
			else
			{
				eventFlags.Remove(name);
			}
		}

		public virtual bool ShouldAllowNonChampionBossSpawn()
		{
			return stageClearCount > 0;
		}

		public bool IsExpansionEnabled([NotNull] ExpansionDef expansionDef)
		{
			if (expansionDef.enabledChoice != null)
			{
				return ruleBook.IsChoiceActive(expansionDef.enabledChoice);
			}
			return false;
		}

		protected virtual void OnSeedSet()
		{
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WriteNetworkGuid_None(writer, _uniqueId);
				GeneratedNetworkCode._WriteNetworkDateTime_None(writer, startTimeUtc);
				writer.Write(fixedTime);
				GeneratedNetworkCode._WriteRunStopwatch_Run(writer, runStopwatch);
				writer.WritePackedUInt32((uint)stageClearCount);
				writer.WritePackedUInt32((uint)selectedDifficultyInternal);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteNetworkGuid_None(writer, _uniqueId);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteNetworkDateTime_None(writer, startTimeUtc);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(fixedTime);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteRunStopwatch_Run(writer, runStopwatch);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)stageClearCount);
			}
			if ((base.syncVarDirtyBits & 0x20u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)selectedDifficultyInternal);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_uniqueId = GeneratedNetworkCode._ReadNetworkGuid_None(reader);
				startTimeUtc = GeneratedNetworkCode._ReadNetworkDateTime_None(reader);
				fixedTime = reader.ReadSingle();
				runStopwatch = GeneratedNetworkCode._ReadRunStopwatch_Run(reader);
				stageClearCount = (int)reader.ReadPackedUInt32();
				selectedDifficultyInternal = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_uniqueId = GeneratedNetworkCode._ReadNetworkGuid_None(reader);
			}
			if (((uint)num & 2u) != 0)
			{
				startTimeUtc = GeneratedNetworkCode._ReadNetworkDateTime_None(reader);
			}
			if (((uint)num & 4u) != 0)
			{
				fixedTime = reader.ReadSingle();
			}
			if (((uint)num & 8u) != 0)
			{
				runStopwatch = GeneratedNetworkCode._ReadRunStopwatch_Run(reader);
			}
			if (((uint)num & 0x10u) != 0)
			{
				stageClearCount = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x20u) != 0)
			{
				selectedDifficultyInternal = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class WeeklyRun : Run
	{
		private Xoroshiro128Plus bossAffixRng;

		public static readonly DateTime startDate = new DateTime(2018, 8, 27, 0, 0, 0, 0, DateTimeKind.Utc);

		public const int cycleLength = 3;

		private string leaderboardName;

		[SyncVar]
		private uint serverSeedCycle;

		private EquipmentIndex[] bossAffixes = Array.Empty<EquipmentIndex>();

		public SpawnCard crystalSpawnCard;

		public uint crystalCount = 3u;

		public uint crystalRewardValue = 50u;

		public uint crystalsRequiredToKill = 3u;

		private List<OnDestroyCallback> crystalActiveList = new List<OnDestroyCallback>();

		public SpawnCard equipmentBarrelSpawnCard;

		public uint equipmentBarrelCount = 3u;

		public float equipmentBarrelRadius = 10f;

		public static DateTime now => Util.UnixTimeStampToDateTimeUtc(Client.Instance.Utils.GetServerRealTime());

		public uint crystalsKilled => (uint)(crystalCount - crystalActiveList.Count);

		public uint NetworkserverSeedCycle
		{
			get
			{
				return serverSeedCycle;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref serverSeedCycle, 64u);
			}
		}

		public static uint GetCurrentSeedCycle()
		{
			return (uint)((now - startDate).Days / 3);
		}

		public static DateTime GetSeedCycleStartDateTime(uint seedCycle)
		{
			return startDate.AddDays(seedCycle * 3);
		}

		public static DateTime GetSeedCycleStartDateTime()
		{
			return GetSeedCycleStartDateTime(GetCurrentSeedCycle());
		}

		public static DateTime GetSeedCycleEndDateTime()
		{
			return GetSeedCycleStartDateTime(GetCurrentSeedCycle() + 1);
		}

		protected new void Start()
		{
			base.Start();
			if (NetworkServer.active)
			{
				bossAffixRng = new Xoroshiro128Plus(runRNG.nextUlong);
				NetworkserverSeedCycle = GetCurrentSeedCycle();
			}
			isRunWeekly = true;
			bossAffixes = new EquipmentIndex[2]
			{
				RoR2Content.Equipment.AffixRed.equipmentIndex,
				RoR2Content.Equipment.AffixBlue.equipmentIndex
			};
		}

		protected override void OnFixedUpdate()
		{
			base.OnFixedUpdate();
			if (!TeleporterInteraction.instance)
			{
				return;
			}
			bool flag = crystalsRequiredToKill > crystalsKilled;
			if (flag == TeleporterInteraction.instance.locked)
			{
				return;
			}
			if (flag)
			{
				if (NetworkServer.active)
				{
					TeleporterInteraction.instance.locked = true;
				}
				return;
			}
			if (NetworkServer.active)
			{
				TeleporterInteraction.instance.locked = false;
			}
			ChildLocator component = TeleporterInteraction.instance.GetComponent<ModelLocator>().modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild("TimeCrystalBeaconBlocker");
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/TimeCrystalDeath"), new EffectData
				{
					origin = transform.transform.position
				}, transmit: false);
				transform.gameObject.SetActive(value: false);
			}
		}

		public override ulong GenerateSeedForNewRun()
		{
			return (ulong)GetCurrentSeedCycle() << 32;
		}

		public override void HandlePlayerFirstEntryAnimation(CharacterBody body, UnityEngine.Vector3 spawnPosition, UnityEngine.Quaternion spawnRotation)
		{
		}

		public override void AdvanceStage(SceneDef nextScene)
		{
			if (stageClearCount == 1 && SceneInfo.instance.countsAsStage)
			{
				BeginGameOver(RoR2Content.GameEndings.PrismaticTrialEnding);
			}
			else
			{
				base.AdvanceStage(nextScene);
			}
		}

		public override void OnClientGameOver(RunReport runReport)
		{
			base.OnClientGameOver(runReport);
			ClientSubmitLeaderboardScore(runReport);
		}

		public override void OnServerBossAdded(BossGroup bossGroup, CharacterMaster characterMaster)
		{
			base.OnServerBossAdded(bossGroup, characterMaster);
			if (stageClearCount >= 1)
			{
				if (characterMaster.inventory.GetEquipmentIndex() == EquipmentIndex.None)
				{
					characterMaster.inventory.SetEquipmentIndex(bossAffixRng.NextElementUniform(bossAffixes));
				}
				characterMaster.inventory.GiveItem(RoR2Content.Items.BoostHp, 5);
				characterMaster.inventory.GiveItem(RoR2Content.Items.BoostDamage);
			}
		}

		public override void OnServerBossDefeated(BossGroup bossGroup)
		{
			base.OnServerBossDefeated(bossGroup);
			if ((bool)TeleporterInteraction.instance)
			{
				TeleporterInteraction.instance.holdoutZoneController.FullyChargeHoldoutZone();
			}
		}

		public override GameObject GetTeleportEffectPrefab(GameObject objectToTeleport)
		{
			return LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/TeleportOutCrystalBoom");
		}

		public override void OnServerTeleporterPlaced(SceneDirector sceneDirector, GameObject teleporter)
		{
			base.OnServerTeleporterPlaced(sceneDirector, teleporter);
			DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule();
			directorPlacementRule.placementMode = DirectorPlacementRule.PlacementMode.Random;
			for (int i = 0; i < crystalCount; i++)
			{
				GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(crystalSpawnCard, directorPlacementRule, stageRng));
				if ((bool)gameObject)
				{
					DeathRewards component2 = gameObject.GetComponent<DeathRewards>();
					if ((bool)component2)
					{
						component2.goldReward = crystalRewardValue;
					}
				}
				crystalActiveList.Add(OnDestroyCallback.AddCallback(gameObject, delegate(OnDestroyCallback component)
				{
					crystalActiveList.Remove(component);
				}));
			}
			if ((bool)TeleporterInteraction.instance)
			{
				ChildLocator component3 = TeleporterInteraction.instance.GetComponent<ModelLocator>().modelTransform.GetComponent<ChildLocator>();
				if ((bool)component3)
				{
					component3.FindChild("TimeCrystalProps").gameObject.SetActive(value: true);
					component3.FindChild("TimeCrystalBeaconBlocker").gameObject.SetActive(value: true);
				}
			}
		}

		public override void OnPlayerSpawnPointsPlaced(SceneDirector sceneDirector)
		{
			if (stageClearCount != 0)
			{
				return;
			}
			SpawnPoint spawnPoint = SpawnPoint.readOnlyInstancesList[0];
			if ((bool)spawnPoint)
			{
				float num = 360f / (float)equipmentBarrelCount;
				for (int i = 0; i < equipmentBarrelCount; i++)
				{
					UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(num * (float)i, UnityEngine.Vector3.up) * (UnityEngine.Vector3.forward * equipmentBarrelRadius);
					DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule();
					directorPlacementRule.minDistance = 0f;
					directorPlacementRule.maxDistance = 3f;
					directorPlacementRule.placementMode = DirectorPlacementRule.PlacementMode.NearestNode;
					directorPlacementRule.position = spawnPoint.transform.position + vector;
					DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(equipmentBarrelSpawnCard, directorPlacementRule, stageRng));
				}
			}
		}

		public static string GetLeaderboardName(int playerCount, uint seedCycle)
		{
			if (Console.sessionCheatsEnabled)
			{
				return null;
			}
			return string.Format(CultureInfo.InvariantCulture, "weekly{0}p{1}", playerCount, seedCycle);
		}

		protected void ClientSubmitLeaderboardScore(RunReport runReport)
		{
			UnityEngine.Debug.LogFormat("Attempting to submit leaderboard score.");
			if (!runReport.gameEnding.isWin)
			{
				return;
			}
			bool flag = false;
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				if (readOnlyLocalPlayers.isParticipating)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return;
			}
			int num = PlayerCharacterMasterController.instances.Count;
			switch (num)
			{
			default:
				return;
			case 3:
			case 4:
				num = 4;
				break;
			case 1:
			case 2:
				break;
			}
			string value = GetLeaderboardName(num, serverSeedCycle);
			if (string.IsNullOrEmpty(value))
			{
				return;
			}
			int[] subScores = new int[64];
			GameObject bodyPrefab = BodyCatalog.GetBodyPrefab(NetworkUser.readOnlyLocalPlayersList[0].bodyIndexPreference);
			if (!bodyPrefab)
			{
				return;
			}
			SurvivorDef survivorDef = SurvivorCatalog.FindSurvivorDefFromBody(bodyPrefab);
			if (!(survivorDef == null))
			{
				subScores[1] = (int)survivorDef.survivorIndex;
				Leaderboard leaderboard = Client.Instance.GetLeaderboard(value, Client.LeaderboardSortMethod.Ascending, Client.LeaderboardDisplayType.TimeMilliSeconds);
				leaderboard.OnBoardInformation = delegate
				{
					leaderboard.AddScore(onlyIfBeatsOldScore: true, (int)Math.Ceiling((double)runReport.runStopwatchValue * 1000.0), subScores);
				};
			}
		}

		public override void OverrideRuleChoices(RuleChoiceMask mustInclude, RuleChoiceMask mustExclude, ulong runSeed)
		{
			base.OverrideRuleChoices(mustInclude, mustExclude, base.seed);
			ForceChoice(mustInclude, mustExclude, "Difficulty.Normal");
			ForceChoice(mustInclude, mustExclude, "Misc.StartingMoney.50");
			ForceChoice(mustInclude, mustExclude, "Misc.StageOrder.Random");
			ForceChoice(mustInclude, mustExclude, "Misc.KeepMoneyBetweenStages.Off");
			for (int i = 0; i < ArtifactCatalog.artifactCount; i++)
			{
				ForceChoice(mustInclude, mustExclude, FindRuleForArtifact((ArtifactIndex)i).FindChoice("Off"));
			}
			Xoroshiro128Plus xoroshiro128Plus = new Xoroshiro128Plus(runSeed);
			UnityEngine.Debug.LogFormat("Weekly Run Seed: {0}", runSeed);
			if (xoroshiro128Plus.nextNormalizedFloat < 1f)
			{
				int num = xoroshiro128Plus.RangeInt(2, 7);
				ArtifactIndex[] array = new ArtifactIndex[ArtifactCatalog.artifactCount];
				for (int j = 0; j < array.Length; j++)
				{
					array[j] = (ArtifactIndex)j;
				}
				Util.ShuffleArray(array, xoroshiro128Plus);
				for (int k = 0; k < num; k++)
				{
					if (ArtifactCatalog.GetArtifactDef(array[k]) != RoR2Content.Artifacts.randomSurvivorOnRespawnArtifactDef)
					{
						ForceChoice(mustInclude, mustExclude, FindRuleForArtifact(array[k]).FindChoice("On"));
					}
				}
			}
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
				RuleChoiceDef ruleChoiceDef = RuleCatalog.FindRuleDef("Items." + itemDef.name)?.FindChoice("On");
				if (ruleChoiceDef != null)
				{
					ForceChoice(mustInclude, mustExclude, ruleChoiceDef);
				}
			}
			EquipmentIndex equipmentIndex = (EquipmentIndex)0;
			for (EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; equipmentIndex < equipmentCount; equipmentIndex++)
			{
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
				RuleChoiceDef ruleChoiceDef2 = RuleCatalog.FindRuleDef("Equipment." + equipmentDef.name)?.FindChoice("On");
				if (ruleChoiceDef2 != null)
				{
					ForceChoice(mustInclude, mustExclude, ruleChoiceDef2);
				}
			}
			foreach (ExpansionDef expansionDef in ExpansionCatalog.expansionDefs)
			{
				RuleChoiceDef ruleChoiceDef3 = RuleCatalog.FindRuleDef("Expansions." + expansionDef.name)?.FindChoice("On");
				if (ruleChoiceDef3 != null)
				{
					ForceChoice(mustInclude, mustExclude, ruleChoiceDef3);
				}
			}
			static RuleDef FindRuleForArtifact(ArtifactIndex artifactIndex)
			{
				ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(artifactIndex);
				return RuleCatalog.FindRuleDef("Artifacts." + artifactDef.cachedName);
			}
		}

		public override bool IsUnlockableUnlocked(UnlockableDef unlockableDef)
		{
			return true;
		}

		public override bool CanUnlockableBeGrantedThisRun(UnlockableDef unlockableDef)
		{
			return false;
		}

		public override bool DoesEveryoneHaveThisUnlockableUnlocked(UnlockableDef unlockableDef)
		{
			return true;
		}

		protected override void HandlePostRunDestination()
		{
			Console.instance.SubmitCmd(null, "transition_command \"disconnect\";");
		}

		protected override bool ShouldUpdateRunStopwatch()
		{
			return base.livingPlayerCount > 0;
		}

		public override bool ShouldAllowNonChampionBossSpawn()
		{
			return true;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			if (forceAll)
			{
				writer.WritePackedUInt32(serverSeedCycle);
				return true;
			}
			bool flag2 = false;
			if ((base.syncVarDirtyBits & 0x40u) != 0)
			{
				if (!flag2)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag2 = true;
				}
				writer.WritePackedUInt32(serverSeedCycle);
			}
			if (!flag2)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
			if (initialState)
			{
				serverSeedCycle = reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & 0x40u) != 0)
			{
				serverSeedCycle = reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class GameObjectUnlockableFilter : NetworkBehaviour
	{
		[Tooltip("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.")]
		[Obsolete("'requiredUnlockable' will be discontinued. Use 'requiredUnlockableDef' instead.", false)]
		public string requiredUnlockable;

		[Tooltip("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.")]
		[Obsolete("'forbiddenUnlockable' will be discontinued. Use 'forbiddenUnlockableDef' instead.", false)]
		public string forbiddenUnlockable;

		public UnlockableDef requiredUnlockableDef;

		public UnlockableDef forbiddenUnlockableDef;

		[Tooltip("If all users have this achievement, disable")]
		public string AchievementToDisable;

		[SyncVar]
		private bool active;

		public bool Networkactive
		{
			get
			{
				return active;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref active, 1u);
			}
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				Run.instance?.RefreshUnlockAvailability();
				Networkactive = ShouldShowGameObject();
				base.gameObject.SetActive(active);
			}
		}

		private bool ShouldShowGameObject()
		{
			if ((bool)Run.instance)
			{
				ref string reference = ref requiredUnlockable;
				ref string reference2 = ref forbiddenUnlockable;
				if (!requiredUnlockableDef && !string.IsNullOrEmpty(reference))
				{
					requiredUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference);
					reference = null;
				}
				if (!forbiddenUnlockableDef && !string.IsNullOrEmpty(reference2))
				{
					forbiddenUnlockableDef = UnlockableCatalog.GetUnlockableDef(reference2);
					reference2 = null;
				}
				if (AchievementToDisable != null)
				{
					bool flag = false;
					foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
					{
						if (!instance.networkUser.localUser.userProfile.HasAchievement(AchievementToDisable))
						{
							flag = true;
							break;
						}
					}
					UnityEngine.Debug.LogFormat("GameObjectUnlockableFilter: Do all users have achievement {0}? : {1}", AchievementToDisable, flag);
					return flag;
				}
				bool flag2 = !requiredUnlockableDef || Run.instance.IsUnlockableUnlocked(requiredUnlockableDef);
				bool flag3 = !forbiddenUnlockableDef || Run.instance.DoesEveryoneHaveThisUnlockableUnlocked(forbiddenUnlockableDef);
				UnityEngine.Debug.LogFormat("GameObjectUnlockableFilter: requiredUnlockableIsUnlocked {0}; forbiddenUnlockableIsUnlocked {1}", flag2, flag3);
				if (flag2)
				{
					return !flag3;
				}
				return false;
			}
			return true;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(active);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(active);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				active = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				active = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(VoteController))]
	public class GameOverController : NetworkBehaviour
	{
		[Tooltip("The prefab to use for the end-of-game report panel.")]
		public GameObject gameEndReportPanelPrefab;

		public float appearanceDelay = 1f;

		private VoteController voteController;

		private bool _shouldDisplayGameEndReportPanels;

		private Dictionary<HUD, GameEndReportPanelController> reportPanels = new Dictionary<HUD, GameEndReportPanelController>();

		private const uint runReportDirtyBit = 1u;

		private const uint allDirtyBits = 1u;

		private static int kRpcRpcClientGameOver;

		public static GameOverController instance { get; private set; }

		public bool shouldDisplayGameEndReportPanels
		{
			get
			{
				return _shouldDisplayGameEndReportPanels;
			}
			set
			{
				_shouldDisplayGameEndReportPanels = value;
				if (_shouldDisplayGameEndReportPanels)
				{
					UpdateReportScreens();
				}
				else
				{
					CleanupReportPanels();
				}
			}
		}

		public RunReport runReport { get; private set; }

		[Server]
		public void SetRunReport([NotNull] RunReport newRunReport)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GameOverController::SetRunReport(RoR2.RunReport)' called on client");
				return;
			}
			SetDirtyBit(1u);
			runReport = newRunReport;
			if ((bool)runReport.gameEnding)
			{
				EntityStateMachine.FindByCustomName(base.gameObject, "Main").initialStateType = runReport.gameEnding.gameOverControllerState;
			}
		}

		private int FindPlayerIndex(LocalUser localUser)
		{
			int i = 0;
			for (int playerInfoCount = runReport.playerInfoCount; i < playerInfoCount; i++)
			{
				if (runReport.GetPlayerInfo(i).localUser == localUser)
				{
					return i;
				}
			}
			return 0;
		}

		private void UpdateReportScreens()
		{
			if (!shouldDisplayGameEndReportPanels)
			{
				return;
			}
			int i = 0;
			for (int count = HUD.readOnlyInstanceList.Count; i < count; i++)
			{
				HUD hUD = HUD.readOnlyInstanceList[i];
				if (!reportPanels.ContainsKey(hUD))
				{
					reportPanels[hUD] = GenerateReportScreen(hUD);
				}
			}
		}

		private void CleanupReportPanels()
		{
			List<HUD> list = CollectionPool<HUD, List<HUD>>.RentCollection();
			foreach (HUD key in reportPanels.Keys)
			{
				if (!key || !shouldDisplayGameEndReportPanels)
				{
					list.Add(key);
				}
			}
			int i = 0;
			for (int count = list.Count; i < count; i++)
			{
				reportPanels.Remove(list[i]);
			}
			CollectionPool<HUD, List<HUD>>.ReturnCollection(list);
		}

		private GameEndReportPanelController GenerateReportScreen(HUD hud)
		{
			LocalUser localUser = hud.localUserViewer;
			GameObject obj = UnityEngine.Object.Instantiate(gameEndReportPanelPrefab, hud.transform);
			obj.transform.parent = hud.transform;
			obj.GetComponent<MPEventSystemProvider>().eventSystem = localUser.eventSystem;
			GameEndReportPanelController component = obj.GetComponent<GameEndReportPanelController>();
			runReport.SortByLocalPlayers();
			GameEndReportPanelController.DisplayData displayData = default(GameEndReportPanelController.DisplayData);
			displayData.runReport = runReport;
			displayData.playerIndex = FindPlayerIndex(localUser);
			GameEndReportPanelController.DisplayData displayData2 = displayData;
			component.SetDisplayData(displayData2);
			component.SetContinueButtonAction(delegate
			{
				if ((bool)localUser.currentNetworkUser)
				{
					localUser.currentNetworkUser.CallCmdSubmitVote(voteController.gameObject, 0);
				}
			});
			GameObject obj2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/VoteInfoPanel"), (RectTransform)component.continueButton.transform.parent);
			obj2.transform.SetAsFirstSibling();
			obj2.GetComponent<VoteInfoPanelController>().voteController = voteController;
			return component;
		}

		private void Awake()
		{
			runReport = new RunReport();
			voteController = GetComponent<VoteController>();
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			CameraRigController.OnHUDUpdated = (Action)Delegate.Combine(CameraRigController.OnHUDUpdated, new Action(UpdateReportScreens));
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			CameraRigController.OnHUDUpdated = (Action)Delegate.Remove(CameraRigController.OnHUDUpdated, new Action(UpdateReportScreens));
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 1u;
			}
			bool num2 = (num & 1) != 0;
			if (!initialState)
			{
				writer.Write((byte)num);
			}
			if (num2)
			{
				runReport.Write(writer);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (((uint)(initialState ? 1 : reader.ReadByte()) & (true ? 1u : 0u)) != 0)
			{
				runReport.Read(reader);
			}
		}

		[ClientRpc]
		public void RpcClientGameOver()
		{
			if ((bool)Run.instance)
			{
				Run.instance.OnClientGameOver(runReport);
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcClientGameOver(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcClientGameOver called on server.");
			}
			else
			{
				((GameOverController)obj).RpcClientGameOver();
			}
		}

		public void CallRpcClientGameOver()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcClientGameOver called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcClientGameOver);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcClientGameOver");
		}

		static GameOverController()
		{
			kRpcRpcClientGameOver = 1518660169;
			NetworkBehaviour.RegisterRpcDelegate(typeof(GameOverController), kRpcRpcClientGameOver, InvokeRpcRpcClientGameOver);
			NetworkCRC.RegisterBehaviour("GameOverController", 0);
		}

		public override void PreStartClient()
		{
		}
	}
	public class GauntletMissionController : NetworkBehaviour
	{
		public class GauntletMissionBaseState : EntityState
		{
			protected GauntletMissionController gauntletMissionController => instance;
		}

		public class MissionCompleted : GauntletMissionBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				base.gauntletMissionController.clearedEffect.SetActive(value: true);
			}
		}

		[Header("Behavior Values")]
		public float dleayBeforeStart;

		public float timeLimit;

		public float degenTickFrequency;

		public float percentDegenPerSecond;

		[Header("Cached Components")]
		private EntityStateMachine mainStateMachine;

		public GameObject[] gauntletShards;

		public GameObject clearedEffect;

		public GameObject gauntletPortal;

		private bool gauntletEnd;

		private bool slowDeathEffectActive;

		private float degenTimer;

		public static GauntletMissionController instance { get; private set; }

		public static event Action onInstanceChangedGlobal;

		private void Awake()
		{
			mainStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Main");
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			GauntletMissionController.onInstanceChangedGlobal?.Invoke();
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			GauntletMissionController.onInstanceChangedGlobal?.Invoke();
		}

		public void GauntletMissionTimesUp()
		{
			gauntletEnd = true;
			mainStateMachine.SetNextState(new MissionCompleted());
		}

		private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod)
		{
			generationMethod = GenerateGauntletShards;
		}

		private void GenerateGauntletShards()
		{
			_ = gauntletShards.LongLength;
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		[Server]
		private void FixedUpdateServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GauntletMissionController::FixedUpdateServer()' called on client");
			}
			else
			{
				if (!gauntletEnd)
				{
					return;
				}
				degenTimer += Time.fixedDeltaTime;
				if (!(degenTimer > 1f / degenTickFrequency))
				{
					return;
				}
				degenTimer -= 1f / degenTickFrequency;
				foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(TeamIndex.Player))
				{
					float damage = percentDegenPerSecond / 100f / degenTickFrequency * teamMember.body.healthComponent.combinedHealth;
					teamMember.body.healthComponent.TakeDamage(new DamageInfo
					{
						damage = damage,
						position = teamMember.body.corePosition,
						damageType = DamageType.Silent
					});
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class GenericDisplayNameProvider : MonoBehaviour, IDisplayNameProvider
	{
		public string displayToken;

		public string GetDisplayName()
		{
			return Language.GetString(displayToken);
		}

		public void SetDisplayToken(string newDisplayToken)
		{
			displayToken = newDisplayToken;
		}
	}
	public class GenericEnergyComponent : NetworkBehaviour
	{
		[SerializeField]
		private float _capacity = 1f;

		[SerializeField]
		private float _chargeRate = 1f;

		[SyncVar]
		private Run.FixedTimeStamp referenceTime;

		private float _internalChargeRate;

		public bool hasEffectiveAuthority { get; private set; }

		public float energy
		{
			get
			{
				if (internalChargeRate == 0f)
				{
					return (referenceTime - Run.FixedTimeStamp.zero) * capacity;
				}
				return Mathf.Clamp01(referenceTime.timeSince * internalChargeRate) * capacity;
			}
			set
			{
				float num = (capacity.Equals(0f) ? 0f : Mathf.Clamp01(value / capacity));
				if (internalChargeRate == 0f)
				{
					NetworkreferenceTime = Run.FixedTimeStamp.zero + num;
				}
				else
				{
					NetworkreferenceTime = Run.FixedTimeStamp.now - num / internalChargeRate;
				}
			}
		}

		public float normalizedEnergy
		{
			get
			{
				if (capacity == 0f)
				{
					return 0f;
				}
				return Mathf.Clamp01(energy / capacity);
			}
		}

		private float internalChargeRate
		{
			get
			{
				return _internalChargeRate;
			}
			set
			{
				if (_internalChargeRate != value)
				{
					float num = energy;
					_internalChargeRate = value;
					energy = num;
				}
			}
		}

		public float chargeRate
		{
			get
			{
				return _chargeRate;
			}
			set
			{
				if (_chargeRate != value)
				{
					float num = energy;
					_chargeRate = value;
					internalChargeRate = ((capacity != 0f) ? (_chargeRate / capacity) : 0f);
					energy = num;
				}
			}
		}

		public float normalizedChargeRate
		{
			get
			{
				if (capacity == 0f)
				{
					return 0f;
				}
				return chargeRate / capacity;
			}
			set
			{
				chargeRate = ((capacity != 0f) ? (value * capacity) : 0f);
			}
		}

		public float capacity
		{
			get
			{
				return _capacity;
			}
			set
			{
				if (value != _capacity)
				{
					float num = energy;
					_capacity = value;
					energy = num;
				}
			}
		}

		public Run.FixedTimeStamp NetworkreferenceTime
		{
			get
			{
				return referenceTime;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref referenceTime, 1u);
			}
		}

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
		}

		private void Awake()
		{
			UpdateAuthority();
			internalChargeRate = ((capacity != 0f) ? (chargeRate / capacity) : 0f);
			if (NetworkServer.active)
			{
				energy = capacity;
			}
		}

		public override void OnStartAuthority()
		{
			base.OnStartAuthority();
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			base.OnStopAuthority();
			UpdateAuthority();
		}

		private void OnEnable()
		{
			internalChargeRate = ((capacity != 0f) ? (chargeRate / capacity) : 0f);
		}

		private void OnDisable()
		{
			internalChargeRate = 0f;
		}

		[Server]
		public bool TakeEnergy(float amount)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.GenericEnergyComponent::TakeEnergy(System.Single)' called on client");
				return false;
			}
			if (amount > energy)
			{
				return false;
			}
			energy -= amount;
			return true;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WriteFixedTimeStamp_Run(writer, referenceTime);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteFixedTimeStamp_Run(writer, referenceTime);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				referenceTime = GeneratedNetworkCode._ReadFixedTimeStamp_Run(reader);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				referenceTime = GeneratedNetworkCode._ReadFixedTimeStamp_Run(reader);
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public sealed class GenericInteraction : NetworkBehaviour, IInteractable
	{
		[Serializable]
		public class InteractorUnityEvent : UnityEvent<Interactor>
		{
		}

		[SyncVar]
		public Interactability interactability = Interactability.Available;

		public bool shouldIgnoreSpherecastForInteractibility;

		public string contextToken;

		public bool shouldProximityHighlight = true;

		public InteractorUnityEvent onActivation;

		public bool shouldShowOnScanner = true;

		public Interactability Networkinteractability
		{
			get
			{
				return interactability;
			}
			[param: In]
			set
			{
				ulong newValueAsUlong = (ulong)value;
				ulong fieldValueAsUlong = (ulong)interactability;
				SetSyncVarEnum(value, newValueAsUlong, ref interactability, fieldValueAsUlong, 1u);
			}
		}

		[Server]
		public void SetInteractabilityAvailable()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericInteraction::SetInteractabilityAvailable()' called on client");
			}
			else
			{
				Networkinteractability = Interactability.Available;
			}
		}

		[Server]
		public void SetInteractabilityConditionsNotMet()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericInteraction::SetInteractabilityConditionsNotMet()' called on client");
			}
			else
			{
				Networkinteractability = Interactability.ConditionsNotMet;
			}
		}

		[Server]
		public void SetInteractabilityDisabled()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericInteraction::SetInteractabilityDisabled()' called on client");
			}
			else
			{
				Networkinteractability = Interactability.Disabled;
			}
		}

		string IInteractable.GetContextString(Interactor activator)
		{
			if (contextToken == "")
			{
				return null;
			}
			return Language.GetString(contextToken);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return shouldIgnoreSpherecastForInteractibility;
		}

		Interactability IInteractable.GetInteractability(Interactor activator)
		{
			return interactability;
		}

		void IInteractable.OnInteractionBegin(Interactor activator)
		{
			onActivation.Invoke(activator);
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			if (shouldShowOnScanner)
			{
				return interactability != Interactability.Disabled;
			}
			return false;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write((int)interactability);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write((int)interactability);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				interactability = (Interactability)reader.ReadInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				interactability = (Interactability)reader.ReadInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class GenericObjectiveProvider : MonoBehaviour
	{
		private class GenericObjectiveTracker : ObjectivePanelController.ObjectiveTracker
		{
			private string previousToken;

			protected override bool shouldConsiderComplete
			{
				get
				{
					if (retired)
					{
						return ((GenericObjectiveProvider)sourceDescriptor.source).markCompletedOnRetired;
					}
					return false;
				}
			}

			protected override string GenerateString()
			{
				GenericObjectiveProvider genericObjectiveProvider = (GenericObjectiveProvider)sourceDescriptor.source;
				previousToken = genericObjectiveProvider.objectiveToken;
				return Language.GetString(genericObjectiveProvider.objectiveToken);
			}

			protected override bool IsDirty()
			{
				return ((GenericObjectiveProvider)sourceDescriptor.source).objectiveToken != previousToken;
			}
		}

		public string objectiveToken;

		public bool markCompletedOnRetired = true;

		private static readonly Action<CharacterMaster, List<ObjectivePanelController.ObjectiveSourceDescriptor>> collectObjectiveSourcesDelegate = CollectObjectiveSources;

		private void OnEnable()
		{
			if (!InstanceTracker.Any<GenericObjectiveProvider>())
			{
				ObjectivePanelController.collectObjectiveSources += collectObjectiveSourcesDelegate;
			}
			InstanceTracker.Add(this);
		}

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
			if (!InstanceTracker.Any<GenericObjectiveProvider>())
			{
				ObjectivePanelController.collectObjectiveSources -= collectObjectiveSourcesDelegate;
			}
		}

		private static void CollectObjectiveSources(CharacterMaster viewer, List<ObjectivePanelController.ObjectiveSourceDescriptor> dest)
		{
			foreach (GenericObjectiveProvider instances in InstanceTracker.GetInstancesList<GenericObjectiveProvider>())
			{
				dest.Add(new ObjectivePanelController.ObjectiveSourceDescriptor
				{
					master = viewer,
					objectiveType = typeof(GenericObjectiveTracker),
					source = instances
				});
			}
		}
	}
	public class GenericOwnership : NetworkBehaviour
	{
		[SyncVar(hook = "SetOwnerClient")]
		private NetworkInstanceId ownerInstanceId;

		private GameObject cachedOwnerObject;

		public GameObject ownerObject
		{
			get
			{
				return cachedOwnerObject;
			}
			[Server]
			set
			{
				if (!NetworkServer.active)
				{
					UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericOwnership::set_ownerObject(UnityEngine.GameObject)' called on client");
					return;
				}
				if (!value)
				{
					value = null;
				}
				if ((object)cachedOwnerObject != value)
				{
					cachedOwnerObject = value;
					NetworkownerInstanceId = cachedOwnerObject?.GetComponent<NetworkIdentity>()?.netId ?? NetworkInstanceId.Invalid;
					this.onOwnerChanged?.Invoke(cachedOwnerObject);
				}
			}
		}

		public NetworkInstanceId NetworkownerInstanceId
		{
			get
			{
				return ownerInstanceId;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetOwnerClient(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref ownerInstanceId, 1u);
			}
		}

		public event Action<GameObject> onOwnerChanged;

		private void SetOwnerClient(NetworkInstanceId id)
		{
			if (!NetworkServer.active)
			{
				cachedOwnerObject = ClientScene.FindLocalObject(id);
				this.onOwnerChanged?.Invoke(cachedOwnerObject);
			}
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			SetOwnerClient(ownerInstanceId);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(ownerInstanceId);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(ownerInstanceId);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				ownerInstanceId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetOwnerClient(reader.ReadNetworkId());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public sealed class GenericPickupController : NetworkBehaviour, IInteractable, IInspectable, IInspectInfoProvider, IDisplayNameProvider
	{
		private class PickupMessage : MessageBase
		{
			public GameObject masterGameObject;

			public PickupIndex pickupIndex;

			public uint pickupQuantity;

			public void Reset()
			{
				masterGameObject = null;
				pickupIndex = PickupIndex.none;
				pickupQuantity = 0u;
			}

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(masterGameObject);
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
				writer.WritePackedUInt32(pickupQuantity);
			}

			public override void Deserialize(NetworkReader reader)
			{
				masterGameObject = reader.ReadGameObject();
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				pickupQuantity = reader.ReadPackedUInt32();
			}
		}

		public enum PickupArtifactFlag
		{
			NONE,
			COMMAND,
			DELUSION
		}

		public struct CreatePickupInfo
		{
			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;

			private PickupIndex? _pickupIndex;

			public PickupPickerController.Option[] pickerOptions;

			public GameObject prefabOverride;

			public ChestBehavior chest;

			public PickupArtifactFlag artifactFlag;

			public ItemIndex delusionItemIndex;

			public ItemIndex falseChoice1;

			public ItemIndex falseChoice2;

			public PickupIndex pickupIndex
			{
				get
				{
					if (!_pickupIndex.HasValue)
					{
						return PickupIndex.none;
					}
					return _pickupIndex.Value;
				}
				set
				{
					_pickupIndex = value;
				}
			}
		}

		public PickupDisplay pickupDisplay;

		public ChestBehavior chestGeneratedFrom;

		[SyncVar(hook = "SyncPickupIndex")]
		public PickupIndex pickupIndex = PickupIndex.none;

		[SyncVar(hook = "SyncRecycled")]
		public bool Recycled;

		public bool selfDestructIfPickupIndexIsNotIdeal;

		public SerializablePickupIndex idealPickupIndex;

		private static readonly PickupMessage pickupMessageInstance = new PickupMessage();

		public float waitDuration = 0.5f;

		private Run.FixedTimeStamp waitStartTime;

		private bool consumed;

		public const string pickupSoundString = "Play_UI_item_pickup";

		private static GameObject pickupPrefab;

		public PickupIndex NetworkpickupIndex
		{
			get
			{
				return pickupIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SyncPickupIndex(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref pickupIndex, 1u);
			}
		}

		public bool NetworkRecycled
		{
			get
			{
				return Recycled;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SyncRecycled(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref Recycled, 2u);
			}
		}

		private void SyncPickupIndex(PickupIndex newPickupIndex)
		{
			NetworkpickupIndex = newPickupIndex;
			UpdatePickupDisplay();
		}

		private void SyncRecycled(bool isRecycled)
		{
			NetworkRecycled = isRecycled;
		}

		[Server]
		public static void SendPickupMessage(CharacterMaster master, PickupIndex pickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericPickupController::SendPickupMessage(RoR2.CharacterMaster,RoR2.PickupIndex)' called on client");
				return;
			}
			uint pickupQuantity = 1u;
			if ((bool)master.inventory)
			{
				ItemIndex itemIndex = PickupCatalog.GetPickupDef(pickupIndex)?.itemIndex ?? ItemIndex.None;
				if (itemIndex != ItemIndex.None)
				{
					pickupQuantity = (uint)master.inventory.GetItemCount(itemIndex);
				}
			}
			try
			{
				PickupMessage msg = new PickupMessage
				{
					masterGameObject = master.gameObject,
					pickupIndex = pickupIndex,
					pickupQuantity = pickupQuantity
				};
				NetworkServer.SendByChannelToAll(57, msg, QosChannelIndex.chat.intVal);
			}
			catch (Exception arg)
			{
				UnityEngine.Debug.Log($"Failed to send pickupMessage for pickupIndex {pickupIndex} - gameObject {master.gameObject.name}\r\n{arg}");
			}
		}

		[NetworkMessageHandler(msgType = 57, client = true)]
		private static void HandlePickupMessage(NetworkMessage netMsg)
		{
			PickupMessage pickupMessage = pickupMessageInstance;
			netMsg.ReadMessage(pickupMessage);
			GameObject masterGameObject = pickupMessage.masterGameObject;
			PickupIndex pickupIndex = pickupMessage.pickupIndex;
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			uint pickupQuantity = pickupMessage.pickupQuantity;
			pickupMessage.Reset();
			if (!masterGameObject)
			{
				return;
			}
			CharacterMaster component = masterGameObject.GetComponent<CharacterMaster>();
			if (!component)
			{
				return;
			}
			PlayerCharacterMasterController component2 = component.GetComponent<PlayerCharacterMasterController>();
			if ((bool)component2)
			{
				NetworkUser networkUser = component2.networkUser;
				if ((bool)networkUser)
				{
					networkUser.localUser?.userProfile.DiscoverPickup(pickupIndex);
				}
			}
			CharacterBody body = component.GetBody();
			_ = (bool)body;
			ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef?.itemIndex ?? ItemIndex.None);
			if (itemDef != null && itemDef.hidden)
			{
				return;
			}
			if (pickupIndex != PickupIndex.none)
			{
				ItemIndex transformedItemIndex = ContagiousItemManager.GetTransformedItemIndex(itemDef?.itemIndex ?? ItemIndex.None);
				if (itemDef == null || transformedItemIndex == ItemIndex.None || component.inventory.GetItemCount(transformedItemIndex) <= 0)
				{
					CharacterMasterNotificationQueue.PushPickupNotification(component, pickupIndex);
				}
			}
			Chat.AddPickupMessage(body, pickupDef?.nameToken ?? PickupCatalog.invalidPickupToken, pickupDef?.baseColor ?? UnityEngine.Color.black, pickupQuantity);
			if ((bool)body)
			{
				Util.PlaySound("Play_UI_item_pickup", body.gameObject);
			}
		}

		public void StartWaitTime()
		{
			waitStartTime = Run.FixedTimeStamp.now;
		}

		private void OnTriggerStay(Collider other)
		{
			if (!NetworkServer.active || !(waitStartTime.timeSince >= waitDuration) || consumed)
			{
				return;
			}
			CharacterBody component = other.GetComponent<CharacterBody>();
			if (!component)
			{
				return;
			}
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			ItemIndex itemIndex = pickupDef?.itemIndex ?? ItemIndex.None;
			if (itemIndex != ItemIndex.None)
			{
				ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(ItemCatalog.GetItemDef(itemIndex).tier);
				if ((bool)itemTierDef && (itemTierDef.pickupRules == ItemTierDef.PickupRules.ConfirmAll || (itemTierDef.pickupRules == ItemTierDef.PickupRules.ConfirmFirst && (bool)component.inventory && component.inventory.GetItemCount(itemIndex) <= 0)))
				{
					return;
				}
			}
			EquipmentIndex equipmentIndex = pickupDef?.equipmentIndex ?? EquipmentIndex.None;
			if ((equipmentIndex == EquipmentIndex.None || (!EquipmentCatalog.GetEquipmentDef(equipmentIndex).isLunar && (!component.inventory || component.inventory.currentEquipmentIndex == EquipmentIndex.None))) && (pickupDef == null || pickupDef.coinValue == 0) && BodyHasPickupPermission(component))
			{
				AttemptGrant(component);
			}
		}

		private static bool BodyHasPickupPermission(CharacterBody body)
		{
			if ((bool)(body.masterObject ? body.masterObject.GetComponent<PlayerCharacterMasterController>() : null))
			{
				return body.inventory;
			}
			return false;
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public string GetContextString(Interactor activator)
		{
			return string.Format(Language.GetString(PickupCatalog.GetPickupDef(pickupIndex)?.interactContextToken ?? string.Empty), GetDisplayName());
		}

		private void UpdatePickupDisplay()
		{
			if (!pickupDisplay)
			{
				return;
			}
			pickupDisplay.SetPickupIndex(pickupIndex);
			if ((bool)pickupDisplay.modelRenderer)
			{
				Highlight component = GetComponent<Highlight>();
				if ((bool)component)
				{
					component.targetRenderer = pickupDisplay.modelRenderer;
					component.ResetHighlight();
				}
			}
		}

		[Server]
		private void AttemptGrant(CharacterBody body)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GenericPickupController::AttemptGrant(RoR2.CharacterBody)' called on client");
				return;
			}
			TeamComponent component = body.GetComponent<TeamComponent>();
			if (!component || component.teamIndex != TeamIndex.Player)
			{
				return;
			}
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if ((bool)body.inventory && pickupDef != null)
			{
				PickupDef.GrantContext grantContext = default(PickupDef.GrantContext);
				grantContext.body = body;
				grantContext.controller = this;
				PickupDef.GrantContext context = grantContext;
				pickupDef.attemptGrant?.Invoke(ref context);
				consumed = context.shouldDestroy;
				if (context.shouldNotify)
				{
					SendPickupMessage(body.master, pickupDef.pickupIndex);
				}
				if ((bool)chestGeneratedFrom && DelusionChestController.isDelusionEnable)
				{
					chestGeneratedFrom.CallRpcSetDelusionPickupIndex(pickupIndex);
				}
				if (context.shouldDestroy)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}

		private void Start()
		{
			waitStartTime = Run.FixedTimeStamp.now;
			consumed = false;
			UpdatePickupDisplay();
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (!base.enabled)
			{
				return Interactability.Disabled;
			}
			if (waitStartTime.timeSince < waitDuration || consumed)
			{
				return Interactability.Disabled;
			}
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				if (!BodyHasPickupPermission(component))
				{
					return Interactability.Disabled;
				}
				return Interactability.Available;
			}
			return Interactability.Disabled;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			AttemptGrant(activator.GetComponent<CharacterBody>());
		}

		public bool ShouldShowOnScanner()
		{
			return true;
		}

		public bool ShouldProximityHighlight()
		{
			return true;
		}

		public string GetDisplayName()
		{
			return Language.GetString(PickupCatalog.GetPickupDef(pickupIndex)?.nameToken ?? PickupCatalog.invalidPickupToken);
		}

		public void SetPickupIndexFromString(string pickupString)
		{
			if (NetworkServer.active)
			{
				PickupIndex networkpickupIndex = PickupCatalog.FindPickupIndex(pickupString);
				NetworkpickupIndex = networkpickupIndex;
			}
		}

		[InitDuringStartup]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/GenericPickup", delegate(GameObject operationResult)
			{
				pickupPrefab = operationResult;
			});
		}

		public static GenericPickupController CreatePickup(in CreatePickupInfo createPickupInfo)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(createPickupInfo.prefabOverride ?? pickupPrefab, createPickupInfo.position, createPickupInfo.rotation);
			GenericPickupController component = gameObject.GetComponent<GenericPickupController>();
			if ((bool)component)
			{
				component.NetworkpickupIndex = createPickupInfo.pickupIndex;
				component.chestGeneratedFrom = createPickupInfo.chest;
			}
			else
			{
				PickupDisplay componentInChildren = gameObject.GetComponentInChildren<PickupDisplay>();
				if ((bool)componentInChildren)
				{
					GameObject modelObjectOverride = gameObject.GetComponentInChildren<MeshRenderer>().gameObject;
					componentInChildren.RebuildModel(modelObjectOverride);
				}
			}
			PickupIndexNetworker component2 = gameObject.GetComponent<PickupIndexNetworker>();
			if ((bool)component2)
			{
				component2.NetworkpickupIndex = createPickupInfo.pickupIndex;
			}
			PickupPickerController component3 = gameObject.GetComponent<PickupPickerController>();
			if ((bool)component3 && createPickupInfo.pickerOptions != null)
			{
				component3.SetOptionsServer(createPickupInfo.pickerOptions);
			}
			NetworkServer.Spawn(gameObject);
			return component;
		}

		[ContextMenu("Print Pickup Index")]
		private void PrintPickupIndex()
		{
			UnityEngine.Debug.LogFormat("pickupIndex={0}", PickupCatalog.GetPickupDef(pickupIndex)?.internalName ?? "Invalid");
		}

		public IInspectInfoProvider GetInspectInfoProvider()
		{
			return this;
		}

		public bool CanBeInspected()
		{
			if (pickupIndex != PickupIndex.none)
			{
				return pickupIndex.isValid;
			}
			return false;
		}

		public InspectInfo GetInfo()
		{
			return PickupCatalog.GetPickupDef(pickupIndex) ?? throw new InvalidOperationException("Attempted to get info for invalid pickup. Should be impossible. Investigate me.");
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
				writer.Write(Recycled);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(Recycled);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				Recycled = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SyncPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader));
			}
			if (((uint)num & 2u) != 0)
			{
				SyncRecycled(reader.ReadBoolean());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public sealed class GenericSkill : MonoBehaviour, ILifeBehavior, IManagedMonoBehaviour
	{
		public class SkillOverride : IEquatable<SkillOverride>
		{
			public readonly object source;

			public readonly SkillDef skillDef;

			public readonly SkillOverridePriority priority;

			public int stock;

			public float rechargeStopwatch;

			public SkillOverride(object source, SkillDef skillDef, SkillOverridePriority priority)
			{
				this.source = source;
				this.skillDef = skillDef;
				this.priority = priority;
				stock = 0;
				rechargeStopwatch = 0f;
			}

			public bool Equals(SkillOverride other)
			{
				if (object.Equals(source, other.source) && object.Equals(skillDef, other.skillDef))
				{
					return priority == other.priority;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is SkillOverride other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((((source != null) ? source.GetHashCode() : 0) * 397) ^ ((skillDef != null) ? skillDef.GetHashCode() : 0)) * 397) ^ (int)priority;
			}
		}

		public enum SkillOverridePriority
		{
			Default,
			Loadout,
			Upgrade,
			Replacement,
			Contextual,
			Network
		}

		public class SkillOverrideHandle : IDisposable
		{
			public readonly object source;

			public readonly SkillDef skill;

			public readonly GenericSkill skillSlot;

			public readonly SkillOverridePriority priority;

			public void Dispose()
			{
			}
		}

		public delegate void StateMachineResolver(GenericSkill genericSkill, SkillDef skillDef, ref EntityStateMachine targetStateMachine);

		[SerializeField]
		private SkillFamily _skillFamily;

		public string skillName;

		public bool hideInCharacterSelect;

		private static readonly List<EntityStateMachine> stateMachineLookupBuffer = new List<EntityStateMachine>();

		private SkillOverride[] skillOverrides = Array.Empty<SkillOverride>();

		private int currentSkillOverride = -1;

		private int bonusStockFromBody;

		public int baseStock;

		private float finalRechargeInterval;

		private float _cooldownScale = 1f;

		private float _flatCooldownReduction = 1f;

		private float _temporaryCooldownPenalty;

		public float baseRechargeStopwatch;

		[HideInInspector]
		public bool hasExecutedSuccessfully;

		public SkillDef skillDef { get; private set; }

		public SkillFamily skillFamily => _skillFamily;

		public SkillDef baseSkill { get; private set; }

		public string skillNameToken => skillDef.GetCurrentNameToken(this);

		public string skillDescriptionToken => skillDef.GetCurrentDescriptionToken(this);

		public float baseRechargeInterval => skillDef.GetRechargeInterval(this);

		public int rechargeStock => skillDef.GetRechargeStock(this);

		public bool beginSkillCooldownOnSkillEnd => skillDef.beginSkillCooldownOnSkillEnd;

		public SerializableEntityStateType activationState => skillDef.activationState;

		public InterruptPriority interruptPriority => skillDef.interruptPriority;

		public bool isCombatSkill => skillDef.isCombatSkill;

		public bool mustKeyPress => skillDef.mustKeyPress;

		public Sprite icon => skillDef.GetCurrentIcon(this);

		[CanBeNull]
		public EntityStateMachine stateMachine { get; private set; }

		[CanBeNull]
		public SkillDef.BaseSkillInstanceData skillInstanceData { get; set; }

		public CharacterBody characterBody { get; private set; }

		public SkillDef defaultSkillDef { get; private set; }

		public int maxStock { get; private set; } = 1;


		public int stock
		{
			get
			{
				if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length)
				{
					return skillOverrides[currentSkillOverride].stock;
				}
				return baseStock;
			}
			set
			{
				if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length)
				{
					skillOverrides[currentSkillOverride].stock = value;
				}
				else
				{
					baseStock = value;
				}
			}
		}

		public float cooldownScale
		{
			get
			{
				return _cooldownScale;
			}
			set
			{
				if (_cooldownScale != value)
				{
					_cooldownScale = value;
					RecalculateFinalRechargeInterval();
				}
			}
		}

		public float flatCooldownReduction
		{
			get
			{
				return _flatCooldownReduction;
			}
			set
			{
				if (_flatCooldownReduction != value)
				{
					_flatCooldownReduction = value;
					RecalculateFinalRechargeInterval();
				}
			}
		}

		public float temporaryCooldownPenalty
		{
			get
			{
				return _temporaryCooldownPenalty;
			}
			set
			{
				if (_temporaryCooldownPenalty != value)
				{
					_temporaryCooldownPenalty = value;
					RecalculateFinalRechargeInterval();
				}
			}
		}

		public float rechargeStopwatch
		{
			get
			{
				if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length)
				{
					return skillOverrides[currentSkillOverride].rechargeStopwatch;
				}
				return baseRechargeStopwatch;
			}
			set
			{
				if (currentSkillOverride >= 0 && currentSkillOverride < skillOverrides.Length)
				{
					skillOverrides[currentSkillOverride].rechargeStopwatch = value;
				}
				else
				{
					baseRechargeStopwatch = value;
				}
			}
		}

		public float cooldownRemaining
		{
			get
			{
				if (stock != maxStock && rechargeStock != 0)
				{
					return finalRechargeInterval - rechargeStopwatch;
				}
				return 0f;
			}
		}

		public event Action<GenericSkill> onSkillChanged;

		private event StateMachineResolver _customStateMachineResolver;

		public event StateMachineResolver customStateMachineResolver
		{
			add
			{
				_customStateMachineResolver += value;
				PickTargetStateMachine();
			}
			remove
			{
				_customStateMachineResolver -= value;
				PickTargetStateMachine();
			}
		}

		private int FindSkillOverrideIndex(ref SkillOverride skillOverride)
		{
			for (int i = 0; i < skillOverrides.Length; i++)
			{
				if (skillOverrides[i].Equals(skillOverride))
				{
					return i;
				}
			}
			return -1;
		}

		public void SetSkillOverride(object source, SkillDef skillDef, SkillOverridePriority priority)
		{
			SkillOverride skillOverride = new SkillOverride(source, skillDef, priority);
			if (FindSkillOverrideIndex(ref skillOverride) == -1)
			{
				ArrayUtils.ArrayAppend(ref skillOverrides, in skillOverride);
				PickCurrentOverride();
			}
		}

		public void UnsetSkillOverride(object source, SkillDef skillDef, SkillOverridePriority priority)
		{
			SkillOverride skillOverride = new SkillOverride(source, skillDef, priority);
			int num = FindSkillOverrideIndex(ref skillOverride);
			if (num != -1)
			{
				ArrayUtils.ArrayRemoveAtAndResize(ref skillOverrides, num);
				PickCurrentOverride();
			}
		}

		public bool HasSkillOverrideOfPriority(SkillOverridePriority priority)
		{
			for (int i = 0; i < skillOverrides.Length; i++)
			{
				if (priority == skillOverrides[i].priority)
				{
					return true;
				}
			}
			return false;
		}

		private void PickCurrentOverride()
		{
			currentSkillOverride = -1;
			SkillOverridePriority skillOverridePriority = SkillOverridePriority.Default;
			for (int i = 0; i < skillOverrides.Length; i++)
			{
				SkillOverridePriority priority = skillOverrides[i].priority;
				if (skillOverridePriority <= priority)
				{
					currentSkillOverride = i;
					skillOverridePriority = priority;
				}
			}
			if (currentSkillOverride == -1)
			{
				SetSkillInternal(baseSkill);
			}
			else
			{
				SetSkillInternal(skillOverrides[currentSkillOverride].skillDef);
			}
		}

		private void SetSkillInternal(SkillDef newSkillDef)
		{
			if (!(skillDef == newSkillDef))
			{
				UnassignSkill();
				AssignSkill(newSkillDef);
				this.onSkillChanged?.Invoke(this);
			}
		}

		public void SetBaseSkill(SkillDef newSkillDef)
		{
			baseSkill = newSkillDef;
			PickCurrentOverride();
		}

		private void UnassignSkill()
		{
			if ((object)skillDef != null)
			{
				skillDef.OnUnassigned(this);
				skillInstanceData = null;
				skillDef = null;
			}
		}

		private void AssignSkill(SkillDef newSkillDef)
		{
			skillDef = newSkillDef;
			if ((object)skillDef != null)
			{
				PickTargetStateMachine();
				RecalculateMaxStock();
				if (skillDef.fullRestockOnAssign && stock < maxStock)
				{
					stock = maxStock;
				}
				if (skillDef.dontAllowPastMaxStocks)
				{
					stock = Mathf.Min(maxStock, stock);
				}
				skillInstanceData = skillDef.OnAssigned(this);
				RecalculateFinalRechargeInterval();
			}
		}

		public void SetBonusStockFromBody(int newBonusStockFromBody)
		{
			bonusStockFromBody = newBonusStockFromBody;
			RecalculateMaxStock();
		}

		private void RecalculateMaxStock()
		{
			if (skillDef != null)
			{
				maxStock = skillDef.GetMaxStock(this) + bonusStockFromBody;
			}
			else
			{
				maxStock = 1;
			}
		}

		private void Awake()
		{
			defaultSkillDef = skillFamily.defaultSkillDef;
			baseSkill = defaultSkillDef;
			characterBody = GetComponent<CharacterBody>();
			AssignSkill(defaultSkillDef);
		}

		private void OnDestroy()
		{
			UnassignSkill();
		}

		private void Start()
		{
			RecalculateMaxStock();
			stock = maxStock;
		}

		private void FixedUpdate()
		{
			ManagedFixedUpdate(Time.fixedDeltaTime);
		}

		public void ManagedFixedUpdate(float deltaTime)
		{
			skillDef?.OnFixedUpdate(this, deltaTime);
		}

		public void OnDeathStart()
		{
			base.enabled = false;
		}

		public bool CanExecute()
		{
			return skillDef?.CanExecute(this) ?? false;
		}

		public bool IsReady()
		{
			return skillDef?.IsReady(this) ?? false;
		}

		public bool ExecuteIfReady()
		{
			hasExecutedSuccessfully = CanExecute();
			if (hasExecutedSuccessfully)
			{
				OnExecute();
				return true;
			}
			return false;
		}

		public void RunRecharge(float dt)
		{
			if (stock < maxStock)
			{
				if (!beginSkillCooldownOnSkillEnd || !(stateMachine.state.GetType() == activationState.stateType))
				{
					rechargeStopwatch += dt;
				}
				if (skillDef != null && skillDef.attackSpeedBuffsRestockSpeed)
				{
					RecalculateFinalRechargeInterval();
				}
				if (rechargeStopwatch >= finalRechargeInterval)
				{
					temporaryCooldownPenalty = 0f;
					RestockSteplike();
				}
			}
		}

		public void Reset()
		{
			rechargeStopwatch = 0f;
			stock = maxStock;
		}

		public bool CanApplyAmmoPack()
		{
			if (stock < maxStock)
			{
				return true;
			}
			return false;
		}

		public void ApplyAmmoPack()
		{
			if (stock < maxStock)
			{
				stock += rechargeStock;
				if (stock > maxStock)
				{
					stock = maxStock;
				}
			}
		}

		public void AddOneStock()
		{
			int num = stock + 1;
			stock = num;
			rechargeStopwatch = 0f;
		}

		public void RemoveAllStocks()
		{
			stock = 0;
			rechargeStopwatch = 0f;
		}

		public void DeductStock(int count)
		{
			stock = Mathf.Max(0, stock - count);
		}

		private void OnExecute()
		{
			skillDef.OnExecute(this);
		}

		public void RechargeBaseSkill(float dt)
		{
			if (baseSkill == null)
			{
				return;
			}
			float rechargeInterval = baseSkill.GetRechargeInterval(this);
			float num = Mathf.Min(rechargeInterval, Mathf.Max(0.5f, rechargeInterval * cooldownScale - flatCooldownReduction)) + temporaryCooldownPenalty;
			int baseMaxStock = GetBaseMaxStock();
			if (num == 0f)
			{
				baseStock = baseMaxStock;
				baseRechargeStopwatch = 0f;
				return;
			}
			baseRechargeStopwatch += dt;
			int num2 = baseSkill.GetRechargeStock(this);
			int num3 = Mathf.FloorToInt(baseRechargeStopwatch / num * (float)num2);
			baseStock += num3;
			if (baseStock >= baseMaxStock)
			{
				baseStock = baseMaxStock;
				baseRechargeStopwatch = 0f;
			}
			else
			{
				baseRechargeStopwatch -= (float)num3 * num;
			}
		}

		public int GetBaseStock()
		{
			return baseStock;
		}

		public int GetBaseMaxStock()
		{
			if (baseSkill == null)
			{
				return 1;
			}
			return baseSkill.GetMaxStock(this) + bonusStockFromBody;
		}

		private void RestockContinuous()
		{
			if (finalRechargeInterval == 0f)
			{
				stock = maxStock;
				rechargeStopwatch = 0f;
				return;
			}
			int num = Mathf.FloorToInt(rechargeStopwatch / finalRechargeInterval * (float)rechargeStock);
			stock += num;
			if (stock >= maxStock)
			{
				stock = maxStock;
				rechargeStopwatch = 0f;
			}
			else
			{
				rechargeStopwatch -= (float)num * finalRechargeInterval;
			}
		}

		public void RestockSteplike()
		{
			stock += rechargeStock;
			if (stock >= maxStock)
			{
				stock = maxStock;
			}
			rechargeStopwatch = 0f;
		}

		public float CalculateFinalRechargeInterval()
		{
			return Mathf.Min(baseRechargeInterval, Mathf.Max(0.5f, baseRechargeInterval * cooldownScale - flatCooldownReduction)) + temporaryCooldownPenalty;
		}

		private void RecalculateFinalRechargeInterval()
		{
			finalRechargeInterval = CalculateFinalRechargeInterval();
		}

		public void RecalculateValues()
		{
			RecalculateMaxStock();
			RecalculateFinalRechargeInterval();
		}

		private void PickTargetStateMachine()
		{
			EntityStateMachine targetStateMachine = stateMachine;
			if (!string.Equals(stateMachine?.customName, skillDef.activationStateMachineName, StringComparison.Ordinal))
			{
				targetStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, skillDef.activationStateMachineName);
			}
			this._customStateMachineResolver?.Invoke(this, skillDef, ref targetStateMachine);
			stateMachine = targetStateMachine;
		}

		[AssetCheck(typeof(GenericSkill))]
		private static void CheckGenericSkillStateMachine(AssetCheckArgs args)
		{
			if (((GenericSkill)args.asset).stateMachine.customName == string.Empty)
			{
				args.LogError("Unnamed state machine.", ((GenericSkill)args.asset).gameObject);
			}
		}
	}
	public class GhostGunController : MonoBehaviour
	{
		public GameObject owner;

		public float interval;

		public float maxRange = 20f;

		public float turnSpeed = 180f;

		public UnityEngine.Vector3 localOffset = UnityEngine.Vector3.zero;

		public float positionSmoothTime = 0.05f;

		public float timeout = 2f;

		private float fireTimer;

		private float timeoutTimer;

		private int ammo;

		private int kills;

		private GameObject target;

		private UnityEngine.Vector3 velocity;

		private void Start()
		{
			fireTimer = 0f;
			ammo = 6;
			kills = 0;
			timeoutTimer = timeout;
		}

		private void Fire(UnityEngine.Vector3 origin, UnityEngine.Vector3 aimDirection)
		{
			BulletAttack obj = new BulletAttack
			{
				aimVector = aimDirection,
				bulletCount = 1u,
				damage = CalcDamage(),
				force = 2400f,
				maxSpread = 0f,
				minSpread = 0f,
				muzzleName = "muzzle",
				origin = origin,
				owner = owner,
				procCoefficient = 0f,
				tracerEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/Tracers/TracerSmokeChase"),
				hitEffectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/Hitspark1"),
				damageColorIndex = DamageColorIndex.Item
			};
			GlobalEventManager.onCharacterDeathGlobal += CheckForKill;
			obj.Fire();
			GlobalEventManager.onCharacterDeathGlobal -= CheckForKill;
		}

		private void CheckForKill(DamageReport damageReport)
		{
			if (damageReport.damageInfo.inflictor == base.gameObject)
			{
				kills++;
			}
		}

		private float CalcDamage()
		{
			float damage = owner.GetComponent<CharacterBody>().damage;
			return 5f * Mathf.Pow(2f, kills) * damage;
		}

		private bool HasLoS(GameObject target)
		{
			Ray ray = new Ray(base.transform.position, target.transform.position - base.transform.position);
			RaycastHit hitInfo = default(RaycastHit);
			if (Physics.Raycast(ray, out hitInfo, maxRange, (int)LayerIndex.CommonMasks.characterBodiesOrDefault | (int)LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				return hitInfo.collider.gameObject == target;
			}
			return true;
		}

		private bool WillHit(GameObject target)
		{
			Ray ray = new Ray(base.transform.position, base.transform.forward);
			RaycastHit hitInfo = default(RaycastHit);
			if (Physics.Raycast(ray, out hitInfo, maxRange, (int)LayerIndex.entityPrecise.mask | (int)LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				HurtBox component = hitInfo.collider.GetComponent<HurtBox>();
				if ((bool)component)
				{
					HealthComponent healthComponent = component.healthComponent;
					if ((bool)healthComponent)
					{
						return healthComponent.gameObject == target;
					}
				}
			}
			return false;
		}

		private GameObject FindTarget()
		{
			TeamIndex teamA = TeamIndex.Neutral;
			TeamComponent component = owner.GetComponent<TeamComponent>();
			if ((bool)component)
			{
				teamA = component.teamIndex;
			}
			UnityEngine.Vector3 position = base.transform.position;
			float num = CalcDamage();
			float num2 = maxRange * maxRange;
			GameObject gameObject = null;
			GameObject result = null;
			float num3 = 0f;
			float num4 = float.PositiveInfinity;
			for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
			{
				if (TeamManager.IsTeamEnemy(teamA, teamIndex))
				{
					ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
					for (int i = 0; i < teamMembers.Count; i++)
					{
						GameObject gameObject2 = teamMembers[i].gameObject;
						if (!((gameObject2.transform.position - position).sqrMagnitude <= num2))
						{
							continue;
						}
						HealthComponent component2 = teamMembers[i].GetComponent<HealthComponent>();
						if (!component2)
						{
							continue;
						}
						if (component2.health <= num)
						{
							if (component2.health > num3 && HasLoS(gameObject2))
							{
								gameObject = gameObject2;
								num3 = component2.health;
							}
						}
						else if (component2.health < num4 && HasLoS(gameObject2))
						{
							result = gameObject2;
							num4 = component2.health;
						}
					}
				}
			}
			if (!gameObject)
			{
				return result;
			}
			return gameObject;
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if (!owner)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			InputBankTest component = owner.GetComponent<InputBankTest>();
			UnityEngine.Vector3 vector = (component ? component.aimDirection : base.transform.forward);
			if ((bool)target)
			{
				vector = (target.transform.position - base.transform.position).normalized;
			}
			base.transform.forward = UnityEngine.Vector3.RotateTowards(base.transform.forward, vector, MathF.PI / 180f * turnSpeed * Time.fixedDeltaTime, 0f);
			UnityEngine.Vector3 vector2 = owner.transform.position + base.transform.rotation * localOffset;
			base.transform.position = UnityEngine.Vector3.SmoothDamp(base.transform.position, vector2, ref velocity, positionSmoothTime, float.PositiveInfinity, Time.fixedDeltaTime);
			fireTimer -= Time.fixedDeltaTime;
			timeoutTimer -= Time.fixedDeltaTime;
			if (fireTimer <= 0f)
			{
				target = FindTarget();
				fireTimer = interval;
			}
			if ((bool)target && WillHit(target))
			{
				UnityEngine.Vector3 normalized = (target.transform.position - base.transform.position).normalized;
				Fire(base.transform.position, normalized);
				ammo--;
				target = null;
				timeoutTimer = timeout;
			}
			if (ammo <= 0 || timeoutTimer <= 0f)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	[RequireComponent(typeof(Inventory))]
	public class GivePickupsOnStart : MonoBehaviour
	{
		[Serializable]
		public struct ItemInfo
		{
			public string itemString;

			public int count;
		}

		[Serializable]
		public struct ItemDefInfo
		{
			public ItemDef itemDef;

			public int count;

			public bool dontExceedCount;
		}

		public EquipmentDef equipmentDef;

		[ShowFieldObsolete]
		public string equipmentString;

		public bool overwriteEquipment = true;

		public ItemDefInfo[] itemDefInfos;

		[ShowFieldObsolete]
		public ItemInfo[] itemInfos;

		private Inventory inventory;

		private void Start()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			inventory = GetComponent<Inventory>();
			if (overwriteEquipment || inventory.currentEquipmentIndex == EquipmentIndex.None)
			{
				if ((bool)equipmentDef)
				{
					inventory.SetEquipmentIndex(equipmentDef.equipmentIndex);
				}
				else if (!string.IsNullOrEmpty(equipmentString))
				{
					inventory.GiveEquipmentString(equipmentString);
				}
			}
			ItemDefInfo[] array = itemDefInfos;
			for (int i = 0; i < array.Length; i++)
			{
				ItemDefInfo itemDefInfo = array[i];
				if ((bool)itemDefInfo.itemDef)
				{
					int num = itemDefInfo.count;
					if (itemDefInfo.dontExceedCount)
					{
						num = Math.Max(itemDefInfo.count - inventory.GetItemCount(itemDefInfo.itemDef), 0);
					}
					if (num != 0)
					{
						inventory.GiveItem(itemDefInfo.itemDef, num);
					}
				}
			}
			for (int j = 0; j < itemInfos.Length; j++)
			{
				ItemInfo itemInfo = itemInfos[j];
				inventory.GiveItemString(itemInfo.itemString, itemInfo.count);
			}
		}
	}
	[ExecuteAlways]
	public class GlassesSize : MonoBehaviour
	{
		public Transform glassesModelBase;

		public Transform glassesBridgeLeft;

		public Transform glassesBridgeRight;

		public float bridgeOffsetScale;

		public UnityEngine.Vector3 offsetVector = UnityEngine.Vector3.right;

		private void Start()
		{
		}

		private void Update()
		{
			UpdateGlasses();
		}

		private void UpdateGlasses()
		{
			UnityEngine.Vector3 localScale = base.transform.localScale;
			float num = Mathf.Max(localScale.y, localScale.z);
			UnityEngine.Vector3 localScale2 = new UnityEngine.Vector3(1f / localScale.x * num, 1f / localScale.y * num, 1f / localScale.z * num);
			if ((bool)glassesModelBase)
			{
				glassesModelBase.transform.localScale = localScale2;
			}
			if ((bool)glassesBridgeLeft && (bool)glassesBridgeRight)
			{
				float num2 = (localScale.x / num - 1f) * bridgeOffsetScale;
				glassesBridgeLeft.transform.localPosition = offsetVector * (0f - num2);
				glassesBridgeRight.transform.localPosition = offsetVector * num2;
			}
		}
	}
	public class GlobalDeathRewards : MonoBehaviour
	{
		[Serializable]
		public struct PickupReward
		{
			[SerializeField]
			public PickupDropTable dropTable;

			[EnumMask(typeof(CharacterBody.BodyFlags))]
			[SerializeField]
			public CharacterBody.BodyFlags requiredBodyFlags;

			[SerializeField]
			[Range(0f, 1f)]
			public float chance;

			[SerializeField]
			public UnityEngine.Vector3 velocity;
		}

		[SerializeField]
		private bool requirePlayerAttacker;

		[SerializeField]
		private PickupReward[] pickupRewards;

		private Xoroshiro128Plus rng;

		private void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.runRNG.nextUlong);
			}
		}

		private void OnEnable()
		{
			GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
		}

		private void OnDisable()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
		}

		private void OnCharacterDeathGlobal(DamageReport damageReport)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			bool flag = true;
			if (requirePlayerAttacker)
			{
				flag = (bool)damageReport.attackerMaster && (bool)damageReport.attackerMaster.GetComponent<PlayerCharacterMasterController>();
			}
			if (!flag)
			{
				return;
			}
			PickupReward[] array = pickupRewards;
			for (int i = 0; i < array.Length; i++)
			{
				PickupReward pickupReward = array[i];
				if ((damageReport.victimBody.bodyFlags & pickupReward.requiredBodyFlags) == pickupReward.requiredBodyFlags && (bool)pickupReward.dropTable && rng.nextNormalizedFloat <= pickupReward.chance)
				{
					PickupDropletController.CreatePickupDroplet(pickupReward.dropTable.GenerateDrop(rng), damageReport.victim.transform.position, pickupReward.velocity);
				}
			}
		}
	}
	public class GlobalEventManager : MonoBehaviour
	{
		private static class CommonAssets
		{
			public static CharacterMaster wispSoulMasterPrefabMasterComponent;

			public static GameObject igniteOnKillExplosionEffectPrefab;

			public static GameObject missilePrefab;

			public static GameObject explodeOnDeathPrefab;

			public static GameObject daggerPrefab;

			public static GameObject bleedOnHitAndExplodeImpactEffect;

			public static GameObject bleedOnHitAndExplodeBlastEffect;

			public static GameObject minorConstructOnKillProjectile;

			public static GameObject knockbackFinEffect;

			public static GameObject runicMeteorEffect;

			public static GameObject missileVoidPrefab;

			public static GameObject eliteEarthHealerMaster;

			public static PickupDropTable dtSonorousEchoPath;

			public static GameObject loseCoinsImpactEffectPrefab;

			public static void Load()
			{
				AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/CharacterMasters/WispSoulMaster");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					wispSoulMasterPrefabMasterComponent = x.Result.GetComponent<CharacterMaster>();
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/IgniteExplosionVFX");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					igniteOnKillExplosionEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Projectiles/MissileProjectile");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					missilePrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Projectiles/DaggerProjectile");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					daggerPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/BleedOnHitAndExplode_Impact");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					bleedOnHitAndExplodeImpactEffect = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/NetworkedObjects/BleedOnHitAndExplodeDelay");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					bleedOnHitAndExplodeBlastEffect = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Projectiles/MissileVoidProjectile");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					missileVoidPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/KnockBackHitEnemiesImpact");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					knockbackFinEffect = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/RunicMeteorStrikePredictionEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					runicMeteorEffect = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/EliteEarth/AffixEarthHealerMaster.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					eliteEarthHealerMaster = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/Base/ExplodeOnDeath/WilloWispDelay.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					explodeOnDeathPrefab = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/MinorConstructOnKill/MinorConstructOnKillProjectile.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					minorConstructOnKillProjectile = x.Result;
				};
				AsyncOperationHandle<PickupDropTable> asyncOperationHandle2 = Addressables.LoadAssetAsync<PickupDropTable>("RoR2/DLC2/Items/ResetChests/dtSonorousEcho.asset");
				asyncOperationHandle2.Completed += delegate(AsyncOperationHandle<PickupDropTable> x)
				{
					dtSonorousEchoPath = x.Result;
				};
				asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("RoR2/Base/Common/VFX/CoinImpact.prefab");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					loseCoinsImpactEffectPrefab = x.Result;
				};
			}
		}

		public static GlobalEventManager instance;

		[Obsolete("Transform of the global event manager should not be used! You probably meant something else instead.", true)]
		private new Transform transform;

		[Obsolete("GameObject of the global event manager should not be used! You probably meant something else instead.", true)]
		private new GameObject gameObject;

		private static readonly string[] standardDeathQuoteTokens = (from i in Enumerable.Range(0, 37)
			select "PLAYER_DEATH_QUOTE_" + TextSerialization.ToStringInvariant(i)).ToArray();

		private static readonly string[] fallDamageDeathQuoteTokens = (from i in Enumerable.Range(0, 5)
			select "PLAYER_DEATH_QUOTE_FALLDAMAGE_" + TextSerialization.ToStringInvariant(i)).ToArray();

		private static readonly SphereSearch igniteOnKillSphereSearch = new SphereSearch();

		private static readonly List<HurtBox> igniteOnKillHurtBoxBuffer = new List<HurtBox>();

		public static event Action<DamageReport> onCharacterDeathGlobal;

		public static event Action<TeamIndex> onTeamLevelUp;

		public static event Action<CharacterBody> onCharacterLevelUp;

		public static event Action<Interactor, IInteractable, GameObject> OnInteractionsGlobal;

		public static event Action<DamageDealtMessage> onClientDamageNotified;

		public static event Action<DamageReport> onServerDamageDealt;

		public static event Action<DamageReport, float> onServerCharacterExecuted;

		[InitDuringStartup]
		private static void Init()
		{
			CommonAssets.Load();
		}

		private void OnEnable()
		{
			if ((bool)instance)
			{
				UnityEngine.Debug.LogError("Only one GlobalEventManager can exist at a time.");
			}
			else
			{
				instance = this;
			}
		}

		private void OnDisable()
		{
			if (instance == this)
			{
				instance = null;
			}
		}

		public void OnHitEnemy([NotNull] DamageInfo damageInfo, [NotNull] GameObject victim)
		{
			ProcessHitEnemy(damageInfo, victim);
		}

		private void ProcessHitEnemy([NotNull] DamageInfo damageInfo, [NotNull] GameObject victim)
		{
			if (damageInfo.procCoefficient == 0f || damageInfo.rejected || !NetworkServer.active)
			{
				return;
			}
			if (damageInfo.attacker == null)
			{
				HandleDamageWithNoAttacker(damageInfo, victim);
			}
			if (!damageInfo.attacker || !(damageInfo.procCoefficient > 0f))
			{
				return;
			}
			uint? maxStacksFromAttacker = null;
			if ((bool)damageInfo?.inflictor)
			{
				ProjectileDamage component = damageInfo.inflictor.GetComponent<ProjectileDamage>();
				if ((bool)component && component.useDotMaxStacksFromAttacker)
				{
					maxStacksFromAttacker = component.dotMaxStacksFromAttacker;
				}
			}
			CharacterBody component2 = damageInfo.attacker.GetComponent<CharacterBody>();
			CharacterBody characterBody = (victim ? victim.GetComponent<CharacterBody>() : null);
			if ((ulong)(damageInfo.damageType & DamageType.LunarRuin) != 0)
			{
				if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L)
				{
					characterBody.AddTimedBuff(DLC2Content.Buffs.lunarruin, 420f);
				}
				else
				{
					DotController.InflictDot(characterBody.gameObject, damageInfo.attacker, DotController.DotIndex.LunarRuin, 5f);
				}
			}
			if ((ulong)(damageInfo.damageType & DamageTypeExtended.DisableAllSkills) != 0L)
			{
				if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L)
				{
					UnityEngine.Debug.LogFormat("Adding DisableAllSkills");
					characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 420f);
				}
				else
				{
					UnityEngine.Debug.LogFormat("Adding DisableAllSkills for 5s");
					characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 5f);
				}
			}
			if (!component2)
			{
				return;
			}
			if ((ulong)(damageInfo.damageType & DamageType.PoisonOnHit) != 0)
			{
				DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Poison, 10f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker);
			}
			CharacterMaster master = component2.master;
			if (!master)
			{
				return;
			}
			Inventory inventory = master.inventory;
			TeamComponent component3 = component2.GetComponent<TeamComponent>();
			TeamIndex teamIndex = (component3 ? component3.teamIndex : TeamIndex.Neutral);
			UnityEngine.Vector3 aimOrigin = component2.aimOrigin;
			if (damageInfo.crit)
			{
				instance.OnCrit(component2, damageInfo, master, damageInfo.procCoefficient, damageInfo.procChainMask);
			}
			if (!damageInfo.procChainMask.HasProc(ProcType.HealOnHit))
			{
				int itemCount = inventory.GetItemCount(RoR2Content.Items.Seed);
				if (itemCount > 0)
				{
					HealthComponent component4 = component2.GetComponent<HealthComponent>();
					if ((bool)component4)
					{
						ProcChainMask procChainMask = damageInfo.procChainMask;
						procChainMask.AddProc(ProcType.HealOnHit);
						component4.Heal((float)itemCount * damageInfo.procCoefficient, procChainMask);
					}
				}
			}
			if (!damageInfo.procChainMask.HasProc(ProcType.BleedOnHit))
			{
				bool flag = (ulong)(damageInfo.damageType & DamageType.BleedOnHit) != 0 || (inventory.GetItemCount(RoR2Content.Items.BleedOnHitAndExplode) > 0 && damageInfo.crit);
				if ((component2.bleedChance > 0f || flag) && (flag || Util.CheckRoll(damageInfo.procCoefficient * component2.bleedChance, master)))
				{
					ProcChainMask procChainMask2 = damageInfo.procChainMask;
					procChainMask2.AddProc(ProcType.BleedOnHit);
					DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Bleed, 3f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker);
				}
			}
			if (!damageInfo.procChainMask.HasProc(ProcType.FractureOnHit))
			{
				int itemCount2 = inventory.GetItemCount(DLC1Content.Items.BleedOnHitVoid);
				itemCount2 += (component2.HasBuff(DLC1Content.Buffs.EliteVoid) ? 10 : 0);
				if (itemCount2 > 0 && Util.CheckRoll(damageInfo.procCoefficient * (float)itemCount2 * 10f, master))
				{
					ProcChainMask procChainMask3 = damageInfo.procChainMask;
					procChainMask3.AddProc(ProcType.FractureOnHit);
					DotController.DotDef dotDef = DotController.GetDotDef(DotController.DotIndex.Fracture);
					DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Fracture, dotDef.interval, 1f, maxStacksFromAttacker);
				}
			}
			bool flag2 = (ulong)(damageInfo.damageType & DamageType.BlightOnHit) != 0;
			if (flag2 && flag2)
			{
				_ = damageInfo.procChainMask;
				DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Blight, 5f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker);
			}
			if ((ulong)(damageInfo.damageType & DamageType.WeakOnHit) != 0)
			{
				characterBody.AddTimedBuff(RoR2Content.Buffs.Weak, 6f * damageInfo.procCoefficient);
			}
			if ((ulong)(damageInfo.damageType & DamageType.IgniteOnHit) != 0 || component2.HasBuff(RoR2Content.Buffs.AffixRed))
			{
				float num = 0.5f;
				InflictDotInfo inflictDotInfo = default(InflictDotInfo);
				inflictDotInfo.attackerObject = damageInfo.attacker;
				inflictDotInfo.victimObject = victim;
				inflictDotInfo.totalDamage = damageInfo.damage * num;
				inflictDotInfo.damageMultiplier = 1f;
				inflictDotInfo.dotIndex = DotController.DotIndex.Burn;
				inflictDotInfo.maxStacksFromAttacker = maxStacksFromAttacker;
				InflictDotInfo dotInfo = inflictDotInfo;
				StrengthenBurnUtils.CheckDotForUpgrade(inventory, ref dotInfo);
				DotController.InflictDot(ref dotInfo);
			}
			int num2 = (component2.HasBuff(RoR2Content.Buffs.AffixWhite) ? 1 : 0);
			num2 += (component2.HasBuff(RoR2Content.Buffs.AffixHaunted) ? 2 : 0);
			if (num2 > 0 && (bool)characterBody)
			{
				EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/AffixWhiteImpactEffect"), damageInfo.position, UnityEngine.Vector3.up, transmit: true);
				characterBody.AddTimedBuff(RoR2Content.Buffs.Slow80, 1.5f * damageInfo.procCoefficient * (float)num2);
			}
			int itemCount3 = master.inventory.GetItemCount(RoR2Content.Items.SlowOnHit);
			if (itemCount3 > 0 && (bool)characterBody)
			{
				characterBody.AddTimedBuff(RoR2Content.Buffs.Slow60, 2f * (float)itemCount3);
			}
			int itemCount4 = master.inventory.GetItemCount(DLC1Content.Items.SlowOnHitVoid);
			if (itemCount4 > 0 && (bool)characterBody && Util.CheckRoll(Util.ConvertAmplificationPercentageIntoReductionPercentage(5f * (float)itemCount4 * damageInfo.procCoefficient), master))
			{
				characterBody.AddTimedBuff(RoR2Content.Buffs.Nullified, 1f * (float)itemCount4);
			}
			if ((component2.HasBuff(RoR2Content.Buffs.AffixPoison) ? 1 : 0) > 0 && (bool)characterBody)
			{
				characterBody.AddTimedBuff(RoR2Content.Buffs.HealingDisabled, 8f * damageInfo.procCoefficient);
			}
			int itemCount5 = inventory.GetItemCount(RoR2Content.Items.GoldOnHit);
			if (itemCount5 > 0 && Util.CheckRoll(30f * damageInfo.procCoefficient, master))
			{
				GoldOrb goldOrb = new GoldOrb();
				goldOrb.origin = damageInfo.position;
				goldOrb.target = component2.mainHurtBox;
				goldOrb.goldAmount = (uint)((float)itemCount5 * 2f * Run.instance.difficultyCoefficient);
				OrbManager.instance.AddOrb(goldOrb);
				EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/CoinImpact"), damageInfo.position, UnityEngine.Vector3.up, transmit: true);
			}
			if (!damageInfo.procChainMask.HasProc(ProcType.Missile))
			{
				int itemCount6 = inventory.GetItemCount(RoR2Content.Items.Missile);
				if (itemCount6 > 0)
				{
					if (Util.CheckRoll(10f * damageInfo.procCoefficient, master))
					{
						float damageCoefficient = 3f * (float)itemCount6;
						float missileDamage = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient);
						MissileUtils.FireMissile(component2.corePosition, component2, damageInfo.procChainMask, victim, missileDamage, damageInfo.crit, CommonAssets.missilePrefab, DamageColorIndex.Item, addMissileProc: true);
					}
				}
				else
				{
					itemCount6 = inventory.GetItemCount(DLC1Content.Items.MissileVoid);
					if (itemCount6 > 0 && component2.healthComponent.shield > 0f)
					{
						int valueOrDefault = (component2?.inventory?.GetItemCount(DLC1Content.Items.MoreMissile)).GetValueOrDefault();
						float num3 = Mathf.Max(1f, 1f + 0.5f * (float)(valueOrDefault - 1));
						float damageCoefficient2 = 0.4f * (float)itemCount6;
						float damageValue = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient2) * num3;
						int num4 = ((valueOrDefault <= 0) ? 1 : 3);
						for (int i = 0; i < num4; i++)
						{
							MissileVoidOrb missileVoidOrb = new MissileVoidOrb();
							missileVoidOrb.origin = aimOrigin;
							missileVoidOrb.damageValue = damageValue;
							missileVoidOrb.isCrit = damageInfo.crit;
							missileVoidOrb.teamIndex = teamIndex;
							missileVoidOrb.attacker = damageInfo.attacker;
							missileVoidOrb.procChainMask = damageInfo.procChainMask;
							missileVoidOrb.procChainMask.AddProc(ProcType.Missile);
							missileVoidOrb.procCoefficient = 0.2f;
							missileVoidOrb.damageColorIndex = DamageColorIndex.Void;
							HurtBox mainHurtBox = characterBody.mainHurtBox;
							if ((bool)mainHurtBox)
							{
								missileVoidOrb.target = mainHurtBox;
								OrbManager.instance.AddOrb(missileVoidOrb);
							}
						}
					}
				}
			}
			if (component2.HasBuff(JunkContent.Buffs.LoaderPylonPowered) && !damageInfo.procChainMask.HasProc(ProcType.LoaderLightning))
			{
				float damageCoefficient3 = 0.3f;
				float damageValue2 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient3);
				LightningOrb lightningOrb = new LightningOrb();
				lightningOrb.origin = damageInfo.position;
				lightningOrb.damageValue = damageValue2;
				lightningOrb.isCrit = damageInfo.crit;
				lightningOrb.bouncesRemaining = 3;
				lightningOrb.teamIndex = teamIndex;
				lightningOrb.attacker = damageInfo.attacker;
				lightningOrb.bouncedObjects = new List<HealthComponent> { victim.GetComponent<HealthComponent>() };
				lightningOrb.procChainMask = damageInfo.procChainMask;
				lightningOrb.procChainMask.AddProc(ProcType.LoaderLightning);
				lightningOrb.procCoefficient = 0f;
				lightningOrb.lightningType = LightningOrb.LightningType.Loader;
				lightningOrb.damageColorIndex = DamageColorIndex.Item;
				lightningOrb.range = 20f;
				HurtBox hurtBox = lightningOrb.PickNextTarget(damageInfo.position);
				if ((bool)hurtBox)
				{
					lightningOrb.target = hurtBox;
					OrbManager.instance.AddOrb(lightningOrb);
				}
			}
			int itemCount7 = inventory.GetItemCount(RoR2Content.Items.ChainLightning);
			float num5 = 25f;
			if (itemCount7 > 0 && !damageInfo.procChainMask.HasProc(ProcType.ChainLightning) && Util.CheckRoll(num5 * damageInfo.procCoefficient, master))
			{
				float damageCoefficient4 = 0.8f;
				float damageValue3 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient4);
				LightningOrb lightningOrb2 = new LightningOrb();
				lightningOrb2.origin = damageInfo.position;
				lightningOrb2.damageValue = damageValue3;
				lightningOrb2.isCrit = damageInfo.crit;
				lightningOrb2.bouncesRemaining = 2 * itemCount7;
				lightningOrb2.teamIndex = teamIndex;
				lightningOrb2.attacker = damageInfo.attacker;
				lightningOrb2.bouncedObjects = new List<HealthComponent> { victim.GetComponent<HealthComponent>() };
				lightningOrb2.procChainMask = damageInfo.procChainMask;
				lightningOrb2.procChainMask.AddProc(ProcType.ChainLightning);
				lightningOrb2.procCoefficient = 0.2f;
				lightningOrb2.lightningType = LightningOrb.LightningType.Ukulele;
				lightningOrb2.damageColorIndex = DamageColorIndex.Item;
				lightningOrb2.range += 2 * itemCount7;
				HurtBox hurtBox2 = lightningOrb2.PickNextTarget(damageInfo.position);
				if ((bool)hurtBox2)
				{
					lightningOrb2.target = hurtBox2;
					OrbManager.instance.AddOrb(lightningOrb2);
				}
			}
			int itemCount8 = inventory.GetItemCount(DLC1Content.Items.ChainLightningVoid);
			float num6 = 25f;
			if (itemCount8 > 0 && !damageInfo.procChainMask.HasProc(ProcType.ChainLightning) && Util.CheckRoll(num6 * damageInfo.procCoefficient, master))
			{
				float damageCoefficient5 = 0.6f;
				float damageValue4 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient5);
				VoidLightningOrb voidLightningOrb = new VoidLightningOrb();
				voidLightningOrb.origin = damageInfo.position;
				voidLightningOrb.damageValue = damageValue4;
				voidLightningOrb.isCrit = damageInfo.crit;
				voidLightningOrb.totalStrikes = 3 * itemCount8;
				voidLightningOrb.teamIndex = teamIndex;
				voidLightningOrb.attacker = damageInfo.attacker;
				voidLightningOrb.procChainMask = damageInfo.procChainMask;
				voidLightningOrb.procChainMask.AddProc(ProcType.ChainLightning);
				voidLightningOrb.procCoefficient = 0.2f;
				voidLightningOrb.damageColorIndex = DamageColorIndex.Void;
				voidLightningOrb.secondsPerStrike = 0.1f;
				HurtBox mainHurtBox2 = characterBody.mainHurtBox;
				if ((bool)mainHurtBox2)
				{
					voidLightningOrb.target = mainHurtBox2;
					OrbManager.instance.AddOrb(voidLightningOrb);
				}
			}
			int itemCount9 = inventory.GetItemCount(RoR2Content.Items.BounceNearby);
			if (itemCount9 > 0)
			{
				float num7 = (1f - 100f / (100f + 20f * (float)itemCount9)) * 100f;
				if (!damageInfo.procChainMask.HasProc(ProcType.BounceNearby) && Util.CheckRoll(num7 * damageInfo.procCoefficient, master))
				{
					List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
					int maxTargets = 5 + itemCount9 * 5;
					BullseyeSearch search = new BullseyeSearch();
					List<HealthComponent> list2 = CollectionPool<HealthComponent, List<HealthComponent>>.RentCollection();
					if ((bool)component2 && (bool)component2.healthComponent)
					{
						list2.Add(component2.healthComponent);
					}
					if ((bool)characterBody && (bool)characterBody.healthComponent)
					{
						list2.Add(characterBody.healthComponent);
					}
					BounceOrb.SearchForTargets(search, teamIndex, damageInfo.position, 30f, maxTargets, list, list2);
					CollectionPool<HealthComponent, List<HealthComponent>>.ReturnCollection(list2);
					List<HealthComponent> bouncedObjects = new List<HealthComponent> { victim.GetComponent<HealthComponent>() };
					float damageCoefficient6 = 1f;
					float damageValue5 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient6);
					int j = 0;
					for (int count = list.Count; j < count; j++)
					{
						HurtBox hurtBox3 = list[j];
						if ((bool)hurtBox3)
						{
							BounceOrb bounceOrb = new BounceOrb();
							bounceOrb.origin = damageInfo.position;
							bounceOrb.damageValue = damageValue5;
							bounceOrb.isCrit = damageInfo.crit;
							bounceOrb.teamIndex = teamIndex;
							bounceOrb.attacker = damageInfo.attacker;
							bounceOrb.procChainMask = damageInfo.procChainMask;
							bounceOrb.procChainMask.AddProc(ProcType.BounceNearby);
							bounceOrb.procCoefficient = 0.33f;
							bounceOrb.damageColorIndex = DamageColorIndex.Item;
							bounceOrb.bouncedObjects = bouncedObjects;
							bounceOrb.target = hurtBox3;
							OrbManager.instance.AddOrb(bounceOrb);
						}
					}
					CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
				}
			}
			int itemCount10 = inventory.GetItemCount(RoR2Content.Items.StickyBomb);
			if (itemCount10 > 0 && Util.CheckRoll(5f * (float)itemCount10 * damageInfo.procCoefficient, master) && (bool)characterBody)
			{
				bool alive = characterBody.healthComponent.alive;
				float num8 = 5f;
				UnityEngine.Vector3 position = damageInfo.position;
				UnityEngine.Vector3 forward = characterBody.corePosition - position;
				float magnitude = forward.magnitude;
				UnityEngine.Quaternion rotation = ((magnitude != 0f) ? Util.QuaternionSafeLookRotation(forward) : UnityEngine.Random.rotationUniform);
				float damageCoefficient7 = 1.8f;
				float damage = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient7);
				ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/StickyBomb"), position, rotation, damageInfo.attacker, damage, 100f, damageInfo.crit, DamageColorIndex.Item, null, alive ? (magnitude * num8) : (-1f));
			}
			if (!damageInfo.procChainMask.HasProc(ProcType.Rings) && damageInfo.damage / component2.damage >= 4f)
			{
				if (component2.HasBuff(RoR2Content.Buffs.ElementalRingsReady))
				{
					int itemCount11 = inventory.GetItemCount(RoR2Content.Items.IceRing);
					int itemCount12 = inventory.GetItemCount(RoR2Content.Items.FireRing);
					component2.RemoveBuff(RoR2Content.Buffs.ElementalRingsReady);
					for (int k = 1; (float)k <= 10f; k++)
					{
						component2.AddTimedBuff(RoR2Content.Buffs.ElementalRingsCooldown, k);
					}
					ProcChainMask procChainMask4 = damageInfo.procChainMask;
					procChainMask4.AddProc(ProcType.Rings);
					UnityEngine.Vector3 position2 = damageInfo.position;
					if (itemCount11 > 0)
					{
						float damageCoefficient8 = 2.5f * (float)itemCount11;
						float damage2 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient8);
						DamageInfo damageInfo2 = new DamageInfo
						{
							damage = damage2,
							damageColorIndex = DamageColorIndex.Item,
							damageType = DamageType.Generic,
							attacker = damageInfo.attacker,
							crit = damageInfo.crit,
							force = UnityEngine.Vector3.zero,
							inflictor = null,
							position = position2,
							procChainMask = procChainMask4,
							procCoefficient = 1f
						};
						EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/IceRingExplosion"), position2, UnityEngine.Vector3.up, transmit: true);
						characterBody.AddTimedBuff(RoR2Content.Buffs.Slow80, 3f * (float)itemCount11);
						characterBody.healthComponent.TakeDamage(damageInfo2);
					}
					if (itemCount12 > 0)
					{
						GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/FireTornado");
						float resetInterval = gameObject.GetComponent<ProjectileOverlapAttack>().resetInterval;
						float lifetime = gameObject.GetComponent<ProjectileSimple>().lifetime;
						float damageCoefficient9 = 3f * (float)itemCount12;
						float damage3 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient9) / lifetime * resetInterval;
						float speedOverride = 0f;
						UnityEngine.Quaternion rotation2 = UnityEngine.Quaternion.identity;
						UnityEngine.Vector3 vector = position2 - aimOrigin;
						vector.y = 0f;
						if (vector != UnityEngine.Vector3.zero)
						{
							speedOverride = -1f;
							rotation2 = Util.QuaternionSafeLookRotation(vector, UnityEngine.Vector3.up);
						}
						ProjectileManager.instance.FireProjectile(new FireProjectileInfo
						{
							damage = damage3,
							crit = damageInfo.crit,
							damageColorIndex = DamageColorIndex.Item,
							position = position2,
							procChainMask = procChainMask4,
							force = 0f,
							owner = damageInfo.attacker,
							projectilePrefab = gameObject,
							rotation = rotation2,
							speedOverride = speedOverride,
							target = null
						});
					}
				}
				else if (component2.HasBuff(DLC1Content.Buffs.ElementalRingVoidReady))
				{
					int itemCount13 = inventory.GetItemCount(DLC1Content.Items.ElementalRingVoid);
					component2.RemoveBuff(DLC1Content.Buffs.ElementalRingVoidReady);
					for (int l = 1; (float)l <= 20f; l++)
					{
						component2.AddTimedBuff(DLC1Content.Buffs.ElementalRingVoidCooldown, l);
					}
					ProcChainMask procChainMask5 = damageInfo.procChainMask;
					procChainMask5.AddProc(ProcType.Rings);
					if (itemCount13 > 0)
					{
						GameObject projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/ElementalRingVoidBlackHole");
						float damageCoefficient10 = 1f * (float)itemCount13;
						float damage4 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient10);
						ProjectileManager.instance.FireProjectile(new FireProjectileInfo
						{
							damage = damage4,
							crit = damageInfo.crit,
							damageColorIndex = DamageColorIndex.Void,
							position = damageInfo.position,
							procChainMask = procChainMask5,
							force = 6000f,
							owner = damageInfo.attacker,
							projectilePrefab = projectilePrefab,
							rotation = UnityEngine.Quaternion.identity,
							target = null
						});
					}
				}
			}
			int itemCount14 = master.inventory.GetItemCount(RoR2Content.Items.DeathMark);
			int num9 = 0;
			if (itemCount14 >= 1 && !characterBody.HasBuff(RoR2Content.Buffs.DeathMark))
			{
				BuffIndex[] debuffBuffIndices = BuffCatalog.debuffBuffIndices;
				foreach (BuffIndex buffType in debuffBuffIndices)
				{
					if (characterBody.HasBuff(buffType))
					{
						num9++;
					}
				}
				DotController dotController = DotController.FindDotController(victim.gameObject);
				if ((bool)dotController)
				{
					for (DotController.DotIndex dotIndex = DotController.DotIndex.Bleed; dotIndex < DotController.DotIndex.Count; dotIndex++)
					{
						if (dotController.HasDotActive(dotIndex))
						{
							num9++;
						}
					}
				}
				if (num9 >= 4)
				{
					characterBody.AddTimedBuff(RoR2Content.Buffs.DeathMark, 7f * (float)itemCount14);
				}
			}
			if (damageInfo != null && damageInfo.inflictor != null && damageInfo.inflictor.GetComponent<BoomerangProjectile>() != null && !damageInfo.procChainMask.HasProc(ProcType.BleedOnHit))
			{
				int num10 = 0;
				if (inventory.GetEquipmentIndex() == RoR2Content.Equipment.Saw.equipmentIndex)
				{
					num10 = 1;
				}
				bool flag3 = (ulong)(damageInfo.damageType & DamageType.BleedOnHit) != 0;
				if ((num10 > 0 || flag3) && (flag3 || Util.CheckRoll(100f, master)))
				{
					ProcChainMask procChainMask6 = damageInfo.procChainMask;
					procChainMask6.AddProc(ProcType.BleedOnHit);
					DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.Bleed, 4f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker);
				}
			}
			if (damageInfo.crit && (ulong)(damageInfo.damageType & DamageType.SuperBleedOnCrit) != 0L)
			{
				DotController.InflictDot(victim, damageInfo.attacker, DotController.DotIndex.SuperBleed, 15f * damageInfo.procCoefficient, 1f, maxStacksFromAttacker);
			}
			if (component2.HasBuff(RoR2Content.Buffs.LifeSteal))
			{
				float amount = damageInfo.damage * 0.2f;
				component2.healthComponent.Heal(amount, damageInfo.procChainMask);
			}
			int itemCount15 = inventory.GetItemCount(RoR2Content.Items.FireballsOnHit);
			if (itemCount15 > 0 && !damageInfo.procChainMask.HasProc(ProcType.Meatball))
			{
				InputBankTest component5 = component2.GetComponent<InputBankTest>();
				UnityEngine.Vector3 vector2 = (characterBody.characterMotor ? (victim.transform.position + UnityEngine.Vector3.up * (characterBody.characterMotor.capsuleHeight * 0.5f + 2f)) : (victim.transform.position + UnityEngine.Vector3.up * 2f));
				UnityEngine.Vector3 vector3 = (component5 ? component5.aimDirection : victim.transform.forward);
				vector3 = UnityEngine.Vector3.up;
				float num11 = 20f;
				if (Util.CheckRoll(10f * damageInfo.procCoefficient, master))
				{
					EffectData effectData = new EffectData
					{
						scale = 1f,
						origin = vector2
					};
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/MuzzleFlashes/MuzzleflashFireMeatBall"), effectData, transmit: true);
					int num12 = 3;
					float damageCoefficient11 = 3f * (float)itemCount15;
					float damage5 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, damageCoefficient11);
					float maxInclusive = 30f;
					ProcChainMask procChainMask7 = damageInfo.procChainMask;
					procChainMask7.AddProc(ProcType.Meatball);
					float speedOverride2 = UnityEngine.Random.Range(15f, maxInclusive);
					float num13 = 360 / num12;
					_ = num13 / 360f;
					float num14 = 1f;
					float num15 = num13;
					for (int n = 0; n < num12; n++)
					{
						float num16 = (float)n * MathF.PI * 2f / (float)num12;
						FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
						fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/FireMeatBall");
						fireProjectileInfo.position = vector2 + new UnityEngine.Vector3(num14 * Mathf.Sin(num16), 0f, num14 * Mathf.Cos(num16));
						fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(vector3);
						fireProjectileInfo.procChainMask = procChainMask7;
						fireProjectileInfo.target = victim;
						fireProjectileInfo.owner = component2.gameObject;
						fireProjectileInfo.damage = damage5;
						fireProjectileInfo.crit = damageInfo.crit;
						fireProjectileInfo.force = 200f;
						fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
						fireProjectileInfo.speedOverride = speedOverride2;
						fireProjectileInfo.useSpeedOverride = true;
						FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
						num15 += num13;
						ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
						vector3.x += Mathf.Sin(num16 + UnityEngine.Random.Range(0f - num11, num11));
						vector3.z += Mathf.Cos(num16 + UnityEngine.Random.Range(0f - num11, num11));
					}
				}
			}
			int itemCount16 = inventory.GetItemCount(RoR2Content.Items.LightningStrikeOnHit);
			if (itemCount16 > 0 && !damageInfo.procChainMask.HasProc(ProcType.LightningStrikeOnHit) && Util.CheckRoll(10f * damageInfo.procCoefficient, master))
			{
				float damageValue6 = Util.OnHitProcDamage(damageInfo.damage, component2.damage, 5f * (float)itemCount16);
				ProcChainMask procChainMask8 = damageInfo.procChainMask;
				procChainMask8.AddProc(ProcType.LightningStrikeOnHit);
				HurtBox target = characterBody.mainHurtBox;
				if ((bool)characterBody.hurtBoxGroup)
				{
					target = characterBody.hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, characterBody.hurtBoxGroup.hurtBoxes.Length)];
				}
				OrbManager.instance.AddOrb(new SimpleLightningStrikeOrb
				{
					attacker = component2.gameObject,
					damageColorIndex = DamageColorIndex.Item,
					damageValue = damageValue6,
					isCrit = Util.CheckRoll(component2.crit, master),
					procChainMask = procChainMask8,
					procCoefficient = 1f,
					target = target
				});
			}
			if ((ulong)(damageInfo.damageType & DamageType.LunarSecondaryRootOnHit) != 0L && (bool)characterBody)
			{
				int itemCount17 = master.inventory.GetItemCount(RoR2Content.Items.LunarSecondaryReplacement);
				characterBody.AddTimedBuff(RoR2Content.Buffs.LunarSecondaryRoot, 3f * (float)itemCount17);
			}
			if ((ulong)(damageInfo.damageType & DamageType.FruitOnHit) != 0L && (bool)characterBody)
			{
				characterBody.AddTimedBuff(RoR2Content.Buffs.Fruiting, 10f);
			}
			if (inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost) > 0)
			{
				DroneWeaponsBoostBehavior component6 = component2.GetComponent<DroneWeaponsBoostBehavior>();
				if ((bool)component6)
				{
					component6.OnEnemyHit(damageInfo, characterBody);
				}
			}
			if (victim.tag != "Player" && inventory.GetItemCount(DLC2Content.Items.IncreaseDamageOnMultiKill) > 0)
			{
				component2.AddIncreasedDamageMultiKillTime();
			}
			if (component2.luminousShotReady)
			{
				DamageInfo damageInfo3 = new DamageInfo
				{
					damage = component2.luminousShotDamage,
					damageColorIndex = DamageColorIndex.Luminous,
					damageType = DamageType.Generic,
					attacker = component2.gameObject,
					position = characterBody.transform.position,
					crit = damageInfo.crit,
					force = UnityEngine.Vector3.zero,
					inflictor = null,
					procCoefficient = 1f
				};
				characterBody.healthComponent.TakeDamage(damageInfo3);
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/IncreasePrimaryDamageImpact"), new EffectData
				{
					origin = characterBody.transform.position
				}, transmit: true);
				component2.IncreasePrimaryDamageReset();
				Util.PlaySound("Play_item_proc_increasePrimaryDamage", characterBody.gameObject);
			}
			if (component2.HasBuff(DLC2Content.Buffs.CookingRolling))
			{
				characterBody.AddBuff(DLC2Content.Buffs.CookingRolled);
			}
			else if (component2.HasBuff(DLC2Content.Buffs.CookingSearing))
			{
				characterBody.AddBuff(DLC2Content.Buffs.CookingRoasted);
			}
			if (characterBody.HasBuff(DLC2Content.Buffs.CookingOiled) && component2.HasBuff(DLC2Content.Buffs.CookingSearing))
			{
				characterBody.AddBuff(DLC2Content.Buffs.CookingFlambe);
				characterBody.RemoveBuff(DLC2Content.Buffs.CookingOiled);
			}
			if (characterBody.HasBuff(DLC2Content.Buffs.CookingFlambe) && (DamageTypeExtended)damageInfo.damageType == DamageTypeExtended.ChefSearDamage)
			{
				float num17 = 0.75f;
				InflictDotInfo inflictDotInfo = default(InflictDotInfo);
				inflictDotInfo.attackerObject = damageInfo.attacker;
				inflictDotInfo.victimObject = victim;
				inflictDotInfo.totalDamage = component2.damage * num17;
				inflictDotInfo.damageMultiplier = 1f;
				inflictDotInfo.dotIndex = DotController.DotIndex.StrongerBurn;
				inflictDotInfo.maxStacksFromAttacker = maxStacksFromAttacker;
				InflictDotInfo dotInfo2 = inflictDotInfo;
				StrengthenBurnUtils.CheckDotForUpgrade(inventory, ref dotInfo2);
				for (int num18 = 0; num18 < 3; num18++)
				{
					DotController.InflictDot(ref dotInfo2);
				}
			}
			int itemCount18 = inventory.GetItemCount(DLC2Content.Items.MeteorAttackOnHighDamage);
			if (itemCount18 > 0 && !damageInfo.procChainMask.HasProc(ProcType.MeteorAttackOnHighDamage))
			{
				float num19 = 0f;
				float num20 = (int)(damageInfo.damage / component2.damage);
				num19 = 5f + 1f * num20 * (float)itemCount18;
				if (num19 > 50f)
				{
					num19 = 50f;
				}
				if (Util.CheckRoll(num19 * damageInfo.procCoefficient, master))
				{
					ProcChainMask procChainMask9 = damageInfo.procChainMask;
					procChainMask9.AddProc(ProcType.MeteorAttackOnHighDamage);
					float num21 = 20f + 0.5f * (float)itemCount18 * num20;
					if (num21 > 75f)
					{
						num21 = 75f;
					}
					num21 *= component2.damage;
					UnityEngine.Vector3 vector4 = damageInfo.position;
					float num22 = 10f;
					float blastForce = 5000f;
					UnityEngine.Vector3 origin = vector4 + UnityEngine.Vector3.up * 6f;
					UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
					onUnitSphere.y = -1f;
					if (Physics.Raycast(origin, onUnitSphere, out var hitInfo, 12f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						vector4 = hitInfo.point;
					}
					else if (Physics.Raycast(vector4, UnityEngine.Vector3.down, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						vector4 = hitInfo.point;
					}
					if (!component2.runicLensMeteorReady)
					{
						Util.PlaySound("Play_item_proc_meteorAttackOnHighDamage", component2.gameObject);
						EffectManager.SpawnEffect(CommonAssets.runicMeteorEffect, new EffectData
						{
							origin = vector4,
							scale = num22
						}, transmit: true);
						new EffectData().origin = vector4;
						component2.runicLensUpdateVariables(num21, vector4, damageInfo, blastForce, num22);
					}
				}
			}
			int itemCount19 = inventory.GetItemCount(DLC2Content.Items.KnockBackHitEnemies);
			if (itemCount19 > 0 && !characterBody.isBoss)
			{
				CharacterMotor component7 = victim.GetComponent<CharacterMotor>();
				victim.GetComponent<RigidbodyMotor>();
				if ((bool)component7 && component7.isGrounded && !characterBody.isChampion && (characterBody.bodyFlags & CharacterBody.BodyFlags.IgnoreFallDamage) == 0 && !characterBody.HasBuff(DLC2Content.Buffs.KnockUpHitEnemies) && Util.CheckRoll(Util.ConvertAmplificationPercentageIntoReductionPercentage(7.5f * (float)itemCount19 * damageInfo.procCoefficient)))
				{
					Ray aimRay = component2.inputBank.GetAimRay();
					characterBody.AddTimedBuff(DLC2Content.Buffs.KnockUpHitEnemies, 5f);
					float scale = 1f;
					switch (characterBody.hullClassification)
					{
					case HullClassification.Human:
						scale = 1f;
						break;
					case HullClassification.Golem:
						scale = 5f;
						break;
					case HullClassification.BeetleQueen:
						scale = 10f;
						break;
					}
					EffectManager.SpawnEffect(CommonAssets.knockbackFinEffect, new EffectData
					{
						origin = characterBody.gameObject.transform.position,
						scale = scale
					}, transmit: true);
					if (!characterBody.mainHurtBox)
					{
						_ = characterBody.transform;
					}
					else
					{
						_ = characterBody.mainHurtBox.transform;
					}
					UnityEngine.Vector3 vector5 = new UnityEngine.Vector3(0f, 1f, 0f);
					float num23 = component7.mass * 20f;
					float num24 = num23 + num23 / 10f * (float)(itemCount19 - 1);
					component7.ApplyForce(num24 * vector5);
					component7.ApplyForce(num24 / 2f * aimRay.direction);
					Util.PlaySound("Play_item_proc_knockBackHitEnemies", component2.gameObject);
				}
			}
			int itemCount20 = inventory.GetItemCount(DLC2Content.Items.StunAndPierce);
			if (itemCount20 > 0 && !damageInfo.procChainMask.HasProc(ProcType.StunAndPierceDamage) && Util.CheckRoll(15f * damageInfo.procCoefficient, master))
			{
				float damage6 = component2.damage * 0.3f * (float)itemCount20;
				ProcChainMask procChainMask10 = damageInfo.procChainMask;
				procChainMask10.AddProc(ProcType.StunAndPierceDamage);
				UnityEngine.Quaternion rotation3 = UnityEngine.Quaternion.LookRotation(new Ray(component2.inputBank.aimOrigin, component2.inputBank.aimDirection).direction);
				GameObject projectilePrefab2 = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/StunAndPierceBoomerang");
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab2;
				fireProjectileInfo.crit = component2.RollCrit();
				fireProjectileInfo.damage = damage6;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.owner = component2.gameObject;
				fireProjectileInfo.position = aimOrigin;
				fireProjectileInfo.rotation = rotation3;
				FireProjectileInfo fireProjectileInfo3 = fireProjectileInfo;
				fireProjectileInfo3.procChainMask = procChainMask10;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo3);
			}
			if (characterBody.HasBuff(DLC2Content.Buffs.EliteBeadCorruption) && !component2.HasBuff(DLC2Content.Buffs.EliteBead) && !damageInfo.procChainMask.HasProc(ProcType.Thorns))
			{
				float damageValue7 = component2.maxHealth * 0.025f;
				component2.RollCrit();
				_ = characterBody.teamComponent.teamIndex;
				LightningOrb lightningOrb3 = new LightningOrb();
				lightningOrb3.attacker = characterBody.gameObject;
				lightningOrb3.bouncedObjects = null;
				lightningOrb3.bouncesRemaining = 0;
				lightningOrb3.damageCoefficientPerBounce = 1f;
				lightningOrb3.damageColorIndex = DamageColorIndex.WeakPoint;
				lightningOrb3.damageValue = damageValue7;
				lightningOrb3.isCrit = false;
				lightningOrb3.lightningType = LightningOrb.LightningType.BeadDamage;
				lightningOrb3.origin = characterBody.transform.position;
				lightningOrb3.procChainMask = default(ProcChainMask);
				lightningOrb3.procChainMask.AddProc(ProcType.Thorns);
				lightningOrb3.procCoefficient = 0.3f;
				lightningOrb3.range = 0f;
				lightningOrb3.target = component2.mainHurtBox;
				OrbManager.instance.AddOrb(lightningOrb3);
			}
			if (component2.HasBuff(DLC2Content.Buffs.EliteAurelionite))
			{
				CharacterMaster master2 = component2.master;
				int baseCost = 2;
				int difficultyScaledCost = Run.instance.GetDifficultyScaledCost(baseCost);
				uint money = master2.money;
				master2.money = (uint)Mathf.Max(0f, (float)master2.money - (float)difficultyScaledCost);
				if (money - master2.money != 0)
				{
					GoldOrb goldOrb2 = new GoldOrb();
					goldOrb2.origin = damageInfo.position;
					goldOrb2.target = (component2 ? component2.mainHurtBox : characterBody.mainHurtBox);
					goldOrb2.goldAmount = (uint)difficultyScaledCost + (uint)((float)difficultyScaledCost * 0.2f);
					OrbManager.instance.AddOrb(goldOrb2);
					EffectManager.SimpleImpactEffect(CommonAssets.loseCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true);
				}
			}
		}

		private void HandleDamageWithNoAttacker([NotNull] DamageInfo damageInfo, [NotNull] GameObject victim)
		{
			CharacterBody characterBody = (victim ? victim.GetComponent<CharacterBody>() : null);
			if (characterBody == null)
			{
				return;
			}
			if ((ulong)(damageInfo.damageType & DamageType.LunarRuin) != 0)
			{
				if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L)
				{
					characterBody.AddTimedBuff(DLC2Content.Buffs.lunarruin, 420f);
				}
				else
				{
					DotController.InflictDot(characterBody.gameObject, damageInfo.attacker, DotController.DotIndex.LunarRuin, 5f);
				}
			}
			if ((ulong)(damageInfo.damageType & DamageTypeExtended.DisableAllSkills) != 0L)
			{
				if ((ulong)(damageInfo.damageType & DamageTypeExtended.ApplyBuffPermanently) != 0L)
				{
					UnityEngine.Debug.LogFormat("Adding DisableAllSkills");
					characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 420f);
				}
				else
				{
					UnityEngine.Debug.LogFormat("Adding DisableAllSkills for 5s");
					characterBody.AddTimedBuff(DLC2Content.Buffs.DisableAllSkills, 5f);
				}
			}
		}

		public void OnCharacterHitGroundServer(CharacterBody characterBody, CharacterMotor.HitGroundInfo hitGroundInfo)
		{
			bool flag = RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.weakAssKneesArtifactDef);
			float num = Mathf.Abs(hitGroundInfo.velocity.y);
			Inventory inventory = characterBody.inventory;
			_ = characterBody.master;
			CharacterMotor characterMotor = characterBody.characterMotor;
			bool tookFallDamage = false;
			if ((((bool)inventory && inventory.GetItemCount(RoR2Content.Items.FallBoots) != 0) ? 1 : 0) <= (false ? 1 : 0) && (characterBody.bodyFlags & CharacterBody.BodyFlags.IgnoreFallDamage) == 0)
			{
				float num2 = Mathf.Max(num - (characterBody.jumpPower + 20f), 0f);
				if (num2 > 0f)
				{
					HealthComponent component = characterBody.GetComponent<HealthComponent>();
					if ((bool)component)
					{
						tookFallDamage = true;
						float num3 = num2 / 60f;
						DamageInfo damageInfo = new DamageInfo
						{
							attacker = null,
							inflictor = null,
							crit = false,
							damage = num3 * characterBody.maxHealth,
							damageType = (DamageType.NonLethal | DamageType.FallDamage),
							force = UnityEngine.Vector3.zero,
							position = characterBody.footPosition,
							procCoefficient = 0f
						};
						if (flag || (characterBody.teamComponent.teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse3))
						{
							damageInfo.damage *= 2f;
							damageInfo.damageType &= (DamageTypeCombo)(~DamageType.NonLethal);
							damageInfo.damageType |= (DamageTypeCombo)DamageType.BypassOneShotProtection;
						}
						component.TakeDamage(damageInfo);
					}
				}
			}
			OnCharacterHitGroundSFX(characterBody, hitGroundInfo, tookFallDamage);
			characterMotor.CallRpcOnHitGroundSFX(hitGroundInfo, tookFallDamage);
		}

		public void OnCharacterHitGroundSFX(CharacterBody characterBody, CharacterMotor.HitGroundInfo hitGroundInfo, bool tookFallDamage)
		{
			CharacterMotor characterMotor = characterBody.characterMotor;
			if (!characterMotor || (!hitGroundInfo.isValidForEffect && !(Run.FixedTimeStamp.now - characterMotor.lastGroundedTime > 0.2f)))
			{
				return;
			}
			UnityEngine.Vector3 footPosition = characterBody.footPosition;
			float radius = characterBody.radius;
			if (!Physics.Raycast(new Ray(footPosition + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.down), out var hitInfo, 4f, (int)LayerIndex.world.mask | (int)LayerIndex.water.mask, QueryTriggerInteraction.Collide))
			{
				return;
			}
			SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitInfo.collider, hitInfo.point);
			if (!objectSurfaceDef)
			{
				return;
			}
			if (NetworkServer.active)
			{
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/CharacterLandImpact"), new EffectData
				{
					origin = footPosition,
					scale = radius,
					color = objectSurfaceDef.approximateColor
				}, transmit: true);
			}
			if ((bool)objectSurfaceDef.footstepEffectPrefab)
			{
				EffectManager.SpawnEffect(objectSurfaceDef.footstepEffectPrefab, new EffectData
				{
					origin = hitInfo.point,
					scale = radius * 3f
				}, transmit: false);
			}
			SfxLocator component = characterBody.GetComponent<SfxLocator>();
			if ((bool)component)
			{
				if (objectSurfaceDef.materialSwitchString != null && objectSurfaceDef.materialSwitchString.Length > 0)
				{
					AkSoundEngine.SetSwitch("material", objectSurfaceDef.materialSwitchString, characterBody.gameObject);
				}
				else
				{
					AkSoundEngine.SetSwitch("material", "dirt", characterBody.gameObject);
				}
				Util.PlaySound(component.landingSound, characterBody.gameObject);
				if (tookFallDamage)
				{
					Util.PlaySound(component.fallDamageSound, characterBody.gameObject);
				}
			}
		}

		[Obsolete("Use OnCharacterHitGroundServer instead, which this is just a backwards-compatibility wrapper for.", false)]
		public void OnCharacterHitGround(CharacterBody characterBody, UnityEngine.Vector3 impactVelocity)
		{
			OnCharacterHitGroundServer(characterBody, new CharacterMotor.HitGroundInfo
			{
				velocity = impactVelocity
			});
		}

		private void OnPlayerCharacterDeath(DamageReport damageReport, NetworkUser victimNetworkUser)
		{
			if ((bool)victimNetworkUser)
			{
				CharacterBody victimBody = damageReport.victimBody;
				string text = (((ulong)(damageReport.damageInfo.damageType & DamageType.VoidDeath) != 0L) ? "PLAYER_DEATH_QUOTE_VOIDDEATH" : (damageReport.isFallDamage ? fallDamageDeathQuoteTokens[UnityEngine.Random.Range(0, fallDamageDeathQuoteTokens.Length)] : ((!victimBody || !victimBody.inventory || victimBody.inventory.GetItemCount(RoR2Content.Items.LunarDagger) <= 0) ? standardDeathQuoteTokens[UnityEngine.Random.Range(0, standardDeathQuoteTokens.Length)] : "PLAYER_DEATH_QUOTE_BRITTLEDEATH")));
				if ((bool)victimNetworkUser.masterController)
				{
					victimNetworkUser.masterController.finalMessageTokenServer = text;
				}
				Chat.SendBroadcastChat(new Chat.PlayerDeathChatMessage
				{
					subjectAsNetworkUser = victimNetworkUser,
					baseToken = text
				});
			}
		}

		private static void ProcIgniteOnKill(DamageReport damageReport, int igniteOnKillCount, CharacterBody victimBody, TeamIndex attackerTeamIndex)
		{
			float num = 8f + 4f * (float)igniteOnKillCount;
			float radius = victimBody.radius;
			float num2 = num + radius;
			float num3 = 1.5f;
			float baseDamage = damageReport.attackerBody.damage * num3;
			UnityEngine.Vector3 corePosition = victimBody.corePosition;
			igniteOnKillSphereSearch.origin = corePosition;
			igniteOnKillSphereSearch.mask = LayerIndex.entityPrecise.mask;
			igniteOnKillSphereSearch.radius = num2;
			igniteOnKillSphereSearch.RefreshCandidates();
			igniteOnKillSphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetUnprotectedTeams(attackerTeamIndex));
			igniteOnKillSphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			igniteOnKillSphereSearch.OrderCandidatesByDistance();
			igniteOnKillSphereSearch.GetHurtBoxes(igniteOnKillHurtBoxBuffer);
			igniteOnKillSphereSearch.ClearCandidates();
			float value = (float)(1 + igniteOnKillCount) * 0.75f * damageReport.attackerBody.damage;
			for (int i = 0; i < igniteOnKillHurtBoxBuffer.Count; i++)
			{
				HurtBox hurtBox = igniteOnKillHurtBoxBuffer[i];
				if ((bool)hurtBox.healthComponent)
				{
					InflictDotInfo inflictDotInfo = default(InflictDotInfo);
					inflictDotInfo.victimObject = hurtBox.healthComponent.gameObject;
					inflictDotInfo.attackerObject = damageReport.attacker;
					inflictDotInfo.totalDamage = value;
					inflictDotInfo.dotIndex = DotController.DotIndex.Burn;
					inflictDotInfo.damageMultiplier = 1f;
					InflictDotInfo dotInfo = inflictDotInfo;
					if ((bool)damageReport?.attackerMaster?.inventory)
					{
						StrengthenBurnUtils.CheckDotForUpgrade(damageReport.attackerMaster.inventory, ref dotInfo);
					}
					DotController.InflictDot(ref dotInfo);
				}
			}
			igniteOnKillHurtBoxBuffer.Clear();
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.radius = num2;
			blastAttack.baseDamage = baseDamage;
			blastAttack.procCoefficient = 0f;
			blastAttack.crit = Util.CheckRoll(damageReport.attackerBody.crit, damageReport.attackerMaster);
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.attackerFiltering = AttackerFiltering.Default;
			blastAttack.falloffModel = BlastAttack.FalloffModel.None;
			blastAttack.attacker = damageReport.attacker;
			blastAttack.teamIndex = attackerTeamIndex;
			blastAttack.position = corePosition;
			blastAttack.Fire();
			EffectManager.SpawnEffect(CommonAssets.igniteOnKillExplosionEffectPrefab, new EffectData
			{
				origin = corePosition,
				scale = num2,
				rotation = Util.QuaternionSafeLookRotation(damageReport.damageInfo.force)
			}, transmit: true);
		}

		public void OnCharacterDeath(DamageReport damageReport)
		{
			if (!NetworkServer.active || damageReport == null)
			{
				return;
			}
			DamageInfo damageInfo = damageReport.damageInfo;
			GameObject gameObject = null;
			if ((bool)damageReport.victim)
			{
				gameObject = damageReport.victim.gameObject;
			}
			CharacterBody victimBody = damageReport.victimBody;
			TeamComponent teamComponent = null;
			CharacterMaster victimMaster = damageReport.victimMaster;
			TeamIndex teamIndex = damageReport.victimTeamIndex;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.identity;
			UnityEngine.Vector3 vector2 = UnityEngine.Vector3.zero;
			Transform transform = gameObject.transform;
			if ((bool)transform)
			{
				vector = transform.position;
				quaternion = transform.rotation;
				vector2 = vector;
			}
			InputBankTest inputBankTest = null;
			EquipmentIndex equipmentIndex = EquipmentIndex.None;
			EquipmentDef equipmentDef = null;
			if ((bool)victimBody)
			{
				teamComponent = victimBody.teamComponent;
				inputBankTest = victimBody.inputBank;
				vector2 = victimBody.corePosition;
				if ((bool)victimBody.equipmentSlot)
				{
					equipmentIndex = victimBody.equipmentSlot.equipmentIndex;
					equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
				}
			}
			Ray ray = (inputBankTest ? inputBankTest.GetAimRay() : new Ray(vector, quaternion * UnityEngine.Vector3.forward));
			GameObject attacker = damageReport.attacker;
			CharacterBody attackerBody = damageReport.attackerBody;
			CharacterMaster attackerMaster = damageReport.attackerMaster;
			Inventory inventory = (attackerMaster ? attackerMaster.inventory : null);
			TeamIndex attackerTeamIndex = damageReport.attackerTeamIndex;
			if ((bool)teamComponent)
			{
				teamIndex = teamComponent.teamIndex;
			}
			if ((bool)victimBody && (bool)victimMaster)
			{
				PlayerCharacterMasterController playerCharacterMasterController = victimMaster.playerCharacterMasterController;
				if ((bool)playerCharacterMasterController)
				{
					NetworkUser networkUser = playerCharacterMasterController.networkUser;
					if ((bool)networkUser)
					{
						OnPlayerCharacterDeath(damageReport, networkUser);
					}
				}
				if (victimBody.HasBuff(RoR2Content.Buffs.AffixWhite))
				{
					UnityEngine.Vector3 position = vector2;
					GameObject gameObject2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/GenericDelayBlast"), position, UnityEngine.Quaternion.identity);
					float num = 12f + victimBody.radius;
					gameObject2.transform.localScale = new UnityEngine.Vector3(num, num, num);
					DelayBlast component = gameObject2.GetComponent<DelayBlast>();
					if ((bool)component)
					{
						component.position = position;
						component.baseDamage = victimBody.damage * 1.5f;
						component.baseForce = 2300f;
						component.attacker = gameObject;
						component.radius = num;
						component.crit = Util.CheckRoll(victimBody.crit, victimMaster);
						component.procCoefficient = 0.75f;
						component.maxTimer = 2f;
						component.falloffModel = BlastAttack.FalloffModel.None;
						component.explosionEffect = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/AffixWhiteExplosion");
						component.delayEffect = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/AffixWhiteDelayEffect");
						component.damageType = DamageType.Freeze2s;
						TeamFilter component2 = gameObject2.GetComponent<TeamFilter>();
						if ((bool)component2)
						{
							component2.teamIndex = TeamComponent.GetObjectTeam(component.attacker);
						}
					}
				}
				if (victimBody.HasBuff(RoR2Content.Buffs.AffixPoison))
				{
					UnityEngine.Vector3 position2 = vector2;
					UnityEngine.Quaternion rotation = UnityEngine.Quaternion.LookRotation(ray.direction);
					GameObject gameObject3 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterMasters/UrchinTurretMaster"), position2, rotation);
					CharacterMaster component3 = gameObject3.GetComponent<CharacterMaster>();
					if ((bool)component3)
					{
						component3.teamIndex = teamIndex;
						NetworkServer.Spawn(gameObject3);
						component3.SpawnBodyHere();
					}
				}
				if (RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.wispOnDeath) && teamIndex == TeamIndex.Monster && victimMaster.masterIndex != CommonAssets.wispSoulMasterPrefabMasterComponent.masterIndex)
				{
					MasterSummon masterSummon = new MasterSummon();
					masterSummon.position = vector2;
					masterSummon.ignoreTeamMemberLimit = true;
					masterSummon.masterPrefab = CommonAssets.wispSoulMasterPrefabMasterComponent.gameObject;
					masterSummon.summonerBodyObject = gameObject;
					masterSummon.rotation = UnityEngine.Quaternion.LookRotation(ray.direction);
					masterSummon.Perform();
				}
				if (victimBody.HasBuff(RoR2Content.Buffs.Fruiting) || (damageReport.damageInfo != null && (ulong)(damageReport.damageInfo.damageType & DamageType.FruitOnHit) != 0))
				{
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/TreebotFruitDeathEffect.prefab"), new EffectData
					{
						origin = vector,
						rotation = UnityEngine.Random.rotation
					}, transmit: true);
					int num2 = Mathf.Min(Math.Max(1, (int)(victimBody.bestFitRadius * 2f)), 8);
					GameObject original = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/TreebotFruitPack");
					for (int i = 0; i < num2; i++)
					{
						GameObject obj = UnityEngine.Object.Instantiate(original, vector + UnityEngine.Random.insideUnitSphere * victimBody.radius * 0.5f, UnityEngine.Random.rotation);
						TeamFilter component4 = obj.GetComponent<TeamFilter>();
						if ((bool)component4)
						{
							component4.teamIndex = attackerTeamIndex;
						}
						obj.GetComponentInChildren<HealthPickup>();
						obj.transform.localScale = new UnityEngine.Vector3(1f, 1f, 1f);
						NetworkServer.Spawn(obj);
					}
				}
				if (victimBody.HasBuff(DLC1Content.Buffs.EliteEarth))
				{
					MasterSummon masterSummon2 = new MasterSummon();
					masterSummon2.position = vector2;
					masterSummon2.ignoreTeamMemberLimit = true;
					masterSummon2.masterPrefab = CommonAssets.eliteEarthHealerMaster;
					masterSummon2.summonerBodyObject = gameObject;
					masterSummon2.rotation = UnityEngine.Quaternion.LookRotation(ray.direction);
					masterSummon2.Perform();
				}
				if (victimBody.HasBuff(DLC1Content.Buffs.EliteVoid) && (!victimMaster || victimMaster.IsDeadAndOutOfLivesServer()))
				{
					UnityEngine.Vector3 position3 = vector2;
					GameObject gameObject4 = UnityEngine.Object.Instantiate(Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/EliteVoid/VoidInfestorMaster.prefab").WaitForCompletion(), position3, UnityEngine.Quaternion.identity);
					CharacterMaster component5 = gameObject4.GetComponent<CharacterMaster>();
					if ((bool)component5)
					{
						component5.teamIndex = TeamIndex.Void;
						NetworkServer.Spawn(gameObject4);
						component5.SpawnBodyHere();
					}
				}
			}
			if ((bool)attackerBody)
			{
				attackerBody.HandleOnKillEffectsServer(damageReport);
				if ((bool)attackerMaster && (bool)inventory)
				{
					int itemCount = inventory.GetItemCount(RoR2Content.Items.IgniteOnKill);
					if (itemCount > 0)
					{
						ProcIgniteOnKill(damageReport, itemCount, victimBody, attackerTeamIndex);
					}
					int itemCount2 = inventory.GetItemCount(RoR2Content.Items.ExplodeOnDeath);
					if (itemCount2 > 0)
					{
						UnityEngine.Vector3 position4 = vector2;
						float damageCoefficient = 3.5f * (1f + (float)(itemCount2 - 1) * 0.8f);
						float baseDamage = Util.OnKillProcDamage(attackerBody.damage, damageCoefficient);
						GameObject obj2 = UnityEngine.Object.Instantiate(CommonAssets.explodeOnDeathPrefab, position4, UnityEngine.Quaternion.identity);
						DelayBlast component6 = obj2.GetComponent<DelayBlast>();
						if ((bool)component6)
						{
							component6.position = position4;
							component6.baseDamage = baseDamage;
							component6.baseForce = 2000f;
							component6.bonusForce = UnityEngine.Vector3.up * 1000f;
							component6.radius = 12f + 2.4f * ((float)itemCount2 - 1f);
							component6.attacker = damageInfo.attacker;
							component6.inflictor = null;
							component6.crit = Util.CheckRoll(attackerBody.crit, attackerMaster);
							component6.maxTimer = 0.5f;
							component6.damageColorIndex = DamageColorIndex.Item;
							component6.falloffModel = BlastAttack.FalloffModel.SweetSpot;
						}
						TeamFilter component7 = obj2.GetComponent<TeamFilter>();
						if ((bool)component7)
						{
							component7.teamIndex = attackerTeamIndex;
						}
						NetworkServer.Spawn(obj2);
					}
					int itemCount3 = inventory.GetItemCount(RoR2Content.Items.Dagger);
					if (itemCount3 > 0)
					{
						float damageCoefficient2 = 1.5f * (float)itemCount3;
						UnityEngine.Vector3 vector3 = vector + UnityEngine.Vector3.up * 1.8f;
						for (int j = 0; j < 3; j++)
						{
							ProjectileManager.instance.FireProjectile(CommonAssets.daggerPrefab, vector3 + UnityEngine.Random.insideUnitSphere * 0.5f, Util.QuaternionSafeLookRotation(UnityEngine.Vector3.up + UnityEngine.Random.insideUnitSphere * 0.1f), attackerBody.gameObject, Util.OnKillProcDamage(attackerBody.damage, damageCoefficient2), 200f, Util.CheckRoll(attackerBody.crit, attackerMaster), DamageColorIndex.Item);
						}
					}
					int itemCount4 = inventory.GetItemCount(RoR2Content.Items.Tooth);
					if (itemCount4 > 0)
					{
						float num3 = Mathf.Pow(itemCount4, 0.25f);
						GameObject obj3 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/HealPack"), vector, UnityEngine.Random.rotation);
						TeamFilter component8 = obj3.GetComponent<TeamFilter>();
						if ((bool)component8)
						{
							component8.teamIndex = attackerTeamIndex;
						}
						HealthPickup componentInChildren = obj3.GetComponentInChildren<HealthPickup>();
						if ((bool)componentInChildren)
						{
							componentInChildren.flatHealing = 8f;
							componentInChildren.fractionalHealing = 0.02f * (float)itemCount4;
						}
						obj3.transform.localScale = new UnityEngine.Vector3(num3, num3, num3);
						NetworkServer.Spawn(obj3);
					}
					float num4 = 0f;
					float num5 = 0f;
					float num6 = 0f;
					float num7 = 0f;
					if (victimBody.HasBuff(DLC2Content.Buffs.CookingChopped))
					{
						num4 += 1f;
						num5 += 2f;
						num6 += 0.04f;
						num7 += 0.75f;
					}
					if (victimBody.HasBuff(DLC2Content.Buffs.CookingOiled))
					{
						num4 += 1f;
						num5 += 2f;
						num6 += 0.04f;
						num7 += 0.75f;
					}
					if (victimBody.HasBuff(DLC2Content.Buffs.CookingRoasted))
					{
						num4 += 1f;
						num5 += 2f;
						num6 += 0.04f;
						num7 += 0.75f;
					}
					if (victimBody.HasBuff(DLC2Content.Buffs.CookingRolled))
					{
						num4 += 1f;
						num5 += 2f;
						num6 += 0.04f;
						num7 += 0.75f;
					}
					if (victimBody.HasBuff(DLC2Content.Buffs.CookingFlambe))
					{
						num4 += 1f;
						num5 += 2f;
						num6 += 0.04f;
						num7 += 0.75f;
					}
					if (num4 > 1f)
					{
						GameObject obj4 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Chef/ChefFoodPickup"), vector, UnityEngine.Random.rotation);
						TeamFilter component9 = obj4.GetComponent<TeamFilter>();
						if ((bool)component9)
						{
							component9.teamIndex = attackerTeamIndex;
						}
						HealthPickup componentInChildren2 = obj4.GetComponentInChildren<HealthPickup>();
						if ((bool)componentInChildren2)
						{
							componentInChildren2.flatHealing = num5;
							componentInChildren2.fractionalHealing = num6;
						}
						obj4.transform.localScale = new UnityEngine.Vector3(num7, num7, num7);
						NetworkServer.Spawn(obj4);
					}
					int itemCount5 = inventory.GetItemCount(RoR2Content.Items.Infusion);
					if (itemCount5 > 0)
					{
						int num8 = itemCount5 * 100;
						if (inventory.infusionBonus < num8)
						{
							InfusionOrb infusionOrb = new InfusionOrb();
							infusionOrb.origin = vector;
							infusionOrb.target = Util.FindBodyMainHurtBox(attackerBody);
							infusionOrb.maxHpValue = itemCount5;
							OrbManager.instance.AddOrb(infusionOrb);
						}
					}
					if ((DamageType)(damageInfo.damageType & DamageType.ResetCooldownsOnKill) == DamageType.ResetCooldownsOnKill)
					{
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/Bandit2ResetEffect"), new EffectData
						{
							origin = damageInfo.position
						}, transmit: true);
						SkillLocator skillLocator = attackerBody.skillLocator;
						if ((bool)skillLocator)
						{
							skillLocator.ResetSkills();
						}
					}
					if ((DamageType)(damageInfo.damageType & DamageType.GiveSkullOnKill) == DamageType.GiveSkullOnKill && (bool)victimMaster)
					{
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/Bandit2KillEffect"), new EffectData
						{
							origin = damageInfo.position
						}, transmit: true);
						attackerBody.AddBuff(RoR2Content.Buffs.BanditSkull);
					}
					int itemCount6 = inventory.GetItemCount(RoR2Content.Items.Talisman);
					if (itemCount6 > 0 && (bool)attackerBody.equipmentSlot)
					{
						inventory.DeductActiveEquipmentCooldown(2f + (float)itemCount6 * 2f);
					}
					int itemCount7 = inventory.GetItemCount(JunkContent.Items.TempestOnKill);
					if (itemCount7 > 0 && Util.CheckRoll(25f, attackerMaster))
					{
						GameObject obj5 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/TempestWard"), victimBody.footPosition, UnityEngine.Quaternion.identity);
						TeamFilter component10 = obj5.GetComponent<TeamFilter>();
						if ((bool)component10)
						{
							component10.teamIndex = attackerTeamIndex;
						}
						BuffWard component11 = obj5.GetComponent<BuffWard>();
						if ((bool)component11)
						{
							component11.expireDuration = 2f + 6f * (float)itemCount7;
						}
						NetworkServer.Spawn(obj5);
					}
					int itemCount8 = inventory.GetItemCount(RoR2Content.Items.Bandolier);
					if (itemCount8 > 0 && Util.CheckRoll((1f - 1f / Mathf.Pow(itemCount8 + 1, 0.33f)) * 100f, attackerMaster))
					{
						GameObject obj6 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/AmmoPack"), vector, UnityEngine.Random.rotation);
						TeamFilter component12 = obj6.GetComponent<TeamFilter>();
						if ((bool)component12)
						{
							component12.teamIndex = attackerTeamIndex;
						}
						NetworkServer.Spawn(obj6);
					}
					if ((bool)victimBody && damageReport.victimIsElite)
					{
						int itemCount9 = inventory.GetItemCount(RoR2Content.Items.HeadHunter);
						int itemCount10 = inventory.GetItemCount(RoR2Content.Items.KillEliteFrenzy);
						if (itemCount9 > 0)
						{
							float duration = 3f + 5f * (float)itemCount9;
							for (int k = 0; k < BuffCatalog.eliteBuffIndices.Length; k++)
							{
								BuffIndex buffIndex = BuffCatalog.eliteBuffIndices[k];
								if (victimBody.HasBuff(buffIndex))
								{
									attackerBody.AddTimedBuff(buffIndex, duration);
								}
							}
						}
						if (itemCount10 > 0)
						{
							attackerBody.AddTimedBuff(RoR2Content.Buffs.NoCooldowns, (float)itemCount10 * 4f);
						}
					}
					int itemCount11 = inventory.GetItemCount(RoR2Content.Items.GhostOnKill);
					if (itemCount11 > 0 && (bool)victimBody && Util.CheckRoll(7f, attackerMaster))
					{
						Util.TryToCreateGhost(victimBody, attackerBody, itemCount11 * 30);
					}
					if (inventory.GetItemCount(DLC1Content.Items.MinorConstructOnKill) > 0 && (bool)victimBody && victimBody.isElite && !attackerMaster.IsDeployableLimited(DeployableSlot.MinorConstructOnKill))
					{
						UnityEngine.Vector3 forward = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * UnityEngine.Quaternion.AngleAxis(-80f, UnityEngine.Vector3.right) * UnityEngine.Vector3.forward;
						FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
						fireProjectileInfo.projectilePrefab = CommonAssets.minorConstructOnKillProjectile;
						fireProjectileInfo.position = vector;
						fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(forward);
						fireProjectileInfo.procChainMask = default(ProcChainMask);
						fireProjectileInfo.target = gameObject;
						fireProjectileInfo.owner = attackerBody.gameObject;
						fireProjectileInfo.damage = 0f;
						fireProjectileInfo.crit = false;
						fireProjectileInfo.force = 0f;
						fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
						FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
						ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
					}
					int itemCount12 = inventory.GetItemCount(DLC1Content.Items.MoveSpeedOnKill);
					if (itemCount12 > 0)
					{
						int num9 = itemCount12 - 1;
						int num10 = 5;
						float num11 = 1f + (float)num9 * 0.5f;
						attackerBody.ClearTimedBuffs(DLC1Content.Buffs.KillMoveSpeed);
						for (int l = 0; l < num10; l++)
						{
							attackerBody.AddTimedBuff(DLC1Content.Buffs.KillMoveSpeed, num11 * (float)(l + 1) / (float)num10);
						}
						EffectData effectData = new EffectData();
						effectData.origin = attackerBody.corePosition;
						CharacterMotor characterMotor = attackerBody.characterMotor;
						bool flag = false;
						if ((bool)characterMotor)
						{
							UnityEngine.Vector3 moveDirection = characterMotor.moveDirection;
							if (moveDirection != UnityEngine.Vector3.zero)
							{
								effectData.rotation = Util.QuaternionSafeLookRotation(moveDirection);
								flag = true;
							}
						}
						if (!flag)
						{
							effectData.rotation = attackerBody.transform.rotation;
						}
						EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/MoveSpeedOnKillActivate"), effectData, transmit: true);
					}
					if ((bool)equipmentDef && Util.CheckRoll(equipmentDef.dropOnDeathChance * 100f, attackerMaster) && (bool)victimBody)
					{
						PickupDropletController.CreatePickupDroplet(PickupCatalog.FindPickupIndex(equipmentIndex), vector + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.up * 20f + ray.direction * 2f);
					}
					int itemCount13 = inventory.GetItemCount(RoR2Content.Items.BarrierOnKill);
					if (itemCount13 > 0 && (bool)attackerBody.healthComponent)
					{
						attackerBody.healthComponent.AddBarrier(15f * (float)itemCount13);
					}
					int itemCount14 = inventory.GetItemCount(RoR2Content.Items.BonusGoldPackOnKill);
					if (itemCount14 > 0 && Util.CheckRoll(4f * (float)itemCount14, attackerMaster))
					{
						GameObject obj7 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/BonusMoneyPack"), vector, UnityEngine.Random.rotation);
						TeamFilter component13 = obj7.GetComponent<TeamFilter>();
						if ((bool)component13)
						{
							component13.teamIndex = attackerTeamIndex;
						}
						NetworkServer.Spawn(obj7);
					}
					int itemCount15 = inventory.GetItemCount(RoR2Content.Items.Plant);
					if (itemCount15 > 0)
					{
						GameObject obj8 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/InterstellarDeskPlant"), victimBody.footPosition, UnityEngine.Quaternion.identity);
						DeskPlantController component14 = obj8.GetComponent<DeskPlantController>();
						if ((bool)component14)
						{
							if ((bool)component14.teamFilter)
							{
								component14.teamFilter.teamIndex = attackerTeamIndex;
							}
							component14.itemCount = itemCount15;
						}
						NetworkServer.Spawn(obj8);
					}
					int incubatorOnKillCount = attackerMaster.inventory.GetItemCount(JunkContent.Items.Incubator);
					if (incubatorOnKillCount > 0 && attackerMaster.GetDeployableCount(DeployableSlot.ParentPodAlly) + attackerMaster.GetDeployableCount(DeployableSlot.ParentAlly) < incubatorOnKillCount && Util.CheckRoll(7f + 1f * (float)incubatorOnKillCount, attackerMaster))
					{
						DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/CharacterSpawnCards/cscParentPod"), new DirectorPlacementRule
						{
							placementMode = DirectorPlacementRule.PlacementMode.Approximate,
							minDistance = 3f,
							maxDistance = 20f,
							spawnOnTarget = transform
						}, RoR2Application.rng);
						directorSpawnRequest.summonerBodyObject = attacker;
						directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult spawnResult)
						{
							if (spawnResult.success)
							{
								Inventory inventory2 = spawnResult.spawnedInstance.GetComponent<CharacterMaster>().inventory;
								if ((bool)inventory2)
								{
									inventory2.GiveItem(RoR2Content.Items.BoostDamage, 30);
									inventory2.GiveItem(RoR2Content.Items.BoostHp, 10 * incubatorOnKillCount);
								}
							}
						});
						DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
					}
					int itemCount16 = inventory.GetItemCount(RoR2Content.Items.BleedOnHitAndExplode);
					if (itemCount16 > 0 && (bool)victimBody && (victimBody.HasBuff(RoR2Content.Buffs.Bleeding) || victimBody.HasBuff(RoR2Content.Buffs.SuperBleed)))
					{
						Util.PlaySound("Play_bleedOnCritAndExplode_explode", gameObject);
						UnityEngine.Vector3 position5 = vector2;
						float damageCoefficient3 = 4f * (float)(1 + (itemCount16 - 1));
						float num12 = 0.15f * (float)(1 + (itemCount16 - 1));
						float baseDamage2 = Util.OnKillProcDamage(attackerBody.damage, damageCoefficient3) + victimBody.maxHealth * num12;
						GameObject obj9 = UnityEngine.Object.Instantiate(CommonAssets.bleedOnHitAndExplodeBlastEffect, position5, UnityEngine.Quaternion.identity);
						DelayBlast component15 = obj9.GetComponent<DelayBlast>();
						component15.position = position5;
						component15.baseDamage = baseDamage2;
						component15.baseForce = 0f;
						component15.radius = 16f;
						component15.attacker = damageInfo.attacker;
						component15.inflictor = null;
						component15.crit = Util.CheckRoll(attackerBody.crit, attackerMaster);
						component15.maxTimer = 0f;
						component15.damageColorIndex = DamageColorIndex.Item;
						component15.falloffModel = BlastAttack.FalloffModel.SweetSpot;
						obj9.GetComponent<TeamFilter>().teamIndex = attackerTeamIndex;
						NetworkServer.Spawn(obj9);
					}
					if (attackerMaster.inventory.GetItemCount(DLC2Content.Items.ResetChests) > 0)
					{
						int itemCount17 = attackerMaster.inventory.GetItemCount(DLC2Content.Items.ResetChests);
						if (victimBody.isChampion && Util.CheckRoll(100f, attackerMaster) && (bool)victimBody)
						{
							PickupDropletController.CreatePickupDroplet(CommonAssets.dtSonorousEchoPath.GenerateDrop(Run.instance.runRNG), vector + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.up * 20f + ray.direction * 2f);
						}
						if (victimBody.isElite && Util.CheckRoll(2f + 1f * (float)itemCount17, attackerMaster) && (bool)victimBody)
						{
							PickupDropletController.CreatePickupDroplet(CommonAssets.dtSonorousEchoPath.GenerateDrop(Run.instance.runRNG), vector + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.up * 20f + ray.direction * 2f);
						}
					}
				}
			}
			GlobalEventManager.onCharacterDeathGlobal?.Invoke(damageReport);
		}

		public void OnHitAll(DamageInfo damageInfo, GameObject hitObject)
		{
			OnHitAllProcess(damageInfo, hitObject);
		}

		private void OnHitAllProcess(DamageInfo damageInfo, GameObject hitObject)
		{
			if (damageInfo.procCoefficient == 0f || damageInfo.rejected)
			{
				return;
			}
			_ = NetworkServer.active;
			if (!damageInfo.attacker)
			{
				return;
			}
			CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>();
			if (!component)
			{
				return;
			}
			CharacterMaster master = component.master;
			if (!master)
			{
				return;
			}
			Inventory inventory = master.inventory;
			if (!master.inventory)
			{
				return;
			}
			if (!damageInfo.procChainMask.HasProc(ProcType.Behemoth))
			{
				int itemCount = inventory.GetItemCount(RoR2Content.Items.Behemoth);
				if (itemCount > 0 && damageInfo.procCoefficient != 0f)
				{
					float num = (1.5f + 2.5f * (float)itemCount) * damageInfo.procCoefficient;
					float damageCoefficient = 0.6f;
					float baseDamage = Util.OnHitProcDamage(damageInfo.damage, component.damage, damageCoefficient);
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OmniEffect/OmniExplosionVFXQuick"), new EffectData
					{
						origin = damageInfo.position,
						scale = num,
						rotation = Util.QuaternionSafeLookRotation(damageInfo.force)
					}, transmit: true);
					BlastAttack obj = new BlastAttack
					{
						position = damageInfo.position,
						baseDamage = baseDamage,
						baseForce = 0f,
						radius = num,
						attacker = damageInfo.attacker,
						inflictor = null
					};
					obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
					obj.crit = damageInfo.crit;
					obj.procChainMask = damageInfo.procChainMask;
					obj.procCoefficient = 0f;
					obj.damageColorIndex = DamageColorIndex.Item;
					obj.falloffModel = BlastAttack.FalloffModel.None;
					obj.damageType = damageInfo.damageType;
					obj.Fire();
				}
			}
			if ((component.HasBuff(RoR2Content.Buffs.AffixBlue) ? 1 : 0) > 0)
			{
				float damageCoefficient2 = 0.5f;
				float damage = Util.OnHitProcDamage(damageInfo.damage, component.damage, damageCoefficient2);
				float force = 0f;
				UnityEngine.Vector3 position = damageInfo.position;
				ProjectileManager.instance.FireProjectile(LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/LightningStake"), position, UnityEngine.Quaternion.identity, damageInfo.attacker, damage, force, damageInfo.crit, DamageColorIndex.Item);
			}
		}

		public void OnCrit(CharacterBody body, DamageInfo damageInfo, CharacterMaster master, float procCoefficient, ProcChainMask procChainMask)
		{
			UnityEngine.Vector3 hitPos = body.corePosition;
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/Critspark");
			if ((bool)body)
			{
				if (body.critMultiplier > 2f)
				{
					gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/CritsparkHeavy");
				}
				if ((bool)body && procCoefficient > 0f && (bool)master && (bool)master.inventory)
				{
					Inventory inventory = master.inventory;
					if (!procChainMask.HasProc(ProcType.HealOnCrit))
					{
						procChainMask.AddProc(ProcType.HealOnCrit);
						int itemCount = inventory.GetItemCount(RoR2Content.Items.HealOnCrit);
						if (itemCount > 0 && (bool)body.healthComponent)
						{
							Util.PlaySound("Play_item_proc_crit_heal", body.gameObject);
							if (NetworkServer.active)
							{
								body.healthComponent.Heal((4f + (float)itemCount * 4f) * procCoefficient, procChainMask);
							}
						}
					}
					if (inventory.GetItemCount(RoR2Content.Items.AttackSpeedOnCrit) > 0)
					{
						body.AddTimedBuff(RoR2Content.Buffs.AttackSpeedOnCrit, 3f * procCoefficient);
					}
					int itemCount2 = inventory.GetItemCount(JunkContent.Items.CooldownOnCrit);
					if (itemCount2 > 0)
					{
						Util.PlaySound("Play_item_proc_crit_cooldown", body.gameObject);
						SkillLocator component = body.GetComponent<SkillLocator>();
						if ((bool)component)
						{
							float dt = (float)itemCount2 * procCoefficient;
							if ((bool)component.primary)
							{
								component.primary.RunRecharge(dt);
							}
							if ((bool)component.secondary)
							{
								component.secondary.RunRecharge(dt);
							}
							if ((bool)component.utility)
							{
								component.utility.RunRecharge(dt);
							}
							if ((bool)component.special)
							{
								component.special.RunRecharge(dt);
							}
						}
					}
				}
			}
			if (damageInfo != null)
			{
				hitPos = damageInfo.position;
			}
			if ((bool)gameObject)
			{
				EffectManager.SimpleImpactEffect(gameObject, hitPos, UnityEngine.Vector3.up, transmit: true);
			}
		}

		public static void OnTeamLevelUp(TeamIndex teamIndex)
		{
			GlobalEventManager.onTeamLevelUp?.Invoke(teamIndex);
		}

		public static void OnCharacterLevelUp(CharacterBody characterBody)
		{
			GlobalEventManager.onCharacterLevelUp?.Invoke(characterBody);
		}

		public void OnInteractionBegin(Interactor interactor, IInteractable interactable, GameObject interactableObject)
		{
			if (!interactor)
			{
				UnityEngine.Debug.LogError("OnInteractionBegin invalid interactor!");
				return;
			}
			if (interactable == null)
			{
				UnityEngine.Debug.LogError("OnInteractionBegin invalid interactable!");
				return;
			}
			if (!interactableObject)
			{
				UnityEngine.Debug.LogError("OnInteractionBegin invalid interactableObject!");
				return;
			}
			GlobalEventManager.OnInteractionsGlobal?.Invoke(interactor, interactable, interactableObject);
			CharacterBody component = interactor.GetComponent<CharacterBody>();
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			UnityEngine.Quaternion rotation = UnityEngine.Quaternion.identity;
			Transform transform = interactableObject.transform;
			if ((bool)transform)
			{
				vector = transform.position;
				rotation = transform.rotation;
			}
			if (!component)
			{
				return;
			}
			Inventory inventory = component.inventory;
			if (!inventory)
			{
				return;
			}
			InteractionProcFilter interactionProcFilter = interactableObject.GetComponent<InteractionProcFilter>();
			int itemCount = inventory.GetItemCount(RoR2Content.Items.Firework);
			if (itemCount > 0 && InteractableIsPermittedForSpawn((MonoBehaviour)interactable))
			{
				Transform transform2 = interactableObject.GetComponent<ModelLocator>()?.modelTransform?.GetComponent<ChildLocator>()?.FindChild("FireworkOrigin");
				UnityEngine.Vector3 position = (transform2 ? transform2.position : (interactableObject.transform.position + UnityEngine.Vector3.up * 2f));
				int remaining = 4 + itemCount * 4;
				FireworkLauncher component2 = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/FireworkLauncher"), position, UnityEngine.Quaternion.identity).GetComponent<FireworkLauncher>();
				component2.owner = interactor.gameObject;
				component2.crit = Util.CheckRoll(component.crit, component.master);
				component2.remaining = remaining;
			}
			int squidStacks = inventory.GetItemCount(RoR2Content.Items.Squid);
			if (squidStacks > 0 && InteractableIsPermittedForSpawn((MonoBehaviour)interactable))
			{
				CharacterSpawnCard spawnCard = LegacyResourcesAPI.Load<CharacterSpawnCard>("SpawnCards/CharacterSpawnCards/cscSquidTurret");
				DirectorPlacementRule placementRule = new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Approximate,
					minDistance = 5f,
					maxDistance = 25f,
					position = interactableObject.transform.position
				};
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, placementRule, RoR2Application.rng);
				directorSpawnRequest.teamIndexOverride = TeamIndex.Player;
				directorSpawnRequest.summonerBodyObject = interactor.gameObject;
				directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult result)
				{
					if (result.success && (bool)result.spawnedInstance)
					{
						CharacterMaster component5 = result.spawnedInstance.GetComponent<CharacterMaster>();
						if ((bool)component5 && (bool)component5.inventory)
						{
							component5.inventory.GiveItem(RoR2Content.Items.HealthDecay, 30);
							component5.inventory.GiveItem(RoR2Content.Items.BoostAttackSpeed, 10 * (squidStacks - 1));
						}
					}
				});
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			}
			int itemCount2 = inventory.GetItemCount(RoR2Content.Items.MonstersOnShrineUse);
			if (itemCount2 <= 0)
			{
				return;
			}
			PurchaseInteraction component3 = interactableObject.GetComponent<PurchaseInteraction>();
			if (!component3 || !component3.isShrine || (bool)interactableObject.GetComponent<ShrineCombatBehavior>())
			{
				return;
			}
			GameObject gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/Encounters/MonstersOnShrineUseEncounter");
			if (!gameObject)
			{
				return;
			}
			GameObject gameObject2 = UnityEngine.Object.Instantiate(gameObject, vector, UnityEngine.Quaternion.identity);
			NetworkServer.Spawn(gameObject2);
			CombatDirector component4 = gameObject2.GetComponent<CombatDirector>();
			if ((bool)component4 && (bool)Stage.instance)
			{
				float monsterCredit = 40f * Stage.instance.entryDifficultyCoefficient * (float)itemCount2;
				DirectorCard directorCard = component4.SelectMonsterCardForCombatShrine(monsterCredit);
				if (directorCard != null)
				{
					component4.CombatShrineActivation(interactor, monsterCredit, directorCard);
					EffectData effectData = new EffectData
					{
						origin = vector,
						rotation = rotation
					};
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/MonstersOnShrineUse"), effectData, transmit: true);
				}
				else
				{
					NetworkServer.Destroy(gameObject2);
				}
			}
			bool InteractableIsPermittedForSpawn(MonoBehaviour interactableAsMonoBehaviour)
			{
				if (!interactableAsMonoBehaviour)
				{
					return false;
				}
				if ((bool)interactionProcFilter)
				{
					return interactionProcFilter.shouldAllowOnInteractionBeginProc;
				}
				if ((bool)interactableAsMonoBehaviour.GetComponent<DelusionChestController>())
				{
					if (interactableAsMonoBehaviour.GetComponent<PickupPickerController>().enabled)
					{
						return false;
					}
					return true;
				}
				if ((bool)interactableAsMonoBehaviour.GetComponent<GenericPickupController>())
				{
					return false;
				}
				if ((bool)interactableAsMonoBehaviour.GetComponent<VehicleSeat>())
				{
					return false;
				}
				if ((bool)interactableAsMonoBehaviour.GetComponent<NetworkUIPromptController>())
				{
					return false;
				}
				return true;
			}
		}

		public static void ClientDamageNotified(DamageDealtMessage damageDealtMessage)
		{
			GlobalEventManager.onClientDamageNotified?.Invoke(damageDealtMessage);
		}

		public static void ServerDamageDealt(DamageReport damageReport)
		{
			GlobalEventManager.onServerDamageDealt?.Invoke(damageReport);
		}

		public static void ServerCharacterExecuted(DamageReport damageReport, float executionHealthLost)
		{
			GlobalEventManager.onServerCharacterExecuted?.Invoke(damageReport, executionHealthLost);
		}
	}
	public class GoldshoresMissionController : MonoBehaviour
	{
		public Xoroshiro128Plus rng;

		public EntityStateMachine entityStateMachine;

		public GameObject beginTransitionIntoBossFightEffect;

		public GameObject exitTransitionIntoBossFightEffect;

		public Transform bossSpawnPosition;

		[SerializeField]
		public ExpansionDef requiredExpansion;

		public List<GameObject> beaconInstanceList = new List<GameObject>();

		public int beaconsRequiredToSpawnBoss;

		public int beaconsToSpawnOnMap;

		public InteractableSpawnCard beaconSpawnCard;

		public static GoldshoresMissionController instance { get; private set; }

		public int beaconsActive => EntityStates.Interactables.GoldBeacon.Ready.count;

		public int beaconCount => EntityStates.Interactables.GoldBeacon.Ready.count + NotReady.count;

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void Awake()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint);
			}
			beginTransitionIntoBossFightEffect.SetActive(value: false);
			exitTransitionIntoBossFightEffect.SetActive(value: false);
		}

		public void SpawnBeacons()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			for (int i = 0; i < beaconsToSpawnOnMap; i++)
			{
				GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(beaconSpawnCard, new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Random
				}, rng));
				if ((bool)gameObject)
				{
					beaconInstanceList.Add(gameObject);
				}
			}
			beaconsToSpawnOnMap = beaconInstanceList.Count;
		}

		public void BeginTransitionIntoBossfight()
		{
			beginTransitionIntoBossFightEffect.SetActive(value: true);
			exitTransitionIntoBossFightEffect.SetActive(value: false);
		}

		public void ExitTransitionIntoBossfight()
		{
			beginTransitionIntoBossFightEffect.SetActive(value: false);
			exitTransitionIntoBossFightEffect.SetActive(value: true);
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	[RequireComponent(typeof(GenericOwnership))]
	public class GrandParentSunController : MonoBehaviour
	{
		private TeamFilter teamFilter;

		private GenericOwnership ownership;

		public BuffDef buffDef;

		[UnityEngine.Min(0.001f)]
		public float cycleInterval = 1f;

		[UnityEngine.Min(0.001f)]
		public float nearBuffDuration = 1f;

		[UnityEngine.Min(0.001f)]
		public float maxDistance = 1f;

		public int minimumStacksBeforeApplyingBurns = 4;

		public float burnDuration = 5f;

		public GameObject buffApplyEffect;

		[SerializeField]
		private LoopSoundDef activeLoopDef;

		[SerializeField]
		private LoopSoundDef damageLoopDef;

		[SerializeField]
		private string stopSoundName;

		private Run.FixedTimeStamp previousCycle = Run.FixedTimeStamp.negativeInfinity;

		private int cycleIndex;

		private List<HurtBox> cycleTargets = new List<HurtBox>();

		private BullseyeSearch bullseyeSearch = new BullseyeSearch();

		private bool isLocalPlayerDamaged;

		private void Awake()
		{
			teamFilter = GetComponent<TeamFilter>();
			ownership = GetComponent<GenericOwnership>();
		}

		private void Start()
		{
			if ((bool)activeLoopDef)
			{
				Util.PlaySound(activeLoopDef.startSoundName, base.gameObject);
			}
		}

		private void OnDestroy()
		{
			if ((bool)activeLoopDef)
			{
				Util.PlaySound(activeLoopDef.stopSoundName, base.gameObject);
			}
			if ((bool)damageLoopDef)
			{
				Util.PlaySound(damageLoopDef.stopSoundName, base.gameObject);
			}
			if (stopSoundName != null)
			{
				Util.PlaySound(stopSoundName, base.gameObject);
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				ServerFixedUpdate();
			}
			if (!damageLoopDef)
			{
				return;
			}
			bool flag = isLocalPlayerDamaged;
			isLocalPlayerDamaged = false;
			foreach (HurtBox cycleTarget in cycleTargets)
			{
				CharacterBody characterBody = null;
				if ((bool)cycleTarget && (bool)cycleTarget.healthComponent)
				{
					characterBody = cycleTarget.healthComponent.body;
				}
				if ((bool)characterBody && (characterBody.bodyFlags & CharacterBody.BodyFlags.OverheatImmune) != 0 && characterBody.hasEffectiveAuthority)
				{
					UnityEngine.Vector3 position = base.transform.position;
					UnityEngine.Vector3 corePosition = characterBody.corePosition;
					if (!Physics.Linecast(position, corePosition, out var _, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						isLocalPlayerDamaged = true;
					}
				}
			}
			if (isLocalPlayerDamaged && !flag)
			{
				Util.PlaySound(damageLoopDef.startSoundName, base.gameObject);
			}
			else if (!isLocalPlayerDamaged && flag)
			{
				Util.PlaySound(damageLoopDef.stopSoundName, base.gameObject);
			}
		}

		private void ServerFixedUpdate()
		{
			float num = Mathf.Clamp01(previousCycle.timeSince / cycleInterval);
			int num2 = ((num == 1f) ? cycleTargets.Count : Mathf.FloorToInt((float)cycleTargets.Count * num));
			UnityEngine.Vector3 position = base.transform.position;
			while (cycleIndex < num2)
			{
				HurtBox hurtBox = cycleTargets[cycleIndex];
				if ((bool)hurtBox && (bool)hurtBox.healthComponent)
				{
					CharacterBody body = hurtBox.healthComponent.body;
					if ((body.bodyFlags & CharacterBody.BodyFlags.OverheatImmune) == 0)
					{
						UnityEngine.Vector3 corePosition = body.corePosition;
						Ray ray = new Ray(position, corePosition - position);
						if (!Physics.Linecast(position, corePosition, out var hitInfo, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
						{
							float num3 = Mathf.Max(1f, hitInfo.distance);
							body.AddTimedBuff(buffDef, nearBuffDuration / num3);
							if ((bool)buffApplyEffect)
							{
								EffectData effectData = new EffectData
								{
									origin = corePosition,
									rotation = Util.QuaternionSafeLookRotation(-ray.direction),
									scale = body.bestFitRadius
								};
								effectData.SetHurtBoxReference(hurtBox);
								EffectManager.SpawnEffect(buffApplyEffect, effectData, transmit: true);
							}
							int num4 = body.GetBuffCount(buffDef) - minimumStacksBeforeApplyingBurns;
							if (num4 > 0)
							{
								InflictDotInfo dotInfo = default(InflictDotInfo);
								dotInfo.dotIndex = DotController.DotIndex.Burn;
								dotInfo.attackerObject = ownership.ownerObject;
								dotInfo.victimObject = body.gameObject;
								dotInfo.damageMultiplier = 1f;
								CharacterBody characterBody = ownership?.ownerObject?.GetComponent<CharacterBody>();
								if ((bool)characterBody && (bool)characterBody.inventory)
								{
									dotInfo.totalDamage = 0.5f * characterBody.damage * burnDuration * (float)num4;
									StrengthenBurnUtils.CheckDotForUpgrade(characterBody.inventory, ref dotInfo);
								}
								DotController.InflictDot(ref dotInfo);
							}
						}
					}
				}
				cycleIndex++;
			}
			if (previousCycle.timeSince >= cycleInterval)
			{
				previousCycle = Run.FixedTimeStamp.now;
				cycleIndex = 0;
				cycleTargets.Clear();
				SearchForTargets(cycleTargets);
			}
		}

		private void SearchForTargets(List<HurtBox> dest)
		{
			bullseyeSearch.searchOrigin = base.transform.position;
			bullseyeSearch.minAngleFilter = 0f;
			bullseyeSearch.maxAngleFilter = 180f;
			bullseyeSearch.maxDistanceFilter = maxDistance;
			bullseyeSearch.filterByDistinctEntity = true;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.viewer = null;
			bullseyeSearch.RefreshCandidates();
			dest.AddRange(bullseyeSearch.GetResults());
		}
	}
	[RequireComponent(typeof(ItemFollower))]
	public class GravCubeController : MonoBehaviour
	{
		private ItemFollower itemFollower;

		private float activeTimer;

		private Animator itemFollowerAnimator;

		private static int activeParamHash = Animator.StringToHash("active");

		private void Start()
		{
			itemFollower = GetComponent<ItemFollower>();
		}

		public void ActivateCube(float duration)
		{
			activeTimer = duration;
		}

		private void Update()
		{
			if ((bool)itemFollower && (bool)itemFollower.followerInstance)
			{
				if (!itemFollowerAnimator)
				{
					itemFollowerAnimator = itemFollower.followerInstance.GetComponentInChildren<Animator>();
				}
				activeTimer -= Time.deltaTime;
				itemFollowerAnimator.SetBool(activeParamHash, activeTimer > 0f);
			}
		}
	}
	public class GravitatePickup : MonoBehaviour
	{
		private Transform gravitateTarget;

		[Tooltip("The rigidbody to set the velocity of.")]
		public Rigidbody rigidbody;

		[Tooltip("The TeamFilter which controls which team can activate this trigger.")]
		public TeamFilter teamFilter;

		public float acceleration;

		public float maxSpeed;

		public bool gravitateAtFullHealth = true;

		private void Start()
		{
		}

		private void OnTriggerEnter(Collider other)
		{
			if (NetworkServer.active && !gravitateTarget && teamFilter.teamIndex != TeamIndex.None)
			{
				HealthComponent component = other.gameObject.GetComponent<HealthComponent>();
				if (TeamComponent.GetObjectTeam(other.gameObject) == teamFilter.teamIndex && (gravitateAtFullHealth || !component || component.health < component.fullHealth))
				{
					gravitateTarget = other.gameObject.transform;
				}
			}
		}

		private void FixedUpdate()
		{
			if ((bool)gravitateTarget)
			{
				rigidbody.velocity = UnityEngine.Vector3.MoveTowards(rigidbody.velocity, (gravitateTarget.transform.position - base.transform.position).normalized * maxSpeed, acceleration);
			}
		}
	}
	[RequireComponent(typeof(GenericOwnership))]
	public class HealBeamController : NetworkBehaviour
	{
		public Transform startPointTransform;

		public Transform endPointTransform;

		public float tickInterval = 1f;

		public bool breakOnTargetFullyHealed;

		public LineRenderer lineRenderer;

		public float lingerAfterBrokenDuration;

		[SyncVar(hook = "OnSyncTarget")]
		private HurtBoxReference netTarget;

		private float stopwatchServer;

		private bool broken;

		private HurtBoxReference previousHurtBoxReference;

		private HurtBox cachedHurtBox;

		private float scaleFactorVelocity;

		private float maxLineWidth = 0.3f;

		private float smoothTime = 0.1f;

		private float scaleFactor;

		public GenericOwnership ownership { get; private set; }

		public HurtBox target
		{
			get
			{
				return cachedHurtBox;
			}
			[Server]
			set
			{
				if (!NetworkServer.active)
				{
					UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealBeamController::set_target(RoR2.HurtBox)' called on client");
					return;
				}
				NetworknetTarget = HurtBoxReference.FromHurtBox(value);
				UpdateCachedHurtBox();
			}
		}

		public float healRate { get; set; }

		public HurtBoxReference NetworknetTarget
		{
			get
			{
				return netTarget;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncTarget(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref netTarget, 1u);
			}
		}

		private void Awake()
		{
			ownership = GetComponent<GenericOwnership>();
			startPointTransform.SetParent(null, worldPositionStays: true);
			endPointTransform.SetParent(null, worldPositionStays: true);
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			UpdateCachedHurtBox();
		}

		private void OnDestroy()
		{
			if ((bool)startPointTransform)
			{
				UnityEngine.Object.Destroy(startPointTransform.gameObject);
			}
			if ((bool)endPointTransform)
			{
				UnityEngine.Object.Destroy(endPointTransform.gameObject);
			}
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		private void LateUpdate()
		{
			UpdateHealBeamVisuals();
		}

		private void OnSyncTarget(HurtBoxReference newValue)
		{
			NetworknetTarget = newValue;
			UpdateCachedHurtBox();
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		private void FixedUpdateServer()
		{
			if (!cachedHurtBox)
			{
				BreakServer();
			}
			else if (tickInterval > 0f)
			{
				stopwatchServer += Time.fixedDeltaTime;
				while (stopwatchServer >= tickInterval)
				{
					stopwatchServer -= tickInterval;
					OnTickServer();
				}
			}
		}

		private void OnTickServer()
		{
			if (!cachedHurtBox || !cachedHurtBox.healthComponent)
			{
				BreakServer();
				return;
			}
			cachedHurtBox.healthComponent.Heal(healRate * tickInterval, default(ProcChainMask));
			if (breakOnTargetFullyHealed && cachedHurtBox.healthComponent.health >= cachedHurtBox.healthComponent.fullHealth)
			{
				BreakServer();
			}
		}

		private void UpdateCachedHurtBox()
		{
			if (!previousHurtBoxReference.Equals(netTarget))
			{
				cachedHurtBox = netTarget.ResolveHurtBox();
				previousHurtBoxReference = netTarget;
			}
		}

		public static bool HealBeamAlreadyExists(GameObject owner, HurtBox target)
		{
			return HealBeamAlreadyExists(owner, target.healthComponent);
		}

		public static bool HealBeamAlreadyExists(GameObject owner, HealthComponent targetHealthComponent)
		{
			List<HealBeamController> instancesList = InstanceTracker.GetInstancesList<HealBeamController>();
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				HealBeamController healBeamController = instancesList[i];
				if ((object)healBeamController.target?.healthComponent == targetHealthComponent && (object)healBeamController.ownership.ownerObject == owner)
				{
					return true;
				}
			}
			return false;
		}

		public static int GetHealBeamCountForOwner(GameObject owner)
		{
			int num = 0;
			List<HealBeamController> instancesList = InstanceTracker.GetInstancesList<HealBeamController>();
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				if ((object)instancesList[i].ownership.ownerObject == owner)
				{
					num++;
				}
			}
			return num;
		}

		private void UpdateHealBeamVisuals()
		{
			float num = (target ? 1f : 0f);
			scaleFactor = Mathf.SmoothDamp(scaleFactor, num, ref scaleFactorVelocity, smoothTime);
			UnityEngine.Vector3 localScale = new UnityEngine.Vector3(scaleFactor, scaleFactor, scaleFactor);
			startPointTransform.SetPositionAndRotation(base.transform.position, base.transform.rotation);
			startPointTransform.localScale = localScale;
			if ((bool)cachedHurtBox)
			{
				endPointTransform.position = cachedHurtBox.transform.position;
			}
			endPointTransform.localScale = localScale;
			lineRenderer.widthMultiplier = scaleFactor * maxLineWidth;
		}

		[Server]
		public void BreakServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealBeamController::BreakServer()' called on client");
			}
			else if (!broken)
			{
				broken = true;
				target = null;
				base.transform.SetParent(null);
				ownership.ownerObject = null;
				UnityEngine.Object.Destroy(base.gameObject, lingerAfterBrokenDuration);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WriteHurtBoxReference_None(writer, netTarget);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteHurtBoxReference_None(writer, netTarget);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				netTarget = GeneratedNetworkCode._ReadHurtBoxReference_None(reader);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncTarget(GeneratedNetworkCode._ReadHurtBoxReference_None(reader));
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	public class HealingWard : NetworkBehaviour
	{
		[SyncVar]
		[Tooltip("The area of effect.")]
		public float radius;

		[Tooltip("How long between heal pulses in the area of effect.")]
		public float interval = 1f;

		[Tooltip("How many hit points to restore each pulse.")]
		public float healPoints;

		[Tooltip("What fraction of the healee max health to restore each pulse.")]
		public float healFraction;

		[Tooltip("The child range indicator object. Will be scaled to the radius.")]
		public Transform rangeIndicator;

		[Tooltip("Should the ward be floored on start")]
		public bool floorWard;

		private TeamFilter teamFilter;

		private float healTimer;

		private float rangeIndicatorScaleVelocity;

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 1u);
			}
		}

		private void Awake()
		{
			teamFilter = GetComponent<TeamFilter>();
			if (NetworkServer.active && floorWard && Physics.Raycast(base.transform.position, UnityEngine.Vector3.down, out var hitInfo, 500f, LayerIndex.world.mask))
			{
				base.transform.position = hitInfo.point;
				base.transform.up = hitInfo.normal;
			}
		}

		private void Update()
		{
			if ((bool)rangeIndicator)
			{
				float num = Mathf.SmoothDamp(rangeIndicator.localScale.x, radius, ref rangeIndicatorScaleVelocity, 0.2f);
				rangeIndicator.localScale = new UnityEngine.Vector3(num, num, num);
			}
		}

		private void FixedUpdate()
		{
			healTimer -= Time.fixedDeltaTime;
			if (healTimer <= 0f && NetworkServer.active)
			{
				healTimer = interval;
				HealOccupants();
			}
		}

		private void HealOccupants()
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamFilter.teamIndex);
			float num = radius * radius;
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < teamMembers.Count; i++)
			{
				if (!((teamMembers[i].transform.position - position).sqrMagnitude <= num))
				{
					continue;
				}
				HealthComponent component = teamMembers[i].GetComponent<HealthComponent>();
				if ((bool)component)
				{
					float num2 = healPoints + component.fullHealth * healFraction;
					if (num2 > 0f)
					{
						component.Heal(num2, default(ProcChainMask));
					}
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(radius);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(radius);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				radius = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				radius = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(NetworkedBodyAttachment))]
	public class HealNearbyController : NetworkBehaviour
	{
		[SyncVar]
		public float radius;

		public float damagePerSecondCoefficient;

		[UnityEngine.Min(float.Epsilon)]
		public float tickRate = 1f;

		[SyncVar]
		public int maxTargets;

		public TetherVfxOrigin tetherVfxOrigin;

		public GameObject activeVfx;

		protected new Transform transform;

		protected NetworkedBodyAttachment networkedBodyAttachment;

		protected SphereSearch sphereSearch;

		protected float timer;

		private bool isTetheredToAtLeastOneObject;

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 1u);
			}
		}

		public int NetworkmaxTargets
		{
			get
			{
				return maxTargets;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref maxTargets, 2u);
			}
		}

		protected void Awake()
		{
			transform = base.transform;
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
			sphereSearch = new SphereSearch();
			timer = 0f;
		}

		protected void FixedUpdate()
		{
			timer -= Time.fixedDeltaTime;
			if (timer <= 0f)
			{
				timer += 1f / tickRate;
				Tick();
			}
		}

		protected void Tick()
		{
			if (!networkedBodyAttachment || !networkedBodyAttachment.attachedBody || !networkedBodyAttachment.attachedBodyObject)
			{
				return;
			}
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			SearchForTargets(list);
			float amount = damagePerSecondCoefficient * networkedBodyAttachment.attachedBody.damage / tickRate;
			List<Transform> list2 = CollectionPool<Transform, List<Transform>>.RentCollection();
			for (int i = 0; i < list.Count; i++)
			{
				HurtBox hurtBox = list[i];
				if ((bool)hurtBox && (bool)hurtBox.healthComponent && networkedBodyAttachment.attachedBody.healthComponent.alive && hurtBox.healthComponent.health < hurtBox.healthComponent.fullHealth && !hurtBox.healthComponent.body.HasBuff(DLC1Content.Buffs.EliteEarth))
				{
					HealthComponent healthComponent = hurtBox.healthComponent;
					if (hurtBox.healthComponent.body == networkedBodyAttachment.attachedBody)
					{
						continue;
					}
					Transform item = healthComponent.body?.coreTransform ?? hurtBox.transform;
					list2.Add(item);
					if (NetworkServer.active)
					{
						healthComponent.Heal(amount, default(ProcChainMask));
					}
				}
				if (list2.Count >= maxTargets)
				{
					break;
				}
			}
			isTetheredToAtLeastOneObject = (float)list2.Count > 0f;
			if ((bool)tetherVfxOrigin)
			{
				tetherVfxOrigin.SetTetheredTransforms(list2);
			}
			if ((bool)activeVfx)
			{
				activeVfx.SetActive(isTetheredToAtLeastOneObject);
			}
			CollectionPool<Transform, List<Transform>>.ReturnCollection(list2);
			CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}

		protected void SearchForTargets(List<HurtBox> dest)
		{
			TeamMask none = TeamMask.none;
			none.AddTeam(networkedBodyAttachment.attachedBody.teamComponent.teamIndex);
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.origin = transform.position;
			sphereSearch.radius = radius + networkedBodyAttachment.attachedBody.radius;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByHurtBoxTeam(none);
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			sphereSearch.GetHurtBoxes(dest);
			sphereSearch.ClearCandidates();
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(radius);
				writer.WritePackedUInt32((uint)maxTargets);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(radius);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)maxTargets);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				radius = reader.ReadSingle();
				maxTargets = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				radius = reader.ReadSingle();
			}
			if (((uint)num & 2u) != 0)
			{
				maxTargets = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public interface IOnIncomingDamageServerReceiver
	{
		void OnIncomingDamageServer(DamageInfo damageInfo);
	}
	public interface IOnTakeDamageServerReceiver
	{
		void OnTakeDamageServer(DamageReport damageReport);
	}
	public interface IOnKilledServerReceiver
	{
		void OnKilledServer(DamageReport damageReport);
	}
	public interface IOnDamageDealtServerReceiver
	{
		void OnDamageDealtServer(DamageReport damageReport);
	}
	public interface IOnDamageInflictedServerReceiver
	{
		void OnDamageInflictedServer(DamageReport damageReport);
	}
	public interface IOnKilledOtherServerReceiver
	{
		void OnKilledOtherServer(DamageReport damageReport);
	}
	[DisallowMultipleComponent]
	[RequireComponent(typeof(CharacterBody))]
	public class HealthComponent : NetworkBehaviour, IManagedMonoBehaviour
	{
		private static class AssetReferences
		{
			public static GameObject bearEffectPrefab;

			public static GameObject bearVoidEffectPrefab;

			public static GameObject executeEffectPrefab;

			public static GameObject critGlassesVoidExecuteEffectPrefab;

			public static GameObject shieldBreakEffectPrefab;

			public static GameObject loseCoinsImpactEffectPrefab;

			public static GameObject gainCoinsImpactEffectPrefab;

			public static GameObject damageRejectedPrefab;

			public static GameObject bossDamageBonusImpactEffectPrefab;

			public static GameObject pulverizedEffectPrefab;

			public static GameObject diamondDamageBonusImpactEffectPrefab;

			public static GameObject crowbarImpactEffectPrefab;

			public static GameObject captainBodyArmorBlockEffectPrefab;

			public static GameObject mercExposeConsumeEffectPrefab;

			public static GameObject explodeOnDeathVoidExplosionPrefab;

			public static GameObject fragileDamageBonusBreakEffectPrefab;

			public static GameObject healthOrbPrefab;

			public static GameObject permanentDebuffEffectPrefab;

			public static void Resolve()
			{
				AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/BearProc");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					bearEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/BearVoidProc");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					bearVoidEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/OmniEffect/OmniImpactExecute");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					executeEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ShieldBreakEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					shieldBreakEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/CoinImpact");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					loseCoinsImpactEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/GainCoinsImpact");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					gainCoinsImpactEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/DamageRejected");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					damageRejectedPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/ImpactBossDamageBonus");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					bossDamageBonusImpactEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/PulverizedEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					pulverizedEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/DiamondDamageBonusEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					diamondDamageBonusImpactEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/ImpactCrowbar");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					crowbarImpactEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/CaptainBodyArmorBlockEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					captainBodyArmorBlockEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/PermanentDebuffEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					permanentDebuffEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/MercExposeConsumeEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					mercExposeConsumeEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/CritGlassesVoidExecuteEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					critGlassesVoidExecuteEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/NetworkedObjects/ExplodeOnDeathVoidExplosion");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					explodeOnDeathVoidExplosionPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/ImpactEffects/DelicateWatchProcEffect");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					fragileDamageBonusBreakEffectPrefab = x.Result;
				};
				asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/NetworkedObjects/TreebotFruitPack");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
				{
					healthOrbPrefab = x.Result;
				};
			}
		}

		private class HealMessage : MessageBase
		{
			public GameObject target;

			public float amount;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(target);
				writer.Write(amount);
			}

			public override void Deserialize(NetworkReader reader)
			{
				target = reader.ReadGameObject();
				amount = reader.ReadSingle();
			}
		}

		private struct ItemCounts
		{
			public int bear;

			public int armorPlate;

			public int goldOnHit;

			public int goldOnHurt;

			public int phasing;

			public int thorns;

			public int invadingDoppelganger;

			public int medkit;

			public int parentEgg;

			public int fragileDamageBonus;

			public int minHealthPercentage;

			public int noxiousThorn;

			public int antlerShield;

			public int increaseHealing;

			public int barrierOnOverHeal;

			public int repeatHeal;

			public int novaOnHeal;

			public int adaptiveArmor;

			public int healingPotion;

			public int infusion;

			public int missileVoid;

			public int unstableTransmitter;

			public ItemCounts([NotNull] Inventory src)
			{
				bear = src.GetItemCount(RoR2Content.Items.Bear);
				armorPlate = src.GetItemCount(RoR2Content.Items.ArmorPlate);
				goldOnHit = src.GetItemCount(RoR2Content.Items.GoldOnHit);
				goldOnHurt = src.GetItemCount(DLC1Content.Items.GoldOnHurt);
				phasing = src.GetItemCount(RoR2Content.Items.Phasing);
				thorns = src.GetItemCount(RoR2Content.Items.Thorns);
				invadingDoppelganger = src.GetItemCount(RoR2Content.Items.InvadingDoppelganger);
				medkit = src.GetItemCount(RoR2Content.Items.Medkit);
				fragileDamageBonus = src.GetItemCount(DLC1Content.Items.FragileDamageBonus);
				minHealthPercentage = src.GetItemCount(RoR2Content.Items.MinHealthPercentage);
				increaseHealing = src.GetItemCount(RoR2Content.Items.IncreaseHealing);
				barrierOnOverHeal = src.GetItemCount(RoR2Content.Items.BarrierOnOverHeal);
				repeatHeal = src.GetItemCount(RoR2Content.Items.RepeatHeal);
				novaOnHeal = src.GetItemCount(RoR2Content.Items.NovaOnHeal);
				adaptiveArmor = src.GetItemCount(RoR2Content.Items.AdaptiveArmor);
				healingPotion = src.GetItemCount(DLC1Content.Items.HealingPotion);
				infusion = src.GetItemCount(RoR2Content.Items.Infusion);
				parentEgg = src.GetItemCount(RoR2Content.Items.ParentEgg);
				missileVoid = src.GetItemCount(DLC1Content.Items.MissileVoid);
				unstableTransmitter = src.GetItemCount(DLC2Content.Items.TeleportOnLowHealth);
				noxiousThorn = src.GetItemCount(DLC2Content.Items.TriggerEnemyDebuffs);
				antlerShield = src.GetItemCount(DLC2Content.Items.NegateAttack);
			}
		}

		public struct HealthBarValues
		{
			public bool hasInfusion;

			public bool hasVoidShields;

			public bool isVoid;

			public bool isElite;

			public bool isBoss;

			public float cullFraction;

			public float healthFraction;

			public float shieldFraction;

			public float barrierFraction;

			public float magneticFraction;

			public float curseFraction;

			public float ospFraction;

			public int healthDisplayValue;

			public int maxHealthDisplayValue;
		}

		private class RepeatHealComponent : MonoBehaviour
		{
			private float reserve;

			private float timer;

			private const float interval = 0.2f;

			public float healthFractionToRestorePerSecond = 0.1f;

			public HealthComponent healthComponent;

			private void FixedUpdate()
			{
				timer -= Time.fixedDeltaTime;
				if (timer <= 0f)
				{
					timer = 0.2f;
					if (reserve > 0f)
					{
						float num = Mathf.Min(healthComponent.fullHealth * healthFractionToRestorePerSecond * 0.2f, reserve);
						reserve -= num;
						ProcChainMask procChainMask = default(ProcChainMask);
						procChainMask.AddProc(ProcType.RepeatHeal);
						healthComponent.Heal(num, procChainMask);
					}
				}
			}

			public void AddReserve(float amount, float max)
			{
				reserve = Mathf.Min(reserve + amount, max);
			}
		}

		public static readonly float lowHealthFraction;

		[SyncVar]
		[HideInInspector]
		[Tooltip("How much health this object has.")]
		public float health = 100f;

		[HideInInspector]
		[Tooltip("How much shield this object has.")]
		[SyncVar]
		public float shield;

		[HideInInspector]
		[SyncVar(hook = "SetBarrier")]
		[Tooltip("How much barrier this object has.")]
		public float barrier;

		[SyncVar]
		[HideInInspector]
		public float magnetiCharge;

		public bool dontShowHealthbar;

		private const float recentlyTookDamageCoyoteTimer_Duration = 0.2f;

		[NonSerialized]
		public float recentlyTookDamageCoyoteTimer;

		public float globalDeathEventChanceCoefficient = 1f;

		[SyncVar]
		private uint _killingDamageType;

		public CharacterBody body;

		private ModelLocator modelLocator;

		private IPainAnimationHandler painAnimationHandler;

		private IOnIncomingDamageServerReceiver[] onIncomingDamageReceivers;

		private IOnTakeDamageServerReceiver[] onTakeDamageReceivers;

		public ScreenDamageCalculator screenDamageCalculator;

		public const float frozenExecuteThreshold = 0.3f;

		private const float adaptiveArmorPerOnePercentTaken = 30f;

		private const float adaptiveArmorDecayPerSecond = 40f;

		private const float adaptiveArmorCap = 400f;

		public const float medkitActivationDelay = 2f;

		private const float devilOrbMaxTimer = 0.1f;

		private float devilOrbHealPool;

		private float devilOrbTimer;

		private float regenAccumulator;

		private bool wasAlive = true;

		private float adaptiveArmorValue;

		private bool isShieldRegenForced;

		public bool forceCulled;

		private float ospTimer;

		private const float ospBufferDuration = 0.1f;

		private float serverDamageTakenThisUpdate;

		private RepeatHealComponent repeatHealComponent;

		private ItemCounts itemCounts;

		private EquipmentIndex currentEquipmentIndex;

		private static int kCmdCmdHealFull;

		private static int kCmdCmdRechargeShieldFull;

		private static int kCmdCmdAddBarrier;

		private static int kCmdCmdForceShieldRegen;

		public bool recentlyTookDamage
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return recentlyTookDamageCoyoteTimer > 0f;
			}
		}

		public DamageTypeCombo killingDamageType
		{
			get
			{
				return _killingDamageType;
			}
			private set
			{
				Network_killingDamageType = (uint)(ulong)value;
			}
		}

		public bool alive => health > 0f;

		public float fullHealth => body.maxHealth;

		public float fullShield => body.maxShield;

		public float fullBarrier => body.maxBarrier;

		public float combinedHealth => health + shield + barrier;

		public float fullCombinedHealth => fullHealth + fullShield;

		public float combinedHealthFraction => combinedHealth / fullCombinedHealth;

		public float missingCombinedHealth => fullCombinedHealth - (combinedHealth - barrier);

		public Run.FixedTimeStamp lastHitTime { get; private set; }

		public Run.FixedTimeStamp lastHealTime { get; private set; }

		public GameObject lastHitAttacker { get; private set; }

		public float timeSinceLastHit => lastHitTime.timeSince;

		public float timeSinceLastHeal => lastHealTime.timeSince;

		public bool godMode { get; set; }

		public float potionReserve { get; private set; }

		public bool isInFrozenState { get; set; }

		public bool isHealthLow => (health + shield) / fullCombinedHealth <= lowHealthFraction;

		public float Networkhealth
		{
			get
			{
				return health;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref health, 1u);
			}
		}

		public float Networkshield
		{
			get
			{
				return shield;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref shield, 2u);
			}
		}

		public float Networkbarrier
		{
			get
			{
				return barrier;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetBarrier(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref barrier, 4u);
			}
		}

		public float NetworkmagnetiCharge
		{
			get
			{
				return magnetiCharge;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref magnetiCharge, 8u);
			}
		}

		public uint Network_killingDamageType
		{
			get
			{
				return _killingDamageType;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _killingDamageType, 16u);
			}
		}

		public static event Action<HealthComponent, float, ProcChainMask> onCharacterHealServer;

		private void SetBarrier(float newBarrier)
		{
			float num = barrier;
			Networkbarrier = newBarrier;
			if (barrier <= 0f && num > 0f)
			{
				body.MarkAllStatsDirty();
			}
		}

		public void OnValidate()
		{
			if (base.gameObject.GetComponents<HealthComponent>().Length > 1)
			{
				UnityEngine.Debug.LogErrorFormat(base.gameObject, "{0} has multiple health components!!", base.gameObject);
			}
		}

		public float Heal(float amount, ProcChainMask procChainMask, bool nonRegen = true)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Single RoR2.HealthComponent::Heal(System.Single, RoR2.ProcChainMask, System.Boolean)' called on client");
				return 0f;
			}
			if (!alive || amount <= 0f || body.HasBuff(RoR2Content.Buffs.HealingDisabled))
			{
				return 0f;
			}
			recentlyTookDamageCoyoteTimer = 0.2f;
			float num = health;
			bool flag = false;
			if (currentEquipmentIndex == RoR2Content.Equipment.LunarPotion.equipmentIndex && !procChainMask.HasProc(ProcType.LunarPotionActivation))
			{
				potionReserve += amount;
				return amount;
			}
			if (nonRegen && !procChainMask.HasProc(ProcType.CritHeal) && Util.CheckRoll(body.critHeal, body.master))
			{
				procChainMask.AddProc(ProcType.CritHeal);
				flag = true;
			}
			if (flag)
			{
				amount *= 2f;
			}
			if (itemCounts.increaseHealing > 0)
			{
				amount *= 1f + (float)itemCounts.increaseHealing;
			}
			if (body.teamComponent.teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse5)
			{
				amount /= 2f;
			}
			if (nonRegen && (bool)repeatHealComponent && !procChainMask.HasProc(ProcType.RepeatHeal))
			{
				repeatHealComponent.healthFractionToRestorePerSecond = 0.1f / (float)itemCounts.repeatHeal;
				repeatHealComponent.AddReserve(amount * (float)(1 + itemCounts.repeatHeal), fullHealth);
				return 0f;
			}
			if (body.HasBuff(DLC2Content.Buffs.lunarruin))
			{
				amount *= 0.8f;
			}
			if (body.HasBuff(DLC2Content.Buffs.SojournHealing))
			{
				int buffCount = body.GetBuffCount(DLC2Content.Buffs.SojournHealing);
				float num2 = 1f - (float)buffCount * 0.1f;
				if (num2 < 0f)
				{
					num2 = 0f;
				}
				amount *= num2;
			}
			float num3 = amount;
			if (health < fullHealth)
			{
				float num4 = Mathf.Max(Mathf.Min(amount, fullHealth - health), 0f);
				num3 = amount - num4;
				Networkhealth = health + num4;
			}
			if (num3 > 0f && nonRegen && itemCounts.barrierOnOverHeal > 0)
			{
				float value = num3 * ((float)itemCounts.barrierOnOverHeal * 0.5f);
				AddBarrier(value);
			}
			if (nonRegen)
			{
				lastHealTime = Run.FixedTimeStamp.now;
				SendHeal(base.gameObject, amount, flag);
				if (itemCounts.novaOnHeal > 0 && !procChainMask.HasProc(ProcType.HealNova))
				{
					devilOrbHealPool = Mathf.Min(devilOrbHealPool + amount * (float)itemCounts.novaOnHeal, fullCombinedHealth);
				}
			}
			if (flag)
			{
				GlobalEventManager.instance.OnCrit(body, null, body.master, amount / fullHealth * 10f, procChainMask);
			}
			if (nonRegen)
			{
				HealthComponent.onCharacterHealServer?.Invoke(this, amount, procChainMask);
			}
			if ((bool)body.inventory && body.inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage) > 0 && alive)
			{
				body.UpdateLowerHealthHigherDamage();
			}
			return health - num;
		}

		public void UsePotion()
		{
			ProcChainMask procChainMask = default(ProcChainMask);
			procChainMask.AddProc(ProcType.LunarPotionActivation);
			Heal(potionReserve, procChainMask);
		}

		public float HealFraction(float fraction, ProcChainMask procChainMask)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Single RoR2.HealthComponent::HealFraction(System.Single, RoR2.ProcChainMask)' called on client");
				return 0f;
			}
			return Heal(fraction * fullHealth, procChainMask);
		}

		public void SetCurrentHealthLevel()
		{
		}

		public float GetNormalizedHealth()
		{
			return health / fullHealth;
		}

		[Command]
		public void CmdHealFull()
		{
			HealFraction(1f, default(ProcChainMask));
		}

		[Server]
		public void RechargeShieldFull()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::RechargeShieldFull()' called on client");
			}
			else if (shield < fullShield)
			{
				Networkshield = fullShield;
			}
		}

		[Command]
		public void CmdRechargeShieldFull()
		{
			RechargeShieldFull();
		}

		[Server]
		public void RechargeShield(float value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::RechargeShield(System.Single)' called on client");
			}
			else if (shield < fullShield)
			{
				Networkshield = shield + value;
				if (shield > fullShield)
				{
					Networkshield = fullShield;
				}
			}
		}

		[Server]
		public void AddBarrier(float value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::AddBarrier(System.Single)' called on client");
			}
			else if (alive && barrier < fullBarrier)
			{
				Networkbarrier = Mathf.Min(barrier + value, fullBarrier);
			}
		}

		[Server]
		public void AddCharge(float value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::AddCharge(System.Single)' called on client");
			}
			else if (alive && magnetiCharge < fullHealth)
			{
				NetworkmagnetiCharge = Mathf.Min(barrier + value, fullBarrier);
			}
		}

		[Command]
		private void CmdAddBarrier(float value)
		{
			AddBarrier(value);
		}

		public void AddBarrierAuthority(float value)
		{
			if (NetworkServer.active)
			{
				AddBarrier(value);
			}
			else
			{
				CallCmdAddBarrier(value);
			}
		}

		[Command]
		private void CmdForceShieldRegen()
		{
			ForceShieldRegen();
		}

		public void ForceShieldRegen()
		{
			if (NetworkServer.active)
			{
				isShieldRegenForced = true;
			}
			else
			{
				CallCmdForceShieldRegen();
			}
		}

		[Server]
		public void Die(bool noCorpse = false)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::Die(System.Boolean)' called on client");
				return;
			}
			Networkhealth = 0f;
			modelLocator.forceCulled = noCorpse;
			if ((bool)body && body.cost > 0f && CombatDirector.instancesList.Count > 0)
			{
				CombatDirector combatDirector = CombatDirector.instancesList[0];
				if (body.isElite || CombatDirector.IsEliteOnlyArtifactActive())
				{
					combatDirector.monsterCredit += body.cost;
				}
				else
				{
					combatDirector.refundedMonsterCredit += body.cost;
				}
				UnityEngine.Debug.LogError("Refunded CombatDirector " + body.cost + " credits");
			}
		}

		[Server]
		public void TakeDamageForce(DamageInfo damageInfo, bool alwaysApply = false, bool disableAirControlUntilCollision = false)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TakeDamageForce(RoR2.DamageInfo,System.Boolean,System.Boolean)' called on client");
			}
			else if (!body.HasBuff(RoR2Content.Buffs.EngiShield) || !(shield > 0f))
			{
				CharacterMotor component = GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					component.ApplyForce(damageInfo.force, alwaysApply, disableAirControlUntilCollision);
				}
				Rigidbody component2 = GetComponent<Rigidbody>();
				if ((bool)component2)
				{
					component2.AddForce(damageInfo.force, ForceMode.Impulse);
				}
			}
		}

		[Server]
		public void TakeDamageForce(UnityEngine.Vector3 force, bool alwaysApply = false, bool disableAirControlUntilCollision = false)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TakeDamageForce(UnityEngine.Vector3,System.Boolean,System.Boolean)' called on client");
			}
			else if (!body.HasBuff(RoR2Content.Buffs.EngiShield) || !(shield > 0f))
			{
				CharacterMotor component = GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					component.ApplyForce(force, alwaysApply, disableAirControlUntilCollision);
				}
				Rigidbody component2 = GetComponent<Rigidbody>();
				if ((bool)component2)
				{
					component2.AddForce(force, ForceMode.Impulse);
				}
			}
		}

		[Server]
		public void TakeDamage(DamageInfo damageInfo)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TakeDamage(RoR2.DamageInfo)' called on client");
			}
			else
			{
				TakeDamageProcess(damageInfo);
			}
		}

		private void TakeDamageProcess(DamageInfo damageInfo)
		{
			if (body.HasBuff(DLC2Content.Buffs.HiddenRejectAllDamage))
			{
				return;
			}
			if (!damageInfo.canRejectForce)
			{
				TakeDamageForce(damageInfo);
			}
			if (!alive || godMode || ospTimer > 0f)
			{
				return;
			}
			CharacterMaster characterMaster = null;
			CharacterBody characterBody = null;
			TeamIndex teamIndex = TeamIndex.None;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			float num = combinedHealth;
			if ((bool)damageInfo.attacker)
			{
				characterBody = damageInfo.attacker.GetComponent<CharacterBody>();
				if ((bool)characterBody)
				{
					teamIndex = characterBody.teamComponent.teamIndex;
					vector = characterBody.corePosition - damageInfo.position;
				}
			}
			if ((DamageTypeExtended)(damageInfo.damageType & DamageTypeExtended.DamagePercentOfMaxHealth) == DamageTypeExtended.DamagePercentOfMaxHealth)
			{
				damageInfo.damage = fullHealth * 0.1f;
			}
			bool flag = (ulong)(damageInfo.damageType & DamageType.BypassArmor) != 0;
			bool flag2 = (ulong)(damageInfo.damageType & DamageType.BypassBlock) != 0;
			if (!flag2 && itemCounts.bear > 0 && Util.CheckRoll(Util.ConvertAmplificationPercentageIntoReductionPercentage(15f * (float)itemCounts.bear)))
			{
				EffectData effectData = new EffectData
				{
					origin = damageInfo.position,
					rotation = Util.QuaternionSafeLookRotation((damageInfo.force != UnityEngine.Vector3.zero) ? damageInfo.force : UnityEngine.Random.onUnitSphere)
				};
				EffectManager.SpawnEffect(AssetReferences.bearEffectPrefab, effectData, transmit: true);
				damageInfo.rejected = true;
			}
			if (!flag2 && body.HasBuff(DLC1Content.Buffs.BearVoidReady) && damageInfo.damage > 0f)
			{
				EffectData effectData2 = new EffectData
				{
					origin = damageInfo.position,
					rotation = Util.QuaternionSafeLookRotation((damageInfo.force != UnityEngine.Vector3.zero) ? damageInfo.force : UnityEngine.Random.onUnitSphere)
				};
				EffectManager.SpawnEffect(AssetReferences.bearVoidEffectPrefab, effectData2, transmit: true);
				damageInfo.rejected = true;
				body.RemoveBuff(DLC1Content.Buffs.BearVoidReady);
				int itemCount = body.inventory.GetItemCount(DLC1Content.Items.BearVoid);
				Mathf.CeilToInt(15f * Mathf.Pow(0.9f, itemCount));
				body.AddTimedBuff(DLC1Content.Buffs.BearVoidCooldown, 15f * Mathf.Pow(0.9f, itemCount));
			}
			if (body.HasBuff(RoR2Content.Buffs.HiddenInvincibility) && !flag)
			{
				damageInfo.rejected = true;
			}
			if (((ulong)(damageInfo.damageType & DamageTypeExtended.SojournVehicleDamage) == 0) & body.HasBuff(DLC2Content.Buffs.SojournVehicle))
			{
				damageInfo.rejected = true;
			}
			if (body.HasBuff(RoR2Content.Buffs.Immune) && (!characterBody || !characterBody.HasBuff(JunkContent.Buffs.GoldEmpowered)))
			{
				EffectManager.SpawnEffect(AssetReferences.damageRejectedPrefab, new EffectData
				{
					origin = damageInfo.position
				}, transmit: true);
				damageInfo.rejected = true;
			}
			if (!damageInfo.rejected && body.HasBuff(JunkContent.Buffs.BodyArmor))
			{
				body.RemoveBuff(JunkContent.Buffs.BodyArmor);
				EffectData effectData3 = new EffectData
				{
					origin = damageInfo.position,
					rotation = Util.QuaternionSafeLookRotation((damageInfo.force != UnityEngine.Vector3.zero) ? damageInfo.force : UnityEngine.Random.onUnitSphere)
				};
				EffectManager.SpawnEffect(AssetReferences.captainBodyArmorBlockEffectPrefab, effectData3, transmit: true);
				damageInfo.rejected = true;
			}
			IOnIncomingDamageServerReceiver[] array = onIncomingDamageReceivers;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].OnIncomingDamageServer(damageInfo);
			}
			if (damageInfo.rejected)
			{
				return;
			}
			if (body.HasBuff(DLC2Content.Buffs.lunarruin))
			{
				float num2 = (float)body.GetBuffCount(DLC2Content.Buffs.lunarruin) * 0.1f;
				float num3 = damageInfo.damage * num2;
				damageInfo.damage += num3;
			}
			float num4 = damageInfo.damage;
			if (teamIndex == body.teamComponent.teamIndex)
			{
				TeamDef teamDef = TeamCatalog.GetTeamDef(teamIndex);
				if (teamDef != null)
				{
					num4 *= teamDef.friendlyFireScaling;
				}
			}
			if (num4 > 0f)
			{
				if ((bool)characterBody)
				{
					if (characterBody.canPerformBackstab && (DamageType)(damageInfo.damageType & DamageType.DoT) != DamageType.DoT && (damageInfo.procChainMask.HasProc(ProcType.Backstab) || BackstabManager.IsBackstab(-vector, body)))
					{
						damageInfo.crit = true;
						damageInfo.procChainMask.AddProc(ProcType.Backstab);
						if ((bool)BackstabManager.backstabImpactEffectPrefab)
						{
							EffectManager.SimpleImpactEffect(BackstabManager.backstabImpactEffectPrefab, damageInfo.position, -damageInfo.force, transmit: true);
						}
					}
					characterMaster = characterBody.master;
					if ((bool)characterMaster && (bool)characterMaster.inventory)
					{
						if (num >= fullCombinedHealth * 0.9f)
						{
							int itemCount2 = characterMaster.inventory.GetItemCount(RoR2Content.Items.Crowbar);
							if (itemCount2 > 0)
							{
								num4 *= 1f + 0.75f * (float)itemCount2;
								EffectManager.SimpleImpactEffect(AssetReferences.crowbarImpactEffectPrefab, damageInfo.position, -damageInfo.force, transmit: true);
							}
						}
						if (num >= fullCombinedHealth && !damageInfo.rejected)
						{
							int itemCount3 = characterMaster.inventory.GetItemCount(DLC1Content.Items.ExplodeOnDeathVoid);
							if (itemCount3 > 0)
							{
								UnityEngine.Vector3 corePosition = Util.GetCorePosition(body);
								float damageCoefficient = 2.6f * (1f + (float)(itemCount3 - 1) * 0.6f);
								float baseDamage = Util.OnKillProcDamage(characterBody.damage, damageCoefficient);
								GameObject obj = UnityEngine.Object.Instantiate(AssetReferences.explodeOnDeathVoidExplosionPrefab, corePosition, UnityEngine.Quaternion.identity);
								DelayBlast component = obj.GetComponent<DelayBlast>();
								component.position = corePosition;
								component.baseDamage = baseDamage;
								component.baseForce = 1000f;
								component.radius = 12f + 2.4f * ((float)itemCount3 - 1f);
								component.attacker = damageInfo.attacker;
								component.inflictor = null;
								component.crit = Util.CheckRoll(characterBody.crit, characterMaster);
								component.maxTimer = 0.2f;
								component.damageColorIndex = DamageColorIndex.Void;
								component.falloffModel = BlastAttack.FalloffModel.SweetSpot;
								obj.GetComponent<TeamFilter>().teamIndex = teamIndex;
								NetworkServer.Spawn(obj);
							}
						}
						int itemCount4 = characterMaster.inventory.GetItemCount(RoR2Content.Items.NearbyDamageBonus);
						if (itemCount4 > 0 && vector.sqrMagnitude <= 169f)
						{
							damageInfo.damageColorIndex = DamageColorIndex.Nearby;
							num4 *= 1f + (float)itemCount4 * 0.2f;
							EffectManager.SimpleImpactEffect(AssetReferences.diamondDamageBonusImpactEffectPrefab, damageInfo.position, vector, transmit: true);
						}
						int itemCount5 = characterMaster.inventory.GetItemCount(DLC1Content.Items.FragileDamageBonus);
						if (itemCount5 > 0)
						{
							num4 *= 1f + (float)itemCount5 * 0.2f;
						}
						if (characterMaster.GetBody().HasBuff(DLC2Content.Buffs.LowerHealthHigherDamageBuff))
						{
							int itemCount6 = characterMaster.inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage);
							num4 *= 1f + (float)itemCount6 * 0.2f;
						}
						if (damageInfo.procCoefficient > 0f)
						{
							int itemCount7 = characterMaster.inventory.GetItemCount(RoR2Content.Items.ArmorReductionOnHit);
							if (itemCount7 > 0 && !body.HasBuff(RoR2Content.Buffs.Pulverized))
							{
								body.AddTimedBuff(RoR2Content.Buffs.PulverizeBuildup, 2f * damageInfo.procCoefficient);
								if (body.GetBuffCount(RoR2Content.Buffs.PulverizeBuildup) >= 5)
								{
									body.ClearTimedBuffs(RoR2Content.Buffs.PulverizeBuildup);
									body.AddTimedBuff(RoR2Content.Buffs.Pulverized, 8f * (float)itemCount7);
									EffectManager.SpawnEffect(AssetReferences.pulverizedEffectPrefab, new EffectData
									{
										origin = body.corePosition,
										scale = body.radius
									}, transmit: true);
								}
							}
							int itemCount8 = characterMaster.inventory.GetItemCount(DLC1Content.Items.PermanentDebuffOnHit);
							bool flag3 = false;
							for (int j = 0; j < itemCount8; j++)
							{
								if (Util.CheckRoll(100f * damageInfo.procCoefficient, characterMaster))
								{
									body.AddBuff(DLC1Content.Buffs.PermanentDebuff);
									flag3 = true;
								}
							}
							if (flag3)
							{
								EffectManager.SpawnEffect(AssetReferences.permanentDebuffEffectPrefab, new EffectData
								{
									origin = damageInfo.position,
									scale = itemCount8
								}, transmit: true);
							}
							if (body.HasBuff(RoR2Content.Buffs.MercExpose) && (bool)characterBody && characterBody.bodyIndex == BodyCatalog.FindBodyIndex("MercBody"))
							{
								body.RemoveBuff(RoR2Content.Buffs.MercExpose);
								float num5 = characterBody.damage * 3.5f;
								num4 += num5;
								damageInfo.damage += num5;
								SkillLocator skillLocator = characterBody.skillLocator;
								if ((bool)skillLocator)
								{
									skillLocator.DeductCooldownFromAllSkillsServer(1f);
								}
								EffectManager.SimpleImpactEffect(AssetReferences.mercExposeConsumeEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true);
							}
						}
						if (body.isBoss)
						{
							int itemCount9 = characterMaster.inventory.GetItemCount(RoR2Content.Items.BossDamageBonus);
							if (itemCount9 > 0)
							{
								num4 *= 1f + 0.2f * (float)itemCount9;
								damageInfo.damageColorIndex = DamageColorIndex.WeakPoint;
								EffectManager.SimpleImpactEffect(AssetReferences.bossDamageBonusImpactEffectPrefab, damageInfo.position, -damageInfo.force, transmit: true);
							}
						}
					}
					if (damageInfo.crit)
					{
						num4 *= characterBody.critMultiplier;
					}
				}
				if ((ulong)(damageInfo.damageType & DamageType.WeakPointHit) != 0L)
				{
					num4 *= 1.5f;
					damageInfo.damageColorIndex = DamageColorIndex.WeakPoint;
				}
				if (body.HasBuff(RoR2Content.Buffs.DeathMark))
				{
					num4 *= 1.5f;
					damageInfo.damageColorIndex = DamageColorIndex.DeathMark;
				}
				if (!flag)
				{
					float armor = body.armor;
					armor += adaptiveArmorValue;
					bool flag4 = (ulong)(damageInfo.damageType & DamageType.AOE) != 0;
					if ((body.bodyFlags & CharacterBody.BodyFlags.ResistantToAOE) != 0 && flag4)
					{
						armor += 300f;
					}
					float num6 = ((armor >= 0f) ? (1f - armor / (armor + 100f)) : (2f - 100f / (100f - armor)));
					num4 = Mathf.Max(1f, num4 * num6);
					if (itemCounts.armorPlate > 0)
					{
						num4 = Mathf.Max(1f, num4 - 5f * (float)itemCounts.armorPlate);
						EntitySoundManager.EmitSoundServer(LegacyResourcesAPI.Load<NetworkSoundEventDef>("NetworkSoundEventDefs/nseArmorPlateBlock").index, base.gameObject);
					}
					if (itemCounts.parentEgg > 0)
					{
						Heal((float)itemCounts.parentEgg * 15f, default(ProcChainMask));
						EntitySoundManager.EmitSoundServer(LegacyResourcesAPI.Load<NetworkSoundEventDef>("NetworkSoundEventDefs/nseParentEggHeal").index, base.gameObject);
					}
				}
				if (body.hasOneShotProtection && (DamageType)(damageInfo.damageType & DamageType.BypassOneShotProtection) != DamageType.BypassOneShotProtection)
				{
					float num7 = (fullCombinedHealth + barrier) * (1f - body.oneShotProtectionFraction);
					float b = Mathf.Max(0f, num7 - serverDamageTakenThisUpdate);
					float num8 = num4;
					num4 = Mathf.Min(num4, b);
					if (num4 != num8)
					{
						TriggerOneShotProtection();
					}
				}
				if ((ulong)(damageInfo.damageType & DamageType.BonusToLowHealth) != 0)
				{
					float num9 = Mathf.Lerp(3f, 1f, combinedHealthFraction);
					num4 *= num9;
				}
				if (body.HasBuff(RoR2Content.Buffs.LunarShell) && num4 > fullHealth * 0.1f)
				{
					num4 = fullHealth * 0.1f;
				}
				if (itemCounts.minHealthPercentage > 0)
				{
					float num10 = fullCombinedHealth * ((float)itemCounts.minHealthPercentage / 100f);
					num4 = Mathf.Max(0f, Mathf.Min(num4, combinedHealth - num10));
				}
			}
			if ((ulong)(damageInfo.damageType & DamageType.SlowOnHit) != 0L)
			{
				body.AddTimedBuff(RoR2Content.Buffs.Slow50, 2f);
			}
			if ((ulong)(damageInfo.damageType & DamageType.ClayGoo) != 0L && (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToGoo) == 0)
			{
				body.AddTimedBuff(RoR2Content.Buffs.ClayGoo, 2f);
			}
			if ((ulong)(damageInfo.damageType & DamageType.Nullify) != 0L)
			{
				body.AddTimedBuff(RoR2Content.Buffs.NullifyStack, 8f);
			}
			if ((ulong)(damageInfo.damageType & DamageType.CrippleOnHit) != 0L || ((bool)characterBody && characterBody.HasBuff(RoR2Content.Buffs.AffixLunar)))
			{
				body.AddTimedBuff(RoR2Content.Buffs.Cripple, 3f);
			}
			if ((ulong)(damageInfo.damageType & DamageType.ApplyMercExpose) != 0L)
			{
				UnityEngine.Debug.LogFormat("Adding expose");
				body.AddBuff(RoR2Content.Buffs.MercExpose);
			}
			CharacterMaster master = body.master;
			if ((bool)master)
			{
				if (itemCounts.goldOnHit > 0)
				{
					uint num11 = (uint)(num4 / fullCombinedHealth * (float)master.money * (float)itemCounts.goldOnHit);
					uint money = master.money;
					master.money = (uint)Mathf.Max(0f, (float)master.money - (float)num11);
					if (money - master.money != 0)
					{
						GoldOrb goldOrb = new GoldOrb();
						goldOrb.origin = damageInfo.position;
						goldOrb.target = (characterBody ? characterBody.mainHurtBox : body.mainHurtBox);
						goldOrb.goldAmount = 0u;
						OrbManager.instance.AddOrb(goldOrb);
						EffectManager.SimpleImpactEffect(AssetReferences.loseCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true);
					}
				}
				if (itemCounts.goldOnHurt > 0 && characterBody != body && characterBody != null)
				{
					int num12 = 3;
					GoldOrb goldOrb2 = new GoldOrb();
					goldOrb2.origin = damageInfo.position;
					goldOrb2.target = body.mainHurtBox;
					goldOrb2.goldAmount = (uint)((float)(itemCounts.goldOnHurt * num12) * Run.instance.difficultyCoefficient);
					OrbManager.instance.AddOrb(goldOrb2);
					EffectManager.SimpleImpactEffect(AssetReferences.gainCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true);
				}
			}
			if (itemCounts.adaptiveArmor > 0)
			{
				float num13 = num4 / fullCombinedHealth * 100f * 30f * (float)itemCounts.adaptiveArmor;
				adaptiveArmorValue = Mathf.Min(adaptiveArmorValue + num13, 400f);
			}
			float num14 = num4;
			if (num14 > 0f)
			{
				isShieldRegenForced = false;
			}
			if (body.teamComponent.teamIndex == TeamIndex.Player && Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse8)
			{
				float num15 = num14 / fullCombinedHealth * 100f;
				float num16 = 0.4f;
				int num17 = Mathf.FloorToInt(num15 * num16);
				for (int k = 0; k < num17; k++)
				{
					body.AddBuff(RoR2Content.Buffs.PermanentCurse);
				}
			}
			if (num14 > 0f && barrier > 0f)
			{
				if (num14 <= barrier)
				{
					Networkbarrier = barrier - num14;
					num14 = 0f;
				}
				else
				{
					num14 -= barrier;
					Networkbarrier = 0f;
				}
			}
			if (num14 > 0f && shield > 0f)
			{
				if (num14 <= shield)
				{
					Networkshield = shield - num14;
					num14 = 0f;
				}
				else
				{
					num14 -= shield;
					Networkshield = 0f;
					float scale = 1f;
					if ((bool)body)
					{
						scale = body.radius;
					}
					EffectManager.SpawnEffect(AssetReferences.shieldBreakEffectPrefab, new EffectData
					{
						origin = base.transform.position,
						scale = scale
					}, transmit: true);
				}
			}
			if (!flag2 && body.HasBuff(DLC2Content.Buffs.DelayedDamageBuff) && damageInfo.damage > 0f && !damageInfo.delayedDamageSecondHalf && !damageInfo.rejected)
			{
				Transform transform = (body.mainHurtBox ? body.mainHurtBox.transform : base.transform);
				UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/DelayedDamageIndicator"), transform.position, UnityEngine.Quaternion.identity, transform);
				Util.PlaySound("Play_item_proc_delayedDamage", body.gameObject);
				num14 *= 0.5f;
				num4 = num14;
				DamageInfo damageInfo2 = new DamageInfo
				{
					crit = damageInfo.crit,
					damage = num14,
					damageType = DamageType.BypassArmor,
					attacker = damageInfo.attacker,
					position = damageInfo.position,
					inflictor = damageInfo.inflictor,
					damageColorIndex = damageInfo.damageColorIndex,
					delayedDamageSecondHalf = true
				};
				damageInfo2.damageType |= damageInfo.damageType & DamageType.NonLethal;
				body.SecondHalfOfDelayedDamage(damageInfo2);
			}
			bool flag5 = (ulong)(damageInfo.damageType & DamageType.VoidDeath) != 0L && (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToVoidDeath) == 0;
			float executionHealthLost = 0f;
			GameObject gameObject = null;
			if (num14 > 0f)
			{
				float num18 = health - num14;
				if (num18 < 1f && (ulong)(damageInfo.damageType & DamageType.NonLethal) != 0L && health >= 1f)
				{
					num18 = 1f;
				}
				Networkhealth = num18;
				recentlyTookDamageCoyoteTimer = 0.2f;
			}
			if (health > 0f && body.teamComponent.teamIndex == TeamIndex.Player && (bool)body.inventory && body.inventory.GetItemCount(DLC2Content.Items.LowerHealthHigherDamage) > 0)
			{
				body.UpdateLowerHealthHigherDamage();
			}
			float num19 = float.NegativeInfinity;
			bool flag6 = (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToExecutes) != 0;
			if (!flag5 && !flag6)
			{
				if (isInFrozenState && num19 < 0.3f)
				{
					num19 = 0.3f;
					gameObject = FrozenState.executeEffectPrefab;
				}
				if ((bool)characterBody)
				{
					if (body.isElite)
					{
						float executeEliteHealthFraction = characterBody.executeEliteHealthFraction;
						if (num19 < executeEliteHealthFraction)
						{
							num19 = executeEliteHealthFraction;
							gameObject = AssetReferences.executeEffectPrefab;
						}
					}
					if (!body.isBoss && (bool)characterBody.inventory && Util.CheckRoll((float)characterBody.inventory.GetItemCount(DLC1Content.Items.CritGlassesVoid) * 0.5f * damageInfo.procCoefficient, characterBody.master))
					{
						flag5 = true;
						gameObject = AssetReferences.critGlassesVoidExecuteEffectPrefab;
						damageInfo.damageType |= (DamageTypeCombo)DamageType.VoidDeath;
					}
				}
			}
			if (flag5 || (num19 > 0f && combinedHealthFraction <= num19))
			{
				flag5 = true;
				executionHealthLost = Mathf.Max(combinedHealth, 0f);
				if (health > 0f)
				{
					Networkhealth = 0f;
				}
				if (shield > 0f)
				{
					Networkshield = 0f;
				}
				if (barrier > 0f)
				{
					Networkbarrier = 0f;
				}
			}
			if (damageInfo.canRejectForce)
			{
				TakeDamageForce(damageInfo);
			}
			DamageReport damageReport = new DamageReport(damageInfo, this, num4, num);
			IOnTakeDamageServerReceiver[] array2 = onTakeDamageReceivers;
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i].OnTakeDamageServer(damageReport);
			}
			if (num4 > 0f)
			{
				SendDamageDealt(damageReport);
			}
			UpdateLastHitTime(damageReport.damageDealt, damageInfo.position, (ulong)(damageInfo.damageType & DamageType.Silent) != 0, damageInfo.attacker);
			if ((bool)damageInfo.attacker)
			{
				List<IOnDamageDealtServerReceiver> gameObjectComponents = GetComponentsCache<IOnDamageDealtServerReceiver>.GetGameObjectComponents(damageInfo.attacker);
				foreach (IOnDamageDealtServerReceiver item in gameObjectComponents)
				{
					item.OnDamageDealtServer(damageReport);
				}
				GetComponentsCache<IOnDamageDealtServerReceiver>.ReturnBuffer(gameObjectComponents);
			}
			if ((bool)damageInfo.inflictor)
			{
				List<IOnDamageInflictedServerReceiver> gameObjectComponents2 = GetComponentsCache<IOnDamageInflictedServerReceiver>.GetGameObjectComponents(damageInfo.inflictor);
				foreach (IOnDamageInflictedServerReceiver item2 in gameObjectComponents2)
				{
					item2.OnDamageInflictedServer(damageReport);
				}
				GetComponentsCache<IOnDamageInflictedServerReceiver>.ReturnBuffer(gameObjectComponents2);
			}
			GlobalEventManager.ServerDamageDealt(damageReport);
			if (!alive)
			{
				killingDamageType = damageInfo.damageType;
				if (flag5)
				{
					GlobalEventManager.ServerCharacterExecuted(damageReport, executionHealthLost);
					if ((object)gameObject != null)
					{
						EffectManager.SpawnEffect(gameObject, new EffectData
						{
							origin = body.corePosition,
							scale = (body ? body.radius : 1f)
						}, transmit: true);
					}
				}
				IOnKilledServerReceiver[] components = GetComponents<IOnKilledServerReceiver>();
				for (int i = 0; i < components.Length; i++)
				{
					components[i].OnKilledServer(damageReport);
				}
				if ((bool)damageInfo.attacker)
				{
					IOnKilledOtherServerReceiver[] components2 = damageInfo.attacker.GetComponents<IOnKilledOtherServerReceiver>();
					for (int i = 0; i < components2.Length; i++)
					{
						components2[i].OnKilledOtherServer(damageReport);
					}
				}
				if (Util.CheckRoll(globalDeathEventChanceCoefficient * 100f))
				{
					GlobalEventManager.instance.OnCharacterDeath(damageReport);
				}
			}
			else
			{
				if (!(num4 > 0f))
				{
					return;
				}
				int a = 5 + 2 * (itemCounts.thorns - 1);
				if (itemCounts.thorns > 0 && !damageReport.damageInfo.procChainMask.HasProc(ProcType.Thorns))
				{
					bool flag7 = itemCounts.invadingDoppelganger > 0;
					float radius = 25f + 10f * (float)(itemCounts.thorns - 1);
					bool isCrit = body.RollCrit();
					float damageValue = 1.6f * body.damage;
					TeamIndex teamIndex2 = body.teamComponent.teamIndex;
					HurtBox[] hurtBoxes = new SphereSearch
					{
						origin = damageReport.damageInfo.position,
						radius = radius,
						mask = LayerIndex.entityPrecise.mask,
						queryTriggerInteraction = QueryTriggerInteraction.UseGlobal
					}.RefreshCandidates().FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamIndex2)).OrderCandidatesByDistance()
						.FilterCandidatesByDistinctHurtBoxEntities()
						.GetHurtBoxes();
					for (int l = 0; l < Mathf.Min(a, hurtBoxes.Length); l++)
					{
						LightningOrb lightningOrb = new LightningOrb();
						lightningOrb.attacker = base.gameObject;
						lightningOrb.bouncedObjects = null;
						lightningOrb.bouncesRemaining = 0;
						lightningOrb.damageCoefficientPerBounce = 1f;
						lightningOrb.damageColorIndex = DamageColorIndex.Item;
						lightningOrb.damageValue = damageValue;
						lightningOrb.isCrit = isCrit;
						lightningOrb.lightningType = LightningOrb.LightningType.RazorWire;
						lightningOrb.origin = damageReport.damageInfo.position;
						lightningOrb.procChainMask = default(ProcChainMask);
						lightningOrb.procChainMask.AddProc(ProcType.Thorns);
						lightningOrb.procCoefficient = (flag7 ? 0f : 0.5f);
						lightningOrb.range = 0f;
						lightningOrb.teamIndex = teamIndex2;
						lightningOrb.target = hurtBoxes[l];
						OrbManager.instance.AddOrb(lightningOrb);
					}
				}
				if (!flag2 && itemCounts.antlerShield > 0 && characterBody != null && !damageInfo.delayedDamageSecondHalf && damageInfo.attacker.GetComponent<TeamComponent>().teamIndex != body.teamComponent.teamIndex && Util.CheckRoll(50f + 5f * (float)(itemCounts.antlerShield - 1)))
				{
					bool flag8 = itemCounts.invadingDoppelganger > 0;
					float damageValue2 = damageInfo.damage / 10f * (float)itemCounts.antlerShield;
					bool isCrit2 = body.RollCrit();
					TeamIndex teamIndex3 = body.teamComponent.teamIndex;
					LightningOrb lightningOrb2 = new LightningOrb();
					lightningOrb2.attacker = base.gameObject;
					lightningOrb2.bouncedObjects = null;
					lightningOrb2.bouncesRemaining = 0;
					lightningOrb2.damageCoefficientPerBounce = 1f;
					lightningOrb2.damageColorIndex = DamageColorIndex.Item;
					lightningOrb2.damageValue = damageValue2;
					lightningOrb2.isCrit = isCrit2;
					lightningOrb2.lightningType = LightningOrb.LightningType.AntlerShield;
					lightningOrb2.origin = damageReport.damageInfo.position;
					lightningOrb2.procChainMask = default(ProcChainMask);
					lightningOrb2.procChainMask.AddProc(ProcType.Thorns);
					lightningOrb2.procCoefficient = (flag8 ? 0f : 0.3f);
					lightningOrb2.range = 0f;
					lightningOrb2.teamIndex = teamIndex3;
					lightningOrb2.target = characterBody.mainHurtBox;
					OrbManager.instance.AddOrb(lightningOrb2);
					Util.PlaySound("Play_item_proc_negateAttack", body.gameObject);
				}
				if (!flag2 && itemCounts.noxiousThorn > 0 && Util.CheckRoll(25f))
				{
					body.TriggerEnemyDebuffs(damageInfo);
				}
				if (!body.HasBuff(DLC2Content.Buffs.AurelioniteBlessing))
				{
					return;
				}
				int baseCost = 1;
				int difficultyScaledCost = Run.instance.GetDifficultyScaledCost(baseCost);
				uint money2 = characterMaster.money;
				characterMaster.money = (uint)Mathf.Max(0f, (float)characterMaster.money - (float)difficultyScaledCost);
				if (money2 - characterMaster.money != 0 || !characterBody.isPlayerControlled)
				{
					GoldOrb goldOrb3 = new GoldOrb();
					goldOrb3.origin = characterBody.transform.position;
					goldOrb3.target = (body ? body.mainHurtBox : characterBody.mainHurtBox);
					goldOrb3.goldAmount = (uint)difficultyScaledCost;
					OrbManager.instance.AddOrb(goldOrb3);
					EffectManager.SimpleImpactEffect(AssetReferences.loseCoinsImpactEffectPrefab, damageInfo.position, UnityEngine.Vector3.up, transmit: true);
					if (!characterBody.isPlayerControlled)
					{
						characterMaster.money = money2;
					}
				}
			}
		}

		[Server]
		private void TriggerOneShotProtection()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::TriggerOneShotProtection()' called on client");
				return;
			}
			ospTimer = 0.1f;
			if (body.GetBuffCount(DLC2Content.Buffs.DelayedDamageDebuff) > 0)
			{
				body.protectFromOneShot = true;
			}
		}

		[Server]
		public void Suicide(GameObject killerOverride = null, GameObject inflictorOverride = null, DamageTypeCombo damageType = default(DamageTypeCombo))
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealthComponent::Suicide(UnityEngine.GameObject,UnityEngine.GameObject,RoR2.DamageTypeCombo)' called on client");
			}
			else if (alive && !godMode)
			{
				float combinedHealthBeforeDamage = combinedHealth;
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = combinedHealth;
				damageInfo.position = base.transform.position;
				damageInfo.damageType = damageType;
				damageInfo.procCoefficient = 1f;
				if ((bool)killerOverride)
				{
					damageInfo.attacker = killerOverride;
				}
				if ((bool)inflictorOverride)
				{
					damageInfo.inflictor = inflictorOverride;
				}
				Networkhealth = 0f;
				DamageReport damageReport = new DamageReport(damageInfo, this, damageInfo.damage, combinedHealthBeforeDamage);
				killingDamageType = damageInfo.damageType;
				IOnKilledServerReceiver[] components = GetComponents<IOnKilledServerReceiver>();
				for (int i = 0; i < components.Length; i++)
				{
					components[i].OnKilledServer(damageReport);
				}
				GlobalEventManager.instance.OnCharacterDeath(damageReport);
			}
		}

		public void UpdateLastHitTime(float damageValue, UnityEngine.Vector3 damagePosition, bool damageIsSilent, GameObject attacker)
		{
			if (NetworkServer.active && (bool)body && damageValue > 0f)
			{
				if (itemCounts.medkit > 0)
				{
					body.AddTimedBuff(RoR2Content.Buffs.MedkitHeal, 2f);
				}
				if (itemCounts.healingPotion > 0 && isHealthLow)
				{
					body.inventory.RemoveItem(DLC1Content.Items.HealingPotion);
					body.inventory.GiveItem(DLC1Content.Items.HealingPotionConsumed);
					CharacterMasterNotificationQueue.SendTransformNotification(body.master, DLC1Content.Items.HealingPotion.itemIndex, DLC1Content.Items.HealingPotionConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default);
					HealFraction(0.75f, default(ProcChainMask));
					EffectData effectData = new EffectData
					{
						origin = base.transform.position
					};
					effectData.SetNetworkedObjectReference(base.gameObject);
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/HealingPotionEffect"), effectData, transmit: true);
				}
				if (body.GetBuffCount(DLC2Content.Buffs.RevitalizeBuff) > 0 && isHealthLow)
				{
					body.RemoveBuff(DLC2Content.Buffs.RevitalizeBuff);
					HealFraction(0.5f, default(ProcChainMask));
					EffectData effectData2 = new EffectData
					{
						origin = base.transform.position
					};
					effectData2.SetNetworkedObjectReference(base.gameObject);
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Seeker/RevitalizeBuffVFXConsumed"), effectData2, transmit: true);
				}
				float num = 120f;
				if (isHealthLow && body.HasBuff(DLC2Content.Buffs.TeleportOnLowHealth) && itemCounts.unstableTransmitter > 0)
				{
					body.RemoveBuff(DLC2Content.Buffs.TeleportOnLowHealth);
					float duration = Mathf.Max(num - num * ((float)(itemCounts.unstableTransmitter - 1) * 0.2f), 15f);
					body.AddTimedBuff(DLC2Content.Buffs.TeleportOnLowHealthCooldown, duration);
					body.hasTeleported = true;
					body.AddTimedBuff(RoR2Content.Buffs.HiddenInvincibility, 2f);
					body.CallRpcTeleportCharacterToSafety();
				}
				if (itemCounts.fragileDamageBonus > 0 && isHealthLow)
				{
					body.inventory.GiveItem(DLC1Content.Items.FragileDamageBonusConsumed, itemCounts.fragileDamageBonus);
					body.inventory.RemoveItem(DLC1Content.Items.FragileDamageBonus, itemCounts.fragileDamageBonus);
					CharacterMasterNotificationQueue.SendTransformNotification(body.master, DLC1Content.Items.FragileDamageBonus.itemIndex, DLC1Content.Items.FragileDamageBonusConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.Default);
					EffectData effectData3 = new EffectData
					{
						origin = base.transform.position
					};
					effectData3.SetNetworkedObjectReference(base.gameObject);
					EffectManager.SpawnEffect(AssetReferences.fragileDamageBonusBreakEffectPrefab, effectData3, transmit: true);
				}
			}
			if (damageIsSilent)
			{
				return;
			}
			lastHitTime = Run.FixedTimeStamp.now;
			lastHitAttacker = attacker;
			serverDamageTakenThisUpdate += damageValue;
			if ((bool)modelLocator)
			{
				Transform modelTransform = modelLocator.modelTransform;
				if ((bool)modelTransform)
				{
					Animator component = modelTransform.GetComponent<Animator>();
					if ((bool)component)
					{
						string layerName = "Flinch";
						int layerIndex = component.GetLayerIndex(layerName);
						if (layerIndex >= 0)
						{
							component.SetLayerWeight(layerIndex, 1f + Mathf.Clamp01(damageValue / fullCombinedHealth * 10f) * 3f);
							component.Play("FlinchStart", layerIndex);
						}
					}
				}
			}
			painAnimationHandler?.HandlePain(damageValue, damagePosition);
		}

		[InitDuringStartup]
		private static void Init()
		{
			AssetReferences.Resolve();
		}

		private void Awake()
		{
			body = GetComponent<CharacterBody>();
			modelLocator = GetComponent<ModelLocator>();
			painAnimationHandler = GetComponent<IPainAnimationHandler>();
			onIncomingDamageReceivers = GetComponents<IOnIncomingDamageServerReceiver>();
			onTakeDamageReceivers = GetComponents<IOnTakeDamageServerReceiver>();
			lastHitTime = Run.FixedTimeStamp.negativeInfinity;
			lastHealTime = Run.FixedTimeStamp.negativeInfinity;
			body.onInventoryChanged += OnInventoryChanged;
		}

		private void OnDestroy()
		{
			body.onInventoryChanged -= OnInventoryChanged;
		}

		public void FixedUpdate()
		{
			ManagedFixedUpdate(Time.fixedDeltaTime);
		}

		public void ManagedFixedUpdate(float deltaTime)
		{
			if (NetworkServer.active)
			{
				ServerFixedUpdate(deltaTime);
			}
			if (!alive && wasAlive)
			{
				wasAlive = false;
				if ((bool)modelLocator)
				{
					modelLocator.forceCulled = forceCulled;
				}
				GetComponent<CharacterDeathBehavior>()?.OnDeath();
			}
		}

		private void ServerFixedUpdate(float deltaTime)
		{
			if (recentlyTookDamageCoyoteTimer > 0f)
			{
				recentlyTookDamageCoyoteTimer -= deltaTime;
			}
			if (!alive)
			{
				return;
			}
			regenAccumulator += body.regen * deltaTime;
			if (barrier > 0f)
			{
				Networkbarrier = Mathf.Max(barrier - body.barrierDecayRate * deltaTime, 0f);
				if (barrier <= 0f)
				{
					body.MarkAllStatsDirty();
				}
			}
			else if (barrier <= 0f && body.HasBuff(DLC2Content.Buffs.GeodeBuff))
			{
				body.RemoveBuff(DLC2Content.Buffs.GeodeBuff);
			}
			if (regenAccumulator > 1f)
			{
				float num = Mathf.Floor(regenAccumulator);
				regenAccumulator -= num;
				Heal(num, default(ProcChainMask), nonRegen: false);
			}
			if (regenAccumulator < -1f)
			{
				float num2 = Mathf.Ceil(regenAccumulator);
				regenAccumulator -= num2;
				Networkhealth = health + num2;
				if (health <= 0f)
				{
					Suicide();
				}
			}
			float num3 = shield;
			bool flag = num3 >= body.maxShield;
			if ((body.outOfDanger || isShieldRegenForced) && !flag)
			{
				num3 += body.maxShield * 0.5f * deltaTime;
				if (num3 > body.maxShield)
				{
					num3 = body.maxShield;
				}
			}
			if (num3 >= body.maxShield && !flag)
			{
				Util.PlaySound("Play_item_proc_personal_shield_end", base.gameObject);
			}
			if (!num3.Equals(shield))
			{
				Networkshield = num3;
			}
			if (devilOrbHealPool > 0f)
			{
				devilOrbTimer -= deltaTime;
				if (devilOrbTimer <= 0f)
				{
					devilOrbTimer += 0.1f;
					float scale = 1f;
					float num4 = fullCombinedHealth / 10f;
					float num5 = 2.5f;
					devilOrbHealPool -= num4;
					DevilOrb devilOrb = new DevilOrb();
					devilOrb.origin = body.aimOriginTransform.position;
					devilOrb.damageValue = num4 * num5;
					devilOrb.teamIndex = TeamComponent.GetObjectTeam(base.gameObject);
					devilOrb.attacker = base.gameObject;
					devilOrb.damageColorIndex = DamageColorIndex.Poison;
					devilOrb.scale = scale;
					devilOrb.procChainMask.AddProc(ProcType.HealNova);
					devilOrb.effectType = DevilOrb.EffectType.Skull;
					HurtBox hurtBox = devilOrb.PickNextTarget(devilOrb.origin, 40f);
					if ((bool)hurtBox)
					{
						devilOrb.target = hurtBox;
						devilOrb.isCrit = Util.CheckRoll(body.crit, body.master);
						OrbManager.instance.AddOrb(devilOrb);
					}
				}
			}
			adaptiveArmorValue = Mathf.Max(0f, adaptiveArmorValue - 40f * deltaTime);
			serverDamageTakenThisUpdate = 0f;
			ospTimer -= deltaTime;
		}

		private static void SendDamageDealt(DamageReport damageReport)
		{
			DamageInfo damageInfo = damageReport.damageInfo;
			DamageDealtMessage damageDealtMessage = new DamageDealtMessage();
			damageDealtMessage.victim = damageReport.victim.gameObject;
			damageDealtMessage.damage = damageReport.damageDealt;
			damageDealtMessage.attacker = damageInfo.attacker;
			damageDealtMessage.position = damageInfo.position;
			damageDealtMessage.crit = damageInfo.crit;
			damageDealtMessage.damageType = damageInfo.damageType;
			damageDealtMessage.damageColorIndex = damageInfo.damageColorIndex;
			damageDealtMessage.hitLowHealth = damageReport.hitLowHealth;
			NetworkServer.SendToAll(60, damageDealtMessage);
		}

		[NetworkMessageHandler(msgType = 60, client = true)]
		private static void HandleDamageDealt(NetworkMessage netMsg)
		{
			DamageDealtMessage damageDealtMessage = netMsg.ReadMessage<DamageDealtMessage>();
			if ((bool)damageDealtMessage.victim)
			{
				HealthComponent component = damageDealtMessage.victim.GetComponent<HealthComponent>();
				if ((bool)component && !NetworkServer.active)
				{
					component.UpdateLastHitTime(damageDealtMessage.damage, damageDealtMessage.position, damageDealtMessage.isSilent, damageDealtMessage.attacker);
				}
			}
			if (SettingsConVars.enableDamageNumbers.value && (bool)DamageNumberManager.instance)
			{
				TeamComponent teamComponent = null;
				if ((bool)damageDealtMessage.attacker)
				{
					teamComponent = damageDealtMessage.attacker.GetComponent<TeamComponent>();
				}
				DamageNumberManager.instance.SpawnDamageNumber(damageDealtMessage.damage, damageDealtMessage.position, damageDealtMessage.crit, teamComponent ? teamComponent.teamIndex : TeamIndex.None, damageDealtMessage.damageColorIndex);
			}
			GlobalEventManager.ClientDamageNotified(damageDealtMessage);
		}

		private static void SendHeal(GameObject target, float amount, bool isCrit)
		{
			HealMessage healMessage = new HealMessage();
			healMessage.target = target;
			healMessage.amount = (isCrit ? (0f - amount) : amount);
			NetworkServer.SendToAll(61, healMessage);
		}

		[NetworkMessageHandler(msgType = 61, client = true)]
		private static void HandleHeal(NetworkMessage netMsg)
		{
			HealMessage healMessage = netMsg.ReadMessage<HealMessage>();
			if (SettingsConVars.enableDamageNumbers.value && (bool)healMessage.target)
			{
				if ((bool)DamageNumberManager.instance)
				{
					DamageNumberManager.instance.SpawnDamageNumber(healMessage.amount, Util.GetCorePosition(healMessage.target), healMessage.amount < 0f, TeamIndex.Player, DamageColorIndex.Heal);
				}
				HealthComponent component = healMessage.target.GetComponent<HealthComponent>();
				if ((bool)component && !NetworkServer.active)
				{
					component.lastHealTime = Run.FixedTimeStamp.now;
				}
			}
		}

		private void OnInventoryChanged()
		{
			itemCounts = default(ItemCounts);
			Inventory inventory = body.inventory;
			itemCounts = (inventory ? new ItemCounts(inventory) : default(ItemCounts));
			currentEquipmentIndex = (inventory ? inventory.currentEquipmentIndex : EquipmentIndex.None);
			if (!NetworkServer.active)
			{
				return;
			}
			bool flag = itemCounts.repeatHeal != 0;
			if (flag != (bool)repeatHealComponent)
			{
				if (flag)
				{
					repeatHealComponent = base.gameObject.AddComponent<RepeatHealComponent>();
					repeatHealComponent.healthComponent = this;
				}
				else
				{
					UnityEngine.Object.Destroy(repeatHealComponent);
					repeatHealComponent = null;
				}
			}
		}

		public HealthBarValues GetHealthBarValues()
		{
			float num = 1f - 1f / body.cursePenalty;
			float num2 = (1f - num) / fullCombinedHealth;
			float num3 = body.oneShotProtectionFraction * fullCombinedHealth - missingCombinedHealth;
			HealthBarValues result = default(HealthBarValues);
			result.hasInfusion = (float)itemCounts.infusion > 0f;
			result.hasVoidShields = (float)itemCounts.missileVoid > 0f;
			result.isElite = body.isElite;
			result.isBoss = body.isBoss;
			result.isVoid = (body.bodyFlags & CharacterBody.BodyFlags.Void) != 0;
			result.cullFraction = ((isInFrozenState && (body.bodyFlags & CharacterBody.BodyFlags.ImmuneToExecutes) == 0) ? Mathf.Clamp01(0.3f * fullCombinedHealth * num2) : 0f);
			result.healthFraction = Mathf.Clamp01(health * num2);
			result.shieldFraction = Mathf.Clamp01(shield * num2);
			result.barrierFraction = Mathf.Clamp01(barrier * num2);
			result.magneticFraction = Mathf.Clamp01(magnetiCharge * num2);
			result.curseFraction = num;
			result.ospFraction = num3 * num2;
			result.healthDisplayValue = (int)combinedHealth;
			result.maxHealthDisplayValue = (int)fullHealth;
			return result;
		}

		static HealthComponent()
		{
			lowHealthFraction = 0.25f;
			kCmdCmdHealFull = -290141736;
			NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdHealFull, InvokeCmdCmdHealFull);
			kCmdCmdRechargeShieldFull = -833942624;
			NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdRechargeShieldFull, InvokeCmdCmdRechargeShieldFull);
			kCmdCmdAddBarrier = -1976809257;
			NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdAddBarrier, InvokeCmdCmdAddBarrier);
			kCmdCmdForceShieldRegen = -1029271894;
			NetworkBehaviour.RegisterCommandDelegate(typeof(HealthComponent), kCmdCmdForceShieldRegen, InvokeCmdCmdForceShieldRegen);
			NetworkCRC.RegisterBehaviour("HealthComponent", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdHealFull(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdHealFull called on client.");
			}
			else
			{
				((HealthComponent)obj).CmdHealFull();
			}
		}

		protected static void InvokeCmdCmdRechargeShieldFull(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdRechargeShieldFull called on client.");
			}
			else
			{
				((HealthComponent)obj).CmdRechargeShieldFull();
			}
		}

		protected static void InvokeCmdCmdAddBarrier(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdAddBarrier called on client.");
			}
			else
			{
				((HealthComponent)obj).CmdAddBarrier(reader.ReadSingle());
			}
		}

		protected static void InvokeCmdCmdForceShieldRegen(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdForceShieldRegen called on client.");
			}
			else
			{
				((HealthComponent)obj).CmdForceShieldRegen();
			}
		}

		public void CallCmdHealFull()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdHealFull called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdHealFull();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdHealFull);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdHealFull");
		}

		public void CallCmdRechargeShieldFull()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdRechargeShieldFull called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdRechargeShieldFull();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdRechargeShieldFull);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdRechargeShieldFull");
		}

		public void CallCmdAddBarrier(float value)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdAddBarrier called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdAddBarrier(value);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdAddBarrier);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(value);
			SendCommandInternal(networkWriter, 0, "CmdAddBarrier");
		}

		public void CallCmdForceShieldRegen()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdForceShieldRegen called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdForceShieldRegen();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdForceShieldRegen);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdForceShieldRegen");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(health);
				writer.Write(shield);
				writer.Write(barrier);
				writer.Write(magnetiCharge);
				writer.WritePackedUInt32(_killingDamageType);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(health);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(shield);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(barrier);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(magnetiCharge);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(_killingDamageType);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				health = reader.ReadSingle();
				shield = reader.ReadSingle();
				barrier = reader.ReadSingle();
				magnetiCharge = reader.ReadSingle();
				_killingDamageType = reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				health = reader.ReadSingle();
			}
			if (((uint)num & 2u) != 0)
			{
				shield = reader.ReadSingle();
			}
			if (((uint)num & 4u) != 0)
			{
				SetBarrier(reader.ReadSingle());
			}
			if (((uint)num & 8u) != 0)
			{
				magnetiCharge = reader.ReadSingle();
			}
			if (((uint)num & 0x10u) != 0)
			{
				_killingDamageType = reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class DamageDealtMessage : MessageBase
	{
		public GameObject victim;

		public float damage;

		public GameObject attacker;

		public UnityEngine.Vector3 position;

		public bool crit;

		public DamageTypeCombo damageType;

		public DamageColorIndex damageColorIndex;

		public bool hitLowHealth;

		public bool isSilent => (ulong)(damageType & DamageType.Silent) != 0;

		public override void Serialize(NetworkWriter writer)
		{
			base.Serialize(writer);
			writer.Write(victim);
			writer.Write(damage);
			writer.Write(attacker);
			writer.Write(position);
			writer.Write(crit);
			writer.WriteDamageType(damageType);
			writer.Write(damageColorIndex);
			writer.Write(hitLowHealth);
		}

		public override void Deserialize(NetworkReader reader)
		{
			base.Deserialize(reader);
			victim = reader.ReadGameObject();
			damage = reader.ReadSingle();
			attacker = reader.ReadGameObject();
			position = reader.ReadVector3();
			crit = reader.ReadBoolean();
			damageType = reader.ReadDamageType();
			damageColorIndex = reader.ReadDamageColorIndex();
			hitLowHealth = reader.ReadBoolean();
		}
	}
	public class HealthPickup : MonoBehaviour
	{
		[Tooltip("The base object to destroy when this pickup is consumed.")]
		public GameObject baseObject;

		[Tooltip("The team filter object which determines who can pick up this pack.")]
		public TeamFilter teamFilter;

		public GameObject pickupEffect;

		public float flatHealing;

		public float fractionalHealing;

		private bool alive = true;

		private void OnTriggerStay(Collider other)
		{
			if (!NetworkServer.active || !alive || TeamComponent.GetObjectTeam(other.gameObject) != teamFilter.teamIndex)
			{
				return;
			}
			CharacterBody component = other.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				HealthComponent healthComponent = component.healthComponent;
				if ((bool)healthComponent)
				{
					component.healthComponent.Heal(flatHealing + healthComponent.fullHealth * fractionalHealing, default(ProcChainMask));
					EffectManager.SpawnEffect(pickupEffect, new EffectData
					{
						origin = base.transform.position
					}, transmit: true);
				}
				UnityEngine.Object.Destroy(baseObject);
			}
		}
	}
	[RequireComponent(typeof(NetworkedBodyAttachment))]
	public class HelfireController : NetworkBehaviour
	{
		[SyncVar]
		public int stack = 1;

		[FormerlySerializedAs("radius")]
		public float baseRadius;

		public float dotDuration;

		public float interval;

		[Range(0f, 1f)]
		public float healthFractionPerSecond = 0.05f;

		public float allyDamageScalar = 0.5f;

		public float enemyDamageScalar = 24f;

		public Transform auraEffectTransform;

		private float timer;

		private float radius;

		private CameraTargetParams.AimRequest aimRequest;

		private CameraTargetParams cameraTargetParams;

		public NetworkedBodyAttachment networkedBodyAttachment { get; private set; }

		public int Networkstack
		{
			get
			{
				return stack;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref stack, 1u);
			}
		}

		private void Awake()
		{
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
			auraEffectTransform.SetParent(null);
		}

		private void OnDestroy()
		{
			if ((bool)auraEffectTransform)
			{
				UnityEngine.Object.Destroy(auraEffectTransform.gameObject);
				auraEffectTransform = null;
			}
			aimRequest?.Dispose();
		}

		private void FixedUpdate()
		{
			radius = baseRadius * (1f + (float)(stack - 1) * 0.5f);
			if (NetworkServer.active)
			{
				ServerFixedUpdate();
			}
		}

		private void ServerFixedUpdate()
		{
			timer -= Time.fixedDeltaTime;
			if (!(timer <= 0f))
			{
				return;
			}
			timer = interval;
			float num = healthFractionPerSecond * dotDuration * networkedBodyAttachment.attachedBody.healthComponent.fullCombinedHealth;
			float num2 = 1f;
			TeamDef teamDef = TeamCatalog.GetTeamDef(networkedBodyAttachment.attachedBody.teamComponent.teamIndex);
			if (teamDef != null && teamDef.friendlyFireScaling > 0f)
			{
				num2 = 1f / teamDef.friendlyFireScaling;
			}
			Collider[] colliders;
			int num3 = HGPhysics.OverlapSphere(out colliders, base.transform.position, radius, LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Collide);
			GameObject[] array = new GameObject[colliders.Length];
			int count = 0;
			for (int i = 0; i < num3; i++)
			{
				CharacterBody characterBody = Util.HurtBoxColliderToBody(colliders[i]);
				GameObject gameObject = (characterBody ? characterBody.gameObject : null);
				if (!gameObject || Array.IndexOf(array, gameObject, 0, count) != -1)
				{
					continue;
				}
				float num4 = num;
				float num5 = 1f;
				if (networkedBodyAttachment.attachedBody.teamComponent.teamIndex == characterBody.teamComponent.teamIndex)
				{
					num4 *= num2;
					num5 *= num2;
					if ((object)networkedBodyAttachment.attachedBody != characterBody)
					{
						num4 *= allyDamageScalar;
						num5 *= allyDamageScalar;
					}
				}
				else
				{
					num4 *= enemyDamageScalar;
					num5 *= enemyDamageScalar;
				}
				InflictDotInfo inflictDotInfo = default(InflictDotInfo);
				inflictDotInfo.attackerObject = networkedBodyAttachment.attachedBodyObject;
				inflictDotInfo.victimObject = gameObject;
				inflictDotInfo.totalDamage = num4;
				inflictDotInfo.damageMultiplier = num5;
				inflictDotInfo.dotIndex = DotController.DotIndex.Helfire;
				inflictDotInfo.maxStacksFromAttacker = 1u;
				InflictDotInfo dotInfo = inflictDotInfo;
				StrengthenBurnUtils.CheckDotForUpgrade(networkedBodyAttachment.attachedBody.inventory, ref dotInfo);
				DotController.InflictDot(ref dotInfo);
				array[count++] = gameObject;
			}
			HGPhysics.ReturnResults(colliders);
		}

		private void LateUpdate()
		{
			CharacterBody attachedBody = networkedBodyAttachment.attachedBody;
			if ((bool)attachedBody)
			{
				auraEffectTransform.position = networkedBodyAttachment.attachedBody.corePosition;
				auraEffectTransform.localScale = new UnityEngine.Vector3(radius, radius, radius);
				if (!cameraTargetParams)
				{
					cameraTargetParams = attachedBody.GetComponent<CameraTargetParams>();
				}
				else if (aimRequest == null)
				{
					aimRequest = cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)stack);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)stack);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				stack = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				stack = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class Highlight : MonoBehaviour
	{
		public enum HighlightColor
		{
			interactive,
			teleporter,
			pickup,
			custom,
			unavailable
		}

		private static List<Highlight> highlightList = new List<Highlight>();

		private static ReadOnlyCollection<Highlight> _readonlyHighlightList = new ReadOnlyCollection<Highlight>(highlightList);

		private IDisplayNameProvider displayNameProvider;

		[HideInInspector]
		public PickupIndex pickupIndex;

		public Renderer targetRenderer;

		public float strength = 1f;

		public HighlightColor highlightColor;

		public UnityEngine.Color CustomColor = UnityEngine.Color.magenta;

		public bool isOn;

		public static ReadOnlyCollection<Highlight> readonlyHighlightList => _readonlyHighlightList;

		private void Awake()
		{
			displayNameProvider = GetComponent<IDisplayNameProvider>();
		}

		private void RemoveHighlightIfInactive()
		{
			if (targetRenderer != null && !targetRenderer.gameObject.activeInHierarchy && highlightList.Contains(this))
			{
				highlightList.Remove(this);
			}
		}

		public UnityEngine.Color GetColor()
		{
			return highlightColor switch
			{
				HighlightColor.interactive => ColorCatalog.GetColor(ColorCatalog.ColorIndex.Interactable), 
				HighlightColor.teleporter => ColorCatalog.GetColor(ColorCatalog.ColorIndex.Teleporter), 
				HighlightColor.pickup => PickupCatalog.GetPickupDef(pickupIndex)?.baseColor ?? PickupCatalog.invalidPickupColor, 
				HighlightColor.custom => CustomColor, 
				_ => UnityEngine.Color.magenta, 
			};
		}

		private void Update()
		{
			RemoveHighlightIfInactive();
		}

		public void OnDisable()
		{
			highlightList.Remove(this);
		}

		public void OnEnable()
		{
			highlightList.Add(this);
		}

		public void ResetHighlight()
		{
		}
	}
	public class HitBox : MonoBehaviour
	{
	}
	public class HitBoxGroup : MonoBehaviour
	{
		[Tooltip("The name of this hitbox group.")]
		public string groupName;

		[Tooltip("The hitbox objects in this group.")]
		public HitBox[] hitBoxes;

		public static HitBoxGroup FindByGroupName(GameObject gameObject, string groupName)
		{
			List<HitBoxGroup> gameObjectComponents = GetComponentsCache<HitBoxGroup>.GetGameObjectComponents(gameObject);
			HitBoxGroup result = null;
			int i = 0;
			for (int count = gameObjectComponents.Count; i < count; i++)
			{
				if (string.CompareOrdinal(groupName, gameObjectComponents[i].groupName) == 0)
				{
					result = gameObjectComponents[i];
					break;
				}
			}
			GetComponentsCache<HitBoxGroup>.ReturnBuffer(gameObjectComponents);
			return result;
		}
	}
	public class HoldoutZoneController : BaseZoneBehavior
	{
		public enum HoldoutZoneShape
		{
			Sphere,
			VerticalTube,
			Count
		}

		public delegate void CalcRadiusDelegate(ref float radius);

		public delegate void CalcChargeRateDelegate(ref float rate);

		public delegate void CalcAccumulatedChargeDelegate(ref float charge);

		public delegate void CalcColorDelegate(ref UnityEngine.Color color);

		[Serializable]
		public class HoldoutZoneControllerChargedUnityEvent : UnityEvent<HoldoutZoneController>
		{
		}

		private class ChargeHoldoutZoneObjectiveTracker : ObjectivePanelController.ObjectiveTracker
		{
			private int lastPercent = -1;

			private HoldoutZoneController holdoutZoneController => (HoldoutZoneController)sourceDescriptor.source;

			private bool ShouldBeFlashing()
			{
				bool flag = true;
				if ((bool)sourceDescriptor.master && (bool)holdoutZoneController)
				{
					flag = holdoutZoneController.IsBodyInChargingRadius(sourceDescriptor.master.GetBody());
				}
				return !flag;
			}

			protected override string GenerateString()
			{
				lastPercent = holdoutZoneController.displayChargePercent;
				string text = string.Format(Language.GetString(holdoutZoneController.inBoundsObjectiveToken), lastPercent);
				if (ShouldBeFlashing())
				{
					text = string.Format(Language.GetString(holdoutZoneController.outOfBoundsObjectiveToken), lastPercent);
					if ((int)(Time.time * 12f) % 2 == 0)
					{
						text = $"<style=cDeath>{text}</style>";
					}
				}
				return text;
			}

			protected override bool IsDirty()
			{
				return true;
			}
		}

		private class FocusConvergenceController : MonoBehaviour
		{
			private static readonly float convergenceRadiusDivisor = 2f;

			private static readonly float convergenceChargeRateBonus = 0.3f;

			private static readonly UnityEngine.Color convergenceMaterialColor = new UnityEngine.Color(0f, 3.9411764f, 5f, 1f);

			private static readonly float rampUpTime = 5f;

			private static readonly float startupDelay = 3f;

			private static readonly int cap = 3;

			private float currentValue;

			private HoldoutZoneController holdoutZoneController;

			private int currentFocusConvergenceCount;

			private Run.FixedTimeStamp enabledTime;

			private static readonly AnimationCurve colorCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);

			private void Awake()
			{
				holdoutZoneController = GetComponent<HoldoutZoneController>();
			}

			private void OnEnable()
			{
				enabledTime = Run.FixedTimeStamp.now;
				holdoutZoneController.calcRadius += ApplyRadius;
				holdoutZoneController.calcChargeRate += ApplyRate;
				holdoutZoneController.calcColor += ApplyColor;
			}

			private void OnDisable()
			{
				holdoutZoneController.calcColor -= ApplyColor;
				holdoutZoneController.calcChargeRate -= ApplyRate;
				holdoutZoneController.calcRadius -= ApplyRadius;
			}

			private void ApplyRadius(ref float radius)
			{
				if (currentFocusConvergenceCount > 0)
				{
					radius /= convergenceRadiusDivisor * (float)currentFocusConvergenceCount;
				}
			}

			private void ApplyColor(ref UnityEngine.Color color)
			{
				color = UnityEngine.Color.Lerp(color, convergenceMaterialColor, colorCurve.Evaluate(currentValue));
			}

			private void ApplyRate(ref float rate)
			{
				if (currentFocusConvergenceCount > 0)
				{
					rate *= 1f + convergenceChargeRateBonus * (float)currentFocusConvergenceCount;
				}
			}

			private void Update()
			{
				DoUpdate(Time.deltaTime);
			}

			private void DoUpdate(float deltaTime)
			{
				currentFocusConvergenceCount = Util.GetItemCountForTeam(holdoutZoneController.chargingTeam, RoR2Content.Items.FocusConvergence.itemIndex, requiresAlive: true, requiresConnected: false);
				if (enabledTime.timeSince < startupDelay)
				{
					currentFocusConvergenceCount = 0;
				}
				currentFocusConvergenceCount = Mathf.Min(currentFocusConvergenceCount, cap);
				float target = (((float)currentFocusConvergenceCount > 0f) ? 1f : 0f);
				float num = Mathf.MoveTowards(currentValue, target, rampUpTime * deltaTime);
				if (currentValue <= 0f && num > 0f)
				{
					Util.PlaySound("Play_item_lunar_focusedConvergence", base.gameObject);
				}
				currentValue = num;
			}
		}

		public HoldoutZoneShape holdoutZoneShape;

		[Tooltip("The base radius of this charging sphere. Players must be within this radius to charge this zone.")]
		public float baseRadius;

		[Tooltip("No modifiers can reduce the radius below this size")]
		public float minimumRadius;

		[Tooltip("The overall change to the radius from 0% charge to 100% charge.")]
		public float chargeRadiusDelta;

		[Tooltip("How long it takes for this zone to finish charging without any modifiers.")]
		public float baseChargeDuration;

		[Tooltip("Approximately how long it should take to change from any given radius to the desired one.")]
		public float radiusSmoothTime;

		[Tooltip("An object instance which will be used to represent the clear radius.")]
		public Renderer radiusIndicator;

		[Tooltip("The child object to enable when healing nova should be active.")]
		public GameObject healingNovaItemEffect;

		public Transform healingNovaRoot;

		public string inBoundsObjectiveToken = "OBJECTIVE_CHARGE_TELEPORTER";

		public string outOfBoundsObjectiveToken = "OBJECTIVE_CHARGE_TELEPORTER_OOB";

		public bool showObjective = true;

		public bool applyFocusConvergence;

		public bool applyHealingNova = true;

		public bool applyDevotedEvolution;

		public bool applyDelusionResetChests;

		[Range(0f, float.MaxValue)]
		public float playerCountScaling = 1f;

		[Tooltip("If the zone is empty, this is the rate at which the charge decreases (a negative value will increase charge)")]
		public float dischargeRate;

		public HoldoutZoneControllerChargedUnityEvent onCharged;

		private BuffWard buffWard;

		private static MaterialPropertyBlock sharedColorPropertyBlock;

		private UnityEngine.Color baseIndicatorColor;

		private float radiusVelocity;

		private bool wasCharged;

		private GameObject[] healingNovaGeneratorsByTeam = new GameObject[5];

		[SyncVar]
		private float _charge;

		public float currentRadius { get; private set; }

		public bool isAnyoneCharging { get; private set; }

		public TeamIndex chargingTeam { get; set; } = TeamIndex.Player;


		public int displayChargePercent => Mathf.Clamp(Mathf.FloorToInt(charge * 99f), 0, 99);

		public float charge
		{
			get
			{
				return _charge;
			}
			private set
			{
				Network_charge = value;
			}
		}

		public float Network_charge
		{
			get
			{
				return _charge;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _charge, 1u);
			}
		}

		public event CalcRadiusDelegate calcRadius;

		public event CalcChargeRateDelegate calcChargeRate;

		public event CalcAccumulatedChargeDelegate calcAccumulatedCharge;

		public event CalcColorDelegate calcColor;

		[InitDuringStartup]
		private static void Init()
		{
			sharedColorPropertyBlock = new MaterialPropertyBlock();
			ObjectivePanelController.collectObjectiveSources += OnCollectObjectiveSources;
		}

		private void Awake()
		{
			if ((bool)radiusIndicator)
			{
				baseIndicatorColor = radiusIndicator.sharedMaterial.GetColor("_TintColor");
			}
			buffWard = GetComponent<BuffWard>();
		}

		private void Start()
		{
			if (applyFocusConvergence)
			{
				base.gameObject.AddComponent<FocusConvergenceController>();
			}
		}

		private void OnEnable()
		{
			if ((bool)radiusIndicator)
			{
				radiusIndicator.enabled = true;
				radiusIndicator.gameObject.SetActive(value: true);
			}
			currentRadius = 0f;
			InstanceTracker.Add(this);
		}

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
			currentRadius = 0f;
			if ((bool)radiusIndicator)
			{
				radiusIndicator.enabled = false;
				radiusIndicator.gameObject.SetActive(value: false);
			}
		}

		private void UpdateHealingNovas(bool isCharging)
		{
			if (!applyHealingNova)
			{
				return;
			}
			bool flag = false;
			for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
			{
				bool flag2 = Util.GetItemCountForTeam(teamIndex, RoR2Content.Items.TPHealingNova.itemIndex, requiresAlive: false) > 0 && isCharging;
				flag = flag || flag2;
				if (NetworkServer.active)
				{
					ref GameObject reference = ref healingNovaGeneratorsByTeam[(int)teamIndex];
					if (flag2 != (bool)reference)
					{
						if (flag2)
						{
							reference = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/TeleporterHealNovaGenerator"), healingNovaRoot ?? base.transform);
							reference.GetComponent<TeamFilter>().teamIndex = teamIndex;
							NetworkServer.Spawn(reference);
						}
						else
						{
							UnityEngine.Object.Destroy(reference);
							reference = null;
						}
					}
				}
			}
			if ((bool)healingNovaItemEffect)
			{
				healingNovaItemEffect.SetActive(flag);
			}
		}

		private void Update()
		{
			DoUpdate(Time.deltaTime);
		}

		private void DoUpdate(float deltaTime)
		{
			int num = CountLivingPlayers(chargingTeam);
			int num2 = CountPlayersInRadius(this, base.transform.position, currentRadius * currentRadius, chargingTeam);
			isAnyoneCharging = num2 > 0;
			if ((bool)Run.instance)
			{
				float radius = baseRadius + charge * chargeRadiusDelta;
				if (Run.instance.selectedDifficulty >= DifficultyIndex.Eclipse2)
				{
					radius *= 0.5f;
				}
				this.calcRadius?.Invoke(ref radius);
				currentRadius = Mathf.Max(Mathf.SmoothDamp(currentRadius, radius, ref radiusVelocity, radiusSmoothTime, float.PositiveInfinity, deltaTime), minimumRadius);
			}
			if ((bool)radiusIndicator)
			{
				float num3 = 2f * currentRadius;
				radiusIndicator.transform.localScale = new UnityEngine.Vector3(num3, num3, num3);
			}
			if (NetworkServer.active && (bool)buffWard)
			{
				buffWard.Networkradius = currentRadius;
			}
			if (NetworkServer.active)
			{
				float num4 = baseChargeDuration;
				float rate = ((!isAnyoneCharging || num <= 0) ? (0f - dischargeRate) : (Mathf.Pow((float)num2 / (float)num, playerCountScaling) / num4));
				this.calcChargeRate?.Invoke(ref rate);
				charge = Mathf.Clamp01(charge + rate * deltaTime);
				float num5 = charge;
				this.calcAccumulatedCharge?.Invoke(ref num5);
				charge = num5;
			}
			UnityEngine.Color color = baseIndicatorColor;
			this.calcColor?.Invoke(ref color);
			sharedColorPropertyBlock.SetColor("_TintColor", color);
			if ((bool)radiusIndicator)
			{
				radiusIndicator.SetPropertyBlock(sharedColorPropertyBlock);
			}
			bool flag = charge >= 1f;
			if (wasCharged != flag)
			{
				wasCharged = flag;
				if (flag)
				{
					onCharged?.Invoke(this);
					if (applyDevotedEvolution)
					{
						UpdateDevotedLumerains(chargingTeam);
					}
					if (applyDelusionResetChests && RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion))
					{
						foreach (ChestBehavior instances in InstanceTracker.GetInstancesList<ChestBehavior>())
						{
							instances.CallRpcResetChests();
						}
					}
				}
			}
			UpdateHealingNovas(isAnyoneCharging);
		}

		private void OnDrawGizmos()
		{
			UnityEngine.Matrix4x4 matrix = Gizmos.matrix;
			UnityEngine.Color color = Gizmos.color;
			Gizmos.matrix = base.transform.localToWorldMatrix;
			Gizmos.color = new UnityEngine.Color(0.75f, 0f, 0f, 0.5f);
			Gizmos.DrawWireSphere(UnityEngine.Vector3.zero, baseRadius);
			Gizmos.color = color;
			Gizmos.matrix = matrix;
		}

		private static bool IsPointInChargingRadius(HoldoutZoneController holdoutZoneController, UnityEngine.Vector3 origin, float chargingRadiusSqr, UnityEngine.Vector3 point)
		{
			switch (holdoutZoneController.holdoutZoneShape)
			{
			case HoldoutZoneShape.Sphere:
				if ((point - origin).sqrMagnitude <= chargingRadiusSqr)
				{
					return true;
				}
				break;
			case HoldoutZoneShape.VerticalTube:
				point.y = 0f;
				origin.y = 0f;
				if ((point - origin).sqrMagnitude <= chargingRadiusSqr)
				{
					return true;
				}
				break;
			}
			return false;
		}

		private static bool IsBodyInChargingRadius(HoldoutZoneController holdoutZoneController, UnityEngine.Vector3 origin, float chargingRadiusSqr, CharacterBody characterBody)
		{
			return IsPointInChargingRadius(holdoutZoneController, origin, chargingRadiusSqr, characterBody.corePosition);
		}

		private static int CountLivingPlayers(TeamIndex teamIndex)
		{
			int num = 0;
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				if (teamMembers[i].body.isPlayerControlled)
				{
					num++;
				}
			}
			return num;
		}

		public static int CountPlayersInRadius(HoldoutZoneController holdoutZoneController, UnityEngine.Vector3 origin, float chargingRadiusSqr, TeamIndex teamIndex)
		{
			int num = 0;
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				TeamComponent teamComponent = teamMembers[i];
				if (teamComponent.body.isPlayerControlled && IsBodyInChargingRadius(holdoutZoneController, origin, chargingRadiusSqr, teamComponent.body))
				{
					num++;
				}
			}
			return num;
		}

		public bool IsBodyInChargingRadius(CharacterBody body)
		{
			if (!body)
			{
				return false;
			}
			return IsBodyInChargingRadius(this, base.transform.position, currentRadius * currentRadius, body);
		}

		[Server]
		public void FullyChargeHoldoutZone()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HoldoutZoneController::FullyChargeHoldoutZone()' called on client");
			}
			else
			{
				charge = 1f;
			}
		}

		private static void OnCollectObjectiveSources(CharacterMaster master, List<ObjectivePanelController.ObjectiveSourceDescriptor> objectiveSourcesList)
		{
			List<HoldoutZoneController> instancesList = InstanceTracker.GetInstancesList<HoldoutZoneController>();
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				HoldoutZoneController holdoutZoneController = instancesList[i];
				if (holdoutZoneController.showObjective && holdoutZoneController.chargingTeam == master.teamIndex)
				{
					objectiveSourcesList.Add(new ObjectivePanelController.ObjectiveSourceDescriptor
					{
						master = master,
						objectiveType = typeof(ChargeHoldoutZoneObjectiveTracker),
						source = holdoutZoneController
					});
				}
			}
		}

		public override bool IsInBounds(UnityEngine.Vector3 position)
		{
			return IsPointInChargingRadius(this, base.transform.position, currentRadius * currentRadius, position);
		}

		private void UpdateDevotedLumerains(TeamIndex teamIndex)
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				TeamComponent teamComponent = teamMembers[i];
				if (teamComponent.body.isPlayerControlled && (bool)teamComponent.body.master.devotionInventoryPrefab)
				{
					teamComponent.body.master.devotionInventoryPrefab.GetComponent<DevotionInventoryController>().ActivateDevotedEvolution();
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			if (forceAll)
			{
				writer.Write(_charge);
				return true;
			}
			bool flag2 = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag2)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag2 = true;
				}
				writer.Write(_charge);
			}
			if (!flag2)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
			if (initialState)
			{
				_charge = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_charge = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[RequireComponent(typeof(PostProcessVolume))]
	public class HookLightingIntoPostProcessVolume : MonoBehaviour
	{
		[Header("Required Values")]
		public PostProcessVolume volume;

		[ColorUsage(true, true)]
		public UnityEngine.Color overrideAmbientColor;

		[Header("Optional Values")]
		public Light directionalLight;

		public UnityEngine.Color overrideDirectionalColor;

		public ParticleSystem particleSystem;

		public float overrideParticleSystemMultiplier;

		private Collider[] volumeColliders;

		private UnityEngine.Color defaultAmbientColor;

		private UnityEngine.Color defaultDirectionalColor;

		private float defaultParticleSystemMultiplier;

		private bool hasCachedInitialValues;

		private void OnEnable()
		{
			volumeColliders = GetComponents<Collider>();
			if (!hasCachedInitialValues)
			{
				defaultAmbientColor = RenderSettings.ambientLight;
				if ((bool)directionalLight)
				{
					defaultDirectionalColor = directionalLight.color;
				}
				if ((bool)particleSystem)
				{
					defaultParticleSystemMultiplier = particleSystem.emission.rateOverTimeMultiplier;
				}
				hasCachedInitialValues = true;
			}
			SceneCamera.onSceneCameraPreRender += OnPreRenderSceneCam;
		}

		private void OnDisable()
		{
			SceneCamera.onSceneCameraPreRender -= OnPreRenderSceneCam;
		}

		private void OnPreRenderSceneCam(SceneCamera sceneCam)
		{
			float interpFactor = GetInterpFactor(sceneCam.camera.transform.position);
			RenderSettings.ambientLight = UnityEngine.Color.Lerp(defaultAmbientColor, overrideAmbientColor, interpFactor);
			if ((bool)directionalLight)
			{
				directionalLight.color = UnityEngine.Color.Lerp(defaultDirectionalColor, overrideDirectionalColor, interpFactor);
			}
			if ((bool)particleSystem)
			{
				ParticleSystem.EmissionModule emission = particleSystem.emission;
				emission.rateOverTimeMultiplier = Mathf.Lerp(defaultParticleSystemMultiplier, overrideParticleSystemMultiplier, interpFactor);
			}
		}

		private float GetInterpFactor(UnityEngine.Vector3 triggerPos)
		{
			if (!volume.enabled || volume.weight <= 0f)
			{
				return 0f;
			}
			if (volume.isGlobal)
			{
				return 1f;
			}
			float num = 0f;
			Collider[] array = volumeColliders;
			foreach (Collider collider in array)
			{
				float num2 = float.PositiveInfinity;
				if (collider.enabled)
				{
					float sqrMagnitude = ((collider.ClosestPoint(triggerPos) - triggerPos) / 2f).sqrMagnitude;
					if (sqrMagnitude < num2)
					{
						num2 = sqrMagnitude;
					}
					float num3 = volume.blendDistance * volume.blendDistance;
					if (!(num2 > num3) && num3 > 0f)
					{
						num = Mathf.Max(num, 1f - num2 / num3);
					}
				}
			}
			return num;
		}
	}
	public class HoverEngine : MonoBehaviour
	{
		public Rigidbody engineRigidbody;

		public Transform wheelVisual;

		public float hoverForce = 65f;

		public float hoverHeight = 3.5f;

		public float hoverDamping = 0.1f;

		public float hoverRadius;

		[HideInInspector]
		public float forceStrength;

		private Ray castRay;

		private UnityEngine.Vector3 castPosition;

		[HideInInspector]
		public RaycastHit raycastHit;

		public float compression;

		public UnityEngine.Vector3 offsetVector = UnityEngine.Vector3.zero;

		public bool isGrounded;

		private void OnDrawGizmos()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			Gizmos.DrawWireSphere(base.transform.TransformPoint(offsetVector), hoverRadius);
			Gizmos.DrawRay(castRay);
			if (isGrounded)
			{
				Gizmos.DrawSphere(raycastHit.point, hoverRadius);
			}
		}

		private void FixedUpdate()
		{
			float num = Mathf.Clamp01(UnityEngine.Vector3.Dot(-base.transform.up, UnityEngine.Vector3.down));
			castPosition = base.transform.TransformPoint(offsetVector);
			castRay = new Ray(castPosition, -base.transform.up);
			isGrounded = false;
			forceStrength = 0f;
			compression = 0f;
			UnityEngine.Vector3 position = castRay.origin + castRay.direction * hoverHeight;
			if (Physics.SphereCast(castRay, hoverRadius, out raycastHit, hoverHeight, LayerIndex.world.mask))
			{
				isGrounded = true;
				float num2 = (hoverHeight - raycastHit.distance) / hoverHeight;
				UnityEngine.Vector3 vector = UnityEngine.Vector3.up * (num2 * hoverForce);
				UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Project(engineRigidbody.GetPointVelocity(castPosition), -base.transform.up) * hoverDamping;
				forceStrength = (vector - vector2).magnitude;
				engineRigidbody.AddForceAtPosition(UnityEngine.Vector3.Project(vector - vector2, -base.transform.up), castPosition, ForceMode.Acceleration);
				compression = Mathf.Clamp01(num2 * num);
				position = raycastHit.point;
			}
			wheelVisual.position = position;
			_ = isGrounded;
		}
	}
	public class HoverEngineDisplay : MonoBehaviour
	{
		public HoverEngine hoverEngine;

		[Tooltip("The local pitch at zero engine strength")]
		public float minPitch = -20f;

		[Tooltip("The local pitch at max engine strength")]
		public float maxPitch = 60f;

		public float smoothTime = 0.2f;

		public float forceScale = 1f;

		private float smoothVelocity;

		private void FixedUpdate()
		{
			UnityEngine.Vector3 localEulerAngles = base.transform.localEulerAngles;
			float x = Mathf.SmoothDampAngle(target: Mathf.LerpAngle(t: Mathf.Clamp01(hoverEngine.forceStrength / hoverEngine.hoverForce * forceScale), a: minPitch, b: maxPitch), current: localEulerAngles.x, currentVelocity: ref smoothVelocity, smoothTime: smoothTime);
			base.transform.localRotation = UnityEngine.Quaternion.Euler(x, 0f, 0f);
		}
	}
	[RequireComponent(typeof(Rigidbody))]
	public class HoverVehicleMotor : MonoBehaviour
	{
		private enum WheelLateralAxis
		{
			Left,
			Right
		}

		public enum WheelLongitudinalAxis
		{
			Front,
			Back
		}

		[Serializable]
		public struct AxleGroup
		{
			public HoverEngine leftWheel;

			public HoverEngine rightWheel;

			public WheelLongitudinalAxis wheelLongitudinalAxis;

			public bool isDriven;

			public AnimationCurve slidingTractionCurve;
		}

		[HideInInspector]
		public UnityEngine.Vector3 targetSteerVector;

		public UnityEngine.Vector3 centerOfMassOffset;

		public AxleGroup[] staticAxles;

		public AxleGroup[] steerAxles;

		public float wheelWellDepth;

		public float wheelBase;

		public float trackWidth;

		public float rollingFrictionCoefficient;

		public float slidingTractionCoefficient;

		public float motorForce;

		public float maxSteerAngle;

		public float maxTurningRadius;

		public float hoverForce = 33f;

		public float hoverHeight = 2f;

		public float hoverDamping = 0.5f;

		public float hoverRadius = 0.5f;

		public UnityEngine.Vector3 hoverOffsetVector = UnityEngine.Vector3.up;

		private InputBankTest inputBank;

		private UnityEngine.Vector3 steerVector = UnityEngine.Vector3.forward;

		private Rigidbody rigidbody;

		private void Start()
		{
			inputBank = GetComponent<InputBankTest>();
			rigidbody = GetComponent<Rigidbody>();
		}

		private void ApplyWheelForces(HoverEngine wheel, float gas, bool driveWheel, AnimationCurve slidingWheelTractionCurve)
		{
			if (wheel.isGrounded)
			{
				float num = 0.005f;
				Transform transform = wheel.transform;
				float num2 = 1f;
				UnityEngine.Vector3 position = transform.position;
				UnityEngine.Vector3 pointVelocity = rigidbody.GetPointVelocity(position);
				UnityEngine.Vector3 vector = UnityEngine.Vector3.Project(pointVelocity, transform.right);
				UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Project(pointVelocity, transform.forward);
				UnityEngine.Vector3 up = UnityEngine.Vector3.up;
				UnityEngine.Debug.DrawRay(position, pointVelocity, UnityEngine.Color.blue);
				UnityEngine.Vector3 vector3 = UnityEngine.Vector3.zero;
				if (driveWheel)
				{
					vector3 = transform.forward * gas * motorForce;
					rigidbody.AddForceAtPosition(transform.forward * gas * motorForce * num2, position);
					UnityEngine.Debug.DrawRay(position, vector3 * num, UnityEngine.Color.yellow);
				}
				UnityEngine.Vector3 vector4 = UnityEngine.Vector3.ProjectOnPlane(-vector2 * rollingFrictionCoefficient * num2, up);
				rigidbody.AddForceAtPosition(vector4, position);
				UnityEngine.Debug.DrawRay(position, vector4 * num, UnityEngine.Color.red);
				UnityEngine.Vector3 vector5 = UnityEngine.Vector3.ProjectOnPlane(-vector * slidingWheelTractionCurve.Evaluate(pointVelocity.magnitude) * slidingTractionCoefficient * num2, up);
				rigidbody.AddForceAtPosition(vector5, position);
				UnityEngine.Debug.DrawRay(position, vector5 * num, UnityEngine.Color.red);
				UnityEngine.Debug.DrawRay(position, (vector3 + vector4 + vector5) * num, UnityEngine.Color.green);
			}
		}

		private void UpdateCenterOfMass()
		{
			rigidbody.ResetCenterOfMass();
			rigidbody.centerOfMass += centerOfMassOffset;
		}

		private void UpdateWheelParameter(HoverEngine wheel, WheelLateralAxis wheelLateralAxis, WheelLongitudinalAxis wheelLongitudinalAxis)
		{
			wheel.hoverForce = hoverForce;
			wheel.hoverDamping = hoverDamping;
			wheel.hoverHeight = hoverHeight;
			wheel.offsetVector = hoverOffsetVector;
			wheel.hoverRadius = hoverRadius;
			UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
			zero.y = 0f - wheelWellDepth;
			switch (wheelLateralAxis)
			{
			case WheelLateralAxis.Left:
				zero.x = (0f - trackWidth) / 2f;
				break;
			case WheelLateralAxis.Right:
				zero.x = trackWidth / 2f;
				break;
			}
			switch (wheelLongitudinalAxis)
			{
			case WheelLongitudinalAxis.Front:
				zero.z = wheelBase / 2f;
				break;
			case WheelLongitudinalAxis.Back:
				zero.z = (0f - wheelBase) / 2f;
				break;
			}
			wheel.transform.localPosition = zero;
		}

		private void UpdateAllWheelParameters()
		{
			AxleGroup[] array = staticAxles;
			for (int i = 0; i < array.Length; i++)
			{
				AxleGroup axleGroup = array[i];
				HoverEngine leftWheel = axleGroup.leftWheel;
				HoverEngine rightWheel = axleGroup.rightWheel;
				UpdateWheelParameter(leftWheel, WheelLateralAxis.Left, axleGroup.wheelLongitudinalAxis);
				UpdateWheelParameter(rightWheel, WheelLateralAxis.Right, axleGroup.wheelLongitudinalAxis);
			}
			array = steerAxles;
			for (int i = 0; i < array.Length; i++)
			{
				AxleGroup axleGroup2 = array[i];
				HoverEngine leftWheel2 = axleGroup2.leftWheel;
				HoverEngine rightWheel2 = axleGroup2.rightWheel;
				UpdateWheelParameter(leftWheel2, WheelLateralAxis.Left, axleGroup2.wheelLongitudinalAxis);
				UpdateWheelParameter(rightWheel2, WheelLateralAxis.Right, axleGroup2.wheelLongitudinalAxis);
			}
		}

		private void FixedUpdate()
		{
			UpdateCenterOfMass();
			UpdateAllWheelParameters();
			if (!inputBank)
			{
				return;
			}
			UnityEngine.Vector3 moveVector = inputBank.moveVector;
			UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(inputBank.aimDirection, base.transform.up).normalized;
			float num = Mathf.Clamp(Util.AngleSigned(base.transform.forward, normalized, base.transform.up), 0f - maxSteerAngle, maxSteerAngle);
			float magnitude = moveVector.magnitude;
			AxleGroup[] array = staticAxles;
			for (int i = 0; i < array.Length; i++)
			{
				AxleGroup axleGroup = array[i];
				HoverEngine leftWheel = axleGroup.leftWheel;
				HoverEngine rightWheel = axleGroup.rightWheel;
				ApplyWheelForces(leftWheel, magnitude, axleGroup.isDriven, axleGroup.slidingTractionCurve);
				ApplyWheelForces(rightWheel, magnitude, axleGroup.isDriven, axleGroup.slidingTractionCurve);
			}
			array = steerAxles;
			for (int i = 0; i < array.Length; i++)
			{
				AxleGroup axleGroup2 = array[i];
				HoverEngine leftWheel2 = axleGroup2.leftWheel;
				HoverEngine rightWheel2 = axleGroup2.rightWheel;
				float num2 = maxTurningRadius / Mathf.Abs(num / maxSteerAngle);
				float num3 = Mathf.Atan(wheelBase / (num2 - trackWidth / 2f)) * 57.29578f;
				float num4 = Mathf.Atan(wheelBase / (num2 + trackWidth / 2f)) * 57.29578f;
				UnityEngine.Quaternion localRotation = UnityEngine.Quaternion.Euler(0f, num3 * Mathf.Sign(num), 0f);
				UnityEngine.Quaternion localRotation2 = UnityEngine.Quaternion.Euler(0f, num4 * Mathf.Sign(num), 0f);
				if (num <= 0f)
				{
					leftWheel2.transform.localRotation = localRotation;
					rightWheel2.transform.localRotation = localRotation2;
				}
				else
				{
					leftWheel2.transform.localRotation = localRotation2;
					rightWheel2.transform.localRotation = localRotation;
				}
				ApplyWheelForces(leftWheel2, magnitude, axleGroup2.isDriven, axleGroup2.slidingTractionCurve);
				ApplyWheelForces(rightWheel2, magnitude, axleGroup2.isDriven, axleGroup2.slidingTractionCurve);
			}
			UnityEngine.Debug.DrawRay(base.transform.position, normalized * 5f, UnityEngine.Color.blue);
		}

		private void OnDrawGizmos()
		{
			if ((bool)rigidbody)
			{
				Gizmos.color = UnityEngine.Color.red;
				Gizmos.DrawSphere(base.transform.TransformPoint(rigidbody.centerOfMass), 0.3f);
			}
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	[RequireComponent(typeof(TeamComponent))]
	[RequireComponent(typeof(InputBankTest))]
	public class HuntressTracker : MonoBehaviour
	{
		public GameObject trackingPrefab;

		public float maxTrackingDistance = 20f;

		public float maxTrackingAngle = 20f;

		public float trackerUpdateFrequency = 10f;

		private HurtBox trackingTarget;

		private CharacterBody characterBody;

		private TeamComponent teamComponent;

		private InputBankTest inputBank;

		private float trackerUpdateStopwatch;

		private Indicator indicator;

		private readonly BullseyeSearch search = new BullseyeSearch();

		private void Awake()
		{
			if (trackingPrefab == null)
			{
				trackingPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/HuntressTrackingIndicator");
			}
			indicator = new Indicator(base.gameObject, trackingPrefab);
		}

		private void Start()
		{
			characterBody = GetComponent<CharacterBody>();
			inputBank = GetComponent<InputBankTest>();
			teamComponent = GetComponent<TeamComponent>();
		}

		public HurtBox GetTrackingTarget()
		{
			return trackingTarget;
		}

		private void OnEnable()
		{
			indicator.active = true;
		}

		private void OnDisable()
		{
			indicator.active = false;
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.fixedDeltaTime);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			trackerUpdateStopwatch += deltaTime;
			if (trackerUpdateStopwatch >= 1f / trackerUpdateFrequency)
			{
				trackerUpdateStopwatch -= 1f / trackerUpdateFrequency;
				_ = trackingTarget;
				Ray aimRay = new Ray(inputBank.aimOrigin, inputBank.aimDirection);
				SearchForTarget(aimRay);
				indicator.targetTransform = (trackingTarget ? trackingTarget.transform : null);
			}
		}

		private void SearchForTarget(Ray aimRay)
		{
			search.teamMaskFilter = TeamMask.all;
			search.teamMaskFilter.RemoveTeam(teamComponent.teamIndex);
			search.filterByLoS = true;
			search.searchOrigin = aimRay.origin;
			search.searchDirection = aimRay.direction;
			search.sortMode = BullseyeSearch.SortMode.Distance;
			search.maxDistanceFilter = maxTrackingDistance;
			search.maxAngleFilter = maxTrackingAngle;
			search.RefreshCandidates();
			search.FilterOutGameObject(base.gameObject);
			trackingTarget = search.GetResults().FirstOrDefault();
		}
	}
	[RequireComponent(typeof(Collider))]
	public class HurtBox : MonoBehaviour
	{
		public enum DamageModifier
		{
			Normal,
			[Obsolete]
			SniperTarget,
			Weak,
			Barrier
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		public struct EntityEqualityComparer : IEqualityComparer<HurtBox>
		{
			public bool Equals(HurtBox a, HurtBox b)
			{
				return HurtBoxesShareEntity(a, b);
			}

			public int GetHashCode(HurtBox hurtBox)
			{
				return FindEntityObject(hurtBox).GetHashCode();
			}
		}

		[Tooltip("The health component to which this hurtbox belongs.")]
		public HealthComponent healthComponent;

		[Tooltip("Whether or not this hurtbox is considered a bullseye. Do not change this at runtime!")]
		public bool isBullseye;

		[Tooltip("Whether or not this hurtbox is considered a sniper target. Do not change this at runtime!")]
		public bool isSniperTarget;

		public DamageModifier damageModifier;

		[SerializeField]
		[HideInInspector]
		public HurtBoxGroup hurtBoxGroup;

		[SerializeField]
		[HideInInspector]
		public short indexInGroup = -1;

		private bool isInBullseyeList;

		private bool isInSniperTargetList;

		private static readonly List<HurtBox> bullseyesList = new List<HurtBox>();

		public static readonly ReadOnlyCollection<HurtBox> readOnlyBullseyesList = bullseyesList.AsReadOnly();

		private static readonly List<HurtBox> sniperTargetsList = new List<HurtBox>();

		public static readonly float sniperTargetRadius = 1f;

		public static readonly float sniperTargetRadiusSqr = sniperTargetRadius * sniperTargetRadius;

		public TeamIndex teamIndex { get; set; } = TeamIndex.None;


		public Collider collider { get; private set; }

		public float volume { get; private set; }

		public UnityEngine.Vector3 randomVolumePoint => Util.RandomColliderVolumePoint(collider);

		public static IReadOnlyList<HurtBox> readOnlySniperTargetsList => sniperTargetsList;

		private void Awake()
		{
			collider = GetComponent<Collider>();
			collider.isTrigger = false;
			Rigidbody rigidbody = GetComponent<Rigidbody>();
			if (!rigidbody)
			{
				rigidbody = base.gameObject.AddComponent<Rigidbody>();
			}
			rigidbody.isKinematic = true;
			UnityEngine.Vector3 lossyScale = base.transform.lossyScale;
			volume = lossyScale.x * 2f * (lossyScale.y * 2f) * (lossyScale.z * 2f);
		}

		private void OnEnable()
		{
			if (isBullseye)
			{
				bullseyesList.Add(this);
				isInBullseyeList = true;
			}
			if (isSniperTarget)
			{
				sniperTargetsList.Add(this);
				isInSniperTargetList = true;
			}
		}

		private void OnDisable()
		{
			if (isInSniperTargetList)
			{
				isInSniperTargetList = false;
				sniperTargetsList.Remove(this);
			}
			if (isInBullseyeList)
			{
				isInBullseyeList = false;
				bullseyesList.Remove(this);
			}
		}

		public static GameObject FindEntityObject([NotNull] HurtBox hurtBox)
		{
			if (!hurtBox.healthComponent)
			{
				return null;
			}
			return hurtBox.healthComponent.gameObject;
		}

		public static bool HurtBoxesShareEntity([NotNull] HurtBox a, [NotNull] HurtBox b)
		{
			return (object)FindEntityObject(a) == FindEntityObject(b);
		}
	}
	public class BullseyeSearch
	{
		private struct CandidateInfo
		{
			public HurtBox hurtBox;

			public UnityEngine.Vector3 position;

			public float dot;

			public float distanceSqr;
		}

		public enum SortMode
		{
			None,
			Distance,
			Angle,
			DistanceAndAngle
		}

		private delegate CandidateInfo Selector(HurtBox hurtBox);

		public CharacterBody viewer;

		public UnityEngine.Vector3 searchOrigin;

		public UnityEngine.Vector3 searchDirection;

		private float minThetaDot = -1f;

		private float maxThetaDot = 1f;

		public float minDistanceFilter;

		public float maxDistanceFilter = float.PositiveInfinity;

		public TeamMask teamMaskFilter = TeamMask.allButNeutral;

		public bool filterByLoS = true;

		public bool filterByDistinctEntity;

		public QueryTriggerInteraction queryTriggerInteraction;

		public SortMode sortMode = SortMode.Distance;

		private List<CandidateInfo> candidatesEnumerable;

		private HashSet<int> DistinctEntityHash = new HashSet<int>();

		public float minAngleFilter
		{
			set
			{
				maxThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f));
			}
		}

		public float maxAngleFilter
		{
			set
			{
				minThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f));
			}
		}

		private bool filterByDistance
		{
			get
			{
				if (!(minDistanceFilter > 0f) && !(maxDistanceFilter < float.PositiveInfinity))
				{
					if ((bool)viewer)
					{
						return viewer.visionDistance < float.PositiveInfinity;
					}
					return false;
				}
				return true;
			}
		}

		private bool filterByAngle
		{
			get
			{
				if (!(minThetaDot > -1f))
				{
					return maxThetaDot < 1f;
				}
				return true;
			}
		}

		private Func<HurtBox, CandidateInfo> GetSelector()
		{
			bool getDot = filterByAngle;
			bool getDistanceSqr = filterByDistance;
			getDistanceSqr |= sortMode == SortMode.Distance || sortMode == SortMode.DistanceAndAngle;
			getDot |= sortMode == SortMode.Angle || sortMode == SortMode.DistanceAndAngle;
			bool getDifference = getDot || getDistanceSqr;
			bool getPosition = getDot || getDistanceSqr || filterByLoS;
			return delegate(HurtBox hurtBox)
			{
				CandidateInfo candidateInfo = default(CandidateInfo);
				candidateInfo.hurtBox = hurtBox;
				CandidateInfo result = candidateInfo;
				if (getPosition)
				{
					result.position = hurtBox.transform.position;
				}
				UnityEngine.Vector3 vector = default(UnityEngine.Vector3);
				if (getDifference)
				{
					vector = result.position - searchOrigin;
				}
				if (getDot)
				{
					result.dot = UnityEngine.Vector3.Dot(searchDirection, vector.normalized);
				}
				if (getDistanceSqr)
				{
					result.distanceSqr = vector.sqrMagnitude;
				}
				return result;
			};
		}

		public void RefreshCandidates()
		{
			Func<HurtBox, CandidateInfo> selector = GetSelector();
			int count = HurtBox.readOnlyBullseyesList.Count;
			List<CandidateInfo> list = (candidatesEnumerable = new List<CandidateInfo>(count));
			bool flag = filterByAngle;
			bool flag2 = filterByDistance;
			float minDistanceSqr = 0f;
			float maxDistanceSqr = 0f;
			if (flag2)
			{
				float num = maxDistanceFilter;
				if ((bool)viewer)
				{
					num = Mathf.Min(num, viewer.visionDistance);
				}
				minDistanceSqr = minDistanceFilter * minDistanceFilter;
				maxDistanceSqr = num * num;
			}
			for (int i = 0; i < count; i++)
			{
				HurtBox hurtBox = HurtBox.readOnlyBullseyesList[i];
				int item = 0;
				if (filterByDistinctEntity)
				{
					item = hurtBox.healthComponent.GetInstanceID();
					if (DistinctEntityHash.Contains(item))
					{
						continue;
					}
				}
				if (!teamMaskFilter.HasTeam(hurtBox.teamIndex))
				{
					continue;
				}
				CandidateInfo candidateInfo2 = selector(hurtBox);
				if ((!flag || DotOkay(candidateInfo2)) && (!flag2 || DistanceOkay(candidateInfo2)))
				{
					if (filterByDistinctEntity)
					{
						DistinctEntityHash.Add(item);
					}
					list.Add(candidateInfo2);
				}
			}
			Func<CandidateInfo, float> sorter = GetSorter();
			if (sorter != null)
			{
				Comparison<CandidateInfo> comparison = (CandidateInfo x, CandidateInfo y) => sorter(x).CompareTo(sorter(y));
				list.Sort(comparison);
			}
			if (filterByDistinctEntity)
			{
				DistinctEntityHash.Clear();
			}
			bool DistanceOkay(CandidateInfo candidateInfo)
			{
				if (candidateInfo.distanceSqr >= minDistanceSqr)
				{
					return candidateInfo.distanceSqr <= maxDistanceSqr;
				}
				return false;
			}
			bool DotOkay(CandidateInfo candidateInfo)
			{
				if (minThetaDot <= candidateInfo.dot)
				{
					return candidateInfo.dot <= maxThetaDot;
				}
				return false;
			}
		}

		private Func<CandidateInfo, float> GetSorter()
		{
			return sortMode switch
			{
				SortMode.Distance => (CandidateInfo candidateInfo) => candidateInfo.distanceSqr, 
				SortMode.Angle => (CandidateInfo candidateInfo) => 0f - candidateInfo.dot, 
				SortMode.DistanceAndAngle => (CandidateInfo candidateInfo) => (0f - candidateInfo.dot) * candidateInfo.distanceSqr, 
				_ => null, 
			};
		}

		public void FilterCandidatesByHealthFraction(float minHealthFraction = 0f, float maxHealthFraction = 1f)
		{
			if (minHealthFraction > 0f)
			{
				if (maxHealthFraction < 1f)
				{
					candidatesEnumerable.RemoveAll(delegate(CandidateInfo v)
					{
						float combinedHealthFraction = v.hurtBox.healthComponent.combinedHealthFraction;
						return combinedHealthFraction < minHealthFraction || maxHealthFraction < combinedHealthFraction;
					});
				}
				else
				{
					candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.combinedHealthFraction < minHealthFraction);
				}
			}
			else if (maxHealthFraction < 1f)
			{
				candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.combinedHealthFraction > maxHealthFraction);
			}
		}

		public void FilterOutGameObject(GameObject gameObject)
		{
			candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.gameObject == gameObject);
		}

		public IEnumerable<HurtBox> GetResults()
		{
			_ = candidatesEnumerable;
			if (filterByLoS)
			{
				candidatesEnumerable.RemoveAll((CandidateInfo candidateInfo) => !CheckLoS(candidateInfo.position));
			}
			if ((bool)viewer)
			{
				candidatesEnumerable.RemoveAll((CandidateInfo candidateInfo) => !CheckVisible(candidateInfo.hurtBox.healthComponent.gameObject));
			}
			int count = candidatesEnumerable.Count;
			HurtBox[] array = new HurtBox[count];
			for (int i = 0; i < count; i++)
			{
				array[i] = candidatesEnumerable[i].hurtBox;
			}
			return array;
		}

		public bool CheckLoS(UnityEngine.Vector3 targetPosition)
		{
			UnityEngine.Vector3 direction = targetPosition - searchOrigin;
			RaycastHit hitInfo;
			return !Physics.Raycast(searchOrigin, direction, out hitInfo, direction.magnitude, LayerIndex.world.mask, queryTriggerInteraction);
		}

		public bool CheckVisible(GameObject gameObject)
		{
			CharacterBody component = gameObject.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				return component.GetVisibilityLevel(viewer) >= VisibilityLevel.Revealed;
			}
			return true;
		}

		public void Reset()
		{
			viewer = null;
			searchOrigin = UnityEngine.Vector3.zero;
			searchDirection = UnityEngine.Vector3.zero;
			minThetaDot = -1f;
			minDistanceFilter = 0f;
			maxDistanceFilter = float.PositiveInfinity;
			teamMaskFilter = TeamMask.allButNeutral;
			filterByLoS = true;
			queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sortMode = SortMode.Distance;
		}
	}
	[Serializable]
	public struct HurtBoxReference : IEquatable<HurtBoxReference>
	{
		public GameObject rootObject;

		public byte hurtBoxIndexPlusOne;

		public static HurtBoxReference FromHurtBox(HurtBox hurtBox)
		{
			if (!hurtBox)
			{
				return default(HurtBoxReference);
			}
			HurtBoxReference result = default(HurtBoxReference);
			result.rootObject = (hurtBox.healthComponent ? hurtBox.healthComponent.gameObject : null);
			result.hurtBoxIndexPlusOne = (byte)(hurtBox.indexInGroup + 1);
			return result;
		}

		public static HurtBoxReference FromRootObject(GameObject rootObject)
		{
			HurtBoxReference result = default(HurtBoxReference);
			result.rootObject = rootObject;
			result.hurtBoxIndexPlusOne = 0;
			return result;
		}

		public GameObject ResolveGameObject()
		{
			if (hurtBoxIndexPlusOne == 0)
			{
				return rootObject;
			}
			if ((bool)rootObject)
			{
				ModelLocator component = rootObject.GetComponent<ModelLocator>();
				if ((bool)component && (bool)component.modelTransform)
				{
					HurtBoxGroup component2 = component.modelTransform.GetComponent<HurtBoxGroup>();
					if ((bool)component2 && component2.hurtBoxes != null)
					{
						int num = hurtBoxIndexPlusOne - 1;
						if (num < component2.hurtBoxes.Length)
						{
							return component2.hurtBoxes[num].gameObject;
						}
					}
				}
			}
			return null;
		}

		public HurtBox ResolveHurtBox()
		{
			GameObject gameObject = ResolveGameObject();
			if (!gameObject)
			{
				return null;
			}
			return gameObject.GetComponent<HurtBox>();
		}

		public void Write(NetworkWriter writer)
		{
			writer.Write(rootObject);
			writer.Write(hurtBoxIndexPlusOne);
		}

		public void Read(NetworkReader reader)
		{
			rootObject = reader.ReadGameObject();
			hurtBoxIndexPlusOne = reader.ReadByte();
		}

		public bool Equals(HurtBoxReference other)
		{
			if (object.Equals(rootObject, other.rootObject))
			{
				return hurtBoxIndexPlusOne == other.hurtBoxIndexPlusOne;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is HurtBoxReference other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((rootObject != null) ? rootObject.GetHashCode() : 0) * 397) ^ hurtBoxIndexPlusOne.GetHashCode();
		}
	}
	public class HurtBoxGroup : MonoBehaviour, ILifeBehavior
	{
		public class VolumeDistribution
		{
			private HurtBox[] hurtBoxes;

			public float totalVolume { get; private set; }

			public UnityEngine.Vector3 randomVolumePoint
			{
				get
				{
					float num = UnityEngine.Random.Range(0f, totalVolume);
					HurtBox hurtBox = hurtBoxes[0];
					float num2 = 0f;
					for (int i = 0; i < hurtBoxes.Length; i++)
					{
						num2 += hurtBoxes[i].volume;
						if (num2 <= num)
						{
							hurtBox = hurtBoxes[i];
							break;
						}
					}
					return hurtBox.randomVolumePoint;
				}
			}

			public VolumeDistribution(HurtBox[] hurtBoxes)
			{
				totalVolume = 0f;
				for (int i = 0; i < hurtBoxes.Length; i++)
				{
					totalVolume += hurtBoxes[i].volume;
				}
				this.hurtBoxes = (HurtBox[])hurtBoxes.Clone();
			}
		}

		[Tooltip("The hurtboxes in this group. This really shouldn't be set manually.")]
		public HurtBox[] hurtBoxes;

		[Tooltip("The most important hurtbox in this group, usually a good center-of-mass target like the chest.")]
		public HurtBox mainHurtBox;

		[HideInInspector]
		public int bullseyeCount;

		private int _hurtBoxesDeactivatorCounter;

		public int hurtBoxesDeactivatorCounter
		{
			get
			{
				return _hurtBoxesDeactivatorCounter;
			}
			set
			{
				bool num = _hurtBoxesDeactivatorCounter <= 0;
				bool flag = value <= 0;
				_hurtBoxesDeactivatorCounter = value;
				if (num != flag)
				{
					SetHurtboxesActive(flag);
				}
			}
		}

		public void OnDeathStart()
		{
			int num = hurtBoxesDeactivatorCounter + 1;
			hurtBoxesDeactivatorCounter = num;
		}

		private void SetHurtboxesActive(bool active)
		{
			for (int i = 0; i < hurtBoxes.Length; i++)
			{
				hurtBoxes[i].gameObject.SetActive(active);
			}
		}

		public void OnValidate()
		{
			int num = 0;
			if (hurtBoxes == null)
			{
				hurtBoxes = Array.Empty<HurtBox>();
			}
			for (short num2 = 0; num2 < hurtBoxes.Length; num2++)
			{
				if (!hurtBoxes[num2])
				{
					UnityEngine.Debug.LogWarningFormat("Object {0} HurtBoxGroup hurtbox #{1} is missing.", Util.GetGameObjectHierarchyName(base.gameObject), num2);
				}
				else
				{
					hurtBoxes[num2].hurtBoxGroup = this;
					hurtBoxes[num2].indexInGroup = num2;
					if (hurtBoxes[num2].isBullseye)
					{
						num++;
					}
				}
			}
			if (bullseyeCount != num)
			{
				bullseyeCount = num;
			}
			if (!mainHurtBox)
			{
				IEnumerable<HurtBox> source = from v in hurtBoxes
					where v
					where v.isBullseye
					select v;
				IEnumerable<HurtBox> source2 = source.Where((HurtBox v) => v.transform.parent.name.ToLower(CultureInfo.InvariantCulture) == "chest");
				mainHurtBox = source2.FirstOrDefault() ?? source.FirstOrDefault();
			}
		}

		public VolumeDistribution GetVolumeDistribution()
		{
			return new VolumeDistribution(hurtBoxes);
		}
	}
	public interface IBarrier
	{
		void BlockedDamage(DamageInfo damageInfo, float actualDamageBlocked);
	}
	public interface ICharacterFlightParameterProvider
	{
		CharacterFlightParameters flightParameters { get; set; }

		bool isFlying { get; }
	}
	[Serializable]
	public struct CharacterFlightParameters : IEquatable<CharacterFlightParameters>
	{
		public int channeledFlightGranterCount;

		public bool Equals(CharacterFlightParameters other)
		{
			return channeledFlightGranterCount == other.channeledFlightGranterCount;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is CharacterFlightParameters other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return channeledFlightGranterCount;
		}

		public bool CheckShouldUseFlight()
		{
			return channeledFlightGranterCount > 0;
		}
	}
	public interface ICharacterGravityParameterProvider
	{
		CharacterGravityParameters gravityParameters { get; set; }

		bool useGravity { get; }

		bool isFlying { get; }
	}
	[Serializable]
	public struct CharacterGravityParameters : IEquatable<CharacterGravityParameters>
	{
		[Tooltip("AntiGravity granted by Zero-G environments. Provides AntiGravity if greater than zero and takes precedence over all other parameters.")]
		public int environmentalAntiGravityGranterCount;

		[Tooltip("AntiGravity neutralizers, like debuffs. Neutralizes non-environmental AntiGravity if greater than zero.")]
		public int antiGravityNeutralizerCount;

		[Tooltip("AntiGravity granted by body, skills, and items. Provides AntiGravity if greater than zero.")]
		public int channeledAntiGravityGranterCount;

		public bool Equals(CharacterGravityParameters other)
		{
			if (environmentalAntiGravityGranterCount == other.environmentalAntiGravityGranterCount && antiGravityNeutralizerCount == other.antiGravityNeutralizerCount)
			{
				return channeledAntiGravityGranterCount == other.channeledAntiGravityGranterCount;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is CharacterGravityParameters other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((environmentalAntiGravityGranterCount * 397) ^ antiGravityNeutralizerCount) * 397) ^ channeledAntiGravityGranterCount;
		}

		public bool CheckShouldUseGravity()
		{
			if (environmentalAntiGravityGranterCount > 0)
			{
				return false;
			}
			if (antiGravityNeutralizerCount > 0)
			{
				return true;
			}
			if (channeledAntiGravityGranterCount > 0)
			{
				return false;
			}
			return true;
		}
	}
	public class IcicleAuraController : NetworkBehaviour
	{
		private struct OwnerInfo
		{
			public readonly GameObject gameObject;

			public readonly Transform transform;

			public readonly CharacterBody characterBody;

			public readonly CameraTargetParams cameraTargetParams;

			public OwnerInfo(GameObject gameObject)
			{
				this.gameObject = gameObject;
				if ((bool)gameObject)
				{
					transform = gameObject.transform;
					characterBody = gameObject.GetComponent<CharacterBody>();
					cameraTargetParams = gameObject.GetComponent<CameraTargetParams>();
				}
				else
				{
					transform = null;
					characterBody = null;
					cameraTargetParams = null;
				}
			}
		}

		public float baseIcicleAttackInterval = 0.25f;

		public float icicleBaseRadius = 10f;

		public float icicleRadiusPerIcicle = 2f;

		public float icicleDamageCoefficientPerTick = 2f;

		public float icicleDamageCoefficientPerTickPerIcicle = 1f;

		public float icicleDuration = 5f;

		public float icicleProcCoefficientPerTick = 0.2f;

		public int icicleCountOnFirstKill = 2;

		public int baseIcicleMax = 6;

		public int icicleMaxPerStack = 3;

		public BuffWard buffWard;

		private CameraTargetParams.AimRequest aimRequest;

		private List<float> icicleLifetimes = new List<float>();

		private float attackStopwatch;

		private int lastIcicleCount;

		[SyncVar]
		private int finalIcicleCount;

		[SyncVar]
		public GameObject owner;

		private OwnerInfo cachedOwnerInfo;

		public ParticleSystem[] auraParticles;

		public ParticleSystem[] procParticles;

		private new Transform transform;

		private float actualRadius;

		private float scaleVelocity;

		private NetworkInstanceId ___ownerNetId;

		private int maxIcicleCount
		{
			get
			{
				int num = 1;
				if ((bool)cachedOwnerInfo.characterBody.inventory)
				{
					num = cachedOwnerInfo.characterBody.inventory.GetItemCount(RoR2Content.Items.Icicle);
				}
				return baseIcicleMax + (num - 1) * icicleMaxPerStack;
			}
		}

		public int NetworkfinalIcicleCount
		{
			get
			{
				return finalIcicleCount;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref finalIcicleCount, 1u);
			}
		}

		public GameObject Networkowner
		{
			get
			{
				return owner;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref owner, 2u, ref ___ownerNetId);
			}
		}

		private void Awake()
		{
			transform = base.transform;
			if ((bool)buffWard)
			{
				buffWard.interval = baseIcicleAttackInterval;
			}
		}

		private void FixedUpdate()
		{
			if (cachedOwnerInfo.gameObject != owner)
			{
				cachedOwnerInfo = new OwnerInfo(owner);
			}
			UpdateRadius();
			if (NetworkServer.active)
			{
				if (!owner)
				{
					UnityEngine.Object.Destroy(base.gameObject);
					return;
				}
				for (int num = icicleLifetimes.Count - 1; num >= 0; num--)
				{
					icicleLifetimes[num] -= Time.fixedDeltaTime;
					if (icicleLifetimes[num] <= 0f)
					{
						icicleLifetimes.RemoveAt(num);
					}
				}
				NetworkfinalIcicleCount = Mathf.Min((icicleLifetimes.Count > 0) ? (icicleCountOnFirstKill + icicleLifetimes.Count) : 0, maxIcicleCount);
				attackStopwatch += Time.fixedDeltaTime;
			}
			if ((bool)cachedOwnerInfo.characterBody)
			{
				if (finalIcicleCount > 0)
				{
					if (lastIcicleCount == 0)
					{
						OnIciclesActivated();
					}
					if (lastIcicleCount < finalIcicleCount)
					{
						OnIcicleGained();
					}
				}
				else if (lastIcicleCount > 0)
				{
					OnIciclesDeactivated();
				}
				lastIcicleCount = finalIcicleCount;
			}
			if (NetworkServer.active && (bool)cachedOwnerInfo.characterBody && finalIcicleCount > 0 && attackStopwatch >= baseIcicleAttackInterval)
			{
				attackStopwatch = 0f;
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = owner;
				blastAttack.inflictor = base.gameObject;
				blastAttack.teamIndex = cachedOwnerInfo.characterBody.teamComponent.teamIndex;
				blastAttack.position = transform.position;
				blastAttack.procCoefficient = icicleProcCoefficientPerTick;
				blastAttack.radius = actualRadius;
				blastAttack.baseForce = 0f;
				blastAttack.baseDamage = cachedOwnerInfo.characterBody.damage * (icicleDamageCoefficientPerTick + icicleDamageCoefficientPerTickPerIcicle * (float)finalIcicleCount);
				blastAttack.bonusForce = UnityEngine.Vector3.zero;
				blastAttack.crit = false;
				blastAttack.damageType = DamageType.Generic;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.damageColorIndex = DamageColorIndex.Item;
				blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
				blastAttack.Fire();
			}
			if ((bool)buffWard)
			{
				buffWard.Networkradius = actualRadius;
			}
		}

		private void UpdateRadius()
		{
			if ((bool)owner)
			{
				if (finalIcicleCount > 0)
				{
					actualRadius = (cachedOwnerInfo.characterBody ? (cachedOwnerInfo.characterBody.radius + icicleBaseRadius + icicleRadiusPerIcicle * (float)finalIcicleCount) : 0f);
				}
				else
				{
					actualRadius = 0f;
				}
			}
		}

		private void UpdateVisuals()
		{
			if ((bool)cachedOwnerInfo.gameObject)
			{
				transform.position = (cachedOwnerInfo.characterBody ? cachedOwnerInfo.characterBody.corePosition : cachedOwnerInfo.transform.position);
			}
			float num = Mathf.SmoothDamp(transform.localScale.x, actualRadius, ref scaleVelocity, 0.5f);
			transform.localScale = new UnityEngine.Vector3(num, num, num);
		}

		private void OnIciclesDeactivated()
		{
			Util.PlaySound("Stop_item_proc_icicle", base.gameObject);
			ParticleSystem[] array = auraParticles;
			for (int i = 0; i < array.Length; i++)
			{
				ParticleSystem.MainModule main = array[i].main;
				main.loop = false;
			}
			aimRequest?.Dispose();
		}

		private void OnIciclesActivated()
		{
			Util.PlaySound("Play_item_proc_icicle", base.gameObject);
			if ((bool)cachedOwnerInfo.cameraTargetParams)
			{
				aimRequest = cachedOwnerInfo.cameraTargetParams.RequestAimType(CameraTargetParams.AimType.Aura);
			}
			ParticleSystem[] array = auraParticles;
			foreach (ParticleSystem obj in array)
			{
				ParticleSystem.MainModule main = obj.main;
				main.loop = true;
				obj.Play();
			}
		}

		private void OnIcicleGained()
		{
			ParticleSystem[] array = procParticles;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Play();
			}
		}

		private void LateUpdate()
		{
			UpdateVisuals();
		}

		public void OnOwnerKillOther()
		{
			icicleLifetimes.Add(icicleDuration);
		}

		public void OnDestroy()
		{
			OnIciclesDeactivated();
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)finalIcicleCount);
				writer.Write(owner);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)finalIcicleCount);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(owner);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				finalIcicleCount = (int)reader.ReadPackedUInt32();
				___ownerNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				finalIcicleCount = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 2u) != 0)
			{
				owner = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___ownerNetId.IsEmpty())
			{
				Networkowner = ClientScene.FindLocalObject(___ownerNetId);
			}
		}
	}
	public interface IDisplacementReceiver
	{
		void AddDisplacement(UnityEngine.Vector3 displacement);
	}
	public interface IDisplayNameProvider
	{
		string GetDisplayName();
	}
	public interface IHologramContentProvider
	{
		bool ShouldDisplayHologram(GameObject viewer);

		GameObject GetHologramContentPrefab();

		void UpdateHologramContent(GameObject hologramContentObject, Transform viewerBody);
	}
	public interface IIKTargetBehavior
	{
		void UpdateIKTargetPosition();

		void UpdateIKState(int targetState);
	}
	public enum Interactability
	{
		Disabled,
		ConditionsNotMet,
		Available
	}
	public interface IInteractable
	{
		[CanBeNull]
		string GetContextString([NotNull] Interactor activator);

		Interactability GetInteractability([NotNull] Interactor activator);

		void OnInteractionBegin([NotNull] Interactor activator);

		bool ShouldIgnoreSpherecastForInteractibility([NotNull] Interactor activator);

		bool ShouldShowOnScanner();

		bool ShouldProximityHighlight();
	}
	public class IKSetWeightFromAnimatorFloat : MonoBehaviour
	{
		public Animator animator;

		public string animatorFloat;

		public InverseKinematics ik;

		private void Update()
		{
			float @float = animator.GetFloat(animatorFloat);
			Core.Chain[] otherChains = ik.otherChains;
			for (int i = 0; i < otherChains.Length; i++)
			{
				otherChains[i].weight = @float;
			}
		}
	}
	public class IKSimpleChain : MonoBehaviour
	{
		public enum InnerAxis
		{
			Left,
			Right,
			Forward,
			Backward
		}

		public float scale = 1f;

		public int maxIterations = 100;

		public float positionAccuracy = 0.001f;

		private float posAccuracy = 0.001f;

		public float bendingLow;

		public float bendingHigh;

		public int chainResolution;

		private int startBone;

		private bool minIsFound;

		private bool bendMore;

		private UnityEngine.Vector3 targetPosition;

		public float legLength;

		public float poleAngle;

		public InnerAxis innerAxis = InnerAxis.Right;

		private Transform tmpBone;

		public Transform ikPole;

		public Transform[] boneList;

		private bool firstRun = true;

		private IIKTargetBehavior ikTarget;

		private void Start()
		{
			ikTarget = GetComponent<IIKTargetBehavior>();
		}

		private void LateUpdate()
		{
			if (firstRun)
			{
				tmpBone = boneList[startBone];
			}
			if (ikTarget != null)
			{
				ikTarget.UpdateIKTargetPosition();
			}
			targetPosition = base.transform.position;
			legLength = CalculateLegLength(boneList);
			Solve(boneList, targetPosition);
			firstRun = false;
		}

		public bool LegTooShort(float legScale = 1f)
		{
			bool result = false;
			if ((targetPosition - boneList[0].transform.position).sqrMagnitude >= legLength * legLength * legScale * legScale)
			{
				result = true;
			}
			return result;
		}

		private float CalculateLegLength(Transform[] bones)
		{
			float[] array = new float[bones.Length - 1];
			float num = 0f;
			for (int i = startBone; i < bones.Length - 1; i++)
			{
				array[i] = (bones[i + 1].position - bones[i].position).magnitude;
				num += array[i];
			}
			return num;
		}

		public void Solve(Transform[] bones, UnityEngine.Vector3 target)
		{
			Transform transform = bones[^1];
			UnityEngine.Vector3[] array = new UnityEngine.Vector3[bones.Length - 2];
			float[] array2 = new float[bones.Length - 2];
			UnityEngine.Quaternion[] array3 = new UnityEngine.Quaternion[bones.Length - 2];
			for (int i = startBone; i < bones.Length - 2; i++)
			{
				array[i] = UnityEngine.Vector3.Cross(bones[i + 1].position - bones[i].position, bones[i + 2].position - bones[i + 1].position);
				array[i] = UnityEngine.Quaternion.Inverse(bones[i].rotation) * array[i];
				array[i] = array[i].normalized;
				array2[i] = UnityEngine.Vector3.Angle(bones[i + 1].position - bones[i].position, bones[i + 1].position - bones[i + 2].position);
				array3[i] = bones[i + 1].localRotation;
			}
			positionAccuracy = legLength * posAccuracy;
			float magnitude = (transform.position - bones[startBone].position).magnitude;
			float magnitude2 = (target - bones[startBone].position).magnitude;
			minIsFound = false;
			bendMore = false;
			if (magnitude2 >= magnitude)
			{
				minIsFound = true;
				bendingHigh = 1f;
				bendingLow = 0f;
			}
			else
			{
				bendMore = true;
				bendingHigh = 1f;
				bendingLow = 0f;
			}
			_ = array3.Length;
			int num = 0;
			while (Mathf.Abs(magnitude - magnitude2) > positionAccuracy && num < maxIterations)
			{
				num++;
				float num2 = (minIsFound ? ((bendingLow + bendingHigh) / 2f) : bendingHigh);
				for (int j = startBone; j < bones.Length - 2; j++)
				{
					float num3 = (bendMore ? (array2[j] * (1f - num2) + (array2[j] - 30f) * num2) : Mathf.Lerp(180f, array2[j], num2));
					UnityEngine.Quaternion localRotation = UnityEngine.Quaternion.AngleAxis(array2[j] - num3, array[j]) * array3[j];
					bones[j + 1].localRotation = localRotation;
				}
				magnitude = (transform.position - bones[startBone].position).magnitude;
				if (magnitude2 > magnitude)
				{
					minIsFound = true;
				}
				if (minIsFound)
				{
					if (magnitude2 > magnitude)
					{
						bendingHigh = num2;
					}
					else
					{
						bendingLow = num2;
					}
					if (bendingHigh < 0.01f)
					{
						break;
					}
				}
				else
				{
					bendingLow = bendingHigh;
					bendingHigh += 1f;
				}
			}
			if (firstRun)
			{
				tmpBone.rotation = bones[startBone].rotation;
			}
			bones[startBone].rotation = UnityEngine.Quaternion.AngleAxis(UnityEngine.Vector3.Angle(transform.position - bones[startBone].position, target - bones[startBone].position), UnityEngine.Vector3.Cross(transform.position - bones[startBone].position, target - bones[startBone].position)) * bones[startBone].rotation;
			if ((bool)ikPole)
			{
				UnityEngine.Vector3 position = bones[startBone].position;
				UnityEngine.Vector3 up = bones[startBone].transform.up;
				UnityEngine.Vector3 position2 = transform.position;
				UnityEngine.Vector3 vector = UnityEngine.Vector3.Cross(rhs: ikPole.position - position, lhs: position2 - position);
				UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Cross(vector, up);
				UnityEngine.Vector3 vecU = UnityEngine.Vector3.zero;
				switch (innerAxis)
				{
				case InnerAxis.Right:
					vecU = bones[startBone].transform.right;
					break;
				case InnerAxis.Left:
					vecU = -bones[startBone].transform.right;
					break;
				case InnerAxis.Forward:
					vecU = bones[startBone].transform.forward;
					break;
				case InnerAxis.Backward:
					vecU = -bones[startBone].transform.forward;
					break;
				}
				float num4 = SignedAngle(vecU, vector2, up);
				num4 += poleAngle;
				bones[startBone].rotation = UnityEngine.Quaternion.AngleAxis(num4, transform.position - bones[startBone].position) * bones[startBone].rotation;
				UnityEngine.Debug.DrawLine(transform.position, bones[startBone].position, UnityEngine.Color.red);
				UnityEngine.Debug.DrawRay(bones[startBone].position, vector, UnityEngine.Color.blue);
				UnityEngine.Debug.DrawRay(bones[startBone].position, vector2, UnityEngine.Color.yellow);
			}
			tmpBone = bones[startBone];
		}

		private float SignedAngle(UnityEngine.Vector3 vecU, UnityEngine.Vector3 vecV, UnityEngine.Vector3 normal)
		{
			float num = UnityEngine.Vector3.Angle(vecU, vecV);
			if (UnityEngine.Vector3.Angle(UnityEngine.Vector3.Cross(vecU, vecV), normal) < 1f)
			{
				num *= -1f;
			}
			return 0f - num;
		}

		private float AngleDir(UnityEngine.Vector3 fwd, UnityEngine.Vector3 targetDir, UnityEngine.Vector3 up)
		{
			float num = UnityEngine.Vector3.Dot(UnityEngine.Vector3.Cross(fwd, targetDir), up);
			if (num > 0f)
			{
				return 1f;
			}
			if (num < 0f)
			{
				return -1f;
			}
			return 0f;
		}
	}
	public class IKTargetPassive : MonoBehaviour, IIKTargetBehavior
	{
		private float smoothedTargetHeightOffset;

		private float targetHeightOffset;

		private float smoothdampVelocity;

		public float minHeight = -0.3f;

		public float maxHeight = 1f;

		public float dampTime = 0.1f;

		public float baseOffset;

		[Tooltip("The IK weight float parameter if used")]
		public string animatorIKWeightFloat = "";

		public Animator animator;

		[Tooltip("The target transform will plant without any calls from external IK chains")]
		public bool selfPlant;

		public float selfPlantFrequency = 5f;

		[Tooltip("Whether or not to cache where the raycast begins. Used when not attached to bones, who reset themselves via animator.")]
		public bool cacheFirstPosition;

		private UnityEngine.Vector3 cachedLocalPosition;

		private float selfPlantTimer;

		public void UpdateIKState(int targetState)
		{
		}

		private void Awake()
		{
			if (cacheFirstPosition)
			{
				cachedLocalPosition = base.transform.localPosition;
			}
		}

		private void LateUpdate()
		{
			selfPlantTimer -= Time.deltaTime;
			if (selfPlant && selfPlantTimer <= 0f)
			{
				selfPlantTimer = 1f / selfPlantFrequency;
				UpdateIKTargetPosition();
			}
			UpdateYOffset();
		}

		public void UpdateIKTargetPosition()
		{
			ResetTransformToCachedPosition();
			if (Physics.Raycast(base.transform.position + UnityEngine.Vector3.up * (0f - minHeight), UnityEngine.Vector3.down, out var hitInfo, maxHeight - minHeight, LayerIndex.world.mask))
			{
				targetHeightOffset = hitInfo.point.y - base.transform.position.y;
			}
			else
			{
				targetHeightOffset = 0f;
			}
			targetHeightOffset += baseOffset;
		}

		public void UpdateYOffset()
		{
			float t = 1f;
			if ((bool)animator && animatorIKWeightFloat.Length > 0)
			{
				t = animator.GetFloat(animatorIKWeightFloat);
			}
			smoothedTargetHeightOffset = Mathf.SmoothDamp(smoothedTargetHeightOffset, targetHeightOffset, ref smoothdampVelocity, dampTime, float.PositiveInfinity, Time.deltaTime);
			ResetTransformToCachedPosition();
			base.transform.position = new UnityEngine.Vector3(base.transform.position.x, base.transform.position.y + Mathf.Lerp(0f, smoothedTargetHeightOffset, t), base.transform.position.z);
		}

		private void ResetTransformToCachedPosition()
		{
			if (cacheFirstPosition)
			{
				base.transform.localPosition = new UnityEngine.Vector3(cachedLocalPosition.x, cachedLocalPosition.y, cachedLocalPosition.z);
			}
		}
	}
	public class IKTargetPlant : MonoBehaviour, IIKTargetBehavior
	{
		public enum IKState
		{
			Plant,
			Reset
		}

		[Tooltip("The max offset to step up")]
		public float minHeight = -0.3f;

		[Tooltip("The max offset to step down")]
		public float maxHeight = 1f;

		[Tooltip("The strength of the IK as a lerp (0-1)")]
		public float ikWeight = 1f;

		[Tooltip("The time to restep")]
		public float timeToReset = 0.6f;

		[Tooltip("The max positional IK error before restepping")]
		public float maxXZPositionalError = 4f;

		public GameObject plantEffect;

		public Animator animator;

		[Tooltip("The IK weight float parameter if used")]
		public string animatorIKWeightFloat;

		[Tooltip("The lift animation trigger string if used")]
		public string animatorLiftTrigger;

		[Tooltip("The scale of the leg for calculating if the leg is too short to reach the IK target")]
		public float legScale = 1f;

		[Tooltip("The height of the step arc")]
		public float arcHeight = 1f;

		[Tooltip("The smoothing duration for the IK. Higher will be smoother but will be delayed.")]
		public float smoothDampTime = 0.1f;

		[Tooltip("Spherecasts will have more hits but take higher performance.")]
		public bool useSpherecast;

		public float spherecastRadius = 0.5f;

		public IKState ikState;

		private bool isPlanted;

		private UnityEngine.Vector3 lastTransformPosition;

		private UnityEngine.Vector3 smoothDampRefVelocity;

		private UnityEngine.Vector3 targetPosition;

		private UnityEngine.Vector3 plantPosition;

		private IKSimpleChain ikChain;

		private float resetTimer;

		private void Awake()
		{
			ikChain = GetComponent<IKSimpleChain>();
		}

		public void UpdateIKState(int targetState)
		{
			if (ikState != IKState.Reset)
			{
				ikState = (IKState)targetState;
			}
		}

		public UnityEngine.Vector3 GetArcPosition(UnityEngine.Vector3 start, UnityEngine.Vector3 end, float arcHeight, float t)
		{
			return UnityEngine.Vector3.Lerp(start, end, Mathf.Sin(t * MathF.PI * 0.5f)) + new UnityEngine.Vector3(0f, Mathf.Sin(t * MathF.PI) * arcHeight, 0f);
		}

		public void UpdateIKTargetPosition()
		{
			if ((bool)animator)
			{
				ikWeight = animator.GetFloat(animatorIKWeightFloat);
			}
			else
			{
				ikWeight = 1f;
			}
			switch (ikState)
			{
			case IKState.Reset:
				resetTimer += Time.deltaTime;
				isPlanted = false;
				RaycastIKTarget(base.transform.position);
				base.transform.position = GetArcPosition(plantPosition, targetPosition, arcHeight, resetTimer / timeToReset);
				if (resetTimer >= timeToReset)
				{
					ikState = IKState.Plant;
					isPlanted = true;
					plantPosition = targetPosition;
					UnityEngine.Object.Instantiate(plantEffect, plantPosition, UnityEngine.Quaternion.identity);
				}
				break;
			case IKState.Plant:
			{
				UnityEngine.Vector3 position = base.transform.position;
				RaycastIKTarget(position);
				if (!isPlanted)
				{
					plantPosition = targetPosition;
					base.transform.position = plantPosition;
					isPlanted = true;
					if ((bool)plantEffect)
					{
						UnityEngine.Object.Instantiate(plantEffect, plantPosition, UnityEngine.Quaternion.identity);
					}
				}
				else
				{
					base.transform.position = UnityEngine.Vector3.Lerp(position, plantPosition, ikWeight);
				}
				UnityEngine.Vector3 vector = position - base.transform.position;
				vector.y = 0f;
				if (ikChain.LegTooShort(legScale) || vector.sqrMagnitude >= maxXZPositionalError * maxXZPositionalError)
				{
					plantPosition = base.transform.position;
					ikState = IKState.Reset;
					if ((bool)animator)
					{
						animator.SetTrigger(animatorLiftTrigger);
					}
					resetTimer = 0f;
				}
				break;
			}
			}
			base.transform.position = UnityEngine.Vector3.SmoothDamp(lastTransformPosition, base.transform.position, ref smoothDampRefVelocity, smoothDampTime);
			lastTransformPosition = base.transform.position;
		}

		public void RaycastIKTarget(UnityEngine.Vector3 position)
		{
			RaycastHit hitInfo;
			if (useSpherecast)
			{
				Physics.SphereCast(position + UnityEngine.Vector3.up * (0f - minHeight), spherecastRadius, UnityEngine.Vector3.down, out hitInfo, maxHeight - minHeight, LayerIndex.world.mask);
			}
			else
			{
				Physics.Raycast(position + UnityEngine.Vector3.up * (0f - minHeight), UnityEngine.Vector3.down, out hitInfo, maxHeight - minHeight, LayerIndex.world.mask);
			}
			if ((bool)hitInfo.collider)
			{
				targetPosition = hitInfo.point;
			}
			else
			{
				targetPosition = position;
			}
		}
	}
	public interface ILifeBehavior
	{
		void OnDeathStart();
	}
	[RequireComponent(typeof(EffectComponent))]
	internal class ImpactEffect : MonoBehaviour
	{
		public ParticleSystem[] particleSystems = Array.Empty<ParticleSystem>();

		private void Start()
		{
			EffectComponent component = GetComponent<EffectComponent>();
			UnityEngine.Color color = ((component.effectData != null) ? ((UnityEngine.Color)component.effectData.color) : UnityEngine.Color.white);
			for (int i = 0; i < particleSystems.Length; i++)
			{
				ParticleSystem.MainModule main = particleSystems[i].main;
				main.startColor = color;
				particleSystems[i].Play();
			}
		}
	}
	public class InfiniteTowerSafeWardController : MonoBehaviour
	{
		[SerializeField]
		private EntityStateMachine wardStateMachine;

		[SerializeField]
		private VerticalTubeZone _safeZone;

		[SerializeField]
		private GameObject positionIndicatorPrefab;

		[SerializeField]
		private HoldoutZoneController holdoutZoneController;

		private PositionIndicator positionIndicator;

		private ChargeIndicatorController chargeIndicatorController;

		public IZone safeZone => _safeZone;

		public bool isAwaitingInteraction
		{
			get
			{
				if ((bool)wardStateMachine)
				{
					return wardStateMachine.state is AwaitingActivation;
				}
				return false;
			}
		}

		public event Action<InfiniteTowerSafeWardController> onActivated;

		private void Awake()
		{
			if (!positionIndicatorPrefab)
			{
				return;
			}
			GameObject gameObject = UnityEngine.Object.Instantiate(positionIndicatorPrefab, base.transform.position, UnityEngine.Quaternion.identity);
			if ((bool)gameObject)
			{
				positionIndicator = gameObject.GetComponent<PositionIndicator>();
				if ((bool)positionIndicator)
				{
					positionIndicator.targetTransform = base.transform;
				}
				chargeIndicatorController = gameObject.GetComponent<ChargeIndicatorController>();
				if ((bool)chargeIndicatorController)
				{
					chargeIndicatorController.holdoutZoneController = holdoutZoneController;
				}
				gameObject.SetActive(value: false);
			}
		}

		public void Activate()
		{
			if ((bool)wardStateMachine && wardStateMachine.state is AwaitingActivation awaitingActivation)
			{
				awaitingActivation.Activate();
				this.onActivated?.Invoke(this);
			}
		}

		public void SelfDestruct()
		{
			if ((bool)wardStateMachine && wardStateMachine.state is EntityStates.InfiniteTowerSafeWard.Active active)
			{
				active.SelfDestruct();
			}
		}

		public void RandomizeLocation(Xoroshiro128Plus rng)
		{
			if ((bool)wardStateMachine)
			{
				wardStateMachine.SetNextState(new Unburrow(rng));
			}
		}

		public void WaitForPortal()
		{
			if ((bool)wardStateMachine)
			{
				wardStateMachine.SetNextState(new AwaitingPortalUse());
			}
		}

		public void SetIndicatorEnabled(bool enabled)
		{
			if ((bool)positionIndicator)
			{
				positionIndicator.gameObject.SetActive(enabled);
			}
		}
	}
	public class InfiniteTowerBossWaveController : InfiniteTowerWaveController
	{
		[SerializeField]
		[Tooltip("The interactable spawner to activate when the player defeats all enemies")]
		private InteractableSpawner rewardInteractableSpawner;

		[SerializeField]
		[Tooltip("If true, it ensures that the combat director gets enough credits to spawn the initially selected champion spawn card.")]
		private bool guaranteeInitialChampion;

		[SerializeField]
		[Tooltip("If true, clear the pickups when this wave finishes")]
		private bool clearPickupsOnFinish;

		[Server]
		public override void Initialize(int waveIndex, Inventory enemyInventory, GameObject spawnTarget)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerBossWaveController::Initialize(System.Int32,RoR2.Inventory,UnityEngine.GameObject)' called on client");
				return;
			}
			base.Initialize(waveIndex, enemyInventory, spawnTarget);
			combatDirector.SetNextSpawnAsBoss();
			if (guaranteeInitialChampion && combatDirector.monsterCredit < (float)combatDirector.lastAttemptedMonsterCard.cost)
			{
				combatDirector.monsterCredit = combatDirector.lastAttemptedMonsterCard.cost;
			}
		}

		protected override void OnAllEnemiesDefeatedServer()
		{
			base.OnAllEnemiesDefeatedServer();
			if ((bool)rewardInteractableSpawner)
			{
				rewardInteractableSpawner.Spawn(new Xoroshiro128Plus(Run.instance.seed ^ (ulong)waveIndex));
			}
			if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion))
			{
				foreach (ChestBehavior instances in InstanceTracker.GetInstancesList<ChestBehavior>())
				{
					instances.CallRpcResetChests();
				}
			}
			InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun;
			if ((bool)infiniteTowerRun && !infiniteTowerRun.IsStageTransitionWave())
			{
				infiniteTowerRun.MoveSafeWard();
			}
		}

		protected override void OnFinishedServer()
		{
			base.OnFinishedServer();
			if ((bool)rewardInteractableSpawner)
			{
				rewardInteractableSpawner.DestroySpawnedInteractables();
			}
			if (!clearPickupsOnFinish)
			{
				return;
			}
			foreach (GenericPickupController item in new List<GenericPickupController>(InstanceTracker.GetInstancesList<GenericPickupController>()))
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(item.pickupIndex);
				if (pickupDef.itemIndex != ItemIndex.None || pickupDef.equipmentIndex != EquipmentIndex.None)
				{
					UnityEngine.Object.Destroy(item.gameObject);
				}
			}
		}

		protected override void OnTimerExpire()
		{
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class InfiniteTowerExplicitSpawnWaveController : InfiniteTowerWaveController
	{
		[Serializable]
		private struct SpawnInfo
		{
			[SerializeField]
			public int count;

			[SerializeField]
			public CharacterSpawnCard spawnCard;

			[SerializeField]
			public EliteDef eliteDef;

			[SerializeField]
			public bool preventOverhead;

			[SerializeField]
			public DirectorCore.MonsterSpawnDistance spawnDistance;
		}

		[Tooltip("The information for all of the characters to spawn.")]
		[SerializeField]
		private SpawnInfo[] spawnList;

		[Server]
		public override void Initialize(int waveIndex, Inventory enemyInventory, GameObject spawnTargetObject)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerExplicitSpawnWaveController::Initialize(System.Int32,RoR2.Inventory,UnityEngine.GameObject)' called on client");
				return;
			}
			base.Initialize(waveIndex, enemyInventory, spawnTargetObject);
			SpawnInfo[] array = spawnList;
			for (int i = 0; i < array.Length; i++)
			{
				SpawnInfo spawnInfo = array[i];
				for (int j = 0; j < spawnInfo.count; j++)
				{
					combatDirector.Spawn(spawnInfo.spawnCard, spawnInfo.eliteDef, spawnTarget.transform, preventOverhead: spawnInfo.preventOverhead, spawnDistance: spawnInfo.spawnDistance);
				}
			}
		}

		protected override void OnAllEnemiesDefeatedServer()
		{
			base.OnAllEnemiesDefeatedServer();
			InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun;
			if ((bool)infiniteTowerRun && !infiniteTowerRun.IsStageTransitionWave())
			{
				infiniteTowerRun.MoveSafeWard();
			}
		}

		protected override void OnTimerExpire()
		{
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[DisallowMultipleComponent]
	public class InfiniteTowerWaveController : NetworkBehaviour
	{
		[Serializable]
		public struct OverlayEntry
		{
			[Tooltip("The overlay prefab to instantiate")]
			[SerializeField]
			public GameObject prefab;

			[Tooltip("The overaly prefab to instantiate")]
			[SerializeField]
			public string hudChildName;
		}

		private const float minimumDistributedCreditsFraction = 0.1f;

		[Tooltip("Should the enemies in this wave count as bosses?")]
		[SerializeField]
		private bool isBossWave;

		[Tooltip("The combat director for this wave")]
		[SerializeField]
		protected CombatDirector combatDirector;

		[Tooltip("The combat squad for this wave")]
		[SerializeField]
		protected CombatSquad combatSquad;

		[Tooltip("The base total number of credits to give to the CombatDirector for this wave.  Wave 1 gets this many credits.")]
		[SerializeField]
		protected float baseCredits;

		[Tooltip("The number of additional credits to give to the CombatDirector for each wave you've completed.  This doesn't affect Wave 1.")]
		[SerializeField]
		protected float linearCreditsPerWave;

		[SerializeField]
		[Tooltip("The period (in seconds) over which we give the CombatDirector its credits.")]
		protected float wavePeriodSeconds;

		[SerializeField]
		[Tooltip("The number of seconds (after the last enemy is spawned) before the radius begins constricting")]
		protected float secondsBeforeSuddenDeath = 60f;

		[SerializeField]
		[Tooltip("If there's ever a period of this many seconds with no enemies, end the wave")]
		protected float secondsBeforeFailsafe = 60f;

		[Range(0f, 1f)]
		[Tooltip("The zone radius percentage is reduced by this amount each second")]
		[SerializeField]
		protected float suddenDeathRadiusConstrictingPerSecond = 0.05f;

		[Tooltip("Broadcast this message at the beginning of sudden death")]
		[SerializeField]
		protected string suddenDeathChatToken = "INFINITETOWER_SUDDEN_DEATH";

		[Range(0f, 1f)]
		[Tooltip("The normalized fraction of the total credits to give to the CombatDirector immediately")]
		[SerializeField]
		protected float immediateCreditsFraction;

		[SerializeField]
		[Tooltip("The maximum number of members in the combat squad before we stop giving the CombatDirector credits.  If the squad size is reduced below this number, we resume giving the director credits.")]
		protected int maxSquadSize;

		[SerializeField]
		[Tooltip("The time (in seconds) after completing the wave before the next wave begins")]
		public int secondsAfterWave;

		[Tooltip("The time (in seconds) after completing the wave before the next wave begins")]
		[SerializeField]
		protected float squadDefeatGracePeriod = 1f;

		[Tooltip("The prefab to instantiate on the UI.")]
		[SerializeField]
		protected GameObject uiPrefab;

		[Tooltip("The overlays to add for this wave")]
		[SerializeField]
		protected OverlayEntry[] overlayEntries;

		[Tooltip("If true, convert all player gold to experience at the end of the wave")]
		[SerializeField]
		protected bool convertGoldOnWaveFinish;

		[Tooltip("The multiplier to use when converting gold to experience (only used if convertGoldOnWaveFinish is true).")]
		[SerializeField]
		protected float goldToExpConversionRatio;

		[SerializeField]
		[Tooltip("The drop table to use for the end of wave rewards")]
		protected PickupDropTable rewardDropTable;

		[Tooltip("Use this tier to get a pickup index for the reward.  The droplet's visuals will correspond to this.")]
		[SerializeField]
		protected ItemTier rewardDisplayTier;

		[Tooltip("The number of options to display when the player interacts with the reward pickup.")]
		[SerializeField]
		protected int rewardOptionCount;

		[Tooltip("The prefab to use for the reward pickup.")]
		[SerializeField]
		protected GameObject rewardPickupPrefab;

		[Tooltip("Where to spawn the reward droplets relative to the spawn target (the center of the safe ward).")]
		[SerializeField]
		protected UnityEngine.Vector3 rewardOffset;

		[Tooltip("Broadcast this message at the beginning of the wave.")]
		[SerializeField]
		protected string beginChatToken = "INFINITETOWER_WAVE_BEGIN";

		[Tooltip("Play this sound at the beginning of the wave.")]
		[SerializeField]
		protected string beginSoundString;

		[Tooltip("Play this sound when all enemies are defeated.")]
		[SerializeField]
		protected string onAllEnemiesDefeatedSoundString;

		[SyncVar]
		private float _totalWaveCredits;

		[SyncVar]
		private float _totalCreditsSpent;

		[SyncVar]
		private float _timerStart;

		[SyncVar]
		private float _failsafeTimer;

		[SyncVar]
		protected float _suddenDeathTimerStart;

		[SyncVar]
		private bool _isFinished;

		[SyncVar]
		private bool _isTimerActive;

		[SyncVar]
		private float _zoneRadiusPercentage = 1f;

		[SyncVar]
		protected int waveIndex;

		[SyncVar]
		private int squadCount;

		[SyncVar]
		private bool haveAllEnemiesBeenDefeated;

		protected float creditsPerSecond;

		protected GameObject uiInstance;

		protected bool hasEnabledEnemyIndicators;

		protected float squadDefeatTimer;

		private Inventory enemyInventory;

		private bool hasTimerExpired;

		protected GameObject spawnTarget;

		private Xoroshiro128Plus rng;

		private List<OverlayController> overlayControllerList = new List<OverlayController>();

		private bool hasNotifiedSuddenDeath;

		private bool hasPlayedEnemiesDefeatedSound;

		private int clearMemoryEveryXRounds = 5;

		public GameObject defaultEnemyIndicatorPrefab { get; set; }

		public bool isFinished
		{
			get
			{
				return _isFinished;
			}
			private set
			{
				Network_isFinished = value;
			}
		}

		public bool isTimerActive
		{
			get
			{
				return _isTimerActive;
			}
			private set
			{
				Network_isTimerActive = value;
			}
		}

		public float totalWaveCredits
		{
			get
			{
				return _totalWaveCredits;
			}
			protected set
			{
				Network_totalWaveCredits = value;
			}
		}

		public float totalCreditsSpent
		{
			get
			{
				return _totalCreditsSpent;
			}
			protected set
			{
				Network_totalCreditsSpent = value;
			}
		}

		public float zoneRadiusPercentage
		{
			get
			{
				return _zoneRadiusPercentage;
			}
			protected set
			{
				Network_zoneRadiusPercentage = value;
			}
		}

		public float secondsRemaining
		{
			get
			{
				if ((bool)Run.instance && _timerStart > 0f)
				{
					return Mathf.Max(0f, (float)secondsAfterWave - (Run.instance.GetRunStopwatch() - _timerStart));
				}
				return secondsAfterWave;
			}
		}

		public bool isInSuddenDeath
		{
			get
			{
				if ((bool)Run.instance && _suddenDeathTimerStart > 0f)
				{
					if (!haveAllEnemiesBeenDefeated && HasFullProgress())
					{
						return secondsBeforeSuddenDeath - (Run.instance.GetRunStopwatch() - _suddenDeathTimerStart) < 0f;
					}
					return false;
				}
				return false;
			}
		}

		public float Network_totalWaveCredits
		{
			get
			{
				return _totalWaveCredits;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _totalWaveCredits, 1u);
			}
		}

		public float Network_totalCreditsSpent
		{
			get
			{
				return _totalCreditsSpent;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _totalCreditsSpent, 2u);
			}
		}

		public float Network_timerStart
		{
			get
			{
				return _timerStart;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _timerStart, 4u);
			}
		}

		public float Network_failsafeTimer
		{
			get
			{
				return _failsafeTimer;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _failsafeTimer, 8u);
			}
		}

		public float Network_suddenDeathTimerStart
		{
			get
			{
				return _suddenDeathTimerStart;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _suddenDeathTimerStart, 16u);
			}
		}

		public bool Network_isFinished
		{
			get
			{
				return _isFinished;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _isFinished, 32u);
			}
		}

		public bool Network_isTimerActive
		{
			get
			{
				return _isTimerActive;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _isTimerActive, 64u);
			}
		}

		public float Network_zoneRadiusPercentage
		{
			get
			{
				return _zoneRadiusPercentage;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _zoneRadiusPercentage, 128u);
			}
		}

		public int NetworkwaveIndex
		{
			get
			{
				return waveIndex;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref waveIndex, 256u);
			}
		}

		public int NetworksquadCount
		{
			get
			{
				return squadCount;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref squadCount, 512u);
			}
		}

		public bool NetworkhaveAllEnemiesBeenDefeated
		{
			get
			{
				return haveAllEnemiesBeenDefeated;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref haveAllEnemiesBeenDefeated, 1024u);
			}
		}

		public event Action<InfiniteTowerWaveController> onAllEnemiesDefeatedServer;

		[Server]
		public virtual void Initialize(int waveIndex, Inventory enemyInventory, GameObject spawnTarget)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::Initialize(System.Int32,RoR2.Inventory,UnityEngine.GameObject)' called on client");
				return;
			}
			totalWaveCredits = (baseCredits + linearCreditsPerWave * (float)(waveIndex - 1)) * Run.instance.difficultyCoefficient;
			creditsPerSecond = Mathf.Max(0.1f, 1f - immediateCreditsFraction) * totalWaveCredits / wavePeriodSeconds;
			if ((bool)combatDirector)
			{
				combatDirector.monsterCredit += immediateCreditsFraction * totalWaveCredits;
				combatDirector.currentSpawnTarget = spawnTarget;
			}
			NetworkwaveIndex = waveIndex;
			this.enemyInventory = enemyInventory;
			this.spawnTarget = spawnTarget;
			rng = new Xoroshiro128Plus((ulong)waveIndex ^ Run.instance.seed);
			if (!string.IsNullOrEmpty(beginChatToken))
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = beginChatToken
				});
			}
		}

		public void InstantiateUi(Transform uiRoot)
		{
			if ((bool)uiRoot && (bool)uiPrefab)
			{
				uiInstance = UnityEngine.Object.Instantiate(uiPrefab, uiRoot);
			}
			OverlayEntry[] array = overlayEntries;
			for (int i = 0; i < array.Length; i++)
			{
				OverlayEntry overlayEntry = array[i];
				OverlayCreationParams overlayCreationParams = default(OverlayCreationParams);
				overlayCreationParams.prefab = overlayEntry.prefab;
				overlayCreationParams.childLocatorEntry = overlayEntry.hudChildName;
				OverlayController item = HudOverlayManager.AddGlobalOverlay(overlayCreationParams);
				overlayControllerList.Add(item);
			}
		}

		public void PlayBeginSound()
		{
			Util.PlaySound(beginSoundString, RoR2Application.instance.gameObject);
		}

		public void PlayAllEnemiesDefeatedSound()
		{
			hasPlayedEnemiesDefeatedSound = true;
			Util.PlaySound(onAllEnemiesDefeatedSoundString, RoR2Application.instance.gameObject);
		}

		public int GetSquadCount()
		{
			if (NetworkServer.active)
			{
				if ((bool)combatSquad)
				{
					return combatSquad.memberCount;
				}
				return 0;
			}
			return squadCount;
		}

		public virtual float GetNormalizedProgress()
		{
			if (totalWaveCredits != 0f)
			{
				return totalCreditsSpent / totalWaveCredits;
			}
			return 1f;
		}

		public virtual bool HasFullProgress()
		{
			return totalCreditsSpent >= totalWaveCredits;
		}

		[Server]
		public virtual void ForceFinish()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::ForceFinish()' called on client");
				return;
			}
			KillSquad();
			if ((bool)combatDirector)
			{
				combatDirector.monsterCredit = 0f;
			}
			MarkAsFinished();
		}

		[Server]
		private void KillSquad()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::KillSquad()' called on client");
			}
			else
			{
				if (!combatSquad)
				{
					return;
				}
				foreach (CharacterMaster item in new List<CharacterMaster>(combatSquad.readOnlyMembersList))
				{
					item.TrueKill();
				}
			}
		}

		[Server]
		protected void MarkAsFinished()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::MarkAsFinished()' called on client");
				return;
			}
			isFinished = true;
			OnFinishedServer();
		}

		[Server]
		protected void StartTimer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::StartTimer()' called on client");
				return;
			}
			Network_isTimerActive = true;
			Network_timerStart = Run.instance.GetRunStopwatch();
		}

		[Server]
		protected virtual void OnAllEnemiesDefeatedServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::OnAllEnemiesDefeatedServer()' called on client");
				return;
			}
			DropRewards();
			this.onAllEnemiesDefeatedServer?.Invoke(this);
		}

		[Server]
		protected virtual void OnTimerExpire()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::OnTimerExpire()' called on client");
			}
			else
			{
				MarkAsFinished();
			}
		}

		[Server]
		protected virtual void OnFinishedServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::OnFinishedServer()' called on client");
			}
			else
			{
				if (!convertGoldOnWaveFinish)
				{
					return;
				}
				ReadOnlyCollection<PlayerCharacterMasterController> instances = PlayerCharacterMasterController.instances;
				for (int i = 0; i < instances.Count; i++)
				{
					CharacterMaster component = instances[i].gameObject.GetComponent<CharacterMaster>();
					uint num = Math.Max(component.money, (uint)Mathf.CeilToInt(component.money));
					ulong num2 = (ulong)((float)num * goldToExpConversionRatio / (float)instances.Count);
					component.money -= num;
					GameObject bodyObject = component.GetBodyObject();
					if ((bool)bodyObject)
					{
						ExperienceManager.instance.AwardExperience(base.transform.position, bodyObject.GetComponent<CharacterBody>(), num2);
					}
					else
					{
						TeamManager.instance.GiveTeamExperience(component.teamIndex, num2);
					}
				}
			}
		}

		private void FixedUpdate()
		{
			if (haveAllEnemiesBeenDefeated && !hasPlayedEnemiesDefeatedSound)
			{
				PlayAllEnemiesDefeatedSound();
				if (waveIndex % clearMemoryEveryXRounds == 0)
				{
					Resources.UnloadUnusedAssets();
				}
			}
			if (NetworkServer.active)
			{
				if ((bool)combatDirector)
				{
					NetworksquadCount = GetSquadCount();
					Network_totalCreditsSpent = combatDirector.totalCreditsSpent;
				}
				if (!isFinished)
				{
					if ((bool)combatSquad && combatSquad.memberCount == 0 && !haveAllEnemiesBeenDefeated)
					{
						Network_failsafeTimer = _failsafeTimer + Time.fixedDeltaTime;
						if (_failsafeTimer > secondsBeforeFailsafe)
						{
							UnityEngine.Debug.LogError($"Failsafe detected!  Ending wave {waveIndex}");
							totalWaveCredits = 0f;
							if ((bool)combatDirector)
							{
								combatDirector.monsterCredit = 0f;
							}
						}
					}
					else
					{
						Network_failsafeTimer = 0f;
					}
					if (isInSuddenDeath)
					{
						if (!hasNotifiedSuddenDeath)
						{
							if (!string.IsNullOrEmpty(suddenDeathChatToken))
							{
								Chat.SendBroadcastChat(new Chat.SimpleChatMessage
								{
									baseToken = suddenDeathChatToken
								});
							}
							hasNotifiedSuddenDeath = true;
						}
						Network_zoneRadiusPercentage = Math.Max(0f, _zoneRadiusPercentage - suddenDeathRadiusConstrictingPerSecond * Time.fixedDeltaTime);
					}
					else
					{
						Network_zoneRadiusPercentage = 1f;
					}
					if (!isTimerActive)
					{
						if ((bool)combatDirector)
						{
							if (combatDirector.totalCreditsSpent < totalWaveCredits)
							{
								if (combatSquad.memberCount < maxSquadSize)
								{
									float num = Time.fixedDeltaTime * creditsPerSecond;
									combatDirector.monsterCredit += num;
								}
							}
							else
							{
								if (_suddenDeathTimerStart == 0f)
								{
									Network_suddenDeathTimerStart = Run.instance.GetRunStopwatch();
								}
								combatDirector.monsterCredit = 0f;
								if (combatSquad.memberCount == 0)
								{
									if (squadDefeatTimer <= 0f)
									{
										NetworkhaveAllEnemiesBeenDefeated = true;
										StartTimer();
										OnAllEnemiesDefeatedServer();
									}
									else
									{
										squadDefeatTimer -= Time.fixedDeltaTime;
									}
								}
							}
						}
					}
					else
					{
						Network_zoneRadiusPercentage = 1f;
						if (!hasTimerExpired && secondsRemaining <= 0f)
						{
							hasTimerExpired = true;
							OnTimerExpire();
						}
					}
				}
				else
				{
					Network_zoneRadiusPercentage = 1f;
				}
			}
			if (hasEnabledEnemyIndicators || !combatSquad || !HasFullProgress())
			{
				return;
			}
			hasEnabledEnemyIndicators = true;
			foreach (CharacterMaster readOnlyMembers in combatSquad.readOnlyMembersList)
			{
				RequestIndicatorForMaster(readOnlyMembers);
			}
		}

		private void OnDestroy()
		{
			if ((bool)uiInstance)
			{
				UnityEngine.Object.Destroy(uiInstance);
			}
			foreach (OverlayController overlayController in overlayControllerList)
			{
				HudOverlayManager.RemoveGlobalOverlay(overlayController);
			}
		}

		private void OnEnable()
		{
			if ((bool)combatSquad)
			{
				combatSquad.onMemberDiscovered += OnCombatSquadMemberDiscovered;
			}
			squadDefeatTimer = squadDefeatGracePeriod;
		}

		private void OnDisable()
		{
			if ((bool)combatSquad)
			{
				combatSquad.onMemberDiscovered -= OnCombatSquadMemberDiscovered;
			}
		}

		protected virtual void OnCombatSquadMemberDiscovered(CharacterMaster master)
		{
			if (hasEnabledEnemyIndicators)
			{
				RequestIndicatorForMaster(master);
			}
			squadDefeatTimer = squadDefeatGracePeriod;
			if (NetworkServer.active)
			{
				master.inventory.AddItemsFrom(enemyInventory);
			}
			master.isBoss = isBossWave;
		}

		protected virtual void RequestIndicatorForMaster(CharacterMaster master)
		{
			GameObject bodyObject = master.GetBodyObject();
			if ((bool)bodyObject)
			{
				TeamComponent component = bodyObject.GetComponent<TeamComponent>();
				if ((bool)component)
				{
					component.RequestDefaultIndicator(defaultEnemyIndicatorPrefab);
				}
			}
		}

		[Server]
		private void DropRewards()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InfiniteTowerWaveController::DropRewards()' called on client");
				return;
			}
			int participatingPlayerCount = Run.instance.participatingPlayerCount;
			if (participatingPlayerCount > 0 && (bool)spawnTarget && (bool)rewardDropTable)
			{
				int num = participatingPlayerCount;
				float angle = 360f / (float)num;
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.up) * (UnityEngine.Vector3.up * 40f + UnityEngine.Vector3.forward * 5f);
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(angle, UnityEngine.Vector3.up);
				UnityEngine.Vector3 position = spawnTarget.transform.position + rewardOffset;
				int num2 = 0;
				while (num2 < num)
				{
					GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
					createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(rewardDisplayTier);
					createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromDropTable(rewardOptionCount, rewardDropTable, rng);
					createPickupInfo.rotation = UnityEngine.Quaternion.identity;
					createPickupInfo.prefabOverride = rewardPickupPrefab;
					createPickupInfo.position = position;
					GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo;
					PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, vector);
					num2++;
					vector = quaternion * vector;
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_totalWaveCredits);
				writer.Write(_totalCreditsSpent);
				writer.Write(_timerStart);
				writer.Write(_failsafeTimer);
				writer.Write(_suddenDeathTimerStart);
				writer.Write(_isFinished);
				writer.Write(_isTimerActive);
				writer.Write(_zoneRadiusPercentage);
				writer.WritePackedUInt32((uint)waveIndex);
				writer.WritePackedUInt32((uint)squadCount);
				writer.Write(haveAllEnemiesBeenDefeated);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_totalWaveCredits);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_totalCreditsSpent);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_timerStart);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_failsafeTimer);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_suddenDeathTimerStart);
			}
			if ((base.syncVarDirtyBits & 0x20u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_isFinished);
			}
			if ((base.syncVarDirtyBits & 0x40u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_isTimerActive);
			}
			if ((base.syncVarDirtyBits & 0x80u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_zoneRadiusPercentage);
			}
			if ((base.syncVarDirtyBits & 0x100u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)waveIndex);
			}
			if ((base.syncVarDirtyBits & 0x200u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)squadCount);
			}
			if ((base.syncVarDirtyBits & 0x400u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(haveAllEnemiesBeenDefeated);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_totalWaveCredits = reader.ReadSingle();
				_totalCreditsSpent = reader.ReadSingle();
				_timerStart = reader.ReadSingle();
				_failsafeTimer = reader.ReadSingle();
				_suddenDeathTimerStart = reader.ReadSingle();
				_isFinished = reader.ReadBoolean();
				_isTimerActive = reader.ReadBoolean();
				_zoneRadiusPercentage = reader.ReadSingle();
				waveIndex = (int)reader.ReadPackedUInt32();
				squadCount = (int)reader.ReadPackedUInt32();
				haveAllEnemiesBeenDefeated = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_totalWaveCredits = reader.ReadSingle();
			}
			if (((uint)num & 2u) != 0)
			{
				_totalCreditsSpent = reader.ReadSingle();
			}
			if (((uint)num & 4u) != 0)
			{
				_timerStart = reader.ReadSingle();
			}
			if (((uint)num & 8u) != 0)
			{
				_failsafeTimer = reader.ReadSingle();
			}
			if (((uint)num & 0x10u) != 0)
			{
				_suddenDeathTimerStart = reader.ReadSingle();
			}
			if (((uint)num & 0x20u) != 0)
			{
				_isFinished = reader.ReadBoolean();
			}
			if (((uint)num & 0x40u) != 0)
			{
				_isTimerActive = reader.ReadBoolean();
			}
			if (((uint)num & 0x80u) != 0)
			{
				_zoneRadiusPercentage = reader.ReadSingle();
			}
			if (((uint)num & 0x100u) != 0)
			{
				waveIndex = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x200u) != 0)
			{
				squadCount = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x400u) != 0)
			{
				haveAllEnemiesBeenDefeated = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class InputBankTest : MonoBehaviour
	{
		private struct CachedRaycastInfo
		{
			public float time;

			public float fixedTime;

			public bool didHit;

			public RaycastHit hitInfo;

			public float maxDistance;

			public static readonly CachedRaycastInfo empty = new CachedRaycastInfo
			{
				time = float.NegativeInfinity,
				fixedTime = float.NegativeInfinity,
				didHit = false,
				maxDistance = 0f
			};
		}

		public struct ButtonState
		{
			public bool down;

			public bool wasDown;

			public bool hasPressBeenClaimed;

			public bool justReleased
			{
				get
				{
					if (!down)
					{
						return wasDown;
					}
					return false;
				}
			}

			public bool justPressed
			{
				get
				{
					if (down)
					{
						return !wasDown;
					}
					return false;
				}
			}

			public void PushState(bool newState)
			{
				hasPressBeenClaimed &= newState;
				wasDown = down;
				down = newState;
			}
		}

		private CharacterBody characterBody;

		private UnityEngine.Vector3 _aimDirection;

		private float lastRaycastTime = float.NegativeInfinity;

		private float lastFixedRaycastTime = float.NegativeInfinity;

		private bool didLastRaycastHit;

		private RaycastHit lastHitInfo;

		private float lastMaxDistance;

		private CachedRaycastInfo cachedRaycast = CachedRaycastInfo.empty;

		public UnityEngine.Vector3 moveVector;

		public ButtonState skill1;

		public ButtonState skill2;

		public ButtonState skill3;

		public ButtonState skill4;

		public ButtonState interact;

		public ButtonState jump;

		public ButtonState sprint;

		public ButtonState activateEquipment;

		public ButtonState ping;

		public ButtonState rawMoveUp;

		public ButtonState rawMoveDown;

		public ButtonState rawMoveRight;

		public ButtonState rawMoveLeft;

		public UnityEngine.Vector2 rawMoveData;

		public UnityEngine.Vector3 aimDirection
		{
			get
			{
				if (!(_aimDirection != UnityEngine.Vector3.zero))
				{
					return base.transform.forward;
				}
				return _aimDirection;
			}
			set
			{
				_aimDirection = value.normalized;
			}
		}

		public UnityEngine.Vector3 aimOrigin
		{
			get
			{
				if (!characterBody.aimOriginTransform)
				{
					return base.transform.position;
				}
				return characterBody.aimOriginTransform.position;
			}
		}

		public int emoteRequest { get; set; } = -1;


		public Ray GetAimRay()
		{
			return new Ray(aimOrigin, aimDirection);
		}

		public bool GetAimRaycast(float maxDistance, out RaycastHit hitInfo)
		{
			float time = Time.time;
			float fixedTime = Time.fixedTime;
			if (!cachedRaycast.time.Equals(time) || !cachedRaycast.fixedTime.Equals(fixedTime) || (!(cachedRaycast.maxDistance >= maxDistance) && !cachedRaycast.didHit))
			{
				float extraRaycastDistance = 0f;
				Ray ray = CameraRigController.ModifyAimRayIfApplicable(GetAimRay(), base.gameObject, out extraRaycastDistance);
				cachedRaycast = CachedRaycastInfo.empty;
				cachedRaycast.time = time;
				cachedRaycast.fixedTime = fixedTime;
				cachedRaycast.maxDistance = maxDistance;
				cachedRaycast.didHit = Util.CharacterRaycast(base.gameObject, ray, maxDistance: maxDistance + extraRaycastDistance, layerMask: (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, hitInfo: out cachedRaycast.hitInfo, queryTriggerInteraction: QueryTriggerInteraction.Ignore);
			}
			bool flag = cachedRaycast.didHit;
			hitInfo = cachedRaycast.hitInfo;
			if (flag && hitInfo.distance > maxDistance)
			{
				flag = false;
				hitInfo = default(RaycastHit);
			}
			return flag;
		}

		public void SetRawMoveStates(UnityEngine.Vector2 _rawMoveData)
		{
			float num = 0.9f;
			float num2 = 0.1f;
			rawMoveUp.PushState((_rawMoveData.y > num && !rawMoveUp.down) || (_rawMoveData.y > num2 && rawMoveUp.down));
			rawMoveDown.PushState((_rawMoveData.y < 0f - num && !rawMoveDown.down) || (_rawMoveData.y < 0f - num2 && rawMoveDown.down));
			rawMoveLeft.PushState((_rawMoveData.x < 0f - num && !rawMoveLeft.down) || (_rawMoveData.x < 0f - num2 && rawMoveLeft.down));
			rawMoveRight.PushState((_rawMoveData.x > num && !rawMoveRight.down) || (_rawMoveData.x > num2 && rawMoveRight.down));
			rawMoveData = _rawMoveData;
		}

		public bool CheckAnyButtonDown()
		{
			if (!skill1.down && !skill2.down && !skill3.down && !skill4.down && !interact.down && !jump.down && !sprint.down && !activateEquipment.down)
			{
				return ping.down;
			}
			return true;
		}

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
		}

		private void Start()
		{
			if (characterBody.hasEffectiveAuthority)
			{
				if ((bool)characterBody.characterDirection)
				{
					aimDirection = characterBody.characterDirection.forward;
				}
				else
				{
					aimDirection = base.transform.forward;
				}
			}
		}
	}
	public class InputResponse : MonoBehaviour
	{
		public string[] inputActionNames;

		public UnityEvent onPress;

		private void Update()
		{
			foreach (Player player in ReInput.players.Players)
			{
				for (int i = 0; i < inputActionNames.Length; i++)
				{
					if (player.GetButtonDown(inputActionNames[i]))
					{
						onPress?.Invoke();
						break;
					}
				}
			}
		}
	}
	public class InstantiatePrefabBehavior : MonoBehaviour
	{
		[Tooltip("The prefab to instantiate.")]
		public GameObject prefab;

		[Tooltip("The object upon which the prefab will be positioned.")]
		public Transform targetTransform;

		[Tooltip("The transform upon which to instantiate the prefab.")]
		public bool copyTargetRotation;

		[Tooltip("Whether or not to parent the instantiated prefab to the specified transform.")]
		public bool parentToTarget;

		[Tooltip("Whether or not this is a networked prefab. If so, this will only run on the server, and will be spawned over the network.")]
		public bool networkedPrefab;

		[Tooltip("Whether or not to instantiate this prefab. If so, this will only run on the server, and will be spawned over the network.")]
		public bool instantiateOnStart = true;

		[Tooltip("Whether or not to force this prefab to be active, even if the prefab itself is inactive.")]
		public bool forceActivate;

		public void Start()
		{
			if (instantiateOnStart)
			{
				InstantiatePrefab();
			}
		}

		public void InstantiatePrefab()
		{
			if (!networkedPrefab || NetworkServer.active)
			{
				UnityEngine.Vector3 position = (targetTransform ? targetTransform.position : UnityEngine.Vector3.zero);
				UnityEngine.Quaternion rotation = (copyTargetRotation ? targetTransform.rotation : UnityEngine.Quaternion.identity);
				Transform parent = (parentToTarget ? targetTransform : null);
				GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position, rotation, parent);
				if (forceActivate)
				{
					gameObject.SetActive(value: true);
				}
				if (networkedPrefab)
				{
					NetworkServer.Spawn(gameObject);
				}
			}
		}
	}
	public class InteractableSpawner : NetworkBehaviour
	{
		[SerializeField]
		[Tooltip("The selection of director cards to use when spawning stuff")]
		private DirectorCardCategorySelection interactableCards;

		[Tooltip("How much stuff should this thing spawn")]
		[SerializeField]
		private float creditsToSpawn;

		private List<GameObject> spawnedObjects = new List<GameObject>();

		[Server]
		public void Spawn(Xoroshiro128Plus rng)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InteractableSpawner::Spawn(Xoroshiro128Plus)' called on client");
				return;
			}
			WeightedSelection<DirectorCard> weightedSelection = interactableCards.GenerateDirectorCardWeightedSelection();
			float num = creditsToSpawn;
			while (num > 0f)
			{
				DirectorCard directorCard = weightedSelection.Evaluate(rng.nextNormalizedFloat);
				if (directorCard == null)
				{
					break;
				}
				if (!directorCard.IsAvailable())
				{
					num -= 1f;
					continue;
				}
				num -= (float)directorCard.cost;
				for (int i = 0; i < 10; i++)
				{
					DirectorPlacementRule placementRule = new DirectorPlacementRule
					{
						placementMode = DirectorPlacementRule.PlacementMode.Random
					};
					GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(directorCard.spawnCard, placementRule, rng));
					if ((bool)gameObject)
					{
						PurchaseInteraction component = gameObject.GetComponent<PurchaseInteraction>();
						if ((bool)component && component.costType == CostTypeIndex.Money)
						{
							component.Networkcost = Run.instance.GetDifficultyScaledCost(component.cost);
						}
						spawnedObjects.Add(gameObject);
						break;
					}
				}
			}
		}

		[Server]
		public void DestroySpawnedInteractables()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.InteractableSpawner::DestroySpawnedInteractables()' called on client");
				return;
			}
			foreach (GameObject spawnedObject in spawnedObjects)
			{
				UnityEngine.Object.Destroy(spawnedObject);
			}
			spawnedObjects.Clear();
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(Interactor))]
	[RequireComponent(typeof(InputBankTest))]
	public class InteractionDriver : MonoBehaviour, ILifeBehavior
	{
		public bool highlightInteractor;

		public UnityEngine.Vector3 aimOffset;

		public bool useAimOffset;

		public bool drawDebugRay;

		public float debugRayLength = 5f;

		private bool inputReceived;

		private NetworkIdentity networkIdentity;

		private InputBankTest inputBank;

		private CharacterBody characterBody;

		private EquipmentSlot equipmentSlot;

		[NonSerialized]
		public GameObject interactableOverride;

		private const float interactableCooldownDuration = 0.25f;

		private float interactableCooldown;

		private const float interactableCheckCooldownDuration = 0f;

		private float interactableCheckCooldown;

		private GameObject saleStarEffect;

		[NonSerialized]
		public GameObject currentInteractable;

		public Interactor interactor { get; private set; }

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			interactor = GetComponent<Interactor>();
			inputBank = GetComponent<InputBankTest>();
			characterBody = GetComponent<CharacterBody>();
			equipmentSlot = (characterBody ? characterBody.equipmentSlot : null);
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.deltaTime);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			if (networkIdentity.hasAuthority)
			{
				interactableCooldown -= deltaTime;
				interactableCheckCooldown -= deltaTime;
				inputReceived = inputBank.interact.justPressed || (inputBank.interact.down && interactableCooldown <= 0f);
				if (inputBank.interact.justReleased)
				{
					inputReceived = false;
					interactableCooldown = 0f;
				}
				currentInteractable = FindBestInteractableObject();
			}
			if (inputReceived && (bool)currentInteractable)
			{
				interactor.AttemptInteraction(currentInteractable);
				interactableCooldown = 0.25f;
			}
			if ((bool)currentInteractable)
			{
				if (characterBody.inventory.GetItemCount(DLC2Content.Items.LowerPricedChests) > 0)
				{
					PurchaseInteraction component = currentInteractable.GetComponent<PurchaseInteraction>();
					if ((object)component != null && component.saleStarCompatible)
					{
						if ((bool)currentInteractable.GetComponent<PurchaseInteraction>() && currentInteractable.GetComponent<PurchaseInteraction>().CanBeAffordedByInteractor(GetComponent<Interactor>()) && !saleStarEffect)
						{
							saleStarEffect = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/LowerPricedChestsGlow"), currentInteractable.transform.position, UnityEngine.Quaternion.identity, currentInteractable.transform);
						}
						return;
					}
				}
				if ((bool)saleStarEffect)
				{
					UnityEngine.Object.Destroy(saleStarEffect);
				}
			}
			else if ((bool)saleStarEffect)
			{
				UnityEngine.Object.Destroy(saleStarEffect);
			}
		}

		public GameObject FindBestInteractableObject()
		{
			if ((bool)interactableOverride)
			{
				return interactableOverride;
			}
			if (interactableCheckCooldown > 0f)
			{
				return currentInteractable;
			}
			interactableCheckCooldown = 0f;
			float extraRaycastDistance = 0f;
			float num = interactor.maxInteractionDistance;
			if ((bool)equipmentSlot && equipmentSlot.equipmentIndex == RoR2Content.Equipment.Recycle.equipmentIndex)
			{
				num *= 2f;
			}
			UnityEngine.Vector3 vector = inputBank.aimOrigin;
			UnityEngine.Vector3 vector2 = inputBank.aimDirection;
			if (useAimOffset)
			{
				UnityEngine.Vector3 vector3 = vector + vector2 * num;
				vector = inputBank.aimOrigin + aimOffset;
				vector2 = (vector3 - vector) / num;
			}
			Ray originalAimRay = new Ray(vector, vector2);
			if (drawDebugRay)
			{
				UnityEngine.Debug.DrawLine(vector, vector + vector2 * debugRayLength, UnityEngine.Color.green, 0.5f);
			}
			Ray raycastRay = CameraRigController.ModifyAimRayIfApplicable(originalAimRay, base.gameObject, out extraRaycastDistance);
			return interactor.FindBestInteractableObject(raycastRay, num + extraRaycastDistance, originalAimRay.origin, num);
		}

		static InteractionDriver()
		{
			OutlineHighlight.onPreRenderOutlineHighlight = (Action<OutlineHighlight>)Delegate.Combine(OutlineHighlight.onPreRenderOutlineHighlight, new Action<OutlineHighlight>(OnPreRenderOutlineHighlight));
		}

		private static void OnPreRenderOutlineHighlight(OutlineHighlight outlineHighlight)
		{
			if (!outlineHighlight.sceneCamera || !outlineHighlight.sceneCamera.cameraRigController)
			{
				return;
			}
			GameObject target = outlineHighlight.sceneCamera.cameraRigController.target;
			if (!target)
			{
				return;
			}
			InteractionDriver component = target.GetComponent<InteractionDriver>();
			if (!component)
			{
				return;
			}
			GameObject gameObject = component.currentInteractable;
			if (!gameObject)
			{
				return;
			}
			IInteractable component2 = gameObject.GetComponent<IInteractable>();
			Highlight component3 = gameObject.GetComponent<Highlight>();
			if ((bool)component3)
			{
				UnityEngine.Color color = component3.GetColor();
				if (component2 != null && ((MonoBehaviour)component2).isActiveAndEnabled && component2.GetInteractability(component.interactor) == Interactability.ConditionsNotMet)
				{
					color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unaffordable);
				}
				outlineHighlight.highlightQueue.Enqueue(new OutlineHighlight.HighlightInfo
				{
					renderer = component3.targetRenderer,
					color = color * component3.strength
				});
			}
		}

		public void OnDeathStart()
		{
			base.enabled = false;
		}
	}
	public class InteractionProcFilter : MonoBehaviour
	{
		[Tooltip("Whether or not OnInteractionBegin for this object should trigger extra gameplay effects like Fireworks and Squid Polyp.")]
		public bool shouldAllowOnInteractionBeginProc = true;
	}
	public class Interactor : NetworkBehaviour
	{
		public float maxInteractionDistance = 1f;

		private static int kCmdCmdInteract;

		private static int kRpcRpcInteractionResult;

		public GameObject FindBestInteractableObject(Ray raycastRay, float maxRaycastDistance, UnityEngine.Vector3 overlapPosition, float overlapRadius)
		{
			LayerMask interactable = LayerIndex.CommonMasks.interactable;
			if (Physics.Raycast(raycastRay, out var hitInfo, maxRaycastDistance, interactable, QueryTriggerInteraction.Collide) && EntityLocator.HasEntityLocator(hitInfo.collider.gameObject, out var foundLocator))
			{
				GameObject entity = foundLocator.entity;
				IInteractable component = entity.GetComponent<IInteractable>();
				if (component != null && ((MonoBehaviour)component).isActiveAndEnabled && component.GetInteractability(this) != 0)
				{
					entity.GetComponent<ISupportsMultipleInspectZones>()?.SetInspectInfoProvider(foundLocator.EntityZoneIndex);
					return entity;
				}
			}
			Collider[] colliders;
			int num = HGPhysics.OverlapSphere(out colliders, overlapPosition, overlapRadius, interactable, QueryTriggerInteraction.Collide);
			GameObject gameObject = null;
			EntityLocator entityLocator = null;
			float num2 = 0f;
			for (int i = 0; i < num; i++)
			{
				Collider collider = colliders[i];
				if (!EntityLocator.HasEntityLocator(collider.gameObject, out var foundLocator2))
				{
					continue;
				}
				GameObject entity2 = foundLocator2.entity;
				IInteractable component2 = entity2.GetComponent<IInteractable>();
				if (component2 != null && ((MonoBehaviour)component2).isActiveAndEnabled && component2.GetInteractability(this) != 0 && !component2.ShouldIgnoreSpherecastForInteractibility(this))
				{
					float num3 = UnityEngine.Vector3.Dot((collider.transform.position - overlapPosition).normalized, raycastRay.direction);
					if (num3 > num2)
					{
						num2 = num3;
						gameObject = entity2.gameObject;
						entityLocator = foundLocator2;
					}
				}
			}
			HGPhysics.ReturnResults(colliders);
			if ((bool)gameObject)
			{
				gameObject.GetComponent<ISupportsMultipleInspectZones>()?.SetInspectInfoProvider(entityLocator.EntityZoneIndex);
			}
			return gameObject;
		}

		[Command]
		public void CmdInteract(GameObject interactableObject)
		{
			PerformInteraction(interactableObject);
		}

		[Server]
		private void PerformInteraction(GameObject interactableObject)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Interactor::PerformInteraction(UnityEngine.GameObject)' called on client");
			}
			else
			{
				if (!interactableObject)
				{
					return;
				}
				bool flag = false;
				bool anyInteractionSucceeded = false;
				IInteractable[] components = interactableObject.GetComponents<IInteractable>();
				foreach (IInteractable interactable in components)
				{
					Interactability interactability = interactable.GetInteractability(this);
					if (interactability == Interactability.Available)
					{
						interactable.OnInteractionBegin(this);
						GlobalEventManager.instance.OnInteractionBegin(this, interactable, interactableObject);
						anyInteractionSucceeded = true;
					}
					flag = flag || interactability != Interactability.Disabled;
				}
				if (flag)
				{
					CallRpcInteractionResult(anyInteractionSucceeded);
				}
			}
		}

		[ClientRpc]
		private void RpcInteractionResult(bool anyInteractionSucceeded)
		{
			if (!anyInteractionSucceeded && CameraRigController.IsObjectSpectatedByAnyCamera(base.gameObject))
			{
				Util.PlaySound("Play_UI_insufficient_funds", RoR2Application.instance.gameObject);
			}
		}

		public void AttemptInteraction(GameObject interactableObject)
		{
			if (NetworkServer.active)
			{
				PerformInteraction(interactableObject);
			}
			else
			{
				CallCmdInteract(interactableObject);
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdInteract(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdInteract called on client.");
			}
			else
			{
				((Interactor)obj).CmdInteract(reader.ReadGameObject());
			}
		}

		public void CallCmdInteract(GameObject interactableObject)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdInteract called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdInteract(interactableObject);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdInteract);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(interactableObject);
			SendCommandInternal(networkWriter, 0, "CmdInteract");
		}

		protected static void InvokeRpcRpcInteractionResult(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcInteractionResult called on server.");
			}
			else
			{
				((Interactor)obj).RpcInteractionResult(reader.ReadBoolean());
			}
		}

		public void CallRpcInteractionResult(bool anyInteractionSucceeded)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcInteractionResult called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcInteractionResult);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(anyInteractionSucceeded);
			SendRPCInternal(networkWriter, 0, "RpcInteractionResult");
		}

		static Interactor()
		{
			kCmdCmdInteract = 591229007;
			NetworkBehaviour.RegisterCommandDelegate(typeof(Interactor), kCmdCmdInteract, InvokeCmdCmdInteract);
			kRpcRpcInteractionResult = 804118976;
			NetworkBehaviour.RegisterRpcDelegate(typeof(Interactor), kRpcRpcInteractionResult, InvokeRpcRpcInteractionResult);
			NetworkCRC.RegisterBehaviour("Interactor", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class IntroCutsceneController : MonoBehaviour
	{
		private static BoolConVar cvIntroSkip = new BoolConVar("intro_skip", ConVarFlags.Archive, "0", "Whether or not to skip the opening cutscene.");

		private static bool _shouldSkip = false;

		private static bool skipRequested = false;

		public static bool shouldSkip
		{
			get
			{
				if (!_shouldSkip)
				{
					return cvIntroSkip.value;
				}
				return true;
			}
			set
			{
				if (value != _shouldSkip)
				{
					_shouldSkip = value;
					if (_shouldSkip)
					{
						IntroCutsceneController.onShouldSkipEnabled?.Invoke();
					}
				}
			}
		}

		private static event Action onShouldSkipEnabled;

		public void Start()
		{
			RoR2Application.instance.PushThreadPriority(UnityEngine.ThreadPriority.Normal);
			onShouldSkipEnabled += delegate
			{
				if (RoR2Application.loadFinished)
				{
					Finish();
				}
				else
				{
					RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(Finish));
				}
			};
		}

		public void Finish()
		{
			RoR2Application.instance.PopThreadPriority();
			if (!skipRequested)
			{
				if (RoR2Application.loadFinished)
				{
					TransitionToTitle();
				}
				else
				{
					RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(TransitionToTitle));
				}
			}
		}

		public void TransitionToTitle()
		{
			Console.instance.SubmitCmd(null, "set_scene title");
			skipRequested = true;
		}
	}
	public class Inventory : NetworkBehaviour
	{
		private int[] itemStacks = ItemCatalog.RequestItemStackArray();

		public readonly List<ItemIndex> itemAcquisitionOrder = new List<ItemIndex>();

		private const uint itemListDirtyBit = 1u;

		private const uint infusionBonusDirtyBit = 4u;

		private const uint itemAcquisitionOrderDirtyBit = 8u;

		private const uint equipmentDirtyBit = 16u;

		private const uint allDirtyBits = 29u;

		private EquipmentState[] equipmentStateSlots = Array.Empty<EquipmentState>();

		private bool equipmentDisabled;

		[HideInInspector]
		public float beadAppliedHealth;

		[HideInInspector]
		public float beadAppliedShield;

		[HideInInspector]
		public float beadAppliedRegen;

		[HideInInspector]
		public float beadAppliedDamage;

		public static readonly Func<ItemIndex, bool> defaultItemCopyFilterDelegate;

		private static int kRpcRpcItemAdded;

		private static int kRpcRpcClientEquipmentChanged;

		public EquipmentIndex currentEquipmentIndex => currentEquipmentState.equipmentIndex;

		public EquipmentState currentEquipmentState => GetEquipment(activeEquipmentSlot);

		public EquipmentIndex alternateEquipmentIndex => alternateEquipmentState.equipmentIndex;

		public EquipmentState alternateEquipmentState
		{
			get
			{
				for (uint num = 0u; num < GetEquipmentSlotCount(); num++)
				{
					if (num != activeEquipmentSlot)
					{
						return GetEquipment(num);
					}
				}
				return EquipmentState.empty;
			}
		}

		public byte activeEquipmentSlot { get; private set; }

		public uint infusionBonus { get; private set; }

		private bool spawnedOverNetwork => base.isServer;

		public event Action onInventoryChanged;

		public event Action onEquipmentExternalRestockServer;

		public static event Action<Inventory> onInventoryChangedGlobal;

		public static event Action<Inventory, ItemIndex, int> onServerItemGiven;

		public event Action<ItemIndex> onItemAddedClient;

		public event Action<EquipmentIndex, uint> onEquipmentChangedClient;

		private bool SetEquipmentInternal(EquipmentState equipmentState, uint slot)
		{
			if (!Run.instance || Run.instance.IsEquipmentExpansionLocked(equipmentState.equipmentIndex))
			{
				return false;
			}
			if (equipmentStateSlots.Length <= slot)
			{
				int num = equipmentStateSlots.Length;
				Array.Resize(ref equipmentStateSlots, (int)(slot + 1));
				for (int i = num; i < equipmentStateSlots.Length; i++)
				{
					equipmentStateSlots[i] = EquipmentState.empty;
				}
			}
			if (equipmentStateSlots[slot].Equals(equipmentState))
			{
				return false;
			}
			equipmentStateSlots[slot] = equipmentState;
			return true;
		}

		[Server]
		public void SetEquipment(EquipmentState equipmentState, uint slot)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipment(RoR2.EquipmentState,System.UInt32)' called on client");
			}
			else if (SetEquipmentInternal(equipmentState, slot))
			{
				if (NetworkServer.active)
				{
					SetDirtyBit(16u);
				}
				HandleInventoryChanged();
				if (spawnedOverNetwork)
				{
					CallRpcClientEquipmentChanged(equipmentState.equipmentIndex, slot);
				}
			}
		}

		public EquipmentState GetEquipment(uint slot)
		{
			if (slot >= equipmentStateSlots.Length)
			{
				return EquipmentState.empty;
			}
			return equipmentStateSlots[slot];
		}

		[Server]
		public void SetActiveEquipmentSlot(byte slotIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetActiveEquipmentSlot(System.Byte)' called on client");
				return;
			}
			activeEquipmentSlot = slotIndex;
			SetDirtyBit(16u);
			HandleInventoryChanged();
		}

		[Server]
		public void SetEquipmentDisabled(bool _active)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipmentDisabled(System.Boolean)' called on client");
				return;
			}
			equipmentDisabled = _active;
			SetDirtyBit(16u);
			HandleInventoryChanged();
		}

		public bool GetEquipmentDisabled()
		{
			return equipmentDisabled;
		}

		public int GetEquipmentSlotCount()
		{
			return equipmentStateSlots.Length;
		}

		[Server]
		public void SetEquipmentIndex(EquipmentIndex newEquipmentIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipmentIndex(RoR2.EquipmentIndex)' called on client");
			}
			else
			{
				SetEquipmentIndexForSlot(newEquipmentIndex, activeEquipmentSlot);
			}
		}

		[Server]
		public void SetEquipmentIndexForSlot(EquipmentIndex newEquipmentIndex, uint slot)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::SetEquipmentIndexForSlot(RoR2.EquipmentIndex,System.UInt32)' called on client");
			}
			else
			{
				if (Run.instance.IsEquipmentExpansionLocked(newEquipmentIndex))
				{
					return;
				}
				EquipmentState equipment = GetEquipment(slot);
				if (equipment.equipmentIndex != newEquipmentIndex)
				{
					byte charges = equipment.charges;
					Run.FixedTimeStamp chargeFinishTime = equipment.chargeFinishTime;
					if (equipment.equipmentIndex == EquipmentIndex.None && chargeFinishTime.isNegativeInfinity)
					{
						charges = 1;
						chargeFinishTime = Run.FixedTimeStamp.now;
					}
					EquipmentState equipmentState = new EquipmentState(newEquipmentIndex, chargeFinishTime, charges);
					SetEquipment(equipmentState, slot);
				}
			}
		}

		public EquipmentIndex GetEquipmentIndex()
		{
			return currentEquipmentIndex;
		}

		[Server]
		public void DeductEquipmentCharges(byte slot, int deduction)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::DeductEquipmentCharges(System.Byte,System.Int32)' called on client");
				return;
			}
			EquipmentState equipment = GetEquipment(slot);
			byte charges = equipment.charges;
			Run.FixedTimeStamp chargeFinishTime = equipment.chargeFinishTime;
			charges = (byte)((charges >= deduction) ? ((byte)(charges - (byte)deduction)) : 0);
			SetEquipment(new EquipmentState(equipment.equipmentIndex, chargeFinishTime, charges), slot);
			UpdateEquipment();
		}

		public int GetEquipmentRestockableChargeCount(byte slot)
		{
			EquipmentState equipment = GetEquipment(slot);
			if (equipment.equipmentIndex == EquipmentIndex.None)
			{
				return 0;
			}
			return HGMath.ByteSafeSubtract((byte)GetEquipmentSlotMaxCharges(slot), equipment.charges);
		}

		[Server]
		public void RestockEquipmentCharges(byte slot, int amount)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::RestockEquipmentCharges(System.Byte,System.Int32)' called on client");
				return;
			}
			amount = Math.Min(amount, GetEquipmentRestockableChargeCount(slot));
			if (amount > 0)
			{
				EquipmentState equipment = GetEquipment(slot);
				byte charges = HGMath.ByteSafeAdd(equipment.charges, (byte)Math.Min(amount, 255));
				SetEquipment(new EquipmentState(equipment.equipmentIndex, equipment.chargeFinishTime, charges), slot);
				this.onEquipmentExternalRestockServer?.Invoke();
			}
		}

		[Server]
		public void DeductActiveEquipmentCooldown(float seconds)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::DeductActiveEquipmentCooldown(System.Single)' called on client");
				return;
			}
			EquipmentState equipment = GetEquipment(activeEquipmentSlot);
			SetEquipment(new EquipmentState(equipment.equipmentIndex, equipment.chargeFinishTime - seconds, equipment.charges), activeEquipmentSlot);
		}

		public int GetEquipmentSlotMaxCharges(byte slot)
		{
			return Math.Min(1 + GetItemCount(RoR2Content.Items.EquipmentMagazine), 255);
		}

		public int GetActiveEquipmentMaxCharges()
		{
			return GetEquipmentSlotMaxCharges(activeEquipmentSlot);
		}

		[Server]
		private void UpdateEquipment()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::UpdateEquipment()' called on client");
				return;
			}
			Run.FixedTimeStamp now = Run.FixedTimeStamp.now;
			byte b = (byte)Mathf.Min(1 + GetItemCount(RoR2Content.Items.EquipmentMagazine), 255);
			for (uint num = 0u; num < equipmentStateSlots.Length; num++)
			{
				EquipmentState equipmentState = equipmentStateSlots[num];
				if (equipmentState.equipmentIndex == EquipmentIndex.None)
				{
					continue;
				}
				if (equipmentState.charges < b)
				{
					Run.FixedTimeStamp fixedTimeStamp = equipmentState.chargeFinishTime;
					byte b2 = equipmentState.charges;
					if (!fixedTimeStamp.isPositiveInfinity)
					{
						b2++;
					}
					if (fixedTimeStamp.isInfinity)
					{
						fixedTimeStamp = now;
					}
					if (fixedTimeStamp.hasPassed)
					{
						float num2 = equipmentState.equipmentDef.cooldown * CalculateEquipmentCooldownScale();
						SetEquipment(new EquipmentState(equipmentState.equipmentIndex, fixedTimeStamp + num2, b2), num);
					}
				}
				if (equipmentState.charges >= b && !equipmentState.chargeFinishTime.isPositiveInfinity)
				{
					SetEquipment(new EquipmentState(equipmentState.equipmentIndex, Run.FixedTimeStamp.positiveInfinity, b), num);
				}
			}
		}

		private float CalculateEquipmentCooldownScale()
		{
			int itemCount = GetItemCount(RoR2Content.Items.EquipmentMagazine);
			int itemCount2 = GetItemCount(RoR2Content.Items.AutoCastEquipment);
			int itemCount3 = GetItemCount(RoR2Content.Items.BoostEquipmentRecharge);
			float num = Mathf.Pow(0.85f, itemCount);
			if (itemCount2 > 0)
			{
				num *= 0.5f * Mathf.Pow(0.85f, itemCount2 - 1);
			}
			if (itemCount3 > 0)
			{
				num *= Mathf.Pow(0.9f, itemCount3);
			}
			return num;
		}

		private void HandleInventoryChanged()
		{
			this.onInventoryChanged?.Invoke();
			Inventory.onInventoryChangedGlobal?.Invoke(this);
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.deltaTime);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			if (NetworkServer.active)
			{
				UpdateEquipment();
			}
		}

		[Server]
		public void AddInfusionBonus(uint value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddInfusionBonus(System.UInt32)' called on client");
			}
			else if (value != 0)
			{
				infusionBonus += value;
				SetDirtyBit(4u);
				HandleInventoryChanged();
			}
		}

		[Server]
		public void GiveItemString(string itemString)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItemString(System.String)' called on client");
			}
			else
			{
				GiveItem(ItemCatalog.FindItemIndex(itemString));
			}
		}

		[Server]
		public void GiveItemString(string itemString, int count)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItemString(System.String,System.Int32)' called on client");
			}
			else
			{
				GiveItem(ItemCatalog.FindItemIndex(itemString), count);
			}
		}

		[Server]
		public void GiveEquipmentString(string equipmentString)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveEquipmentString(System.String)' called on client");
			}
			else
			{
				SetEquipmentIndex(EquipmentCatalog.FindEquipmentIndex(equipmentString));
			}
		}

		[Server]
		public void GiveRandomItems(int count, bool lunarEnabled, bool voidEnabled)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveRandomItems(System.Int32,System.Boolean,System.Boolean)' called on client");
				return;
			}
			try
			{
				if (count > 0)
				{
					WeightedSelection<List<PickupIndex>> weightedSelection = new WeightedSelection<List<PickupIndex>>();
					weightedSelection.AddChoice(Run.instance.availableTier1DropList, 100f);
					weightedSelection.AddChoice(Run.instance.availableTier2DropList, 60f);
					weightedSelection.AddChoice(Run.instance.availableTier3DropList, 4f);
					if (lunarEnabled)
					{
						weightedSelection.AddChoice(Run.instance.availableLunarItemDropList, 4f);
					}
					if (voidEnabled)
					{
						weightedSelection.AddChoice(Run.instance.availableVoidTier1DropList, 4f);
						weightedSelection.AddChoice(Run.instance.availableVoidTier1DropList, 2.3999999f);
						weightedSelection.AddChoice(Run.instance.availableVoidTier1DropList, 0.16f);
					}
					for (int i = 0; i < count; i++)
					{
						List<PickupIndex> list = weightedSelection.Evaluate(UnityEngine.Random.value);
						GiveItem(PickupCatalog.GetPickupDef(list[UnityEngine.Random.Range(0, list.Count)])?.itemIndex ?? ItemIndex.None);
					}
				}
			}
			catch (ArgumentException)
			{
			}
		}

		[Server]
		public void GiveRandomEquipment()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveRandomEquipment()' called on client");
				return;
			}
			PickupIndex pickupIndex = Run.instance.availableEquipmentDropList[UnityEngine.Random.Range(0, Run.instance.availableEquipmentDropList.Count)];
			SetEquipmentIndex(PickupCatalog.GetPickupDef(pickupIndex)?.equipmentIndex ?? EquipmentIndex.None);
		}

		[Server]
		public void GiveRandomEquipment(Xoroshiro128Plus rng)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveRandomEquipment(Xoroshiro128Plus)' called on client");
				return;
			}
			PickupIndex pickupIndex = rng.NextElementUniform(Run.instance.availableEquipmentDropList);
			SetEquipmentIndex(PickupCatalog.GetPickupDef(pickupIndex)?.equipmentIndex ?? EquipmentIndex.None);
		}

		[Server]
		public void GiveItem(ItemIndex itemIndex, int count = 1)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItem(RoR2.ItemIndex,System.Int32)' called on client");
			}
			else
			{
				if (((bool)Run.instance && Run.instance.IsItemExpansionLocked(itemIndex)) || (uint)itemIndex >= itemStacks.Length || itemIndex == ItemIndex.None)
				{
					return;
				}
				if (count <= 0)
				{
					if (count < 0)
					{
						RemoveItem(itemIndex, -count);
					}
					return;
				}
				SetDirtyBit(1u);
				if ((itemStacks[(int)itemIndex] += count) == count)
				{
					itemAcquisitionOrder.Add(itemIndex);
					SetDirtyBit(8u);
				}
				HandleInventoryChanged();
				Inventory.onServerItemGiven?.Invoke(this, itemIndex, count);
				if (spawnedOverNetwork)
				{
					CallRpcItemAdded(itemIndex);
				}
			}
		}

		[Server]
		public void GiveItem(ItemDef itemDef, int count = 1)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::GiveItem(RoR2.ItemDef,System.Int32)' called on client");
			}
			else
			{
				GiveItem(itemDef?.itemIndex ?? ItemIndex.None, count);
			}
		}

		[ClientRpc]
		private void RpcItemAdded(ItemIndex itemIndex)
		{
			this.onItemAddedClient?.Invoke(itemIndex);
		}

		[ClientRpc]
		private void RpcClientEquipmentChanged(EquipmentIndex newEquipIndex, uint slot)
		{
			this.onEquipmentChangedClient?.Invoke(newEquipIndex, slot);
		}

		[Server]
		public void RemoveItem(ItemIndex itemIndex, int count = 1)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::RemoveItem(RoR2.ItemIndex,System.Int32)' called on client");
			}
			else
			{
				if ((uint)itemIndex >= itemStacks.Length)
				{
					return;
				}
				if (count <= 0)
				{
					if (count < 0)
					{
						GiveItem(itemIndex, -count);
					}
					return;
				}
				int num = itemStacks[(int)itemIndex];
				count = Math.Min(count, num);
				if (count != 0)
				{
					if ((itemStacks[(int)itemIndex] = num - count) == 0)
					{
						itemAcquisitionOrder.Remove(itemIndex);
						SetDirtyBit(8u);
					}
					SetDirtyBit(1u);
					HandleInventoryChanged();
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Server]
		public void RemoveItem(ItemDef itemDef, int count = 1)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::RemoveItem(RoR2.ItemDef,System.Int32)' called on client");
			}
			else
			{
				RemoveItem(itemDef?.itemIndex ?? ItemIndex.None, count);
			}
		}

		[Server]
		public void ResetItem(ItemIndex itemIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::ResetItem(RoR2.ItemIndex)' called on client");
			}
			else if ((uint)itemIndex < itemStacks.Length)
			{
				ref int reference = ref itemStacks[(int)itemIndex];
				if (reference > 0)
				{
					reference = 0;
					SetDirtyBit(1u);
					SetDirtyBit(8u);
					HandleInventoryChanged();
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Server]
		public void ResetItem(ItemDef itemDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::ResetItem(RoR2.ItemDef)' called on client");
			}
			else
			{
				ResetItem(itemDef?.itemIndex ?? ItemIndex.None);
			}
		}

		[Server]
		public void CopyEquipmentFrom(Inventory other)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CopyEquipmentFrom(RoR2.Inventory)' called on client");
				return;
			}
			for (int i = 0; i < other.equipmentStateSlots.Length; i++)
			{
				SetEquipment(new EquipmentState(other.equipmentStateSlots[i].equipmentIndex, Run.FixedTimeStamp.negativeInfinity, 1), (uint)i);
			}
		}

		private static bool DefaultItemCopyFilter(ItemIndex itemIndex)
		{
			return !ItemCatalog.GetItemDef(itemIndex).ContainsTag(ItemTag.CannotCopy);
		}

		[Server]
		public void AddItemsFrom([NotNull] Inventory other)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemsFrom(RoR2.Inventory)' called on client");
			}
			else
			{
				AddItemsFrom(other, defaultItemCopyFilterDelegate);
			}
		}

		[Server]
		public void AddItemsFrom([NotNull] Inventory other, [NotNull] Func<ItemIndex, bool> filter)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemsFrom(RoR2.Inventory,System.Func`2<RoR2.ItemIndex,System.Boolean>)' called on client");
			}
			else
			{
				AddItemsFrom(other.itemStacks, filter);
			}
		}

		[Server]
		public void AddItemsFrom([NotNull] int[] otherItemStacks, [NotNull] Func<ItemIndex, bool> filter)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemsFrom(System.Int32[],System.Func`2<RoR2.ItemIndex,System.Boolean>)' called on client");
				return;
			}
			for (ItemIndex itemIndex = ItemIndex.Count; (int)itemIndex < itemStacks.Length; itemIndex++)
			{
				int num = otherItemStacks[(int)itemIndex];
				if (num > 0 && filter(itemIndex))
				{
					ref int reference = ref itemStacks[(int)itemIndex];
					if (reference == 0)
					{
						itemAcquisitionOrder.Add(itemIndex);
					}
					reference += num;
				}
			}
			SetDirtyBit(1u);
			SetDirtyBit(8u);
			HandleInventoryChanged();
		}

		[Server]
		private void AddItemAcquisitionOrderFrom([NotNull] List<ItemIndex> otherItemAcquisitionOrder)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::AddItemAcquisitionOrderFrom(System.Collections.Generic.List`1<RoR2.ItemIndex>)' called on client");
				return;
			}
			int[] array = ItemCatalog.RequestItemStackArray();
			for (int i = 0; i < itemAcquisitionOrder.Count; i++)
			{
				ItemIndex itemIndex = itemAcquisitionOrder[i];
				array[(int)itemIndex] = 1;
			}
			int j = 0;
			for (int count = otherItemAcquisitionOrder.Count; j < count; j++)
			{
				ItemIndex itemIndex2 = otherItemAcquisitionOrder[j];
				ref int reference = ref array[(int)itemIndex2];
				if (reference == 0)
				{
					reference = 1;
					itemAcquisitionOrder.Add(itemIndex2);
				}
			}
			ItemCatalog.ReturnItemStackArray(array);
		}

		[Server]
		public void CopyItemsFrom([NotNull] Inventory other)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CopyItemsFrom(RoR2.Inventory)' called on client");
			}
			else
			{
				CopyItemsFrom(other, defaultItemCopyFilterDelegate);
			}
		}

		[Server]
		public void CopyItemsFrom([NotNull] Inventory other, [NotNull] Func<ItemIndex, bool> filter)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CopyItemsFrom(RoR2.Inventory,System.Func`2<RoR2.ItemIndex,System.Boolean>)' called on client");
				return;
			}
			itemAcquisitionOrder.Clear();
			int[] array = itemStacks;
			int value = 0;
			ArrayUtils.SetAll(array, in value);
			AddItemsFrom(other);
		}

		[Server]
		public void CleanInventory()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::CleanInventory()' called on client");
				return;
			}
			itemAcquisitionOrder.Clear();
			itemStacks = ItemCatalog.RequestItemStackArray();
			SetDirtyBit(8u);
			SetDirtyBit(1u);
			HandleInventoryChanged();
		}

		[Server]
		public void ShrineRestackInventory([NotNull] Xoroshiro128Plus rng)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Inventory::ShrineRestackInventory(Xoroshiro128Plus)' called on client");
				return;
			}
			List<ItemIndex> list = new List<ItemIndex>();
			bool flag = false;
			foreach (ItemTierDef allItemTierDef in ItemTierCatalog.allItemTierDefs)
			{
				if (!allItemTierDef.canRestack)
				{
					continue;
				}
				int num = 0;
				list.Clear();
				for (int i = 0; i < itemStacks.Length; i++)
				{
					if (itemStacks[i] > 0)
					{
						ItemIndex itemIndex = (ItemIndex)i;
						ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
						if (allItemTierDef.tier == itemDef.tier)
						{
							num += itemStacks[i];
							list.Add(itemIndex);
							itemAcquisitionOrder.Remove(itemIndex);
							ResetItem(itemIndex);
						}
					}
				}
				if (list.Count > 0)
				{
					GiveItem(rng.NextElementUniform(list), num);
					flag = true;
				}
			}
			if (flag)
			{
				SetDirtyBit(8u);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public int GetItemCount(ItemIndex itemIndex)
		{
			return ArrayUtils.GetSafe(itemStacks, (int)itemIndex);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public int GetItemCount(ItemDef itemDef)
		{
			return GetItemCount(itemDef?.itemIndex ?? ItemIndex.None);
		}

		public bool HasAtLeastXTotalItemsOfTier(ItemTier itemTier, int x)
		{
			int num = 0;
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				if (ItemCatalog.GetItemDef(itemIndex).tier == itemTier)
				{
					num += GetItemCount(itemIndex);
					if (num >= x)
					{
						return true;
					}
				}
			}
			return false;
		}

		public int GetTotalItemCountOfTier(ItemTier itemTier)
		{
			int num = 0;
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				if (ItemCatalog.GetItemDef(itemIndex).tier == itemTier)
				{
					num += GetItemCount(itemIndex);
				}
			}
			return num;
		}

		public void WriteItemStacks(int[] output)
		{
			Array.Copy(itemStacks, output, output.Length);
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			byte num = reader.ReadByte();
			bool flag = (num & 1) != 0;
			bool flag2 = (num & 4) != 0;
			bool flag3 = (num & 8) != 0;
			bool flag4 = (num & 0x10) != 0;
			if (flag)
			{
				reader.ReadItemStacks(itemStacks);
			}
			if (flag2)
			{
				infusionBonus = reader.ReadPackedUInt32();
			}
			if (flag3)
			{
				uint num2 = reader.ReadPackedUInt32();
				itemAcquisitionOrder.Clear();
				itemAcquisitionOrder.Capacity = (int)num2;
				for (uint num3 = 0u; num3 < num2; num3++)
				{
					ItemIndex item = (ItemIndex)reader.ReadPackedUInt32();
					itemAcquisitionOrder.Add(item);
				}
			}
			if (flag4)
			{
				equipmentDisabled = reader.ReadBoolean();
				uint num4 = reader.ReadByte();
				for (uint num5 = 0u; num5 < num4; num5++)
				{
					SetEquipmentInternal(EquipmentState.Deserialize(reader), num5);
				}
				activeEquipmentSlot = reader.ReadByte();
			}
			if (flag || flag4 || flag2)
			{
				HandleInventoryChanged();
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 29u;
			}
			for (int i = 0; i < equipmentStateSlots.Length; i++)
			{
				if (equipmentStateSlots[i].dirty)
				{
					num |= 0x10u;
					break;
				}
			}
			bool num2 = (num & 1) != 0;
			bool flag = (num & 4) != 0;
			bool flag2 = (num & 8) != 0;
			bool flag3 = (num & 0x10) != 0;
			writer.Write((byte)num);
			if (num2)
			{
				writer.WriteItemStacks(itemStacks);
			}
			if (flag)
			{
				writer.WritePackedUInt32(infusionBonus);
			}
			if (flag2)
			{
				int count = itemAcquisitionOrder.Count;
				writer.WritePackedUInt32((uint)count);
				for (int j = 0; j < count; j++)
				{
					writer.WritePackedUInt32((uint)itemAcquisitionOrder[j]);
				}
			}
			if (flag3)
			{
				writer.Write(equipmentDisabled);
				writer.Write((byte)equipmentStateSlots.Length);
				for (int k = 0; k < equipmentStateSlots.Length; k++)
				{
					EquipmentState.Serialize(writer, equipmentStateSlots[k]);
				}
				writer.Write(activeEquipmentSlot);
			}
			if (!initialState)
			{
				for (int l = 0; l < equipmentStateSlots.Length; l++)
				{
					equipmentStateSlots[l].dirty = false;
				}
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		static Inventory()
		{
			defaultItemCopyFilterDelegate = DefaultItemCopyFilter;
			kRpcRpcItemAdded = 1978705787;
			NetworkBehaviour.RegisterRpcDelegate(typeof(Inventory), kRpcRpcItemAdded, InvokeRpcRpcItemAdded);
			kRpcRpcClientEquipmentChanged = 1435548707;
			NetworkBehaviour.RegisterRpcDelegate(typeof(Inventory), kRpcRpcClientEquipmentChanged, InvokeRpcRpcClientEquipmentChanged);
			NetworkCRC.RegisterBehaviour("Inventory", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcItemAdded(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcItemAdded called on server.");
			}
			else
			{
				((Inventory)obj).RpcItemAdded((ItemIndex)reader.ReadInt32());
			}
		}

		protected static void InvokeRpcRpcClientEquipmentChanged(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcClientEquipmentChanged called on server.");
			}
			else
			{
				((Inventory)obj).RpcClientEquipmentChanged((EquipmentIndex)reader.ReadInt32(), reader.ReadPackedUInt32());
			}
		}

		public void CallRpcItemAdded(ItemIndex itemIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcItemAdded called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcItemAdded);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)itemIndex);
			SendRPCInternal(networkWriter, 0, "RpcItemAdded");
		}

		public void CallRpcClientEquipmentChanged(EquipmentIndex newEquipIndex, uint slot)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcClientEquipmentChanged called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcClientEquipmentChanged);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)newEquipIndex);
			networkWriter.WritePackedUInt32(slot);
			SendRPCInternal(networkWriter, 0, "RpcClientEquipmentChanged");
		}

		public override void PreStartClient()
		{
		}
	}
	public struct EquipmentState : IEquatable<EquipmentState>
	{
		public readonly EquipmentIndex equipmentIndex;

		public readonly Run.FixedTimeStamp chargeFinishTime;

		public readonly byte charges;

		public bool isDisabled;

		public bool dirty;

		[CanBeNull]
		public readonly EquipmentDef equipmentDef;

		public static readonly EquipmentState empty = new EquipmentState(EquipmentIndex.None, Run.FixedTimeStamp.negativeInfinity, 0);

		public bool isPerfomingRecharge => !chargeFinishTime.isPositiveInfinity;

		public EquipmentState(EquipmentIndex equipmentIndex, Run.FixedTimeStamp chargeFinishTime, byte charges, bool isDisabled = false)
		{
			this.equipmentIndex = equipmentIndex;
			this.chargeFinishTime = chargeFinishTime;
			this.charges = charges;
			this.isDisabled = isDisabled;
			dirty = true;
			equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
		}

		public bool Equals(EquipmentState other)
		{
			if (equipmentIndex == other.equipmentIndex && chargeFinishTime.Equals(other.chargeFinishTime))
			{
				return charges == other.charges;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is EquipmentState)
			{
				return Equals((EquipmentState)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((int)equipmentIndex * 397) ^ chargeFinishTime.GetHashCode();
		}

		public static EquipmentState Deserialize(NetworkReader reader)
		{
			EquipmentIndex num = reader.ReadEquipmentIndex();
			Run.FixedTimeStamp fixedTimeStamp = reader.ReadFixedTimeStamp();
			byte b = reader.ReadByte();
			return new EquipmentState(num, fixedTimeStamp, b);
		}

		public static void Serialize(NetworkWriter writer, EquipmentState equipmentState)
		{
			writer.Write(equipmentState.equipmentIndex);
			writer.Write(equipmentState.chargeFinishTime);
			writer.Write(equipmentState.charges);
		}
	}
	public interface IPainAnimationHandler
	{
		void HandlePain(float damage, UnityEngine.Vector3 position);
	}
	public interface IPhysMotor
	{
		float mass { get; }

		UnityEngine.Vector3 velocity { get; }

		UnityEngine.Vector3 velocityAuthority { get; set; }

		void ApplyForceImpulse(in PhysForceInfo physForceInfo);
	}
	public interface ITeleportHandler : IEventSystemHandler
	{
		void OnTeleport(UnityEngine.Vector3 oldPosition, UnityEngine.Vector3 newPosition);
	}
	public class AffixAurelioniteBehavior : CharacterBody.ItemBehavior
	{
		private float timer;

		private float duration = 20f;

		private float durationModifier = 5f;

		public int goldTransfer = 25;

		private void Start()
		{
			if (NetworkServer.active)
			{
				goldTransfer = Run.instance.GetDifficultyScaledCost(goldTransfer);
			}
			timer = UnityEngine.Random.Range(5f, 15f);
		}

		private void Update()
		{
			if (NetworkServer.active)
			{
				timer -= Time.deltaTime;
				if (timer <= 0f && stack > 0)
				{
					timer = duration;
					AurelioniteBlessing();
				}
			}
		}

		private void AurelioniteBlessing()
		{
			body.AddTimedBuff(DLC2Content.Buffs.AurelioniteBlessing, 5f);
		}

		private void OnDisable()
		{
			if (body.HasBuff(DLC2Content.Buffs.AurelioniteBlessing))
			{
				body.RemoveBuff(DLC2Content.Buffs.AurelioniteBlessing);
			}
		}
	}
	public class AffixBeadBehavior : CharacterBody.ItemBehavior
	{
		private GameObject affixBeadWard;

		public GameObject affixBeadWardReference;

		private GameObject beadHolderVFX;

		public GameObject beadHolderVFXReference;

		private void Update()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			bool flag = stack > 0;
			if ((bool)affixBeadWard != flag)
			{
				if (flag)
				{
					affixBeadWard = UnityEngine.Object.Instantiate(affixBeadWardReference);
					affixBeadWard.GetComponent<TeamFilter>().teamIndex = body.teamComponent.teamIndex;
					affixBeadWard.GetComponent<BuffWard>().Networkradius = 30f + body.radius;
					affixBeadWard.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(body.gameObject);
					beadHolderVFX = UnityEngine.Object.Instantiate(beadHolderVFXReference);
					beadHolderVFX.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(body.gameObject, "Head");
					beadHolderVFX.transform.localScale *= body.modelLocator.modelScaleCompensation;
				}
				else
				{
					UnityEngine.Object.Destroy(affixBeadWard);
					affixBeadWard = null;
					UnityEngine.Object.Destroy(beadHolderVFX);
					beadHolderVFX = null;
				}
			}
		}

		private void OnEnable()
		{
			beadHolderVFXReference = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC2/Elites/EliteBead/EliteBeadFire.prefab").WaitForCompletion();
			affixBeadWardReference = Addressables.LoadAssetAsync<GameObject>("RoR2/DLC2/Elites/EliteBead/AffixBeadWard.prefab").WaitForCompletion();
		}

		private void OnDisable()
		{
			if ((bool)affixBeadWard)
			{
				UnityEngine.Object.Destroy(affixBeadWard);
			}
			if ((bool)beadHolderVFX)
			{
				UnityEngine.Object.Destroy(beadHolderVFX);
			}
		}
	}
	public class AffixEarthBehavior : CharacterBody.ItemBehavior
	{
		private const float baseOrbitDegreesPerSecond = 90f;

		private const float baseOrbitRadius = 3f;

		private const string projectilePath = "Prefabs/Projectiles/AffixEarthProjectile";

		private GameObject affixEarthAttachment;

		private GameObject projectilePrefab;

		private int maxProjectiles;

		private static GameObject attachmentPrefab;

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("112bf5913df2135478a9785e0bc18477");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				attachmentPrefab = x.Result;
			};
		}

		private void Start()
		{
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			bool flag = stack > 0;
			if ((bool)affixEarthAttachment != flag)
			{
				if (flag)
				{
					affixEarthAttachment = UnityEngine.Object.Instantiate(attachmentPrefab);
					affixEarthAttachment.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(body.gameObject);
				}
				else
				{
					UnityEngine.Object.Destroy(affixEarthAttachment);
					affixEarthAttachment = null;
				}
			}
		}

		private void OnDisable()
		{
			if ((bool)affixEarthAttachment)
			{
				UnityEngine.Object.Destroy(affixEarthAttachment);
			}
		}
	}
	public class AffixVoidBehavior : CharacterBody.ItemBehavior
	{
		private const string sdStateMachineName = "Weapon";

		private bool wasVoidBody;

		private EntityStateMachine sdStateMachine;

		private HealthComponent healthComponent;

		private bool hasEffectiveAuthority;

		private bool hasBegunSelfDestruct;

		private void Awake()
		{
			base.enabled = false;
			sdStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Weapon");
			healthComponent = GetComponent<HealthComponent>();
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
			hasBegunSelfDestruct = false;
		}

		private void OnEnable()
		{
			if ((bool)body)
			{
				wasVoidBody = (body.bodyFlags & CharacterBody.BodyFlags.Void) != 0;
				body.bodyFlags |= CharacterBody.BodyFlags.Void;
			}
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				if (body.HasBuff(DLC1Content.Buffs.BearVoidReady))
				{
					body.RemoveBuff(DLC1Content.Buffs.BearVoidReady);
				}
				if (body.HasBuff(DLC1Content.Buffs.BearVoidCooldown))
				{
					body.RemoveBuff(DLC1Content.Buffs.BearVoidCooldown);
				}
				if (!wasVoidBody)
				{
					body.bodyFlags &= ~CharacterBody.BodyFlags.Void;
				}
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active && (bool)body && !body.HasBuff(DLC1Content.Buffs.BearVoidReady) && !body.HasBuff(DLC1Content.Buffs.BearVoidCooldown))
			{
				body.AddBuff(DLC1Content.Buffs.BearVoidReady);
			}
		}
	}
	public class BearVoidBehavior : CharacterBody.ItemBehavior
	{
		private void Awake()
		{
			base.enabled = false;
		}

		private void OnEnable()
		{
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				if (body.HasBuff(DLC1Content.Buffs.BearVoidReady))
				{
					body.RemoveBuff(DLC1Content.Buffs.BearVoidReady);
				}
				if (body.HasBuff(DLC1Content.Buffs.BearVoidCooldown))
				{
					body.RemoveBuff(DLC1Content.Buffs.BearVoidCooldown);
				}
			}
		}

		private void FixedUpdate()
		{
			if ((bool)body && !body.HasBuff(DLC1Content.Buffs.BearVoidReady) && !body.HasBuff(DLC1Content.Buffs.BearVoidCooldown))
			{
				body.AddBuff(DLC1Content.Buffs.BearVoidReady);
			}
		}
	}
	public class DroneWeaponsBehavior : CharacterBody.ItemBehavior
	{
		private const float display2Chance = 0.1f;

		private int previousStack;

		private CharacterSpawnCard droneSpawnCard;

		private Xoroshiro128Plus rng;

		private DirectorPlacementRule placementRule;

		private const float minSpawnDist = 3f;

		private const float maxSpawnDist = 40f;

		private const float spawnRetryDelay = 1f;

		private bool hasSpawnedDrone;

		private float spawnDelay;

		private void OnEnable()
		{
			ulong seed = Run.instance.seed ^ (ulong)Run.instance.stageClearCount;
			rng = new Xoroshiro128Plus(seed);
			droneSpawnCard = Addressables.LoadAssetAsync<CharacterSpawnCard>("RoR2/DLC1/DroneCommander/cscDroneCommander.asset").WaitForCompletion();
			placementRule = new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Approximate,
				minDistance = 3f,
				maxDistance = 40f,
				spawnOnTarget = base.transform
			};
			UpdateAllMinions(stack);
			MasterSummon.onServerMasterSummonGlobal += OnServerMasterSummonGlobal;
		}

		private void OnDisable()
		{
			MasterSummon.onServerMasterSummonGlobal -= OnServerMasterSummonGlobal;
			UpdateAllMinions(0);
		}

		private void FixedUpdate()
		{
			if (previousStack != stack)
			{
				UpdateAllMinions(stack);
			}
			spawnDelay -= Time.fixedDeltaTime;
			if (!hasSpawnedDrone && (bool)body && spawnDelay <= 0f)
			{
				TrySpawnDrone();
			}
		}

		private void OnServerMasterSummonGlobal(MasterSummon.MasterSummonReport summonReport)
		{
			if (!body || !body.master || !(body.master == summonReport.leaderMasterInstance))
			{
				return;
			}
			CharacterMaster summonMasterInstance = summonReport.summonMasterInstance;
			if ((bool)summonMasterInstance)
			{
				CharacterBody characterBody = summonMasterInstance.GetBody();
				if ((bool)characterBody)
				{
					UpdateMinionInventory(summonMasterInstance.inventory, characterBody.bodyFlags, stack);
				}
			}
		}

		private void UpdateAllMinions(int newStack)
		{
			if (!body || !(body?.master))
			{
				return;
			}
			MinionOwnership.MinionGroup minionGroup = MinionOwnership.MinionGroup.FindGroup(body.master.netId);
			if (minionGroup == null)
			{
				return;
			}
			MinionOwnership[] members = minionGroup.members;
			foreach (MinionOwnership minionOwnership in members)
			{
				if (!minionOwnership)
				{
					continue;
				}
				CharacterMaster component = minionOwnership.GetComponent<CharacterMaster>();
				if ((bool)component && (bool)component.inventory)
				{
					CharacterBody characterBody = component.GetBody();
					if ((bool)characterBody)
					{
						UpdateMinionInventory(component.inventory, characterBody.bodyFlags, newStack);
					}
				}
			}
			previousStack = newStack;
		}

		private void UpdateMinionInventory(Inventory inventory, CharacterBody.BodyFlags bodyFlags, int newStack)
		{
			if (((bool)inventory && newStack > 0 && (bodyFlags & CharacterBody.BodyFlags.Mechanical) != 0) || (bodyFlags & CharacterBody.BodyFlags.Devotion) != 0)
			{
				int itemCount = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsBoost);
				int itemCount2 = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsDisplay1);
				int itemCount3 = inventory.GetItemCount(DLC1Content.Items.DroneWeaponsDisplay2);
				if (itemCount < stack)
				{
					inventory.GiveItem(DLC1Content.Items.DroneWeaponsBoost, stack - itemCount);
				}
				else if (itemCount > stack)
				{
					inventory.RemoveItem(DLC1Content.Items.DroneWeaponsBoost, itemCount - stack);
				}
				if (itemCount2 + itemCount3 <= 0)
				{
					ItemDef itemDef = DLC1Content.Items.DroneWeaponsDisplay1;
					if (UnityEngine.Random.value < 0.1f)
					{
						itemDef = DLC1Content.Items.DroneWeaponsDisplay2;
					}
					inventory.GiveItem(itemDef);
				}
			}
			else
			{
				inventory.ResetItem(DLC1Content.Items.DroneWeaponsBoost);
				inventory.ResetItem(DLC1Content.Items.DroneWeaponsDisplay1);
				inventory.ResetItem(DLC1Content.Items.DroneWeaponsDisplay2);
			}
		}

		private void TrySpawnDrone()
		{
			if (!body.master.IsDeployableLimited(DeployableSlot.DroneWeaponsDrone))
			{
				spawnDelay = 1f;
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(droneSpawnCard, placementRule, rng);
				directorSpawnRequest.summonerBodyObject = base.gameObject;
				directorSpawnRequest.onSpawnedServer = OnMasterSpawned;
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			}
		}

		private void OnMasterSpawned(SpawnCard.SpawnResult spawnResult)
		{
			hasSpawnedDrone = true;
			GameObject spawnedInstance = spawnResult.spawnedInstance;
			if (!spawnedInstance)
			{
				return;
			}
			CharacterMaster component = spawnedInstance.GetComponent<CharacterMaster>();
			if ((bool)component)
			{
				Deployable component2 = component.GetComponent<Deployable>();
				if ((bool)component2)
				{
					body.master.AddDeployable(component2, DeployableSlot.DroneWeaponsDrone);
				}
			}
		}
	}
	public class DroneWeaponsBoostBehavior : CharacterBody.ItemBehavior
	{
		private const string controllerPrefabPath = "Prefabs/NetworkedObjects/DroneWeaponsChainGunController";

		private const string missileMuzzleChildName = "MissileMuzzle";

		private const float microMissileDamageCoefficient = 3f;

		private const float microMissileProcCoefficient = 1f;

		private Transform missileMuzzleTransform;

		private GameObject chainGunController;

		public void Start()
		{
			GetComponent<InputBankTest>();
			ModelLocator component = GetComponent<ModelLocator>();
			if ((bool)component)
			{
				Transform modelTransform = component.modelTransform;
				if ((bool)modelTransform)
				{
					CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
					if ((bool)component2)
					{
						List<GameObject> itemDisplayObjects = component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay1.itemIndex);
						itemDisplayObjects.AddRange(component2.GetItemDisplayObjects(DLC1Content.Items.DroneWeaponsDisplay2.itemIndex));
						foreach (GameObject item in itemDisplayObjects)
						{
							ChildLocator component3 = item.GetComponent<ChildLocator>();
							if ((bool)component3)
							{
								Transform transform = component3.FindChild("MissileMuzzle");
								if ((bool)transform)
								{
									missileMuzzleTransform = transform;
									break;
								}
							}
						}
					}
				}
			}
			chainGunController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/DroneWeaponsChainGunController"));
			chainGunController.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.gameObject);
		}

		public void OnDestroy()
		{
			UnityEngine.Object.Destroy(chainGunController);
		}

		public void OnEnemyHit(DamageInfo damageInfo, CharacterBody victimBody)
		{
			CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>();
			CharacterMaster characterMaster = component?.master;
			if ((bool)characterMaster && !damageInfo.procChainMask.HasProc(ProcType.MicroMissile) && Util.CheckRoll(10f, characterMaster))
			{
				ProcChainMask procChainMask = damageInfo.procChainMask;
				procChainMask.AddProc(ProcType.MicroMissile);
				HurtBox hurtBox = victimBody.mainHurtBox;
				if ((bool)victimBody.hurtBoxGroup)
				{
					hurtBox = victimBody.hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, victimBody.hurtBoxGroup.hurtBoxes.Length)];
				}
				if ((bool)hurtBox)
				{
					MicroMissileOrb microMissileOrb = new MicroMissileOrb();
					microMissileOrb.damageValue = component.damage * 3f;
					microMissileOrb.isCrit = Util.CheckRoll(component.crit, characterMaster);
					microMissileOrb.teamIndex = TeamComponent.GetObjectTeam(component.gameObject);
					microMissileOrb.attacker = component.gameObject;
					microMissileOrb.procCoefficient = 1f;
					microMissileOrb.procChainMask = procChainMask;
					microMissileOrb.origin = (missileMuzzleTransform ? missileMuzzleTransform.position : component.corePosition);
					microMissileOrb.target = hurtBox;
					microMissileOrb.damageColorIndex = DamageColorIndex.Item;
					OrbManager.instance.AddOrb(microMissileOrb);
				}
			}
		}
	}
	public class ElementalRingVoidBehavior : CharacterBody.ItemBehavior
	{
		private void Awake()
		{
			base.enabled = false;
		}

		private void OnEnable()
		{
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				if (body.HasBuff(DLC1Content.Buffs.ElementalRingVoidReady))
				{
					body.RemoveBuff(DLC1Content.Buffs.ElementalRingVoidReady);
				}
				if (body.HasBuff(DLC1Content.Buffs.ElementalRingVoidCooldown))
				{
					body.RemoveBuff(DLC1Content.Buffs.ElementalRingVoidCooldown);
				}
			}
		}

		private void FixedUpdate()
		{
			if ((bool)body && !body.HasBuff(DLC1Content.Buffs.ElementalRingVoidReady) && !body.HasBuff(DLC1Content.Buffs.ElementalRingVoidCooldown))
			{
				body.AddBuff(DLC1Content.Buffs.ElementalRingVoidReady);
			}
		}
	}
	public class LunarSunBehavior : CharacterBody.ItemBehavior
	{
		private const float secondsPerTransform = 60f;

		private const float secondsPerProjectile = 3f;

		private const string projectilePath = "Prefabs/Projectiles/LunarSunProjectile";

		private const int baseMaxProjectiles = 2;

		private const int maxProjectilesPerStack = 1;

		private const float baseOrbitDegreesPerSecond = 180f;

		private const float orbitDegreesPerSecondFalloff = 0.9f;

		private const float baseOrbitRadius = 2f;

		private const float orbitRadiusPerStack = 0.25f;

		private const float maxInclinationDegrees = 0f;

		private const float baseDamageCoefficient = 3.6f;

		private float projectileTimer;

		private float transformTimer;

		private GameObject projectilePrefab;

		private Xoroshiro128Plus transformRng;

		public event Action<LunarSunBehavior> onDisabled;

		public static int GetMaxProjectiles(Inventory inventory)
		{
			return 2 + inventory.GetItemCount(DLC1Content.Items.LunarSun);
		}

		public void InitializeOrbiter(ProjectileOwnerOrbiter orbiter, LunarSunProjectileController controller)
		{
			float num = body.radius + 2f + UnityEngine.Random.Range(0.25f, 0.25f * (float)stack);
			float num2 = num / 2f;
			num2 *= num2;
			float degreesPerSecond = 180f * Mathf.Pow(0.9f, num2);
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 360f), UnityEngine.Vector3.up);
			UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f, 0f), UnityEngine.Vector3.forward);
			UnityEngine.Vector3 planeNormal = quaternion * quaternion2 * UnityEngine.Vector3.up;
			float initialDegreesFromOwnerForward = UnityEngine.Random.Range(0f, 360f);
			orbiter.Initialize(planeNormal, num, degreesPerSecond, initialDegreesFromOwnerForward);
			onDisabled += DestroyOrbiter;
			void DestroyOrbiter(LunarSunBehavior lunarSunBehavior)
			{
				if ((bool)controller)
				{
					controller.Detonate();
				}
			}
		}

		private void Awake()
		{
			base.enabled = false;
			projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/LunarSunProjectile");
			ulong seed = Run.instance.seed ^ (ulong)Run.instance.stageClearCount;
			transformRng = new Xoroshiro128Plus(seed);
		}

		private void OnEnable()
		{
		}

		private void OnDisable()
		{
			this.onDisabled?.Invoke(this);
			this.onDisabled = null;
		}

		private void FixedUpdate()
		{
			projectileTimer += Time.fixedDeltaTime;
			if (!body.master.IsDeployableLimited(DeployableSlot.LunarSunBomb) && projectileTimer > 3f / (float)stack)
			{
				projectileTimer = 0f;
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.projectilePrefab = projectilePrefab;
				fireProjectileInfo.crit = body.RollCrit();
				fireProjectileInfo.damage = body.damage * 3.6f;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Item;
				fireProjectileInfo.force = 0f;
				fireProjectileInfo.owner = base.gameObject;
				fireProjectileInfo.position = body.transform.position;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.identity;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
			transformTimer += Time.fixedDeltaTime;
			if (!(transformTimer > 60f))
			{
				return;
			}
			transformTimer = 0f;
			if (!body.master || !body.inventory)
			{
				return;
			}
			List<ItemIndex> list = new List<ItemIndex>(body.inventory.itemAcquisitionOrder);
			ItemIndex itemIndex = ItemIndex.None;
			Util.ShuffleList(list, transformRng);
			foreach (ItemIndex item in list)
			{
				if (item != DLC1Content.Items.LunarSun.itemIndex)
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(item);
					if ((bool)itemDef && itemDef.tier != ItemTier.NoTier)
					{
						itemIndex = item;
						break;
					}
				}
			}
			if (itemIndex != ItemIndex.None)
			{
				body.inventory.RemoveItem(itemIndex);
				body.inventory.GiveItem(DLC1Content.Items.LunarSun);
				CharacterMasterNotificationQueue.SendTransformNotification(body.master, itemIndex, DLC1Content.Items.LunarSun.itemIndex, CharacterMasterNotificationQueue.TransformationType.LunarSun);
			}
		}
	}
	public class MushroomVoidBehavior : CharacterBody.ItemBehavior
	{
		private const float healPercentagePerStack = 0.01f;

		private const float healPeriodSeconds = 0.5f;

		private bool wasSprinting;

		private HealthComponent healthComponent;

		private float healTimer;

		private void Awake()
		{
			base.enabled = false;
		}

		private void OnEnable()
		{
			if ((bool)body)
			{
				wasSprinting = body.GetBuffCount(DLC1Content.Buffs.MushroomVoidActive) > 0;
				healthComponent = body.GetComponent<HealthComponent>();
			}
			healTimer = 0f;
		}

		private void OnDisable()
		{
			if ((bool)body && wasSprinting)
			{
				body.RemoveBuff(DLC1Content.Buffs.MushroomVoidActive);
			}
			healthComponent = null;
		}

		private void FixedUpdate()
		{
			if ((bool)body)
			{
				if (body.isSprinting)
				{
					healTimer += Time.fixedDeltaTime;
					if (!wasSprinting)
					{
						wasSprinting = true;
						body.AddBuff(DLC1Content.Buffs.MushroomVoidActive);
					}
				}
				else if (wasSprinting)
				{
					body.RemoveBuff(DLC1Content.Buffs.MushroomVoidActive);
					wasSprinting = false;
				}
			}
			while (healTimer > 0.5f)
			{
				healthComponent.HealFraction(0.01f * (float)stack, default(ProcChainMask));
				healTimer -= 0.5f;
			}
		}
	}
	internal class OutOfCombatArmorBehavior : CharacterBody.ItemBehavior
	{
		private bool providingBuff;

		private void SetProvidingBuff(bool shouldProvideBuff)
		{
			if (shouldProvideBuff != providingBuff)
			{
				providingBuff = shouldProvideBuff;
				if (providingBuff)
				{
					body.AddBuff(DLC1Content.Buffs.OutOfCombatArmorBuff);
				}
				else
				{
					body.RemoveBuff(DLC1Content.Buffs.OutOfCombatArmorBuff);
				}
			}
		}

		private void OnDisable()
		{
			SetProvidingBuff(shouldProvideBuff: false);
		}

		private void FixedUpdate()
		{
			SetProvidingBuff(body.outOfDanger);
		}
	}
	public class PrimarySkillShurikenBehavior : CharacterBody.ItemBehavior
	{
		private const float minSpreadDegrees = 0f;

		private const float rangeSpreadDegrees = 1f;

		private const int numShurikensPerStack = 1;

		private const int numShurikensBase = 2;

		private const string projectilePrefabPath = "Prefabs/Projectiles/ShurikenProjectile";

		private const float totalReloadTime = 10f;

		private const float damageCoefficientBase = 3f;

		private const float damageCoefficientPerStack = 1f;

		private const float force = 0f;

		private SkillLocator skillLocator;

		private float reloadTimer;

		private GameObject projectilePrefab;

		private InputBankTest inputBank;

		private void Awake()
		{
			base.enabled = false;
		}

		private void Start()
		{
			projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/ShurikenProjectile");
		}

		private void OnEnable()
		{
			if ((bool)body)
			{
				body.onSkillActivatedServer += OnSkillActivated;
				skillLocator = body.GetComponent<SkillLocator>();
				inputBank = body.GetComponent<InputBankTest>();
			}
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				body.onSkillActivatedServer -= OnSkillActivated;
				while (body.HasBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff))
				{
					body.RemoveBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff);
				}
			}
			inputBank = null;
			skillLocator = null;
		}

		private void OnSkillActivated(GenericSkill skill)
		{
			if ((object)skillLocator?.primary == skill && body.GetBuffCount(DLC1Content.Buffs.PrimarySkillShurikenBuff) > 0)
			{
				body.RemoveBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff);
				FireShuriken();
			}
		}

		private void FixedUpdate()
		{
			int num = stack + 2;
			if (body.GetBuffCount(DLC1Content.Buffs.PrimarySkillShurikenBuff) < num)
			{
				float num2 = 10f / (float)num;
				reloadTimer += Time.fixedDeltaTime;
				while (reloadTimer > num2 && body.GetBuffCount(DLC1Content.Buffs.PrimarySkillShurikenBuff) < num)
				{
					body.AddBuff(DLC1Content.Buffs.PrimarySkillShurikenBuff);
					reloadTimer -= num2;
				}
			}
		}

		private void FireShuriken()
		{
			Ray aimRay = GetAimRay();
			ProjectileManager.instance.FireProjectile(projectilePrefab, aimRay.origin, Util.QuaternionSafeLookRotation(aimRay.direction) * GetRandomRollPitch(), base.gameObject, body.damage * (3f + 1f * (float)stack), 0f, Util.CheckRoll(body.crit, body.master), DamageColorIndex.Item);
		}

		private Ray GetAimRay()
		{
			if ((bool)inputBank)
			{
				return new Ray(inputBank.aimOrigin, inputBank.aimDirection);
			}
			return new Ray(base.transform.position, base.transform.forward);
		}

		protected UnityEngine.Quaternion GetRandomRollPitch()
		{
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0, 360), UnityEngine.Vector3.forward);
			UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(0f + UnityEngine.Random.Range(0f, 1f), UnityEngine.Vector3.left);
			return quaternion * quaternion2;
		}
	}
	public class VoidMegaCrabItemBehavior : CharacterBody.ItemBehavior
	{
		private const float baseSecondsPerSpawn = 60f;

		private const int baseMaxAllies = 1;

		private const int maxAlliesPerStack = 1;

		private const float minSpawnDist = 3f;

		private const float maxSpawnDist = 40f;

		private float spawnTimer;

		private Xoroshiro128Plus rng;

		private WeightedSelection<CharacterSpawnCard> spawnSelection;

		private DirectorPlacementRule placementRule;

		public static int GetMaxProjectiles(Inventory inventory)
		{
			return 1 + (inventory.GetItemCount(DLC1Content.Items.VoidMegaCrabItem) - 1);
		}

		private void Awake()
		{
			base.enabled = false;
			ulong seed = Run.instance.seed ^ (ulong)Run.instance.stageClearCount;
			rng = new Xoroshiro128Plus(seed);
			spawnSelection = new WeightedSelection<CharacterSpawnCard>();
			spawnSelection.AddChoice(Addressables.LoadAssetAsync<CharacterSpawnCard>("RoR2/DLC1/VoidJailer/cscVoidJailerAlly.asset").WaitForCompletion(), 15f);
			spawnSelection.AddChoice(Addressables.LoadAssetAsync<CharacterSpawnCard>("RoR2/Base/Nullifier/cscNullifierAlly.asset").WaitForCompletion(), 15f);
			spawnSelection.AddChoice(Addressables.LoadAssetAsync<CharacterSpawnCard>("RoR2/DLC1/VoidMegaCrab/cscVoidMegaCrabAlly.asset").WaitForCompletion(), 1f);
			placementRule = new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Approximate,
				minDistance = 3f,
				maxDistance = 40f,
				spawnOnTarget = base.transform
			};
		}

		private void FixedUpdate()
		{
			spawnTimer += Time.fixedDeltaTime;
			if (!body.master.IsDeployableLimited(DeployableSlot.VoidMegaCrabItem) && spawnTimer > 60f / (float)stack)
			{
				spawnTimer = 0f;
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnSelection.Evaluate(rng.nextNormalizedFloat), placementRule, rng);
				directorSpawnRequest.summonerBodyObject = base.gameObject;
				directorSpawnRequest.onSpawnedServer = OnMasterSpawned;
				directorSpawnRequest.summonerBodyObject = base.gameObject;
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			}
		}

		private void OnMasterSpawned(SpawnCard.SpawnResult spawnResult)
		{
			GameObject spawnedInstance = spawnResult.spawnedInstance;
			if (!spawnedInstance)
			{
				return;
			}
			CharacterMaster component = spawnedInstance.GetComponent<CharacterMaster>();
			if ((bool)component)
			{
				Deployable component2 = component.GetComponent<Deployable>();
				if ((bool)component2)
				{
					body.master.AddDeployable(component2, DeployableSlot.VoidMegaCrabItem);
				}
			}
		}
	}
	public class ItemDisplay : MonoBehaviour
	{
		public CharacterModel.RendererInfo[] rendererInfos;

		public GameObject[] hideOnDeathObjects;

		private VisibilityLevel visibilityLevel = VisibilityLevel.Visible;

		private bool isDead;

		public VisibilityLevel GetVisibilityLevel()
		{
			return visibilityLevel;
		}

		public void SetVisibilityLevel(VisibilityLevel newVisibilityLevel)
		{
			if (visibilityLevel == newVisibilityLevel)
			{
				return;
			}
			visibilityLevel = newVisibilityLevel;
			switch (visibilityLevel)
			{
			case VisibilityLevel.Invisible:
			{
				for (int l = 0; l < rendererInfos.Length; l++)
				{
					CharacterModel.RendererInfo rendererInfo4 = rendererInfos[l];
					rendererInfo4.renderer.enabled = false;
					rendererInfo4.renderer.shadowCastingMode = ShadowCastingMode.Off;
				}
				break;
			}
			case VisibilityLevel.Cloaked:
			{
				for (int j = 0; j < rendererInfos.Length; j++)
				{
					CharacterModel.RendererInfo rendererInfo2 = rendererInfos[j];
					rendererInfo2.renderer.enabled = !rendererInfo2.ignoreOverlays && (!isDead || !rendererInfo2.hideOnDeath);
					rendererInfo2.renderer.shadowCastingMode = ShadowCastingMode.Off;
					rendererInfo2.renderer.material = CharacterModel.cloakedMaterial;
				}
				break;
			}
			case VisibilityLevel.Revealed:
			{
				for (int k = 0; k < rendererInfos.Length; k++)
				{
					CharacterModel.RendererInfo rendererInfo3 = rendererInfos[k];
					rendererInfo3.renderer.enabled = !rendererInfo3.ignoreOverlays && (!isDead || !rendererInfo3.hideOnDeath);
					rendererInfo3.renderer.shadowCastingMode = ShadowCastingMode.Off;
					rendererInfo3.renderer.material = CharacterModel.revealedMaterial;
				}
				break;
			}
			case VisibilityLevel.Visible:
			{
				for (int i = 0; i < rendererInfos.Length; i++)
				{
					CharacterModel.RendererInfo rendererInfo = rendererInfos[i];
					bool flag = !isDead || !rendererInfo.hideOnDeath;
					rendererInfo.renderer.enabled = flag;
					rendererInfo.renderer.shadowCastingMode = ((!flag) ? ShadowCastingMode.On : ShadowCastingMode.Off);
					rendererInfo.renderer.material = rendererInfo.defaultMaterial;
				}
				break;
			}
			}
		}

		public void OnDeath()
		{
			isDead = true;
			for (int i = 0; i < rendererInfos.Length; i++)
			{
				CharacterModel.RendererInfo rendererInfo = rendererInfos[i];
				if (rendererInfo.hideOnDeath)
				{
					rendererInfo.renderer.enabled = false;
					rendererInfo.renderer.shadowCastingMode = ShadowCastingMode.Off;
				}
			}
			GameObject[] array = hideOnDeathObjects;
			for (int j = 0; j < array.Length; j++)
			{
				array[j].SetActive(value: false);
			}
		}
	}
	[SelectionBase]
	[ExecuteInEditMode]
	[DisallowMultipleComponent]
	public class ItemDisplayRuleComponent : MonoBehaviour
	{
		public UnityEngine.Object keyAsset;

		public LimbFlags limbMask;

		[SerializeField]
		[HideInInspector]
		private ItemDisplayRuleType _ruleType;

		public string nameInLocator;

		[HideInInspector]
		[SerializeField]
		private GameObject _prefab;

		private GameObject prefabInstance;

		private ItemDisplayRule itemDisplayRule;

		public ItemDisplayRuleType ruleType
		{
			get
			{
				return _ruleType;
			}
			set
			{
				_ruleType = value;
				if (_ruleType != 0)
				{
					prefab = null;
				}
			}
		}

		public GameObject prefab
		{
			get
			{
				return _prefab;
			}
			set
			{
				if (!prefabInstance || _prefab != value)
				{
					_prefab = value;
					BuildPreview();
				}
			}
		}

		private void Start()
		{
			BuildPreview();
		}

		public bool SetItemDisplayRule(ItemDisplayRule newItemDisplayRule, ChildLocator childLocator, UnityEngine.Object newKeyAsset)
		{
			itemDisplayRule = newItemDisplayRule;
			string childName = itemDisplayRule.childName;
			Transform transform = childLocator.FindChild(childName);
			if (!transform)
			{
				UnityEngine.Debug.LogWarningFormat(childLocator.gameObject, "Could not fully load item display rules for {0} because child {1} could not be found in the child locator.", childLocator.gameObject.name, childName);
				return false;
			}
			base.transform.parent = transform;
			keyAsset = newKeyAsset;
			nameInLocator = itemDisplayRule.childName;
			ruleType = itemDisplayRule.ruleType;
			switch (ruleType)
			{
			case ItemDisplayRuleType.ParentedPrefab:
				base.transform.localPosition = itemDisplayRule.localPos;
				base.transform.localEulerAngles = itemDisplayRule.localAngles;
				base.transform.localScale = itemDisplayRule.localScale;
				prefab = itemDisplayRule.followerPrefab;
				limbMask = LimbFlags.None;
				break;
			case ItemDisplayRuleType.LimbMask:
				prefab = null;
				limbMask = itemDisplayRule.limbMask;
				break;
			}
			return true;
		}

		private void DestroyPreview()
		{
			if ((bool)prefabInstance)
			{
				UnityEngine.Object.DestroyImmediate(prefabInstance);
			}
			prefabInstance = null;
		}

		private void BuildPreview()
		{
			DestroyPreview();
			if ((bool)prefab)
			{
				prefabInstance = UnityEngine.Object.Instantiate(prefab);
				prefabInstance.name = "Preview";
				prefabInstance.transform.parent = base.transform;
				prefabInstance.transform.localPosition = UnityEngine.Vector3.zero;
				prefabInstance.transform.localRotation = UnityEngine.Quaternion.identity;
				prefabInstance.transform.localScale = UnityEngine.Vector3.one;
				SetPreviewFlags(prefabInstance.transform);
			}
		}

		private static void SetPreviewFlags(Transform transform)
		{
			transform.gameObject.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
			foreach (Transform item in transform)
			{
				SetPreviewFlags(item);
			}
		}

		private void OnDestroy()
		{
			DestroyPreview();
		}
	}
	[RequireComponent(typeof(ItemDisplay))]
	public class ItemFollower : MonoBehaviour
	{
		public GameObject followerPrefab;

		public GameObject targetObject;

		public BezierCurveLine followerCurve;

		public LineRenderer followerLineRenderer;

		public float distanceDampTime;

		public float distanceMaxSpeed;

		private ItemDisplay itemDisplay;

		private UnityEngine.Vector3 velocityDistance;

		private UnityEngine.Vector3 v0;

		private UnityEngine.Vector3 v1;

		[HideInInspector]
		public GameObject followerInstance;

		private void Start()
		{
			itemDisplay = GetComponent<ItemDisplay>();
			followerLineRenderer = GetComponent<LineRenderer>();
			Rebuild();
		}

		private void Rebuild()
		{
			if (itemDisplay.GetVisibilityLevel() == VisibilityLevel.Invisible)
			{
				if ((bool)followerInstance)
				{
					UnityEngine.Object.Destroy(followerInstance);
				}
				if ((bool)followerLineRenderer)
				{
					followerLineRenderer.enabled = false;
				}
				return;
			}
			if (!followerInstance)
			{
				followerInstance = UnityEngine.Object.Instantiate(followerPrefab, targetObject.transform.position, UnityEngine.Quaternion.identity);
				followerInstance.transform.localScale = base.transform.localScale;
				if ((bool)followerCurve)
				{
					v0 = followerCurve.v0;
					v1 = followerCurve.v1;
				}
			}
			if ((bool)followerLineRenderer)
			{
				followerLineRenderer.enabled = true;
			}
		}

		private void Update()
		{
			Rebuild();
			if ((bool)followerInstance)
			{
				Transform transform = followerInstance.transform;
				Transform transform2 = targetObject.transform;
				transform.position = UnityEngine.Vector3.SmoothDamp(transform.position, transform2.position, ref velocityDistance, distanceDampTime);
				transform.rotation = transform2.rotation;
				if ((bool)followerCurve)
				{
					followerCurve.v0 = base.transform.TransformVector(v0);
					followerCurve.v1 = transform.TransformVector(v1);
					followerCurve.p1 = transform.position;
				}
			}
		}

		private void OnDestroy()
		{
			if ((bool)followerInstance)
			{
				UnityEngine.Object.Destroy(followerInstance);
			}
		}
	}
	public class ItemStealController : NetworkBehaviour
	{
		[Serializable]
		private class StolenInventoryInfo : IDisposable
		{
			[SerializeField]
			private ItemStealController owner;

			public Inventory victimInventory;

			public bool allowLending = true;

			public bool showStealOrbs = true;

			private int[] stolenItemStacks;

			private int[] lentItemStacks;

			private int[] itemAcqusitionSet;

			private ItemIndex[] itemAcquisitionOrder;

			[SerializeField]
			private int itemAcquisitionOrderCount;

			[SerializeField]
			private List<ItemTransferOrb> inFlightOrbs;

			public int stolenItemCount => itemAcquisitionOrderCount;

			[SerializeField]
			private Inventory lendeeInventory => owner.lendeeInventory;

			public bool hasOrbsInFlight => inFlightOrbs.Count > 0;

			public bool hasItemsToReclaim { get; private set; }

			public StolenInventoryInfo(ItemStealController owner, Inventory victimInventory)
			{
				this.owner = owner;
				this.victimInventory = victimInventory;
				stolenItemStacks = ItemCatalog.RequestItemStackArray();
				lentItemStacks = ItemCatalog.RequestItemStackArray();
				itemAcqusitionSet = ItemCatalog.RequestItemStackArray();
				itemAcquisitionOrder = ItemCatalog.RequestItemOrderBuffer();
				itemAcquisitionOrderCount = 0;
				inFlightOrbs = new List<ItemTransferOrb>();
			}

			public void Dispose()
			{
				victimInventory = null;
				if (stolenItemStacks != null)
				{
					ItemCatalog.ReturnItemStackArray(stolenItemStacks);
					stolenItemStacks = null;
				}
				if (lentItemStacks != null)
				{
					ItemCatalog.ReturnItemStackArray(lentItemStacks);
					lentItemStacks = null;
				}
				if (itemAcqusitionSet != null)
				{
					ItemCatalog.ReturnItemStackArray(itemAcqusitionSet);
					itemAcqusitionSet = null;
				}
				if (itemAcquisitionOrder != null)
				{
					ItemCatalog.ReturnItemOrderBuffer(itemAcquisitionOrder);
					itemAcquisitionOrder = null;
				}
				inFlightOrbs = null;
			}

			public bool StealNewestItem(int maxStackToSteal = int.MaxValue, bool? useOrbOverride = null)
			{
				if (!victimInventory)
				{
					return false;
				}
				List<ItemIndex> list = victimInventory.itemAcquisitionOrder;
				for (int num = list.Count - 1; num >= 0; num--)
				{
					ItemIndex itemIndex = list[num];
					if (StealItem(itemIndex, maxStackToSteal, useOrbOverride) > 0)
					{
						return true;
					}
				}
				return false;
			}

			private int StealItem(ItemIndex itemIndex, int maxStackToSteal, bool? useOrbOverride = null)
			{
				if (!owner.itemStealFilter(itemIndex))
				{
					return 0;
				}
				int itemCount = victimInventory.GetItemCount(itemIndex);
				int itemsToSteal = Math.Min(itemCount, maxStackToSteal);
				if (itemsToSteal > 0)
				{
					victimInventory.RemoveItem(itemIndex, itemsToSteal);
					UnityEngine.Vector3? vector = ((useOrbOverride ?? showStealOrbs) ? FindInventoryOrbOrigin(victimInventory) : null);
					if (vector.HasValue)
					{
						ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(vector.Value, null, itemIndex, itemsToSteal, delegate(ItemTransferOrb orb)
						{
							GiveItemToSelf(itemIndex, itemsToSteal);
							inFlightOrbs.Remove(orb);
						}, owner.networkIdentity);
						inFlightOrbs.Add(item);
					}
					else
					{
						GiveItemToSelf(itemIndex, itemsToSteal);
					}
				}
				return itemsToSteal;
			}

			private void RegisterItemAsAcquired(ItemIndex itemIndex)
			{
				ref int reference = ref itemAcqusitionSet[(int)itemIndex];
				if (reference == 0)
				{
					reference = 1;
					itemAcquisitionOrder[itemAcquisitionOrderCount++] = itemIndex;
				}
			}

			public bool LendNewestStolenItem(bool useOrb, int maxStackToGive = int.MaxValue)
			{
				for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--)
				{
					ItemIndex itemIndex = itemAcquisitionOrder[num];
					if (LendStolenItem(itemIndex, useOrb, maxStackToGive) > 0)
					{
						return true;
					}
				}
				return false;
			}

			public void LendAllItems(bool useOrb, int maxStackToGive = int.MaxValue)
			{
				for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--)
				{
					ItemIndex itemIndex = itemAcquisitionOrder[num];
					LendStolenItem(itemIndex, useOrb, maxStackToGive);
				}
			}

			private int LendStolenItem(ItemIndex itemIndex, bool useOrb, int maxStackToGive = int.MaxValue)
			{
				if (!lendeeInventory)
				{
					return 0;
				}
				int num = TakeItemFromSelf(itemIndex, maxStackToGive);
				if (num > 0)
				{
					if (useOrb)
					{
						ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(owner.orbTargetTransform.position, lendeeInventory, itemIndex, num, delegate(ItemTransferOrb orb)
						{
							GiveItemToLendee(orb.itemIndex, orb.stack);
							inFlightOrbs.Remove(orb);
						});
						inFlightOrbs.Add(item);
					}
					else
					{
						GiveItemToLendee(itemIndex, num);
					}
				}
				hasItemsToReclaim = true;
				return num;
			}

			private int ReclaimLentItem(ItemIndex itemToReclaim, int maxStackToReclaim = int.MaxValue, bool? useOrbOverride = null)
			{
				int num = TakeItemFromLendee(itemToReclaim, maxStackToReclaim);
				if (num > 0)
				{
					UnityEngine.Vector3? orbOrigin = ((useOrbOverride ?? showStealOrbs) ? FindInventoryOrbOrigin(lendeeInventory) : null);
					DispatchOrbOrGiveItem(victimInventory, itemToReclaim, num, orbOrigin, useOrbOverride);
				}
				return num;
			}

			private int ReclaimStolenItem(ItemIndex itemToReclaim, int maxStacksToReclaim = int.MaxValue, bool? useOrbOverride = null)
			{
				int num = TakeItemFromSelf(itemToReclaim, maxStacksToReclaim);
				if (num > 0)
				{
					DispatchOrbOrGiveItem(victimInventory, itemToReclaim, num, owner.orbTargetTransform.position, useOrbOverride);
				}
				return num;
			}

			private void DispatchOrbOrGiveItem(Inventory inventoryToGrantTo, ItemIndex itemToReclaim, int stacks, UnityEngine.Vector3? orbOrigin, bool? useOrbOverride = null)
			{
				if (!inventoryToGrantTo)
				{
					return;
				}
				if (orbOrigin.HasValue && (useOrbOverride ?? showStealOrbs))
				{
					ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(orbOrigin.Value, victimInventory, itemToReclaim, stacks, delegate(ItemTransferOrb orb)
					{
						ItemTransferOrb.DefaultOnArrivalBehavior(orb);
						inFlightOrbs.Remove(orb);
					});
					inFlightOrbs.Add(item);
				}
				else if ((bool)inventoryToGrantTo)
				{
					inventoryToGrantTo.GiveItem(itemToReclaim, stacks);
				}
			}

			public bool ReclaimNewestLentItem(int maxStackToReclaim = int.MaxValue)
			{
				for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--)
				{
					ItemIndex itemToReclaim = itemAcquisitionOrder[num];
					if (ReclaimLentItem(itemToReclaim, maxStackToReclaim) > 0)
					{
						return true;
					}
				}
				hasItemsToReclaim = false;
				return false;
			}

			public bool ReclaimOldestLentItem(int maxStackToReclaim = int.MaxValue)
			{
				for (int i = 0; i < itemAcquisitionOrderCount; i++)
				{
					ItemIndex itemToReclaim = itemAcquisitionOrder[i];
					if (ReclaimLentItem(itemToReclaim, maxStackToReclaim) > 0)
					{
						return true;
					}
				}
				hasItemsToReclaim = false;
				return false;
			}

			private void ForceAllOrbsToFinish()
			{
				while (inFlightOrbs.Count > 0)
				{
					OrbManager.instance.ForceImmediateArrival(inFlightOrbs[0]);
				}
			}

			private void GiveItemToSelf(ItemIndex itemIndex, int stack)
			{
				stolenItemStacks[(int)itemIndex] += stack;
				RegisterItemAsAcquired(itemIndex);
			}

			private int TakeItemFromSelf(ItemIndex itemIndex, int maxStackToTake)
			{
				ref int reference = ref stolenItemStacks[(int)itemIndex];
				int num = Math.Min(reference, maxStackToTake);
				reference -= num;
				return num;
			}

			private void GiveItemToLendee(ItemIndex itemIndex, int stack)
			{
				lentItemStacks[(int)itemIndex] += stack;
				if ((bool)lendeeInventory && allowLending && owner.itemLendFilter(itemIndex))
				{
					lendeeInventory.GiveItem(itemIndex, stack);
				}
			}

			private int TakeItemFromLendee(ItemIndex itemIndex, int maxStackToTake)
			{
				ref int reference = ref lentItemStacks[(int)itemIndex];
				int num = Math.Min(reference, maxStackToTake);
				if ((bool)lendeeInventory && owner.itemLendFilter(itemIndex))
				{
					lendeeInventory.RemoveItem(itemIndex, num);
				}
				reference -= num;
				return num;
			}

			public void ForceReclaimAllItemsImmediately()
			{
				ForceAllOrbsToFinish();
				for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--)
				{
					ItemIndex itemIndex = itemAcquisitionOrder[num];
					int num2 = 0;
					num2 += TakeItemFromSelf(itemIndex, int.MaxValue);
					num2 += TakeItemFromLendee(itemIndex, int.MaxValue);
					if ((bool)victimInventory)
					{
						victimInventory.GiveItem(itemIndex, num2);
					}
				}
			}

			public void ReclaimAllItems(bool? useOrbOverride)
			{
				for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--)
				{
					ItemIndex itemToReclaim = itemAcquisitionOrder[num];
					ReclaimLentItem(itemToReclaim, int.MaxValue, useOrbOverride);
					ReclaimStolenItem(itemToReclaim, int.MaxValue, useOrbOverride);
				}
				hasItemsToReclaim = false;
			}

			public void TakeBackItemsFromLendee()
			{
				UnityEngine.Vector3? vector = FindInventoryOrbOrigin(lendeeInventory);
				for (int num = itemAcquisitionOrderCount - 1; num >= 0; num--)
				{
					ItemIndex itemIndex = itemAcquisitionOrder[num];
					int itemStackToTake = TakeItemFromLendee(itemIndex, int.MaxValue);
					if (vector.HasValue)
					{
						ItemTransferOrb item = ItemTransferOrb.DispatchItemTransferOrb(vector.Value, null, itemIndex, itemStackToTake, delegate(ItemTransferOrb orb)
						{
							GiveItemToSelf(itemIndex, itemStackToTake);
							inFlightOrbs.Remove(orb);
						}, owner.orbTarget);
						inFlightOrbs.Add(item);
					}
					else
					{
						GiveItemToSelf(itemIndex, itemStackToTake);
					}
				}
			}

			private static UnityEngine.Vector3? FindInventoryOrbOrigin(Inventory inventory)
			{
				if ((bool)inventory)
				{
					CharacterMaster component = inventory.GetComponent<CharacterMaster>();
					if ((bool)component)
					{
						CharacterBody body = component.GetBody();
						if ((bool)body)
						{
							return body.corePosition;
						}
					}
				}
				return null;
			}
		}

		public UnityEvent onStealBeginServer;

		public UnityEvent onStealFinishServer;

		public UnityEvent onLendingBeginServer;

		public UnityEvent onLendingFinishServer;

		public float stealInterval = 0.2f;

		public HurtBox orbDestinationHurtBoxOverride;

		private NetworkIdentity networkIdentity;

		public Func<ItemIndex, bool> itemStealFilter = DefaultItemFilter;

		public Func<ItemIndex, bool> itemLendFilter = AIItemFilter;

		private StolenInventoryInfo[] stolenInventoryInfos = Array.Empty<StolenInventoryInfo>();

		private bool _inItemSteal;

		private bool _inLending;

		private float stealTimer;

		private float lendTimer;

		private Func<CharacterMaster, bool> stealMasterFilter;

		private static int kRpcRpcOnStealBeginClient;

		private static int kRpcRpcOnStealFinishClient;

		private static int kRpcRpcOnLendingBeginClient;

		private static int kRpcRpcOnLendingFinishClient;

		public Inventory lendeeInventory { get; private set; }

		public bool inItemSteal
		{
			get
			{
				return _inItemSteal;
			}
			private set
			{
				if (_inItemSteal != value)
				{
					if (_inItemSteal)
					{
						hasStolen = true;
					}
					_inItemSteal = value;
					(_inItemSteal ? onStealBeginServer : onStealFinishServer)?.Invoke();
					if (_inItemSteal)
					{
						CallRpcOnStealBeginClient();
					}
					else
					{
						CallRpcOnStealFinishClient();
					}
				}
			}
		}

		public bool hasStolen { get; private set; }

		public bool inLending
		{
			get
			{
				return _inLending;
			}
			private set
			{
				if (_inLending != value)
				{
					_inLending = value;
					(_inLending ? onLendingBeginServer : onLendingFinishServer)?.Invoke();
					if (_inItemSteal)
					{
						CallRpcOnLendingBeginClient();
					}
					else
					{
						CallRpcOnLendingFinishClient();
					}
				}
			}
		}

		private Either<NetworkIdentity, HurtBox> orbTarget
		{
			get
			{
				if ((bool)orbDestinationHurtBoxOverride)
				{
					return orbDestinationHurtBoxOverride;
				}
				return networkIdentity;
			}
		}

		private Transform orbTargetTransform
		{
			get
			{
				if ((bool)orbDestinationHurtBoxOverride)
				{
					return orbDestinationHurtBoxOverride.transform;
				}
				return networkIdentity.transform;
			}
		}

		public event Action onStealBeginClient;

		public event Action onStealFinishClient;

		public event Action onLendingBeginClient;

		public event Action onLendingFinishClient;

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
		}

		private void OnEnable()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
			}
		}

		private void OnDisable()
		{
			inItemSteal = false;
			ForceReclaimAllItemsImmediately();
		}

		private void OnDestroy()
		{
			StolenInventoryInfo[] array = stolenInventoryInfos;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Dispose();
			}
			stolenInventoryInfos = Array.Empty<StolenInventoryInfo>();
		}

		private void FixedUpdate()
		{
			if (inItemSteal)
			{
				stealTimer -= Time.fixedDeltaTime;
				if (stealTimer <= 0f)
				{
					stealTimer = stealInterval;
					StepSteal();
				}
			}
			if (inLending)
			{
				lendTimer -= Time.fixedDeltaTime;
				if (lendTimer <= 0f)
				{
					lendTimer = stealInterval;
					StepLend();
				}
			}
		}

		public static bool DefaultItemFilter(ItemIndex itemIndex)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if (itemDef.canRemove)
			{
				return itemDef.DoesNotContainTag(ItemTag.CannotSteal);
			}
			return false;
		}

		public static bool AIItemFilter(ItemIndex itemIndex)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if (itemDef.canRemove)
			{
				return itemDef.DoesNotContainTag(ItemTag.AIBlacklist);
			}
			return false;
		}

		public static bool BrotherItemFilter(ItemIndex itemIndex)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if (itemDef.canRemove && itemDef.DoesNotContainTag(ItemTag.AIBlacklist))
			{
				return itemDef.DoesNotContainTag(ItemTag.BrotherBlacklist);
			}
			return false;
		}

		public void StartLending(Inventory newLendeeInventory)
		{
			if (lendeeInventory != newLendeeInventory)
			{
				StolenInventoryInfo[] array = stolenInventoryInfos;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].TakeBackItemsFromLendee();
				}
			}
			lendeeInventory = newLendeeInventory;
			inLending = true;
		}

		public void LendImmediately(Inventory newLendeeInventory)
		{
			UnityEngine.Debug.LogFormat("LendImmediately({0})", newLendeeInventory);
			StartLending(newLendeeInventory);
			StolenInventoryInfo[] array = stolenInventoryInfos;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].LendAllItems(useOrb: false);
			}
			inLending = false;
		}

		public void StartStealingFromInventory(Inventory victimInventory)
		{
			if (GetStolenInventoryInfo(victimInventory) == null)
			{
				StolenInventoryInfo value = new StolenInventoryInfo(this, victimInventory);
				if ((bool)victimInventory.GetComponent<MinionOwnership>().ownerMaster)
				{
					value.allowLending = false;
					value.showStealOrbs = false;
				}
				ArrayUtils.ArrayAppend(ref stolenInventoryInfos, in value);
				inItemSteal = true;
			}
		}

		public void StepSteal()
		{
			if (stealMasterFilter != null)
			{
				foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
				{
					if (stealMasterFilter(readOnlyInstances))
					{
						StartStealingFromInventory(readOnlyInstances.inventory);
					}
				}
			}
			bool flag = false;
			StolenInventoryInfo[] array = stolenInventoryInfos;
			foreach (StolenInventoryInfo stolenInventoryInfo in array)
			{
				flag |= stolenInventoryInfo.hasOrbsInFlight;
				flag |= stolenInventoryInfo.StealNewestItem();
			}
			if (!flag)
			{
				inItemSteal = false;
			}
		}

		public void StepLend()
		{
			bool flag = false;
			StolenInventoryInfo[] array = stolenInventoryInfos;
			foreach (StolenInventoryInfo stolenInventoryInfo in array)
			{
				flag |= stolenInventoryInfo.hasOrbsInFlight;
				flag |= stolenInventoryInfo.LendNewestStolenItem(useOrb: true);
			}
			if (!flag)
			{
				inLending = false;
			}
		}

		public int GetStolenItemCount(Inventory victimInventory)
		{
			return GetStolenInventoryInfo(victimInventory)?.stolenItemCount ?? 0;
		}

		private StolenInventoryInfo GetStolenInventoryInfo(Inventory victimInventory)
		{
			for (int i = 0; i < stolenInventoryInfos.Length; i++)
			{
				if (stolenInventoryInfos[i].victimInventory == victimInventory)
				{
					return stolenInventoryInfos[i];
				}
			}
			return null;
		}

		private void ForceReclaimAllItemsImmediately()
		{
			StolenInventoryInfo[] array = stolenInventoryInfos;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].ForceReclaimAllItemsImmediately();
			}
		}

		public void ReclaimAllItems()
		{
			StolenInventoryInfo[] array = stolenInventoryInfos;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].ReclaimAllItems(null);
			}
		}

		public void StartSteal(Func<CharacterMaster, bool> filter)
		{
			if (NetworkServer.active)
			{
				stealMasterFilter = filter;
				inItemSteal = true;
			}
		}

		public bool ReclaimItemForInventory(Inventory inventory, int maxStack = int.MaxValue)
		{
			return GetStolenInventoryInfo(inventory)?.ReclaimNewestLentItem(maxStack) ?? false;
		}

		public void FindDeadOwnersOfStolenItems(List<Inventory> dest)
		{
			List<Inventory> list = CollectionPool<Inventory, List<Inventory>>.RentCollection();
			List<Inventory> list2 = CollectionPool<Inventory, List<Inventory>>.RentCollection();
			for (int i = 0; i < stolenInventoryInfos.Length; i++)
			{
				ref StolenInventoryInfo reference = ref stolenInventoryInfos[i];
				if ((bool)reference.victimInventory)
				{
					CharacterMaster component = reference.victimInventory.GetComponent<CharacterMaster>();
					if ((bool)component && !component.hasBody && reference.hasItemsToReclaim)
					{
						(reference.allowLending ? list : list2).Add(reference.victimInventory);
					}
				}
			}
			dest.AddRange(list);
			dest.AddRange(list2);
			CollectionPool<Inventory, List<Inventory>>.ReturnCollection(list2);
			CollectionPool<Inventory, List<Inventory>>.ReturnCollection(list);
		}

		public void AddValidStolenInventoriesToList(List<Inventory> list)
		{
			if (list == null)
			{
				return;
			}
			StolenInventoryInfo[] array = stolenInventoryInfos;
			foreach (StolenInventoryInfo stolenInventoryInfo in array)
			{
				if ((bool)stolenInventoryInfo.victimInventory)
				{
					list.Add(stolenInventoryInfo.victimInventory);
				}
			}
		}

		[ClientRpc]
		private void RpcOnStealBeginClient()
		{
			this.onStealBeginClient?.Invoke();
		}

		[ClientRpc]
		private void RpcOnStealFinishClient()
		{
			this.onStealFinishClient?.Invoke();
		}

		[ClientRpc]
		private void RpcOnLendingBeginClient()
		{
			this.onLendingBeginClient?.Invoke();
		}

		[ClientRpc]
		private void RpcOnLendingFinishClient()
		{
			this.onLendingFinishClient?.Invoke();
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcOnStealBeginClient(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnStealBeginClient called on server.");
			}
			else
			{
				((ItemStealController)obj).RpcOnStealBeginClient();
			}
		}

		protected static void InvokeRpcRpcOnStealFinishClient(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnStealFinishClient called on server.");
			}
			else
			{
				((ItemStealController)obj).RpcOnStealFinishClient();
			}
		}

		protected static void InvokeRpcRpcOnLendingBeginClient(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnLendingBeginClient called on server.");
			}
			else
			{
				((ItemStealController)obj).RpcOnLendingBeginClient();
			}
		}

		protected static void InvokeRpcRpcOnLendingFinishClient(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnLendingFinishClient called on server.");
			}
			else
			{
				((ItemStealController)obj).RpcOnLendingFinishClient();
			}
		}

		public void CallRpcOnStealBeginClient()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnStealBeginClient called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnStealBeginClient);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnStealBeginClient");
		}

		public void CallRpcOnStealFinishClient()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnStealFinishClient called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnStealFinishClient);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnStealFinishClient");
		}

		public void CallRpcOnLendingBeginClient()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnLendingBeginClient called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnLendingBeginClient);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnLendingBeginClient");
		}

		public void CallRpcOnLendingFinishClient()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnLendingFinishClient called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnLendingFinishClient);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnLendingFinishClient");
		}

		static ItemStealController()
		{
			kRpcRpcOnStealBeginClient = 166425938;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnStealBeginClient, InvokeRpcRpcOnStealBeginClient);
			kRpcRpcOnStealFinishClient = -1161796992;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnStealFinishClient, InvokeRpcRpcOnStealFinishClient);
			kRpcRpcOnLendingBeginClient = -1214064562;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnLendingBeginClient, InvokeRpcRpcOnLendingBeginClient);
			kRpcRpcOnLendingFinishClient = -1007329532;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ItemStealController), kRpcRpcOnLendingFinishClient, InvokeRpcRpcOnLendingFinishClient);
			NetworkCRC.RegisterBehaviour("ItemStealController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public interface IZone
	{
		bool IsInBounds(UnityEngine.Vector3 position);
	}
	[RequireComponent(typeof(NetworkedBodyAttachment))]
	public class JetpackController : NetworkBehaviour
	{
		private static readonly List<JetpackController> instancesList;

		private NetworkedBodyAttachment networkedBodyAttachment;

		public float duration;

		public float acceleration;

		public float boostSpeedMultiplier = 3f;

		public float boostCooldown = 0.5f;

		private float stopwatch;

		private Transform wingTransform;

		private Animator wingAnimator;

		private GameObject[] wingMotions;

		private GameObject wingMeshObject;

		private float boostCooldownTimer;

		private bool hasBegunSoundLoop;

		private ICharacterGravityParameterProvider targetCharacterGravityParameterProvider;

		private ICharacterFlightParameterProvider targetCharacterFlightParameterProvider;

		private bool _providingAntiGravity;

		private bool _providingFlight;

		private static int wingsReadyParamHash;

		private static int flyParamHash;

		private static int kRpcRpcResetTimer;

		private CharacterBody targetBody => networkedBodyAttachment.attachedBody;

		private bool providingAntiGravity
		{
			get
			{
				return _providingAntiGravity;
			}
			set
			{
				if (_providingAntiGravity != value)
				{
					_providingAntiGravity = value;
					if (targetCharacterGravityParameterProvider != null)
					{
						CharacterGravityParameters gravityParameters = targetCharacterGravityParameterProvider.gravityParameters;
						gravityParameters.channeledAntiGravityGranterCount += (_providingAntiGravity ? 1 : (-1));
						targetCharacterGravityParameterProvider.gravityParameters = gravityParameters;
					}
				}
			}
		}

		private bool providingFlight
		{
			get
			{
				return _providingFlight;
			}
			set
			{
				if (_providingFlight != value)
				{
					_providingFlight = value;
					if (targetCharacterFlightParameterProvider != null)
					{
						CharacterFlightParameters flightParameters = targetCharacterFlightParameterProvider.flightParameters;
						flightParameters.channeledFlightGranterCount += (_providingFlight ? 1 : (-1));
						targetCharacterFlightParameterProvider.flightParameters = flightParameters;
					}
				}
			}
		}

		public static JetpackController FindJetpackController(GameObject targetObject)
		{
			if (!targetObject)
			{
				return null;
			}
			for (int i = 0; i < instancesList.Count; i++)
			{
				if (instancesList[i].networkedBodyAttachment.attachedBodyObject == targetObject)
				{
					return instancesList[i];
				}
			}
			return null;
		}

		private void Awake()
		{
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
		}

		private void Start()
		{
			SetupWings();
			if ((bool)targetBody)
			{
				targetCharacterGravityParameterProvider = targetBody.GetComponent<ICharacterGravityParameterProvider>();
				targetCharacterFlightParameterProvider = targetBody.GetComponent<ICharacterFlightParameterProvider>();
				StartFlight();
			}
		}

		private void StartFlight()
		{
			providingAntiGravity = true;
			providingFlight = true;
			if (targetBody.hasEffectiveAuthority && (bool)targetBody.characterMotor && targetBody.characterMotor.isGrounded)
			{
				UnityEngine.Vector3 velocity = targetBody.characterMotor.velocity;
				velocity.y = 15f;
				targetBody.characterMotor.velocity = velocity;
				targetBody.characterMotor.Motor.ForceUnground();
			}
		}

		private void OnDestroy()
		{
			ShowMotionLines(showWings: false);
			if ((bool)targetBody)
			{
				providingFlight = false;
				targetCharacterFlightParameterProvider = null;
				providingAntiGravity = false;
				targetCharacterGravityParameterProvider = null;
			}
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void FixedUpdate()
		{
			stopwatch += Time.fixedDeltaTime;
			boostCooldownTimer -= Time.fixedDeltaTime;
			if ((bool)targetBody)
			{
				base.transform.position = targetBody.transform.position;
				if (targetBody.hasEffectiveAuthority && (bool)targetBody.characterMotor)
				{
					if (stopwatch < duration)
					{
						if (boostCooldownTimer <= 0f && targetBody.inputBank.jump.justPressed && targetBody.inputBank.moveVector != UnityEngine.Vector3.zero)
						{
							boostCooldownTimer = boostCooldown;
							targetBody.characterMotor.velocity = targetBody.inputBank.moveVector * (targetBody.moveSpeed * boostSpeedMultiplier);
							targetBody.characterMotor.disableAirControlUntilCollision = false;
						}
					}
					else
					{
						UnityEngine.Vector3 velocity = targetBody.characterMotor.velocity;
						velocity.y = Mathf.Max(velocity.y, -5f);
						targetBody.characterMotor.velocity = velocity;
						providingAntiGravity = false;
						providingFlight = false;
					}
				}
			}
			if (stopwatch >= duration)
			{
				bool flag = !targetBody.characterMotor || !targetBody.characterMotor.isGrounded;
				if ((bool)wingAnimator && !flag)
				{
					wingAnimator.SetBool(wingsReadyParamHash, value: false);
				}
				if (NetworkServer.active && !flag)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
				return;
			}
			float num = 4f;
			if ((bool)targetBody.characterMotor)
			{
				float magnitude = targetBody.characterMotor.velocity.magnitude;
				float moveSpeed = targetBody.moveSpeed;
				if (magnitude != 0f && moveSpeed != 0f)
				{
					num += magnitude / moveSpeed * 6f;
				}
			}
			if ((bool)wingAnimator)
			{
				wingAnimator.SetBool(wingsReadyParamHash, value: true);
				wingAnimator.SetFloat(flyParamHash, num, 0.1f, Time.fixedDeltaTime);
				ShowMotionLines(showWings: true);
			}
		}

		public void ResetTimer()
		{
			stopwatch = 0f;
			StartFlight();
			if (NetworkServer.active)
			{
				CallRpcResetTimer();
			}
		}

		[ClientRpc]
		private void RpcResetTimer()
		{
			if (!NetworkServer.active)
			{
				ResetTimer();
			}
		}

		private Transform FindWings()
		{
			ModelLocator modelLocator = targetBody.modelLocator;
			if ((bool)modelLocator)
			{
				Transform modelTransform = modelLocator.modelTransform;
				if ((bool)modelTransform)
				{
					CharacterModel component = modelTransform.GetComponent<CharacterModel>();
					if ((bool)component)
					{
						List<GameObject> equipmentDisplayObjects = component.GetEquipmentDisplayObjects(RoR2Content.Equipment.Jetpack.equipmentIndex);
						if (equipmentDisplayObjects.Count > 0)
						{
							return equipmentDisplayObjects[0].transform;
						}
					}
				}
			}
			return null;
		}

		private void ShowMotionLines(bool showWings)
		{
			if (wingMotions == null)
			{
				return;
			}
			for (int i = 0; i < wingMotions.Length; i++)
			{
				if ((bool)wingMotions[i])
				{
					wingMotions[i].SetActive(showWings);
				}
			}
			if ((bool)wingMeshObject)
			{
				wingMeshObject.SetActive(!showWings);
			}
			if (hasBegunSoundLoop != showWings)
			{
				if (showWings)
				{
					Util.PlaySound("Play_item_use_bugWingFlapLoop", base.gameObject);
				}
				else
				{
					Util.PlaySound("Stop_item_use_bugWingFlapLoop", base.gameObject);
				}
				hasBegunSoundLoop = showWings;
			}
		}

		public void SetupWings()
		{
			wingTransform = FindWings();
			if ((bool)wingTransform)
			{
				wingAnimator = wingTransform.GetComponentInChildren<Animator>();
				ChildLocator component = wingTransform.GetComponent<ChildLocator>();
				if ((bool)wingAnimator)
				{
					wingAnimator.SetBool(wingsReadyParamHash, value: true);
				}
				if ((bool)component)
				{
					wingMotions = new GameObject[4];
					wingMotions[0] = component.FindChild("WingMotionLargeL").gameObject;
					wingMotions[1] = component.FindChild("WingMotionLargeR").gameObject;
					wingMotions[2] = component.FindChild("WingMotionSmallL").gameObject;
					wingMotions[3] = component.FindChild("WingMotionSmallR").gameObject;
					wingMeshObject = component.FindChild("WingMesh").gameObject;
				}
			}
		}

		static JetpackController()
		{
			instancesList = new List<JetpackController>();
			wingsReadyParamHash = Animator.StringToHash("wingsReady");
			flyParamHash = Animator.StringToHash("fly.playbackRate");
			kRpcRpcResetTimer = 1278379706;
			NetworkBehaviour.RegisterRpcDelegate(typeof(JetpackController), kRpcRpcResetTimer, InvokeRpcRpcResetTimer);
			NetworkCRC.RegisterBehaviour("JetpackController", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcResetTimer(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcResetTimer called on server.");
			}
			else
			{
				((JetpackController)obj).RpcResetTimer();
			}
		}

		public void CallRpcResetTimer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcResetTimer called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcResetTimer);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcResetTimer");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class JitterBones : MonoBehaviour
	{
		private struct BoneInfo
		{
			public Transform transform;

			public bool isHead;

			public bool isRoot;
		}

		[SerializeField]
		private SkinnedMeshRenderer _skinnedMeshRenderer;

		private BoneInfo[] bones = Array.Empty<BoneInfo>();

		public float perlinNoiseFrequency;

		public float perlinNoiseStrength;

		public float perlinNoiseMinimumCutoff;

		public float perlinNoiseMaximumCutoff = 1f;

		public float headBonusStrength;

		private float age;

		public SkinnedMeshRenderer skinnedMeshRenderer
		{
			get
			{
				return _skinnedMeshRenderer;
			}
			set
			{
				if ((object)_skinnedMeshRenderer != value)
				{
					_skinnedMeshRenderer = value;
					RebuildBones();
				}
			}
		}

		private void RebuildBones()
		{
			if (!_skinnedMeshRenderer)
			{
				bones = Array.Empty<BoneInfo>();
				return;
			}
			Transform[] array = _skinnedMeshRenderer.bones;
			Array.Resize(ref bones, array.Length);
			for (int i = 0; i < bones.Length; i++)
			{
				Transform transform = array[i];
				string text = transform.name.ToLower();
				bones[i] = new BoneInfo
				{
					transform = transform,
					isHead = text.Contains("head"),
					isRoot = text.Contains("root")
				};
			}
		}

		private void Start()
		{
			RebuildBones();
		}

		private void LateUpdate()
		{
			if (!skinnedMeshRenderer)
			{
				return;
			}
			age += Time.deltaTime;
			for (int i = 0; i < bones.Length; i++)
			{
				BoneInfo boneInfo = bones[i];
				if (!boneInfo.isRoot)
				{
					float num = age * perlinNoiseFrequency;
					float num2 = i;
					UnityEngine.Vector3 value = new UnityEngine.Vector3(Mathf.PerlinNoise(num, num2), Mathf.PerlinNoise(num + 4f, num2 + 3f), Mathf.PerlinNoise(num + 6f, num2 - 7f));
					value = HGMath.Remap(value, perlinNoiseMinimumCutoff, perlinNoiseMaximumCutoff, -1f, 1f);
					value = HGMath.Clamp(value, 0f, 1f);
					value *= perlinNoiseStrength;
					if (headBonusStrength >= 0f && boneInfo.isHead)
					{
						value *= headBonusStrength;
					}
					boneInfo.transform.rotation *= UnityEngine.Quaternion.Euler(value);
				}
			}
		}
	}
	public class JumpVolume : MonoBehaviour
	{
		public Transform targetElevationTransform;

		public UnityEngine.Vector3 jumpVelocity;

		public float time;

		public string jumpSoundString;

		public UnityEvent onJump;

		public void OnTriggerStay(Collider other)
		{
			CharacterMotor component = other.GetComponent<CharacterMotor>();
			if ((bool)component && component.hasEffectiveAuthority && !component.doNotTriggerJumpVolumes)
			{
				onJump.Invoke();
				if (!component.disableAirControlUntilCollision)
				{
					Util.PlaySound(jumpSoundString, base.gameObject);
				}
				component.velocity = jumpVelocity;
				component.disableAirControlUntilCollision = true;
				component.Motor.ForceUnground();
			}
		}

		private void OnDrawGizmos()
		{
			int num = 20;
			float num2 = time / (float)num;
			UnityEngine.Vector3 vector = base.transform.position;
			_ = base.transform.position;
			UnityEngine.Vector3 vector2 = jumpVelocity;
			Gizmos.color = UnityEngine.Color.yellow;
			for (int i = 0; i <= num; i++)
			{
				UnityEngine.Vector3 vector3 = vector + vector2 * num2;
				vector2 += Physics.gravity * num2;
				Gizmos.DrawLine(vector3, vector);
				vector = vector3;
			}
		}
	}
	public class KillOnTimer : MonoBehaviour
	{
		public float duration;

		private float age;

		private HealthComponent health;

		private void Start()
		{
			if (!TryGetComponent<HealthComponent>(out var component))
			{
				UnityEngine.Debug.LogWarning(base.gameObject.name + " does not have a health component!  KillOnTimer will not work!!");
			}
			else
			{
				health = component;
			}
		}

		private void Update()
		{
			age += Time.deltaTime;
			if (age > duration)
			{
				if ((bool)health && NetworkServer.active)
				{
					health.Suicide();
				}
				base.enabled = false;
			}
		}
	}
	[RequireComponent(typeof(LineRenderer))]
	public class LaserPointer : MonoBehaviour
	{
		public float laserDistance;

		private LineRenderer line;

		private void Start()
		{
			line = GetComponent<LineRenderer>();
		}

		private void Update()
		{
			if (Physics.Raycast(base.transform.position, base.transform.forward, out var hitInfo, laserDistance, LayerIndex.world.mask))
			{
				line.SetPosition(0, base.transform.position);
				line.SetPosition(1, hitInfo.point);
			}
		}
	}
	internal class LaserPointerController : MonoBehaviour
	{
		public InputBankTest source;

		public GameObject dotObject;

		public LineRenderer beam;

		public float minDistanceFromStart = 4f;

		private void LateUpdate()
		{
			bool flag = false;
			bool active = false;
			if ((bool)source)
			{
				Ray ray = new Ray(source.aimOrigin, source.aimDirection);
				if (Physics.Raycast(ray, out var hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
				{
					base.transform.position = hitInfo.point;
					base.transform.forward = -ray.direction;
					float num = hitInfo.distance - minDistanceFromStart;
					if (num >= 0.1f)
					{
						beam.SetPosition(1, new UnityEngine.Vector3(0f, 0f, num));
						flag = true;
					}
					active = true;
				}
			}
			dotObject.SetActive(active);
			beam.enabled = flag;
		}
	}
	[RequireComponent(typeof(GenericOwnership))]
	[RequireComponent(typeof(NetworkIdentity))]
	[RequireComponent(typeof(EntityStateMachine))]
	[RequireComponent(typeof(NetworkStateMachine))]
	public class LaserTurbineController : NetworkBehaviour
	{
		public float visualSpinRate = 7200f;

		public Transform chargeIndicator;

		public Transform spinIndicator;

		public Transform turbineDisplayRoot;

		public bool showTurbineDisplay;

		public string spinRtpc;

		public float spinRtpcScale;

		public float visualSpin;

		public float visualSpinDecayRate = 0.2f;

		private GenericOwnership genericOwnership;

		private CharacterBody cachedOwnerBody;

		public float charge { get; private set; }

		private void Awake()
		{
			genericOwnership = GetComponent<GenericOwnership>();
			genericOwnership.onOwnerChanged += OnOwnerChanged;
		}

		private void Update()
		{
			if (NetworkClient.active)
			{
				UpdateClient();
			}
		}

		private void FixedUpdate()
		{
			int killChargeCount = 0;
			if ((bool)cachedOwnerBody)
			{
				killChargeCount = cachedOwnerBody.GetBuffCount(RoR2Content.Buffs.LaserTurbineKillCharge);
			}
			charge = CalcCurrentChargeValue(killChargeCount);
			if ((bool)turbineDisplayRoot)
			{
				turbineDisplayRoot.gameObject.SetActive(showTurbineDisplay);
			}
		}

		private void OnEnable()
		{
			if (NetworkServer.active)
			{
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobalServer;
			}
		}

		private void OnDisable()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobalServer;
		}

		[Client]
		private void UpdateClient()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.LaserTurbineController::UpdateClient()' called on server");
				return;
			}
			if (visualSpin <= charge)
			{
				visualSpin = charge;
			}
			else
			{
				visualSpin -= visualSpinDecayRate * Time.deltaTime;
			}
			visualSpin = Mathf.Max(visualSpin, 0f);
			float num = HGMath.CircleAreaToRadius(visualSpin * HGMath.CircleRadiusToArea(1f));
			chargeIndicator.localScale = new UnityEngine.Vector3(num, num, num);
			UnityEngine.Vector3 localEulerAngles = spinIndicator.localEulerAngles;
			localEulerAngles.y += visualSpin * Time.deltaTime * visualSpinRate;
			spinIndicator.localEulerAngles = localEulerAngles;
			AkSoundEngine.SetRTPCValue(spinRtpc, visualSpin * spinRtpcScale, base.gameObject);
		}

		[Server]
		public void ExpendCharge()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LaserTurbineController::ExpendCharge()' called on client");
			}
			else if ((bool)cachedOwnerBody)
			{
				cachedOwnerBody.ClearTimedBuffs(RoR2Content.Buffs.LaserTurbineKillCharge);
			}
		}

		private void OnCharacterDeathGlobalServer(DamageReport damageReport)
		{
			if ((object)damageReport.attacker == genericOwnership.ownerObject && (object)damageReport.attacker != null)
			{
				OnOwnerKilledOtherServer();
			}
		}

		private void OnOwnerKilledOtherServer()
		{
			if ((bool)cachedOwnerBody)
			{
				cachedOwnerBody.AddTimedBuff(RoR2Content.Buffs.LaserTurbineKillCharge, RechargeState.killChargeDuration, RechargeState.killChargesRequired);
			}
		}

		private void OnOwnerChanged(GameObject newOwner)
		{
			cachedOwnerBody = (newOwner ? newOwner.GetComponent<CharacterBody>() : null);
		}

		public float CalcCurrentChargeValue(int killChargeCount)
		{
			return Mathf.Clamp01((float)killChargeCount / (float)RechargeState.killChargesRequired);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(EntityStateMachine))]
	public class LightningStormController : NetworkBehaviour
	{
		[Serializable]
		public struct LightningStrikePoint
		{
			[Tooltip("Just for identifying points - not used in code")]
			public string description;

			[Tooltip("How far from the target's position should this point appear.")]
			public float distanceFromTargetPosition;

			[FormerlySerializedAs("speedMultiplier")]
			[Tooltip("How much the projected position should take into account the player's current velocity. 1.8 tends to work if you want it to go off right as they pass by it.")]
			[FormerlySerializedAs("distanceProjectionMultiplier")]
			public float velocityMultiplier;

			[Tooltip("Degrees to offset the prstrike position (0 = forward, 180 = behind, 90 = right, 270 / -90 = left, etc)")]
			public float directionOffset;

			[Tooltip("A randomized number of degrees (+/-) to adjust direction offset by.")]
			public float randomDegreeOffset;
		}

		public static LightningStrikePattern lightningPattern;

		[SyncVar(hook = "Client_HandleStormActiveChanged")]
		public bool stormActive;

		[SyncVar(hook = "Client_SetStormStrikePattern")]
		private int strikePatternID = -1;

		[SerializeField]
		private List<LightningStrikePattern> strikePatterns = new List<LightningStrikePattern>();

		[SerializeField]
		[Space(20f)]
		private EntityStateMachine stormStateMachine;

		[SerializeField]
		public GameObject startPostProcessingObject;

		[SerializeField]
		public PostProcessDuration startPostProcessDuration;

		[SerializeField]
		public GameObject endPostProcessingObject;

		[SerializeField]
		public PostProcessDuration endPostProcessDuration;

		[SerializeField]
		[FormerlySerializedAs("serializedlightningPattern")]
		public LightningStrikePattern fallbackLightningPattern;

		private static int kCmdCmdSetStormActive;

		private static int kCmdCmdSetStrikePattern;

		public static LightningStormController instance { get; private set; }

		public bool NetworkstormActive
		{
			get
			{
				return stormActive;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					Client_HandleStormActiveChanged(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref stormActive, 1u);
			}
		}

		public int NetworkstrikePatternID
		{
			get
			{
				return strikePatternID;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					Client_SetStormStrikePattern(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref strikePatternID, 2u);
			}
		}

		public static void SetStormActive(bool b)
		{
			if (!(instance == null) && b != instance.stormActive)
			{
				if (!NetworkServer.active)
				{
					instance.CallCmdSetStormActive(b);
				}
				else
				{
					instance.ServerSetStormActive(b);
				}
			}
		}

		public static void SetStormStrikePattern(LightningStrikePattern _pattern)
		{
			if (!(instance == null) && !(_pattern == null) && !(_pattern == lightningPattern) && _pattern != null)
			{
				if (NetworkServer.active)
				{
					instance.ServerSetStrikePattern(_pattern.ID);
				}
				else
				{
					instance.CallCmdSetStrikePattern(_pattern.ID);
				}
			}
		}

		public static LightningStrikeInstance FireLightningBolt(UnityEngine.Vector3 position, GameObject lightningPrefab, BlastAttack _blastInfo = null)
		{
			if (instance != null && !instance.stormActive)
			{
				return null;
			}
			GameObject gameObject = UnityEngine.Object.Instantiate(lightningPrefab);
			LightningStrikeInstance component = gameObject.GetComponent<LightningStrikeInstance>();
			if (!component)
			{
				UnityEngine.Object.Destroy(gameObject);
				return null;
			}
			component.Initialize(position, _blastInfo);
			return component;
		}

		public static bool ShouldFireLighting()
		{
			if (instance == null)
			{
				return false;
			}
			return instance.stormActive;
		}

		public static UnityEngine.Vector3 PredictPosition(UnityEngine.Vector3 position, UnityEngine.Vector3 forwardDirection, float maxSpeed, LightningStrikePoint strikePointData)
		{
			forwardDirection = UnityEngine.Quaternion.AngleAxis(strikePointData.directionOffset, UnityEngine.Vector3.up) * forwardDirection;
			if (strikePointData.randomDegreeOffset != 0f)
			{
				forwardDirection = UnityEngine.Quaternion.AngleAxis(UnityEngine.Random.Range(0f - strikePointData.randomDegreeOffset, strikePointData.randomDegreeOffset), UnityEngine.Vector3.up) * forwardDirection;
			}
			position += forwardDirection * maxSpeed * strikePointData.velocityMultiplier;
			position += forwardDirection * strikePointData.distanceFromTargetPosition;
			return position;
		}

		public static float GetMaxDistance(UnityEngine.Vector3 forwardDirection, float maxSpeed, LightningStrikePoint strikePointData)
		{
			return (forwardDirection * maxSpeed * strikePointData.velocityMultiplier).magnitude + strikePointData.distanceFromTargetPosition;
		}

		[ContextMenu("Load Current Lightning Pattern Scrob into Memory")]
		public void LoadCurrentLightningPatternScrob()
		{
			SetStormStrikePattern(fallbackLightningPattern);
		}

		[Command]
		private void CmdSetStormActive(bool b)
		{
			ServerSetStormActive(b);
		}

		[Server]
		private void ServerSetStormActive(bool b)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LightningStormController::ServerSetStormActive(System.Boolean)' called on client");
				return;
			}
			if (b != stormActive)
			{
				if (b)
				{
					HandleStormBegins();
				}
				else
				{
					HandleStormEnds();
				}
			}
			NetworkstormActive = b;
		}

		private void Client_HandleStormActiveChanged(bool newValue)
		{
			if (NetworkServer.active)
			{
				return;
			}
			if (newValue != stormActive)
			{
				if (newValue)
				{
					HandleStormBegins();
				}
				else
				{
					HandleStormEnds();
				}
			}
			NetworkstormActive = newValue;
		}

		[Server]
		private void ServerSetStrikePattern(int patternID)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LightningStormController::ServerSetStrikePattern(System.Int32)' called on client");
				return;
			}
			if (patternID >= strikePatterns.Count || patternID < 0)
			{
				patternID = 0;
			}
			if (patternID != strikePatternID)
			{
				NetworkstrikePatternID = patternID;
				lightningPattern = strikePatterns[patternID];
			}
		}

		[Command]
		private void CmdSetStrikePattern(int patternID)
		{
			ServerSetStrikePattern(patternID);
		}

		private void Client_SetStormStrikePattern(int newPatternIndex)
		{
			if (NetworkServer.active)
			{
				return;
			}
			if (newPatternIndex >= strikePatterns.Count || newPatternIndex < 0)
			{
				newPatternIndex = 0;
				if (strikePatterns.Count < 1)
				{
					return;
				}
			}
			lightningPattern = strikePatterns[newPatternIndex];
			NetworkstrikePatternID = newPatternIndex;
		}

		private void Awake()
		{
			if (strikePatterns.Count >= 1)
			{
				for (int i = 0; i < strikePatterns.Count; i++)
				{
					strikePatterns[i].ID = i;
				}
				int num = ((fallbackLightningPattern != null) ? fallbackLightningPattern.ID : 0);
				if (NetworkServer.active)
				{
					ServerSetStrikePattern(num);
				}
				else
				{
					lightningPattern = strikePatterns[num];
				}
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			if (stormActive)
			{
				HandleStormBegins();
			}
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			HandleStormEnds();
		}

		private void HandleStormBegins()
		{
			if (!(lightningPattern == null))
			{
				SetStormStrikePattern(fallbackLightningPattern);
				stormStateMachine.SetNextState(new LightningStormState());
			}
		}

		private void HandleStormEnds()
		{
			stormStateMachine.SetNextState(new EntityStates.Idle());
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdSetStormActive(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetStormActive called on client.");
			}
			else
			{
				((LightningStormController)obj).CmdSetStormActive(reader.ReadBoolean());
			}
		}

		protected static void InvokeCmdCmdSetStrikePattern(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetStrikePattern called on client.");
			}
			else
			{
				((LightningStormController)obj).CmdSetStrikePattern((int)reader.ReadPackedUInt32());
			}
		}

		public void CallCmdSetStormActive(bool b)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetStormActive called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetStormActive(b);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetStormActive);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(b);
			SendCommandInternal(networkWriter, 0, "CmdSetStormActive");
		}

		public void CallCmdSetStrikePattern(int patternID)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetStrikePattern called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetStrikePattern(patternID);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetStrikePattern);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)patternID);
			SendCommandInternal(networkWriter, 0, "CmdSetStrikePattern");
		}

		static LightningStormController()
		{
			kCmdCmdSetStormActive = 753869832;
			NetworkBehaviour.RegisterCommandDelegate(typeof(LightningStormController), kCmdCmdSetStormActive, InvokeCmdCmdSetStormActive);
			kCmdCmdSetStrikePattern = 1007190007;
			NetworkBehaviour.RegisterCommandDelegate(typeof(LightningStormController), kCmdCmdSetStrikePattern, InvokeCmdCmdSetStrikePattern);
			NetworkCRC.RegisterBehaviour("LightningStormController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(stormActive);
				writer.WritePackedUInt32((uint)strikePatternID);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(stormActive);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)strikePatternID);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				stormActive = reader.ReadBoolean();
				strikePatternID = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				Client_HandleStormActiveChanged(reader.ReadBoolean());
			}
			if (((uint)num & 2u) != 0)
			{
				Client_SetStormStrikePattern((int)reader.ReadPackedUInt32());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class LightningStrikeInstance : MonoBehaviour
	{
		public GameObject warningEffectPrefab;

		public GameObject impactEffectPrefab;

		public TeamComponent teamComponent;

		public float impactDelay;

		public float blastDamage;

		public float blastRadius;

		public float blastForce;

		public DamageTypeCombo blastDamageType;

		private Action ExecuteNextStep;

		private float stepTimer;

		private UnityEngine.Vector3 impactPosition;

		private BlastAttack blastAttack;

		public bool Initialize(UnityEngine.Vector3 _impactPosition, BlastAttack _blastInfo)
		{
			impactPosition = _impactPosition;
			if (!ConfirmGroundBelowImpactPoint())
			{
				return false;
			}
			base.transform.position = impactPosition;
			stepTimer = 0.0001f;
			if (impactDelay <= 0f)
			{
				ExecuteNextStep = HandleStrike;
			}
			else
			{
				ExecuteNextStep = HandleWarning;
			}
			if (_blastInfo != null)
			{
				blastAttack = _blastInfo;
			}
			else
			{
				blastAttack = new BlastAttack
				{
					attacker = null,
					baseDamage = blastDamage,
					baseForce = blastForce,
					radius = blastRadius,
					damageType = blastDamageType,
					teamIndex = teamComponent.teamIndex
				};
			}
			SetupDefaultBlastInfo(ref blastAttack);
			return true;
		}

		private bool ConfirmGroundBelowImpactPoint()
		{
			if (Physics.Raycast(new Ray(impactPosition + UnityEngine.Vector3.up * 2f, UnityEngine.Vector3.down), out var hitInfo, 200f, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault, QueryTriggerInteraction.Ignore))
			{
				impactPosition = hitInfo.point;
				return true;
			}
			return false;
		}

		private void SetupDefaultBlastInfo(ref BlastAttack _blastInfo)
		{
			_blastInfo.position = impactPosition;
			if (_blastInfo.attacker == null)
			{
				_blastInfo.attacker = base.gameObject;
			}
			_blastInfo.inflictor = base.gameObject;
			_blastInfo.attackerFiltering = AttackerFiltering.Default;
			_blastInfo.falloffModel = BlastAttack.FalloffModel.Linear;
			_blastInfo.bonusForce = UnityEngine.Vector3.zero;
			_blastInfo.damageColorIndex = DamageColorIndex.Item;
			_blastInfo.procChainMask = default(ProcChainMask);
			_blastInfo.procCoefficient = 1f;
			if (_blastInfo.teamIndex == TeamIndex.Neutral)
			{
				_blastInfo.teamIndex = teamComponent.teamIndex;
			}
		}

		private void Update()
		{
			if (stepTimer > 0f)
			{
				stepTimer -= Time.deltaTime;
				if (stepTimer <= 0f)
				{
					ExecuteNextStep?.Invoke();
				}
			}
		}

		private void HandleWarning()
		{
			if (!LightningStormController.ShouldFireLighting())
			{
				ExecuteNextStep = HandleCleanup;
				stepTimer = 0.2f;
				return;
			}
			EffectManager.SpawnEffect(warningEffectPrefab, new EffectData
			{
				origin = impactPosition,
				scale = blastRadius
			}, transmit: true);
			stepTimer = impactDelay;
			ExecuteNextStep = HandleStrike;
		}

		private void HandleStrike()
		{
			if (!LightningStormController.ShouldFireLighting())
			{
				ExecuteNextStep = HandleCleanup;
				stepTimer = 0.2f;
				return;
			}
			if ((bool)impactEffectPrefab)
			{
				EffectData effectData = new EffectData
				{
					origin = impactPosition
				};
				EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true);
			}
			StrikeAboveImpactPosition();
			blastAttack.Fire();
			stepTimer = 1f;
			ExecuteNextStep = HandleCleanup;
		}

		private void StrikeAboveImpactPosition()
		{
			ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
			float num = 100f;
			float radius = this.blastAttack.radius;
			float num2 = this.blastAttack.radius * 1.3f;
			num2 *= num2;
			UnityEngine.Vector3 vector = impactPosition;
			foreach (CharacterMaster item in readOnlyInstancesList)
			{
				if (item == null || item.GetBody() == null)
				{
					continue;
				}
				UnityEngine.Vector3 corePosition = item.GetBody().corePosition;
				float num3 = Mathf.Abs(corePosition.y - impactPosition.y);
				if (num3 > num || num3 < radius)
				{
					continue;
				}
				vector.y = corePosition.y;
				if (!((corePosition - vector).sqrMagnitude > num2))
				{
					BlastAttack blastAttack = CopyBlastAttack(ref this.blastAttack);
					blastAttack.position = vector;
					if ((bool)impactEffectPrefab)
					{
						EffectData effectData = new EffectData
						{
							origin = blastAttack.position
						};
						EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true);
					}
					blastAttack.Fire();
				}
			}
		}

		private BlastAttack CopyBlastAttack(ref BlastAttack _source)
		{
			BlastAttack _blastInfo = new BlastAttack();
			_blastInfo.attacker = _source.attacker;
			_blastInfo.baseDamage = _source.baseDamage;
			_blastInfo.baseForce = _source.baseForce;
			_blastInfo.radius = _source.radius;
			_blastInfo.damageType = _source.damageType;
			SetupDefaultBlastInfo(ref _blastInfo);
			return _blastInfo;
		}

		private void HandleCleanup()
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}
	[CreateAssetMenu(fileName = "New Lightning Pattern Data", menuName = "RoR2/Lightning Pattern")]
	public class LightningStrikePattern : ScriptableObject
	{
		[NonSerialized]
		[HideInInspector]
		public int ID;

		[Tooltip("How far can a discovered node be from the predicted position and still qualify as a strike point.")]
		public float maxAcceptableDistanceFromPredictedPoint = 2f;

		[Tooltip("How many lightning strikes should we reduce the total by, per additional player. (Single player will not reduce any)")]
		public float forEachAdditionalPlayerReduceStrikeTotalBy = 1f;

		public float frequencyOfLightningStrikes = 4f;

		public float timeBetweenIndividualStrikes = 0.2f;

		public List<LightningStormController.LightningStrikePoint> lightningStrikePoints;
	}
	public class LightScaleFromParent : MonoBehaviour
	{
		private void Start()
		{
			Light component = GetComponent<Light>();
			if ((bool)component)
			{
				float range = component.range;
				UnityEngine.Vector3 lossyScale = base.transform.lossyScale;
				component.range = range * Mathf.Max(lossyScale.x, lossyScale.y, lossyScale.z);
			}
		}
	}
	public class LimbMatcher : MonoBehaviour
	{
		[Serializable]
		public struct LimbPair
		{
			public Transform originalTransform;

			public string targetChildLimb;

			public float originalLimbLength;

			[NonSerialized]
			public Transform targetTransform;
		}

		public bool scaleLimbs = true;

		private bool valid;

		public LimbPair[] limbPairs;

		public void SetChildLocator(ChildLocator childLocator)
		{
			valid = true;
			for (int i = 0; i < limbPairs.Length; i++)
			{
				LimbPair limbPair = limbPairs[i];
				Transform transform = childLocator.FindChild(limbPair.targetChildLimb);
				if (!transform)
				{
					valid = false;
					break;
				}
				limbPairs[i].targetTransform = transform;
			}
		}

		private void LateUpdate()
		{
			UpdateLimbs();
		}

		private void UpdateLimbs()
		{
			if (!valid)
			{
				return;
			}
			for (int i = 0; i < limbPairs.Length; i++)
			{
				LimbPair limbPair = limbPairs[i];
				Transform targetTransform = limbPair.targetTransform;
				if (!targetTransform || !limbPair.originalTransform)
				{
					continue;
				}
				limbPair.originalTransform.position = targetTransform.position;
				limbPair.originalTransform.rotation = targetTransform.rotation;
				if (i < limbPairs.Length - 1)
				{
					float num = UnityEngine.Vector3.Magnitude(limbPairs[i + 1].targetTransform.position - targetTransform.position);
					float originalLimbLength = limbPair.originalLimbLength;
					if (scaleLimbs)
					{
						UnityEngine.Vector3 localScale = limbPair.originalTransform.localScale;
						localScale.y = num / originalLimbLength;
						limbPair.originalTransform.localScale = localScale;
					}
				}
			}
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class LoaderStaticChargeComponent : NetworkBehaviour, IOnDamageDealtServerReceiver, IOnTakeDamageServerReceiver
	{
		private enum State
		{
			Idle,
			Drain
		}

		public float maxCharge = 100f;

		public float consumptionRate = 10f;

		[SyncVar]
		private float _charge;

		private CharacterBody characterBody;

		private State state;

		private static int kCmdCmdConsumeCharge;

		public float charge => _charge;

		public float chargeFraction => charge / maxCharge;

		public float Network_charge
		{
			get
			{
				return _charge;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _charge, 1u);
			}
		}

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
		}

		public void OnDamageDealtServer(DamageReport damageReport)
		{
			AddChargeServer(damageReport.damageDealt);
		}

		public void OnTakeDamageServer(DamageReport damageReport)
		{
			AddChargeServer(damageReport.damageDealt);
		}

		[Server]
		private void AddChargeServer(float additionalCharge)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LoaderStaticChargeComponent::AddChargeServer(System.Single)' called on client");
				return;
			}
			float num = _charge + additionalCharge;
			if (num > maxCharge)
			{
				num = maxCharge;
			}
			Network_charge = num;
		}

		[Server]
		private void ConsumeChargeInternal()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.LoaderStaticChargeComponent::ConsumeChargeInternal()' called on client");
			}
			else
			{
				SetState(State.Drain);
			}
		}

		public void ConsumeChargeAuthority()
		{
			if (NetworkServer.active)
			{
				ConsumeChargeInternal();
			}
			else
			{
				CallCmdConsumeCharge();
			}
		}

		private void SetState(State newState)
		{
			if (state != newState)
			{
				if (state == State.Drain && NetworkServer.active)
				{
					characterBody.RemoveBuff(JunkContent.Buffs.LoaderOvercharged);
				}
				state = newState;
				if (state == State.Drain && NetworkServer.active)
				{
					characterBody.AddBuff(JunkContent.Buffs.LoaderOvercharged);
				}
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active && state == State.Drain)
			{
				Network_charge = _charge - Time.fixedDeltaTime * consumptionRate;
				if (_charge <= 0f)
				{
					Network_charge = 0f;
					SetState(State.Idle);
				}
			}
		}

		[Command]
		private void CmdConsumeCharge()
		{
			ConsumeChargeInternal();
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdConsumeCharge(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdConsumeCharge called on client.");
			}
			else
			{
				((LoaderStaticChargeComponent)obj).CmdConsumeCharge();
			}
		}

		public void CallCmdConsumeCharge()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdConsumeCharge called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdConsumeCharge();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdConsumeCharge);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdConsumeCharge");
		}

		static LoaderStaticChargeComponent()
		{
			kCmdCmdConsumeCharge = -261598328;
			NetworkBehaviour.RegisterCommandDelegate(typeof(LoaderStaticChargeComponent), kCmdCmdConsumeCharge, InvokeCmdCmdConsumeCharge);
			NetworkCRC.RegisterBehaviour("LoaderStaticChargeComponent", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_charge);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_charge);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_charge = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_charge = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class LocalCameraEffect : MonoBehaviour
	{
		public GameObject targetCharacter;

		public GameObject effectRoot;

		private static List<LocalCameraEffect> instancesList;

		static LocalCameraEffect()
		{
			instancesList = new List<LocalCameraEffect>();
			RoR2Application.onUpdate += CullNonLocalCameraEffects;
		}

		private static void CullNonLocalCameraEffects()
		{
			foreach (LocalCameraEffect instances in instancesList)
			{
				instances.effectRoot.SetActive(instances.TryFindLocalUserCameraRigController() != null);
			}
		}

		private CameraRigController TryFindLocalUserCameraRigController()
		{
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				CameraRigController cameraRigController = readOnlyLocalUsers.cameraRigController;
				if ((bool)cameraRigController && cameraRigController.target == targetCharacter && cameraRigController.cameraMode == CameraModePlayerBasic.playerBasic)
				{
					return cameraRigController;
				}
			}
			return null;
		}

		private void Start()
		{
			instancesList.Add(this);
			PostProcessVolume componentInChildren = effectRoot.GetComponentInChildren<PostProcessVolume>();
			if (componentInChildren != null)
			{
				CameraRigController cameraRigController = TryFindLocalUserCameraRigController();
				if (cameraRigController != null)
				{
					cameraRigController.SetPostProcessVolumeExclusive(componentInChildren);
				}
			}
		}

		private void OnDestroy()
		{
			instancesList.Remove(this);
		}
	}
	[ExecuteAlways]
	public class LookAtTransform : MonoBehaviour
	{
		public enum Axis
		{
			Right,
			Left,
			Up,
			Down,
			Forward,
			Backward
		}

		public Transform target;

		public Axis axis = Axis.Forward;

		private void LateUpdate()
		{
			if (!target)
			{
				return;
			}
			UnityEngine.Vector3 vector = target.position - base.transform.position;
			if (!(vector == UnityEngine.Vector3.zero))
			{
				switch (axis)
				{
				case Axis.Right:
					base.transform.right = vector;
					break;
				case Axis.Left:
					base.transform.right = -vector;
					break;
				case Axis.Up:
					base.transform.up = vector;
					break;
				case Axis.Down:
					base.transform.right = -vector;
					break;
				case Axis.Forward:
					base.transform.forward = vector;
					break;
				case Axis.Backward:
					base.transform.forward = -vector;
					break;
				default:
					throw new ArgumentOutOfRangeException();
				}
			}
		}
	}
	public class LoopSound : MonoBehaviour
	{
		public string akSoundString;

		public float repeatInterval;

		public Transform soundOwner;

		private float stopwatch;

		private void Update()
		{
			stopwatch += Time.deltaTime;
			if (stopwatch > repeatInterval)
			{
				stopwatch -= repeatInterval;
				if ((bool)soundOwner)
				{
					Util.PlaySound(akSoundString, soundOwner.gameObject);
				}
			}
		}
	}
	public class LoopSoundPlayer : MonoBehaviour
	{
		[SerializeField]
		private LoopSoundDef loopDef;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		private void OnEnable()
		{
			if ((bool)loopDef)
			{
				loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, loopDef);
			}
		}

		private void OnDisable()
		{
			if (loopPtr.isValid)
			{
				LoopSoundManager.StopSoundLoopLocal(loopPtr);
			}
		}
	}
	[RequireComponent(typeof(CharacterMotor))]
	[RequireComponent(typeof(CharacterBody))]
	public class LoopSoundWhileCharacterMoving : MonoBehaviour
	{
		[SerializeField]
		private string startSoundName;

		[SerializeField]
		private string stopSoundName;

		[SerializeField]
		private float minSpeed;

		[SerializeField]
		private bool requireGrounded;

		[SerializeField]
		private bool disableWhileSprinting;

		[SerializeField]
		private bool applyScale;

		private CharacterBody body;

		private CharacterMotor motor;

		private bool isLooping;

		private uint soundId;

		private void Start()
		{
			isLooping = false;
			body = GetComponent<CharacterBody>();
			motor = GetComponent<CharacterMotor>();
		}

		private void OnDestroy()
		{
			if (isLooping)
			{
				StopLoop();
			}
		}

		private void FixedUpdate()
		{
			if (!body || !motor)
			{
				return;
			}
			if (isLooping)
			{
				float magnitude = motor.velocity.magnitude;
				if (applyScale)
				{
					float num = body.moveSpeed;
					float num2 = num;
					if (!body.isSprinting)
					{
						num *= body.sprintingSpeedMultiplier;
					}
					else
					{
						num2 /= body.sprintingSpeedMultiplier;
					}
					float in_value = Mathf.Lerp(0f, 50f, magnitude / num2) + Mathf.Lerp(0f, 50f, (magnitude - num2) / (num - num2));
					AkSoundEngine.SetRTPCValueByPlayingID("charMultSpeed", in_value, soundId);
				}
				if ((body.isSprinting && disableWhileSprinting) || (requireGrounded && !motor.isGrounded) || magnitude < minSpeed)
				{
					StopLoop();
				}
			}
			else if ((!body.isSprinting || !disableWhileSprinting) && (!requireGrounded || motor.isGrounded) && motor.velocity.sqrMagnitude >= minSpeed)
			{
				StartLoop();
			}
		}

		private void StartLoop()
		{
			soundId = Util.PlaySound(startSoundName, base.gameObject);
			isLooping = true;
		}

		private void StopLoop()
		{
			Util.PlaySound(stopSoundName, base.gameObject);
			isLooping = false;
		}
	}
	[RequireComponent(typeof(NetworkedBodyAttachment))]
	public class LunarDetonatorPassiveAttachment : NetworkBehaviour, INetworkedBodyAttachmentListener
	{
		private class DamageListener : MonoBehaviour, IOnDamageDealtServerReceiver
		{
			public LunarDetonatorPassiveAttachment passiveController;

			public void OnDamageDealtServer(DamageReport damageReport)
			{
				if (passiveController.skillAvailable && damageReport.victim.alive && Util.CheckRoll(damageReport.damageInfo.procCoefficient * 100f, damageReport.attackerMaster))
				{
					damageReport.victimBody.AddTimedBuff(RoR2Content.Buffs.LunarDetonationCharge, 10f);
				}
			}
		}

		private GenericSkill _monitoredSkill;

		[SyncVar(hook = "SetSkillSlotIndexPlusOne")]
		private uint skillSlotIndexPlusOne;

		private bool skillAvailable;

		private NetworkedBodyAttachment networkedBodyAttachment;

		private DamageListener damageListener;

		private static int kCmdCmdSetSkillAvailable;

		public GenericSkill monitoredSkill
		{
			get
			{
				return _monitoredSkill;
			}
			set
			{
				if ((object)_monitoredSkill == value)
				{
					return;
				}
				_monitoredSkill = value;
				int num = -1;
				if ((bool)_monitoredSkill)
				{
					SkillLocator component = _monitoredSkill.GetComponent<SkillLocator>();
					if ((bool)component)
					{
						num = component.GetSkillSlotIndex(_monitoredSkill);
					}
				}
				SetSkillSlotIndexPlusOne((uint)(num + 1));
			}
		}

		public uint NetworkskillSlotIndexPlusOne
		{
			get
			{
				return skillSlotIndexPlusOne;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetSkillSlotIndexPlusOne(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref skillSlotIndexPlusOne, 1u);
			}
		}

		private void Awake()
		{
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
		}

		private void FixedUpdate()
		{
			if (networkedBodyAttachment.hasEffectiveAuthority)
			{
				FixedUpdateAuthority();
			}
		}

		private void OnDestroy()
		{
			if ((bool)damageListener)
			{
				UnityEngine.Object.Destroy(damageListener);
			}
			damageListener = null;
		}

		public override void OnStartClient()
		{
			SetSkillSlotIndexPlusOne(skillSlotIndexPlusOne);
		}

		private void SetSkillSlotIndexPlusOne(uint newSkillSlotIndexPlusOne)
		{
			NetworkskillSlotIndexPlusOne = newSkillSlotIndexPlusOne;
			if (!NetworkServer.active)
			{
				ResolveMonitoredSkill();
			}
		}

		private void ResolveMonitoredSkill()
		{
			if ((bool)networkedBodyAttachment.attachedBody)
			{
				SkillLocator component = networkedBodyAttachment.attachedBody.GetComponent<SkillLocator>();
				if ((bool)component)
				{
					monitoredSkill = component.GetSkillAtIndex((int)(skillSlotIndexPlusOne - 1));
				}
			}
		}

		private void FixedUpdateAuthority()
		{
			bool flag = false;
			if ((bool)monitoredSkill)
			{
				flag = monitoredSkill.stock > 0;
			}
			if (skillAvailable != flag)
			{
				skillAvailable = flag;
				if (!NetworkServer.active)
				{
					CallCmdSetSkillAvailable(skillAvailable);
				}
			}
		}

		[Command]
		private void CmdSetSkillAvailable(bool newSkillAvailable)
		{
			skillAvailable = newSkillAvailable;
		}

		public void OnAttachedBodyDiscovered(NetworkedBodyAttachment networkedBodyAttachment, CharacterBody attachedBody)
		{
			if (NetworkServer.active)
			{
				damageListener = attachedBody.gameObject.AddComponent<DamageListener>();
				damageListener.passiveController = this;
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdSetSkillAvailable(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetSkillAvailable called on client.");
			}
			else
			{
				((LunarDetonatorPassiveAttachment)obj).CmdSetSkillAvailable(reader.ReadBoolean());
			}
		}

		public void CallCmdSetSkillAvailable(bool newSkillAvailable)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetSkillAvailable called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetSkillAvailable(newSkillAvailable);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetSkillAvailable);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(newSkillAvailable);
			SendCommandInternal(networkWriter, 0, "CmdSetSkillAvailable");
		}

		static LunarDetonatorPassiveAttachment()
		{
			kCmdCmdSetSkillAvailable = -1453655134;
			NetworkBehaviour.RegisterCommandDelegate(typeof(LunarDetonatorPassiveAttachment), kCmdCmdSetSkillAvailable, InvokeCmdCmdSetSkillAvailable);
			NetworkCRC.RegisterBehaviour("LunarDetonatorPassiveAttachment", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32(skillSlotIndexPlusOne);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(skillSlotIndexPlusOne);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				skillSlotIndexPlusOne = reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetSkillSlotIndexPlusOne(reader.ReadPackedUInt32());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class MageCalibrationController : MonoBehaviour
	{
		[Serializable]
		public struct CalibrationInfo
		{
			public bool enableCalibrationOverlay;

			public Material calibrationOverlayMaterial;
		}

		public CalibrationInfo[] calibrationInfos;

		public SkinnedMeshRenderer calibrationOverlayRenderer;

		[Tooltip("The state machine upon which to perform the calibration state.")]
		public EntityStateMachine stateMachine;

		[Tooltip("The priority with which the calibration state will try to interrupt the current state.")]
		public InterruptPriority calibrationStateInterruptPriority;

		private CharacterBody characterBody;

		private bool hasEffectiveAuthority;

		private MageElement _currentElement;

		private static readonly int[] elementCounter = new int[4];

		private MageElement currentElement
		{
			get
			{
				return _currentElement;
			}
			set
			{
				if (value != _currentElement)
				{
					_currentElement = value;
					RefreshCalibrationElement(_currentElement);
				}
			}
		}

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
			characterBody.onInventoryChanged += OnInventoryChanged;
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
		}

		private void Start()
		{
			currentElement = GetAwardedElementFromInventory();
			RefreshCalibrationElement(currentElement);
		}

		private void OnDestroy()
		{
			characterBody.onInventoryChanged -= OnInventoryChanged;
		}

		private void OnInventoryChanged()
		{
			base.enabled = true;
		}

		private void FixedUpdate()
		{
			base.enabled = false;
			currentElement = GetAwardedElementFromInventory();
			if (hasEffectiveAuthority && currentElement == MageElement.None)
			{
				MageElement mageElement = CalcElementToAward();
				if (mageElement != 0 && !(stateMachine.state is MageCalibrate))
				{
					MageCalibrate mageCalibrate = new MageCalibrate();
					mageCalibrate.element = mageElement;
					stateMachine.SetInterruptState(mageCalibrate, calibrationStateInterruptPriority);
				}
			}
		}

		private MageElement GetAwardedElementFromInventory()
		{
			Inventory inventory = characterBody.inventory;
			if ((bool)inventory)
			{
				MageElement mageElement = (MageElement)inventory.GetItemCount(JunkContent.Items.MageAttunement);
				if ((int)mageElement >= 0 && (int)mageElement < 4)
				{
					return mageElement;
				}
			}
			return MageElement.None;
		}

		private MageElement CalcElementToAward()
		{
			for (int i = 0; i < elementCounter.Length; i++)
			{
				elementCounter[i] = 0;
			}
			Inventory inventory = characterBody.inventory;
			if (!inventory)
			{
				return MageElement.None;
			}
			List<ItemIndex> itemAcquisitionOrder = inventory.itemAcquisitionOrder;
			for (int j = 0; j < itemAcquisitionOrder.Count; j++)
			{
				ItemCatalog.GetItemDef(itemAcquisitionOrder[j]);
			}
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(inventory.currentEquipmentIndex);
			if ((bool)equipmentDef)
			{
				MageElement mageElement = equipmentDef.mageElement;
				if (mageElement != 0)
				{
					elementCounter[(uint)mageElement] += 2;
				}
			}
			MageElement result = MageElement.None;
			int num = 0;
			MageElement mageElement2 = MageElement.Fire;
			while ((int)mageElement2 < 4)
			{
				int num2 = elementCounter[(uint)mageElement2];
				if (num2 > num)
				{
					result = mageElement2;
					num = num2;
				}
				mageElement2++;
			}
			if (num >= 5)
			{
				return result;
			}
			return MageElement.None;
		}

		public MageElement GetActiveCalibrationElement()
		{
			return currentElement;
		}

		public void SetElement(MageElement newElement)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			Inventory inventory = characterBody.inventory;
			if ((bool)inventory)
			{
				MageElement mageElement = (MageElement)inventory.GetItemCount(JunkContent.Items.MageAttunement);
				if (mageElement != newElement)
				{
					int count = newElement - mageElement;
					inventory.GiveItem(JunkContent.Items.MageAttunement, count);
				}
			}
		}

		public void RefreshCalibrationElement(MageElement targetElement)
		{
			CalibrationInfo calibrationInfo = calibrationInfos[(uint)targetElement];
			calibrationOverlayRenderer.enabled = calibrationInfo.enableCalibrationOverlay;
			calibrationOverlayRenderer.material = calibrationInfo.calibrationOverlayMaterial;
		}
	}
	public class MapZone : MonoBehaviour
	{
		public enum TriggerType
		{
			TriggerExit,
			TriggerEnter
		}

		public enum ZoneType
		{
			OutOfBounds,
			KickOutPlayers
		}

		private struct CollisionInfo : IEquatable<CollisionInfo>
		{
			public readonly MapZone mapZone;

			public readonly Collider otherCollider;

			public CollisionInfo(MapZone mapZone, Collider otherCollider)
			{
				this.mapZone = mapZone;
				this.otherCollider = otherCollider;
			}

			public bool Equals(CollisionInfo other)
			{
				if ((object)mapZone == other.mapZone)
				{
					return (object)otherCollider == other.otherCollider;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is CollisionInfo)
				{
					return Equals((CollisionInfo)obj);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return otherCollider.GetHashCode();
			}
		}

		public TriggerType triggerType;

		public ZoneType zoneType;

		public Transform explicitDestination;

		public GameObject explicitSpawnEffectPrefab;

		public float destinationIdealRadius;

		private Collider collider;

		private readonly List<CollisionInfo> queuedCollisions = new List<CollisionInfo>();

		private static readonly Queue<Collider> collidersToCheckInFixedUpdate;

		public event Action<CharacterBody> onBodyTeleport;

		static MapZone()
		{
			collidersToCheckInFixedUpdate = new Queue<Collider>();
			VehicleSeat.onPassengerExitGlobal += CheckCharacterOnVehicleExit;
			RoR2Application.onFixedUpdate += StaticFixedUpdate;
		}

		private static bool TestColliders(Collider characterCollider, Collider triggerCollider)
		{
			UnityEngine.Vector3 direction;
			float distance;
			return Physics.ComputePenetration(characterCollider, characterCollider.transform.position, characterCollider.transform.rotation, triggerCollider, triggerCollider.transform.position, triggerCollider.transform.rotation, out direction, out distance);
		}

		private void Awake()
		{
			collider = GetComponent<Collider>();
		}

		public void OnTriggerEnter(Collider other)
		{
			if (triggerType == TriggerType.TriggerEnter)
			{
				TryZoneStart(other);
			}
			else
			{
				TryZoneEnd(other);
			}
		}

		public void OnTriggerExit(Collider other)
		{
			if (triggerType == TriggerType.TriggerExit)
			{
				TryZoneStart(other);
			}
			else
			{
				TryZoneEnd(other);
			}
		}

		public bool IsPointInsideMapZone(UnityEngine.Vector3 point)
		{
			if (collider == null)
			{
				return true;
			}
			return collider.bounds.Contains(point);
		}

		private void TryZoneStart(Collider other)
		{
			CharacterBody component = other.GetComponent<CharacterBody>();
			if (!component)
			{
				return;
			}
			if ((bool)component.currentVehicle)
			{
				if (component.currentVehicle.GetComponent<SojournVehicle>() == null)
				{
					queuedCollisions.Add(new CollisionInfo(this, other));
					return;
				}
				component.currentVehicle.EjectPassenger();
			}
			TeamComponent teamComponent = component.teamComponent;
			switch (zoneType)
			{
			case ZoneType.OutOfBounds:
			{
				bool flag = false;
				if ((bool)component.inventory)
				{
					flag = component.inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0 || component.inventory.GetItemCount(RoR2Content.Items.TeleportWhenOob) > 0;
				}
				if (teamComponent.teamIndex != TeamIndex.Player && !flag)
				{
					if (!NetworkServer.active || Physics.GetIgnoreLayerCollision(base.gameObject.layer, other.gameObject.layer))
					{
						break;
					}
					UnityEngine.Debug.LogFormat("Killing {0} for being out of bounds.", component.gameObject);
					HealthComponent healthComponent = component.healthComponent;
					if ((bool)healthComponent)
					{
						if ((bool)component.master)
						{
							component.master.TrueKill(healthComponent.lastHitAttacker, base.gameObject, DamageType.OutOfBounds);
						}
						else
						{
							healthComponent.Suicide(healthComponent.lastHitAttacker, base.gameObject, DamageType.OutOfBounds);
						}
					}
					else if ((bool)component.master)
					{
						component.master.TrueKill(null, null, DamageType.OutOfBounds);
					}
				}
				else
				{
					TeleportBody(component);
				}
				break;
			}
			case ZoneType.KickOutPlayers:
				if (teamComponent.teamIndex == TeamIndex.Player)
				{
					TeleportBody(component);
				}
				break;
			}
		}

		private void TryZoneEnd(Collider other)
		{
			if (queuedCollisions.Count != 0 && queuedCollisions.Contains(new CollisionInfo(this, other)))
			{
				queuedCollisions.Remove(new CollisionInfo(this, other));
			}
		}

		private void ProcessQueuedCollisionsForCollider(Collider collider)
		{
			for (int num = queuedCollisions.Count - 1; num >= 0; num--)
			{
				if ((object)queuedCollisions[num].otherCollider == collider)
				{
					queuedCollisions.RemoveAt(num);
					TryZoneStart(collider);
				}
			}
		}

		private static void StaticFixedUpdate()
		{
			int i = 0;
			for (int count = collidersToCheckInFixedUpdate.Count; i < count; i++)
			{
				Collider collider = collidersToCheckInFixedUpdate.Dequeue();
				if (!collider)
				{
					continue;
				}
				foreach (MapZone instances in InstanceTracker.GetInstancesList<MapZone>())
				{
					instances.ProcessQueuedCollisionsForCollider(collider);
				}
			}
		}

		private static void CheckCharacterOnVehicleExit(VehicleSeat vehicleSeat, GameObject passengerObject)
		{
			Collider component = passengerObject.GetComponent<Collider>();
			collidersToCheckInFixedUpdate.Enqueue(component);
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		private void TeleportBody(CharacterBody characterBody)
		{
			if (Util.HasEffectiveAuthority(characterBody.gameObject) && !Physics.GetIgnoreLayerCollision(base.gameObject.layer, characterBody.gameObject.layer))
			{
				UnityEngine.Vector3 vector = Run.instance.FindSafeTeleportPosition(characterBody, explicitDestination, 0f, destinationIdealRadius);
				TeleportHelper.TeleportBody(characterBody, vector);
				GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(characterBody.gameObject);
				if ((bool)explicitSpawnEffectPrefab)
				{
					teleportEffectPrefab = explicitSpawnEffectPrefab;
				}
				if ((bool)teleportEffectPrefab)
				{
					EffectManager.SimpleEffect(teleportEffectPrefab, vector, UnityEngine.Quaternion.identity, transmit: true);
				}
				this.onBodyTeleport?.Invoke(characterBody);
			}
		}
	}
	[RequireComponent(typeof(CharacterMaster))]
	public class MasterDropDroplet : MonoBehaviour
	{
		private CharacterMaster characterMaster;

		public PickupDropTable[] dropTables;

		public ulong salt;

		[Header("Deprecated")]
		public SerializablePickupIndex[] pickupsToDrop;

		private Xoroshiro128Plus rng;

		private void Start()
		{
			characterMaster = GetComponent<CharacterMaster>();
			rng = new Xoroshiro128Plus(Run.instance.seed ^ salt);
		}

		public void DropItems()
		{
			CharacterBody body = characterMaster.GetBody();
			if (!body)
			{
				return;
			}
			PickupDropTable[] array = dropTables;
			foreach (PickupDropTable pickupDropTable in array)
			{
				if ((bool)pickupDropTable)
				{
					PickupDropletController.CreatePickupDroplet(pickupDropTable.GenerateDrop(rng), body.coreTransform.position, new UnityEngine.Vector3(UnityEngine.Random.Range(-4f, 4f), 20f, UnityEngine.Random.Range(-4f, 4f)));
				}
			}
			SerializablePickupIndex[] array2 = pickupsToDrop;
			for (int i = 0; i < array2.Length; i++)
			{
				PickupDropletController.CreatePickupDroplet(PickupCatalog.FindPickupIndex(array2[i].pickupName), body.coreTransform.position, new UnityEngine.Vector3(UnityEngine.Random.Range(-4f, 4f), 20f, UnityEngine.Random.Range(-4f, 4f)));
			}
		}
	}
	public class MasterSpawnSlotController : NetworkBehaviour
	{
		public interface ISlot
		{
			bool IsOpen();

			void Spawn(GameObject summonerBodyObject, Xoroshiro128Plus rng, Action<ISlot, SpawnCard.SpawnResult> callback = null);

			void Kill();
		}

		public List<ISlot> slots = new List<ISlot>();

		[SyncVar]
		private int _openSlotCount;

		public int openSlotCount
		{
			get
			{
				if (NetworkServer.active)
				{
					return CalcOpenSlotCount();
				}
				return _openSlotCount;
			}
		}

		public int Network_openSlotCount
		{
			get
			{
				return _openSlotCount;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _openSlotCount, 1u);
			}
		}

		private int CalcOpenSlotCount()
		{
			int num = 0;
			foreach (ISlot slot in slots)
			{
				if (slot.IsOpen())
				{
					num++;
				}
			}
			return num;
		}

		private void OnEnable()
		{
			GetComponents(slots);
		}

		[Server]
		public void SpawnAllOpen(GameObject summonerBodyObject, Xoroshiro128Plus rng, Action<ISlot, SpawnCard.SpawnResult> callback = null)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MasterSpawnSlotController::SpawnAllOpen(UnityEngine.GameObject,Xoroshiro128Plus,System.Action`2<RoR2.MasterSpawnSlotController/ISlot,RoR2.SpawnCard/SpawnResult>)' called on client");
				return;
			}
			foreach (ISlot slot in slots)
			{
				if (slot.IsOpen())
				{
					slot.Spawn(summonerBodyObject, rng, callback);
				}
			}
		}

		[Server]
		public void SpawnRandomOpen(int spawnCount, Xoroshiro128Plus rng, GameObject summonerBodyObject, Action<ISlot, SpawnCard.SpawnResult> callback = null)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MasterSpawnSlotController::SpawnRandomOpen(System.Int32,Xoroshiro128Plus,UnityEngine.GameObject,System.Action`2<RoR2.MasterSpawnSlotController/ISlot,RoR2.SpawnCard/SpawnResult>)' called on client");
				return;
			}
			List<ISlot> list = new List<ISlot>();
			foreach (ISlot slot in slots)
			{
				if (slot.IsOpen())
				{
					list.Add(slot);
				}
			}
			Util.ShuffleList(list, rng);
			for (int i = 0; i < spawnCount && i < list.Count; i++)
			{
				list[i].Spawn(summonerBodyObject, rng, callback);
			}
		}

		[Server]
		public void KillAll()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MasterSpawnSlotController::KillAll()' called on client");
				return;
			}
			foreach (ISlot slot in slots)
			{
				slot.Kill();
			}
		}

		private void Update()
		{
			if (NetworkServer.active)
			{
				Network_openSlotCount = CalcOpenSlotCount();
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)_openSlotCount);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)_openSlotCount);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_openSlotCount = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_openSlotCount = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class MasterSuicideOnTimer : MonoBehaviour
	{
		public float lifeTimer;

		[Tooltip("Reset the timer if we're within this radius of the owner")]
		public float timerResetDistanceToOwner;

		public MinionOwnership minionOwnership;

		private CharacterBody body;

		private CharacterBody ownerBody;

		private float timer;

		private bool hasDied;

		private CharacterMaster characterMaster;

		private void Start()
		{
			characterMaster = GetComponent<CharacterMaster>();
			if ((bool)minionOwnership && (bool)minionOwnership.ownerMaster)
			{
				ownerBody = minionOwnership.ownerMaster.GetBody();
			}
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if ((bool)ownerBody)
			{
				if (!body)
				{
					body = characterMaster.GetBody();
				}
				if ((bool)body && (ownerBody.transform.position - body.transform.position).sqrMagnitude < timerResetDistanceToOwner * timerResetDistanceToOwner)
				{
					timer = 0f;
				}
			}
			timer += Time.fixedDeltaTime;
			if (!(timer >= lifeTimer) || hasDied)
			{
				return;
			}
			GameObject bodyObject = characterMaster.GetBodyObject();
			if ((bool)bodyObject)
			{
				HealthComponent component = bodyObject.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					component.Suicide();
					hasDied = true;
				}
			}
		}
	}
	[ExecuteInEditMode]
	[RequireComponent(typeof(Camera))]
	public class MatchCamera : MonoBehaviour
	{
		private Camera destCamera;

		public Camera srcCamera;

		public bool matchFOV = true;

		public bool matchRect = true;

		public bool matchPosition;

		private void Awake()
		{
			destCamera = GetComponent<Camera>();
		}

		private void LateUpdate()
		{
			if ((bool)srcCamera)
			{
				if (matchRect)
				{
					destCamera.rect = srcCamera.rect;
				}
				if (matchFOV)
				{
					destCamera.fieldOfView = srcCamera.fieldOfView;
				}
				if (matchPosition)
				{
					destCamera.transform.position = srcCamera.transform.position;
					destCamera.transform.rotation = srcCamera.transform.rotation;
				}
			}
		}
	}
	[ExecuteAlways]
	public class MatchTransform : MonoBehaviour
	{
		public Transform targetTransform;

		public void LateUpdate()
		{
			UpdateNow();
		}

		[ContextMenu("Update Now")]
		public void UpdateNow()
		{
			if ((bool)targetTransform)
			{
				base.transform.SetPositionAndRotation(targetTransform.position, targetTransform.rotation);
			}
		}
	}
	public class MeridianEventLightningTrigger : NetworkBehaviour
	{
		public GameObject lightningStorm;

		public CombatDirector enemySpawnerScript;

		public bool lightningToggle;

		public bool enemySpawnToggle;

		private float monsterCredit;

		[SerializeField]
		private float levelstartMonsterCredit;

		[SerializeField]
		private float expRewardCoefficient;

		[SerializeField]
		private float eliteBias;

		[SerializeField]
		private float spawnDistanceMultiplier;

		private void Start()
		{
			if (NetworkServer.active)
			{
				monsterCredit = (int)(levelstartMonsterCredit * Run.instance.difficultyCoefficient);
			}
		}

		public void OnTriggerExit(Collider other)
		{
			if (other.TryGetComponent<CharacterBody>(out var component) && component.isPlayerControlled)
			{
				LightningStormController.SetStormActive(lightningToggle);
				enemySpawnerScript.enabled = enemySpawnToggle;
				PopulateSceneWithMonsters();
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void PopulateSceneWithMonsters()
		{
			float num = enemySpawnerScript.expRewardCoefficient;
			float num2 = enemySpawnerScript.eliteBias;
			float num3 = enemySpawnerScript.spawnDistanceMultiplier;
			enemySpawnerScript.monsterCredit += monsterCredit;
			enemySpawnerScript.expRewardCoefficient = expRewardCoefficient;
			enemySpawnerScript.eliteBias = eliteBias;
			enemySpawnerScript.spawnDistanceMultiplier = spawnDistanceMultiplier;
			monsterCredit = 0f;
			enemySpawnerScript.SpendAllCreditsOnMapSpawns(TeleporterInteraction.instance ? TeleporterInteraction.instance.transform : null);
			enemySpawnerScript.expRewardCoefficient = num;
			enemySpawnerScript.eliteBias = num2;
			enemySpawnerScript.spawnDistanceMultiplier = num3;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[Serializable]
	public struct GameObjectsToModify
	{
		public GameObject[] objects;

		public Material idleMaterial;

		public Material eventMaterial;
	}
	[RequireComponent(typeof(EntityStateMachine))]
	public class MeridianEventTriggerInteraction : NetworkBehaviour, IDisplayNameProvider
	{
		public enum RingFallingState
		{
			None,
			OuterRingFalling,
			MiddleRingFalling
		}

		public class MeridianEventBaseState : EntityState
		{
			protected MeridianEventTriggerInteraction meridianEventTriggerInteraction => instance;
		}

		public class MeridianEventStart : MeridianEventBaseState
		{
			public static event Action OnMeridianEventStart;

			public override void OnEnter()
			{
				base.OnEnter();
				MeridianEventStart.OnMeridianEventStart?.Invoke();
				base.meridianEventTriggerInteraction.EventPPVolume.SetActive(value: true);
				base.meridianEventTriggerInteraction.HandleNodeGateActivation(0);
				if (NetworkServer.active)
				{
					base.meridianEventTriggerInteraction.CallRpcSetEventMaterials();
				}
				base.meridianEventTriggerInteraction.SetEventObjects();
				base.meridianEventTriggerInteraction.isHeadRotating = true;
				outer.SetNextState(new Phase1());
			}
		}

		public class FSBFEncounterBaseState : EntityState
		{
			protected ChildLocator childLocator;

			protected MeridianEventTriggerInteraction meridianEventTriggerInteraction => instance;

			public override void OnEnter()
			{
				base.OnEnter();
				childLocator = GetComponent<ChildLocator>();
			}

			public override void OnExit()
			{
				base.OnExit();
			}

			public void KillAllMonsters()
			{
				if (!NetworkServer.active)
				{
					return;
				}
				foreach (TeamComponent item in new List<TeamComponent>(TeamComponent.GetTeamMembers(TeamIndex.Monster)))
				{
					if ((bool)item)
					{
						HealthComponent component = item.GetComponent<HealthComponent>();
						if ((bool)component)
						{
							component.Suicide();
						}
					}
				}
			}
		}

		public abstract class FSBFPhaseBaseState : FSBFEncounterBaseState
		{
			[NonSerialized]
			public static bool readyToSpawnNextBossBody;

			[SerializeField]
			public float durationBeforeEnablingCombatEncounter;

			[SerializeField]
			public float durationBeforeRingsSpawn;

			[SerializeField]
			public GameObject speechControllerPrefab;

			[SerializeField]
			public GameObject spawnVFX;

			protected ScriptedCombatEncounter phaseScriptedCombatEncounter;

			protected GameObject phaseControllerObject;

			protected GameObject phaseControllerSubObjectContainer;

			protected BossGroup phaseBossGroup;

			private bool hasSpawned;

			private bool spawnedNextState;

			private const float minimumDurationPerPhase = 2f;

			private Run.FixedTimeStamp healthBarShowTime = Run.FixedTimeStamp.positiveInfinity;

			protected abstract EntityState nextState { get; }

			protected abstract string phaseControllerChildString { get; }

			protected virtual float healthBarShowDelay => 0f;

			public override void OnEnter()
			{
				base.OnEnter();
				if (!base.meridianEventTriggerInteraction.isFirstPhase)
				{
					speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBoss1PhaseSpeechController;
					base.meridianEventTriggerInteraction.isFirstPhase = true;
				}
				else if (!base.meridianEventTriggerInteraction.isFinalPhase)
				{
					speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBossEarlySpeechController;
				}
				else
				{
					speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBossLateSpeechController;
				}
				if ((bool)childLocator)
				{
					phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject;
					if ((bool)phaseControllerObject)
					{
						phaseScriptedCombatEncounter = phaseControllerObject.GetComponent<ScriptedCombatEncounter>();
						phaseBossGroup = phaseControllerObject.GetComponent<BossGroup>();
					}
				}
				healthBarShowTime = Run.FixedTimeStamp.now + healthBarShowDelay;
				if ((bool)DirectorCore.instance)
				{
					CombatDirector[] components = DirectorCore.instance.GetComponents<CombatDirector>();
					for (int i = 0; i < components.Length; i++)
					{
						components[i].enabled = false;
					}
				}
				if (NetworkServer.active && (object)phaseScriptedCombatEncounter != null)
				{
					phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer += OnMemberAddedServer;
				}
			}

			public override void OnExit()
			{
				if (NetworkServer.active)
				{
					if ((object)phaseScriptedCombatEncounter != null)
					{
						phaseScriptedCombatEncounter.combatSquad.onMemberAddedServer -= OnMemberAddedServer;
					}
					if ((bool)phaseControllerSubObjectContainer)
					{
						phaseControllerSubObjectContainer.SetActive(value: false);
					}
				}
				if ((bool)phaseBossGroup)
				{
					phaseBossGroup.shouldDisplayHealthBarOnHud = false;
				}
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				phaseBossGroup.shouldDisplayHealthBarOnHud = healthBarShowTime.hasPassed;
				if (!hasSpawned && readyToSpawnNextBossBody && base.fixedAge > durationBeforeEnablingCombatEncounter)
				{
					BeginEncounter();
				}
				else if (hasSpawned && readyToSpawnNextBossBody && !spawnedNextState && base.fixedAge > 2f + durationBeforeEnablingCombatEncounter && (bool)phaseScriptedCombatEncounter && phaseScriptedCombatEncounter.combatSquad.memberCount == 0)
				{
					spawnedNextState = true;
					outer.SetNextState(nextState);
				}
			}

			protected void BeginEncounter()
			{
				readyToSpawnNextBossBody = false;
				hasSpawned = true;
				PreEncounterBegin();
				if (NetworkServer.active)
				{
					phaseScriptedCombatEncounter.BeginEncounter();
				}
			}

			protected virtual void PreEncounterBegin()
			{
			}

			protected virtual void OnMemberAddedServer(CharacterMaster master)
			{
				if ((bool)speechControllerPrefab)
				{
					UnityEngine.Object.Instantiate(speechControllerPrefab, master.transform).GetComponent<CharacterSpeechController>().characterMaster = master;
				}
			}
		}

		public class Phase1 : FSBFPhaseBaseState
		{
			private bool spawnedEntryFX;

			private bool lightningStarted;

			protected override string phaseControllerChildString => "Phase1";

			protected override EntityState nextState => new Phase2();

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (base.fixedAge > 15f && !lightningStarted)
				{
					lightningStarted = true;
					base.meridianEventTriggerInteraction.arenaGeode3.SetActive(value: true);
					base.meridianEventTriggerInteraction.arenaGeode4.SetActive(value: true);
				}
				if (!spawnedEntryFX && base.fixedAge > base.meridianEventTriggerInteraction.additionalEntryVFXDelay + durationBeforeEnablingCombatEncounter)
				{
					spawnedEntryFX = true;
					SetPlayersInvulnerable(b: false);
					EffectManager.SpawnEffect(base.meridianEventTriggerInteraction.falseSonEntryFX, new EffectData
					{
						origin = base.meridianEventTriggerInteraction.falseSonEntryFXPosition.position
					}, transmit: false);
					base.meridianEventTriggerInteraction.musicPhaseNone.SetActive(value: false);
					base.meridianEventTriggerInteraction.musicPhaseOne.SetActive(value: true);
				}
				if (spawnedEntryFX && base.meridianEventTriggerInteraction.meridianColumnsGameObject.activeInHierarchy && !base.meridianEventTriggerInteraction.meridianPlayableColumns.activeInHierarchy && base.fixedAge > base.meridianEventTriggerInteraction.additionalEntryVFXDelay + durationBeforeEnablingCombatEncounter + 3f)
				{
					base.meridianEventTriggerInteraction.meridianColumnsGameObject.SetActive(value: false);
					base.meridianEventTriggerInteraction.meridianPlayableColumns.SetActive(value: true);
				}
			}

			public override void OnEnter()
			{
				base.meridianEventTriggerInteraction.onFalseSonAppearance.SetActive(value: true);
				base.meridianEventTriggerInteraction.HandleNodeGateActivation(0);
				durationBeforeEnablingCombatEncounter = 7f;
				KillAllMonsters();
				base.OnEnter();
				FSBFPhaseBaseState.readyToSpawnNextBossBody = true;
				Util.PlaySound("Play_boss_falseson_VO_spawn", base.gameObject);
				base.meridianEventTriggerInteraction.Boundary1.SetActive(value: true);
				if (NetworkServer.active)
				{
					SetPlayersInvulnerable(b: true);
				}
			}

			protected override void OnMemberAddedServer(CharacterMaster master)
			{
				base.OnMemberAddedServer(master);
			}
		}

		public class Phase2 : FSBFPhaseBaseState
		{
			private bool startRingsFalling;

			protected override string phaseControllerChildString => "Phase2";

			protected override EntityState nextState => new Phase3();

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (base.fixedAge > durationBeforeRingsSpawn && !startRingsFalling)
				{
					base.meridianEventTriggerInteraction.Boundary1.SetActive(value: false);
					base.meridianEventTriggerInteraction.Boundary2.SetActive(value: true);
					base.meridianEventTriggerInteraction.StartOuterRingFalling();
					base.meridianEventTriggerInteraction.arenaGeode3.SetActive(value: false);
					startRingsFalling = true;
				}
			}

			public override void OnEnter()
			{
				base.meridianEventTriggerInteraction.onEnteringPhase2.SetActive(value: true);
				base.meridianEventTriggerInteraction.HandleNodeGateActivation(1);
				base.meridianEventTriggerInteraction.phase2CombatDirector.SetActive(value: true);
				durationBeforeEnablingCombatEncounter = 1f;
				durationBeforeRingsSpawn = 1.75f;
				childLocator = GetComponent<ChildLocator>();
				phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject;
				Util.PlaySound("Play_boss_falseson_VO_spawn", base.gameObject);
				Util.PlaySound("Play_boss_falseson_VO_anger", base.gameObject);
				base.OnEnter();
				SetPlayersInvulnerable(b: false);
			}

			public override void OnExit()
			{
				base.meridianEventTriggerInteraction.isFinalPhase = true;
				base.meridianEventTriggerInteraction.phase2CombatDirector.SetActive(value: false);
				KillAllMonsters();
				base.OnExit();
			}

			protected override void OnMemberAddedServer(CharacterMaster master)
			{
				base.OnMemberAddedServer(master);
			}
		}

		public class Phase3 : FSBFPhaseBaseState
		{
			private bool startRingsFalling;

			protected override string phaseControllerChildString => "Phase3";

			protected override EntityState nextState => new MeridianEventCleared();

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (base.fixedAge > durationBeforeRingsSpawn && !startRingsFalling)
				{
					base.meridianEventTriggerInteraction.Boundary2.SetActive(value: false);
					base.meridianEventTriggerInteraction.Boundary3.SetActive(value: true);
					base.meridianEventTriggerInteraction.StartMiddleRingFalling();
					base.meridianEventTriggerInteraction.arenaGeode4.SetActive(value: false);
					startRingsFalling = true;
				}
			}

			public override void OnEnter()
			{
				speechControllerPrefab = base.meridianEventTriggerInteraction.falseSonBossLateSpeechController;
				if (NetworkServer.active)
				{
					LightningStormController.SetStormStrikePattern(base.meridianEventTriggerInteraction.bossLightningStrikePattern);
					LightningStormController.SetStormActive(b: true);
				}
				base.meridianEventTriggerInteraction.onEnteringPhase3.SetActive(value: true);
				base.meridianEventTriggerInteraction.HandleNodeGateActivation(2);
				durationBeforeEnablingCombatEncounter = 1f;
				durationBeforeRingsSpawn = 1.75f;
				childLocator = GetComponent<ChildLocator>();
				phaseControllerObject = childLocator.FindChild(phaseControllerChildString).gameObject;
				GoldTitanManager.onGoldTitanSpawned += IsAurelionitePresent;
				Util.PlaySound("Play_boss_falseson_VO_spawn", base.gameObject);
				base.OnEnter();
			}

			public override void OnExit()
			{
				base.OnExit();
				GoldTitanManager.onGoldTitanSpawned -= IsAurelionitePresent;
			}

			protected override void OnMemberAddedServer(CharacterMaster master)
			{
				base.OnMemberAddedServer(master);
			}

			private void IsAurelionitePresent()
			{
				instance.isGoldTitanSpawned = true;
			}
		}

		public class MeridianEventCleared : MeridianEventBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				base.meridianEventTriggerInteraction.EventCompletePPVolume.SetActive(value: true);
				base.meridianEventTriggerInteraction.EventPPVolume.SetActive(value: false);
				base.meridianEventTriggerInteraction.shrineModel.SetActive(value: true);
				base.meridianEventTriggerInteraction.shrine.GetComponent<ShrineRebirthController>().stateMachine.SetNextStateToMain();
				base.meridianEventTriggerInteraction.finalPillars.SetActive(value: true);
				base.meridianEventTriggerInteraction.meridianRain.SetActive(value: false);
				base.meridianEventTriggerInteraction.meridianStormCloud.SetActive(value: false);
				base.meridianEventTriggerInteraction.eventClearedVFX.SetActive(value: true);
				base.meridianEventTriggerInteraction.arenaGeode1.SetActive(value: false);
				base.meridianEventTriggerInteraction.arenaGeode2.SetActive(value: false);
				base.meridianEventTriggerInteraction.bossFightAMB.Stop(base.gameObject);
				base.meridianEventTriggerInteraction.bossDefeatAMB.Post(base.gameObject);
				Util.PlaySound("Play_env_meridian_level_cleared", base.gameObject);
				if (!NetworkServer.active)
				{
					return;
				}
				GameObject[] destinationPortals = base.meridianEventTriggerInteraction.destinationPortals;
				for (int i = 0; i < destinationPortals.Length; i++)
				{
					destinationPortals[i].SetActive(value: true);
				}
				foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
				{
					if (!(instance == null))
					{
						CharacterBody body = instance.master.GetBody();
						if (!(body == null))
						{
							Util.CleanseBody(body, removeDebuffs: true, removeBuffs: false, removeCooldownBuffs: false, removeDots: false, removeStun: false, removeNearbyProjectiles: false);
						}
					}
				}
			}
		}

		[HideInInspector]
		public static Transform bossTransform;

		public string contextToken = "MERIDIAN_EVENTTRIGGER_CONTEXT";

		public string displayNameToken = "MERIDIAN_EVENTTRIGGER_NAME";

		public int minimumNumberToSpawnPerMonsterType;

		public int maximumNumberToSpawnBeforeSkipping;

		public GameObject eventGateStateObject;

		public GameObject eventGateStatePhase2Object;

		public GameObject eventGateStatePhase3Object;

		public CombatDirector combatDirectorWave1;

		public CombatDirector combatDirectorWave2;

		public SceneExitController sceneExitController;

		[Header("Post Process Volumes")]
		public GameObject EventPPVolume;

		public GameObject EventCompletePPVolume;

		public GameObject AfterEventCompletePPVolume;

		[Header("Destination Portals")]
		public GameObject[] destinationPortals;

		[Header("Colossus Head")]
		public GameObject colossusHead;

		public Transform colossusHeadFinalPosition;

		public float colossusHeadDuration = 420f;

		private bool isHeadRotating;

		[Header("False Son Core")]
		public GameObject falseSonCore;

		[Header("Game Objects to Modify")]
		public GameObjectsToModify[] gameObjectsToModify;

		[Header("Event Objects to Toggle")]
		public GameObject[] eventGameObjectsToToggle;

		[Header("Cleaered Objects to Toggle")]
		public GameObject[] clearedGameObjectsToToggle;

		[Header("False Son Boss Encounter")]
		public ScriptedCombatEncounter falseSonBossEncounter;

		public BossGroup falseSonBossGroup;

		public CombatDirector combatDirector;

		[Header("Teleport Locs")]
		public GameObject playerTPLoc1;

		public GameObject playerTPLoc2;

		public GameObject playerTPLoc3;

		public GameObject playerTPLoc4;

		private GameObject[] playerTPLocs = new GameObject[4];

		[Header("Cutscene")]
		public GameObject cutsceneCamera;

		public AK.Wwise.Event startSceneAMB;

		public AK.Wwise.Event bossFightAMB;

		public AK.Wwise.Event bossDefeatAMB;

		[Header("Boss Music Phases")]
		public GameObject musicPhaseNone;

		public GameObject musicPhaseOne;

		public GameObject musicPhaseTwo;

		public GameObject musicPhaseThree;

		public GameObject musicPhaseBossDead;

		[Header("Arena Setup")]
		public GameObject lightningStorm;

		public GameObject fog;

		public GameObject sceneBoundsOld;

		public GameObject sceneBoundsNew;

		public GameObject meridianColumnsGameObject;

		public GameObject meridianPlayableColumns;

		public LightningStrikePattern bossLightningStrikePattern;

		[Header("Phase 1 Spawn FX Data")]
		[SerializeField]
		[HideInInspector]
		public GameObject falseSonEntryFX;

		[SerializeField]
		public Transform falseSonEntryFXPosition;

		[SerializeField]
		public float additionalEntryVFXDelay;

		[Header("In-Scene Phase Transition VFX - should automatically disable itself")]
		public GameObject onFalseSonAppearance;

		public GameObject onEnteringPhase2;

		public GameObject onEnteringPhase3;

		[Space(20f)]
		public float ringFallOffTime = 50f;

		[HideInInspector]
		public int ringFallingState;

		private int localRingFallingState;

		[Header("Rings Locs")]
		public GameObject ringPiece1;

		public GameObject ringPiece2;

		public GameObject ringPiece3;

		public GameObject ringPiece4;

		public GameObject ringPiece5;

		public GameObject ringPiece6;

		public GameObject ringPiece7;

		public GameObject ringPiece8;

		public GameObject ringPiece9;

		public GameObject ringPiece10;

		public GameObject ringPiece1FinalPosition;

		public GameObject ringPiece2FinalPosition;

		public GameObject ringPiece3FinalPosition;

		public GameObject ringPiece4FinalPosition;

		public GameObject ringPiece5FinalPosition;

		public GameObject ringPiece6FinalPosition;

		public GameObject ringPiece7FinalPosition;

		public GameObject ringPiece8FinalPosition;

		public GameObject ringPiece9FinalPosition;

		public GameObject ringPiece10FinalPosition;

		[Header("Arena Finale")]
		public GameObject shrine;

		public GameObject shrineModel;

		public GameObject finalPillars;

		public GameObject eventClearedVFX;

		public GameObject meridianRain;

		public GameObject meridianStormCloud;

		[Header("Geode System")]
		public GameObject arenaGeode1;

		public GameObject arenaGeode2;

		public GameObject arenaGeode3;

		public GameObject arenaGeode4;

		[Header("Boss Bounds System")]
		public GameObject Boundary1;

		public GameObject Boundary2;

		public GameObject Boundary3;

		[Header("Boss Dialogue Prefabs")]
		public GameObject falseSonBossEarlySpeechController;

		public GameObject falseSonBossLateSpeechController;

		public GameObject falseSonBoss1PhaseSpeechController;

		[HideInInspector]
		public bool isFirstPhase;

		[HideInInspector]
		public bool isFinalPhase;

		[HideInInspector]
		public bool isGoldTitanSpawned;

		[Header("Monster Waves Combat Director Prefabs")]
		public GameObject phase2CombatDirector;

		private EntityStateMachine mainStateMachine;

		private bool triggerEventClear;

		[SyncVar(hook = "Client_HandleStartMeridianEvent")]
		public bool isTriggered;

		private static int kRpcRpcTeleportWithLocalAuthority;

		private static int kRpcRpcOnFalseSonDefeated;

		private static int kRpcRpcSetEventMaterials;

		public static MeridianEventTriggerInteraction instance { get; private set; }

		protected MeridianEventTriggerInteraction eventTriggerInteraction { get; private set; }

		public bool NetworkisTriggered
		{
			get
			{
				return isTriggered;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					Client_HandleStartMeridianEvent(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref isTriggered, 1u);
			}
		}

		public static event Action<MeridianEventTriggerInteraction> onDefeatedServerGlobal;

		public static event Action<MeridianEventTriggerInteraction, Interactor> onActivated;

		public static event Action onInstanceChangedGlobal;

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextToken);
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (isTriggered)
			{
				return Interactability.Disabled;
			}
			return Interactability.Available;
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public bool ShouldShowOnScanner()
		{
			return !isTriggered;
		}

		private void Start()
		{
			eventTriggerInteraction = GetComponent<MeridianEventTriggerInteraction>();
		}

		public void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			MeridianEventTriggerInteraction.onInstanceChangedGlobal?.Invoke();
			if (falseSonEntryFX == null)
			{
				AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("FalseSonBoss/FalseSonBossAppearVFX");
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> result)
				{
					falseSonEntryFX = result.Result;
				};
			}
		}

		public void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			MeridianEventTriggerInteraction.onInstanceChangedGlobal?.Invoke();
		}

		[Server]
		public override void OnStartServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MeridianEventTriggerInteraction::OnStartServer()' called on client");
				return;
			}
			base.OnStartServer();
			startSceneAMB.Post(base.gameObject);
		}

		public void OnTriggerEnter(Collider other)
		{
			if (NetworkServer.active && !isTriggered && other.TryGetComponent<CharacterBody>(out var component) && component.isPlayerControlled)
			{
				HandleInitializeMeridianEvent();
			}
		}

		public static void SetPlayersInvulnerable(bool b)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (instance == null)
				{
					continue;
				}
				CharacterBody body = instance.master.GetBody();
				if (!(body == null))
				{
					if (b)
					{
						body.AddTimedBuff(DLC2Content.Buffs.HiddenRejectAllDamage, 1.5f);
					}
					else if (body.HasBuff(DLC2Content.Buffs.HiddenRejectAllDamage))
					{
						body.RemoveBuff(DLC2Content.Buffs.HiddenRejectAllDamage);
					}
				}
			}
		}

		[Server]
		private void HandleInitializeMeridianEvent()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MeridianEventTriggerInteraction::HandleInitializeMeridianEvent()' called on client");
				return;
			}
			LightningStormController.SetStormActive(b: false);
			combatDirector.enabled = false;
			playerTPLocs[0] = playerTPLoc1;
			playerTPLocs[1] = playerTPLoc2;
			playerTPLocs[2] = playerTPLoc3;
			playerTPLocs[3] = playerTPLoc4;
			int num = 0;
			int num2 = 0;
			int count = PlayerCharacterMasterController.instances.Count;
			bool flag = count > 4;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (instance == null)
				{
					continue;
				}
				UnityEngine.Vector3 vector;
				UnityEngine.Quaternion rotation;
				if (flag)
				{
					int num3 = playerTPLocs.Length - 1;
					float num4 = (float)num2 / (float)(count - 1) * (float)num3;
					int num5 = Mathf.Clamp(Mathf.FloorToInt(num4), 0, num3 - 1);
					float t = num4 - (float)num5;
					Transform obj = playerTPLocs[num5].transform;
					Transform transform = playerTPLocs[num5 + 1].transform;
					vector = UnityEngine.Vector3.Lerp(obj.position, transform.position, t);
					rotation = UnityEngine.Quaternion.Lerp(obj.rotation, transform.rotation, t);
				}
				else
				{
					int num6 = num2;
					if (playerTPLocs[num6] == null)
					{
						num6 = num;
					}
					Transform obj2 = playerTPLocs[num6].transform;
					vector = obj2.position;
					rotation = obj2.rotation;
				}
				CharacterBody body = instance.master.GetBody();
				if (!(body == null))
				{
					body.currentVehicle?.EjectPassenger();
					if (Util.HasEffectiveAuthority(body.gameObject))
					{
						TeleportHelper.TeleportBody(body, vector);
					}
					else
					{
						CallRpcTeleportWithLocalAuthority(body.gameObject, vector, rotation);
					}
					num2++;
				}
			}
			NetworkisTriggered = true;
		}

		[ClientRpc]
		private void RpcTeleportWithLocalAuthority(GameObject playerObject, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			if (Util.HasEffectiveAuthority(playerObject))
			{
				CharacterBody component = playerObject.GetComponent<CharacterBody>();
				if (component == null)
				{
					UnityEngine.Debug.LogWarning("Received RPCTeleport request but the game object doesn't have a CharacterBody! " + playerObject.name, playerObject);
				}
				else
				{
					TeleportHelper.TeleportBody(component, position);
				}
			}
		}

		[Client]
		private void Client_HandleStartMeridianEvent(bool newValue)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.MeridianEventTriggerInteraction::Client_HandleStartMeridianEvent(System.Boolean)' called on server");
				return;
			}
			NetworkisTriggered = newValue;
			HandleStartMeridianEvent();
		}

		private void HandleStartMeridianEvent()
		{
			fog.SetActive(value: true);
			sceneBoundsOld.SetActive(value: false);
			sceneBoundsNew.SetActive(value: true);
			startSceneAMB.Stop(base.gameObject);
			bossFightAMB.Post(base.gameObject);
			musicPhaseNone.SetActive(value: true);
			cutsceneCamera.SetActive(value: true);
			Util.PlaySound("Play_env_meridian_activate_boss_cutscene", base.gameObject);
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			if (firstLocalUser != null && firstLocalUser.cachedBody != null)
			{
				string bodyName = BodyCatalog.GetBodyName(firstLocalUser.cachedBody.bodyIndex);
				firstLocalUser.userProfile.HasAchievement(bodyName.Substring(0, bodyName.Length - 4) + "ClearMeridianEvent");
			}
			mainStateMachine.SetNextState(new MeridianEventStart());
		}

		private IEnumerator RotateHead()
		{
			float timeElapsed = 0f;
			while (timeElapsed < colossusHeadDuration)
			{
				colossusHead.transform.rotation = UnityEngine.Quaternion.Lerp(colossusHead.transform.rotation, colossusHeadFinalPosition.rotation, timeElapsed / colossusHeadDuration);
				ringPiece1.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece1.transform.rotation, ringPiece1FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 20f));
				ringPiece2.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece2.transform.rotation, ringPiece2FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 22f));
				ringPiece3.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece3.transform.rotation, ringPiece3FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 25f));
				ringPiece4.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece4.transform.rotation, ringPiece4FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 26f));
				ringPiece5.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece5.transform.rotation, ringPiece5FinalPosition.transform.rotation, timeElapsed / (colossusHeadDuration - 19f));
				ringPiece1.transform.position = UnityEngine.Vector3.Lerp(ringPiece1.transform.position, ringPiece1FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 20f));
				ringPiece2.transform.position = UnityEngine.Vector3.Lerp(ringPiece2.transform.position, ringPiece2FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 22f));
				ringPiece3.transform.position = UnityEngine.Vector3.Lerp(ringPiece3.transform.position, ringPiece3FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 25f));
				ringPiece4.transform.position = UnityEngine.Vector3.Lerp(ringPiece4.transform.position, ringPiece4FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 26f));
				ringPiece5.transform.position = UnityEngine.Vector3.Lerp(ringPiece5.transform.position, ringPiece5FinalPosition.transform.position, timeElapsed / (colossusHeadDuration - 19f));
				ringPiece6.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece6.transform.rotation, ringPiece6FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration);
				ringPiece7.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece7.transform.rotation, ringPiece7FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration);
				ringPiece8.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece8.transform.rotation, ringPiece8FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration);
				ringPiece9.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece9.transform.rotation, ringPiece9FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration);
				ringPiece10.transform.rotation = UnityEngine.Quaternion.Lerp(ringPiece10.transform.rotation, ringPiece10FinalPosition.transform.rotation, timeElapsed / colossusHeadDuration);
				ringPiece6.transform.position = UnityEngine.Vector3.Lerp(ringPiece6.transform.position, ringPiece6FinalPosition.transform.position, timeElapsed / colossusHeadDuration);
				ringPiece7.transform.position = UnityEngine.Vector3.Lerp(ringPiece7.transform.position, ringPiece7FinalPosition.transform.position, timeElapsed / colossusHeadDuration);
				ringPiece8.transform.position = UnityEngine.Vector3.Lerp(ringPiece8.transform.position, ringPiece8FinalPosition.transform.position, timeElapsed / colossusHeadDuration);
				ringPiece9.transform.position = UnityEngine.Vector3.Lerp(ringPiece9.transform.position, ringPiece9FinalPosition.transform.position, timeElapsed / colossusHeadDuration);
				ringPiece10.transform.position = UnityEngine.Vector3.Lerp(ringPiece10.transform.position, ringPiece10FinalPosition.transform.position, timeElapsed / colossusHeadDuration);
				timeElapsed += Time.deltaTime;
				yield return null;
			}
		}

		private void StartOuterRingFalling()
		{
			ringFallingState = Mathf.Max(1, ringFallingState);
			Util.PlaySound("Play_env_meridian_level_ring_fall", base.gameObject);
		}

		private void StartMiddleRingFalling()
		{
			ringFallingState = Mathf.Max(2, ringFallingState);
			Util.PlaySound("Play_env_meridian_level_ring_fall", base.gameObject);
		}

		private IEnumerator OuterRingFalling()
		{
			float timeElapsed = 0f;
			while (timeElapsed < ringFallOffTime)
			{
				ringPiece6.transform.position = UnityEngine.Vector3.Lerp(ringPiece6.transform.position, ringPiece6.transform.position - new UnityEngine.Vector3(0f, 100f, 0f), timeElapsed / ringFallOffTime);
				ringPiece7.transform.position = UnityEngine.Vector3.Lerp(ringPiece7.transform.position, ringPiece7.transform.position - new UnityEngine.Vector3(0f, 230f, 0f), timeElapsed / ringFallOffTime);
				ringPiece8.transform.position = UnityEngine.Vector3.Lerp(ringPiece8.transform.position, ringPiece8.transform.position - new UnityEngine.Vector3(0f, 120f, 0f), timeElapsed / ringFallOffTime);
				ringPiece9.transform.position = UnityEngine.Vector3.Lerp(ringPiece9.transform.position, ringPiece9.transform.position - new UnityEngine.Vector3(0f, 350f, 0f), timeElapsed / ringFallOffTime);
				ringPiece10.transform.position = UnityEngine.Vector3.Lerp(ringPiece10.transform.position, ringPiece10.transform.position - new UnityEngine.Vector3(0f, 130f, 0f), timeElapsed / ringFallOffTime);
				timeElapsed += Time.deltaTime;
				yield return null;
			}
			ringPiece6.SetActive(value: false);
			ringPiece7.SetActive(value: false);
			ringPiece8.SetActive(value: false);
			ringPiece9.SetActive(value: false);
			ringPiece10.SetActive(value: false);
		}

		private IEnumerator MiddleRingFalling()
		{
			float timeElapsed = 0f;
			while (timeElapsed < ringFallOffTime)
			{
				ringPiece1.transform.position = UnityEngine.Vector3.Lerp(ringPiece1.transform.position, ringPiece1.transform.position - new UnityEngine.Vector3(0f, 120f, 0f), timeElapsed / ringFallOffTime);
				ringPiece2.transform.position = UnityEngine.Vector3.Lerp(ringPiece2.transform.position, ringPiece2.transform.position - new UnityEngine.Vector3(0f, 110f, 0f), timeElapsed / ringFallOffTime);
				ringPiece3.transform.position = UnityEngine.Vector3.Lerp(ringPiece3.transform.position, ringPiece3.transform.position - new UnityEngine.Vector3(0f, 350f, 0f), timeElapsed / ringFallOffTime);
				ringPiece4.transform.position = UnityEngine.Vector3.Lerp(ringPiece4.transform.position, ringPiece4.transform.position - new UnityEngine.Vector3(0f, 130f, 0f), timeElapsed / ringFallOffTime);
				ringPiece5.transform.position = UnityEngine.Vector3.Lerp(ringPiece5.transform.position, ringPiece5.transform.position - new UnityEngine.Vector3(0f, 470f, 0f), timeElapsed / ringFallOffTime);
				timeElapsed += Time.deltaTime;
				yield return null;
			}
			ringPiece1.SetActive(value: false);
			ringPiece2.SetActive(value: false);
			ringPiece3.SetActive(value: false);
			ringPiece4.SetActive(value: false);
			ringPiece5.SetActive(value: false);
		}

		public void TriggerEventClear()
		{
			triggerEventClear = true;
		}

		public void Update()
		{
			if (isHeadRotating)
			{
				StartCoroutine(RotateHead());
				cutsceneCamera.SetActive(value: true);
				isHeadRotating = false;
			}
			if (ringFallingState > localRingFallingState)
			{
				if (ringFallingState == 1)
				{
					StartCoroutine(OuterRingFalling());
				}
				else if (ringFallingState == 2)
				{
					StartCoroutine(MiddleRingFalling());
				}
				localRingFallingState = ringFallingState;
			}
			if (triggerEventClear && NetworkServer.active)
			{
				CallRpcOnFalseSonDefeated();
				triggerEventClear = false;
			}
		}

		private void Awake()
		{
			mainStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Main");
			if (NetworkServer.active)
			{
				SkyJumpDeathState.falseSonDeathEvent += TriggerEventClear;
			}
			GameObject[] array = destinationPortals;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetActive(value: false);
			}
		}

		[ClientRpc]
		private void RpcOnFalseSonDefeated()
		{
			EventCompletePPVolume.SetActive(value: true);
			EventPPVolume.SetActive(value: false);
			if (AfterEventCompletePPVolume != null)
			{
				AfterEventCompletePPVolume.SetActive(value: true);
			}
			SetIdleMaterials();
			SetClearedObjects();
		}

		private void Wave1OnDefeatedServer()
		{
			combatDirectorWave2.enabled = true;
			combatDirectorWave2.currentSpawnTarget = base.gameObject;
			combatDirectorWave2.monsterCredit += (int)(600f * Mathf.Pow(Run.instance.compensatedDifficultyCoefficient, 0.5f));
		}

		private void Wave2OnDefeatedServer()
		{
			mainStateMachine.SetNextState(new MeridianEventCleared());
		}

		private void SetEventObjects()
		{
			for (int i = 0; i < eventGameObjectsToToggle.Length; i++)
			{
				if (!(eventGameObjectsToToggle[i] == null))
				{
					bool activeInHierarchy = eventGameObjectsToToggle[i].activeInHierarchy;
					eventGameObjectsToToggle[i].SetActive(!activeInHierarchy);
				}
			}
		}

		private void HandleNodeGateActivation(int currentState)
		{
			eventGateStateObject.SetActive(currentState <= 0);
			eventGateStatePhase2Object.SetActive(currentState <= 1);
			eventGateStatePhase3Object.SetActive(currentState <= 2);
		}

		private void SetClearedObjects()
		{
			for (int i = 0; i < clearedGameObjectsToToggle.Length; i++)
			{
				if (!(clearedGameObjectsToToggle[i] == null))
				{
					bool activeInHierarchy = clearedGameObjectsToToggle[i].activeInHierarchy;
					clearedGameObjectsToToggle[i].SetActive(!activeInHierarchy);
				}
			}
		}

		[ClientRpc]
		private void RpcSetEventMaterials()
		{
			for (int i = 0; i < gameObjectsToModify.Length; i++)
			{
				GameObject[] objects = gameObjectsToModify[i].objects;
				foreach (GameObject gameObject in objects)
				{
					if (!(gameObject == null) && gameObject.TryGetComponent<Renderer>(out var component))
					{
						component.material = gameObjectsToModify[i].eventMaterial;
					}
				}
			}
		}

		private void SetIdleMaterials()
		{
			for (int i = 0; i < gameObjectsToModify.Length; i++)
			{
				GameObject[] objects = gameObjectsToModify[i].objects;
				foreach (GameObject gameObject in objects)
				{
					if (!(gameObject == null))
					{
						gameObject.GetComponent<Renderer>().material = gameObjectsToModify[i].idleMaterial;
					}
				}
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcTeleportWithLocalAuthority(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcTeleportWithLocalAuthority called on server.");
			}
			else
			{
				((MeridianEventTriggerInteraction)obj).RpcTeleportWithLocalAuthority(reader.ReadGameObject(), reader.ReadVector3(), reader.ReadQuaternion());
			}
		}

		protected static void InvokeRpcRpcOnFalseSonDefeated(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnFalseSonDefeated called on server.");
			}
			else
			{
				((MeridianEventTriggerInteraction)obj).RpcOnFalseSonDefeated();
			}
		}

		protected static void InvokeRpcRpcSetEventMaterials(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetEventMaterials called on server.");
			}
			else
			{
				((MeridianEventTriggerInteraction)obj).RpcSetEventMaterials();
			}
		}

		public void CallRpcTeleportWithLocalAuthority(GameObject playerObject, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcTeleportWithLocalAuthority called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcTeleportWithLocalAuthority);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(playerObject);
			networkWriter.Write(position);
			networkWriter.Write(rotation);
			SendRPCInternal(networkWriter, 0, "RpcTeleportWithLocalAuthority");
		}

		public void CallRpcOnFalseSonDefeated()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnFalseSonDefeated called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnFalseSonDefeated);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcOnFalseSonDefeated");
		}

		public void CallRpcSetEventMaterials()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetEventMaterials called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetEventMaterials);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcSetEventMaterials");
		}

		static MeridianEventTriggerInteraction()
		{
			kRpcRpcTeleportWithLocalAuthority = -40849326;
			NetworkBehaviour.RegisterRpcDelegate(typeof(MeridianEventTriggerInteraction), kRpcRpcTeleportWithLocalAuthority, InvokeRpcRpcTeleportWithLocalAuthority);
			kRpcRpcOnFalseSonDefeated = 1048548329;
			NetworkBehaviour.RegisterRpcDelegate(typeof(MeridianEventTriggerInteraction), kRpcRpcOnFalseSonDefeated, InvokeRpcRpcOnFalseSonDefeated);
			kRpcRpcSetEventMaterials = 1585739;
			NetworkBehaviour.RegisterRpcDelegate(typeof(MeridianEventTriggerInteraction), kRpcRpcSetEventMaterials, InvokeRpcRpcSetEventMaterials);
			NetworkCRC.RegisterBehaviour("MeridianEventTriggerInteraction", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(isTriggered);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(isTriggered);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				isTriggered = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				Client_HandleStartMeridianEvent(reader.ReadBoolean());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class MeridianSpawnPointGenerator : MonoBehaviour
	{
		[SerializeField]
		private Transform playerSpawnPoint;

		private void OnEnable()
		{
			SceneDirector.onPreGeneratePlayerSpawnPointsServer += OnPreGeneratePlayerSpawnPointsServer;
		}

		private void OnDisable()
		{
			SceneDirector.onPreGeneratePlayerSpawnPointsServer -= OnPreGeneratePlayerSpawnPointsServer;
		}

		private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod)
		{
			generationMethod = GeneratePlayerSpawnPointsServer;
		}

		private void GeneratePlayerSpawnPointsServer()
		{
			if (SpawnPoint.readOnlyInstancesList.Count > 3 || playerSpawnPoint == null)
			{
				return;
			}
			UnityEngine.Vector3 position = playerSpawnPoint.position;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			if (!groundNodes)
			{
				UnityEngine.Debug.LogError("MeridianSpawnPointGenerator.GeneratePlayerSpawnPointsServer: No ground nodegraph found to place spawn points.", this);
				return;
			}
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human);
			nodeGraphSpider.AddNodeForNextStep(groundNodes.FindClosestNode(position, HullClassification.Human));
			for (int i = 0; i < 4; i++)
			{
				nodeGraphSpider.PerformStep();
				if (nodeGraphSpider.collectedSteps.Count > 16)
				{
					break;
				}
			}
			for (int j = 0; j < nodeGraphSpider.collectedSteps.Count; j++)
			{
				NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[j];
				groundNodes.GetNodePosition(stepInfo.node, out var position2);
				UnityEngine.Quaternion rotation = playerSpawnPoint.rotation;
				SpawnPoint.AddSpawnPoint(position2, rotation);
			}
		}
	}
	public class MeteorController : NetworkBehaviour
	{
		public GameObject meteorTest1;

		public GameObject meteorTest2;

		public GameObject meteorTest3;

		private ParticleSystem meteorTest1ps;

		private ParticleSystem meteorTest2ps;

		private ParticleSystem meteorTest3ps;

		public ShakeEmitter shakeEmitter;

		private bool meteorTimerOn;

		private float meteorTimer;

		private float meteorDuration = 30f;

		private void Awake()
		{
			meteorTest1ps = meteorTest1.GetComponent<ParticleSystem>();
			meteorTest2ps = meteorTest2.GetComponent<ParticleSystem>();
			meteorTest3ps = meteorTest3.GetComponent<ParticleSystem>();
			meteorTest1.SetActive(value: false);
			meteorTest2.SetActive(value: false);
			meteorTest3.SetActive(value: false);
		}

		private void Start()
		{
		}

		private void ActivateMeteors(bool value)
		{
			meteorTest1.SetActive(value);
			meteorTest2.SetActive(value);
			meteorTest3.SetActive(value);
		}

		private void Update()
		{
			if ((double)Run.instance.GetRunStopwatch() - Math.Floor(Run.instance.GetRunStopwatch() * (1f / 60f)) * 60.0 <= 0.1 && !meteorTimerOn)
			{
				meteorTimerOn = true;
				ActivateMeteors(value: true);
			}
			if (meteorTimerOn)
			{
				meteorTimer += Time.fixedDeltaTime;
			}
			if (meteorTimer >= meteorDuration)
			{
				meteorTimerOn = false;
				meteorTimer = 0f;
				ActivateMeteors(value: false);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class MeteorStormController : MonoBehaviour
	{
		private class Meteor
		{
			public UnityEngine.Vector3 impactPosition;

			public float startTime;

			public bool didTravelEffect;

			public bool valid = true;
		}

		private class MeteorWave
		{
			private readonly CharacterBody[] targets;

			private int currentStep;

			private float hitChance = 0.4f;

			private readonly UnityEngine.Vector3 center;

			public float timer;

			private NodeGraphSpider nodeGraphSpider;

			public MeteorWave(CharacterBody[] targets, UnityEngine.Vector3 center)
			{
				this.targets = new CharacterBody[targets.Length];
				targets.CopyTo(this.targets, 0);
				Util.ShuffleArray(targets);
				this.center = center;
				nodeGraphSpider = new NodeGraphSpider(SceneInfo.instance.groundNodes, HullMask.Human);
				nodeGraphSpider.AddNodeForNextStep(SceneInfo.instance.groundNodes.FindClosestNode(center, HullClassification.Human));
				int i = 0;
				for (int num = 20; i < num; i++)
				{
					if (!nodeGraphSpider.PerformStep())
					{
						break;
					}
				}
			}

			public Meteor GetNextMeteor()
			{
				if (currentStep >= targets.Length)
				{
					return null;
				}
				CharacterBody characterBody = targets[currentStep];
				Meteor meteor = new Meteor();
				if ((bool)characterBody && UnityEngine.Random.value < hitChance)
				{
					meteor.impactPosition = characterBody.corePosition;
					UnityEngine.Vector3 origin = meteor.impactPosition + UnityEngine.Vector3.up * 6f;
					UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
					onUnitSphere.y = -1f;
					if (Physics.Raycast(origin, onUnitSphere, out var hitInfo, 12f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						meteor.impactPosition = hitInfo.point;
					}
					else if (Physics.Raycast(meteor.impactPosition, UnityEngine.Vector3.down, out hitInfo, float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						meteor.impactPosition = hitInfo.point;
					}
				}
				else if (nodeGraphSpider.collectedSteps.Count != 0)
				{
					int index = UnityEngine.Random.Range(0, nodeGraphSpider.collectedSteps.Count);
					SceneInfo.instance.groundNodes.GetNodePosition(nodeGraphSpider.collectedSteps[index].node, out meteor.impactPosition);
				}
				else
				{
					meteor.valid = false;
				}
				meteor.startTime = Run.instance.time;
				currentStep++;
				return meteor;
			}
		}

		public int waveCount;

		public float waveMinInterval;

		public float waveMaxInterval;

		public GameObject warningEffectPrefab;

		public GameObject travelEffectPrefab;

		public float travelEffectDuration;

		public GameObject impactEffectPrefab;

		public float impactDelay;

		public float blastDamageCoefficient;

		public float blastRadius;

		public float blastForce;

		public DamageTypeCombo blastDamageType;

		[NonSerialized]
		public GameObject owner;

		[NonSerialized]
		public float ownerDamage;

		[NonSerialized]
		public bool isCrit;

		public UnityEvent onDestroyEvents;

		private List<Meteor> meteorList;

		private List<MeteorWave> waveList;

		private int wavesPerformed;

		private float waveTimer;

		private void Start()
		{
			if (NetworkServer.active)
			{
				meteorList = new List<Meteor>();
				waveList = new List<MeteorWave>();
			}
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			waveTimer -= Time.fixedDeltaTime;
			if (waveTimer <= 0f && wavesPerformed < waveCount)
			{
				wavesPerformed++;
				waveTimer = UnityEngine.Random.Range(waveMinInterval, waveMaxInterval);
				MeteorWave item = new MeteorWave(CharacterBody.readOnlyInstancesList.ToArray(), base.transform.position);
				waveList.Add(item);
			}
			for (int num = waveList.Count - 1; num >= 0; num--)
			{
				MeteorWave meteorWave = waveList[num];
				meteorWave.timer -= Time.fixedDeltaTime;
				if (meteorWave.timer <= 0f)
				{
					meteorWave.timer = UnityEngine.Random.Range(0.05f, 1f);
					Meteor nextMeteor = meteorWave.GetNextMeteor();
					if (nextMeteor == null)
					{
						waveList.RemoveAt(num);
					}
					else if (nextMeteor.valid)
					{
						meteorList.Add(nextMeteor);
						EffectManager.SpawnEffect(warningEffectPrefab, new EffectData
						{
							origin = nextMeteor.impactPosition,
							scale = blastRadius
						}, transmit: true);
					}
				}
			}
			float num2 = Run.instance.time - impactDelay;
			float num3 = num2 - travelEffectDuration;
			for (int num4 = meteorList.Count - 1; num4 >= 0; num4--)
			{
				Meteor meteor = meteorList[num4];
				if (meteor.startTime < num3 && !meteor.didTravelEffect)
				{
					DoMeteorEffect(meteor);
				}
				if (meteor.startTime < num2)
				{
					meteorList.RemoveAt(num4);
					DetonateMeteor(meteor);
				}
			}
			if (wavesPerformed == waveCount && meteorList.Count == 0)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void OnDestroy()
		{
			onDestroyEvents.Invoke();
		}

		private void DoMeteorEffect(Meteor meteor)
		{
			meteor.didTravelEffect = true;
			if ((bool)travelEffectPrefab)
			{
				EffectManager.SpawnEffect(travelEffectPrefab, new EffectData
				{
					origin = meteor.impactPosition
				}, transmit: true);
			}
		}

		private void DetonateMeteor(Meteor meteor)
		{
			EffectData effectData = new EffectData
			{
				origin = meteor.impactPosition
			};
			EffectManager.SpawnEffect(impactEffectPrefab, effectData, transmit: true);
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.inflictor = base.gameObject;
			blastAttack.baseDamage = blastDamageCoefficient * ownerDamage;
			blastAttack.baseForce = blastForce;
			blastAttack.attackerFiltering = AttackerFiltering.AlwaysHit;
			blastAttack.crit = isCrit;
			blastAttack.falloffModel = BlastAttack.FalloffModel.Linear;
			blastAttack.attacker = owner;
			blastAttack.bonusForce = UnityEngine.Vector3.zero;
			blastAttack.damageColorIndex = DamageColorIndex.Item;
			blastAttack.position = meteor.impactPosition;
			blastAttack.procChainMask = default(ProcChainMask);
			blastAttack.procCoefficient = 1f;
			blastAttack.teamIndex = TeamIndex.None;
			blastAttack.radius = blastRadius;
			blastAttack.damageType = blastDamageType;
			blastAttack.Fire();
		}
	}
	[ExecuteAlways]
	public class MidpointBetweenTwoTransforms : MonoBehaviour
	{
		public Transform transform1;

		public Transform transform2;

		public void Update()
		{
			base.transform.position = UnityEngine.Vector3.Lerp(transform1.position, transform2.position, 0.5f);
		}
	}
	[DisallowMultipleComponent]
	public class MinionOwnership : NetworkBehaviour
	{
		public class MinionGroup : IDisposable
		{
			private class MinionGroupDestroyer : MonoBehaviour
			{
				public MinionGroup group;

				private void OnDestroy()
				{
					group.Dispose();
					group.refCount--;
				}
			}

			private static readonly List<MinionGroup> instancesList = new List<MinionGroup>();

			public readonly NetworkInstanceId ownerId;

			private MinionOwnership[] _members;

			private int _memberCount;

			private int refCount;

			private bool resolved;

			private GameObject resolvedOwnerGameObject;

			private CharacterMaster resolvedOwnerMaster;

			public MinionOwnership[] members => _members;

			public int memberCount => _memberCount;

			public bool isMinion => ownerId != NetworkInstanceId.Invalid;

			public static MinionGroup FindGroup(NetworkInstanceId ownerId)
			{
				foreach (MinionGroup instances in instancesList)
				{
					if (instances.ownerId == ownerId)
					{
						return instances;
					}
				}
				return null;
			}

			public static void SetMinionOwner(MinionOwnership minion, NetworkInstanceId ownerId)
			{
				if (minion.group != null)
				{
					if (minion.group.ownerId == ownerId)
					{
						return;
					}
					RemoveMinion(minion.group.ownerId, minion);
				}
				if (ownerId != NetworkInstanceId.Invalid)
				{
					AddMinion(ownerId, minion);
				}
			}

			private static void AddMinion(NetworkInstanceId ownerId, MinionOwnership minion)
			{
				MinionGroup minionGroup = null;
				for (int i = 0; i < instancesList.Count; i++)
				{
					MinionGroup minionGroup2 = instancesList[i];
					if (instancesList[i].ownerId == ownerId)
					{
						minionGroup = minionGroup2;
						break;
					}
				}
				if (minionGroup == null)
				{
					minionGroup = new MinionGroup(ownerId);
				}
				minionGroup.AddMember(minion);
				minionGroup.AttemptToResolveOwner();
				CharacterMaster component = minion.GetComponent<CharacterMaster>();
				if ((bool)component)
				{
					component.inventory.GiveItem(RoR2Content.Items.MinionLeash);
				}
			}

			private static void RemoveMinion(NetworkInstanceId ownerId, MinionOwnership minion)
			{
				CharacterMaster component = minion.GetComponent<CharacterMaster>();
				if ((bool)component)
				{
					component.inventory.RemoveItem(RoR2Content.Items.MinionLeash);
				}
				MinionGroup minionGroup = null;
				for (int i = 0; i < instancesList.Count; i++)
				{
					MinionGroup minionGroup2 = instancesList[i];
					if (instancesList[i].ownerId == ownerId)
					{
						minionGroup = minionGroup2;
						break;
					}
				}
				if (minionGroup == null)
				{
					throw new InvalidOperationException(string.Format("{0}.{1} Could not find group to which {2} belongs", "MinionGroup", "RemoveMinion", minion));
				}
				minionGroup.RemoveMember(minion);
				if (minionGroup.refCount == 0 && !minionGroup.resolvedOwnerGameObject)
				{
					minionGroup.Dispose();
				}
			}

			private MinionGroup(NetworkInstanceId ownerId)
			{
				this.ownerId = ownerId;
				_members = new MinionOwnership[4];
				_memberCount = 0;
				instancesList.Add(this);
			}

			public void Dispose()
			{
				for (int num = _memberCount - 1; num >= 0; num--)
				{
					RemoveMemberAt(num);
				}
				instancesList.Remove(this);
			}

			private void AttemptToResolveOwner()
			{
				if (resolved)
				{
					return;
				}
				resolvedOwnerGameObject = Util.FindNetworkObject(ownerId);
				if ((bool)resolvedOwnerGameObject)
				{
					resolved = true;
					resolvedOwnerMaster = resolvedOwnerGameObject.GetComponent<CharacterMaster>();
					resolvedOwnerGameObject.AddComponent<MinionGroupDestroyer>().group = this;
					refCount++;
					for (int i = 0; i < _memberCount; i++)
					{
						_members[i].HandleOwnerDiscovery(resolvedOwnerMaster);
					}
				}
			}

			public void AddMember(MinionOwnership minion)
			{
				ArrayUtils.ArrayAppend(ref _members, ref _memberCount, in minion);
				refCount++;
				minion.HandleGroupDiscovery(this);
				if ((bool)resolvedOwnerMaster)
				{
					minion.HandleOwnerDiscovery(resolvedOwnerMaster);
				}
			}

			public void RemoveMember(MinionOwnership minion)
			{
				RemoveMemberAt(Array.IndexOf(_members, minion));
				refCount--;
			}

			private void RemoveMemberAt(int i)
			{
				MinionOwnership obj = _members[i];
				ArrayUtils.ArrayRemoveAt(_members, ref _memberCount, i);
				obj.HandleOwnerDiscovery(null);
				obj.HandleGroupDiscovery(null);
			}

			[ConCommand(commandName = "minion_dump", flags = ConVarFlags.None, helpText = "Prints debug information about all active minion groups.")]
			private static void CCMinionPrint(ConCommandArgs args)
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int i = 0; i < instancesList.Count; i++)
				{
					MinionGroup minionGroup = instancesList[i];
					stringBuilder.Append("group [").Append(i).Append("] size=")
						.Append(minionGroup._memberCount)
						.Append(" id=")
						.Append(minionGroup.ownerId)
						.Append(" resolvedOwnerGameObject=")
						.Append(minionGroup.resolvedOwnerGameObject)
						.AppendLine();
					for (int j = 0; j < minionGroup._memberCount; j++)
					{
						stringBuilder.Append("  ").Append("[").Append(j)
							.Append("] member.name=")
							.Append(minionGroup._members[j].name)
							.AppendLine();
					}
				}
			}
		}

		[SyncVar(hook = "OnSyncOwnerMasterId")]
		private NetworkInstanceId ownerMasterId = NetworkInstanceId.Invalid;

		public CharacterMaster ownerMaster { get; private set; }

		public MinionGroup group { get; private set; }

		public NetworkInstanceId NetworkownerMasterId
		{
			get
			{
				return ownerMasterId;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncOwnerMasterId(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref ownerMasterId, 1u);
			}
		}

		public event Action<CharacterMaster> onOwnerDiscovered;

		public event Action<CharacterMaster> onOwnerLost;

		public static event Action<MinionOwnership> onMinionGroupChangedGlobal;

		public static event Action<MinionOwnership> onMinionOwnerChangedGlobal;

		[Server]
		public void SetOwner(CharacterMaster newOwnerMaster)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MinionOwnership::SetOwner(RoR2.CharacterMaster)' called on client");
				return;
			}
			NetworkownerMasterId = (newOwnerMaster ? newOwnerMaster.netId : NetworkInstanceId.Invalid);
			MinionGroup.SetMinionOwner(this, ownerMasterId);
		}

		private void OnSyncOwnerMasterId(NetworkInstanceId newOwnerMasterId)
		{
			MinionGroup.SetMinionOwner(this, ownerMasterId);
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			if (!NetworkServer.active)
			{
				MinionGroup.SetMinionOwner(this, ownerMasterId);
			}
		}

		private void HandleGroupDiscovery(MinionGroup newGroup)
		{
			group = newGroup;
			MinionOwnership.onMinionGroupChangedGlobal?.Invoke(this);
		}

		private void HandleOwnerDiscovery(CharacterMaster newOwner)
		{
			if ((object)ownerMaster != null)
			{
				this.onOwnerLost?.Invoke(ownerMaster);
			}
			ownerMaster = newOwner;
			if ((object)ownerMaster != null)
			{
				this.onOwnerDiscovered?.Invoke(ownerMaster);
			}
			MinionOwnership.onMinionOwnerChangedGlobal?.Invoke(this);
		}

		private void OnDestroy()
		{
			MinionGroup.SetMinionOwner(this, NetworkInstanceId.Invalid);
		}

		[AssetCheck(typeof(CharacterMaster))]
		private static void AddMinionOwnershipComponent(AssetCheckArgs args)
		{
			CharacterMaster characterMaster = args.asset as CharacterMaster;
			if (!characterMaster.GetComponent<MinionOwnership>())
			{
				characterMaster.gameObject.AddComponent<MinionOwnership>();
				args.UpdatePrefab();
			}
		}

		private void OnValidate()
		{
			if (GetComponents<MinionOwnership>().Length > 1)
			{
				UnityEngine.Debug.LogError("Only one MinionOwnership is allowed per object!", this);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(ownerMasterId);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(ownerMasterId);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				ownerMasterId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncOwnerMasterId(reader.ReadNetworkId());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(Camera))]
	public class ModelCamera : MonoBehaviour
	{
		private struct ObjectRestoreInfo
		{
			public GameObject obj;

			public int layer;
		}

		[NonSerialized]
		public RenderSettingsState renderSettings;

		public UnityEngine.Color ambientLight;

		private readonly List<Light> lights = new List<Light>();

		public static ModelCamera instance { get; private set; }

		public Camera attachedCamera { get; private set; }

		private void OnEnable()
		{
			if ((bool)instance && instance != this)
			{
				UnityEngine.Debug.LogErrorFormat("Only one {0} instance can be active at a time.", GetType().Name);
			}
			else
			{
				instance = this;
			}
		}

		private void OnDisable()
		{
			if (instance == this)
			{
				instance = null;
			}
		}

		private void Awake()
		{
			attachedCamera = GetComponent<Camera>();
			attachedCamera.enabled = false;
			attachedCamera.cullingMask = LayerIndex.manualRender.mask;
			UnityEngine.Object.Destroy(GetComponent<AkAudioListener>());
		}

		private static void PrepareObjectForRendering(Transform objTransform, List<ObjectRestoreInfo> objectRestorationList)
		{
			GameObject gameObject = objTransform.gameObject;
			objectRestorationList.Add(new ObjectRestoreInfo
			{
				obj = gameObject,
				layer = gameObject.layer
			});
			gameObject.layer = LayerIndex.manualRender.intVal;
			int childCount = objTransform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				PrepareObjectForRendering(objTransform.GetChild(i), objectRestorationList);
			}
		}

		public void RenderItem(GameObject obj, RenderTexture targetTexture)
		{
			for (int i = 0; i < lights.Count; i++)
			{
				lights[i].cullingMask = LayerIndex.manualRender.mask;
			}
			RenderSettingsState renderSettingsState = RenderSettingsState.FromCurrent();
			renderSettings.Apply();
			List<ObjectRestoreInfo> list = new List<ObjectRestoreInfo>();
			if ((bool)obj)
			{
				PrepareObjectForRendering(obj.transform, list);
			}
			attachedCamera.targetTexture = targetTexture;
			attachedCamera.Render();
			for (int j = 0; j < list.Count; j++)
			{
				list[j].obj.layer = list[j].layer;
			}
			for (int k = 0; k < lights.Count; k++)
			{
				lights[k].cullingMask = 0;
			}
			renderSettingsState.Apply();
		}

		public void AddLight(Light light)
		{
			lights.Add(light);
		}

		public void RemoveLight(Light light)
		{
			lights.Remove(light);
		}
	}
	[DisallowMultipleComponent]
	public class ModelLocator : MonoBehaviour, ILifeBehavior
	{
		private class DestructionNotifier : MonoBehaviour
		{
			public ModelLocator subscriber { private get; set; }

			private void OnDestroy()
			{
				if ((object)subscriber != null)
				{
					subscriber.modelTransform = null;
				}
			}
		}

		[SerializeField]
		[FormerlySerializedAs("modelTransform")]
		[Tooltip("The transform of the child gameobject which acts as the model for this entity.")]
		[Header("Cached Model Values")]
		private Transform _modelTransform;

		public RendererVisiblity modelVisibility;

		private DestructionNotifier modelDestructionNotifier;

		[Tooltip("The transform of the child gameobject which acts as the base for this entity's model. If provided, this will be detached from the hierarchy and positioned to match this object's position.")]
		public Transform modelBaseTransform;

		[Tooltip("Compensates for the irregular scaling from baseline human scale for attached VFX.")]
		public float modelScaleCompensation = 1f;

		[Tooltip("Whether or not to update the model transforms automatically.")]
		[Header("Update Properties")]
		public bool autoUpdateModelTransform = true;

		[Tooltip("Forces the model to remain in hierarchy, rather that detaching on start. You usually don't want this for anything that moves.")]
		public bool dontDetatchFromParent;

		private Transform modelParentTransform;

		[Tooltip("Only matters if preserveModel=true. Prevents the addition of a Corpse component to the model when this object is destroyed.")]
		[Header("Corpse Properties")]
		public bool noCorpse;

		[Tooltip("If true, ownership of the model will not be relinquished by death.")]
		public bool dontReleaseModelOnDeath;

		[Tooltip("Prevents the model from being destroyed when this object is destroyed. This is rarely used, as character death states are usually responsible for snatching the model away and leaving this ModelLocator with nothing to destroy.")]
		public bool preserveModel;

		public bool forceCulled;

		[Header("Normal Properties")]
		[Tooltip("Allows the model to align to the floor.")]
		public bool normalizeToFloor;

		public float normalSmoothdampTime = 0.1f;

		[Range(0f, 90f)]
		public float normalMaxAngleDelta = 90f;

		private UnityEngine.Vector3 normalSmoothdampVelocity;

		private UnityEngine.Vector3 targetNormal = UnityEngine.Vector3.up;

		private UnityEngine.Vector3 currentNormal = UnityEngine.Vector3.up;

		private CharacterMotor characterMotor;

		public Transform modelTransform
		{
			get
			{
				return _modelTransform;
			}
			set
			{
				if ((object)_modelTransform != value)
				{
					if ((object)modelDestructionNotifier != null)
					{
						modelDestructionNotifier.subscriber = null;
						UnityEngine.Object.Destroy(modelDestructionNotifier);
						modelDestructionNotifier = null;
					}
					_modelTransform = value;
					if ((bool)_modelTransform)
					{
						modelDestructionNotifier = _modelTransform.gameObject.AddComponent<DestructionNotifier>();
						modelDestructionNotifier.subscriber = this;
					}
					this.onModelChanged?.Invoke(_modelTransform);
				}
			}
		}

		public event Action<Transform> onModelChanged;

		private void Awake()
		{
			characterMotor = GetComponent<CharacterMotor>();
		}

		public void Start()
		{
			if ((bool)modelTransform)
			{
				modelParentTransform = modelTransform.parent;
				if (!dontDetatchFromParent)
				{
					modelTransform.parent = null;
				}
			}
		}

		private void UpdateModelTransform(float deltaTime)
		{
			if ((bool)modelTransform && (bool)modelParentTransform)
			{
				UnityEngine.Vector3 position = modelParentTransform.position;
				UnityEngine.Quaternion rotation = modelParentTransform.rotation;
				UpdateTargetNormal();
				SmoothNormals(deltaTime);
				rotation = UnityEngine.Quaternion.FromToRotation(UnityEngine.Vector3.up, currentNormal) * rotation;
				modelTransform.SetPositionAndRotation(position, rotation);
			}
		}

		private void SmoothNormals(float deltaTime)
		{
			currentNormal = UnityEngine.Vector3.SmoothDamp(currentNormal, targetNormal, ref normalSmoothdampVelocity, normalSmoothdampTime, float.PositiveInfinity, deltaTime);
		}

		private void UpdateTargetNormal()
		{
			if (normalizeToFloor && (bool)characterMotor)
			{
				targetNormal = (characterMotor.isGrounded ? characterMotor.estimatedGroundNormal : UnityEngine.Vector3.up);
				targetNormal = UnityEngine.Vector3.RotateTowards(UnityEngine.Vector3.up, targetNormal, normalMaxAngleDelta * (MathF.PI / 180f), float.PositiveInfinity);
			}
			else
			{
				targetNormal = UnityEngine.Vector3.up;
			}
		}

		public void LateUpdate()
		{
			if (autoUpdateModelTransform)
			{
				UpdateModelTransform(Time.deltaTime);
			}
		}

		private void OnDestroy()
		{
			if (!modelTransform)
			{
				return;
			}
			if (preserveModel)
			{
				if (!noCorpse)
				{
					modelTransform.gameObject.AddComponent<Corpse>();
				}
				modelTransform = null;
			}
			else
			{
				UnityEngine.Object.Destroy(modelTransform.gameObject);
			}
		}

		public void OnDeathStart()
		{
			if (!dontReleaseModelOnDeath)
			{
				preserveModel = true;
			}
		}
	}
	public class ModelPanelParameters : MonoBehaviour
	{
		public Transform focusPointTransform;

		public Transform cameraPositionTransform;

		public UnityEngine.Quaternion modelRotation = UnityEngine.Quaternion.identity;

		public float minDistance = 1f;

		public float maxDistance = 10f;

		public UnityEngine.Vector3 cameraDirection => focusPointTransform.position - cameraPositionTransform.position;

		public void OnDrawGizmos()
		{
			if ((bool)focusPointTransform)
			{
				Gizmos.color = UnityEngine.Color.yellow;
				Gizmos.DrawWireSphere(focusPointTransform.position, 0.1f);
				Gizmos.color = UnityEngine.Color.gray;
				Gizmos.DrawWireSphere(focusPointTransform.position, minDistance);
				Gizmos.DrawWireSphere(focusPointTransform.position, maxDistance);
			}
			if ((bool)cameraPositionTransform)
			{
				Gizmos.color = UnityEngine.Color.yellow;
				Gizmos.DrawWireSphere(cameraPositionTransform.position, 0.2f);
			}
			if ((bool)focusPointTransform && (bool)cameraPositionTransform)
			{
				Gizmos.DrawLine(focusPointTransform.position, cameraPositionTransform.position);
			}
		}
	}
	[RequireComponent(typeof(CharacterModel))]
	[DisallowMultipleComponent]
	public class ModelSkinController : MonoBehaviour
	{
		public SkinDef[] skins;

		private CharacterModel characterModel;

		public int currentSkinIndex { get; private set; } = -1;


		private void Awake()
		{
			characterModel = GetComponent<CharacterModel>();
		}

		private void Start()
		{
			if ((bool)characterModel.body)
			{
				ApplySkin((int)characterModel.body.skinIndex);
			}
		}

		public void ApplySkin(int skinIndex)
		{
			if (skinIndex != currentSkinIndex && (uint)skinIndex < skins.Length)
			{
				skins[skinIndex].Apply(base.gameObject);
				characterModel.forceUpdate = true;
				currentSkinIndex = skinIndex;
			}
		}
	}
	public class MoneyPickup : MonoBehaviour
	{
		[Tooltip("The base object to destroy when this pickup is consumed.")]
		public GameObject baseObject;

		[Tooltip("The team filter object which determines who can pick up this pack.")]
		public TeamFilter teamFilter;

		public GameObject pickupEffectPrefab;

		public int baseGoldReward;

		public bool shouldScale;

		private bool alive = true;

		private int goldReward;

		private void Start()
		{
			if (NetworkServer.active)
			{
				goldReward = (shouldScale ? Run.instance.GetDifficultyScaledCost(baseGoldReward) : baseGoldReward);
			}
		}

		private void OnTriggerStay(Collider other)
		{
			if (!NetworkServer.active || !alive)
			{
				return;
			}
			TeamIndex objectTeam = TeamComponent.GetObjectTeam(other.gameObject);
			if (objectTeam == teamFilter.teamIndex)
			{
				alive = false;
				UnityEngine.Vector3 position = base.transform.position;
				TeamManager.instance.GiveTeamMoney(objectTeam, (uint)goldReward);
				if ((bool)pickupEffectPrefab)
				{
					EffectManager.SimpleEffect(pickupEffectPrefab, position, UnityEngine.Quaternion.identity, transmit: true);
				}
				UnityEngine.Object.Destroy(baseObject);
			}
		}
	}
	public class MonsterCounter : MonoBehaviour
	{
		private int enemyList;

		private int CountEnemies()
		{
			return TeamComponent.GetTeamMembers(TeamIndex.Monster).Count;
		}

		private void Update()
		{
			enemyList = CountEnemies();
		}

		private void OnGUI()
		{
			GUI.Label(new UnityEngine.Rect(12f, 160f, 200f, 25f), "Living Monsters: " + enemyList);
		}
	}
	[RequireComponent(typeof(EntityStateMachine))]
	public class MoonBatteryMissionController : NetworkBehaviour
	{
		[SerializeField]
		private GameObject[] moonBatteries;

		[SerializeField]
		private GameObject[] elevators;

		[SerializeField]
		private int _numRequiredBatteries;

		[SerializeField]
		private string _objectiveToken;

		private HoldoutZoneController[] batteryHoldoutZones;

		private EntityStateMachine[] batteryStateMachines;

		private EntityStateMachine[] elevatorStateMachines;

		[SyncVar]
		private int _numChargedBatteries;

		public static MoonBatteryMissionController instance { get; private set; }

		public int numChargedBatteries => _numChargedBatteries;

		public int numRequiredBatteries => _numRequiredBatteries;

		public string objectiveToken => _objectiveToken;

		public int Network_numChargedBatteries
		{
			get
			{
				return _numChargedBatteries;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _numChargedBatteries, 1u);
			}
		}

		public static event Action onInstanceChangedGlobal;

		private void Awake()
		{
			List<HoldoutZoneController> list = new List<HoldoutZoneController>();
			List<EntityStateMachine> list2 = new List<EntityStateMachine>();
			for (int i = 0; i < moonBatteries.Length; i++)
			{
				if (moonBatteries[i] != null)
				{
					list.Add(moonBatteries[i].GetComponent<HoldoutZoneController>());
					list2.Add(moonBatteries[i].GetComponent<EntityStateMachine>());
				}
			}
			batteryHoldoutZones = list.ToArray();
			batteryStateMachines = list2.ToArray();
			List<EntityStateMachine> list3 = new List<EntityStateMachine>();
			for (int j = 0; j < elevators.Length; j++)
			{
				if (elevators[j] != null)
				{
					list3.Add(elevators[j].GetComponent<EntityStateMachine>());
				}
			}
			elevatorStateMachines = list3.ToArray();
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			MoonBatteryMissionController.onInstanceChangedGlobal?.Invoke();
			ObjectivePanelController.collectObjectiveSources += OnCollectObjectiveSources;
			for (int i = 0; i < batteryHoldoutZones.Length; i++)
			{
				batteryHoldoutZones[i].onCharged.AddListener(OnBatteryCharged);
			}
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			MoonBatteryMissionController.onInstanceChangedGlobal?.Invoke();
			ObjectivePanelController.collectObjectiveSources -= OnCollectObjectiveSources;
			for (int i = 0; i < batteryHoldoutZones.Length; i++)
			{
				batteryHoldoutZones[i].onCharged.RemoveListener(OnBatteryCharged);
			}
		}

		private void OnCollectObjectiveSources(CharacterMaster master, List<ObjectivePanelController.ObjectiveSourceDescriptor> objectiveSourcesList)
		{
			if (_numChargedBatteries > 0 && _numChargedBatteries < _numRequiredBatteries)
			{
				objectiveSourcesList.Add(new ObjectivePanelController.ObjectiveSourceDescriptor
				{
					master = master,
					objectiveType = typeof(MoonBatteryMissionObjectiveTracker),
					source = this
				});
			}
		}

		private void OnBatteryCharged(HoldoutZoneController holdoutZone)
		{
			Network_numChargedBatteries = _numChargedBatteries + 1;
			if (_numChargedBatteries < _numRequiredBatteries || !NetworkServer.active)
			{
				return;
			}
			for (int i = 0; i < batteryHoldoutZones.Length; i++)
			{
				if (batteryHoldoutZones[i].enabled)
				{
					batteryHoldoutZones[i].FullyChargeHoldoutZone();
					batteryHoldoutZones[i].onCharged.RemoveListener(OnBatteryCharged);
				}
			}
			batteryHoldoutZones = new HoldoutZoneController[0];
			for (int j = 0; j < batteryStateMachines.Length; j++)
			{
				if (!(batteryStateMachines[j].state is MoonBatteryComplete))
				{
					batteryStateMachines[j].SetNextState(new MoonBatteryDisabled());
				}
			}
			for (int k = 0; k < elevatorStateMachines.Length; k++)
			{
				elevatorStateMachines[k].SetNextState(new InactiveToReady());
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)_numChargedBatteries);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)_numChargedBatteries);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_numChargedBatteries = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_numChargedBatteries = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class MoonMissionController : NetworkBehaviour
	{
		private Xoroshiro128Plus rng;

		public static MoonMissionController instance { get; private set; }

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			SceneDirector.onPreGeneratePlayerSpawnPointsServer += OnPreGeneratePlayerSpawnPointsServer;
		}

		private void OnDisable()
		{
			SceneDirector.onPreGeneratePlayerSpawnPointsServer -= OnPreGeneratePlayerSpawnPointsServer;
			instance = SingletonHelper.Unassign(instance, this);
		}

		[Server]
		public override void OnStartServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.MoonMissionController::OnStartServer()' called on client");
				return;
			}
			base.OnStartServer();
			rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint);
		}

		private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod)
		{
			generationMethod = GeneratePlayerSpawnPointsServer;
		}

		private void GeneratePlayerSpawnPointsServer()
		{
			if (!SceneInfo.instance)
			{
				return;
			}
			ChildLocator component = SceneInfo.instance.GetComponent<ChildLocator>();
			if (!component)
			{
				return;
			}
			Transform transform = component.FindChild("PlayerSpawnOrigin");
			UnityEngine.Vector3 position = transform.position;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			if (!groundNodes)
			{
				UnityEngine.Debug.LogError("MoonMissionController.GeneratePlayerSpawnPointsServer: No ground nodegraph found to place spawn points.", this);
				return;
			}
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human);
			nodeGraphSpider.AddNodeForNextStep(groundNodes.FindClosestNode(position, HullClassification.Human));
			for (int i = 0; i < 4; i++)
			{
				nodeGraphSpider.PerformStep();
				if (nodeGraphSpider.collectedSteps.Count > 16)
				{
					break;
				}
			}
			for (int j = 0; j < nodeGraphSpider.collectedSteps.Count; j++)
			{
				NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[j];
				groundNodes.GetNodePosition(stepInfo.node, out var position2);
				UnityEngine.Quaternion rotation = transform.rotation;
				SpawnPoint.AddSpawnPoint(position2, rotation);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class MorsecodeFlasher : MonoBehaviour
	{
		private string[] alphabet = new string[36]
		{
			".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---",
			"-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-",
			"..-", "...-", ".--", "-..-", "-.--", "--..", "-----", ".----", "..---", "...--",
			"....-", ".....", "-....", "--...", "---..", "----."
		};

		public string morsecodeMessage;

		public float spaceDelay;

		public float delayBetweenCharacters;

		public float dotDuration;

		public float dashDuration;

		public float messageRepeatDelay;

		public GameObject flashRootObject;

		private float age;

		private void FixedUpdate()
		{
			age -= Time.fixedDeltaTime;
			if (age <= 0f)
			{
				age = messageRepeatDelay;
				PlayMorseCodeMessage(morsecodeMessage);
			}
		}

		public void PlayMorseCodeMessage(string message)
		{
			StartCoroutine("_PlayMorseCodeMessage", message);
		}

		private IEnumerator _PlayMorseCodeMessage(string message)
		{
			Regex regex = new Regex("[^A-z0-9 ]");
			message = regex.Replace(message.ToUpper(), "");
			string text = message;
			foreach (char c in text)
			{
				if (c == ' ')
				{
					yield return new WaitForSeconds(spaceDelay);
					continue;
				}
				int num = c - 65;
				if (num < 0)
				{
					num = c - 48 + 26;
				}
				string text2 = alphabet[num];
				string text3 = text2;
				foreach (char num2 in text3)
				{
					float num3 = dotDuration;
					if (num2 == '-')
					{
						num3 = dashDuration;
					}
					StartCoroutine("_FlashMorseCodeObject", num3);
					yield return new WaitForSeconds(num3 + delayBetweenCharacters);
				}
			}
		}

		private IEnumerator _FlashMorseCodeObject(float duration)
		{
			flashRootObject.SetActive(value: true);
			yield return new WaitForSeconds(duration);
			flashRootObject.SetActive(value: false);
		}
	}
	public class MultiBodyTrigger : MonoBehaviour
	{
		[Header("Parameters")]
		public bool playerControlledOnly = true;

		[Header("Events")]
		public CharacterBody.CharacterBodyUnityEvent onFirstQualifyingBodyEnter;

		public CharacterBody.CharacterBodyUnityEvent onLastQualifyingBodyExit;

		public CharacterBody.CharacterBodyUnityEvent onAnyQualifyingBodyEnter;

		public CharacterBody.CharacterBodyUnityEvent onAnyQualifyingBodyExit;

		public UnityEvent onAllQualifyingBodiesEnter;

		public UnityEvent onAllQualifyingBodiesExit;

		private readonly Queue<Collider> collisionsQueue = new Queue<Collider>();

		private readonly List<CharacterBody> encounteredBodies = new List<CharacterBody>();

		private bool allCandidatesPreviouslyTriggering;

		private bool cachedEnabled;

		private void OnEnable()
		{
			cachedEnabled = true;
		}

		private void OnDisable()
		{
			cachedEnabled = false;
			collisionsQueue.Clear();
			List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			SetEncounteredBodies(list, 0);
			list = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
		}

		private void OnTriggerStay(Collider collider)
		{
			if (cachedEnabled)
			{
				collisionsQueue.Enqueue(collider);
			}
		}

		private void FixedUpdate()
		{
			if (collisionsQueue.Count == 0 && encounteredBodies.Count == 0)
			{
				return;
			}
			List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			while (collisionsQueue.Count > 0)
			{
				Collider collider = collisionsQueue.Dequeue();
				if ((bool)collider)
				{
					CharacterBody value = collider.GetComponent<CharacterBody>();
					if ((bool)value && (!playerControlledOnly || value.isPlayerControlled) && ListUtils.FirstOccurrenceByReference(list, in value) == -1)
					{
						list.Add(value);
					}
				}
			}
			SetEncounteredBodies(list, playerControlledOnly ? (Run.instance?.livingPlayerCount ?? 0) : 0);
			list = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
		}

		private void SetEncounteredBodies(List<CharacterBody> newEncounteredBodies, int candidateCount)
		{
			List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			List<CharacterBody> list2 = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			ListUtils.FindExclusiveEntriesByReference(encounteredBodies, newEncounteredBodies, list2, list);
			bool flag = encounteredBodies.Count == 0;
			bool flag2 = newEncounteredBodies.Count == 0;
			ListUtils.CloneTo(newEncounteredBodies, encounteredBodies);
			foreach (CharacterBody item in list2)
			{
				try
				{
					onAnyQualifyingBodyExit?.Invoke(item);
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
			if (flag != flag2)
			{
				if (flag2)
				{
					try
					{
						onLastQualifyingBodyExit?.Invoke(list2[list2.Count - 1]);
					}
					catch (Exception message2)
					{
						UnityEngine.Debug.LogError(message2);
					}
				}
				else
				{
					try
					{
						onFirstQualifyingBodyEnter?.Invoke(list[0]);
					}
					catch (Exception message3)
					{
						UnityEngine.Debug.LogError(message3);
					}
				}
			}
			foreach (CharacterBody item2 in list)
			{
				try
				{
					onAnyQualifyingBodyEnter?.Invoke(item2);
				}
				catch (Exception message4)
				{
					UnityEngine.Debug.LogError(message4);
				}
			}
			list2 = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list2);
			list = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
			bool flag3 = encounteredBodies.Count >= candidateCount && candidateCount > 0;
			if (allCandidatesPreviouslyTriggering == flag3)
			{
				return;
			}
			try
			{
				if (flag3)
				{
					onAllQualifyingBodiesEnter?.Invoke();
				}
				else
				{
					onAllQualifyingBodiesExit?.Invoke();
				}
			}
			catch (Exception message5)
			{
				UnityEngine.Debug.LogError(message5);
			}
			allCandidatesPreviouslyTriggering = flag3;
		}

		public void KillAllOutsideWithVoidDeath()
		{
			List<CharacterBody> list = CollectionPool<CharacterBody, List<CharacterBody>>.RentCollection();
			ListUtils.AddRange(list, CharacterBody.readOnlyInstancesList);
			foreach (CharacterBody item in list)
			{
				if (encounteredBodies.Contains(item))
				{
					continue;
				}
				CharacterMaster master = item.master;
				if ((bool)master)
				{
					try
					{
						master.TrueKill(BodyCatalog.FindBodyPrefab("BrotherBody"), null, DamageType.VoidDeath);
					}
					catch (Exception message)
					{
						UnityEngine.Debug.LogError(message);
					}
				}
			}
			list = CollectionPool<CharacterBody, List<CharacterBody>>.ReturnCollection(list);
		}
	}
	[ExecuteAlways]
	[RequireComponent(typeof(LineRenderer))]
	public class MultiPointBezierCurveLine : MonoBehaviour
	{
		[Serializable]
		public struct Vertex
		{
			public Transform vertexTransform;

			public UnityEngine.Vector3 position;

			public UnityEngine.Vector3 localVelocity;
		}

		public Vertex[] vertexList;

		public UnityEngine.Vector3[] linePositionList;

		[HideInInspector]
		public LineRenderer lineRenderer;

		private void Start()
		{
			lineRenderer = GetComponent<LineRenderer>();
		}

		private void LateUpdate()
		{
			for (int i = 0; i < linePositionList.Length; i++)
			{
				float globalT = (float)i / (float)(linePositionList.Length - 1);
				linePositionList[i] = EvaluateBezier(globalT);
			}
			lineRenderer.SetPositions(linePositionList);
		}

		private UnityEngine.Vector3 EvaluateBezier(float globalT)
		{
			int num = vertexList.Length - 1;
			int num2;
			int num3 = Mathf.Min((num2 = Mathf.FloorToInt((float)num * globalT)) + 1, num);
			Vertex vertex = vertexList[num2];
			Vertex vertex2 = vertexList[num3];
			UnityEngine.Vector3 vector = (vertex.vertexTransform ? vertex.vertexTransform.position : vertex.position);
			UnityEngine.Vector3 vector2 = (vertex2.vertexTransform ? vertex2.vertexTransform.position : vertex2.position);
			UnityEngine.Vector3 vector3 = (vertex.vertexTransform ? vertex.vertexTransform.TransformVector(vertex.localVelocity) : vertex.localVelocity);
			UnityEngine.Vector3 vector4 = (vertex2.vertexTransform ? vertex2.vertexTransform.TransformVector(vertex2.localVelocity) : vertex2.localVelocity);
			if (num2 == num3)
			{
				return vector;
			}
			float inMin = (float)num2 / (float)num;
			float inMax = (float)num3 / (float)num;
			float num4 = Util.Remap(globalT, inMin, inMax, 0f, 1f);
			UnityEngine.Vector3 a = UnityEngine.Vector3.Lerp(vector, vector + vector3, num4);
			UnityEngine.Vector3 b = UnityEngine.Vector3.Lerp(vector2, vector2 + vector4, 1f - num4);
			return UnityEngine.Vector3.Lerp(a, b, num4);
		}
	}
	public class MultiShopController : NetworkBehaviour, IHologramContentProvider
	{
		[Tooltip("The shop terminal prefab to instantiate.")]
		public GameObject terminalPrefab;

		[Tooltip("The positions at which to instantiate shop terminals.")]
		public Transform[] terminalPositions;

		[Tooltip("The number of terminals guaranteed to have their item revealed")]
		public int revealCount = 1;

		[Tooltip("The percentage chance that terminals after the reveal count will be hidden")]
		public float hiddenChance = 0.2f;

		[Header("Deprecated")]
		[Tooltip("The tier of items to drop")]
		public ItemTier itemTier;

		public bool doEquipmentInstead;

		[Tooltip("Whether or not there's a chance the item contents are replaced with a '?'")]
		private bool hideDisplayContent = true;

		private bool[] doCloseOnTerminalPurchase;

		private GameObject[] _terminalGameObjects;

		public ReadOnlyArray<GameObject> terminalGameObjects;

		[SyncVar]
		private bool available = true;

		public int baseCost;

		public CostTypeIndex costType;

		[SyncVar]
		private int cost;

		private Xoroshiro128Plus rng;

		private static int kRpcRpcSetTerminalPingable;

		public bool Networkavailable
		{
			get
			{
				return available;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref available, 1u);
			}
		}

		public int Networkcost
		{
			get
			{
				return cost;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref cost, 2u);
			}
		}

		private void Start()
		{
			if (!Run.instance || !NetworkServer.active)
			{
				return;
			}
			rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			CreateTerminals();
			Networkcost = Run.instance.GetDifficultyScaledCost(baseCost);
			if (_terminalGameObjects != null)
			{
				GameObject[] array = _terminalGameObjects;
				for (int i = 0; i < array.Length; i++)
				{
					PurchaseInteraction component = array[i].GetComponent<PurchaseInteraction>();
					component.Networkcost = cost;
					component.costType = costType;
				}
			}
		}

		private void OnDestroy()
		{
			if (_terminalGameObjects != null)
			{
				for (int num = _terminalGameObjects.Length - 1; num >= 0; num--)
				{
					UnityEngine.Object.Destroy(_terminalGameObjects[num]);
				}
				_terminalGameObjects = null;
			}
		}

		private void CreateTerminals()
		{
			doCloseOnTerminalPurchase = new bool[terminalPositions.Length];
			_terminalGameObjects = new GameObject[terminalPositions.Length];
			terminalGameObjects = new ReadOnlyArray<GameObject>(_terminalGameObjects);
			for (int i = 0; i < terminalPositions.Length; i++)
			{
				doCloseOnTerminalPurchase[i] = true;
				GameObject gameObject = UnityEngine.Object.Instantiate(terminalPrefab, terminalPositions[i].position, terminalPositions[i].rotation);
				_terminalGameObjects[i] = gameObject;
				ShopTerminalBehavior component = gameObject.GetComponent<ShopTerminalBehavior>();
				component.serverMultiShopController = this;
				if (!component.selfGeneratePickup)
				{
					PickupIndex newPickupIndex = PickupIndex.none;
					if (doEquipmentInstead)
					{
						newPickupIndex = rng.NextElementUniform(Run.instance.availableEquipmentDropList);
					}
					else
					{
						switch (itemTier)
						{
						case ItemTier.Tier1:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableTier1DropList);
							break;
						case ItemTier.Tier2:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableTier2DropList);
							break;
						case ItemTier.Tier3:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableTier3DropList);
							break;
						case ItemTier.Lunar:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableLunarCombinedDropList);
							break;
						case ItemTier.VoidTier1:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidTier1DropList);
							break;
						case ItemTier.VoidTier2:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidTier2DropList);
							break;
						case ItemTier.VoidTier3:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidTier3DropList);
							break;
						case ItemTier.VoidBoss:
							newPickupIndex = rng.NextElementUniform(Run.instance.availableVoidBossDropList);
							break;
						}
					}
					bool newHidden = hideDisplayContent && i >= revealCount && rng.nextNormalizedFloat < hiddenChance;
					component.SetPickupIndex(newPickupIndex, newHidden);
				}
				else
				{
					component.SetHidden(i >= revealCount && rng.nextNormalizedFloat < hiddenChance);
				}
				NetworkServer.Spawn(gameObject);
			}
			GameObject[] array = _terminalGameObjects;
			foreach (GameObject gameObject2 in array)
			{
				PurchaseInteraction purchaseInteraction = gameObject2.GetComponent<PurchaseInteraction>();
				purchaseInteraction.onPurchase.AddListener(delegate(Interactor interactor)
				{
					OnPurchase(interactor, purchaseInteraction);
				});
			}
		}

		private void OnPurchase(Interactor interactor, PurchaseInteraction purchaseInteraction)
		{
			bool flag = false;
			Networkavailable = false;
			for (int i = 0; i < _terminalGameObjects.Length; i++)
			{
				GameObject gameObject = _terminalGameObjects[i];
				PurchaseInteraction component = gameObject.GetComponent<PurchaseInteraction>();
				if ((object)purchaseInteraction == component)
				{
					component.Networkavailable = false;
					gameObject.GetComponent<ShopTerminalBehavior>().SetNoPickup();
					CallRpcSetTerminalPingable(gameObject, value: false);
					flag = doCloseOnTerminalPurchase[i];
				}
				Networkavailable = available || component.available;
			}
			if (flag)
			{
				Networkavailable = false;
				GameObject[] array = _terminalGameObjects;
				foreach (GameObject gameObject2 in array)
				{
					gameObject2.GetComponent<PurchaseInteraction>().Networkavailable = false;
					gameObject2.GetComponent<ShopTerminalBehavior>().SetNoPickup();
					CallRpcSetTerminalPingable(gameObject2, value: false);
				}
			}
		}

		[ClientRpc]
		private void RpcSetTerminalPingable(GameObject terminalGO, bool value)
		{
			NetworkIdentity component = terminalGO.GetComponent<NetworkIdentity>();
			if ((bool)component)
			{
				component.isPingable = value;
			}
		}

		public bool ShouldDisplayHologram(GameObject viewer)
		{
			if (available)
			{
				if (cost != 0)
				{
					return costType != CostTypeIndex.None;
				}
				return false;
			}
			return false;
		}

		public GameObject GetHologramContentPrefab()
		{
			return LegacyResourcesAPI.Load<GameObject>("Prefabs/CostHologramContent");
		}

		public void UpdateHologramContent(GameObject hologramContentObject, Transform viewer)
		{
			CostHologramContent component = hologramContentObject.GetComponent<CostHologramContent>();
			if (!component)
			{
				return;
			}
			if ((bool)viewer && costType.Equals(CostTypeIndex.Money))
			{
				if (TeamManager.LongstandingSolitudesInParty() > 0)
				{
					component.displayValue = cost * (TeamManager.LongstandingSolitudesInParty() + 1);
				}
				else
				{
					component.displayValue = cost;
				}
			}
			component.costType = costType;
		}

		public void SetCloseOnTerminalPurchase(PurchaseInteraction terminalPurchaseInteraction, bool doCloseMultiShop)
		{
			for (int i = 0; i < _terminalGameObjects.Length; i++)
			{
				if ((object)_terminalGameObjects[i].GetComponent<PurchaseInteraction>() == terminalPurchaseInteraction)
				{
					doCloseOnTerminalPurchase[i] = doCloseMultiShop;
				}
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcSetTerminalPingable(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetTerminalPingable called on server.");
			}
			else
			{
				((MultiShopController)obj).RpcSetTerminalPingable(reader.ReadGameObject(), reader.ReadBoolean());
			}
		}

		public void CallRpcSetTerminalPingable(GameObject terminalGO, bool value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetTerminalPingable called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetTerminalPingable);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(terminalGO);
			networkWriter.Write(value);
			SendRPCInternal(networkWriter, 0, "RpcSetTerminalPingable");
		}

		static MultiShopController()
		{
			kRpcRpcSetTerminalPingable = -474614679;
			NetworkBehaviour.RegisterRpcDelegate(typeof(MultiShopController), kRpcRpcSetTerminalPingable, InvokeRpcRpcSetTerminalPingable);
			NetworkCRC.RegisterBehaviour("MultiShopController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(available);
				writer.WritePackedUInt32((uint)cost);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(available);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)cost);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				available = reader.ReadBoolean();
				cost = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				available = reader.ReadBoolean();
			}
			if (((uint)num & 2u) != 0)
			{
				cost = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class MusicController : MonoBehaviour
	{
		public delegate void PickTrackDelegate(MusicController musicController, ref MusicTrackDef newTrack);

		private struct EnemyInfo
		{
			public Ray aimRay;

			public float lookScore;

			public float proximityScore;

			public float threatScore;
		}

		private struct CalculateIntensityJob : IJobParallelFor
		{
			[ReadOnly]
			public UnityEngine.Vector3 targetPosition;

			[ReadOnly]
			public int elementCount;

			public NativeArray<EnemyInfo> enemyInfoBuffer;

			[ReadOnly]
			public float nearDistance;

			[ReadOnly]
			public float farDistance;

			public void Execute(int i)
			{
				EnemyInfo value = enemyInfoBuffer[i];
				UnityEngine.Vector3 vector = targetPosition - value.aimRay.origin;
				float magnitude = vector.magnitude;
				float num = Mathf.Clamp01(UnityEngine.Vector3.Dot(vector / magnitude, value.aimRay.direction));
				float num2 = Mathf.Clamp01(Mathf.InverseLerp(farDistance, nearDistance, magnitude));
				value.lookScore = num * value.threatScore;
				value.proximityScore = num2 * value.threatScore;
				enemyInfoBuffer[i] = value;
			}

			public void CalculateSum(out float proximityScore, out float lookScore)
			{
				proximityScore = 0f;
				lookScore = 0f;
				for (int i = 0; i < elementCount; i++)
				{
					proximityScore += enemyInfoBuffer[i].proximityScore;
					lookScore += enemyInfoBuffer[i].lookScore;
				}
			}
		}

		public GameObject target;

		public bool enableMusicSystem;

		public MusicTrackDef introCutsceneMusic;

		private CameraRigController targetCamera;

		private MusicTrackDef _currentTrack;

		private RtpcSetter rtpcPlayerHealthValue;

		private RtpcSetter rtpcEnemyValue;

		private RtpcSetter rtpcTeleporterProximityValue;

		private RtpcSetter rtpcTeleporterDirectionValue;

		private RtpcSetter rtpcTeleporterPlayerStatus;

		private StateSetter stBossStatus;

		public static int timesStartRan;

		private float updateTimer;

		private const float MUSIC_UPDATE_INTERVAL = 0.25f;

		private bool wasPaused;

		private NativeArray<EnemyInfo> enemyInfoBuffer;

		private CalculateIntensityJob calculateIntensityJob;

		private JobHandle calculateIntensityJobHandle;

		public static MusicController Instance { get; private set; }

		private MusicTrackDef currentTrack
		{
			get
			{
				return _currentTrack;
			}
			set
			{
				if ((object)_currentTrack != value)
				{
					if ((object)_currentTrack != null)
					{
						_currentTrack.Stop();
					}
					_currentTrack = value;
					if ((object)_currentTrack != null)
					{
						_currentTrack.Play();
					}
				}
			}
		}

		public static event PickTrackDelegate pickTrackHook;

		private void InitializeEngineDependentValues()
		{
			rtpcPlayerHealthValue = new RtpcSetter("playerHealth");
			rtpcEnemyValue = new RtpcSetter("enemyValue");
			rtpcTeleporterProximityValue = new RtpcSetter("teleporterProximity");
			rtpcTeleporterDirectionValue = new RtpcSetter("teleporterDirection");
			rtpcTeleporterPlayerStatus = new RtpcSetter("teleporterPlayerStatus");
			stBossStatus = new StateSetter("bossStatus");
		}

		private void Update()
		{
			if (updateTimer <= 0f)
			{
				updateTimer = 0.25f;
				UpdateState();
				targetCamera = ((CameraRigController.readOnlyInstancesList.Count > 0) ? CameraRigController.readOnlyInstancesList[0] : null);
				target = (targetCamera ? targetCamera.target : null);
				ScheduleIntensityCalculation(target);
			}
			else
			{
				updateTimer -= Time.deltaTime;
			}
		}

		private void RecalculateHealth(GameObject playerObject)
		{
			rtpcPlayerHealthValue.value = 100f;
			if (!target)
			{
				return;
			}
			CharacterBody component = target.GetComponent<CharacterBody>();
			if (!component)
			{
				return;
			}
			if (component.HasBuff(JunkContent.Buffs.Deafened))
			{
				rtpcPlayerHealthValue.value = -100f;
				return;
			}
			HealthComponent healthComponent = component.healthComponent;
			if ((bool)healthComponent)
			{
				rtpcPlayerHealthValue.value = healthComponent.combinedHealthFraction * 100f;
			}
		}

		private void UpdateTeleporterParameters(TeleporterInteraction teleporter, Transform cameraTransform, CharacterBody targetBody)
		{
			float value = float.PositiveInfinity;
			float value2 = 0f;
			bool flag = true;
			stBossStatus.valueId = CommonWwiseIds.alive;
			if ((bool)teleporter)
			{
				if ((bool)cameraTransform)
				{
					UnityEngine.Vector3 position = cameraTransform.position;
					UnityEngine.Vector3 forward = cameraTransform.forward;
					UnityEngine.Vector3 vector = teleporter.transform.position - position;
					float num = UnityEngine.Vector2.SignedAngle(new UnityEngine.Vector2(vector.x, vector.z), new UnityEngine.Vector2(forward.x, forward.z));
					if (num < 0f)
					{
						num += 360f;
					}
					value = vector.magnitude;
					value2 = num;
				}
				if (TeleporterInteraction.instance.isIdleToCharging || TeleporterInteraction.instance.isCharging)
				{
					stBossStatus.valueId = CommonWwiseIds.alive;
				}
				else if (TeleporterInteraction.instance.isCharged)
				{
					stBossStatus.valueId = CommonWwiseIds.dead;
				}
				if (teleporter.isCharging && (bool)targetBody)
				{
					flag = teleporter.holdoutZoneController.IsBodyInChargingRadius(targetBody);
				}
			}
			value = Mathf.Clamp(value, 20f, 250f);
			rtpcTeleporterProximityValue.value = Util.Remap(value, 20f, 250f, 0f, 10000f);
			rtpcTeleporterDirectionValue.value = value2;
			rtpcTeleporterPlayerStatus.value = (flag ? 1f : 0f);
		}

		private void LateUpdate()
		{
			bool flag = Time.timeScale == 0f;
			if (wasPaused != flag)
			{
				AkSoundEngine.PostEvent(flag ? "Pause_Music" : "Unpause_Music", base.gameObject);
				wasPaused = flag;
			}
			RecalculateHealth(target);
			UpdateTeleporterParameters(TeleporterInteraction.instance, targetCamera ? targetCamera.transform : null, target ? target.GetComponent<CharacterBody>() : null);
			calculateIntensityJobHandle.Complete();
			calculateIntensityJob.CalculateSum(out var proximityScore, out var lookScore);
			float num = 0.025f;
			Mathf.Clamp(1f - rtpcPlayerHealthValue.value * 0.01f, 0.25f, 0.75f);
			float value = (proximityScore * 0.75f + lookScore * 0.25f) * num;
			rtpcEnemyValue.value = value;
			FlushValuesToEngine();
		}

		private void FlushValuesToEngine()
		{
			stBossStatus.FlushIfChanged();
			rtpcPlayerHealthValue.FlushIfChanged();
			rtpcTeleporterProximityValue.FlushIfChanged();
			rtpcTeleporterDirectionValue.FlushIfChanged();
			rtpcTeleporterPlayerStatus.FlushIfChanged();
			rtpcEnemyValue.FlushIfChanged();
		}

		private void PickCurrentTrack(ref MusicTrackDef newTrack)
		{
			SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef;
			bool flag = false;
			if ((bool)TeleporterInteraction.instance && !TeleporterInteraction.instance.isIdle)
			{
				flag = true;
			}
			if (enableMusicSystem && (bool)mostRecentSceneDef)
			{
				if (flag && (bool)mostRecentSceneDef.bossTrack)
				{
					newTrack = mostRecentSceneDef.bossTrack;
				}
				else if ((bool)mostRecentSceneDef.mainTrack)
				{
					newTrack = mostRecentSceneDef.mainTrack;
				}
			}
			MusicController.pickTrackHook?.Invoke(this, ref newTrack);
		}

		private void UpdateState()
		{
			MusicTrackDef newTrack = currentTrack;
			PickCurrentTrack(ref newTrack);
			currentTrack = newTrack;
		}

		private void EnsureEnemyBufferSize(int requiredSize)
		{
			if (enemyInfoBuffer.Length < requiredSize)
			{
				if (enemyInfoBuffer.Length != 0)
				{
					enemyInfoBuffer.Dispose();
				}
				enemyInfoBuffer = new NativeArray<EnemyInfo>(requiredSize, Allocator.Persistent);
			}
		}

		private void OnDestroy()
		{
			enemyInfoBuffer.Dispose();
		}

		private void ScheduleIntensityCalculation(GameObject targetBodyObject)
		{
			if (!targetBodyObject)
			{
				return;
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Monster);
			int count = teamMembers.Count;
			EnsureEnemyBufferSize(count);
			int num = 0;
			int i = 0;
			for (int num2 = count; i < num2; i++)
			{
				TeamComponent teamComponent = teamMembers[i];
				InputBankTest component = teamComponent.GetComponent<InputBankTest>();
				CharacterBody component2 = teamComponent.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					enemyInfoBuffer[num++] = new EnemyInfo
					{
						aimRay = new Ray(component.aimOrigin, component.aimDirection),
						threatScore = (component2.master ? component2.GetNormalizedThreatValue() : 0f)
					};
				}
			}
			calculateIntensityJob = new CalculateIntensityJob
			{
				enemyInfoBuffer = enemyInfoBuffer,
				elementCount = num,
				targetPosition = targetBodyObject.transform.position,
				nearDistance = 20f,
				farDistance = 75f
			};
			calculateIntensityJobHandle = calculateIntensityJob.Schedule(num, 32);
		}

		public static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/MusicController");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> result)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(result.Result, RoR2Application.instance.transform);
				if (gameObject != null)
				{
					gameObject.GetComponent<MusicController>().PreloadForCutsceneStart();
				}
			};
		}

		public void PreloadForCutsceneStart()
		{
			Instance = this;
			enemyInfoBuffer = new NativeArray<EnemyInfo>(64, Allocator.Persistent);
			InitializeEngineDependentValues();
			SceneManager.sceneLoaded += SceneManager_OnLoadNextScene;
		}

		private void SceneManager_OnLoadNextScene(Scene arg0, LoadSceneMode arg1)
		{
			if (arg0.name == "intro")
			{
				currentTrack = introCutsceneMusic;
			}
			else
			{
				SceneManager.sceneLoaded -= SceneManager_OnLoadNextScene;
			}
		}

		public void StartIntroMusic()
		{
			AkSoundEngine.PostEvent("Play_Music_System", base.gameObject);
			currentTrack = introCutsceneMusic;
			enableMusicSystem = true;
		}
	}
	public class MusicTrackOverride : MonoBehaviour
	{
		public MusicTrackDef track;

		public int priority;

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			if (InstanceTracker.GetInstancesList<MusicTrackOverride>().Count == 1)
			{
				MusicController.pickTrackHook += PickMusicTrack;
			}
		}

		private void OnDisable()
		{
			if (InstanceTracker.GetInstancesList<MusicTrackOverride>().Count == 1)
			{
				MusicController.pickTrackHook -= PickMusicTrack;
			}
			InstanceTracker.Remove(this);
		}

		private static void PickMusicTrack(MusicController musicController, ref MusicTrackDef newTrack)
		{
			List<MusicTrackOverride> instancesList = InstanceTracker.GetInstancesList<MusicTrackOverride>();
			int num = int.MinValue;
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				MusicTrackOverride musicTrackOverride = instancesList[i];
				int num2 = musicTrackOverride.priority;
				if (num < num2)
				{
					num = num2;
					newTrack = musicTrackOverride.track;
				}
			}
		}
	}
	public sealed class NetworkedBodyAttachment : NetworkBehaviour
	{
		[SyncVar(hook = "OnSyncAttachedBodyObject")]
		private GameObject _attachedBodyObject;

		[SyncVar(hook = "OnSyncAttachedBodyChildName")]
		private string attachedBodyChildName;

		public bool shouldParentToAttachedBody = true;

		public bool forceHostAuthority;

		private NetworkIdentity networkIdentity;

		private CharacterBody attachmentBody;

		private bool attached;

		private NetworkInstanceId ____attachedBodyObjectNetId;

		public GameObject attachedBodyObject => _attachedBodyObject;

		public CharacterBody attachedBody { get; private set; }

		public bool hasEffectiveAuthority { get; private set; }

		public GameObject Network_attachedBodyObject
		{
			get
			{
				return _attachedBodyObject;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncAttachedBodyObject(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVarGameObject(value, ref _attachedBodyObject, 1u, ref ____attachedBodyObjectNetId);
			}
		}

		public string NetworkattachedBodyChildName
		{
			get
			{
				return attachedBodyChildName;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncAttachedBodyChildName(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref attachedBodyChildName, 2u);
			}
		}

		private void OnSyncAttachedBodyObject(GameObject value)
		{
			if (!NetworkServer.active)
			{
				Network_attachedBodyObject = value;
				OnAttachedBodyObjectAssigned();
			}
		}

		private void OnSyncAttachedBodyChildName(string newName)
		{
			NetworkattachedBodyChildName = newName;
			if (shouldParentToAttachedBody)
			{
				ParentToBody();
			}
		}

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			attachmentBody = GetComponent<CharacterBody>();
		}

		[Server]
		public void AttachToGameObjectAndSpawn([NotNull] GameObject newAttachedBodyObject, string attachedBodyChildName = null)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkedBodyAttachment::AttachToGameObjectAndSpawn(UnityEngine.GameObject,System.String)' called on client");
			}
			else if (attached)
			{
				UnityEngine.Debug.LogErrorFormat("Can't attach object '{0}' to object '{1}', it's already been assigned to object '{2}'.", base.gameObject, newAttachedBodyObject, attachedBodyObject);
			}
			else if ((bool)newAttachedBodyObject)
			{
				NetworkIdentity component = newAttachedBodyObject.GetComponent<NetworkIdentity>();
				if (component.netId.Value == 0)
				{
					UnityEngine.Debug.LogWarningFormat("Network Identity for object {0} has a zero netID. Attachment will fail over the network.", newAttachedBodyObject);
				}
				NetworkattachedBodyChildName = attachedBodyChildName;
				Network_attachedBodyObject = newAttachedBodyObject;
				OnAttachedBodyObjectAssigned();
				NetworkConnection networkConnection = null;
				networkConnection = component.clientAuthorityOwner;
				if (networkConnection == null || forceHostAuthority)
				{
					NetworkServer.Spawn(base.gameObject);
				}
				else
				{
					NetworkServer.SpawnWithClientAuthority(base.gameObject, networkConnection);
				}
			}
		}

		private void OnAttachedBodyObjectAssigned()
		{
			if (attached)
			{
				return;
			}
			attached = true;
			if ((bool)_attachedBodyObject)
			{
				attachedBody = _attachedBodyObject.GetComponent<CharacterBody>();
				if (shouldParentToAttachedBody)
				{
					ParentToBody();
				}
			}
			if (!attachedBody)
			{
				return;
			}
			List<INetworkedBodyAttachmentListener> list = CollectionPool<INetworkedBodyAttachmentListener, List<INetworkedBodyAttachmentListener>>.RentCollection();
			GetComponents(list);
			foreach (INetworkedBodyAttachmentListener item in list)
			{
				item.OnAttachedBodyDiscovered(this, attachedBody);
			}
			list = CollectionPool<INetworkedBodyAttachmentListener, List<INetworkedBodyAttachmentListener>>.ReturnCollection(list);
		}

		private void ParentToBody()
		{
			if (!_attachedBodyObject)
			{
				return;
			}
			Transform parent = _attachedBodyObject.transform;
			if (!string.IsNullOrEmpty(attachedBodyChildName))
			{
				ModelLocator component = _attachedBodyObject.GetComponent<ModelLocator>();
				if ((bool)component && (bool)component.modelTransform)
				{
					ChildLocator component2 = component.modelTransform.GetComponent<ChildLocator>();
					if ((bool)component2)
					{
						Transform transform = component2.FindChild(attachedBodyChildName);
						if ((bool)transform)
						{
							parent = transform;
						}
						else
						{
							transform = component2.FindChild("Root");
							if ((bool)transform)
							{
								parent = transform;
							}
						}
					}
				}
			}
			base.transform.SetParent(parent, worldPositionStays: false);
			base.transform.localPosition = UnityEngine.Vector3.zero;
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			OnSyncAttachedBodyObject(attachedBodyObject);
		}

		private void FixedUpdate()
		{
			if (!attachedBodyObject && NetworkServer.active)
			{
				if ((bool)attachmentBody && (bool)attachmentBody.healthComponent)
				{
					attachmentBody.healthComponent.Suicide();
				}
				else
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}

		private void OnValidate()
		{
			if (!GetComponent<NetworkIdentity>().localPlayerAuthority && !forceHostAuthority)
			{
				UnityEngine.Debug.LogWarningFormat("NetworkedBodyAttachment: Object {0} NetworkIdentity needs localPlayerAuthority=true", base.gameObject.name);
			}
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public static void FindBodyAttachments(CharacterBody body, List<NetworkedBodyAttachment> output)
		{
			foreach (NetworkedBodyAttachment instances in InstanceTracker.GetInstancesList<NetworkedBodyAttachment>())
			{
				if ((object)instances.attachedBody == body)
				{
					output.Add(instances);
				}
			}
		}

		public override void OnStartAuthority()
		{
			base.OnStartAuthority();
			hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity);
		}

		public override void OnStopAuthority()
		{
			base.OnStopAuthority();
			hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_attachedBodyObject);
				writer.Write(attachedBodyChildName);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_attachedBodyObject);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(attachedBodyChildName);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				____attachedBodyObjectNetId = reader.ReadNetworkId();
				attachedBodyChildName = reader.ReadString();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncAttachedBodyObject(reader.ReadGameObject());
			}
			if (((uint)num & 2u) != 0)
			{
				OnSyncAttachedBodyChildName(reader.ReadString());
			}
		}

		public override void PreStartClient()
		{
			if (!____attachedBodyObjectNetId.IsEmpty())
			{
				Network_attachedBodyObject = ClientScene.FindLocalObject(____attachedBodyObjectNetId);
			}
		}
	}
	public interface INetworkedBodyAttachmentListener
	{
		void OnAttachedBodyDiscovered(NetworkedBodyAttachment networkedBodyAttachment, CharacterBody attachedBody);
	}
	public class NetworkedBodySpawnSlot : MonoBehaviour, MasterSpawnSlotController.ISlot
	{
		[SerializeField]
		private SpawnCard spawnCard;

		[SerializeField]
		private CharacterBody ownerBody;

		[SerializeField]
		private ChildLocator ownerChildLocator;

		[SerializeField]
		private string ownerAttachChildName;

		[SerializeField]
		private GameObject spawnEffectPrefab;

		[SerializeField]
		private GameObject killEffectPrefab;

		private CharacterMaster spawnedMaster;

		private bool isSpawnPending;

		public bool IsOpen()
		{
			if (!isSpawnPending)
			{
				return !spawnedMaster;
			}
			return false;
		}

		public void Spawn(GameObject summonerBodyObject, Xoroshiro128Plus rng, Action<MasterSpawnSlotController.ISlot, SpawnCard.SpawnResult> callback = null)
		{
			if (!NetworkServer.active || !ownerBody)
			{
				return;
			}
			Transform spawnOnTarget = ownerBody.transform;
			if (!string.IsNullOrEmpty(ownerAttachChildName) && (bool)ownerChildLocator)
			{
				Transform transform = ownerChildLocator.FindChild(ownerAttachChildName);
				if ((bool)transform)
				{
					spawnOnTarget = transform.transform;
				}
			}
			DirectorPlacementRule placementRule = new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Direct,
				spawnOnTarget = spawnOnTarget
			};
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, placementRule, rng);
			directorSpawnRequest.summonerBodyObject = summonerBodyObject;
			directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult spawnResult)
			{
				OnSpawnedServer(ownerBody.gameObject, spawnResult, callback);
			});
			isSpawnPending = true;
			DirectorCore.instance?.TrySpawnObject(directorSpawnRequest);
		}

		public void Kill()
		{
			if (NetworkServer.active && (bool)spawnedMaster)
			{
				GameObject bodyObject = spawnedMaster.GetBodyObject();
				if ((bool)killEffectPrefab && (bool)bodyObject)
				{
					EffectData effectData = new EffectData
					{
						origin = bodyObject.transform.position,
						rotation = bodyObject.transform.rotation
					};
					EffectManager.SpawnEffect(killEffectPrefab, effectData, transmit: true);
				}
				spawnedMaster.TrueKill();
				spawnedMaster = null;
			}
		}

		private void OnSpawnedServer(GameObject ownerBodyObject, SpawnCard.SpawnResult spawnResult, Action<MasterSpawnSlotController.ISlot, SpawnCard.SpawnResult> callback)
		{
			isSpawnPending = false;
			if (spawnResult.success)
			{
				spawnedMaster = spawnResult.spawnedInstance.GetComponent<CharacterMaster>();
				spawnedMaster.onBodyDestroyed += OnBodyDestroyed;
				GameObject bodyObject = spawnedMaster.GetBodyObject();
				if ((bool)bodyObject)
				{
					if ((bool)spawnEffectPrefab)
					{
						EffectData effectData = new EffectData
						{
							origin = bodyObject.transform.position,
							rotation = bodyObject.transform.rotation
						};
						EffectManager.SpawnEffect(spawnEffectPrefab, effectData, transmit: true);
					}
					NetworkedBodyAttachment component = bodyObject.GetComponent<NetworkedBodyAttachment>();
					if ((bool)component)
					{
						component.AttachToGameObjectAndSpawn(ownerBodyObject, ownerAttachChildName);
					}
				}
			}
			callback?.Invoke(this, spawnResult);
		}

		private void OnBodyDestroyed(CharacterBody body)
		{
			if (body.master.IsDeadAndOutOfLivesServer() && (bool)spawnedMaster)
			{
				spawnedMaster.onBodyDestroyed -= OnBodyDestroyed;
				spawnedMaster = null;
			}
		}
	}
	public class NetworkParent : NetworkBehaviour
	{
		[Serializable]
		private struct ParentIdentifier : IEquatable<ParentIdentifier>
		{
			public byte indexInParentChildLocatorPlusOne;

			public NetworkInstanceId parentNetworkInstanceId;

			public int indexInParentChildLocator
			{
				get
				{
					return indexInParentChildLocatorPlusOne - 1;
				}
				set
				{
					indexInParentChildLocatorPlusOne = (byte)(value + 1);
				}
			}

			private static ChildLocator LookUpChildLocator(Transform rootObject)
			{
				ModelLocator component = rootObject.GetComponent<ModelLocator>();
				if (!component)
				{
					return null;
				}
				Transform modelTransform = component.modelTransform;
				if (!modelTransform)
				{
					return null;
				}
				return modelTransform.GetComponent<ChildLocator>();
			}

			public ParentIdentifier(Transform parent)
			{
				parentNetworkInstanceId = NetworkInstanceId.Invalid;
				indexInParentChildLocatorPlusOne = 0;
				if (!parent)
				{
					return;
				}
				NetworkIdentity componentInParent = parent.GetComponentInParent<NetworkIdentity>();
				if (!componentInParent)
				{
					UnityEngine.Debug.LogWarningFormat("NetworkParent cannot accept a non-null parent without a NetworkIdentity! parent={0}", parent);
					return;
				}
				parentNetworkInstanceId = componentInParent.netId;
				if ((object)componentInParent.gameObject == parent.gameObject)
				{
					return;
				}
				ChildLocator childLocator = LookUpChildLocator(componentInParent.transform);
				if (!childLocator)
				{
					UnityEngine.Debug.LogWarningFormat("NetworkParent can only be parented directly to another object with a NetworkIdentity or an object registered in the ChildLocator of a a model of an object with a NetworkIdentity. parent={0}", parent);
					return;
				}
				indexInParentChildLocator = childLocator.FindChildIndex(parent);
				if (indexInParentChildLocatorPlusOne == 0)
				{
					UnityEngine.Debug.LogWarningFormat("NetworkParent parent={0} is not registered in a ChildLocator.", parent);
				}
			}

			public bool Equals(ParentIdentifier other)
			{
				if (indexInParentChildLocatorPlusOne == other.indexInParentChildLocatorPlusOne)
				{
					return parentNetworkInstanceId.Equals(other.parentNetworkInstanceId);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is ParentIdentifier other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (indexInParentChildLocatorPlusOne.GetHashCode() * 397) ^ parentNetworkInstanceId.GetHashCode();
			}

			public Transform Resolve()
			{
				GameObject gameObject = Util.FindNetworkObject(parentNetworkInstanceId);
				NetworkIdentity networkIdentity = (gameObject ? gameObject.GetComponent<NetworkIdentity>() : null);
				if (!networkIdentity)
				{
					return null;
				}
				if (indexInParentChildLocatorPlusOne == 0)
				{
					return networkIdentity.transform;
				}
				ChildLocator childLocator = LookUpChildLocator(networkIdentity.transform);
				if ((bool)childLocator)
				{
					return childLocator.FindChild(indexInParentChildLocator);
				}
				return null;
			}
		}

		private Transform cachedServerParentTransform;

		private new Transform transform;

		[SyncVar(hook = "SetParentIdentifier")]
		private ParentIdentifier parentIdentifier;

		public ParentIdentifier NetworkparentIdentifier
		{
			get
			{
				return parentIdentifier;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetParentIdentifier(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref parentIdentifier, 1u);
			}
		}

		private void Awake()
		{
			transform = base.transform;
		}

		public override void OnStartServer()
		{
			ServerUpdateParent();
		}

		private void OnTransformParentChanged()
		{
			if (NetworkServer.active)
			{
				ServerUpdateParent();
			}
			if ((bool)transform.parent)
			{
				transform.localPosition = UnityEngine.Vector3.zero;
				transform.localRotation = UnityEngine.Quaternion.identity;
				transform.localScale = UnityEngine.Vector3.one;
			}
		}

		[Server]
		private void ServerUpdateParent()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkParent::ServerUpdateParent()' called on client");
				return;
			}
			Transform transform = this.transform.parent;
			if ((object)transform != cachedServerParentTransform)
			{
				if (!transform)
				{
					transform = null;
				}
				cachedServerParentTransform = transform;
				SetParentIdentifier(new ParentIdentifier(transform));
			}
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			SetParentIdentifier(parentIdentifier);
		}

		private void SetParentIdentifier(ParentIdentifier newParentIdentifier)
		{
			NetworkparentIdentifier = newParentIdentifier;
			if (!NetworkServer.active)
			{
				transform.parent = parentIdentifier.Resolve();
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WriteParentIdentifier_NetworkParent(writer, parentIdentifier);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteParentIdentifier_NetworkParent(writer, parentIdentifier);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				parentIdentifier = GeneratedNetworkCode._ReadParentIdentifier_NetworkParent(reader);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetParentIdentifier(GeneratedNetworkCode._ReadParentIdentifier_NetworkParent(reader));
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[DefaultExecutionOrder(-1)]
	public class NetworkRuleBook : NetworkBehaviour
	{
		private const uint ruleBookDirtyBit = 1u;

		public RuleBook ruleBook { get; private set; }

		public event Action<NetworkRuleBook> onRuleBookUpdated;

		private void Awake()
		{
			ruleBook = new RuleBook();
		}

		[Server]
		public void SetRuleBook([NotNull] RuleBook newRuleBook)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkRuleBook::SetRuleBook(RoR2.RuleBook)' called on client");
			}
			else if (!ruleBook.Equals(newRuleBook))
			{
				SetDirtyBit(1u);
				ruleBook.Copy(newRuleBook);
				this.onRuleBookUpdated?.Invoke(this);
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 1u;
			}
			bool num2 = (num & 1) != 0;
			writer.Write((byte)num);
			if (num2)
			{
				writer.Write(ruleBook);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (((uint)reader.ReadByte() & (true ? 1u : 0u)) != 0)
			{
				reader.ReadRuleBook(ruleBook);
				try
				{
					this.onRuleBookUpdated?.Invoke(this);
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[DefaultExecutionOrder(-1)]
	public class NetworkRuleChoiceMask : NetworkBehaviour
	{
		private const uint maskDirtyBit = 1u;

		public RuleChoiceMask ruleChoiceMask { get; private set; }

		private void Awake()
		{
			ruleChoiceMask = new RuleChoiceMask();
		}

		[Server]
		public void SetRuleChoiceMask([NotNull] RuleChoiceMask newRuleChoiceMask)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkRuleChoiceMask::SetRuleChoiceMask(RoR2.RuleChoiceMask)' called on client");
			}
			else if (!ruleChoiceMask.Equals(newRuleChoiceMask))
			{
				SetDirtyBit(1u);
				ruleChoiceMask.Copy(newRuleChoiceMask);
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 1u;
			}
			bool num2 = (num & 1) != 0;
			writer.Write((byte)num);
			if (num2)
			{
				writer.Write(ruleChoiceMask);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (((uint)reader.ReadByte() & (true ? 1u : 0u)) != 0)
			{
				reader.ReadRuleChoiceMask(ruleChoiceMask);
			}
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class NetworkSession : NetworkBehaviour
	{
		[Flags]
		public enum Flags
		{
			None = 0,
			HasPassword = 1,
			IsDedicatedServer = 2
		}

		[SyncVar(hook = "OnSyncSteamId")]
		private ulong serverSteamId;

		[SyncVar]
		public ulong lobbySteamId;

		[SyncVar]
		private uint _flags;

		[SyncVar]
		public string tagsString;

		[SyncVar]
		public uint maxPlayers;

		[SyncVar]
		public string serverName;

		private TagManager serverManager;

		private static readonly BoolConVar cvSteamLobbyAllowPersistence = new BoolConVar("steam_lobby_allow_persistence", ConVarFlags.None, "1", "Whether or not the application should attempt to reestablish an active game session's Steamworks lobby if it's been lost.");

		public static NetworkSession instance { get; private set; }

		public Flags flags
		{
			get
			{
				return (Flags)_flags;
			}
			set
			{
				Network_flags = (uint)value;
			}
		}

		public ulong NetworkserverSteamId
		{
			get
			{
				return serverSteamId;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncSteamId(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref serverSteamId, 1u);
			}
		}

		public ulong NetworklobbySteamId
		{
			get
			{
				return lobbySteamId;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref lobbySteamId, 2u);
			}
		}

		public uint Network_flags
		{
			get
			{
				return _flags;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _flags, 4u);
			}
		}

		public string NetworktagsString
		{
			get
			{
				return tagsString;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref tagsString, 8u);
			}
		}

		public uint NetworkmaxPlayers
		{
			get
			{
				return maxPlayers;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref maxPlayers, 16u);
			}
		}

		public string NetworkserverName
		{
			get
			{
				return serverName;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref serverName, 32u);
			}
		}

		private void SetFlag(Flags flag, bool flagEnabled)
		{
			if (flagEnabled)
			{
				flags |= flag;
			}
			else
			{
				flags &= ~flag;
			}
		}

		public bool HasFlag(Flags flag)
		{
			return (flags & flag) == flag;
		}

		public override void OnStartServer()
		{
			base.OnStartServer();
			SetFlag(Flags.IsDedicatedServer, flagEnabled: false);
			NetworkManagerSystem.SvPasswordConVar.instance.onValueChanged += UpdatePasswordFlag;
			UpdatePasswordFlag(NetworkManagerSystem.SvPasswordConVar.instance.value);
			RegisterTags();
			NetworkmaxPlayers = (uint)NetworkManagerSystem.SvMaxPlayersConVar.instance.intValue;
			NetworkManagerSystem.SvHostNameConVar.instance.onValueChanged += UpdateServerName;
			UpdateServerName(NetworkManagerSystem.SvHostNameConVar.instance.GetString());
		}

		private void RegisterTags()
		{
			if (PlatformSystems.ShouldUseEpicOnlineSystems)
			{
				serverManager = ServerManagerBase<EOSServerManager>.instance;
			}
			else
			{
				serverManager = ServerManagerBase<SteamworksServerManager>.instance;
				NetworkserverSteamId = NetworkManagerSystem.singleton.serverP2PId.ID;
			}
			if (serverManager != null)
			{
				TagManager tagManager = serverManager;
				tagManager.onTagsStringUpdated = (Action<string>)Delegate.Combine(tagManager.onTagsStringUpdated, new Action<string>(UpdateTagsString));
				UpdateTagsString(serverManager.tagsString ?? string.Empty);
			}
		}

		private void OnDestroy()
		{
			NetworkManagerSystem.SvHostNameConVar.instance.onValueChanged -= UpdateServerName;
			NetworkManagerSystem.SvPasswordConVar.instance.onValueChanged -= UpdatePasswordFlag;
			UnregisterTags();
		}

		private void UnregisterTags()
		{
			if (serverManager != null)
			{
				TagManager tagManager = serverManager;
				tagManager.onTagsStringUpdated = (Action<string>)Delegate.Remove(tagManager.onTagsStringUpdated, new Action<string>(UpdateTagsString));
			}
		}

		private void UpdateTagsString(string tagsString)
		{
			NetworktagsString = tagsString;
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			SteamworksAdvertiseGame();
		}

		private void UpdatePasswordFlag(string password)
		{
			SetFlag(Flags.HasPassword, !string.IsNullOrEmpty(password));
		}

		private void OnSyncSteamId(ulong newValue)
		{
			NetworkserverSteamId = newValue;
			SteamworksAdvertiseGame();
		}

		private void SteamworksAdvertiseGame()
		{
			if (RoR2Application.instance.steamworksClient != null)
			{
				ulong num = serverSteamId;
				uint num2 = 0u;
				ushort num3 = 0;
				CallMethod(GetField(GetField(Client.Instance, "native"), "user"), "AdvertiseGame", new object[3] { num, num2, num3 });
			}
			static void CallMethod(object obj, string methodName, object[] args)
			{
				obj.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic).Invoke(obj, args);
			}
			static object GetField(object obj, string fieldName)
			{
				return obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void Start()
		{
			UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
			if (NetworkServer.active)
			{
				NetworkServer.Spawn(base.gameObject);
			}
			StartCoroutine(SteamworksLobbyPersistenceCoroutine());
		}

		private void UpdateServerName(string newHostName)
		{
			NetworkserverName = newHostName;
		}

		[Server]
		public Run BeginRun(Run runPrefabComponent, RuleBook ruleBook, ulong seed)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.Run RoR2.NetworkSession::BeginRun(RoR2.Run,RoR2.RuleBook,System.UInt64)' called on client");
				return null;
			}
			if (!Run.instance)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(runPrefabComponent.gameObject);
				Run component = gameObject.GetComponent<Run>();
				component.SetRuleBook(ruleBook);
				component.seed = seed;
				NetworkServer.Spawn(gameObject);
				{
					foreach (ExpansionDef expansionDef in ExpansionCatalog.expansionDefs)
					{
						if (component.IsExpansionEnabled(expansionDef) && (bool)expansionDef.runBehaviorPrefab)
						{
							NetworkServer.Spawn(UnityEngine.Object.Instantiate(expansionDef.runBehaviorPrefab, gameObject.transform));
						}
					}
					return component;
				}
			}
			return null;
		}

		[Server]
		public void EndRun()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkSession::EndRun()' called on client");
			}
			else if ((bool)Run.instance)
			{
				UnityEngine.Object.Destroy(Run.instance.gameObject);
			}
		}

		private IEnumerator SteamworksLobbyPersistenceCoroutine()
		{
			while (true)
			{
				UpdateSteamworksLobbyPersistence();
				yield return new WaitForSecondsRealtime(4f);
			}
		}

		private void UpdateSteamworksLobbyPersistence()
		{
			if (Client.Instance == null || !cvSteamLobbyAllowPersistence.value || NetworkServer.dontListen || PlatformSystems.lobbyManager.awaitingJoin || PlatformSystems.lobbyManager.awaitingCreate)
			{
				return;
			}
			ulong currentLobby = Client.Instance.Lobby.CurrentLobby;
			if (NetworkServer.active)
			{
				if (PlatformSystems.lobbyManager.isInLobby)
				{
					NetworklobbySteamId = currentLobby;
				}
				else
				{
					PlatformSystems.lobbyManager.CreateLobby();
				}
			}
			else if (lobbySteamId != 0L && lobbySteamId != currentLobby)
			{
				PlatformSystems.lobbyManager.JoinLobby(new PlatformID(lobbySteamId));
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt64(serverSteamId);
				writer.WritePackedUInt64(lobbySteamId);
				writer.WritePackedUInt32(_flags);
				writer.Write(tagsString);
				writer.WritePackedUInt32(maxPlayers);
				writer.Write(serverName);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt64(serverSteamId);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt64(lobbySteamId);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(_flags);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(tagsString);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(maxPlayers);
			}
			if ((base.syncVarDirtyBits & 0x20u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(serverName);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				serverSteamId = reader.ReadPackedUInt64();
				lobbySteamId = reader.ReadPackedUInt64();
				_flags = reader.ReadPackedUInt32();
				tagsString = reader.ReadString();
				maxPlayers = reader.ReadPackedUInt32();
				serverName = reader.ReadString();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncSteamId(reader.ReadPackedUInt64());
			}
			if (((uint)num & 2u) != 0)
			{
				lobbySteamId = reader.ReadPackedUInt64();
			}
			if (((uint)num & 4u) != 0)
			{
				_flags = reader.ReadPackedUInt32();
			}
			if (((uint)num & 8u) != 0)
			{
				tagsString = reader.ReadString();
			}
			if (((uint)num & 0x10u) != 0)
			{
				maxPlayers = reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x20u) != 0)
			{
				serverName = reader.ReadString();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class NetworkSpawnOnStart : MonoBehaviour
	{
		private void Start()
		{
			if (NetworkServer.active)
			{
				NetworkServer.Spawn(base.gameObject);
			}
		}
	}
	[DisallowMultipleComponent]
	public class NetworkStateMachine : NetworkBehaviour
	{
		[SerializeField]
		[Tooltip("The sibling state machine components to network.")]
		private EntityStateMachine[] stateMachines = Array.Empty<EntityStateMachine>();

		private NetworkIdentity networkIdentity;

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			for (int i = 0; i < stateMachines.Length; i++)
			{
				EntityStateMachine obj = stateMachines[i];
				obj.networkIndex = i;
				obj.networker = this;
				obj.networkIdentity = networkIdentity;
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			if (initialState)
			{
				for (int i = 0; i < stateMachines.Length; i++)
				{
					EntityStateMachine entityStateMachine = stateMachines[i];
					writer.Write(EntityStateCatalog.GetStateIndex(entityStateMachine.state.GetType()));
					entityStateMachine.state.OnSerialize(writer);
				}
				return true;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (!initialState)
			{
				return;
			}
			for (int i = 0; i < stateMachines.Length; i++)
			{
				EntityStateMachine entityStateMachine = stateMachines[i];
				EntityStateIndex entityStateIndex = reader.ReadEntityStateIndex();
				if (base.hasAuthority)
				{
					continue;
				}
				EntityState entityState = EntityStateCatalog.InstantiateState(entityStateIndex);
				if (entityState != null)
				{
					entityState.outer = entityStateMachine;
					entityState.OnDeserialize(reader);
					if (!stateMachines[i])
					{
						UnityEngine.Debug.LogErrorFormat("State machine [{0}] on object {1} is not set! incoming state = {2}", i, base.gameObject, entityState.GetType());
					}
					entityStateMachine.SetNextState(entityState);
				}
			}
		}

		[NetworkMessageHandler(msgType = 48, client = true, server = true)]
		public static void HandleSetEntityState(NetworkMessage netMsg)
		{
			NetworkIdentity networkIdentity = netMsg.reader.ReadNetworkIdentity();
			byte b = netMsg.reader.ReadByte();
			EntityStateIndex entityStateIndex = netMsg.reader.ReadEntityStateIndex();
			if (networkIdentity == null)
			{
				return;
			}
			NetworkStateMachine component = networkIdentity.gameObject.GetComponent<NetworkStateMachine>();
			if (component == null || b >= component.stateMachines.Length)
			{
				return;
			}
			EntityStateMachine entityStateMachine = component.stateMachines[b];
			if (entityStateMachine == null)
			{
				return;
			}
			if (networkIdentity.isServer)
			{
				HashSet<NetworkInstanceId> clientOwnedObjects = netMsg.conn.clientOwnedObjects;
				if (clientOwnedObjects == null || !clientOwnedObjects.Contains(networkIdentity.netId))
				{
					return;
				}
			}
			else if (networkIdentity.hasAuthority)
			{
				return;
			}
			EntityState entityState = EntityStateCatalog.InstantiateState(entityStateIndex);
			if (entityState != null)
			{
				entityState.outer = entityStateMachine;
				entityState.OnDeserialize(netMsg.reader);
				entityStateMachine.SetState(entityState);
			}
		}

		public void SendSetEntityState(int stateMachineIndex)
		{
			if (NetworkServer.active || base.hasAuthority)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				EntityStateMachine entityStateMachine = stateMachines[stateMachineIndex];
				networkWriter.StartMessage(48);
				networkWriter.Write(networkIdentity);
				networkWriter.Write((byte)stateMachineIndex);
				networkWriter.Write(EntityStateCatalog.GetStateIndex(entityStateMachine.state.GetType()));
				entityStateMachine.state.OnSerialize(networkWriter);
				networkWriter.FinishMessage();
				if (NetworkServer.active)
				{
					NetworkServer.SendWriterToReady(base.gameObject, networkWriter, GetNetworkChannel());
				}
				else if (ClientScene.readyConnection != null)
				{
					ClientScene.readyConnection.SendWriter(networkWriter, GetNetworkChannel());
				}
			}
		}

		private void OnValidate()
		{
			for (int i = 0; i < stateMachines.Length; i++)
			{
				if (!stateMachines[i])
				{
					UnityEngine.Debug.LogErrorFormat("{0} has a blank entry for NetworkStateMachine!", base.gameObject);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class NetworkUIPromptController : NetworkBehaviour
	{
		private struct LocalUserInfo
		{
			public LocalUser localUser;

			public NetworkUIPromptController currentController;
		}

		private float lastCurrentLocalParticipantUpdateTime = float.NegativeInfinity;

		private LocalUser _currentLocalParticipant;

		private CharacterMaster _currentParticipantMaster;

		private bool _inControl;

		[SyncVar(hook = "SetParticipantMasterId")]
		private NetworkInstanceId masterObjectInstanceId;

		private CameraRigController _currentCamera;

		private static LocalUserInfo[] allLocalUserInfo = Array.Empty<LocalUserInfo>();

		private static int allLocalUserInfoCount = 0;

		public Action<NetworkReader> messageFromClientHandler;

		private LocalUser currentLocalParticipant
		{
			get
			{
				return _currentLocalParticipant;
			}
			set
			{
				if (_currentLocalParticipant != value)
				{
					if (_currentLocalParticipant != null)
					{
						OnLocalParticipantLost(_currentLocalParticipant);
					}
					_currentLocalParticipant = value;
					if (_currentLocalParticipant != null)
					{
						OnLocalParticipantDiscovered(_currentLocalParticipant);
					}
				}
			}
		}

		public CharacterMaster currentParticipantMaster
		{
			get
			{
				return _currentParticipantMaster;
			}
			private set
			{
				if ((object)_currentParticipantMaster != value)
				{
					if ((object)_currentParticipantMaster != null)
					{
						OnParticipantLost(_currentParticipantMaster);
					}
					_currentParticipantMaster = value;
					if ((object)_currentParticipantMaster != null)
					{
						OnParticipantDiscovered(_currentParticipantMaster);
					}
				}
			}
		}

		private bool inControl
		{
			get
			{
				return _inControl;
			}
			set
			{
				if (_inControl != value)
				{
					_inControl = value;
					if (_inControl)
					{
						OnControlBegin();
					}
					else
					{
						OnControlEnd();
					}
				}
			}
		}

		private CameraRigController currentCamera
		{
			get
			{
				return _currentCamera;
			}
			set
			{
				if ((object)_currentCamera != value)
				{
					if ((object)_currentCamera != null)
					{
						this.onDisplayEnd?.Invoke(this, currentLocalParticipant, _currentCamera);
					}
					_currentCamera = value;
					if ((object)_currentCamera != null)
					{
						this.onDisplayBegin?.Invoke(this, currentLocalParticipant, _currentCamera);
					}
				}
			}
		}

		public bool inUse => currentParticipantMaster;

		public bool isDisplaying => currentCamera;

		public NetworkInstanceId NetworkmasterObjectInstanceId
		{
			get
			{
				return masterObjectInstanceId;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetParticipantMasterId(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref masterObjectInstanceId, 1u);
			}
		}

		public event Action<NetworkUIPromptController, LocalUser, CameraRigController> onDisplayBegin;

		public event Action<NetworkUIPromptController, LocalUser, CameraRigController> onDisplayEnd;

		private void OnParticipantDiscovered([NotNull] CharacterMaster master)
		{
			LocalUser localUser = null;
			if ((bool)master.playerCharacterMasterController && (bool)master.playerCharacterMasterController.networkUser)
			{
				localUser = master.playerCharacterMasterController.networkUser.localUser;
			}
			currentLocalParticipant = localUser;
		}

		private void OnParticipantLost([NotNull] CharacterMaster master)
		{
			currentLocalParticipant = null;
		}

		private void OnLocalParticipantDiscovered([NotNull] LocalUser localUser)
		{
			lastCurrentLocalParticipantUpdateTime = Time.unscaledTime;
			UpdateBestControllerForLocalUser(localUser);
		}

		private void OnLocalParticipantLost([NotNull] LocalUser localUser)
		{
			ref LocalUserInfo localUserInfo = ref GetLocalUserInfo(localUser);
			if (localUserInfo.currentController == this)
			{
				localUserInfo.currentController.inControl = false;
				localUserInfo.currentController = null;
			}
		}

		private void HandleCameraDiscovered(CameraRigController cameraRigController)
		{
			currentCamera = cameraRigController;
		}

		private void HandleCameraLost(CameraRigController cameraRigController)
		{
			currentCamera = null;
		}

		private void OnControlBegin()
		{
			currentCamera = currentLocalParticipant.cameraRigController;
			currentLocalParticipant.onCameraDiscovered += HandleCameraDiscovered;
			currentLocalParticipant.onCameraLost += HandleCameraLost;
		}

		private void OnControlEnd()
		{
			currentLocalParticipant.onCameraLost -= HandleCameraLost;
			currentLocalParticipant.onCameraDiscovered -= HandleCameraDiscovered;
			currentCamera = null;
		}

		[CanBeNull]
		private static NetworkUIPromptController FindBestControllerForLocalUser([NotNull] LocalUser localUser)
		{
			NetworkUIPromptController result = null;
			float num = float.PositiveInfinity;
			List<NetworkUIPromptController> instancesList = InstanceTracker.GetInstancesList<NetworkUIPromptController>();
			for (int i = 0; i < instancesList.Count; i++)
			{
				NetworkUIPromptController networkUIPromptController = instancesList[i];
				if (networkUIPromptController.currentLocalParticipant == localUser && networkUIPromptController.lastCurrentLocalParticipantUpdateTime < num)
				{
					num = networkUIPromptController.lastCurrentLocalParticipantUpdateTime;
					result = networkUIPromptController;
				}
			}
			return result;
		}

		private static void UpdateBestControllerForLocalUser([NotNull] LocalUser localUser)
		{
			ref LocalUserInfo localUserInfo = ref GetLocalUserInfo(localUser);
			NetworkUIPromptController currentController = localUserInfo.currentController;
			NetworkUIPromptController networkUIPromptController = FindBestControllerForLocalUser(localUser);
			if ((object)currentController != networkUIPromptController)
			{
				if ((object)currentController != null)
				{
					currentController.inControl = false;
				}
				if ((object)networkUIPromptController != null)
				{
					networkUIPromptController.inControl = true;
				}
				localUserInfo.currentController = networkUIPromptController;
			}
		}

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

		private void OnDisable()
		{
			SetParticipantMasterId(NetworkInstanceId.Invalid);
			InstanceTracker.Remove(this);
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			if (!NetworkServer.active)
			{
				SetParticipantMasterId(masterObjectInstanceId);
			}
		}

		private void SetParticipantMasterId(NetworkInstanceId newMasterObjectInstanceId)
		{
			NetworkmasterObjectInstanceId = newMasterObjectInstanceId;
			GameObject gameObject = Util.FindNetworkObject(masterObjectInstanceId);
			CharacterMaster characterMaster = null;
			if ((bool)gameObject)
			{
				characterMaster = gameObject.GetComponent<CharacterMaster>();
			}
			currentParticipantMaster = characterMaster;
		}

		[Server]
		public void ClearParticipant()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::ClearParticipant()' called on client");
			}
			else
			{
				SetParticipantMaster(null);
			}
		}

		[Server]
		public void SetParticipantMaster([CanBeNull] CharacterMaster newParticipantMaster)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::SetParticipantMaster(RoR2.CharacterMaster)' called on client");
				return;
			}
			NetworkIdentity networkIdentity = (newParticipantMaster ? newParticipantMaster.networkIdentity : null);
			SetParticipantMasterId(networkIdentity ? networkIdentity.netId : NetworkInstanceId.Invalid);
		}

		[Server]
		public void SetParticipantMasterFromInteractor([CanBeNull] Interactor newParticipantInteractor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::SetParticipantMasterFromInteractor(RoR2.Interactor)' called on client");
				return;
			}
			CharacterMaster participantMaster = ((!newParticipantInteractor) ? null : newParticipantInteractor.GetComponent<CharacterBody>()?.master);
			SetParticipantMaster(participantMaster);
		}

		[Server]
		public void SetParticipantMasterFromInteractorObject([CanBeNull] UnityEngine.Object newParticipantInteractor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUIPromptController::SetParticipantMasterFromInteractorObject(UnityEngine.Object)' called on client");
			}
			else
			{
				SetParticipantMasterFromInteractor(newParticipantInteractor as Interactor);
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			LocalUserManager.onUserSignIn += OnUserSignIn;
			LocalUserManager.onUserSignOut += OnUserSignOut;
		}

		private static void OnUserSignIn(LocalUser localUser)
		{
			LocalUserInfo localUserInfo = default(LocalUserInfo);
			localUserInfo.localUser = localUser;
			localUserInfo.currentController = null;
			LocalUserInfo value = localUserInfo;
			ArrayUtils.ArrayAppend(ref allLocalUserInfo, ref allLocalUserInfoCount, in value);
		}

		private static void OnUserSignOut(LocalUser localUser)
		{
			for (int i = 0; i < allLocalUserInfoCount; i++)
			{
				if (allLocalUserInfo[i].localUser == localUser)
				{
					ArrayUtils.ArrayRemoveAt(allLocalUserInfo, ref allLocalUserInfoCount, i);
					break;
				}
			}
		}

		private static ref LocalUserInfo GetLocalUserInfo(LocalUser localUser)
		{
			for (int i = 0; i < allLocalUserInfoCount; i++)
			{
				if (allLocalUserInfo[i].localUser == localUser)
				{
					return ref allLocalUserInfo[i];
				}
			}
			throw new ArgumentException("localUser must be signed in");
		}

		[Client]
		public NetworkWriter BeginMessageToServer()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'UnityEngine.Networking.NetworkWriter RoR2.NetworkUIPromptController::BeginMessageToServer()' called on server");
				return null;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.StartMessage(76);
			networkWriter.Write(base.gameObject);
			return networkWriter;
		}

		[Client]
		public void FinishMessageToServer(NetworkWriter writer)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUIPromptController::FinishMessageToServer(UnityEngine.Networking.NetworkWriter)' called on server");
				return;
			}
			writer.FinishMessage();
			NetworkUser networkUser = FindParticipantNetworkUser(this);
			if ((bool)networkUser)
			{
				networkUser.connectionToServer.SendWriter(writer, GetNetworkChannel());
			}
		}

		private static NetworkUser FindParticipantNetworkUser(NetworkUIPromptController instance)
		{
			if ((bool)instance)
			{
				CharacterMaster characterMaster = instance.currentParticipantMaster;
				if ((bool)characterMaster)
				{
					PlayerCharacterMasterController playerCharacterMasterController = characterMaster.playerCharacterMasterController;
					if ((bool)playerCharacterMasterController)
					{
						return playerCharacterMasterController.networkUser;
					}
				}
			}
			return null;
		}

		[NetworkMessageHandler(client = false, server = true, msgType = 76)]
		private static void HandleNetworkUIPromptMessage(NetworkMessage netMsg)
		{
			GameObject gameObject = netMsg.reader.ReadGameObject();
			if (!gameObject)
			{
				return;
			}
			NetworkUIPromptController component = gameObject.GetComponent<NetworkUIPromptController>();
			if ((bool)component)
			{
				NetworkUser networkUser = FindParticipantNetworkUser(component);
				NetworkConnection networkConnection = (networkUser ? networkUser.connectionToClient : null);
				if (netMsg.conn == networkConnection)
				{
					component.messageFromClientHandler?.Invoke(netMsg.reader);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(masterObjectInstanceId);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(masterObjectInstanceId);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				masterObjectInstanceId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetParticipantMasterId(reader.ReadNetworkId());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(NetworkLoadout))]
	public class NetworkUser : NetworkBehaviour
	{
		public delegate void NetworkUserGenericDelegate(NetworkUser networkUser);

		private static readonly List<NetworkUser> instancesList;

		public static readonly ReadOnlyCollection<NetworkUser> readOnlyInstancesList;

		private static readonly List<NetworkUser> localPlayers;

		public static readonly ReadOnlyCollection<NetworkUser> readOnlyLocalPlayersList;

		[SyncVar(hook = "OnSyncId")]
		private NetworkUserId _id;

		[SyncVar]
		public byte rewiredPlayerId;

		[SyncVar(hook = "OnSyncMasterObjectId")]
		private NetworkInstanceId _masterObjectId;

		[CanBeNull]
		public LocalUser localUser;

		public CameraRigController cameraRigController;

		public string userName = "";

		[SyncVar]
		public Color32 userColor = UnityEngine.Color.red;

		[SyncVar]
		private uint netLunarCoins;

		[SyncVar]
		public ItemIndex rebirthItem = ItemIndex.None;

		private MemoizedGetComponent<CharacterMaster> cachedMaster;

		private MemoizedGetComponent<PlayerCharacterMasterController> cachedPlayerCharacterMasterController;

		private MemoizedGetComponent<PlayerStatsComponent> cachedPlayerStatsComponent;

		private GameObject _masterObject;

		[NonSerialized]
		[SyncVar(hook = "SetBodyPreference")]
		public BodyIndex bodyIndexPreference = BodyIndex.None;

		private float secondAccumulator;

		[NonSerialized]
		public List<UnlockableDef> unlockables = new List<UnlockableDef>();

		public List<string> debugUnlockablesList = new List<string>();

		private static NetworkInstanceId serverCurrentStage;

		private NetworkInstanceId _serverLastStageAcknowledgedByClient;

		private static int kRpcRpcDeductLunarCoins;

		private static int kCmdCmdAwardLunarCoins;

		private static int kCmdCmdStoreRebirthItems;

		private static int kRpcRpcStoreRebirthItems;

		private static int kCmdCmdSetRebirthItems;

		private static int kRpcRpcAwardLunarCoins;

		private static int kCmdCmdSetNetLunarCoins;

		private static int kCmdCmdSetBodyPreference;

		private static int kCmdCmdSendConsoleCommand;

		private static int kCmdCmdSendNewUnlockables;

		private static int kRpcRpcRequestUnlockables;

		private static int kCmdCmdReportAchievement;

		private static int kCmdCmdReportUnlock;

		private static int kCmdCmdAcknowledgeStage;

		private static int kCmdCmdSubmitVote;

		public NetworkLoadout networkLoadout { get; private set; }

		public NetworkUserId id
		{
			get
			{
				return _id;
			}
			set
			{
				if (!_id.Equals(value))
				{
					Network_id = value;
					UpdateUserName();
				}
			}
		}

		public bool authed => id.HasValidValue();

		public Player inputPlayer => localUser?.inputPlayer;

		public uint lunarCoins
		{
			get
			{
				if (localUser != null)
				{
					return localUser.userProfile.coins;
				}
				return netLunarCoins;
			}
		}

		public CharacterMaster master => cachedMaster.Get(masterObject);

		public PlayerCharacterMasterController masterController => cachedPlayerCharacterMasterController.Get(masterObject);

		public PlayerStatsComponent masterPlayerStatsComponent => cachedPlayerStatsComponent.Get(masterObject);

		public GameObject masterObject
		{
			get
			{
				if (!_masterObject)
				{
					_masterObject = Util.FindNetworkObject(_masterObjectId);
				}
				return _masterObject;
			}
			set
			{
				if ((bool)value)
				{
					Network_masterObjectId = value.GetComponent<NetworkIdentity>().netId;
					_masterObject = value;
				}
				else
				{
					Network_masterObjectId = NetworkInstanceId.Invalid;
					_masterObject = null;
				}
			}
		}

		public bool isParticipating => masterObject;

		public bool isSplitScreenExtraPlayer => id.subId != 0;

		public bool serverIsClientLoaded { get; private set; }

		private NetworkInstanceId serverLastStageAcknowledgedByClient
		{
			get
			{
				return _serverLastStageAcknowledgedByClient;
			}
			set
			{
				if (!(_serverLastStageAcknowledgedByClient == value))
				{
					_serverLastStageAcknowledgedByClient = value;
					if (serverCurrentStage == _serverLastStageAcknowledgedByClient)
					{
						serverIsClientLoaded = true;
						NetworkUser.onNetworkUserLoadedSceneServer?.Invoke(this);
					}
				}
			}
		}

		public NetworkUserId Network_id
		{
			get
			{
				return _id;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncId(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref _id, 1u);
			}
		}

		public byte NetworkrewiredPlayerId
		{
			get
			{
				return rewiredPlayerId;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref rewiredPlayerId, 2u);
			}
		}

		public NetworkInstanceId Network_masterObjectId
		{
			get
			{
				return _masterObjectId;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncMasterObjectId(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref _masterObjectId, 4u);
			}
		}

		public Color32 NetworkuserColor
		{
			get
			{
				return userColor;
			}
			[param: In]
			set
			{
				SetSyncVar<Color32>(value, ref userColor, 8u);
			}
		}

		public uint NetworknetLunarCoins
		{
			get
			{
				return netLunarCoins;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref netLunarCoins, 16u);
			}
		}

		public ItemIndex NetworkrebirthItem
		{
			get
			{
				return rebirthItem;
			}
			[param: In]
			set
			{
				ulong newValueAsUlong = (ulong)value;
				ulong fieldValueAsUlong = (ulong)rebirthItem;
				SetSyncVarEnum(value, newValueAsUlong, ref rebirthItem, fieldValueAsUlong, 32u);
			}
		}

		public BodyIndex NetworkbodyIndexPreference
		{
			get
			{
				return bodyIndexPreference;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetBodyPreference(value);
					base.syncVarHookGuard = false;
				}
				ulong newValueAsUlong = (ulong)value;
				ulong fieldValueAsUlong = (ulong)bodyIndexPreference;
				SetSyncVarEnum(value, newValueAsUlong, ref bodyIndexPreference, fieldValueAsUlong, 64u);
			}
		}

		public static event Action<NetworkUser> onNetworkUserLoadedSceneServer;

		public static event Action<NetworkUser> onLoadoutChangedGlobal;

		[Obsolete("Use onPostNetworkUserStart instead", false)]
		public static event NetworkUserGenericDelegate OnPostNetworkUserStart
		{
			add
			{
				onPostNetworkUserStart += value;
			}
			remove
			{
				onPostNetworkUserStart -= value;
			}
		}

		public static event NetworkUserGenericDelegate onPostNetworkUserStart;

		[Obsolete("Use onNetworkUserUnlockablesUpdated instead", false)]
		public static event NetworkUserGenericDelegate OnNetworkUserUnlockablesUpdated
		{
			add
			{
				onNetworkUserUnlockablesUpdated += value;
			}
			remove
			{
				onNetworkUserUnlockablesUpdated -= value;
			}
		}

		public static event NetworkUserGenericDelegate onNetworkUserUnlockablesUpdated;

		public static event NetworkUserGenericDelegate onNetworkUserDiscovered;

		public static event NetworkUserGenericDelegate onNetworkUserLost;

		public static event NetworkUserGenericDelegate onNetworkUserBodyPreferenceChanged;

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
		private static void Init()
		{
			UserProfile.onUnlockableGranted += delegate(UserProfile userProfile, UnlockableDef unlockableDef)
			{
				if (NetworkClient.active)
				{
					NetworkUser networkUser3 = FindNetworkUserByUserProfile(userProfile);
					if ((bool)networkUser3)
					{
						networkUser3.SendServerUnlockables();
					}
				}
			};
			UserProfile.onLoadoutChangedGlobal += delegate(UserProfile userProfile)
			{
				if (NetworkClient.active)
				{
					NetworkUser networkUser2 = FindNetworkUserByUserProfile(userProfile);
					if ((bool)networkUser2)
					{
						networkUser2.PullLoadoutFromUserProfile();
					}
				}
			};
			UserProfile.onSurvivorPreferenceChangedGlobal += delegate(UserProfile userProfile)
			{
				if (NetworkClient.active)
				{
					NetworkUser networkUser = FindNetworkUserByUserProfile(userProfile);
					if ((bool)networkUser)
					{
						networkUser.SetSurvivorPreferenceClient(userProfile.GetSurvivorPreference());
					}
				}
			};
			Stage.onStageStartGlobal += delegate(Stage stage)
			{
				if (NetworkServer.active)
				{
					serverCurrentStage = stage.netId;
				}
				foreach (NetworkUser localPlayer in localPlayers)
				{
					localPlayer.CallCmdAcknowledgeStage(stage.netId);
				}
			};
		}

		private void OnEnable()
		{
			instancesList.Add(this);
			NetworkUser.onNetworkUserDiscovered?.Invoke(this);
		}

		private void OnDisable()
		{
			NetworkUser.onNetworkUserLost?.Invoke(this);
			instancesList.Remove(this);
		}

		private void Awake()
		{
			UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
			networkLoadout = GetComponent<NetworkLoadout>();
			networkLoadout.onLoadoutUpdated += OnLoadoutUpdated;
		}

		private void OnLoadoutUpdated()
		{
			NetworkUser.onLoadoutChangedGlobal?.Invoke(this);
		}

		private void PullLoadoutFromUserProfile()
		{
			UserProfile userProfile = localUser?.userProfile;
			if (userProfile != null)
			{
				Loadout loadout = Loadout.RequestInstance();
				userProfile.CopyLoadout(loadout);
				networkLoadout.SetLoadout(loadout);
				Loadout.ReturnInstance(loadout);
			}
		}

		private void Start()
		{
			if (base.isLocalPlayer)
			{
				LocalUserManager.FindLocalUser(base.playerControllerId)?.LinkNetworkUser(this);
				PullLoadoutFromUserProfile();
				if (!Run.instance || bodyIndexPreference == BodyIndex.None)
				{
					SetSurvivorPreferenceClient(localUser.userProfile.GetSurvivorPreference());
				}
			}
			if ((bool)Run.instance)
			{
				Run.instance.OnUserAdded(this);
			}
			if (NetworkClient.active)
			{
				SyncLunarCoinsToServer();
				SyncRebirthItemsToServer();
				SendServerUnlockables();
			}
			OnLoadoutUpdated();
			NetworkUser.onPostNetworkUserStart?.Invoke(this);
			if (base.isLocalPlayer && (bool)Stage.instance)
			{
				CallCmdAcknowledgeStage(Stage.instance.netId);
			}
		}

		private void OnDestroy()
		{
			localPlayers.Remove(this);
			Run.instance?.OnUserRemoved(this);
			RunCameraManager.instance?.OnUserRemoved(this);
			localUser?.UnlinkNetworkUser();
		}

		public void BumpDLCChecker()
		{
			NetworkUser.onPostNetworkUserStart(this);
		}

		public override void OnStartLocalPlayer()
		{
			base.OnStartLocalPlayer();
			if (!localPlayers.Contains(this))
			{
				localPlayers.Add(this);
			}
			else
			{
				UnityEngine.Debug.LogError("OnStartLocalPlayer Already has THIS local player!");
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine($"OnStartLocalPlayer LOCAL_PLAYERS COUNT {localPlayers.Count}:");
			foreach (NetworkUser localPlayer in localPlayers)
			{
				stringBuilder.AppendLine("\t" + localPlayer.id.strValue);
			}
		}

		public override void OnStartClient()
		{
			UpdateUserName();
		}

		private void OnSyncId(NetworkUserId newId)
		{
			id = newId;
		}

		private void OnSyncMasterObjectId(NetworkInstanceId newValue)
		{
			_masterObject = null;
			Network_masterObjectId = newValue;
		}

		public NetworkPlayerName GetNetworkPlayerName()
		{
			NetworkPlayerName result = default(NetworkPlayerName);
			result.nameOverride = ((id.strValue != null) ? id.strValue : null);
			result.playerId = ((!string.IsNullOrEmpty(id.strValue)) ? default(PlatformID) : new PlatformID(id.value));
			return result;
		}

		[Server]
		public void DeductLunarCoins(uint count)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::DeductLunarCoins(System.UInt32)' called on client");
				return;
			}
			NetworknetLunarCoins = HGMath.UintSafeSubtract(netLunarCoins, count);
			CallRpcDeductLunarCoins(count);
		}

		[ClientRpc]
		private void RpcDeductLunarCoins(uint count)
		{
			if (localUser != null)
			{
				localUser.userProfile.coins = HGMath.UintSafeSubtract(localUser.userProfile.coins, count);
				SyncLunarCoinsToServer();
			}
		}

		[Server]
		public void AwardLunarCoins(uint count)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::AwardLunarCoins(System.UInt32)' called on client");
				return;
			}
			NetworknetLunarCoins = HGMath.UintSafeAdd(netLunarCoins, count);
			CallRpcAwardLunarCoins(count);
		}

		[Command]
		public void CmdAwardLunarCoins(uint count)
		{
			AwardLunarCoins(count);
		}

		[Command]
		public void CmdStoreRebirthItems(ItemIndex item)
		{
			StoreRebirthItems(item);
		}

		[Server]
		private void StoreRebirthItems(ItemIndex item)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::StoreRebirthItems(RoR2.ItemIndex)' called on client");
				return;
			}
			NetworkrebirthItem = item;
			CallRpcStoreRebirthItems(item);
		}

		[ClientRpc]
		private void RpcStoreRebirthItems(ItemIndex item)
		{
			if (localUser != null)
			{
				localUser.userProfile.RebirthItem = PickupCatalog.GetPickupDef(PickupCatalog.FindPickupIndex(item))?.internalName;
				SyncRebirthItemsToServer();
			}
		}

		[Client]
		private void SyncRebirthItemsToServer()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SyncRebirthItemsToServer()' called on server");
			}
			else if (localUser != null)
			{
				UserProfile userProfile = localUser.userProfile;
				if (!string.IsNullOrEmpty(userProfile.RebirthItem))
				{
					CallCmdSetRebirthItems((userProfile.RebirthItem != null) ? PickupCatalog.GetPickupDef(PickupCatalog.FindPickupIndex(userProfile.RebirthItem)).itemIndex : ItemIndex.None);
				}
			}
		}

		[Command]
		private void CmdSetRebirthItems(ItemIndex item)
		{
			NetworkrebirthItem = item;
		}

		[ClientRpc]
		private void RpcAwardLunarCoins(uint count)
		{
			if (localUser != null)
			{
				_ = localUser.userProfile.name;
				localUser.userProfile.coins = HGMath.UintSafeAdd(localUser.userProfile.coins, count);
				localUser.userProfile.totalCollectedCoins = HGMath.UintSafeAdd(localUser.userProfile.totalCollectedCoins, count);
				SyncLunarCoinsToServer();
			}
		}

		[Client]
		private void SyncLunarCoinsToServer()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SyncLunarCoinsToServer()' called on server");
			}
			else if (localUser != null)
			{
				CallCmdSetNetLunarCoins(localUser.userProfile.coins);
			}
		}

		[Command]
		private void CmdSetNetLunarCoins(uint newNetLunarCoins)
		{
			NetworknetLunarCoins = newNetLunarCoins;
		}

		public CharacterBody GetCurrentBody()
		{
			CharacterMaster characterMaster = master;
			if ((bool)characterMaster)
			{
				return characterMaster.GetBody();
			}
			return null;
		}

		[Server]
		public void CopyLoadoutFromMaster()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::CopyLoadoutFromMaster()' called on client");
			}
			else
			{
				networkLoadout.SetLoadout(master.loadout);
			}
		}

		[Server]
		public void CopyLoadoutToMaster()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::CopyLoadoutToMaster()' called on client");
				return;
			}
			Loadout loadout = Loadout.RequestInstance();
			networkLoadout.CopyLoadout(loadout);
			master.SetLoadoutServer(loadout);
			Loadout.ReturnInstance(loadout);
		}

		private void SetBodyPreference(BodyIndex newBodyIndexPreference)
		{
			NetworkbodyIndexPreference = newBodyIndexPreference;
			NetworkUser.onNetworkUserBodyPreferenceChanged?.Invoke(this);
		}

		[Command]
		public void CmdSetBodyPreference(BodyIndex newBodyIndexPreference)
		{
			SetBodyPreference(newBodyIndexPreference);
		}

		[Client]
		public void SetSurvivorPreferenceClient(SurvivorDef survivorDef)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SetSurvivorPreferenceClient(RoR2.SurvivorDef)' called on server");
				return;
			}
			if (!survivorDef)
			{
				throw new ArgumentException("Provided object is null or invalid", "survivorDef");
			}
			BodyIndex bodyIndexFromSurvivorIndex = SurvivorCatalog.GetBodyIndexFromSurvivorIndex(survivorDef ? survivorDef.survivorIndex : SurvivorIndex.None);
			CallCmdSetBodyPreference(bodyIndexFromSurvivorIndex);
		}

		public SurvivorDef GetSurvivorPreference()
		{
			return SurvivorCatalog.GetSurvivorDef(SurvivorCatalog.GetSurvivorIndexFromBodyIndex(bodyIndexPreference));
		}

		private void Update()
		{
			if (localUser == null)
			{
				return;
			}
			if (Time.timeScale != 0f)
			{
				secondAccumulator += Time.unscaledDeltaTime;
			}
			if (!(secondAccumulator >= 1f))
			{
				return;
			}
			secondAccumulator -= 1f;
			if (!Run.instance)
			{
				return;
			}
			localUser.userProfile.totalRunSeconds++;
			if ((bool)masterObject)
			{
				CharacterMaster component = masterObject.GetComponent<CharacterMaster>();
				if ((bool)component && component.hasBody)
				{
					localUser.userProfile.totalAliveSeconds++;
				}
			}
		}

		public void UpdateUserName()
		{
			userName = GetNetworkPlayerName().GetResolvedName();
		}

		[Command]
		public void CmdSendConsoleCommand(string commandName, string[] args)
		{
			Console.instance.RunClientCmd(this, commandName, args);
		}

		[Client]
		public void SendServerUnlockables()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.NetworkUser::SendServerUnlockables()' called on server");
			}
			else if (localUser != null)
			{
				int unlockableCount = localUser.userProfile.statSheet.GetUnlockableCount();
				UnlockableIndex[] array = new UnlockableIndex[unlockableCount];
				for (int i = 0; i < unlockableCount; i++)
				{
					array[i] = localUser.userProfile.statSheet.GetUnlockableIndex(i);
				}
				CallCmdSendNewUnlockables(array);
			}
		}

		[Command]
		private void CmdSendNewUnlockables(UnlockableIndex[] newUnlockableIndices)
		{
			unlockables.Clear();
			debugUnlockablesList.Clear();
			int i = 0;
			for (int num = newUnlockableIndices.Length; i < num; i++)
			{
				UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(newUnlockableIndices[i]);
				if (unlockableDef != null)
				{
					unlockables.Add(unlockableDef);
					debugUnlockablesList.Add(unlockableDef.cachedName);
				}
			}
			NetworkUser.onNetworkUserUnlockablesUpdated?.Invoke(this);
		}

		[Server]
		public void ServerRequestUnlockables()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::ServerRequestUnlockables()' called on client");
			}
			else
			{
				CallRpcRequestUnlockables();
			}
		}

		[ClientRpc]
		private void RpcRequestUnlockables()
		{
			if (Util.HasEffectiveAuthority(base.gameObject))
			{
				SendServerUnlockables();
			}
		}

		[Command]
		public void CmdReportAchievement(string achievementNameToken)
		{
			Chat.SubjectFormatChatMessage subjectFormatChatMessage = new Chat.SubjectFormatChatMessage();
			subjectFormatChatMessage.baseToken = "ACHIEVEMENT_UNLOCKED_MESSAGE";
			subjectFormatChatMessage.subjectAsNetworkUser = this;
			subjectFormatChatMessage.paramTokens = new string[1] { achievementNameToken };
			Chat.SendBroadcastChat(subjectFormatChatMessage);
		}

		[Command]
		public void CmdReportUnlock(UnlockableIndex unlockIndex)
		{
			UnityEngine.Debug.LogFormat("NetworkUser.CmdReportUnlock({0})", unlockIndex);
			UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(unlockIndex);
			if (unlockableDef != null)
			{
				ServerHandleUnlock(unlockableDef);
			}
		}

		[Server]
		public void ServerHandleUnlock([NotNull] UnlockableDef unlockableDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::ServerHandleUnlock(RoR2.UnlockableDef)' called on client");
				return;
			}
			UnityEngine.Debug.LogFormat("NetworkUser.ServerHandleUnlock({0})", unlockableDef.cachedName);
			if ((bool)masterObject)
			{
				PlayerStatsComponent component = masterObject.GetComponent<PlayerStatsComponent>();
				if ((bool)component)
				{
					component.currentStats.AddUnlockable(unlockableDef);
					component.ForceNextTransmit();
				}
			}
		}

		[Server]
		public void ServerRemoveUnlock(UnlockableIndex index)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.NetworkUser::ServerRemoveUnlock(RoR2.UnlockableIndex)' called on client");
				return;
			}
			UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(index);
			UnityEngine.Debug.LogFormat("NetworkUser.ServerRemoveUnlock({0})", unlockableDef.cachedName);
			if ((bool)masterObject)
			{
				PlayerStatsComponent component = masterObject.GetComponent<PlayerStatsComponent>();
				if ((bool)component)
				{
					component.currentStats.RemoveUnlockable(index);
					component.ForceNextTransmit();
				}
			}
			(localUser?.userProfile)?.RevokeUnlockable(unlockableDef);
		}

		[Command]
		public void CmdAcknowledgeStage(NetworkInstanceId stageNetworkId)
		{
			serverLastStageAcknowledgedByClient = stageNetworkId;
		}

		[Command]
		public void CmdSubmitVote(GameObject voteControllerGameObject, int choiceIndex)
		{
			if ((bool)voteControllerGameObject)
			{
				VoteController component = voteControllerGameObject.GetComponent<VoteController>();
				if ((bool)component)
				{
					component.ReceiveUserVote(this, choiceIndex);
				}
			}
		}

		public static bool AllParticipatingNetworkUsersReady()
		{
			ReadOnlyCollection<NetworkUser> readOnlyCollection = readOnlyInstancesList;
			for (int i = 0; i < readOnlyCollection.Count; i++)
			{
				NetworkUser networkUser = readOnlyCollection[i];
				if (networkUser.isParticipating && !networkUser.connectionToClient.isReady)
				{
					return false;
				}
			}
			return true;
		}

		[CanBeNull]
		private static NetworkUser FindNetworkUserByUserProfile([NotNull] UserProfile userProfile)
		{
			if (userProfile == null)
			{
				throw new ArgumentNullException("userProfile");
			}
			ReadOnlyCollection<LocalUser> readOnlyLocalUsersList = LocalUserManager.readOnlyLocalUsersList;
			for (int i = 0; i < readOnlyLocalUsersList.Count; i++)
			{
				LocalUser localUser = readOnlyLocalUsersList[i];
				if (localUser.userProfile == userProfile)
				{
					return localUser.currentNetworkUser;
				}
			}
			return null;
		}

		static NetworkUser()
		{
			instancesList = new List<NetworkUser>();
			readOnlyInstancesList = new ReadOnlyCollection<NetworkUser>(instancesList);
			localPlayers = new List<NetworkUser>();
			readOnlyLocalPlayersList = new ReadOnlyCollection<NetworkUser>(localPlayers);
			kCmdCmdAwardLunarCoins = 654823536;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdAwardLunarCoins, InvokeCmdCmdAwardLunarCoins);
			kCmdCmdStoreRebirthItems = -2063320580;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdStoreRebirthItems, InvokeCmdCmdStoreRebirthItems);
			kCmdCmdSetRebirthItems = 1883408829;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSetRebirthItems, InvokeCmdCmdSetRebirthItems);
			kCmdCmdSetNetLunarCoins = -934763456;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSetNetLunarCoins, InvokeCmdCmdSetNetLunarCoins);
			kCmdCmdSetBodyPreference = 234442470;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSetBodyPreference, InvokeCmdCmdSetBodyPreference);
			kCmdCmdSendConsoleCommand = -1997680971;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSendConsoleCommand, InvokeCmdCmdSendConsoleCommand);
			kCmdCmdSendNewUnlockables = 1855027350;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSendNewUnlockables, InvokeCmdCmdSendNewUnlockables);
			kCmdCmdReportAchievement = -1674656990;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdReportAchievement, InvokeCmdCmdReportAchievement);
			kCmdCmdReportUnlock = -1831223439;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdReportUnlock, InvokeCmdCmdReportUnlock);
			kCmdCmdAcknowledgeStage = -2118585573;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdAcknowledgeStage, InvokeCmdCmdAcknowledgeStage);
			kCmdCmdSubmitVote = 329593659;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkUser), kCmdCmdSubmitVote, InvokeCmdCmdSubmitVote);
			kRpcRpcDeductLunarCoins = -1554352898;
			NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcDeductLunarCoins, InvokeRpcRpcDeductLunarCoins);
			kRpcRpcStoreRebirthItems = -669811482;
			NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcStoreRebirthItems, InvokeRpcRpcStoreRebirthItems);
			kRpcRpcAwardLunarCoins = -604060198;
			NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcAwardLunarCoins, InvokeRpcRpcAwardLunarCoins);
			kRpcRpcRequestUnlockables = -1809653515;
			NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkUser), kRpcRpcRequestUnlockables, InvokeRpcRpcRequestUnlockables);
			NetworkCRC.RegisterBehaviour("NetworkUser", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdAwardLunarCoins(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdAwardLunarCoins called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdAwardLunarCoins(reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeCmdCmdStoreRebirthItems(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdStoreRebirthItems called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdStoreRebirthItems((ItemIndex)reader.ReadInt32());
			}
		}

		protected static void InvokeCmdCmdSetRebirthItems(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetRebirthItems called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdSetRebirthItems((ItemIndex)reader.ReadInt32());
			}
		}

		protected static void InvokeCmdCmdSetNetLunarCoins(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetNetLunarCoins called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdSetNetLunarCoins(reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeCmdCmdSetBodyPreference(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetBodyPreference called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdSetBodyPreference((BodyIndex)reader.ReadInt32());
			}
		}

		protected static void InvokeCmdCmdSendConsoleCommand(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSendConsoleCommand called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdSendConsoleCommand(reader.ReadString(), GeneratedNetworkCode._ReadArrayString_None(reader));
			}
		}

		protected static void InvokeCmdCmdSendNewUnlockables(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSendNewUnlockables called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdSendNewUnlockables(GeneratedNetworkCode._ReadArrayUnlockableIndex_None(reader));
			}
		}

		protected static void InvokeCmdCmdReportAchievement(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdReportAchievement called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdReportAchievement(reader.ReadString());
			}
		}

		protected static void InvokeCmdCmdReportUnlock(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdReportUnlock called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdReportUnlock((UnlockableIndex)reader.ReadInt32());
			}
		}

		protected static void InvokeCmdCmdAcknowledgeStage(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdAcknowledgeStage called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdAcknowledgeStage(reader.ReadNetworkId());
			}
		}

		protected static void InvokeCmdCmdSubmitVote(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSubmitVote called on client.");
			}
			else
			{
				((NetworkUser)obj).CmdSubmitVote(reader.ReadGameObject(), (int)reader.ReadPackedUInt32());
			}
		}

		public void CallCmdAwardLunarCoins(uint count)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdAwardLunarCoins called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdAwardLunarCoins(count);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdAwardLunarCoins);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32(count);
			SendCommandInternal(networkWriter, 0, "CmdAwardLunarCoins");
		}

		public void CallCmdStoreRebirthItems(ItemIndex item)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdStoreRebirthItems called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdStoreRebirthItems(item);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdStoreRebirthItems);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)item);
			SendCommandInternal(networkWriter, 0, "CmdStoreRebirthItems");
		}

		public void CallCmdSetRebirthItems(ItemIndex item)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetRebirthItems called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetRebirthItems(item);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetRebirthItems);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)item);
			SendCommandInternal(networkWriter, 0, "CmdSetRebirthItems");
		}

		public void CallCmdSetNetLunarCoins(uint newNetLunarCoins)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetNetLunarCoins called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetNetLunarCoins(newNetLunarCoins);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetNetLunarCoins);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32(newNetLunarCoins);
			SendCommandInternal(networkWriter, 0, "CmdSetNetLunarCoins");
		}

		public void CallCmdSetBodyPreference(BodyIndex newBodyIndexPreference)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetBodyPreference called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetBodyPreference(newBodyIndexPreference);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetBodyPreference);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)newBodyIndexPreference);
			SendCommandInternal(networkWriter, 0, "CmdSetBodyPreference");
		}

		public void CallCmdSendConsoleCommand(string commandName, string[] args)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSendConsoleCommand called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSendConsoleCommand(commandName, args);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSendConsoleCommand);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(commandName);
			GeneratedNetworkCode._WriteArrayString_None(networkWriter, args);
			SendCommandInternal(networkWriter, 0, "CmdSendConsoleCommand");
		}

		public void CallCmdSendNewUnlockables(UnlockableIndex[] newUnlockableIndices)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSendNewUnlockables called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSendNewUnlockables(newUnlockableIndices);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSendNewUnlockables);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteArrayUnlockableIndex_None(networkWriter, newUnlockableIndices);
			SendCommandInternal(networkWriter, 0, "CmdSendNewUnlockables");
		}

		public void CallCmdReportAchievement(string achievementNameToken)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdReportAchievement called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdReportAchievement(achievementNameToken);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdReportAchievement);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(achievementNameToken);
			SendCommandInternal(networkWriter, 0, "CmdReportAchievement");
		}

		public void CallCmdReportUnlock(UnlockableIndex unlockIndex)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdReportUnlock called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdReportUnlock(unlockIndex);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdReportUnlock);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)unlockIndex);
			SendCommandInternal(networkWriter, 0, "CmdReportUnlock");
		}

		public void CallCmdAcknowledgeStage(NetworkInstanceId stageNetworkId)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdAcknowledgeStage called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdAcknowledgeStage(stageNetworkId);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdAcknowledgeStage);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(stageNetworkId);
			SendCommandInternal(networkWriter, 0, "CmdAcknowledgeStage");
		}

		public void CallCmdSubmitVote(GameObject voteControllerGameObject, int choiceIndex)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSubmitVote called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSubmitVote(voteControllerGameObject, choiceIndex);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSubmitVote);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(voteControllerGameObject);
			networkWriter.WritePackedUInt32((uint)choiceIndex);
			SendCommandInternal(networkWriter, 0, "CmdSubmitVote");
		}

		protected static void InvokeRpcRpcDeductLunarCoins(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcDeductLunarCoins called on server.");
			}
			else
			{
				((NetworkUser)obj).RpcDeductLunarCoins(reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeRpcRpcStoreRebirthItems(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcStoreRebirthItems called on server.");
			}
			else
			{
				((NetworkUser)obj).RpcStoreRebirthItems((ItemIndex)reader.ReadInt32());
			}
		}

		protected static void InvokeRpcRpcAwardLunarCoins(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcAwardLunarCoins called on server.");
			}
			else
			{
				((NetworkUser)obj).RpcAwardLunarCoins(reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeRpcRpcRequestUnlockables(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcRequestUnlockables called on server.");
			}
			else
			{
				((NetworkUser)obj).RpcRequestUnlockables();
			}
		}

		public void CallRpcDeductLunarCoins(uint count)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcDeductLunarCoins called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcDeductLunarCoins);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32(count);
			SendRPCInternal(networkWriter, 0, "RpcDeductLunarCoins");
		}

		public void CallRpcStoreRebirthItems(ItemIndex item)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcStoreRebirthItems called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcStoreRebirthItems);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write((int)item);
			SendRPCInternal(networkWriter, 0, "RpcStoreRebirthItems");
		}

		public void CallRpcAwardLunarCoins(uint count)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcAwardLunarCoins called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcAwardLunarCoins);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32(count);
			SendRPCInternal(networkWriter, 0, "RpcAwardLunarCoins");
		}

		public void CallRpcRequestUnlockables()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcRequestUnlockables called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcRequestUnlockables);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcRequestUnlockables");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WriteNetworkUserId_None(writer, _id);
				writer.WritePackedUInt32(rewiredPlayerId);
				writer.Write(_masterObjectId);
				writer.Write(userColor);
				writer.WritePackedUInt32(netLunarCoins);
				writer.Write((int)rebirthItem);
				writer.Write((int)bodyIndexPreference);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteNetworkUserId_None(writer, _id);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(rewiredPlayerId);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_masterObjectId);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(userColor);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(netLunarCoins);
			}
			if ((base.syncVarDirtyBits & 0x20u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write((int)rebirthItem);
			}
			if ((base.syncVarDirtyBits & 0x40u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write((int)bodyIndexPreference);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_id = GeneratedNetworkCode._ReadNetworkUserId_None(reader);
				rewiredPlayerId = (byte)reader.ReadPackedUInt32();
				_masterObjectId = reader.ReadNetworkId();
				userColor = reader.ReadColor32();
				netLunarCoins = reader.ReadPackedUInt32();
				rebirthItem = (ItemIndex)reader.ReadInt32();
				bodyIndexPreference = (BodyIndex)reader.ReadInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncId(GeneratedNetworkCode._ReadNetworkUserId_None(reader));
			}
			if (((uint)num & 2u) != 0)
			{
				rewiredPlayerId = (byte)reader.ReadPackedUInt32();
			}
			if (((uint)num & 4u) != 0)
			{
				OnSyncMasterObjectId(reader.ReadNetworkId());
			}
			if (((uint)num & 8u) != 0)
			{
				userColor = reader.ReadColor32();
			}
			if (((uint)num & 0x10u) != 0)
			{
				netLunarCoins = reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x20u) != 0)
			{
				rebirthItem = (ItemIndex)reader.ReadInt32();
			}
			if (((uint)num & 0x40u) != 0)
			{
				SetBodyPreference((BodyIndex)reader.ReadInt32());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[DisallowMultipleComponent]
	public class NonSolidToCamera : MonoBehaviour
	{
	}
	[ExecuteAlways]
	[RequireComponent(typeof(ParticleSystem))]
	public class NormalizeParticleScale : MonoBehaviour
	{
		public bool normalizeWithSkinnedMeshRendererInstead;

		[Tooltip("if the mesh scale is below this value, don't use the renderer to normalize our scale")]
		public float skinnedMeshRendererMinScale;

		private ParticleSystem particleSystem;

		public void OnEnable()
		{
			UpdateParticleSystem();
		}

		public void UpdateParticleSystem()
		{
			if (!particleSystem)
			{
				particleSystem = GetComponent<ParticleSystem>();
			}
			ParticleSystem.MainModule main = particleSystem.main;
			ParticleSystem.MinMaxCurve startSize = main.startSize;
			UnityEngine.Vector3 lossyScale = base.transform.lossyScale;
			float num = 1f;
			if (normalizeWithSkinnedMeshRendererInstead)
			{
				SkinnedMeshRenderer skinnedMeshRenderer = particleSystem.shape.skinnedMeshRenderer;
				if ((bool)skinnedMeshRenderer)
				{
					_ = skinnedMeshRenderer.transform.lossyScale;
					float num2 = Mathf.Max(lossyScale.x, lossyScale.y, lossyScale.z);
					if (num2 < skinnedMeshRendererMinScale)
					{
						num = num2;
					}
				}
			}
			else
			{
				num = Mathf.Max(lossyScale.x, lossyScale.y, lossyScale.z);
			}
			startSize.constantMin /= num;
			startSize.constantMax /= num;
			main.startSize = startSize;
		}
	}
	public class ObjectScaleCurve : MonoBehaviour
	{
		public bool useOverallCurveOnly;

		public bool resetOnAwake = true;

		public bool useUnscaledTime;

		public AnimationCurve curveX;

		public AnimationCurve curveY;

		public AnimationCurve curveZ;

		public AnimationCurve overallCurve;

		public float timeMax = 5f;

		public float time { get; set; }

		public UnityEngine.Vector3 baseScale { get; set; }

		private void Awake()
		{
			baseScale = base.transform.localScale;
			if (resetOnAwake)
			{
				Reset();
			}
		}

		private void OnEnable()
		{
			Reset();
		}

		public void Reset()
		{
			time = 0f;
			UpdateScale(0f);
		}

		private void Update()
		{
			time += (useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime);
			UpdateScale(time);
		}

		private void UpdateScale(float time)
		{
			float num = ((timeMax > 0f) ? Mathf.Clamp01(time / timeMax) : 0f);
			float num2 = 1f;
			if (overallCurve != null)
			{
				num2 = overallCurve.Evaluate(num);
			}
			UnityEngine.Vector3 vector;
			if (useOverallCurveOnly)
			{
				vector = baseScale * num2;
			}
			else
			{
				if (curveX == null || curveY == null || curveZ == null)
				{
					return;
				}
				vector = new UnityEngine.Vector3(curveX.Evaluate(num) * baseScale.x, curveY.Evaluate(num) * baseScale.y, curveZ.Evaluate(num) * baseScale.z);
			}
			base.transform.localScale = vector * num2;
		}
	}
	public class ObjectTransformCurve : MonoBehaviour
	{
		public bool useRotationCurves;

		public bool useTranslationCurves;

		public bool loop;

		public bool randomizeInitialTime;

		public AnimationCurve rotationCurveX;

		public AnimationCurve rotationCurveY;

		public AnimationCurve rotationCurveZ;

		public AnimationCurve translationCurveX;

		public AnimationCurve translationCurveY;

		public AnimationCurve translationCurveZ;

		public float timeMax = 5f;

		public float time { get; set; }

		public UnityEngine.Vector3 basePosition { get; private set; }

		public UnityEngine.Quaternion baseRotation { get; private set; }

		private void Awake()
		{
			basePosition = base.transform.localPosition;
			baseRotation = base.transform.localRotation;
			Reset();
		}

		private void OnEnable()
		{
			Reset();
		}

		public void Reset()
		{
			time = 0f;
			if (randomizeInitialTime)
			{
				time = UnityEngine.Random.Range(0f, timeMax);
			}
			UpdateTransform(time);
		}

		private void Update()
		{
			time += Time.deltaTime;
			if (loop && time > timeMax)
			{
				time %= timeMax;
			}
			UpdateTransform(time);
		}

		private void UpdateTransform(float time)
		{
			UnityEngine.Vector3 vector = basePosition;
			UnityEngine.Quaternion quaternion = baseRotation;
			float num = ((timeMax > 0f) ? Mathf.Clamp01(time / timeMax) : 0f);
			if (useRotationCurves)
			{
				if (rotationCurveX == null || rotationCurveY == null || rotationCurveZ == null)
				{
					return;
				}
				quaternion = UnityEngine.Quaternion.Euler(rotationCurveX.Evaluate(num), rotationCurveY.Evaluate(num), rotationCurveZ.Evaluate(num));
				base.transform.localRotation = quaternion;
			}
			if (useTranslationCurves && translationCurveX != null && translationCurveY != null && translationCurveZ != null)
			{
				vector = new UnityEngine.Vector3(translationCurveX.Evaluate(num), translationCurveY.Evaluate(num), translationCurveZ.Evaluate(num));
				base.transform.localPosition = vector;
			}
		}
	}
	public class OccupyNearbyNodes : MonoBehaviour
	{
		public float radius = 5f;

		private static readonly List<OccupyNearbyNodes> instancesList = new List<OccupyNearbyNodes>();

		private void OnDrawGizmos()
		{
			Gizmos.color = new UnityEngine.Color(1f, 1f, 0f, 0.3f);
			Gizmos.DrawWireSphere(base.transform.position, radius);
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			SceneDirector.onPrePopulateSceneServer += OnSceneDirectorPrePopulateSceneServer;
		}

		private static void OnSceneDirectorPrePopulateSceneServer(SceneDirector sceneDirector)
		{
			DirectorCore instance = DirectorCore.instance;
			NodeGraph groundNodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			NodeGraph.NodeIndex[] array = instancesList.SelectMany((OccupyNearbyNodes v) => groundNodeGraph.FindNodesInRange(v.transform.position, 0f, v.radius, HullMask.None)).Distinct().ToArray();
			foreach (NodeGraph.NodeIndex nodeIndex in array)
			{
				instance.AddOccupiedNode(groundNodeGraph, nodeIndex);
			}
		}
	}
	public class OmniEffect : MonoBehaviour
	{
		[Serializable]
		public class OmniEffectElement
		{
			public string name;

			public ParticleSystem particleSystem;

			public bool particleSystemEmitParticles;

			public Material particleSystemOverrideMaterial;

			public float maximumValidRadius = float.PositiveInfinity;

			public float bonusEmissionPerBonusRadius;

			public void ProcessEffectElement(float radius, float minimumValidRadius)
			{
				if (!particleSystem)
				{
					return;
				}
				if ((bool)particleSystemOverrideMaterial)
				{
					ParticleSystemRenderer component = particleSystem.GetComponent<ParticleSystemRenderer>();
					if ((bool)particleSystemOverrideMaterial)
					{
						component.material = particleSystemOverrideMaterial;
					}
				}
				ParticleSystem.EmissionModule emission = particleSystem.emission;
				if (emission.burstCount > 0)
				{
					int num = Mathf.Min(emission.GetBurst(0).maxCount + (int)((radius - minimumValidRadius) * bonusEmissionPerBonusRadius), particleSystem.main.maxParticles);
					emission.SetBurst(0, new ParticleSystem.Burst(0f, num));
				}
				if (particleSystemEmitParticles)
				{
					particleSystem.gameObject.SetActive(value: true);
				}
				else
				{
					particleSystem.gameObject.SetActive(value: false);
				}
			}
		}

		[Serializable]
		public class OmniEffectGroup
		{
			public string name;

			public OmniEffectElement[] omniEffectElements;
		}

		public OmniEffectGroup[] omniEffectGroups;

		private float radius;

		private void Start()
		{
			radius = base.transform.localScale.x;
			OmniEffectGroup[] array = omniEffectGroups;
			foreach (OmniEffectGroup omniEffectGroup in array)
			{
				float minimumValidRadius = 0f;
				for (int j = 0; j < omniEffectGroup.omniEffectElements.Length; j++)
				{
					OmniEffectElement omniEffectElement = omniEffectGroup.omniEffectElements[j];
					if (omniEffectElement.maximumValidRadius >= radius)
					{
						omniEffectElement.ProcessEffectElement(radius, minimumValidRadius);
						break;
					}
					minimumValidRadius = omniEffectElement.maximumValidRadius;
				}
			}
		}
	}
	public class OnCollisionEventController : NetworkBehaviour
	{
		[Serializable]
		public class OnCollisionEvent : UnityEvent
		{
		}

		[SerializeField]
		private float monsterCredits;

		[SerializeField]
		private CombatDirector director;

		[SerializeField]
		private bool shouldAccountForMultiplePlayers;

		public OnCollisionEvent onPlayerCollision;

		[SyncVar]
		public bool available = true;

		public bool Networkavailable
		{
			get
			{
				return available;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref available, 1u);
			}
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public void OnTriggerStay(Collider other)
		{
			if (NetworkServer.active && available && other.TryGetComponent<CharacterBody>(out var component) && component.isPlayerControlled)
			{
				int participatingPlayerCount = Run.instance.participatingPlayerCount;
				if (shouldAccountForMultiplePlayers)
				{
					monsterCredits *= participatingPlayerCount;
				}
				if ((bool)director)
				{
					director.SetMonsterCredit(monsterCredits);
				}
				onPlayerCollision.Invoke();
			}
		}

		[Server]
		public void SetAvailable(bool setActive)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OnCollisionEventController::SetAvailable(System.Boolean)' called on client");
			}
			else
			{
				Networkavailable = setActive;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(available);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(available);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				available = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				available = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class OnDestroyCallback : MonoBehaviour
	{
		private Action<OnDestroyCallback> callback;

		public void OnDestroy()
		{
			if (callback != null)
			{
				callback(this);
			}
		}

		public static OnDestroyCallback AddCallback(GameObject gameObject, Action<OnDestroyCallback> callback)
		{
			OnDestroyCallback onDestroyCallback = gameObject.AddComponent<OnDestroyCallback>();
			onDestroyCallback.callback = callback;
			return onDestroyCallback;
		}

		public static void RemoveCallback(OnDestroyCallback callbackComponent)
		{
			callbackComponent.callback = null;
			UnityEngine.Object.Destroy(callbackComponent);
		}
	}
	public class OnDisableEvent : MonoBehaviour
	{
		public UnityEvent action;

		private void OnDisable()
		{
			action?.Invoke();
		}
	}
	public class OnEnableEvent : MonoBehaviour
	{
		public UnityEvent action;

		private void OnEnable()
		{
			action?.Invoke();
		}
	}
	public class OnPlayerEnterEvent : MonoBehaviour
	{
		public bool serverOnly;

		public UnityEvent action;

		private bool calledAction;

		private void OnTriggerEnter(Collider other)
		{
			if ((!serverOnly || NetworkServer.active) && !calledAction)
			{
				CharacterBody component = other.GetComponent<CharacterBody>();
				if ((bool)component && component.isPlayerControlled)
				{
					UnityEngine.Debug.LogFormat("OnPlayerEnterEvent called on {0}", base.gameObject.name);
					calledAction = true;
					action?.Invoke();
				}
			}
		}
	}
	public class OptionChestBehavior : NetworkBehaviour, IChestBehavior
	{
		[SerializeField]
		private PickupDropTable dropTable;

		[SerializeField]
		private Transform dropTransform;

		[SerializeField]
		private float dropUpVelocityStrength = 20f;

		[SerializeField]
		private float dropForwardVelocityStrength = 2f;

		[SerializeField]
		private SerializableEntityStateType openState = new SerializableEntityStateType(typeof(EntityStates.Barrel.Opening));

		[SerializeField]
		private GameObject pickupPrefab;

		[SerializeField]
		private int numOptions;

		[SerializeField]
		private ItemTier displayTier;

		private PickupIndex[] generatedDrops;

		private Xoroshiro128Plus rng;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		[Server]
		public void Roll()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OptionChestBehavior::Roll()' called on client");
			}
			else
			{
				generatedDrops = dropTable.GenerateUniqueDrops(numOptions, rng);
			}
		}

		private void Awake()
		{
			if (dropTransform == null)
			{
				dropTransform = base.transform;
			}
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
				Roll();
			}
		}

		[Server]
		public void Open()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OptionChestBehavior::Open()' called on client");
				return;
			}
			EntityStateMachine component = GetComponent<EntityStateMachine>();
			if ((bool)component)
			{
				component.SetNextState(EntityStateCatalog.InstantiateState(ref openState));
			}
		}

		[Server]
		public void ItemDrop()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.OptionChestBehavior::ItemDrop()' called on client");
			}
			else if (generatedDrops != null && generatedDrops.Length != 0)
			{
				GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
				createPickupInfo.pickerOptions = PickupPickerController.GenerateOptionsFromArray(generatedDrops);
				createPickupInfo.prefabOverride = pickupPrefab;
				createPickupInfo.position = dropTransform.position;
				createPickupInfo.rotation = UnityEngine.Quaternion.identity;
				createPickupInfo.pickupIndex = PickupCatalog.FindPickupIndex(displayTier);
				GenericPickupController.CreatePickupInfo pickupInfo = createPickupInfo;
				PickupDropletController.CreatePickupDroplet(pickupInfo, pickupInfo.position, UnityEngine.Vector3.up * dropUpVelocityStrength + dropTransform.forward * dropForwardVelocityStrength);
				generatedDrops = null;
			}
		}

		public bool HasRolledPickup(PickupIndex pickupIndex)
		{
			if (generatedDrops != null)
			{
				PickupIndex[] array = generatedDrops;
				for (int i = 0; i < array.Length; i++)
				{
					if (array[i] == pickupIndex)
					{
						return true;
					}
				}
			}
			return false;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class OrbFireZone : MonoBehaviour
	{
		public float baseDamage;

		public float procCoefficient;

		public float orbRemoveFromBottomOfListFrequency;

		public float orbResetListFrequency;

		private List<Collider> previousColliderList = new List<Collider>();

		private float resetStopwatch;

		private float removeFromBottomOfListStopwatch;

		private void Awake()
		{
		}

		private void FixedUpdate()
		{
			if (previousColliderList.Count > 0)
			{
				resetStopwatch += Time.fixedDeltaTime;
				removeFromBottomOfListStopwatch += Time.fixedDeltaTime;
				if (removeFromBottomOfListStopwatch > 1f / orbRemoveFromBottomOfListFrequency)
				{
					removeFromBottomOfListStopwatch -= 1f / orbRemoveFromBottomOfListFrequency;
					previousColliderList.RemoveAt(previousColliderList.Count - 1);
				}
				if (resetStopwatch > 1f / orbResetListFrequency)
				{
					resetStopwatch -= 1f / orbResetListFrequency;
					previousColliderList.Clear();
				}
			}
		}

		private void OnTriggerStay(Collider other)
		{
			if (!NetworkServer.active || previousColliderList.Contains(other))
			{
				return;
			}
			previousColliderList.Add(other);
			CharacterBody component = other.GetComponent<CharacterBody>();
			if ((bool)component && (bool)component.mainHurtBox)
			{
				DamageOrb damageOrb = new DamageOrb();
				damageOrb.attacker = null;
				damageOrb.damageOrbType = DamageOrb.DamageOrbType.ClayGooOrb;
				damageOrb.procCoefficient = procCoefficient;
				damageOrb.damageValue = baseDamage * Run.instance.teamlessDamageCoefficient;
				damageOrb.target = component.mainHurtBox;
				damageOrb.teamIndex = TeamIndex.None;
				if (Physics.Raycast(damageOrb.target.transform.position + UnityEngine.Random.insideUnitSphere * 3f, UnityEngine.Vector3.down, out var hitInfo, 1000f, LayerIndex.world.mask))
				{
					damageOrb.origin = hitInfo.point;
					OrbManager.instance.AddOrb(damageOrb);
				}
			}
		}
	}
	public class OrbitalLaserController : MonoBehaviour
	{
		private abstract class OrbitalLaserBaseState : BaseState
		{
			protected OrbitalLaserController controller;

			public override void OnEnter()
			{
				base.OnEnter();
				controller = GetComponent<OrbitalLaserController>();
			}
		}

		private class OrbitalLaserChargeState : OrbitalLaserBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				controller.chargeEffect.SetActive(value: true);
				controller.maxSpeed = controller.chargeMaxVelocity;
			}

			public override void OnExit()
			{
				controller.chargeEffect.SetActive(value: false);
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= controller.chargeDuration)
				{
					outer.SetNextState(new OrbitalLaserFireState());
				}
			}
		}

		private class OrbitalLaserFireState : OrbitalLaserBaseState
		{
			private float bulletAttackTimer;

			public override void OnEnter()
			{
				base.OnEnter();
				controller.fireEffect.SetActive(value: true);
				controller.maxSpeed = controller.fireMaxVelocity;
			}

			public override void OnExit()
			{
				controller.fireEffect.SetActive(value: false);
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (!NetworkServer.active)
				{
					return;
				}
				if (base.fixedAge >= controller.fireDuration || !controller.ownerBody)
				{
					outer.SetNextState(new OrbitalLaserDecayState());
					return;
				}
				bulletAttackTimer -= GetDeltaTime();
				if ((bool)controller.ownerBody && bulletAttackTimer < 0f)
				{
					bulletAttackTimer += 1f / controller.fireFrequency;
					BulletAttack bulletAttack = new BulletAttack();
					bulletAttack.owner = controller.ownerBody.gameObject;
					bulletAttack.weapon = base.gameObject;
					bulletAttack.origin = base.transform.position + UnityEngine.Vector3.up * 600f;
					bulletAttack.maxDistance = 1200f;
					bulletAttack.aimVector = UnityEngine.Vector3.down;
					bulletAttack.minSpread = 0f;
					bulletAttack.maxSpread = 0f;
					bulletAttack.damage = Mathf.Lerp(controller.damageCoefficientInitial, controller.damageCoefficientFinal, base.fixedAge / controller.fireDuration) * controller.ownerBody.damage / controller.fireFrequency;
					bulletAttack.force = controller.force;
					bulletAttack.tracerEffectPrefab = controller.tracerEffectPrefab;
					bulletAttack.muzzleName = "";
					bulletAttack.hitEffectPrefab = controller.hitEffectPrefab;
					bulletAttack.isCrit = Util.CheckRoll(controller.ownerBody.crit, controller.ownerBody.master);
					bulletAttack.stopperMask = LayerIndex.world.mask;
					bulletAttack.damageColorIndex = DamageColorIndex.Item;
					bulletAttack.procCoefficient = controller.procCoefficient / controller.fireFrequency;
					bulletAttack.radius = 2f;
					bulletAttack.Fire();
				}
			}
		}

		private class OrbitalLaserDecayState : OrbitalLaserBaseState
		{
			public override void OnEnter()
			{
				base.OnEnter();
				controller.maxSpeed = 0f;
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= controller.decayDuration)
				{
					EntityState.Destroy(base.gameObject);
				}
			}
		}

		[NonSerialized]
		public CharacterBody ownerBody;

		private InputBankTest ownerInputBank;

		[Header("Movement Parameters")]
		public float smoothDampTime = 0.3f;

		private UnityEngine.Vector3 velocity;

		private float maxSpeed;

		[Header("Attack Parameters")]
		public float fireFrequency = 5f;

		public float damageCoefficientInitial = 6f;

		public float damageCoefficientFinal = 6f;

		public float procCoefficient = 0.5f;

		public float force;

		[Header("Charge")]
		public GameObject chargeEffect;

		public float chargeDuration = 3f;

		public float chargeMaxVelocity = 20f;

		private Transform chargeEffectTransform;

		[Header("Fire")]
		public GameObject fireEffect;

		public float fireDuration = 6f;

		public float fireMaxVelocity = 1f;

		public GameObject tracerEffectPrefab;

		public GameObject hitEffectPrefab;

		[Header("Decay")]
		public float decayDuration = 1.5f;

		[Header("Laser Pointer")]
		[Tooltip("The transform of the child laser pointer effect.")]
		public Transform laserPointerEffectTransform;

		[Tooltip("The transform of the muzzle effect.")]
		public Transform muzzleEffectTransform;

		private UnityEngine.Vector3 mostRecentPointerPosition;

		private UnityEngine.Vector3 mostRecentPointerNormal;

		private UnityEngine.Vector3 mostRecentMuzzlePosition;

		private void Start()
		{
			chargeEffect.SetActive(value: true);
			chargeEffect.GetComponent<ObjectScaleCurve>().timeMax = chargeDuration;
			mostRecentPointerPosition = base.transform.position;
			mostRecentPointerNormal = UnityEngine.Vector3.up;
		}

		private void UpdateLaserPointer()
		{
			if ((bool)ownerBody)
			{
				ownerInputBank = ownerBody.GetComponent<InputBankTest>();
				Ray ray = default(Ray);
				ray.origin = ownerInputBank.aimOrigin;
				ray.direction = ownerInputBank.aimDirection;
				Ray ray2 = ray;
				mostRecentMuzzlePosition = ray2.origin;
				float num = 900f;
				if (Physics.Raycast(ray2, out var hitInfo, num, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore))
				{
					mostRecentPointerPosition = hitInfo.point;
				}
				else
				{
					mostRecentPointerPosition = ray2.GetPoint(num);
				}
				mostRecentPointerNormal = -ray2.direction;
			}
		}

		private void Update()
		{
			UpdateLaserPointer();
			laserPointerEffectTransform.SetPositionAndRotation(mostRecentPointerPosition, UnityEngine.Quaternion.LookRotation(mostRecentPointerNormal));
			muzzleEffectTransform.SetPositionAndRotation(mostRecentMuzzlePosition, UnityEngine.Quaternion.identity);
		}

		private void FixedUpdate()
		{
			UpdateLaserPointer();
			if (NetworkServer.active)
			{
				base.transform.position = UnityEngine.Vector3.SmoothDamp(base.transform.position, mostRecentPointerPosition, ref velocity, smoothDampTime, maxSpeed, Time.fixedDeltaTime);
			}
		}
	}
	public class OutroCutsceneController : MonoBehaviour
	{
		public PlayableDirector playableDirector;

		private int finishCount;

		public static OutroCutsceneController instance { get; private set; }

		public bool cutsceneIsFinished { get; private set; }

		public void Finish()
		{
			finishCount++;
			if (finishCount >= 1)
			{
				cutsceneIsFinished = true;
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}
	}
	public class OutsideInteractableLocker : MonoBehaviour
	{
		private struct Candidate
		{
			public PurchaseInteraction purchaseInteraction;

			public float distanceSqr;
		}

		private class LockInfo
		{
			public GameObject lockObj;

			public float distSqr;

			public bool IsLocked()
			{
				return lockObj != null;
			}
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		private struct CandidateDistanceCompararer : IComparer<Candidate>
		{
			public int Compare(Candidate a, Candidate b)
			{
				return a.distanceSqr.CompareTo(b.distanceSqr);
			}
		}

		[Tooltip("The networked object which will be instantiated to lock purchasables.")]
		public GameObject lockPrefab;

		[Tooltip("How long to wait between steps.")]
		public float updateInterval = 0.1f;

		[Tooltip("Whether or not to invert the requirements.")]
		public bool lockInside;

		private Dictionary<PurchaseInteraction, GameObject> lockObjectMap;

		private Dictionary<LemurianEggController, LockInfo> eggLockInfoMap;

		private float updateTimer;

		private IEnumerator currentCoroutine;

		public float radius { get; set; }

		private void Awake()
		{
			if (NetworkServer.active)
			{
				lockObjectMap = new Dictionary<PurchaseInteraction, GameObject>();
				if (DevotionInventoryController.isDevotionEnable)
				{
					eggLockInfoMap = new Dictionary<LemurianEggController, LockInfo>();
				}
			}
			else
			{
				base.enabled = false;
			}
		}

		private void OnEnable()
		{
			if (NetworkServer.active)
			{
				currentCoroutine = ChestLockCoroutine();
				updateTimer = updateInterval;
			}
		}

		private void OnDisable()
		{
			if (NetworkServer.active)
			{
				currentCoroutine = null;
				UnlockAll();
			}
		}

		private void FixedUpdate()
		{
			updateTimer -= Time.fixedDeltaTime;
			if (updateTimer <= 0f)
			{
				updateTimer = updateInterval;
				currentCoroutine?.MoveNext();
			}
		}

		private void LockPurchasable(PurchaseInteraction purchaseInteraction)
		{
			if (!purchaseInteraction.lockGameObject)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(lockPrefab, purchaseInteraction.transform.position, UnityEngine.Quaternion.identity);
				NetworkServer.Spawn(gameObject);
				purchaseInteraction.NetworklockGameObject = gameObject;
				lockObjectMap.Add(purchaseInteraction, gameObject);
			}
		}

		private void UnlockPurchasable(PurchaseInteraction purchaseInteraction)
		{
			if (lockObjectMap.TryGetValue(purchaseInteraction, out var value) && !(value != purchaseInteraction.lockGameObject))
			{
				UnityEngine.Object.Destroy(value);
				lockObjectMap.Remove(purchaseInteraction);
			}
		}

		private void UnlockAll()
		{
			foreach (GameObject value in lockObjectMap.Values)
			{
				UnityEngine.Object.Destroy(value);
			}
			lockObjectMap.Clear();
			if (eggLockInfoMap == null)
			{
				return;
			}
			foreach (KeyValuePair<LemurianEggController, LockInfo> item in eggLockInfoMap)
			{
				UnlockLemurianEgg(item.Key);
			}
			eggLockInfoMap.Clear();
		}

		private void LockLemurianEgg(LemurianEggController egg)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(lockPrefab, egg.transform.position, UnityEngine.Quaternion.identity);
			NetworkServer.Spawn(gameObject);
			eggLockInfoMap[egg].lockObj = gameObject;
			egg.SetInteractability(interactable: false);
		}

		private void UnlockLemurianEgg(LemurianEggController egg)
		{
			LockInfo lockInfo = eggLockInfoMap[egg];
			if ((bool)lockInfo.lockObj)
			{
				NetworkServer.Destroy(lockInfo.lockObj);
				lockInfo.lockObj = null;
			}
			egg.SetInteractability(interactable: true);
		}

		private IEnumerator ChestLockCoroutine()
		{
			Candidate[] candidates = new Candidate[64];
			int candidatesCount = 0;
			if (DevotionInventoryController.isDevotionEnable)
			{
				foreach (LemurianEggController instances in InstanceTracker.GetInstancesList<LemurianEggController>())
				{
					LockInfo lockInfo = new LockInfo();
					lockInfo.lockObj = null;
					lockInfo.distSqr = (instances.transform.position - base.transform.position).sqrMagnitude;
					eggLockInfoMap[instances] = lockInfo;
				}
			}
			while (true)
			{
				UnityEngine.Vector3 position = base.transform.position;
				if (DevotionInventoryController.isDevotionEnable)
				{
					foreach (KeyValuePair<LemurianEggController, LockInfo> item in eggLockInfoMap)
					{
						float num = radius * radius;
						LockInfo value = item.Value;
						bool flag = value.distSqr <= num;
						value.IsLocked();
						if (flag != lockInside)
						{
							UnlockLemurianEgg(item.Key);
						}
						else
						{
							LockLemurianEgg(item.Key);
						}
					}
				}
				List<PurchaseInteraction> instancesList = InstanceTracker.GetInstancesList<PurchaseInteraction>();
				int num2 = candidatesCount;
				candidatesCount = instancesList.Count;
				ArrayUtils.EnsureCapacity(ref candidates, candidatesCount);
				for (int j = num2; j < candidatesCount; j++)
				{
					candidates[j] = default(Candidate);
				}
				for (int k = 0; k < candidatesCount; k++)
				{
					PurchaseInteraction purchaseInteraction = instancesList[k];
					candidates[k] = new Candidate
					{
						purchaseInteraction = purchaseInteraction,
						distanceSqr = (purchaseInteraction.transform.position - position).sqrMagnitude
					};
				}
				yield return null;
				Array.Sort(candidates, 0, candidatesCount, default(CandidateDistanceCompararer));
				yield return null;
				int i = 0;
				while (i < candidatesCount)
				{
					PurchaseInteraction purchaseInteraction2 = candidates[i].purchaseInteraction;
					if ((bool)purchaseInteraction2)
					{
						float num3 = radius * radius;
						if (candidates[i].distanceSqr <= num3 != lockInside || !purchaseInteraction2.available)
						{
							UnlockPurchasable(purchaseInteraction2);
						}
						else
						{
							LockPurchasable(purchaseInteraction2);
						}
						yield return null;
					}
					int num4 = i + 1;
					i = num4;
				}
				yield return null;
			}
		}
	}
	public class PaintDetailsBelow : MonoBehaviour
	{
		[Tooltip("Influence radius in world coordinates")]
		public float influenceOuter = 2f;

		public float influenceInner = 1f;

		[Tooltip("Which detail layer")]
		public int layer;

		[Tooltip("Density, from 0-1")]
		public float density = 0.5f;

		public float densityPower = 1f;

		private static List<PaintDetailsBelow> painterList;

		static PaintDetailsBelow()
		{
			painterList = new List<PaintDetailsBelow>();
		}

		public void OnEnable()
		{
			painterList.Add(this);
		}

		public void OnDisable()
		{
			painterList.Remove(this);
		}

		public static List<PaintDetailsBelow> GetPainters()
		{
			return painterList;
		}
	}
	public class PaintTerrain : MonoBehaviour
	{
		public float splatHeightReference = 60f;

		public float splatRaycastLength = 200f;

		public float splatSlopePower = 1f;

		public float heightPower = 1f;

		public UnityEngine.Vector3 snowfallDirection = UnityEngine.Vector3.up;

		public Texture2D grassNoiseMap;

		private Terrain terrain;

		private TerrainData data;

		private float[,,] alphamaps;

		private int[,] detailmapGrass;

		private void Start()
		{
			snowfallDirection = snowfallDirection.normalized;
			terrain = GetComponent<Terrain>();
			data = terrain.terrainData;
			alphamaps = data.GetAlphamaps(0, 0, data.alphamapWidth, data.alphamapHeight);
			detailmapGrass = data.GetDetailLayer(0, 0, data.detailWidth, data.detailHeight, 0);
			UpdateAlphaMaps();
			UpdateDetailMaps();
		}

		private void UpdateAlphaMaps()
		{
			for (int i = 0; i < data.alphamapHeight; i++)
			{
				for (int j = 0; j < data.alphamapWidth; j++)
				{
					float z = (float)j / (float)data.alphamapWidth * data.size.x;
					float x = (float)i / (float)data.alphamapHeight * data.size.z;
					float num = 0f;
					float num2 = 0f;
					float num3 = 0f;
					float num4 = 0f;
					float num5 = Mathf.Pow(UnityEngine.Vector3.Dot(UnityEngine.Vector3.up, data.GetInterpolatedNormal((float)i / (float)data.alphamapHeight, (float)j / (float)data.alphamapWidth)), splatSlopePower);
					num = num5;
					num3 = 1f - num5;
					float interpolatedHeight = data.GetInterpolatedHeight((float)i / (float)data.alphamapHeight, (float)j / (float)data.alphamapWidth);
					if (Physics.Raycast(new UnityEngine.Vector3(x, interpolatedHeight, z), snowfallDirection, out var hitInfo, splatRaycastLength, LayerIndex.world.mask))
					{
						float num6 = num;
						float num7 = Mathf.Clamp01(Mathf.Pow(hitInfo.distance / splatHeightReference, heightPower));
						num = num7 * num6;
						num2 = (1f - num7) * num6;
					}
					alphamaps[j, i, 0] = num;
					alphamaps[j, i, 1] = num2;
					alphamaps[j, i, 2] = num3;
					alphamaps[j, i, 3] = num4;
				}
			}
			data.SetAlphamaps(0, 0, alphamaps);
		}

		private void UpdateDetailMaps()
		{
			for (int i = 0; i < data.detailHeight; i++)
			{
				for (int j = 0; j < data.detailWidth; j++)
				{
					int num = 0;
					detailmapGrass[j, i] = num;
				}
			}
			data.SetDetailLayer(0, 0, 0, detailmapGrass);
		}
	}
	public class PaladinBarrierController : MonoBehaviour, IBarrier
	{
		public float blockLaserDamageCoefficient;

		public float blockLaserProcCoefficient;

		public float blockLaserDistance;

		private float totalDamageBlocked;

		private CharacterBody characterBody;

		private InputBankTest inputBank;

		private TeamComponent teamComponent;

		private bool barrierIsOn;

		public Transform barrierPivotTransform;

		public void BlockedDamage(DamageInfo damageInfo, float actualDamageBlocked)
		{
			totalDamageBlocked += actualDamageBlocked;
			LightningOrb lightningOrb = new LightningOrb();
			lightningOrb.teamIndex = teamComponent.teamIndex;
			lightningOrb.origin = damageInfo.position;
			lightningOrb.damageValue = actualDamageBlocked * blockLaserDamageCoefficient;
			lightningOrb.bouncesRemaining = 0;
			lightningOrb.attacker = damageInfo.attacker;
			lightningOrb.procCoefficient = blockLaserProcCoefficient;
			lightningOrb.lightningType = LightningOrb.LightningType.TreePoisonDart;
			HurtBox hurtBox = lightningOrb.PickNextTarget(lightningOrb.origin);
			if ((bool)hurtBox)
			{
				lightningOrb.target = hurtBox;
				lightningOrb.isCrit = Util.CheckRoll(characterBody.crit, characterBody.master);
				OrbManager.instance.AddOrb(lightningOrb);
			}
		}

		public void EnableBarrier()
		{
			barrierPivotTransform.gameObject.SetActive(value: true);
			barrierIsOn = true;
		}

		public void DisableBarrier()
		{
			barrierPivotTransform.gameObject.SetActive(value: false);
			barrierIsOn = false;
		}

		private void Start()
		{
			inputBank = GetComponent<InputBankTest>();
			characterBody = GetComponent<CharacterBody>();
			teamComponent = GetComponent<TeamComponent>();
			DisableBarrier();
		}

		private void Update()
		{
			if (barrierIsOn)
			{
				barrierPivotTransform.rotation = Util.QuaternionSafeLookRotation(inputBank.aimDirection);
			}
		}
	}
	public class ParticleBirthEvent : MonoBehaviour
	{
		public ParticleSystem particleSystemToTrack;

		public bool OnServerOnly;

		[Tooltip("Displays a message whenever a new particle is born")]
		public bool debugMessages;

		[Space(20f)]
		public UnityEvent onParticleBirth;

		private ParticleSystem.Particle[] particleArray;

		private void Awake()
		{
			if (particleSystemToTrack == null)
			{
				particleSystemToTrack = GetComponent<ParticleSystem>();
			}
			if (particleSystemToTrack != null)
			{
				particleArray = new ParticleSystem.Particle[particleSystemToTrack.main.maxParticles];
			}
		}

		private void LateUpdate()
		{
			if (particleSystemToTrack == null || (OnServerOnly && !NetworkServer.active))
			{
				base.enabled = false;
			}
			else
			{
				if (!particleSystemToTrack.isEmitting)
				{
					return;
				}
				int particles = particleSystemToTrack.GetParticles(particleArray);
				for (int i = 0; i < particles; i++)
				{
					ParticleSystem.Particle particle = particleArray[i];
					if (Mathf.Approximately(particle.startLifetime, particle.remainingLifetime))
					{
						FireEvent();
						break;
					}
				}
			}
		}

		private void FireEvent()
		{
			_ = debugMessages;
			onParticleBirth?.Invoke();
		}
	}
	public class ParticleDeathEvent : MonoBehaviour
	{
		public ParticleSystem particleSystemToTrack;

		public bool OnServerOnly;

		[Tooltip("Displays a message whenever a new particle is born")]
		public bool debugMessages;

		[Space(20f)]
		[Tooltip("The trigger will not fire if it's fired within this many seconds ago. Leave at -1 for 'fire every frame if need be.'")]
		public float triggerCooldown = -1f;

		[Space(20f)]
		public UnityEvent onParticleTrigger;

		private ParticleSystem.Particle[] particleArray;

		private float lastTriggerTimestamp;

		private float nextEventFireTimestamp = -1f;

		private void Awake()
		{
			if (particleSystemToTrack == null)
			{
				particleSystemToTrack = GetComponent<ParticleSystem>();
			}
			if (particleSystemToTrack != null)
			{
				particleArray = new ParticleSystem.Particle[particleSystemToTrack.main.maxParticles];
			}
		}

		private void LateUpdate()
		{
			if (particleSystemToTrack == null || (OnServerOnly && !NetworkServer.active))
			{
				base.enabled = false;
				return;
			}
			float time = Time.time;
			if (nextEventFireTimestamp > 0f && time > nextEventFireTimestamp)
			{
				HandleFireEvent(time);
			}
			if (particleSystemToTrack.isEmitting)
			{
				HandleEstimateNextParticleDeath(time);
			}
		}

		private void HandleEstimateNextParticleDeath(float currentTime)
		{
			int particles = particleSystemToTrack.GetParticles(particleArray);
			float num = ((nextEventFireTimestamp != -1f) ? (nextEventFireTimestamp - currentTime) : float.MaxValue);
			for (int i = 0; i < particles; i++)
			{
				float remainingLifetime = particleArray[i].remainingLifetime;
				if (remainingLifetime < num)
				{
					num = remainingLifetime;
				}
			}
			if (num != float.MaxValue)
			{
				nextEventFireTimestamp = currentTime + num;
			}
		}

		private void HandleFireEvent(float currentTime)
		{
			nextEventFireTimestamp = -1f;
			if (!(currentTime - lastTriggerTimestamp < triggerCooldown))
			{
				_ = debugMessages;
				lastTriggerTimestamp = currentTime;
				onParticleTrigger?.Invoke();
			}
		}
	}
	public class ParticleLifetimeSoundPlayer : MonoBehaviour
	{
		private class ParticleLifetimeTracker
		{
			private static int idCounter;

			public bool isActive;

			private bool firedStart;

			private bool firedEnd;

			private float lifetimeTimeStamp;

			private float startTimeTimeStamp;

			private float endTimeTimeStamp;

			private int localId;

			private AK.Wwise.Event startEvent;

			private AK.Wwise.Event endEvent;

			private GameObject soundObject;

			public ParticleLifetimeTracker(GameObject go)
			{
				soundObject = go;
			}

			public void Initialize(float currentTime, float lifeTime, float startTimeOffset, float endTimeOffset, ref AK.Wwise.Event _startEvent, ref AK.Wwise.Event _endEvent, bool debug)
			{
				localId = idCounter++;
				lifetimeTimeStamp = currentTime + lifeTime;
				startTimeTimeStamp = currentTime + startTimeOffset;
				endTimeTimeStamp = lifetimeTimeStamp + endTimeOffset;
				firedStart = false;
				firedEnd = false;
				isActive = true;
				startEvent = _startEvent;
				endEvent = _endEvent;
			}

			public void Update(float currentTime, bool debug)
			{
				if (isActive)
				{
					if (!firedStart && currentTime > startTimeTimeStamp)
					{
						firedStart = true;
						startEvent?.Post(soundObject);
					}
					if (!firedEnd && currentTime > endTimeTimeStamp)
					{
						firedEnd = true;
						endEvent?.Post(soundObject);
					}
					isActive = currentTime < lifetimeTimeStamp;
					_ = !isActive && debug;
				}
			}
		}

		public ParticleSystem particleSystemToTrack;

		[Tooltip("How long after a particle is born should the StartEvent be posted.")]
		public float startTimeOffset;

		[Tooltip("How long before/after a particle dies should the EndEvent be posted.")]
		public float endTimeOffset;

		[Tooltip("Displays a message whenever a new particle is born")]
		public bool debugMessages;

		public AK.Wwise.Event startEvent;

		public AK.Wwise.Event endEvent;

		[Tooltip("How long between particles should we wait before firing the next sound. -1 = no delay")]
		public float soundCooldown = -1f;

		private float lastParticleTrackedTimeStamp;

		private ParticleSystem.Particle[] particleArray;

		[Space(20f)]
		[SerializeField]
		public List<GameObject> soundObjects = new List<GameObject>();

		private List<ParticleLifetimeTracker> particleTrackers = new List<ParticleLifetimeTracker>();

		private void Awake()
		{
			if (particleSystemToTrack == null)
			{
				particleSystemToTrack = GetComponent<ParticleSystem>();
			}
			int count = soundObjects.Count;
			for (int i = 0; i < count; i++)
			{
				particleTrackers.Add(new ParticleLifetimeTracker(soundObjects[i]));
			}
			if (particleSystemToTrack != null)
			{
				particleArray = new ParticleSystem.Particle[particleSystemToTrack.main.maxParticles];
			}
		}

		private void LateUpdate()
		{
			if (particleSystemToTrack == null)
			{
				base.enabled = false;
				return;
			}
			float time = Time.time;
			UpdateExistingParticlePlayers(time);
			if (particleSystemToTrack.isEmitting && !(time - lastParticleTrackedTimeStamp < soundCooldown))
			{
				DiscoverAndTrackNewParticles(time);
			}
		}

		private void UpdateExistingParticlePlayers(float currentTime)
		{
			for (int i = 0; i < particleTrackers.Count; i++)
			{
				particleTrackers[i]?.Update(currentTime, debugMessages);
			}
		}

		private ParticleLifetimeTracker FindAvailableParticleTracker()
		{
			int count = particleTrackers.Count;
			for (int i = 0; i < count; i++)
			{
				if (!particleTrackers[i].isActive)
				{
					return particleTrackers[i];
				}
			}
			return null;
		}

		private void DiscoverAndTrackNewParticles(float currentTime)
		{
			ParticleLifetimeTracker particleLifetimeTracker = FindAvailableParticleTracker();
			if (particleLifetimeTracker == null)
			{
				return;
			}
			int particles = particleSystemToTrack.GetParticles(particleArray);
			for (int i = 0; i < particles; i++)
			{
				ParticleSystem.Particle particle = particleArray[i];
				if (Mathf.Approximately(particle.startLifetime, particle.remainingLifetime))
				{
					lastParticleTrackedTimeStamp = currentTime;
					particleLifetimeTracker.Initialize(currentTime, particle.remainingLifetime, startTimeOffset, endTimeOffset, ref startEvent, ref endEvent, debugMessages);
					break;
				}
			}
		}
	}
	[RequireComponent(typeof(EffectComponent))]
	public class ParticleSystemColorFromEffectData : MonoBehaviour
	{
		public ParticleSystem[] particleSystems;

		public EffectComponent effectComponent;

		private void Start()
		{
			UnityEngine.Color color = effectComponent.effectData.color;
			for (int i = 0; i < particleSystems.Length; i++)
			{
				ParticleSystem.MainModule main = particleSystems[i].main;
				main.startColor = color;
				particleSystems[i].Clear();
				particleSystems[i].Play();
			}
		}
	}
	public class ParticleSystemRandomColor : MonoBehaviour
	{
		public UnityEngine.Color[] colors;

		public ParticleSystem[] particleSystems;

		private void Awake()
		{
			if (colors.Length != 0)
			{
				UnityEngine.Color color = colors[UnityEngine.Random.Range(0, colors.Length)];
				for (int i = 0; i < particleSystems.Length; i++)
				{
					ParticleSystem.MainModule main = particleSystems[i].main;
					main.startColor = color;
				}
			}
		}

		[AssetCheck(typeof(ParticleSystemRandomColor))]
		private static void CheckParticleSystemRandomColor(AssetCheckArgs args)
		{
			ParticleSystemRandomColor particleSystemRandomColor = (ParticleSystemRandomColor)args.asset;
			for (int i = 0; i < particleSystemRandomColor.particleSystems.Length; i++)
			{
				if (!particleSystemRandomColor.particleSystems[i])
				{
					args.LogErrorFormat(args.asset, "Null particle system in slot {0}", i);
				}
			}
		}
	}
	public class ParticleTriggerEvent : MonoBehaviour
	{
		public ParticleSystem particleSystemToTrack;

		public bool OnServerOnly;

		public bool killParticleOnEventTrigger;

		[Tooltip("Displays a message whenever a new particle is born")]
		public bool debugMessages;

		[Space(20f)]
		public ParticleSystemTriggerEventType triggerType;

		[Tooltip("The trigger will not fire if it's fired within this many seconds ago. Leave at -1 for 'fire every frame if need be.'")]
		[Space(20f)]
		public float triggerCooldown = -1f;

		[Space(20f)]
		public UnityEvent onParticleTrigger;

		private List<ParticleSystem.Particle> particleList;

		private float lastTriggerTimestamp;

		private void Awake()
		{
			if (particleSystemToTrack == null)
			{
				particleSystemToTrack = GetComponent<ParticleSystem>();
			}
			if (particleSystemToTrack != null)
			{
				particleList = new List<ParticleSystem.Particle>(particleSystemToTrack.main.maxParticles);
			}
			if (particleSystemToTrack == null || (OnServerOnly && !NetworkServer.active))
			{
				base.enabled = false;
			}
		}

		private void OnParticleTrigger()
		{
			float time = Time.time;
			if (particleSystemToTrack.GetTriggerParticles(triggerType, particleList) > 0)
			{
				FireEvent(time);
				if (killParticleOnEventTrigger)
				{
					KillParticles(triggerType);
				}
			}
		}

		private void KillParticles(ParticleSystemTriggerEventType trigType)
		{
			int count = particleList.Count;
			for (int i = 0; i < count; i++)
			{
				ParticleSystem.Particle value = particleList[i];
				value.remainingLifetime = -1f;
				particleList[i] = value;
			}
			_ = debugMessages;
			particleSystemToTrack.SetTriggerParticles(trigType, particleList);
		}

		private void FireEvent(float currentTime)
		{
			if (triggerCooldown == -1f || !(currentTime - lastTriggerTimestamp < triggerCooldown))
			{
				_ = debugMessages;
				lastTriggerTimestamp = currentTime;
				onParticleTrigger?.Invoke();
			}
		}
	}
	public class PhaseCounter : MonoBehaviour
	{
		private static PhaseCounter _instance;

		public static PhaseCounter instance => _instance;

		public int phase { get; private set; }

		private void OnEnable()
		{
			if (!_instance)
			{
				_instance = this;
			}
		}

		private void OnDisable()
		{
			if (_instance == this)
			{
				_instance = null;
			}
		}

		public void GoToNextPhase()
		{
			phase++;
			UnityEngine.Debug.LogFormat("Entering phase {0}", phase);
		}
	}
	public class PhasedInventorySetter : MonoBehaviour
	{
		[Serializable]
		public struct PhaseItems
		{
			public ItemCountPair[] itemCounts;
		}

		[SerializeField]
		private CharacterBody body;

		[SerializeField]
		private PhaseItems[] phases;

		private bool isPhaseDirty = true;

		private int phaseIndex;

		public bool AdvancePhase()
		{
			if (phaseIndex < phases.Length - 1)
			{
				phaseIndex++;
				isPhaseDirty = true;
				TryUpdateInventory();
				return true;
			}
			return false;
		}

		private void FixedUpdate()
		{
			TryUpdateInventory();
		}

		private void TryUpdateInventory()
		{
			if (NetworkServer.active && isPhaseDirty && phaseIndex < phases.Length && (bool)body && (bool)body.inventory)
			{
				ItemCountPair[] itemCounts = phases[phaseIndex].itemCounts;
				for (int i = 0; i < itemCounts.Length; i++)
				{
					ItemCountPair itemCountPair = itemCounts[i];
					int itemCount = body.inventory.GetItemCount(itemCountPair.itemDef);
					body.inventory.GiveItem(itemCountPair.itemDef, itemCountPair.count - itemCount);
				}
				isPhaseDirty = false;
			}
		}

		public int GetNumPhases()
		{
			return phases.Length;
		}

		public int GetItemCountForPhase(int phaseIndex, ItemDef itemDef)
		{
			if (phases.Length > phaseIndex)
			{
				ItemCountPair[] itemCounts = phases[phaseIndex].itemCounts;
				for (int i = 0; i < itemCounts.Length; i++)
				{
					ItemCountPair itemCountPair = itemCounts[i];
					if ((object)itemDef == itemCountPair.itemDef)
					{
						return itemCountPair.count;
					}
				}
			}
			return 0;
		}
	}
	public class PickRandomObjectOnAwake : MonoBehaviour
	{
		public GameObject[] ObjectsToSelect;

		private void Awake()
		{
			int num = UnityEngine.Random.Range(0, ObjectsToSelect.Length);
			for (int i = 0; i < ObjectsToSelect.Length; i++)
			{
				ObjectsToSelect[i].SetActive(i == num);
			}
		}
	}
	public class PickupDisplay : MonoBehaviour
	{
		[Tooltip("The vertical motion of the display model.")]
		public Wave verticalWave;

		public bool dontInstantiatePickupModel;

		[Tooltip("The speed in degrees/second at which the display model rotates about the y axis.")]
		public float spinSpeed = 75f;

		public GameObject tier1ParticleEffect;

		public GameObject tier2ParticleEffect;

		public GameObject tier3ParticleEffect;

		public GameObject equipmentParticleEffect;

		public GameObject lunarParticleEffect;

		public GameObject bossParticleEffect;

		public GameObject voidParticleEffect;

		[Tooltip("The particle system to tint.")]
		public ParticleSystem[] coloredParticleSystems;

		private PickupIndex pickupIndex = PickupIndex.none;

		private bool hidden;

		public Highlight highlight;

		private static readonly UnityEngine.Vector3 idealModelBox = UnityEngine.Vector3.one;

		private static readonly float idealVolume = idealModelBox.x * idealModelBox.y * idealModelBox.z;

		private GameObject modelObject;

		private GameObject modelPrefab;

		private float modelScale;

		private float localTime;

		private bool shouldUpdate = true;

		public Renderer modelRenderer { get; private set; }

		private UnityEngine.Vector3 localModelPivotPosition => UnityEngine.Vector3.up * verticalWave.Evaluate(localTime);

		public void SetPickupIndex(PickupIndex newPickupIndex, bool newHidden = false)
		{
			if (!(pickupIndex == newPickupIndex) || hidden != newHidden)
			{
				pickupIndex = newPickupIndex;
				hidden = newHidden;
				RebuildModel();
			}
		}

		private void DestroyModel()
		{
			if ((bool)modelObject)
			{
				UnityEngine.Object.Destroy(modelObject);
				modelObject = null;
				modelRenderer = null;
			}
		}

		public void RebuildModel(GameObject modelObjectOverride = null)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (modelObjectOverride != null)
			{
				modelObject = modelObjectOverride;
			}
			else
			{
				GameObject gameObject = null;
				if (pickupDef != null)
				{
					gameObject = (hidden ? PickupCatalog.GetHiddenPickupDisplayPrefab() : pickupDef.displayPrefab);
				}
				if (modelPrefab != gameObject)
				{
					DestroyModel();
					modelPrefab = gameObject;
					modelScale = base.transform.lossyScale.x;
					if (!dontInstantiatePickupModel && modelPrefab != null)
					{
						modelObject = UnityEngine.Object.Instantiate(modelPrefab);
						modelRenderer = modelObject.GetComponentInChildren<Renderer>();
						if ((bool)modelRenderer)
						{
							modelObject.transform.rotation = UnityEngine.Quaternion.identity;
							UnityEngine.Vector3 size = modelRenderer.bounds.size;
							float num = size.x * size.y * size.z;
							if (num <= float.Epsilon)
							{
								UnityEngine.Debug.LogError("PickupDisplay bounds are zero! This is not allowed!");
								num = 1f;
							}
							modelScale *= Mathf.Pow(idealVolume, 1f / 3f) / Mathf.Pow(num, 1f / 3f);
							if ((bool)highlight)
							{
								highlight.targetRenderer = modelRenderer;
								highlight.isOn = true;
								highlight.pickupIndex = pickupIndex;
								highlight.ResetHighlight();
							}
						}
						modelObject.transform.parent = base.transform;
						modelObject.transform.localPosition = localModelPivotPosition;
						modelObject.transform.localRotation = UnityEngine.Quaternion.identity;
						modelObject.transform.localScale = new UnityEngine.Vector3(modelScale, modelScale, modelScale);
					}
				}
			}
			if ((bool)tier1ParticleEffect)
			{
				tier1ParticleEffect.SetActive(value: false);
			}
			if ((bool)tier2ParticleEffect)
			{
				tier2ParticleEffect.SetActive(value: false);
			}
			if ((bool)tier3ParticleEffect)
			{
				tier3ParticleEffect.SetActive(value: false);
			}
			if ((bool)equipmentParticleEffect)
			{
				equipmentParticleEffect.SetActive(value: false);
			}
			if ((bool)lunarParticleEffect)
			{
				lunarParticleEffect.SetActive(value: false);
			}
			if ((bool)voidParticleEffect)
			{
				voidParticleEffect.SetActive(value: false);
			}
			ItemIndex itemIndex = pickupDef?.itemIndex ?? ItemIndex.None;
			EquipmentIndex equipmentIndex = pickupDef?.equipmentIndex ?? EquipmentIndex.None;
			if (itemIndex != ItemIndex.None)
			{
				switch (ItemCatalog.GetItemDef(itemIndex).tier)
				{
				case ItemTier.Tier1:
					if ((bool)tier1ParticleEffect)
					{
						tier1ParticleEffect.SetActive(value: true);
					}
					break;
				case ItemTier.Tier2:
					if ((bool)tier2ParticleEffect)
					{
						tier2ParticleEffect.SetActive(value: true);
					}
					break;
				case ItemTier.Tier3:
					if ((bool)tier3ParticleEffect)
					{
						tier3ParticleEffect.SetActive(value: true);
					}
					break;
				case ItemTier.VoidTier1:
				case ItemTier.VoidTier2:
				case ItemTier.VoidTier3:
				case ItemTier.VoidBoss:
					if ((bool)voidParticleEffect)
					{
						voidParticleEffect.SetActive(value: true);
					}
					break;
				}
			}
			else if (equipmentIndex != EquipmentIndex.None && (bool)equipmentParticleEffect)
			{
				equipmentParticleEffect.SetActive(value: true);
			}
			if ((bool)bossParticleEffect)
			{
				bossParticleEffect.SetActive(pickupDef?.isBoss ?? false);
			}
			if ((bool)lunarParticleEffect)
			{
				lunarParticleEffect.SetActive(pickupDef?.isLunar ?? false);
			}
			if ((bool)highlight)
			{
				highlight.isOn = true;
				highlight.pickupIndex = pickupIndex;
			}
			ParticleSystem[] array = coloredParticleSystems;
			foreach (ParticleSystem obj in array)
			{
				obj.gameObject.SetActive(modelPrefab != null);
				ParticleSystem.MainModule main = obj.main;
				main.startColor = pickupDef?.baseColor ?? PickupCatalog.invalidPickupColor;
			}
		}

		private void Start()
		{
			localTime = 0f;
		}

		private void OnBecameVisible()
		{
			shouldUpdate = true;
		}

		private void OnBecameInvisible()
		{
			shouldUpdate = false;
		}

		private void Update()
		{
			if (shouldUpdate)
			{
				localTime += Time.deltaTime;
				if ((bool)modelObject)
				{
					Transform obj = modelObject.transform;
					UnityEngine.Vector3 localEulerAngles = obj.localEulerAngles;
					localEulerAngles.y = spinSpeed * localTime;
					obj.localEulerAngles = localEulerAngles;
					obj.localPosition = localModelPivotPosition;
				}
			}
		}

		private void OnDrawGizmos()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			UnityEngine.Matrix4x4 matrix = Gizmos.matrix;
			Gizmos.matrix = UnityEngine.Matrix4x4.TRS(base.transform.position, base.transform.rotation, base.transform.lossyScale);
			Gizmos.DrawWireCube(UnityEngine.Vector3.zero, idealModelBox);
			Gizmos.matrix = matrix;
		}
	}
	public class PickupDropletController : NetworkBehaviour
	{
		[NonSerialized]
		[SyncVar]
		public PickupIndex pickupIndex = PickupIndex.none;

		private bool alive = true;

		private GenericPickupController.CreatePickupInfo createPickupInfo;

		private static GameObject commandCubePrefab;

		private static bool isCommandChest;

		private static GameObject pickupDropletPrefab;

		public PickupIndex NetworkpickupIndex
		{
			get
			{
				return pickupIndex;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref pickupIndex, 1u);
			}
		}

		public static void CreatePickupDroplet(PickupIndex pickupIndex, UnityEngine.Vector3 position, UnityEngine.Vector3 velocity)
		{
			GenericPickupController.CreatePickupInfo pickupInfo = default(GenericPickupController.CreatePickupInfo);
			pickupInfo.rotation = UnityEngine.Quaternion.identity;
			pickupInfo.pickupIndex = pickupIndex;
			pickupInfo.position = position;
			CreatePickupDroplet(pickupInfo, position, velocity);
		}

		public static void CreatePickupDroplet(GenericPickupController.CreatePickupInfo pickupInfo, UnityEngine.Vector3 position, UnityEngine.Vector3 velocity)
		{
			if (CommandArtifactManager.IsCommandArtifactEnabled)
			{
				pickupInfo.artifactFlag |= GenericPickupController.PickupArtifactFlag.COMMAND;
			}
			GameObject obj = UnityEngine.Object.Instantiate(pickupDropletPrefab, position, UnityEngine.Quaternion.identity);
			PickupDropletController component = obj.GetComponent<PickupDropletController>();
			if ((bool)component)
			{
				component.createPickupInfo = pickupInfo;
				component.NetworkpickupIndex = pickupInfo.pickupIndex;
			}
			Rigidbody component2 = obj.GetComponent<Rigidbody>();
			component2.velocity = velocity;
			component2.AddTorque(UnityEngine.Random.Range(150f, 120f) * UnityEngine.Random.onUnitSphere);
			NetworkServer.Spawn(obj);
		}

		[InitDuringStartup]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/PickupDroplet", delegate(GameObject operationResult)
			{
				pickupDropletPrefab = operationResult;
			});
		}

		public static void IfCommandChestSpawned(bool value, PickupIndex pickupIndex, UnityEngine.Vector3 position, UnityEngine.Vector3 velocity)
		{
			isCommandChest = value;
			commandCubePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/CommandCube");
			CreatePickupDroplet(pickupIndex, position, velocity);
		}

		public void OnCollisionEnter(Collision collision)
		{
			if (NetworkServer.active && alive)
			{
				alive = false;
				createPickupInfo.position = base.transform.position;
				CreatePickup();
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void Start()
		{
			GameObject gameObject = PickupCatalog.GetPickupDef(pickupIndex)?.dropletDisplayPrefab;
			if ((bool)gameObject)
			{
				UnityEngine.Object.Instantiate(gameObject, base.transform);
			}
		}

		private void CreatePickup()
		{
			if (createPickupInfo.artifactFlag.HasFlag(GenericPickupController.PickupArtifactFlag.COMMAND) && !createPickupInfo.artifactFlag.HasFlag(GenericPickupController.PickupArtifactFlag.DELUSION))
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(createPickupInfo.pickupIndex);
				if (pickupDef != null && (pickupDef.itemIndex != ItemIndex.None || pickupDef.equipmentIndex != EquipmentIndex.None || pickupDef.itemTier != ItemTier.NoTier))
				{
					CreateCommandCube();
					return;
				}
			}
			GenericPickupController.CreatePickup(in createPickupInfo);
		}

		private void CreateCommandCube()
		{
			GameObject obj = UnityEngine.Object.Instantiate(CommandArtifactManager.commandCubePrefab, createPickupInfo.position, createPickupInfo.rotation);
			obj.GetComponent<PickupIndexNetworker>().NetworkpickupIndex = createPickupInfo.pickupIndex;
			PickupPickerController component = obj.GetComponent<PickupPickerController>();
			component.SetOptionsFromPickupForCommandArtifact(createPickupInfo.pickupIndex);
			component.chestGeneratedFrom = createPickupInfo.chest;
			NetworkServer.Spawn(obj);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class PickupIndexNetworker : NetworkBehaviour
	{
		[SyncVar(hook = "SyncPickupIndex")]
		public PickupIndex pickupIndex;

		public PickupDisplay pickupDisplay;

		public PickupIndex NetworkpickupIndex
		{
			get
			{
				return pickupIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SyncPickupIndex(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref pickupIndex, 1u);
			}
		}

		private void SyncPickupIndex(PickupIndex newPickupIndex)
		{
			NetworkpickupIndex = newPickupIndex;
			UpdatePickupDisplay();
		}

		private void UpdatePickupDisplay()
		{
			if ((bool)pickupDisplay)
			{
				pickupDisplay.SetPickupIndex(pickupIndex);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SyncPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader));
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(NetworkUIPromptController))]
	public class PickupPickerController : NetworkBehaviour, IInteractable, IInspectable
	{
		public struct Option
		{
			public PickupIndex pickupIndex;

			public bool available;
		}

		[Serializable]
		public class PickupIndexUnityEvent : UnityEvent<int>
		{
		}

		public GameObject panelPrefab;

		public PickupIndexUnityEvent onPickupSelected;

		public GenericInteraction.InteractorUnityEvent onServerInteractionBegin;

		public float cutoffDistance;

		private bool available = true;

		public string contextString = "";

		public bool shouldProximityHighlight = true;

		public bool synchronizeItemSelectionAcrossNetwork;

		public bool isDelusionChoice;

		public bool isRebirthChoice;

		private Inventory delusionInventory;

		private bool delusionOptionsSet;

		private int delusionChoicePickupIndex;

		private NetworkUIPromptController networkUIPromptController;

		private const byte msgSubmit = 0;

		private const byte msgCancel = 1;

		private GameObject panelInstance;

		private PickupPickerPanel panelInstanceController;

		public ChestBehavior chestGeneratedFrom;

		private Option[] options = Array.Empty<Option>();

		private static readonly uint optionsDirtyBit;

		private static readonly uint availableDirtyBit;

		private static readonly uint allDirtyBits;

		private int numberOfPickUpsSelected;

		public bool multiOptionsAvailable;

		private static int GrabNumbers;

		private EventFunctions eventFunctions;

		private static int kRpcRpcHandlePickupSelected;

		private void Awake()
		{
			networkUIPromptController = GetComponent<NetworkUIPromptController>();
			if (NetworkClient.active)
			{
				networkUIPromptController.onDisplayBegin += OnDisplayBegin;
				networkUIPromptController.onDisplayEnd += OnDisplayEnd;
			}
			if (NetworkServer.active)
			{
				networkUIPromptController.messageFromClientHandler = HandleClientMessage;
			}
			eventFunctions = base.gameObject.GetComponent<EventFunctions>();
			if (GrabNumbers > 1)
			{
				multiOptionsAvailable = true;
			}
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		private void HandleClientMessage(NetworkReader reader)
		{
			switch (reader.ReadByte())
			{
			case 0:
			{
				int choiceIndex = reader.ReadInt32();
				HandlePickupSelected(choiceIndex);
				break;
			}
			case 1:
				networkUIPromptController.SetParticipantMaster(null);
				break;
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		private void FixedUpdateServer()
		{
			CharacterMaster currentParticipantMaster = networkUIPromptController.currentParticipantMaster;
			if ((bool)currentParticipantMaster)
			{
				CharacterBody body = currentParticipantMaster.GetBody();
				if (!body || (body.inputBank.aimOrigin - base.transform.position).sqrMagnitude > cutoffDistance * cutoffDistance)
				{
					networkUIPromptController.SetParticipantMaster(null);
				}
			}
		}

		private void OnPanelDestroyed(OnDestroyCallback onDestroyCallback)
		{
			NetworkWriter networkWriter = networkUIPromptController.BeginMessageToServer();
			networkWriter.Write((byte)1);
			networkUIPromptController.FinishMessageToServer(networkWriter);
		}

		private void OnDisplayBegin(NetworkUIPromptController networkUIPromptController, LocalUser localUser, CameraRigController cameraRigController)
		{
			panelInstance = UnityEngine.Object.Instantiate(panelPrefab, cameraRigController.hud.mainContainer.transform);
			panelInstanceController = panelInstance.GetComponent<PickupPickerPanel>();
			panelInstanceController.pickerController = this;
			panelInstanceController.SetPickupOptions(options);
			OnDestroyCallback.AddCallback(panelInstance, OnPanelDestroyed);
		}

		private void OnDisplayEnd(NetworkUIPromptController networkUIPromptController, LocalUser localUser, CameraRigController cameraRigController)
		{
			UnityEngine.Object.Destroy(panelInstance);
			panelInstance = null;
			panelInstanceController = null;
		}

		[Server]
		public void SetAvailable(bool newAvailable)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PickupPickerController::SetAvailable(System.Boolean)' called on client");
				return;
			}
			available = newAvailable;
			SetDirtyBit(availableDirtyBit);
		}

		public void SubmitChoice(int choiceIndex)
		{
			if (!NetworkServer.active)
			{
				NetworkWriter networkWriter = networkUIPromptController.BeginMessageToServer();
				networkWriter.Write((byte)0);
				networkWriter.Write(choiceIndex);
				networkUIPromptController.FinishMessageToServer(networkWriter);
			}
			else
			{
				HandlePickupSelected(choiceIndex);
			}
		}

		public bool IsChoiceAvailable(PickupIndex choice)
		{
			for (int i = 0; i < options.Length; i++)
			{
				ref Option reference = ref options[i];
				if (reference.pickupIndex == choice)
				{
					return reference.available;
				}
			}
			return false;
		}

		[Server]
		private void HandlePickupSelected(int choiceIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PickupPickerController::HandlePickupSelected(System.Int32)' called on client");
			}
			else
			{
				if ((uint)choiceIndex >= options.Length)
				{
					return;
				}
				ref Option reference = ref options[choiceIndex];
				if (reference.available)
				{
					onPickupSelected?.Invoke(reference.pickupIndex.value);
					if (synchronizeItemSelectionAcrossNetwork)
					{
						CallRpcHandlePickupSelected(choiceIndex);
					}
				}
			}
		}

		[ClientRpc]
		private void RpcHandlePickupSelected(int choiceIndex)
		{
			if ((uint)choiceIndex < options.Length)
			{
				ref Option reference = ref options[choiceIndex];
				if (reference.available)
				{
					reference.available = false;
				}
			}
		}

		[Server]
		public void SetOptionsServer(Option[] newOptions)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PickupPickerController::SetOptionsServer(RoR2.PickupPickerController/Option[])' called on client");
			}
			else
			{
				SetOptionsInternal(newOptions);
			}
		}

		private void SetOptionsInternal(Option[] newOptions)
		{
			Array.Resize(ref options, newOptions.Length);
			Array.Copy(newOptions, options, newOptions.Length);
			if ((bool)panelInstanceController)
			{
				panelInstanceController.SetPickupOptions(options);
			}
			if (NetworkServer.active)
			{
				SetDirtyBit(optionsDirtyBit);
			}
		}

		[Server]
		public void SetTestOptions()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PickupPickerController::SetTestOptions()' called on client");
				return;
			}
			SetOptionsServer((from itemIndex in ItemCatalog.allItems
				select ItemCatalog.GetItemDef(itemIndex) into itemDef
				where itemDef.tier == ItemTier.Tier2
				select itemDef).Select(delegate(ItemDef itemDef)
			{
				Option result = default(Option);
				result.pickupIndex = PickupCatalog.FindPickupIndex(itemDef.itemIndex);
				result.available = true;
				return result;
			}).ToArray());
		}

		public static Option[] GenerateOptionsFromDropTable(int numOptions, PickupDropTable dropTable, Xoroshiro128Plus rng)
		{
			PickupIndex[] array = dropTable.GenerateUniqueDrops(numOptions, rng);
			GrabNumbers = numOptions - 2;
			Option[] array2 = new Option[array.Length];
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i] = new Option
				{
					available = true,
					pickupIndex = array[i]
				};
			}
			return array2;
		}

		public static Option[] GenerateOptionsFromDropTablePlusForcedStorm(int numOptions, PickupDropTable dropTable, PickupDropTable stormDropTable, Xoroshiro128Plus rng)
		{
			PickupIndex[] array = stormDropTable.GenerateUniqueDrops(numOptions, rng);
			PickupIndex[] array2 = dropTable.GenerateUniqueDrops(numOptions, rng);
			int num = 0;
			int num2 = 0;
			Option[] array3 = new Option[numOptions];
			for (int i = 0; i < array3.Length; i++)
			{
				if (num <= num2 - 2)
				{
					array3[i] = new Option
					{
						available = true,
						pickupIndex = array[i]
					};
					num++;
				}
				else
				{
					array3[i] = new Option
					{
						available = true,
						pickupIndex = array2[i]
					};
					num2++;
				}
			}
			Shuffle(new System.Random(), array3);
			GrabNumbers = numOptions - 2;
			return array3;
		}

		private static void Shuffle<T>(System.Random rng, T[] array)
		{
			int num = array.Length;
			while (num > 1)
			{
				int num2 = rng.Next(num--);
				T val = array[num];
				array[num] = array[num2];
				array[num2] = val;
			}
		}

		private static Option[] GetOptionsFromPickupIndex(PickupIndex pickupIndex)
		{
			PickupIndex[] groupFromPickupIndex = PickupTransmutationManager.GetGroupFromPickupIndex(pickupIndex);
			if (groupFromPickupIndex == null)
			{
				return new Option[1]
				{
					new Option
					{
						available = true,
						pickupIndex = pickupIndex
					}
				};
			}
			Option[] array = new Option[groupFromPickupIndex.Length];
			for (int i = 0; i < groupFromPickupIndex.Length; i++)
			{
				PickupIndex pickupIndex2 = groupFromPickupIndex[i];
				array[i] = new Option
				{
					available = Run.instance.IsPickupAvailable(pickupIndex2),
					pickupIndex = pickupIndex2
				};
			}
			return array;
		}

		public static Option[] GenerateOptionsFromArray(PickupIndex[] drops)
		{
			Option[] array = new Option[drops.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new Option
				{
					available = true,
					pickupIndex = drops[i]
				};
			}
			return array;
		}

		[Server]
		public void SetOptionsFromPickupForCommandArtifact(PickupIndex pickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PickupPickerController::SetOptionsFromPickupForCommandArtifact(RoR2.PickupIndex)' called on client");
			}
			else
			{
				SetOptionsServer(GetOptionsFromPickupIndex(pickupIndex));
			}
		}

		[Server]
		public void CreatePickup(int intPickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PickupPickerController::CreatePickup(System.Int32)' called on client");
			}
			else
			{
				CreatePickup(new PickupIndex(intPickupIndex));
			}
		}

		[Server]
		public void CreatePickup(PickupIndex pickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PickupPickerController::CreatePickup(RoR2.PickupIndex)' called on client");
				return;
			}
			GenericPickupController.CreatePickupInfo createPickupInfo = default(GenericPickupController.CreatePickupInfo);
			createPickupInfo.rotation = UnityEngine.Quaternion.identity;
			createPickupInfo.position = base.transform.position;
			createPickupInfo.pickupIndex = pickupIndex;
			createPickupInfo.chest = chestGeneratedFrom;
			GenericPickupController.CreatePickupInfo createPickupInfo2 = createPickupInfo;
			GenericPickupController.CreatePickup(in createPickupInfo2);
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = allDirtyBits;
			}
			bool num2 = (num & optionsDirtyBit) != 0;
			writer.WritePackedUInt32(num);
			if (num2)
			{
				writer.WritePackedUInt32((uint)options.Length);
				for (int i = 0; i < options.Length; i++)
				{
					ref Option reference = ref options[i];
					writer.Write(reference.pickupIndex);
					writer.Write(reference.available);
				}
			}
			if ((num & availableDirtyBit) != 0)
			{
				writer.Write(available);
			}
			return num != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			uint num = reader.ReadPackedUInt32();
			if ((num & optionsDirtyBit) != 0)
			{
				Option[] array = new Option[reader.ReadPackedUInt32()];
				for (int i = 0; i < array.Length; i++)
				{
					ref Option reference = ref array[i];
					reference.pickupIndex = reader.ReadPickupIndex();
					reference.available = reader.ReadBoolean();
				}
				SetOptionsInternal(array);
			}
			if ((num & availableDirtyBit) != 0)
			{
				available = reader.ReadBoolean();
			}
		}

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextString);
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (networkUIPromptController.inUse)
			{
				return Interactability.ConditionsNotMet;
			}
			if (!available)
			{
				return Interactability.Disabled;
			}
			return Interactability.Available;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			if (base.enabled)
			{
				onServerInteractionBegin.Invoke(activator);
				networkUIPromptController.SetParticipantMasterFromInteractor(activator);
			}
		}

		public void SetDelusionOptionsFromInteractor(Interactor activator)
		{
			if (DelusionChestController.isDelusionEnable && TryGetComponent<DelusionChestController>(out var component))
			{
				if (component.IsDelusionChoiceReady)
				{
					component.GenerateDelusionPickupIndexes(activator);
					PickupIndex[] pickupIndexes = component.GetPickupIndexes(activator);
					Option[] array = new Option[pickupIndexes.Count()];
					for (int i = 0; i < pickupIndexes.Count(); i++)
					{
						array[i] = new Option
						{
							available = true,
							pickupIndex = pickupIndexes[i]
						};
					}
					SetOptionsServer(array);
				}
			}
			else
			{
				UnityEngine.Debug.LogError("delusion is not enable but set with pickup picker controller");
			}
		}

		public void SetOptionsFromInteractor(Interactor activator)
		{
			if (!activator)
			{
				return;
			}
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if (!component)
			{
				return;
			}
			Inventory inventory = component.inventory;
			if (!inventory)
			{
				return;
			}
			List<Option> list = new List<Option>();
			for (int i = 0; i < inventory.itemAcquisitionOrder.Count; i++)
			{
				ItemIndex itemIndex = inventory.itemAcquisitionOrder[i];
				ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
				ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(itemDef.tier);
				PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(itemIndex);
				if ((!itemTierDef || itemTierDef.canScrap) && itemDef.canRemove && !itemDef.hidden && itemDef.DoesNotContainTag(ItemTag.Scrap) && (!(GetComponent<LemurianEggController>() != null) || !itemDef.ContainsTag(ItemTag.CannotCopy)) && (!isRebirthChoice || !itemDef.ContainsTag(ItemTag.RebirthBlacklist)))
				{
					list.Add(new Option
					{
						available = true,
						pickupIndex = pickupIndex
					});
				}
			}
			SetOptionsServer(list.ToArray());
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public bool ShouldShowOnScanner()
		{
			if (GetComponent<DelusionChestController>() != null)
			{
				return available;
			}
			return true;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		public void AddPickupSelected()
		{
			numberOfPickUpsSelected++;
			if (numberOfPickUpsSelected >= GrabNumbers)
			{
				multiOptionsAvailable = false;
				KillPanel();
			}
		}

		private void KillPanel()
		{
			eventFunctions.DestroySelf();
		}

		public void OnDelusionPickupSelected(int pickupSelectedIndex)
		{
			if (base.enabled && TryGetComponent<DelusionChestController>(out var component))
			{
				component = GetComponent<DelusionChestController>();
				component.SelectedPickupIndex = new PickupIndex(pickupSelectedIndex);
				component.delusionChest.Open();
				SetAvailable(newAvailable: false);
			}
		}

		public IInspectInfoProvider GetInspectInfoProvider()
		{
			IInspectInfoProvider component = GetComponent<IInspectInfoProvider>();
			if (component != null)
			{
				return component;
			}
			return null;
		}

		static PickupPickerController()
		{
			optionsDirtyBit = 1u;
			availableDirtyBit = 2u;
			allDirtyBits = optionsDirtyBit | availableDirtyBit;
			GrabNumbers = 1;
			kRpcRpcHandlePickupSelected = 1904538683;
			NetworkBehaviour.RegisterRpcDelegate(typeof(PickupPickerController), kRpcRpcHandlePickupSelected, InvokeRpcRpcHandlePickupSelected);
			NetworkCRC.RegisterBehaviour("PickupPickerController", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcHandlePickupSelected(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcHandlePickupSelected called on server.");
			}
			else
			{
				((PickupPickerController)obj).RpcHandlePickupSelected((int)reader.ReadPackedUInt32());
			}
		}

		public void CallRpcHandlePickupSelected(int choiceIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcHandlePickupSelected called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcHandlePickupSelected);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)choiceIndex);
			SendRPCInternal(networkWriter, 0, "RpcHandlePickupSelected");
		}

		public override void PreStartClient()
		{
		}
	}
	public class PingerController : NetworkBehaviour
	{
		[Serializable]
		public struct PingInfo : IEquatable<PingInfo>
		{
			public bool active;

			public UnityEngine.Vector3 origin;

			public UnityEngine.Vector3 normal;

			public NetworkIdentity targetNetworkIdentity;

			public GameObject targetGameObject
			{
				get
				{
					if (!targetNetworkIdentity)
					{
						return null;
					}
					return targetNetworkIdentity.gameObject;
				}
			}

			public bool Equals(PingInfo other)
			{
				if (active.Equals(other.active) && origin.Equals(other.origin) && normal.Equals(other.normal))
				{
					return (object)targetNetworkIdentity == other.targetNetworkIdentity;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				return (obj as PingInfo?)?.Equals(this) ?? false;
			}

			public override int GetHashCode()
			{
				return (((-1814869148 * -1521134295 + active.GetHashCode()) * -1521134295 + EqualityComparer<UnityEngine.Vector3>.Default.GetHashCode(origin)) * -1521134295 + EqualityComparer<UnityEngine.Vector3>.Default.GetHashCode(normal)) * -1521134295 + EqualityComparer<NetworkIdentity>.Default.GetHashCode(targetNetworkIdentity);
			}
		}

		private int pingStock = 3;

		private float pingRechargeStopwatch;

		private const int maximumPingStock = 3;

		private const float pingRechargeInterval = 1.5f;

		private static readonly PingInfo emptyPing;

		private PingIndicator pingIndicator;

		[SyncVar(hook = "OnSyncCurrentPing")]
		public PingInfo currentPing;

		private static int kCmdCmdPing;

		public PingInfo NetworkcurrentPing
		{
			get
			{
				return currentPing;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncCurrentPing(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref currentPing, 1u);
			}
		}

		private void RebuildPing(PingInfo pingInfo)
		{
			if (!pingInfo.active && (object)pingIndicator != null)
			{
				if ((bool)pingIndicator)
				{
					UnityEngine.Object.Destroy(pingIndicator.gameObject);
				}
				pingIndicator = null;
				return;
			}
			if (!pingIndicator)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/PingIndicator"));
				pingIndicator = gameObject.GetComponent<PingIndicator>();
				pingIndicator.pingOwner = base.gameObject;
			}
			pingIndicator.pingOrigin = pingInfo.origin;
			pingIndicator.pingNormal = pingInfo.normal;
			pingIndicator.pingTarget = pingInfo.targetGameObject;
			pingIndicator.RebuildPing();
		}

		private void OnDestroy()
		{
			if ((bool)pingIndicator)
			{
				UnityEngine.Object.Destroy(pingIndicator.gameObject);
			}
		}

		private void OnSyncCurrentPing(PingInfo newPingInfo)
		{
			if (!base.hasAuthority)
			{
				SetCurrentPing(newPingInfo);
			}
		}

		private void SetCurrentPing(PingInfo newPingInfo)
		{
			if ((bool)currentPing.targetGameObject)
			{
				currentPing.targetGameObject.GetComponent<TeleporterInteraction>()?.CancelTeleporterPing(pingIndicator);
			}
			NetworkcurrentPing = newPingInfo;
			RebuildPing(currentPing);
			if (base.hasAuthority)
			{
				CallCmdPing(currentPing);
			}
		}

		[Command]
		private void CmdPing(PingInfo incomingPing)
		{
			NetworkcurrentPing = incomingPing;
		}

		private void FixedUpdate()
		{
			if (base.hasAuthority)
			{
				pingRechargeStopwatch -= Time.fixedDeltaTime;
				if (pingRechargeStopwatch <= 0f)
				{
					pingStock = Mathf.Min(pingStock + 1, 3);
					pingRechargeStopwatch = 1.5f;
				}
			}
		}

		private static bool GeneratePingInfo(Ray aimRay, GameObject bodyObject, out PingInfo result)
		{
			result = new PingInfo
			{
				active = true,
				origin = UnityEngine.Vector3.zero,
				normal = UnityEngine.Vector3.zero,
				targetNetworkIdentity = null
			};
			aimRay = CameraRigController.ModifyAimRayIfApplicable(aimRay, bodyObject, out var extraRaycastDistance);
			float maxDistance = 1000f + extraRaycastDistance;
			if (Util.CharacterRaycast(bodyObject, aimRay, out var hitInfo, maxDistance, (int)LayerIndex.entityPrecise.mask | (int)LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal))
			{
				HurtBox component = hitInfo.collider.GetComponent<HurtBox>();
				if ((bool)component && (bool)component.healthComponent)
				{
					CharacterBody body = component.healthComponent.body;
					result.origin = body.corePosition;
					result.normal = UnityEngine.Vector3.zero;
					result.targetNetworkIdentity = body.networkIdentity;
					return true;
				}
			}
			if (Util.CharacterRaycast(bodyObject, aimRay, out hitInfo, maxDistance, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault | (int)LayerIndex.pickups.mask, QueryTriggerInteraction.Collide))
			{
				GameObject gameObject = hitInfo.collider.gameObject;
				NetworkIdentity networkIdentity = gameObject.GetComponentInParent<NetworkIdentity>();
				ForcePingable component2 = gameObject.GetComponent<ForcePingable>();
				if (!networkIdentity && (component2 == null || !component2.bypassEntityLocator))
				{
					Transform parent = gameObject.transform.parent;
					EntityLocator entityLocator = (parent ? parent.GetComponentInChildren<EntityLocator>() : gameObject.GetComponent<EntityLocator>());
					if ((bool)entityLocator)
					{
						gameObject = entityLocator.entity;
						networkIdentity = gameObject.GetComponent<NetworkIdentity>();
					}
				}
				result.origin = hitInfo.point;
				result.normal = hitInfo.normal;
				if ((bool)networkIdentity && networkIdentity.isPingable)
				{
					result.targetNetworkIdentity = networkIdentity;
				}
				return true;
			}
			return false;
		}

		public void AttemptPing(Ray aimRay, GameObject bodyObject)
		{
			if (pingStock <= 0)
			{
				Chat.AddMessage(Language.GetString("PLAYER_PING_COOLDOWN"));
				return;
			}
			if (!RoR2Application.isInSinglePlayer)
			{
				pingStock--;
			}
			if (!GeneratePingInfo(aimRay, bodyObject, out var result))
			{
				return;
			}
			if ((object)result.targetNetworkIdentity != null && (object)result.targetNetworkIdentity == currentPing.targetNetworkIdentity)
			{
				if ((bool)currentPing.targetGameObject && (bool)currentPing.targetGameObject.GetComponent<TeleporterInteraction>())
				{
					if ((bool)pingIndicator)
					{
						result = emptyPing;
						pingStock++;
					}
				}
				else
				{
					result = emptyPing;
					pingStock++;
				}
			}
			SetCurrentPing(result);
		}

		static PingerController()
		{
			kCmdCmdPing = 1170265357;
			NetworkBehaviour.RegisterCommandDelegate(typeof(PingerController), kCmdCmdPing, InvokeCmdCmdPing);
			NetworkCRC.RegisterBehaviour("PingerController", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdPing(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdPing called on client.");
			}
			else
			{
				((PingerController)obj).CmdPing(GeneratedNetworkCode._ReadPingInfo_PingerController(reader));
			}
		}

		public void CallCmdPing(PingInfo incomingPing)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdPing called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdPing(incomingPing);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdPing);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WritePingInfo_PingerController(networkWriter, incomingPing);
			SendCommandInternal(networkWriter, 0, "CmdPing");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WritePingInfo_PingerController(writer, currentPing);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WritePingInfo_PingerController(writer, currentPing);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				currentPing = GeneratedNetworkCode._ReadPingInfo_PingerController(reader);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncCurrentPing(GeneratedNetworkCode._ReadPingInfo_PingerController(reader));
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class PingInfoProvider : MonoBehaviour
	{
		[SerializeField]
		public Sprite pingIconOverride;
	}
	public class PlacementUtility : MonoBehaviour
	{
		public Transform targetParent;

		public GameObject prefabPlacement;

		public bool normalToSurface;

		public bool flipForwardDirection;

		public float minScale = 1f;

		public float maxScale = 2f;

		public float minXRotation;

		public float maxXRotation;

		public float minYRotation;

		public float maxYRotation;

		public float minZRotation;

		public float maxZRotation;

		private void Start()
		{
		}

		private void Update()
		{
		}

		public void PlacePrefab(UnityEngine.Vector3 targetPosition, UnityEngine.Quaternion rotation)
		{
			_ = (bool)prefabPlacement;
		}
	}
	[RequireComponent(typeof(CharacterMaster))]
	[RequireComponent(typeof(PingerController))]
	public class PlayerCharacterMasterController : NetworkBehaviour
	{
		private static List<PlayerCharacterMasterController> _instances;

		private static ReadOnlyCollection<PlayerCharacterMasterController> _instancesReadOnly;

		private CharacterBody body;

		private InputBankTest bodyInputs;

		private CharacterMotor bodyMotor;

		private GameObject previousBodyObject;

		[CompilerGenerated]
		private string _003CfinalMessageTokenServer_003Ek__BackingField;

		private PingerController pingerController;

		[SyncVar(hook = "OnSyncNetworkUserInstanceId")]
		private NetworkInstanceId networkUserInstanceId;

		private GameObject resolvedNetworkUserGameObjectInstance;

		private bool networkUserResolved;

		private NetworkUser resolvedNetworkUserInstance;

		private bool alreadyLinkedToNetworkUserOnce;

		public float cameraMinPitch = -70f;

		public float cameraMaxPitch = 70f;

		public GameObject crosshair;

		public UnityEngine.Vector3 crosshairPosition;

		private NetworkIdentity netid;

		private static readonly float sprintMinAimMoveDot;

		private bool sprintInputPressReceived;

		private bool wasClaimed;

		private float lunarCoinChanceMultiplier = 0.5f;

		private static int kRpcRpcOnLinkedToNetworkUser;

		private static int kRpcRpcIncrementRunCount;

		public static ReadOnlyCollection<PlayerCharacterMasterController> instances => _instancesReadOnly;

		private bool bodyIsFlier
		{
			get
			{
				if ((bool)bodyMotor)
				{
					return bodyMotor.isFlying;
				}
				return true;
			}
		}

		public CharacterMaster master { get; private set; }

		private NetworkIdentity networkIdentity => master.networkIdentity;

		public string finalMessageTokenServer
		{
			[Server]
			[CompilerGenerated]
			get
			{
				if (!NetworkServer.active)
				{
					UnityEngine.Debug.LogWarning("[Server] function 'System.String RoR2.PlayerCharacterMasterController::get_finalMessageTokenServer()' called on client");
					return null;
				}
				return _003CfinalMessageTokenServer_003Ek__BackingField;
			}
			[Server]
			[CompilerGenerated]
			set
			{
				if (!NetworkServer.active)
				{
					UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PlayerCharacterMasterController::set_finalMessageTokenServer(System.String)' called on client");
				}
				else
				{
					_003CfinalMessageTokenServer_003Ek__BackingField = value;
				}
			}
		} = string.Empty;


		public bool hasEffectiveAuthority => master.hasEffectiveAuthority;

		public GameObject networkUserObject
		{
			get
			{
				if (!networkUserResolved)
				{
					resolvedNetworkUserGameObjectInstance = Util.FindNetworkObject(networkUserInstanceId);
					resolvedNetworkUserInstance = null;
					if ((bool)resolvedNetworkUserGameObjectInstance)
					{
						resolvedNetworkUserInstance = resolvedNetworkUserGameObjectInstance.GetComponent<NetworkUser>();
						networkUserResolved = true;
						SetBodyPrefabToPreference();
					}
				}
				return resolvedNetworkUserGameObjectInstance;
			}
			private set
			{
				NetworkInstanceId invalid = NetworkInstanceId.Invalid;
				resolvedNetworkUserGameObjectInstance = null;
				resolvedNetworkUserInstance = null;
				networkUserResolved = true;
				if ((bool)value)
				{
					NetworkIdentity component = value.GetComponent<NetworkIdentity>();
					if ((bool)component)
					{
						invalid = component.netId;
						resolvedNetworkUserGameObjectInstance = value;
						resolvedNetworkUserInstance = value.GetComponent<NetworkUser>();
						SetBodyPrefabToPreference();
					}
				}
				NetworknetworkUserInstanceId = invalid;
			}
		}

		public NetworkUser networkUser
		{
			get
			{
				if (!networkUserObject)
				{
					return null;
				}
				return resolvedNetworkUserInstance;
			}
		}

		public bool isConnected => networkUserObject;

		public bool preventGameOver => master.preventGameOver;

		public NetworkInstanceId NetworknetworkUserInstanceId
		{
			get
			{
				return networkUserInstanceId;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncNetworkUserInstanceId(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref networkUserInstanceId, 1u);
			}
		}

		public event Action onLinkedToNetworkUserServer;

		public static event Action<PlayerCharacterMasterController> onPlayerAdded;

		public static event Action<PlayerCharacterMasterController> onPlayerRemoved;

		public static event Action<PlayerCharacterMasterController> onLinkedToNetworkUserServerGlobal;

		public static event Action<PlayerCharacterMasterController> onLinkedToNetworkUserLocal;

		private void OnSyncNetworkUserInstanceId(NetworkInstanceId value)
		{
			resolvedNetworkUserGameObjectInstance = null;
			resolvedNetworkUserInstance = null;
			networkUserResolved = value == NetworkInstanceId.Invalid;
			NetworknetworkUserInstanceId = value;
		}

		[Server]
		public void LinkToNetworkUserServer(NetworkUser networkUser)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PlayerCharacterMasterController::LinkToNetworkUserServer(RoR2.NetworkUser)' called on client");
				return;
			}
			networkUser.masterObject = base.gameObject;
			networkUserObject = networkUser.gameObject;
			networkIdentity.AssignClientAuthority(networkUser.connectionToClient);
			if (!alreadyLinkedToNetworkUserOnce)
			{
				networkUser.CopyLoadoutToMaster();
				alreadyLinkedToNetworkUserOnce = true;
			}
			else
			{
				networkUser.CopyLoadoutFromMaster();
			}
			SetBodyPrefabToPreference();
			this.onLinkedToNetworkUserServer?.Invoke();
			PlayerCharacterMasterController.onLinkedToNetworkUserServerGlobal?.Invoke(this);
			HandleLinkedToNetworkUser(networkUser.id);
			CallRpcOnLinkedToNetworkUser(networkUser.id);
		}

		[ClientRpc]
		private void RpcOnLinkedToNetworkUser(NetworkUserId id)
		{
			HandleLinkedToNetworkUser(id);
		}

		private void HandleLinkedToNetworkUser(NetworkUserId id)
		{
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				if ((bool)readOnlyLocalUsers.currentNetworkUser && readOnlyLocalUsers.currentNetworkUser.id.Equals(id))
				{
					PlayerCharacterMasterController.onLinkedToNetworkUserLocal?.Invoke(this);
					break;
				}
			}
		}

		private void Awake()
		{
			master = GetComponent<CharacterMaster>();
			netid = GetComponent<NetworkIdentity>();
			pingerController = GetComponent<PingerController>();
		}

		private void OnEnable()
		{
			_instances.Add(this);
			if (PlayerCharacterMasterController.onPlayerAdded != null)
			{
				PlayerCharacterMasterController.onPlayerAdded(this);
			}
			NetworkUser.onNetworkUserBodyPreferenceChanged += OnNetworkUserBodyPreferenceChanged;
		}

		private void OnDisable()
		{
			_instances.Remove(this);
			if (PlayerCharacterMasterController.onPlayerRemoved != null)
			{
				PlayerCharacterMasterController.onPlayerRemoved(this);
			}
			NetworkUser.onNetworkUserBodyPreferenceChanged -= OnNetworkUserBodyPreferenceChanged;
		}

		private void Start()
		{
			if (NetworkServer.active && (bool)networkUser)
			{
				CallRpcIncrementRunCount();
			}
		}

		[ClientRpc]
		private void RpcIncrementRunCount()
		{
			if ((bool)networkUser)
			{
				LocalUser localUser = networkUser.localUser;
				if (localUser != null)
				{
					localUser.userProfile.totalRunCount++;
				}
			}
		}

		private static bool CanSendBodyInput(NetworkUser networkUser, out LocalUser localUser, out Player inputPlayer, out CameraRigController cameraRigController, out bool onlyAllowMovement)
		{
			if (!networkUser)
			{
				localUser = null;
				inputPlayer = null;
				cameraRigController = null;
				onlyAllowMovement = false;
				return false;
			}
			localUser = networkUser.localUser;
			inputPlayer = networkUser.inputPlayer;
			cameraRigController = networkUser.cameraRigController;
			onlyAllowMovement = false;
			if (localUser == null || inputPlayer == null || !cameraRigController)
			{
				return false;
			}
			if (localUser.isUIFocused)
			{
				UIInputPassthrough uIPassthrough = localUser.GetUIPassthrough();
				if (!uIPassthrough)
				{
					return false;
				}
				onlyAllowMovement = uIPassthrough.OnlyAllowMovement;
			}
			if (!cameraRigController.isControlAllowed)
			{
				return false;
			}
			return true;
		}

		private void Update()
		{
			if (!hasEffectiveAuthority)
			{
				return;
			}
			SetBody(master.GetBodyObject());
			if (!bodyInputs)
			{
				return;
			}
			UnityEngine.Vector3 moveVector = UnityEngine.Vector3.zero;
			UnityEngine.Vector3 aimDirection = bodyInputs.aimDirection;
			if (CanSendBodyInput(networkUser, out var _, out var inputPlayer, out var cameraRigController, out var _))
			{
				Transform transform = cameraRigController.transform;
				sprintInputPressReceived |= inputPlayer.GetButtonDown(18);
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(inputPlayer.GetAxis(0), inputPlayer.GetAxis(1));
				UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(inputPlayer.GetAxis(12), inputPlayer.GetAxis(13));
				bodyInputs.SetRawMoveStates(vector + vector2);
				float sqrMagnitude = vector.sqrMagnitude;
				if (sqrMagnitude > 1f)
				{
					vector /= Mathf.Sqrt(sqrMagnitude);
				}
				if (bodyIsFlier)
				{
					moveVector = transform.right * vector.x + transform.forward * vector.y;
				}
				else
				{
					float y = transform.eulerAngles.y;
					moveVector = UnityEngine.Quaternion.Euler(0f, y, 0f) * new UnityEngine.Vector3(vector.x, 0f, vector.y);
				}
				aimDirection = (cameraRigController.crosshairWorldPosition - bodyInputs.aimOrigin).normalized;
			}
			bodyInputs.moveVector = moveVector;
			bodyInputs.aimDirection = aimDirection;
		}

		private void FixedUpdate()
		{
			if (hasEffectiveAuthority && (bool)bodyInputs)
			{
				PollButtonInput();
				CheckPinging();
			}
		}

		private void PollButtonInput()
		{
			bool newState = false;
			bool newState2 = false;
			bool newState3 = false;
			bool newState4 = false;
			bool newState5 = false;
			bool newState6 = false;
			bool newState7 = false;
			bool newState8 = false;
			bool newState9 = false;
			if (CanSendBodyInput(networkUser, out var _, out var inputPlayer, out var _, out var _))
			{
				bool flag = false;
				flag = body.isSprinting;
				if (sprintInputPressReceived)
				{
					sprintInputPressReceived = false;
					flag = !flag;
				}
				if (flag)
				{
					UnityEngine.Vector3 aimDirection = bodyInputs.aimDirection;
					aimDirection.y = 0f;
					aimDirection.Normalize();
					UnityEngine.Vector3 moveVector = bodyInputs.moveVector;
					moveVector.y = 0f;
					moveVector.Normalize();
					if ((body.bodyFlags & CharacterBody.BodyFlags.SprintAnyDirection) == 0 && UnityEngine.Vector3.Dot(aimDirection, moveVector) < sprintMinAimMoveDot)
					{
						flag = false;
					}
				}
				newState = inputPlayer.GetButton(7);
				newState2 = inputPlayer.GetButton(8);
				newState3 = inputPlayer.GetButton(9);
				newState4 = inputPlayer.GetButton(10);
				newState5 = inputPlayer.GetButton(5);
				newState6 = inputPlayer.GetButton(4);
				newState7 = flag;
				newState8 = inputPlayer.GetButton(6);
				newState9 = inputPlayer.GetButton(28);
			}
			bodyInputs.skill1.PushState(newState);
			bodyInputs.skill2.PushState(newState2);
			bodyInputs.skill3.PushState(newState3);
			bodyInputs.skill4.PushState(newState4);
			bodyInputs.interact.PushState(newState5);
			bodyInputs.jump.PushState(newState6);
			bodyInputs.sprint.PushState(newState7);
			bodyInputs.activateEquipment.PushState(newState8);
			bodyInputs.ping.PushState(newState9);
		}

		public void RedirectCamera(UnityEngine.Vector3 desiredRotation)
		{
			if (CanSendBodyInput(networkUser, out var _, out var _, out var cameraRigController, out var _))
			{
				CameraState cameraStateToMatch = cameraRigController.currentCameraState;
				cameraStateToMatch.rotation = UnityEngine.Quaternion.Euler(desiredRotation.x, desiredRotation.y, desiredRotation.z);
				CameraModeBase.CameraModeContext context = default(CameraModeBase.CameraModeContext);
				context.cameraInfo.cameraRigController = cameraRigController;
				cameraRigController.cameraMode?.MatchState(in context, in cameraStateToMatch);
			}
		}

		private void CheckPinging()
		{
			if (hasEffectiveAuthority && (bool)body && (bool)bodyInputs && bodyInputs.ping.justPressed)
			{
				pingerController.AttemptPing(new Ray(bodyInputs.aimOrigin, bodyInputs.aimDirection), body.gameObject);
			}
		}

		public string GetDisplayName()
		{
			string result = "";
			if ((bool)networkUserObject)
			{
				NetworkUser component = networkUserObject.GetComponent<NetworkUser>();
				if ((bool)component)
				{
					result = component.userName;
				}
			}
			return result;
		}

		private void SetBody(GameObject newBody)
		{
			if ((bool)newBody)
			{
				body = newBody.GetComponent<CharacterBody>();
			}
			else
			{
				body = null;
			}
			if ((bool)body)
			{
				bodyInputs = body.inputBank;
				bodyMotor = body.characterMotor;
			}
			else
			{
				bodyInputs = null;
				bodyMotor = null;
			}
		}

		[Server]
		public void OnBodyDeath()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PlayerCharacterMasterController::OnBodyDeath()' called on client");
			}
		}

		public void OnBodyStart()
		{
			if (NetworkServer.active)
			{
				finalMessageTokenServer = string.Empty;
			}
		}

		public static int GetPlayersWithBodiesCount()
		{
			int num = 0;
			foreach (PlayerCharacterMasterController instance in _instances)
			{
				if (instance.master.hasBody)
				{
					num++;
				}
			}
			return num;
		}

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
		private static void Init()
		{
			GlobalEventManager.onCharacterDeathGlobal += delegate(DamageReport damageReport)
			{
				CharacterMaster characterMaster = damageReport.attackerMaster;
				if ((bool)characterMaster)
				{
					if ((bool)characterMaster.minionOwnership.ownerMaster)
					{
						characterMaster = characterMaster.minionOwnership.ownerMaster;
					}
					PlayerCharacterMasterController component = characterMaster.GetComponent<PlayerCharacterMasterController>();
					if ((bool)component && Util.CheckRoll(1f * component.lunarCoinChanceMultiplier))
					{
						PickupDropletController.CreatePickupDroplet(PickupCatalog.FindPickupIndex(RoR2Content.MiscPickups.LunarCoin.miscPickupIndex), damageReport.victim.transform.position, UnityEngine.Vector3.up * 10f);
						component.lunarCoinChanceMultiplier *= 0.5f;
					}
				}
			};
		}

		private void SetBodyPrefabToPreference()
		{
			master.bodyPrefab = BodyCatalog.GetBodyPrefab(networkUser.bodyIndexPreference);
			if (!master.bodyPrefab)
			{
				UnityEngine.Debug.LogError($"SetBodyPrefabToPreference failed to find a body prefab for index '{networkUser.bodyIndexPreference}'.  Reverting to backup: {master.backupBodyIndex}");
				master.bodyPrefab = BodyCatalog.GetBodyPrefab(master.backupBodyIndex);
				if (!master.bodyPrefab)
				{
					UnityEngine.Debug.LogError($"SetBodyPrefabToPreference backup ({master.backupBodyIndex}) failed.");
				}
			}
		}

		private void OnNetworkUserBodyPreferenceChanged(NetworkUser networkUser)
		{
			if ((bool)this.networkUser && networkUser.netId.Value == this.networkUser.netId.Value)
			{
				SetBodyPrefabToPreference();
			}
		}

		static PlayerCharacterMasterController()
		{
			_instances = new List<PlayerCharacterMasterController>();
			_instancesReadOnly = new ReadOnlyCollection<PlayerCharacterMasterController>(_instances);
			sprintMinAimMoveDot = Mathf.Cos(MathF.PI / 3f);
			kRpcRpcOnLinkedToNetworkUser = 585837834;
			NetworkBehaviour.RegisterRpcDelegate(typeof(PlayerCharacterMasterController), kRpcRpcOnLinkedToNetworkUser, InvokeRpcRpcOnLinkedToNetworkUser);
			kRpcRpcIncrementRunCount = 1915650359;
			NetworkBehaviour.RegisterRpcDelegate(typeof(PlayerCharacterMasterController), kRpcRpcIncrementRunCount, InvokeRpcRpcIncrementRunCount);
			NetworkCRC.RegisterBehaviour("PlayerCharacterMasterController", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcOnLinkedToNetworkUser(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcOnLinkedToNetworkUser called on server.");
			}
			else
			{
				((PlayerCharacterMasterController)obj).RpcOnLinkedToNetworkUser(GeneratedNetworkCode._ReadNetworkUserId_None(reader));
			}
		}

		protected static void InvokeRpcRpcIncrementRunCount(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcIncrementRunCount called on server.");
			}
			else
			{
				((PlayerCharacterMasterController)obj).RpcIncrementRunCount();
			}
		}

		public void CallRpcOnLinkedToNetworkUser(NetworkUserId id)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcOnLinkedToNetworkUser called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcOnLinkedToNetworkUser);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteNetworkUserId_None(networkWriter, id);
			SendRPCInternal(networkWriter, 0, "RpcOnLinkedToNetworkUser");
		}

		public void CallRpcIncrementRunCount()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcIncrementRunCount called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcIncrementRunCount);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcIncrementRunCount");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(networkUserInstanceId);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(networkUserInstanceId);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				networkUserInstanceId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncNetworkUserInstanceId(reader.ReadNetworkId());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(PlayerCharacterMasterController))]
	public class PlayerCharacterMasterControllerEntitlementTracker : NetworkBehaviour
	{
		private PlayerCharacterMasterController playerCharacterMasterController;

		private static readonly uint entitlementsSetDirtyBit = 1u;

		private static readonly uint allDirtyBits = entitlementsSetDirtyBit;

		private bool[] entitlementsSet;

		private void Awake()
		{
			playerCharacterMasterController = GetComponent<PlayerCharacterMasterController>();
			entitlementsSet = new bool[EntitlementCatalog.entitlementDefs.Length];
			playerCharacterMasterController.onLinkedToNetworkUserServer += OnLinkedToNetworkUserServer;
		}

		private void OnLinkedToNetworkUserServer()
		{
			UpdateEntitlementsServer();
			GameObject bodyPrefab = playerCharacterMasterController.master.bodyPrefab;
			if ((bool)bodyPrefab)
			{
				ExpansionRequirementComponent component = bodyPrefab.GetComponent<ExpansionRequirementComponent>();
				if ((bool)component && !component.PlayerCanUseBody(playerCharacterMasterController))
				{
					UnityEngine.Debug.LogWarning("Player can't use body " + bodyPrefab.name + "; defaulting to default survivor.");
					playerCharacterMasterController.master.bodyPrefab = SurvivorCatalog.defaultSurvivor.bodyPrefab;
				}
			}
		}

		[Server]
		private void UpdateEntitlementsServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PlayerCharacterMasterControllerEntitlementTracker::UpdateEntitlementsServer()' called on client");
				return;
			}
			NetworkUser networkUser = playerCharacterMasterController.networkUser;
			if (!networkUser)
			{
				return;
			}
			bool flag = false;
			NetworkUserServerEntitlementTracker networkUserEntitlementTracker = EntitlementManager.networkUserEntitlementTracker;
			ReadOnlyArray<EntitlementDef> entitlementDefs = EntitlementCatalog.entitlementDefs;
			for (int i = 0; i < entitlementDefs.Length; i++)
			{
				EntitlementDef entitlementDef = entitlementDefs[i];
				if (!entitlementsSet[i] && networkUserEntitlementTracker.UserHasEntitlement(networkUser, entitlementDef))
				{
					entitlementsSet[i] = true;
					flag = true;
				}
			}
			if (flag)
			{
				SetDirtyBit(entitlementsSetDirtyBit);
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = (initialState ? allDirtyBits : base.syncVarDirtyBits);
			writer.WritePackedUInt32(num);
			if ((num & entitlementsSetDirtyBit) != 0)
			{
				writer.WriteBitArray(entitlementsSet);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if ((reader.ReadPackedUInt32() & entitlementsSetDirtyBit) != 0)
			{
				reader.ReadBitArray(entitlementsSet);
			}
		}

		public bool HasEntitlement([NotNull] EntitlementDef entitlementDef)
		{
			if ((object)entitlementDef == null)
			{
				throw new ArgumentNullException("entitlementDef");
			}
			bool[] array = entitlementsSet;
			EntitlementIndex entitlementIndex = entitlementDef.entitlementIndex;
			bool defaultValue = false;
			return ArrayUtils.GetSafe(array, (int)entitlementIndex, in defaultValue);
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class PlayerSpawnInhibitor : MonoBehaviour
	{
		private static List<PlayerSpawnInhibitor> instancesList = new List<PlayerSpawnInhibitor>();

		private static ReadOnlyCollection<PlayerSpawnInhibitor> _readOnlyInstancesList = new ReadOnlyCollection<PlayerSpawnInhibitor>(instancesList);

		[SerializeField]
		private float radius;

		[SerializeField]
		private Transform center;

		public static ReadOnlyCollection<PlayerSpawnInhibitor> readOnlyInstancesList => _readOnlyInstancesList;

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		public bool IsInhibiting(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex)
		{
			if ((bool)nodeGraph && nodeGraph.GetNodePosition(nodeIndex, out var position))
			{
				return (center.position - position).sqrMagnitude < radius * radius;
			}
			return false;
		}
	}
	public class PortalDialerController : NetworkBehaviour
	{
		[Serializable]
		public struct DialedAction
		{
			public Sha256HashAsset hashAsset;

			public UnityEvent action;
		}

		private class PortalDialerBaseState : BaseState
		{
			protected PortalDialerController portalDialer { get; private set; }

			public override void OnEnter()
			{
				base.OnEnter();
				portalDialer = GetComponent<PortalDialerController>();
			}
		}

		private class PortalDialerIdleState : PortalDialerBaseState
		{
			private PurchaseInteraction dialerInteraction;

			public override void OnEnter()
			{
				base.OnEnter();
				PortalDialerButtonController[] buttons = base.portalDialer.buttons;
				for (int i = 0; i < buttons.Length; i++)
				{
					buttons[i].GetComponent<GenericInteraction>().Networkinteractability = Interactability.Available;
				}
				dialerInteraction = base.portalDialer.GetComponent<PurchaseInteraction>();
				if (NetworkServer.active)
				{
					dialerInteraction.SetAvailable(newAvailable: true);
					dialerInteraction.onPurchase.AddListener(OnActivationServer);
					if (Run.instance.GetEventFlag("NoArtifactWorld"))
					{
						outer.SetNextState(new PortalDialerDisabledState());
					}
				}
			}

			private void OnActivationServer(Interactor interactor)
			{
				outer.SetNextState(new PortalDialerPreDialState());
			}

			public override void OnExit()
			{
				if (NetworkServer.active)
				{
					dialerInteraction.SetAvailable(newAvailable: false);
					dialerInteraction.onPurchase.RemoveListener(OnActivationServer);
				}
				PortalDialerButtonController[] buttons = base.portalDialer.buttons;
				foreach (PortalDialerButtonController portalDialerButtonController in buttons)
				{
					if ((bool)portalDialerButtonController)
					{
						portalDialerButtonController.GetComponent<GenericInteraction>().Networkinteractability = Interactability.Disabled;
					}
				}
				base.OnExit();
			}
		}

		private class PortalDialerDisabledState : PortalDialerBaseState
		{
			private PurchaseInteraction dialerInteraction;

			public override void OnEnter()
			{
				base.OnEnter();
				PortalDialerButtonController[] buttons = base.portalDialer.buttons;
				for (int i = 0; i < buttons.Length; i++)
				{
					buttons[i].GetComponent<GenericInteraction>().Networkinteractability = Interactability.Disabled;
				}
				dialerInteraction = base.portalDialer.GetComponent<PurchaseInteraction>();
				if (NetworkServer.active)
				{
					dialerInteraction.SetAvailable(newAvailable: false);
				}
			}
		}

		private class PortalDialerPreDialState : PortalDialerBaseState
		{
			public static float baseDuration;

			public static GameObject portalPrespawnEffect;

			private float duration;

			private byte[] sequenceServer;

			public override void OnEnter()
			{
				base.OnEnter();
				duration = baseDuration;
				if (NetworkServer.active)
				{
					sequenceServer = new byte[base.portalDialer.buttons.Length];
				}
				if ((bool)portalPrespawnEffect)
				{
					EffectManager.SimpleEffect(portalPrespawnEffect, base.portalDialer.portalSpawnLocation.position, base.portalDialer.portalSpawnLocation.rotation, transmit: false);
				}
				Util.PlaySound("Play_env_hiddenLab_laptop_activate", base.gameObject);
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= duration)
				{
					outer.SetNextState(new PortalDialerDialDigitState
					{
						currentDigit = 0,
						sequenceServer = sequenceServer
					});
				}
			}
		}

		private class PortalDialerDialDigitState : PortalDialerBaseState
		{
			public static float baseDuration;

			public int currentDigit;

			private float duration;

			public byte[] sequenceServer;

			public override void OnEnter()
			{
				base.OnEnter();
				duration = baseDuration;
				PortalDialerButtonController portalDialerButtonController = base.portalDialer.dialingOrder[currentDigit];
				if (NetworkServer.active)
				{
					sequenceServer[Array.IndexOf(base.portalDialer.buttons, portalDialerButtonController)] = (byte)portalDialerButtonController.currentDigitDef.value;
					if ((bool)portalDialerButtonController)
					{
						portalDialerButtonController.NetworkcurrentDigitIndex = 0;
					}
				}
				Util.PlaySound("Play_env_hiddenLab_laptop_sequence_lock", base.gameObject);
			}

			public override void OnExit()
			{
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= duration)
				{
					if (currentDigit >= base.portalDialer.buttons.Length - 1)
					{
						UnityEngine.Debug.LogFormat("Submitting sequence {0}", SequenceToString(sequenceServer));
						outer.SetNextState(new PortalDialerPostDialState
						{
							sequenceServer = sequenceServer
						});
					}
					else
					{
						outer.SetNextState(new PortalDialerDialDigitState
						{
							currentDigit = currentDigit + 1,
							sequenceServer = sequenceServer
						});
					}
				}
			}

			public override void OnSerialize(NetworkWriter writer)
			{
				base.OnSerialize(writer);
				writer.Write((byte)currentDigit);
			}

			public override void OnDeserialize(NetworkReader reader)
			{
				base.OnDeserialize(reader);
				currentDigit = reader.ReadByte();
			}
		}

		private class PortalDialerPostDialState : PortalDialerBaseState
		{
			public static float baseDuration;

			public static GameObject portalSpawnEffect;

			private float duration;

			public byte[] sequenceServer;

			public override void OnEnter()
			{
				base.OnEnter();
				duration = baseDuration;
				if ((bool)portalSpawnEffect)
				{
					EffectManager.SimpleEffect(portalSpawnEffect, base.portalDialer.portalSpawnLocation.position, base.portalDialer.portalSpawnLocation.rotation, transmit: false);
				}
			}

			public override void OnExit()
			{
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge >= duration)
				{
					outer.SetNextState(new PortalDialerPerformActionState
					{
						sequenceServer = sequenceServer
					});
				}
			}
		}

		private class PortalDialerPerformActionState : PortalDialerBaseState
		{
			public byte[] sequenceServer;

			public static NetworkSoundEventDef nseSuccess;

			public static NetworkSoundEventDef nseFail;

			public override void OnEnter()
			{
				base.OnEnter();
				if (NetworkServer.active)
				{
					if (base.portalDialer.PerformActionServer(sequenceServer))
					{
						EffectManager.SimpleSoundEffect(nseSuccess.index, base.portalDialer.portalSpawnLocation.position, transmit: true);
						return;
					}
					EffectManager.SimpleSoundEffect(nseFail.index, base.portalDialer.portalSpawnLocation.position, transmit: true);
					outer.SetNextState(new PortalDialerIdleState());
				}
			}
		}

		public PortalDialerButtonController[] buttons;

		public PortalDialerButtonController[] dialingOrder;

		public DialedAction[] actions;

		public Transform portalSpawnLocation;

		private SHA256 hasher;

		private byte[] dialedNumber;

		private void Awake()
		{
			if (NetworkServer.active)
			{
				hasher = SHA256.Create();
			}
		}

		private void OnDestroy()
		{
			if (hasher != null)
			{
				hasher.Dispose();
				hasher = null;
			}
		}

		private byte[] GetSequence()
		{
			byte[] array = new byte[buttons.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = (byte)buttons[i].currentDigitDef.value;
			}
			return array;
		}

		private Sha256Hash GetResult(byte[] sequence)
		{
			hasher.Initialize();
			return Sha256Hash.FromBytes(hasher.ComputeHash(sequence));
		}

		[Server]
		public bool PerformActionServer(byte[] sequence)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.PortalDialerController::PerformActionServer(System.Byte[])' called on client");
				return false;
			}
			Sha256Hash result = GetResult(sequence);
			UnityEngine.Debug.LogFormat("Performing action for sequence={0} hash={1}", sequence, result.ToString());
			for (int i = 0; i < actions.Length; i++)
			{
				if (result.Equals(actions[i].hashAsset.value))
				{
					actions[i].action?.Invoke();
					return true;
				}
			}
			UnityEngine.Debug.LogFormat("Could not find action to perform for {0}", result.ToString());
			return false;
		}

		private static string SequenceToString(byte[] bytes)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(bytes[0]);
			for (int i = 1; i < bytes.Length; i++)
			{
				stringBuilder.Append(":");
				stringBuilder.Append(bytes[i]);
			}
			return stringBuilder.ToString();
		}

		public void PrintResult()
		{
		}

		[Server]
		public void OpenArtifactPortalServer(ArtifactDef artifactDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PortalDialerController::OpenArtifactPortalServer(RoR2.ArtifactDef)' called on client");
				return;
			}
			ArtifactTrialMissionController.trialArtifact = artifactDef;
			SpawnPortalServer(SceneCatalog.GetSceneDefFromSceneName(UnityEngine.Random.Range(0, 4) switch
			{
				1 => "artifactworld01", 
				2 => "artifactworld02", 
				3 => "artifactworld03", 
				_ => "artifactworld", 
			}));
			GetComponent<PurchaseInteraction>().SetAvailable(newAvailable: false);
		}

		[Server]
		public void SpawnPortalServer(SceneDef destination)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PortalDialerController::SpawnPortalServer(RoR2.SceneDef)' called on client");
				return;
			}
			GameObject original = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/PortalArtifactworld");
			if ((bool)destination.preferredPortalPrefab)
			{
				original = destination.preferredPortalPrefab;
			}
			GameObject obj = UnityEngine.Object.Instantiate(original, portalSpawnLocation.position, portalSpawnLocation.rotation);
			SceneExitController component = obj.GetComponent<SceneExitController>();
			component.useRunNextStageScene = false;
			component.destinationScene = destination;
			NetworkServer.Spawn(obj);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class PortalSpawner : NetworkBehaviour
	{
		[SerializeField]
		private InteractableSpawnCard portalSpawnCard;

		[Range(0f, 1f)]
		[SerializeField]
		private float spawnChance;

		[SerializeField]
		[Tooltip("The portal is spawned relative to this transform.  If null, it uses this object's transform for reference.")]
		private Transform spawnReferenceLocation;

		[SerializeField]
		private float minSpawnDistance;

		[Tooltip("The maximum spawn distance for the portal relative to the spawnReferenceLocation.  If 0, it will be spawned at exactly the referenced location.")]
		[SerializeField]
		private float maxSpawnDistance;

		[SerializeField]
		private string spawnPreviewMessageToken;

		[SerializeField]
		private string spawnMessageToken;

		[SerializeField]
		private ChildLocator modelChildLocator;

		[SerializeField]
		private string previewChildName;

		[SerializeField]
		private ExpansionDef requiredExpansion;

		[SerializeField]
		private int minStagesCleared;

		[SerializeField]
		private string bannedEventFlag;

		[SerializeField]
		private string requiredEventFlag;

		[SerializeField]
		private string[] validStages;

		[SerializeField]
		private string[] invalidStages;

		[SerializeField]
		private int[] validStageTiers;

		private Xoroshiro128Plus rng;

		private GameObject previewChild;

		[SyncVar(hook = "OnWillSpawnUpdated")]
		private bool willSpawn;

		public bool NetworkwillSpawn
		{
			get
			{
				return willSpawn;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnWillSpawnUpdated(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref willSpawn, 1u);
			}
		}

		private void Start()
		{
			GetPreviewChild();
			if (!NetworkServer.active)
			{
				return;
			}
			rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong);
			bool flag = !requiredExpansion || Run.instance.IsExpansionEnabled(requiredExpansion);
			bool flag2 = Run.instance.stageClearCount >= minStagesCleared;
			bool flag3 = string.IsNullOrEmpty(bannedEventFlag) || !Run.instance.GetEventFlag(bannedEventFlag);
			if ((string.IsNullOrEmpty(requiredEventFlag) || Run.instance.GetEventFlag(requiredEventFlag)) && flag3 && rng.nextNormalizedFloat <= spawnChance && flag && flag2 && isValidStage())
			{
				NetworkwillSpawn = true;
				if (!string.IsNullOrEmpty(spawnPreviewMessageToken))
				{
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = spawnPreviewMessageToken
					});
				}
				if ((bool)previewChild)
				{
					previewChild.SetActive(value: true);
				}
			}
		}

		private void GetPreviewChild()
		{
			if ((bool)modelChildLocator)
			{
				Transform transform = modelChildLocator.FindChild(previewChildName);
				if ((bool)transform)
				{
					previewChild = transform.gameObject;
				}
			}
		}

		private bool isValidStage()
		{
			bool result = false;
			bool flag = false;
			if (validStages.Length != 0)
			{
				string baseSceneNameOverride = Stage.instance.sceneDef.baseSceneNameOverride;
				for (int i = 0; i < validStages.Length; i++)
				{
					if (validStages[i] == baseSceneNameOverride)
					{
						flag = true;
					}
				}
			}
			else if (validStages.Length == 0)
			{
				flag = true;
			}
			bool flag2 = false;
			if (invalidStages.Length != 0)
			{
				string baseSceneNameOverride2 = Stage.instance.sceneDef.baseSceneNameOverride;
				for (int j = 0; j < invalidStages.Length; j++)
				{
					if (invalidStages[j] == baseSceneNameOverride2)
					{
						flag2 = true;
					}
				}
			}
			bool flag3 = false;
			if (validStageTiers.Length != 0)
			{
				int stageOrder = Stage.instance.sceneDef.stageOrder;
				for (int k = 0; k < validStageTiers.Length; k++)
				{
					if (validStageTiers[k] == stageOrder)
					{
						flag3 = true;
					}
				}
			}
			else if (validStageTiers.Length == 0)
			{
				flag3 = true;
			}
			if (flag && !flag2 && flag3)
			{
				result = true;
			}
			_ = flag && flag2;
			return result;
		}

		[Server]
		public bool AttemptSpawnPortalServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.PortalSpawner::AttemptSpawnPortalServer()' called on client");
				return false;
			}
			if (willSpawn)
			{
				if ((bool)previewChild)
				{
					previewChild.SetActive(value: false);
				}
				NetworkwillSpawn = false;
				DirectorPlacementRule.PlacementMode placementMode = DirectorPlacementRule.PlacementMode.Approximate;
				if (maxSpawnDistance <= 0f)
				{
					placementMode = DirectorPlacementRule.PlacementMode.Direct;
				}
				Transform transform = spawnReferenceLocation;
				if (!transform)
				{
					transform = base.transform;
				}
				GameObject obj = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(portalSpawnCard, new DirectorPlacementRule
				{
					minDistance = minSpawnDistance,
					maxDistance = maxSpawnDistance,
					placementMode = placementMode,
					position = base.transform.position,
					spawnOnTarget = transform
				}, rng));
				if ((bool)obj && !string.IsNullOrEmpty(spawnMessageToken))
				{
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = spawnMessageToken
					});
				}
				return obj;
			}
			return false;
		}

		private void OnWillSpawnUpdated(bool newValue)
		{
			NetworkwillSpawn = newValue;
			if (previewChild == null)
			{
				GetPreviewChild();
			}
			if ((bool)previewChild)
			{
				previewChild.SetActive(newValue);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(willSpawn);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(willSpawn);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				willSpawn = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnWillSpawnUpdated(reader.ReadBoolean());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class PortalStatueBehavior : NetworkBehaviour
	{
		public enum PortalType
		{
			Shop,
			Goldshores,
			Count
		}

		public PortalType portalType;

		private static int kRpcRpcSetPingable;

		public void GrantPortalEntry()
		{
			switch (portalType)
			{
			case PortalType.Shop:
				if ((bool)TeleporterInteraction.instance)
				{
					TeleporterInteraction.instance.shouldAttemptToSpawnShopPortal = true;
				}
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
				{
					origin = base.transform.position,
					rotation = UnityEngine.Quaternion.identity,
					scale = 1f,
					color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.LunarItem)
				}, transmit: true);
				break;
			case PortalType.Goldshores:
				if ((bool)TeleporterInteraction.instance)
				{
					TeleporterInteraction.instance.shouldAttemptToSpawnGoldshoresPortal = true;
				}
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
				{
					origin = base.transform.position,
					rotation = UnityEngine.Quaternion.identity,
					scale = 1f,
					color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Money)
				}, transmit: true);
				break;
			}
			PortalStatueBehavior[] array = UnityEngine.Object.FindObjectsOfType<PortalStatueBehavior>();
			foreach (PortalStatueBehavior portalStatueBehavior in array)
			{
				if (portalStatueBehavior.portalType == portalType)
				{
					PurchaseInteraction component = portalStatueBehavior.GetComponent<PurchaseInteraction>();
					if ((bool)component)
					{
						component.Networkavailable = false;
						CallRpcSetPingable(portalStatueBehavior.gameObject, value: false);
					}
				}
			}
		}

		[ClientRpc]
		private void RpcSetPingable(GameObject statueGO, bool value)
		{
			NetworkIdentity component = statueGO.GetComponent<NetworkIdentity>();
			if ((bool)component)
			{
				component.isPingable = value;
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcSetPingable(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetPingable called on server.");
			}
			else
			{
				((PortalStatueBehavior)obj).RpcSetPingable(reader.ReadGameObject(), reader.ReadBoolean());
			}
		}

		public void CallRpcSetPingable(GameObject statueGO, bool value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetPingable called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetPingable);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(statueGO);
			networkWriter.Write(value);
			SendRPCInternal(networkWriter, 0, "RpcSetPingable");
		}

		static PortalStatueBehavior()
		{
			kRpcRpcSetPingable = 1586108438;
			NetworkBehaviour.RegisterRpcDelegate(typeof(PortalStatueBehavior), kRpcRpcSetPingable, InvokeRpcRpcSetPingable);
			NetworkCRC.RegisterBehaviour("PortalStatueBehavior", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[ExecuteAlways]
	public class PositionAlongBasicBezierSpline : MonoBehaviour
	{
		public BasicBezierSpline curve;

		[Range(0f, 1f)]
		public float normalizedPositionAlongCurve;

		private void Update()
		{
			if ((bool)curve)
			{
				base.transform.position = curve.Evaluate(normalizedPositionAlongCurve);
			}
		}
	}
	[RequireComponent(typeof(Camera))]
	[RequireComponent(typeof(SceneCamera))]
	public class OutlineHighlight : MonoBehaviour
	{
		private enum Passes
		{
			FillPass,
			Blit
		}

		public enum RTResolution
		{
			Quarter = 4,
			Half = 2,
			Full = 1
		}

		public struct HighlightInfo
		{
			public UnityEngine.Color color;

			public Renderer renderer;
		}

		public RTResolution m_resolution = RTResolution.Full;

		public readonly Queue<HighlightInfo> highlightQueue = new Queue<HighlightInfo>();

		private Material highlightMaterial;

		private CommandBuffer commandBuffer;

		private int m_RTWidth = 512;

		private int m_RTHeight = 512;

		public Material outlineMaterial;

		public Material outlineMaterial_Skinned;

		public static Action<OutlineHighlight> onPreRenderOutlineHighlight;

		public SceneCamera sceneCamera { get; private set; }

		private void InitOutlineMaterials()
		{
		}

		private void Awake()
		{
			sceneCamera = GetComponent<SceneCamera>();
			CreateBuffers();
			CreateMaterials();
			m_RTWidth = (int)((float)Screen.width / (float)m_resolution);
			m_RTHeight = (int)((float)Screen.height / (float)m_resolution);
			InitOutlineMaterials();
		}

		private void CreateBuffers()
		{
			commandBuffer = new CommandBuffer();
		}

		private void ClearCommandBuffers()
		{
			commandBuffer.Clear();
		}

		private void CreateMaterials()
		{
			highlightMaterial = new Material(LegacyShaderAPI.Find("Hopoo Games/Internal/Outline Highlight"));
		}

		private void RenderHighlights(RenderTexture rt)
		{
			RenderTargetIdentifier renderTarget = new RenderTargetIdentifier(rt);
			commandBuffer.SetRenderTarget(renderTarget);
			foreach (Highlight readonlyHighlight in Highlight.readonlyHighlightList)
			{
				if (readonlyHighlight.isOn && (bool)readonlyHighlight.targetRenderer)
				{
					highlightQueue.Enqueue(new HighlightInfo
					{
						color = readonlyHighlight.GetColor() * readonlyHighlight.strength,
						renderer = readonlyHighlight.targetRenderer
					});
				}
			}
			onPreRenderOutlineHighlight?.Invoke(this);
			while (highlightQueue.Count > 0)
			{
				HighlightInfo highlightInfo = highlightQueue.Dequeue();
				if ((bool)highlightInfo.renderer)
				{
					highlightMaterial.SetColor("_Color", highlightInfo.color);
					commandBuffer.DrawRenderer(highlightInfo.renderer, highlightMaterial, 0, 0);
					RenderTexture.active = rt;
					Graphics.ExecuteCommandBuffer(commandBuffer);
					RenderTexture.active = null;
					ClearCommandBuffers();
				}
			}
		}

		private bool NeedsHighlight()
		{
			foreach (Highlight readonlyHighlight in Highlight.readonlyHighlightList)
			{
				if (readonlyHighlight.isOn && (bool)readonlyHighlight.targetRenderer)
				{
					return true;
				}
			}
			return false;
		}

		private void OnRenderImage(RenderTexture source, RenderTexture destination)
		{
			if (!NeedsHighlight())
			{
				Graphics.Blit(source, destination);
				return;
			}
			int width = (int)((float)destination.width / (float)m_resolution);
			int height = (int)((float)destination.height / (float)m_resolution);
			RenderTexture renderTexture = (RenderTexture.active = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.ARGB32));
			GL.Clear(clearDepth: true, clearColor: true, UnityEngine.Color.clear);
			RenderTexture.active = null;
			ClearCommandBuffers();
			RenderHighlights(renderTexture);
			highlightMaterial.SetTexture("_OutlineMap", renderTexture);
			highlightMaterial.SetColor("_Color", UnityEngine.Color.white);
			Graphics.Blit(source, destination, highlightMaterial, 1);
			RenderTexture.ReleaseTemporary(renderTexture);
		}
	}
	public class PostProcessDuration : MonoBehaviour
	{
		public PostProcessVolume ppVolume;

		public AnimationCurve ppWeightCurve;

		public float maxDuration;

		public bool destroyOnEnd;

		public bool useUnscaledTime;

		private float stopwatch;

		private void Update()
		{
			stopwatch += (useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime);
			UpdatePostProccess();
		}

		private void Awake()
		{
			UpdatePostProccess();
		}

		private void OnEnable()
		{
			stopwatch = 0f;
		}

		private void UpdatePostProccess()
		{
			float num = Mathf.Clamp01(stopwatch / maxDuration);
			ppVolume.weight = ppWeightCurve.Evaluate(num);
			PostProcessVolume.DispatchVolumeSettingsChangedEvent();
			if (num == 1f && destroyOnEnd)
			{
				UnityEngine.Object.Destroy(ppVolume.gameObject);
			}
		}

		private void OnValidate()
		{
			if (maxDuration <= Mathf.Epsilon)
			{
				UnityEngine.Debug.LogWarningFormat("{0} has PP of time zero!", base.gameObject);
			}
		}
	}
	[RequireComponent(typeof(NetworkRuleChoiceMask))]
	[RequireComponent(typeof(NetworkRuleBook))]
	public class PreGameController : NetworkBehaviour
	{
		private enum PregameState
		{
			Idle,
			Launching,
			Launched
		}

		public class GameModeConVar : BaseConVar
		{
			public static readonly GameModeConVar instance;

			public Run runPrefabComponent;

			public GameModeConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			static GameModeConVar()
			{
				instance = new GameModeConVar("gamemode", ConVarFlags.None, "ClassicRun", "Sets the specified game mode as the one to use in the next run.");
				GameModeCatalog.availability.CallWhenAvailable(delegate
				{
					instance.runPrefabComponent = GameModeCatalog.FindGameModePrefabComponent(instance.GetString());
				});
			}

			public override void SetString(string newValue)
			{
				GameModeCatalog.availability.CallWhenAvailable(delegate
				{
					Run run = GameModeCatalog.FindGameModePrefabComponent(newValue);
					if (!run)
					{
						UnityEngine.Debug.LogFormat("GameMode \"{0}\" does not exist.", newValue);
					}
					else
					{
						runPrefabComponent = run;
					}
				});
			}

			public override string GetString()
			{
				if (!runPrefabComponent)
				{
					return "ClassicRun";
				}
				return runPrefabComponent.gameObject.name;
			}
		}

		private NetworkRuleChoiceMask networkRuleChoiceMaskComponent;

		private NetworkRuleBook networkRuleBookComponent;

		private RuleChoiceMask serverAvailableChoiceMask;

		public ulong runSeed;

		public static readonly IntConVar overrideRunSeed;

		[SyncVar(hook = "UpdateGameModeIndex")]
		private int _gameModeIndex;

		private GameObject lobbyBackground;

		private int currentLobbyBackgroundGameModeIndex;

		private float lobbyBackgroundTimeToRefresh;

		private const float lobbyBackgroundTimeToRefreshInterval = 4f;

		private RuleBook ruleBookBuffer;

		[SyncVar]
		private int pregameStateInternal;

		private const float launchTransitionDuration = 0f;

		private GameObject gameModePrefab;

		[SyncVar]
		private float launchStartTime = float.PositiveInfinity;

		private RuleChoiceMask unlockedChoiceMask;

		private RuleChoiceMask dependencyChoiceMask;

		private RuleChoiceMask entitlementChoiceMask;

		private RuleChoiceMask requiredExpansionEnabledChoiceMask;

		private RuleChoiceMask choiceMaskBuffer;

		public static readonly BoolConVar cvSvAllowRuleVoting;

		public static readonly BoolConVar cvSvAllowMultiplayerPause;

		private static int kRpcRpcUpdateGameModeIndex;

		private static int kRpcRpcUpdateMultiplayerPause;

		public static PreGameController instance { get; private set; }

		public RuleChoiceMask resolvedRuleChoiceMask => networkRuleChoiceMaskComponent.ruleChoiceMask;

		public RuleBook readOnlyRuleBook => networkRuleBookComponent.ruleBook;

		public GameModeIndex gameModeIndex
		{
			get
			{
				return (GameModeIndex)_gameModeIndex;
			}
			set
			{
				Network_gameModeIndex = (int)value;
			}
		}

		private PregameState pregameState
		{
			get
			{
				return (PregameState)pregameStateInternal;
			}
			set
			{
				NetworkpregameStateInternal = (int)value;
			}
		}

		public int Network_gameModeIndex
		{
			get
			{
				return _gameModeIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					UpdateGameModeIndex(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref _gameModeIndex, 1u);
			}
		}

		public int NetworkpregameStateInternal
		{
			get
			{
				return pregameStateInternal;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref pregameStateInternal, 2u);
			}
		}

		public float NetworklaunchStartTime
		{
			get
			{
				return launchStartTime;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref launchStartTime, 4u);
			}
		}

		public static event Action<PreGameController, RuleBook> onPreGameControllerSetRuleBookServerGlobal;

		public static event Action<PreGameController, RuleBook> onPreGameControllerSetRuleBookGlobal;

		public static event Action<PreGameController> onServerRecalculatedModifierAvailability;

		private void Awake()
		{
			lobbyBackgroundTimeToRefresh = 0f;
			networkRuleChoiceMaskComponent = GetComponent<NetworkRuleChoiceMask>();
			networkRuleBookComponent = GetComponent<NetworkRuleBook>();
			networkRuleBookComponent.onRuleBookUpdated += OnRuleBookUpdated;
			ruleBookBuffer = new RuleBook();
			serverAvailableChoiceMask = new RuleChoiceMask();
			unlockedChoiceMask = new RuleChoiceMask();
			dependencyChoiceMask = new RuleChoiceMask();
			entitlementChoiceMask = new RuleChoiceMask();
			choiceMaskBuffer = new RuleChoiceMask();
			requiredExpansionEnabledChoiceMask = new RuleChoiceMask();
			if (NetworkServer.active)
			{
				gameModeIndex = GameModeCatalog.FindGameModeIndex(GameModeConVar.instance.GetString());
				runSeed = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex).GenerateSeedForNewRun();
			}
			bool isInSinglePlayer = RoR2Application.isInSinglePlayer;
			for (int i = 0; i < serverAvailableChoiceMask.length; i++)
			{
				RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(i);
				serverAvailableChoiceMask[i] = (isInSinglePlayer ? choiceDef.availableInSinglePlayer : choiceDef.availableInMultiPlayer);
			}
			NetworkUser.OnPostNetworkUserStart += GenerateRuleVoteController;
			RefreshLobbyBackground();
		}

		private void OnDestroy()
		{
			NetworkUser.OnPostNetworkUserStart -= GenerateRuleVoteController;
		}

		private void GenerateRuleVoteController(NetworkUser networkUser)
		{
			if (NetworkServer.active && !PreGameRuleVoteController.FindForUser(networkUser) && (networkUser.isLocalPlayer || cvSvAllowRuleVoting.value))
			{
				PreGameRuleVoteController.CreateForNetworkUserServer(networkUser);
			}
		}

		private void Start()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			ResolveChoiceMask();
			Console.instance.SubmitCmd(null, "exec server_pregame");
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				UnityEngine.Debug.LogFormat("Attempting to generate PreGameVoteController for {0}", readOnlyInstances.userName);
				GenerateRuleVoteController(readOnlyInstances);
				readOnlyInstances.BumpDLCChecker();
			}
		}

		[Server]
		public bool ApplyChoice(int ruleChoiceIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.PreGameController::ApplyChoice(System.Int32)' called on client");
				return false;
			}
			if (!resolvedRuleChoiceMask[ruleChoiceIndex])
			{
				return false;
			}
			RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(ruleChoiceIndex);
			if (readOnlyRuleBook.GetRuleChoice(choiceDef.ruleDef.globalIndex) == choiceDef)
			{
				return false;
			}
			ruleBookBuffer.Copy(readOnlyRuleBook);
			ruleBookBuffer.ApplyChoice(choiceDef);
			SetRuleBook(ruleBookBuffer);
			return true;
		}

		private void SetRuleBook(RuleBook newRuleBook)
		{
			networkRuleBookComponent.SetRuleBook(newRuleBook);
			PreGameController.onPreGameControllerSetRuleBookServerGlobal?.Invoke(this, readOnlyRuleBook);
		}

		private void OnRuleBookUpdated(NetworkRuleBook networkRuleBookComponent)
		{
			PreGameController.onPreGameControllerSetRuleBookGlobal?.Invoke(this, networkRuleBookComponent.ruleBook);
		}

		[Server]
		public void EnforceValidRuleChoices()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::EnforceValidRuleChoices()' called on client");
				return;
			}
			ruleBookBuffer.Copy(readOnlyRuleBook);
			for (int i = 0; i < RuleCatalog.ruleCount; i++)
			{
				RuleChoiceDef ruleChoice = ruleBookBuffer.GetRuleChoice(i);
				if (resolvedRuleChoiceMask[ruleChoice])
				{
					continue;
				}
				RuleDef ruleDef = RuleCatalog.GetRuleDef(i);
				RuleChoiceDef choiceDef = ruleDef.choices[ruleDef.defaultChoiceIndex];
				int num = 0;
				int j = 0;
				for (int count = ruleDef.choices.Count; j < count; j++)
				{
					if (resolvedRuleChoiceMask[ruleDef.choices[j]])
					{
						num++;
					}
				}
				if (resolvedRuleChoiceMask[choiceDef] || num == 0)
				{
					ruleBookBuffer.ApplyChoice(choiceDef);
					continue;
				}
				int k = 0;
				for (int count2 = ruleDef.choices.Count; k < count2; k++)
				{
					if (resolvedRuleChoiceMask[ruleDef.choices[k]])
					{
						ruleBookBuffer.ApplyChoice(ruleDef.choices[k]);
						break;
					}
				}
			}
			SetRuleBook(ruleBookBuffer);
		}

		private void TestRuleValues()
		{
			RuleBook ruleBook = new RuleBook();
			ruleBook.Copy(networkRuleBookComponent.ruleBook);
			RuleDef ruleDef = RuleCatalog.GetRuleDef(UnityEngine.Random.Range(0, RuleCatalog.ruleCount));
			RuleChoiceDef choiceDef = ruleDef.choices[UnityEngine.Random.Range(0, ruleDef.choices.Count)];
			ruleBook.ApplyChoice(choiceDef);
			SetRuleBook(ruleBook);
			Invoke("TestRuleValues", 0.5f);
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			PauseManager.isPaused = false;
			PauseStopController.instance?.ForceClientUnpause();
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			if (NetworkServer.active)
			{
				RecalculateModifierAvailability();
			}
			NetworkUser.OnNetworkUserUnlockablesUpdated += OnNetworkUserUnlockablesUpdatedCallback;
			NetworkUser.OnPostNetworkUserStart += OnPostNetworkUserStartCallback;
			NetworkUser.onNetworkUserBodyPreferenceChanged += OnNetworkUserBodyPreferenceChanged;
			NetworkUser.onNetworkUserLost += OnNetworkUserLost;
			if (NetworkClient.active)
			{
				foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
				{
					readOnlyLocalPlayers.SendServerUnlockables();
				}
			}
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				readOnlyInstances.ServerRequestUnlockables();
			}
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			NetworkUser.OnPostNetworkUserStart -= OnPostNetworkUserStartCallback;
			NetworkUser.OnNetworkUserUnlockablesUpdated -= OnNetworkUserUnlockablesUpdatedCallback;
			NetworkUser.onNetworkUserBodyPreferenceChanged -= OnNetworkUserBodyPreferenceChanged;
			NetworkUser.onNetworkUserLost -= OnNetworkUserLost;
		}

		public bool IsCharacterSwitchingCurrentlyAllowed()
		{
			return pregameState == PregameState.Idle;
		}

		private void Update()
		{
			if (pregameState == PregameState.Launching)
			{
				if (PlatformSystems.networkManager.unpredictedServerFixedTime - launchStartTime >= 0.5f && NetworkServer.active)
				{
					StartRun();
				}
			}
			else
			{
				_ = pregameState;
				_ = 2;
			}
			if (NetworkServer.active)
			{
				lobbyBackgroundTimeToRefresh -= Time.deltaTime;
				if (lobbyBackgroundTimeToRefresh <= 0f)
				{
					lobbyBackgroundTimeToRefresh = 4f;
					CallRpcUpdateGameModeIndex(_gameModeIndex);
					CallRpcUpdateMultiplayerPause(cvSvAllowMultiplayerPause.value);
				}
			}
		}

		[Server]
		public void StartLaunch()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::StartLaunch()' called on client");
			}
			else if (pregameState == PregameState.Idle)
			{
				pregameState = PregameState.Launching;
				NetworklaunchStartTime = PlatformSystems.networkManager.unpredictedServerFixedTime;
			}
		}

		[Server]
		private void StartRun()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::StartRun()' called on client");
				return;
			}
			ExpansionRequirementComponent component = GameModeConVar.instance.runPrefabComponent.GetComponent<ExpansionRequirementComponent>();
			if (!component || !component.requiredExpansion || EntitlementManager.networkUserEntitlementTracker.AnyUserHasEntitlement(component.requiredExpansion.requiredEntitlement))
			{
				pregameState = PregameState.Launched;
				NetworkSession.instance.BeginRun(GameModeConVar.instance.runPrefabComponent, readOnlyRuleBook, runSeed);
			}
		}

		[ConCommand(commandName = "pregame_start_run", flags = ConVarFlags.SenderMustBeServer, helpText = "Begins a run out of pregame.")]
		private static void CCPregameStartRun(ConCommandArgs args)
		{
			if ((bool)instance)
			{
				instance.StartRun();
			}
		}

		private static bool AnyUserHasUnlockable([NotNull] UnlockableDef unlockableDef)
		{
			ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				if (readOnlyInstancesList[i].unlockables.Contains(unlockableDef))
				{
					return true;
				}
			}
			return false;
		}

		[ContextMenu("RecalculateModifierAvailability")]
		[Server]
		public void RecalculateModifierAvailability()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::RecalculateModifierAvailability()' called on client");
				return;
			}
			for (int i = 0; i < RuleCatalog.choiceCount; i++)
			{
				RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(i);
				unlockedChoiceMask[i] = !choiceDef.requiredUnlockable || AnyUserHasUnlockable(choiceDef.requiredUnlockable);
				dependencyChoiceMask[i] = choiceDef.requiredChoiceDef == null || readOnlyRuleBook.IsChoiceActive(choiceDef.requiredChoiceDef);
				entitlementChoiceMask[i] = !choiceDef.requiredEntitlementDef || EntitlementManager.networkUserEntitlementTracker.AnyUserHasEntitlement(choiceDef.requiredEntitlementDef) || EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(choiceDef.requiredEntitlementDef);
				requiredExpansionEnabledChoiceMask[i] = !choiceDef.requiredExpansionDef || readOnlyRuleBook.IsChoiceActive(choiceDef.requiredExpansionDef.enabledChoice);
			}
			ResolveChoiceMask();
			PreGameController.onServerRecalculatedModifierAvailability?.Invoke(this);
		}

		[Server]
		private void ResolveChoiceMask()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PreGameController::ResolveChoiceMask()' called on client");
				return;
			}
			RuleChoiceMask ruleChoiceMask = new RuleChoiceMask();
			RuleChoiceMask ruleChoiceMask2 = new RuleChoiceMask();
			Run gameModePrefabComponent = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex);
			if ((bool)gameModePrefabComponent)
			{
				if (overrideRunSeed.value != -1)
				{
					runSeed = (ulong)overrideRunSeed.value;
				}
				gameModePrefabComponent.OverrideRuleChoices(ruleChoiceMask, ruleChoiceMask2, runSeed);
			}
			for (int i = 0; i < choiceMaskBuffer.length; i++)
			{
				RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(i);
				bool flag = ruleChoiceMask[i];
				bool flag2 = ruleChoiceMask2[i];
				bool flag3 = serverAvailableChoiceMask[i];
				bool flag4 = unlockedChoiceMask[i];
				bool flag5 = dependencyChoiceMask[i];
				bool flag6 = entitlementChoiceMask[i];
				bool flag7 = requiredExpansionEnabledChoiceMask[i];
				choiceMaskBuffer[i] = flag || (!flag2 && flag3 && flag4 && flag5 && flag6 && flag7 && !choiceDef.excludeByDefault);
			}
			networkRuleChoiceMaskComponent.SetRuleChoiceMask(choiceMaskBuffer);
			EnforceValidRuleChoices();
		}

		private void OnNetworkUserUnlockablesUpdatedCallback(NetworkUser networkUser)
		{
			if (NetworkServer.active)
			{
				RecalculateModifierAvailability();
			}
		}

		private void OnPostNetworkUserStartCallback(NetworkUser networkUser)
		{
			if (NetworkServer.active)
			{
				networkUser.ServerRequestUnlockables();
			}
		}

		private void OnNetworkUserBodyPreferenceChanged(NetworkUser networkUser)
		{
			if (NetworkServer.active)
			{
				RecalculateModifierAvailability();
			}
		}

		private void OnNetworkUserLost(NetworkUser networkUser)
		{
			if (NetworkServer.active)
			{
				RecalculateModifierAvailability();
			}
		}

		private void UpdateGameModeIndex(int newIndex)
		{
			if (newIndex != currentLobbyBackgroundGameModeIndex)
			{
				Network_gameModeIndex = newIndex;
				RefreshLobbyBackground();
			}
		}

		private void UpdateMultiplayerPause(bool newBool)
		{
			if ((bool)PauseStopController.instance)
			{
				PauseStopController.instance.allowMultiplayerPause = newBool;
			}
		}

		[ClientRpc]
		private void RpcUpdateGameModeIndex(int newIndex)
		{
			UpdateGameModeIndex(newIndex);
		}

		[ClientRpc]
		private void RpcUpdateMultiplayerPause(bool newBool)
		{
			UpdateMultiplayerPause(newBool);
		}

		private void RefreshLobbyBackground()
		{
			if ((bool)lobbyBackground)
			{
				UnityEngine.Object.Destroy(lobbyBackground);
			}
			currentLobbyBackgroundGameModeIndex = _gameModeIndex;
			lobbyBackground = UnityEngine.Object.Instantiate(GameModeCatalog.GetGameModePrefabComponent(gameModeIndex).lobbyBackgroundPrefab);
		}

		[ConCommand(commandName = "pregame_set_rule_choice", flags = ConVarFlags.SenderMustBeServer, helpText = "Sets the specified choice during pregame. See the command \"rule_list_choices\" for possible options.")]
		public static void CCPregameSetRuleChoice(ConCommandArgs args)
		{
			string argString = args.GetArgString(0);
			RuleChoiceDef ruleChoiceDef = RuleCatalog.FindChoiceDef(argString);
			if (ruleChoiceDef == null)
			{
				throw new ConCommandException($"'{argString}' is not a recognized rule choice name.");
			}
			if (!instance)
			{
				throw new ConCommandException("This command cannot be issued outside the character select screen.");
			}
			if (instance.ApplyChoice(ruleChoiceDef.globalIndex))
			{
				instance.RecalculateModifierAvailability();
			}
		}

		static PreGameController()
		{
			overrideRunSeed = new IntConVar("override_run_seed", ConVarFlags.None, "-1", "Forces a default seed for benchmarking.");
			cvSvAllowRuleVoting = new BoolConVar("sv_allow_rule_voting", ConVarFlags.None, "1", "Whether or not players are allowed to vote on rules.");
			cvSvAllowMultiplayerPause = new BoolConVar("sv_allow_multiplayer_pause", ConVarFlags.None, "0", "Whether or not players are allowed to pause the multiplayer game.");
			kRpcRpcUpdateGameModeIndex = -600953683;
			NetworkBehaviour.RegisterRpcDelegate(typeof(PreGameController), kRpcRpcUpdateGameModeIndex, InvokeRpcRpcUpdateGameModeIndex);
			kRpcRpcUpdateMultiplayerPause = 2048931628;
			NetworkBehaviour.RegisterRpcDelegate(typeof(PreGameController), kRpcRpcUpdateMultiplayerPause, InvokeRpcRpcUpdateMultiplayerPause);
			NetworkCRC.RegisterBehaviour("PreGameController", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcUpdateGameModeIndex(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcUpdateGameModeIndex called on server.");
			}
			else
			{
				((PreGameController)obj).RpcUpdateGameModeIndex((int)reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeRpcRpcUpdateMultiplayerPause(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcUpdateMultiplayerPause called on server.");
			}
			else
			{
				((PreGameController)obj).RpcUpdateMultiplayerPause(reader.ReadBoolean());
			}
		}

		public void CallRpcUpdateGameModeIndex(int newIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcUpdateGameModeIndex called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcUpdateGameModeIndex);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)newIndex);
			SendRPCInternal(networkWriter, 0, "RpcUpdateGameModeIndex");
		}

		public void CallRpcUpdateMultiplayerPause(bool newBool)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcUpdateMultiplayerPause called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcUpdateMultiplayerPause);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(newBool);
			SendRPCInternal(networkWriter, 0, "RpcUpdateMultiplayerPause");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)_gameModeIndex);
				writer.WritePackedUInt32((uint)pregameStateInternal);
				writer.Write(launchStartTime);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)_gameModeIndex);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)pregameStateInternal);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(launchStartTime);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_gameModeIndex = (int)reader.ReadPackedUInt32();
				pregameStateInternal = (int)reader.ReadPackedUInt32();
				launchStartTime = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				UpdateGameModeIndex((int)reader.ReadPackedUInt32());
			}
			if (((uint)num & 2u) != 0)
			{
				pregameStateInternal = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 4u) != 0)
			{
				launchStartTime = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class PreGameRuleVoteController : NetworkBehaviour
	{
		private static class LocalUserBallotPersistenceManager
		{
			private static readonly Dictionary<LocalUser, Vote[]> votesCache;

			static LocalUserBallotPersistenceManager()
			{
				votesCache = new Dictionary<LocalUser, Vote[]>();
				LocalUserManager.onUserSignIn += OnLocalUserSignIn;
				LocalUserManager.onUserSignOut += OnLocalUserSignOut;
				onVotesUpdated += OnVotesUpdated;
			}

			private static void OnLocalUserSignIn(LocalUser localUser)
			{
				votesCache.Add(localUser, null);
			}

			private static void OnLocalUserSignOut(LocalUser localUser)
			{
				votesCache.Remove(localUser);
			}

			private static void OnVotesUpdated()
			{
				foreach (PreGameRuleVoteController instances in instancesList)
				{
					if (instances.localUser != null)
					{
						votesCache[instances.localUser] = instances.votes;
					}
				}
			}

			public static void ApplyPersistentBallotIfPresent(LocalUser localUser, Vote[] dest)
			{
				if (votesCache.TryGetValue(localUser, out var value) && value != null)
				{
					UnityEngine.Debug.LogFormat("Applying persistent ballot of votes for LocalUser {0}.", localUser.userProfile.name);
					Array.Copy(value, dest, value.Length);
				}
			}
		}

		[Serializable]
		private struct Vote
		{
			[SerializeField]
			private byte internalValue;

			public bool hasVoted => internalValue != 0;

			public int choiceValue
			{
				get
				{
					return internalValue - 1;
				}
				set
				{
					internalValue = (byte)(value + 1);
				}
			}

			public static void Serialize(NetworkWriter writer, Vote vote)
			{
				writer.Write(vote.internalValue);
			}

			public static Vote Deserialize(NetworkReader reader)
			{
				Vote result = default(Vote);
				result.internalValue = reader.ReadByte();
				return result;
			}
		}

		private static readonly List<PreGameRuleVoteController> instancesList;

		private const byte networkUserIdentityDirtyBit = 1;

		private const byte votesDirtyBit = 2;

		private const byte allDirtyBits = 3;

		private Vote[] votes = CreateBallot();

		public static int[] votesForEachChoice;

		private bool clientShouldTransmit;

		private NetworkUser networkUser;

		private static bool shouldUpdateGameVotes;

		private readonly RuleMask ruleMaskBuffer = new RuleMask();

		public NetworkIdentity networkUserNetworkIdentity { get; private set; }

		private LocalUser localUser => networkUser?.localUser;

		public static event Action onVotesUpdated;

		public static PreGameRuleVoteController FindForUser(NetworkUser networkUser)
		{
			GameObject gameObject = networkUser.gameObject;
			foreach (PreGameRuleVoteController instances in instancesList)
			{
				if ((bool)instances.networkUserNetworkIdentity && instances.networkUserNetworkIdentity.gameObject == gameObject)
				{
					return instances;
				}
			}
			return null;
		}

		public static void CreateForNetworkUserServer(NetworkUser networkUser)
		{
			GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/PreGameRuleVoteController"));
			PreGameRuleVoteController component = obj.GetComponent<PreGameRuleVoteController>();
			component.networkUserNetworkIdentity = networkUser.GetComponent<NetworkIdentity>();
			component.networkUser = networkUser;
			NetworkServer.Spawn(obj);
		}

		private static Vote[] CreateBallot()
		{
			return new Vote[RuleCatalog.ruleCount];
		}

		[SystemInitializer(new Type[] { typeof(RuleCatalog) })]
		private static void Init()
		{
			votesForEachChoice = new int[RuleCatalog.choiceCount];
		}

		private void Start()
		{
			if (localUser != null)
			{
				LocalUserBallotPersistenceManager.ApplyPersistentBallotIfPresent(localUser, votes);
				ClientTransmitVotesToServer();
			}
			if (NetworkServer.active)
			{
				UpdateGameVotes();
			}
		}

		private void Update()
		{
			if (NetworkServer.active && !networkUserNetworkIdentity)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			if (clientShouldTransmit)
			{
				clientShouldTransmit = false;
				ClientTransmitVotesToServer();
			}
			if (shouldUpdateGameVotes)
			{
				shouldUpdateGameVotes = false;
				UpdateGameVotes();
			}
		}

		[Client]
		private void ClientTransmitVotesToServer()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.PreGameRuleVoteController::ClientTransmitVotesToServer()' called on server");
			}
			else if ((bool)networkUserNetworkIdentity)
			{
				NetworkUser component = networkUserNetworkIdentity.GetComponent<NetworkUser>();
				if ((bool)component)
				{
					NetworkWriter networkWriter = new NetworkWriter();
					networkWriter.StartMessage(70);
					networkWriter.Write(base.gameObject);
					WriteVotes(networkWriter);
					networkWriter.FinishMessage();
					component.connectionToServer.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
				}
			}
		}

		[NetworkMessageHandler(msgType = 70, client = false, server = true)]
		public static void ServerHandleClientVoteUpdate(NetworkMessage netMsg)
		{
			UnityEngine.Debug.LogFormat("Received vote from {0}", NetworkUser.readOnlyInstancesList.FirstOrDefault((NetworkUser v) => v.connectionToClient == netMsg.conn)?.userName);
			GameObject gameObject = netMsg.reader.ReadGameObject();
			if (!gameObject)
			{
				return;
			}
			PreGameRuleVoteController component = gameObject.GetComponent<PreGameRuleVoteController>();
			if (!component)
			{
				return;
			}
			NetworkIdentity networkIdentity = component.networkUserNetworkIdentity;
			if (!networkIdentity)
			{
				return;
			}
			NetworkUser component2 = networkIdentity.GetComponent<NetworkUser>();
			if ((bool)component2)
			{
				if (component2.connectionToClient != netMsg.conn)
				{
					UnityEngine.Debug.LogFormat("PreGameRuleVoteController.ServerHandleClientVoteUpdate() failed: {0}!={1}", component.connectionToClient, netMsg.conn);
				}
				else
				{
					UnityEngine.Debug.LogFormat("Accepting vote from {0}", component2.userName);
					component.ReadVotes(netMsg.reader);
				}
			}
		}

		public void SetVote(int ruleIndex, int choiceValue)
		{
			Vote vote = votes[ruleIndex];
			if (vote.choiceValue != choiceValue)
			{
				votes[ruleIndex].choiceValue = choiceValue;
				if (!NetworkServer.active && (bool)networkUserNetworkIdentity && networkUserNetworkIdentity.isLocalPlayer)
				{
					clientShouldTransmit = true;
				}
				else
				{
					SetDirtyBit(2u);
				}
				shouldUpdateGameVotes = true;
			}
		}

		private static void UpdateGameVotes()
		{
			int i = 0;
			for (int choiceCount = RuleCatalog.choiceCount; i < choiceCount; i++)
			{
				votesForEachChoice[i] = 0;
			}
			int j = 0;
			for (int ruleCount = RuleCatalog.ruleCount; j < ruleCount; j++)
			{
				RuleDef ruleDef = RuleCatalog.GetRuleDef(j);
				int count = ruleDef.choices.Count;
				foreach (PreGameRuleVoteController instances in instancesList)
				{
					Vote vote = instances.votes[j];
					if (vote.hasVoted && vote.choiceValue < count)
					{
						RuleChoiceDef ruleChoiceDef = ruleDef.choices[vote.choiceValue];
						votesForEachChoice[ruleChoiceDef.globalIndex]++;
					}
				}
			}
			if (NetworkServer.active)
			{
				bool flag = false;
				int k = 0;
				for (int ruleCount2 = RuleCatalog.ruleCount; k < ruleCount2; k++)
				{
					RuleDef ruleDef2 = RuleCatalog.GetRuleDef(k);
					int count2 = ruleDef2.choices.Count;
					PreGameController.instance.readOnlyRuleBook.GetRuleChoiceIndex(ruleDef2);
					int ruleChoiceIndex = -1;
					int num = 0;
					bool flag2 = false;
					for (int l = 0; l < count2; l++)
					{
						RuleChoiceDef ruleChoiceDef2 = ruleDef2.choices[l];
						int num2 = votesForEachChoice[ruleChoiceDef2.globalIndex];
						if (num2 == num)
						{
							flag2 = true;
						}
						else if (num2 > num)
						{
							ruleChoiceIndex = ruleChoiceDef2.globalIndex;
							num = num2;
							flag2 = false;
						}
					}
					if (num == 0)
					{
						ruleChoiceIndex = ruleDef2.choices[ruleDef2.defaultChoiceIndex].globalIndex;
					}
					if (!flag2 || num == 0)
					{
						flag = PreGameController.instance.ApplyChoice(ruleChoiceIndex) || flag;
					}
				}
				if (flag)
				{
					PreGameController.instance.RecalculateModifierAvailability();
				}
			}
			PreGameRuleVoteController.onVotesUpdated?.Invoke();
		}

		private void Awake()
		{
			instancesList.Add(this);
		}

		private void OnDestroy()
		{
			shouldUpdateGameVotes = true;
			instancesList.Remove(this);
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 3u;
			}
			writer.Write((byte)num);
			bool num2 = (num & 1) != 0;
			bool flag = (num & 2) != 0;
			if (num2)
			{
				writer.Write(networkUserNetworkIdentity);
			}
			if (flag)
			{
				WriteVotes(writer);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			byte num = reader.ReadByte();
			bool flag = (num & 1) != 0;
			bool num2 = (num & 2) != 0;
			if (flag)
			{
				networkUserNetworkIdentity = reader.ReadNetworkIdentity();
				networkUser = (networkUserNetworkIdentity ? networkUserNetworkIdentity.GetComponent<NetworkUser>() : null);
			}
			if (num2)
			{
				ReadVotes(reader);
			}
		}

		private RuleChoiceDef GetDefaultChoice(RuleDef ruleDef)
		{
			return ruleDef.choices[PreGameController.instance.readOnlyRuleBook.GetRuleChoiceIndex(ruleDef)];
		}

		private void SetVotesFromRuleBookForSinglePlayer()
		{
			for (int i = 0; i < votes.Length; i++)
			{
				RuleDef ruleDef = RuleCatalog.GetRuleDef(i);
				votes[i].choiceValue = GetDefaultChoice(ruleDef).localIndex;
			}
			SetDirtyBit(2u);
		}

		private void WriteVotes(NetworkWriter writer)
		{
			int i = 0;
			for (int ruleCount = RuleCatalog.ruleCount; i < ruleCount; i++)
			{
				ruleMaskBuffer[i] = votes[i].hasVoted;
			}
			writer.Write(ruleMaskBuffer);
			int j = 0;
			for (int ruleCount2 = RuleCatalog.ruleCount; j < ruleCount2; j++)
			{
				if (votes[j].hasVoted)
				{
					Vote.Serialize(writer, votes[j]);
				}
			}
		}

		private void ReadVotes(NetworkReader reader)
		{
			reader.ReadRuleMask(ruleMaskBuffer);
			bool flag = !networkUserNetworkIdentity || !networkUserNetworkIdentity.isLocalPlayer;
			int i = 0;
			for (int ruleCount = RuleCatalog.ruleCount; i < ruleCount; i++)
			{
				Vote vote = ((!ruleMaskBuffer[i]) ? default(Vote) : Vote.Deserialize(reader));
				if (flag)
				{
					votes[i] = vote;
				}
			}
			shouldUpdateGameVotes |= flag;
			if (NetworkServer.active)
			{
				SetDirtyBit(2u);
			}
		}

		public bool IsChoiceVoted(RuleChoiceDef ruleChoiceDef)
		{
			return votes[ruleChoiceDef.ruleDef.globalIndex].choiceValue == ruleChoiceDef.localIndex;
		}

		static PreGameRuleVoteController()
		{
			instancesList = new List<PreGameRuleVoteController>();
			PreGameController.onServerRecalculatedModifierAvailability += delegate
			{
				UpdateGameVotes();
			};
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class PreGameShakeController : MonoBehaviour
	{
		public ShakeEmitter shakeEmitter;

		public float minInterval = 0.5f;

		public float maxInterval = 7f;

		public Rigidbody[] physicsBodies;

		public float physicsForce;

		private float timer;

		private void ResetTimer()
		{
			timer = UnityEngine.Random.Range(minInterval, maxInterval);
		}

		private void DoShake()
		{
			shakeEmitter.StartShake();
			UnityEngine.Vector3 onUnitSphere = UnityEngine.Random.onUnitSphere;
			Rigidbody[] array = physicsBodies;
			foreach (Rigidbody rigidbody in array)
			{
				if ((bool)rigidbody)
				{
					UnityEngine.Vector3 force = onUnitSphere * ((0.75f + UnityEngine.Random.value * 0.25f) * physicsForce);
					float y = rigidbody.GetComponent<Collider>().bounds.min.y;
					UnityEngine.Vector3 centerOfMass = rigidbody.centerOfMass;
					centerOfMass.y = y;
					rigidbody.AddForceAtPosition(force, centerOfMass);
				}
			}
		}

		private void Awake()
		{
			ResetTimer();
		}

		private void Update()
		{
			timer -= Time.deltaTime;
			if (timer <= 0f)
			{
				ResetTimer();
				DoShake();
			}
		}
	}
	public class PressurePlateController : MonoBehaviour
	{
		public bool enableOverlapSphere = true;

		public float overlapSphereRadius;

		public float overlapSphereFrequency;

		public string switchDownSoundString;

		public string switchUpSoundString;

		public UnityEvent OnSwitchDown;

		public UnityEvent OnSwitchUp;

		public Collider pingCollider;

		public AnimationCurve switchVisualPositionFromUpToDown;

		public AnimationCurve switchVisualPositionFromDownToUp;

		public Transform switchVisualTransform;

		private float overlapSphereStopwatch;

		private float animationStopwatch;

		private bool switchDown;

		private void Start()
		{
		}

		private void FixedUpdate()
		{
			if (enableOverlapSphere)
			{
				overlapSphereStopwatch += Time.fixedDeltaTime;
				if (overlapSphereStopwatch >= 1f / overlapSphereFrequency)
				{
					overlapSphereStopwatch -= 1f / overlapSphereFrequency;
					bool @switch = HGPhysics.DoesOverlapSphere(base.transform.position, overlapSphereRadius, (int)LayerIndex.CommonMasks.characterBodiesOrDefault | (int)LayerIndex.CommonMasks.fakeActorLayers);
					SetSwitch(@switch);
				}
			}
		}

		public void EnableOverlapSphere(bool input)
		{
			enableOverlapSphere = input;
		}

		public void SetSwitch(bool switchIsDown)
		{
			if (switchIsDown != switchDown)
			{
				if (switchIsDown)
				{
					animationStopwatch = 0f;
					Util.PlaySound(switchDownSoundString, base.gameObject);
					OnSwitchDown?.Invoke();
				}
				else
				{
					animationStopwatch = 0f;
					Util.PlaySound(switchUpSoundString, base.gameObject);
					OnSwitchUp?.Invoke();
				}
				switchDown = switchIsDown;
			}
		}

		private void Update()
		{
			animationStopwatch += Time.deltaTime;
			if ((bool)switchVisualTransform)
			{
				UnityEngine.Vector3 localPosition = switchVisualTransform.transform.localPosition;
				if (switchDown)
				{
					localPosition.z = switchVisualPositionFromUpToDown.Evaluate(animationStopwatch);
				}
				else
				{
					localPosition.z = switchVisualPositionFromDownToUp.Evaluate(animationStopwatch);
				}
				switchVisualTransform.localPosition = localPosition;
			}
		}

		private void OnDrawGizmos()
		{
			Gizmos.DrawWireSphere(base.transform.position, overlapSphereRadius);
		}
	}
	public class PrintController : MonoBehaviour
	{
		private struct RendererMaterialPair
		{
			public readonly Renderer renderer;

			public readonly Material material;

			public RendererMaterialPair(Renderer renderer, Material material)
			{
				this.renderer = renderer;
				this.material = material;
			}
		}

		[Header("Print Time and Behaviors")]
		public float printTime;

		public AnimationCurve printCurve;

		public float age;

		public bool disableWhenFinished = true;

		public bool paused;

		[Header("Print Start/End Values")]
		public float startingPrintHeight;

		public float maxPrintHeight;

		public float startingPrintBias;

		public float maxPrintBias;

		public bool animateFlowmapPower;

		public float startingFlowmapPower;

		public float maxFlowmapPower;

		private CharacterModel characterModel;

		private MaterialPropertyBlock _propBlock;

		private RendererMaterialPair[] rendererMaterialPairs = Array.Empty<RendererMaterialPair>();

		private bool hasSetupOnce;

		private static Shader printShader;

		private static int sliceHeightShaderPropertyId;

		private static int printBiasShaderPropertyId;

		private static int flowHeightPowerShaderPropertyId;

		private static int printOnPropertyId;

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<Shader> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Shader>("Shaders/Deferred/HGStandard");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Shader> x)
			{
				printShader = x.Result;
			};
			sliceHeightShaderPropertyId = Shader.PropertyToID("_SliceHeight");
			printBiasShaderPropertyId = Shader.PropertyToID("_PrintBias");
			flowHeightPowerShaderPropertyId = Shader.PropertyToID("_FlowHeightPower");
			printOnPropertyId = Shader.PropertyToID("_PrintOn");
		}

		private void Awake()
		{
			characterModel = GetComponent<CharacterModel>();
			_propBlock = new MaterialPropertyBlock();
			SetupPrint();
		}

		private void OnDisable()
		{
			SetMaterialPrintCutoffEnabled(shouldEnable: false);
		}

		private void OnEnable()
		{
			SetMaterialPrintCutoffEnabled(shouldEnable: true);
			age = 0f;
		}

		private void Update()
		{
			UpdatePrint(Time.deltaTime);
		}

		private void OnDestroy()
		{
			for (int num = rendererMaterialPairs.Length - 1; num > 0; num--)
			{
				UnityEngine.Object.Destroy(rendererMaterialPairs[num].material);
				rendererMaterialPairs[num] = new RendererMaterialPair(null, null);
			}
			rendererMaterialPairs = Array.Empty<RendererMaterialPair>();
		}

		private void OnValidate()
		{
			if (printCurve == null)
			{
				printCurve = new AnimationCurve();
			}
			Keyframe[] keys = printCurve.keys;
			for (int i = 1; i < keys.Length; i++)
			{
				ref Keyframe reference = ref keys[i - 1];
				ref Keyframe reference2 = ref keys[i];
				if (reference.time >= reference2.time)
				{
					UnityEngine.Debug.LogErrorFormat("Animation curve error on object {0}", base.gameObject.name);
					break;
				}
			}
			if (printTime == 0f)
			{
				UnityEngine.Debug.LogErrorFormat("printTime==0f on object {0}", base.gameObject.name);
			}
		}

		public void SetPaused(bool newPaused)
		{
			paused = newPaused;
		}

		private void UpdatePrint(float deltaTime)
		{
			if (printCurve != null)
			{
				if (!paused)
				{
					age += deltaTime;
				}
				float printThreshold = printCurve.Evaluate(age / printTime);
				SetPrintThreshold(printThreshold);
				if (age >= printTime && disableWhenFinished)
				{
					base.enabled = false;
					age = 0f;
				}
			}
		}

		private void SetPrintThreshold(float sample)
		{
			float num = 1f - sample;
			float value = sample * maxPrintHeight + num * startingPrintHeight;
			float value2 = sample * maxPrintBias + num * startingPrintBias;
			float value3 = sample * maxFlowmapPower + num * startingFlowmapPower;
			for (int i = 0; i < rendererMaterialPairs.Length; i++)
			{
				ref RendererMaterialPair reference = ref rendererMaterialPairs[i];
				reference.renderer.GetPropertyBlock(_propBlock);
				_propBlock.SetFloat(sliceHeightShaderPropertyId, value);
				_propBlock.SetFloat(printBiasShaderPropertyId, value2);
				if (animateFlowmapPower)
				{
					_propBlock.SetFloat(flowHeightPowerShaderPropertyId, value3);
				}
				reference.renderer.SetPropertyBlock(_propBlock);
			}
		}

		private void SetupPrint()
		{
			if (hasSetupOnce)
			{
				return;
			}
			hasSetupOnce = true;
			if ((bool)characterModel)
			{
				CharacterModel.RendererInfo[] baseRendererInfos = characterModel.baseRendererInfos;
				int num = 0;
				for (int i = 0; i < baseRendererInfos.Length; i++)
				{
					if (!(baseRendererInfos[i].defaultMaterial?.shader != printShader))
					{
						num++;
					}
				}
				Array.Resize(ref rendererMaterialPairs, num);
				int j = 0;
				int num2 = 0;
				for (; j < baseRendererInfos.Length; j++)
				{
					ref CharacterModel.RendererInfo reference = ref baseRendererInfos[j];
					if (!(reference.defaultMaterial?.shader != printShader))
					{
						Material material = (reference.defaultMaterial = UnityEngine.Object.Instantiate(reference.defaultMaterial));
						rendererMaterialPairs[num2++] = new RendererMaterialPair(reference.renderer, material);
					}
				}
			}
			else
			{
				List<Renderer> gameObjectComponentsInChildren = GetComponentsCache<Renderer>.GetGameObjectComponentsInChildren(base.gameObject, includeInactive: true);
				Array.Resize(ref rendererMaterialPairs, gameObjectComponentsInChildren.Count);
				int k = 0;
				for (int count = gameObjectComponentsInChildren.Count; k < count; k++)
				{
					Renderer renderer = gameObjectComponentsInChildren[k];
					Material material2 = renderer.material;
					rendererMaterialPairs[k] = new RendererMaterialPair(renderer, material2);
				}
				GetComponentsCache<Renderer>.ReturnBuffer(gameObjectComponentsInChildren);
			}
			SetMaterialPrintCutoffEnabled(shouldEnable: false);
			age = 0f;
		}

		private void SetMaterialPrintCutoffEnabled(bool shouldEnable)
		{
			if (shouldEnable)
			{
				EnableMaterialPrintCutoff();
			}
			else
			{
				DisableMaterialPrintCutoff();
			}
		}

		private void EnableMaterialPrintCutoff()
		{
			for (int i = 0; i < rendererMaterialPairs.Length; i++)
			{
				Material material = rendererMaterialPairs[i].material;
				material.EnableKeyword("PRINT_CUTOFF");
				material.SetInt(printOnPropertyId, 1);
			}
		}

		private void DisableMaterialPrintCutoff()
		{
			for (int i = 0; i < rendererMaterialPairs.Length; i++)
			{
				Material material = rendererMaterialPairs[i].material;
				material.DisableKeyword("PRINT_CUTOFF");
				material.SetInt(printOnPropertyId, 0);
			}
			SetPrintThreshold(1f);
		}
	}
	public class ArrayAverage
	{
		private int[] valueArray;

		private int arrayIndex;

		public float peakAverage;

		public float peakSingleValue;

		public float average
		{
			get
			{
				float num = 0f;
				float num2 = 0f;
				for (int i = 0; i < valueArray.Length; i++)
				{
					int num3 = valueArray[i];
					if (num3 != 0)
					{
						num += (float)num3;
						num2 += 1f;
					}
				}
				if (num2 == 0f)
				{
					return 0f;
				}
				num /= num2;
				if (num > peakAverage)
				{
					peakAverage = num;
				}
				return num;
			}
		}

		public int nextValue
		{
			get
			{
				return valueArray[arrayIndex];
			}
			set
			{
				if ((float)value > peakSingleValue)
				{
					peakSingleValue = value;
				}
				arrayIndex = (arrayIndex + 1) % valueArray.Length;
				valueArray[arrayIndex] = value;
			}
		}

		public ArrayAverage(int arraySize)
		{
			arrayIndex = 0;
			valueArray = new int[Mathf.Max(arraySize, 1)];
		}
	}
	public static class WorkQueue
	{
		private static Queue<Func<bool>> queuedWork;

		private static int workPerFrame;

		private static int workPerFrame_Max;

		private static int queuedBacklogMinimum;

		private static int workPerFrame_BacklogMax;

		private static bool useFlexBudgeting;

		private static bool useQueueing;

		private static ArrayAverage performanceAverager;

		static WorkQueue()
		{
			queuedWork = new Queue<Func<bool>>(150);
			workPerFrame_Max = 25;
			queuedBacklogMinimum = 500;
			workPerFrame_BacklogMax = 250;
			useFlexBudgeting = true;
			useQueueing = true;
			performanceAverager = new ArrayAverage(100);
		}

		public static void RequestUpdate()
		{
			if (Time.deltaTime <= 0f)
			{
				return;
			}
			workPerFrame = 0;
			int num = Mathf.Min(queuedWork.Count);
			int num2 = ((useFlexBudgeting && queuedWork.Count > queuedBacklogMinimum) ? workPerFrame_BacklogMax : workPerFrame_Max);
			if (useQueueing)
			{
				for (int i = 0; i < num; i++)
				{
					if (queuedWork.Dequeue()())
					{
						workPerFrame++;
						if (workPerFrame >= num2)
						{
							break;
						}
					}
				}
			}
			else
			{
				num2 = 1000000;
				while (queuedWork.Count > 0)
				{
					if (queuedWork.Dequeue()())
					{
						workPerFrame++;
					}
				}
			}
			if (workPerFrame > 0)
			{
				performanceAverager.nextValue = workPerFrame;
				_ = useQueueing;
			}
		}

		public static void ExecuteOrEnqueue(Func<bool> spawnCallback)
		{
			if (CanAffordProjectile())
			{
				workPerFrame++;
				spawnCallback();
			}
			else
			{
				queuedWork.Enqueue(spawnCallback);
			}
		}

		private static bool CanAffordProjectile()
		{
			return workPerFrame < workPerFrame_Max;
		}
	}
	public class ProxyInteraction : MonoBehaviour, IInteractable
	{
		public Func<ProxyInteraction, Interactor, string> getContextString;

		public Func<ProxyInteraction, Interactor, Interactability> getInteractability;

		public Action<ProxyInteraction, Interactor> onInteractionBegin;

		public Func<ProxyInteraction, Interactor, bool> shouldIgnoreSpherecastForInteractability;

		public Func<ProxyInteraction, bool> shouldShowOnScanner;

		public string GetContextString(Interactor activator)
		{
			return getContextString?.Invoke(this, activator);
		}

		public Interactability GetInteractability(Interactor activator)
		{
			return getInteractability?.Invoke(this, activator) ?? Interactability.Disabled;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			onInteractionBegin?.Invoke(this, activator);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return shouldIgnoreSpherecastForInteractability?.Invoke(this, activator) ?? true;
		}

		public bool ShouldShowOnScanner()
		{
			return shouldShowOnScanner?.Invoke(this) ?? false;
		}

		public bool ShouldProximityHighlight()
		{
			return false;
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}
	}
	public class PullNearby : MonoBehaviour
	{
		public float pullRadius;

		public float pullDuration;

		public AnimationCurve pullStrengthCurve;

		public bool pullOnStart;

		public int maximumPullCount = int.MaxValue;

		private List<CharacterBody> victimBodyList = new List<CharacterBody>();

		private bool pulling;

		private TeamFilter teamFilter;

		private float fixedAge;

		private void Start()
		{
			teamFilter = GetComponent<TeamFilter>();
			if (pullOnStart)
			{
				InitializePull();
			}
		}

		private void FixedUpdate()
		{
			fixedAge += Time.fixedDeltaTime;
			if (!(fixedAge > pullDuration))
			{
				UpdatePull(Time.fixedDeltaTime);
			}
		}

		private void UpdatePull(float deltaTime)
		{
			if (!pulling)
			{
				return;
			}
			for (int i = 0; i < victimBodyList.Count; i++)
			{
				CharacterBody characterBody = victimBodyList[i];
				UnityEngine.Vector3 vector = base.transform.position - characterBody.corePosition;
				float num = pullStrengthCurve.Evaluate(vector.magnitude / pullRadius);
				UnityEngine.Vector3 vector2 = vector.normalized * num * deltaTime;
				CharacterMotor component = characterBody.GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					component.rootMotion += vector2;
					continue;
				}
				Rigidbody component2 = characterBody.GetComponent<Rigidbody>();
				if ((bool)component2)
				{
					component2.velocity += vector2;
				}
			}
		}

		public void InitializePull()
		{
			if (pulling)
			{
				return;
			}
			pulling = true;
			Collider[] colliders;
			int num = HGPhysics.OverlapSphere(out colliders, base.transform.position, pullRadius, LayerIndex.CommonMasks.characterBodiesOrDefault);
			int i = 0;
			int num2 = 0;
			for (; i < num; i++)
			{
				if (num2 >= maximumPullCount)
				{
					break;
				}
				HealthComponent component = colliders[i].GetComponent<HealthComponent>();
				if ((bool)component)
				{
					TeamComponent component2 = component.GetComponent<TeamComponent>();
					bool flag = false;
					if ((bool)component2 && (bool)teamFilter)
					{
						flag = component2.teamIndex == teamFilter.teamIndex;
					}
					if (!flag)
					{
						AddToList(component.gameObject);
						num2++;
					}
				}
			}
			HGPhysics.ReturnResults(colliders);
		}

		private void AddToList(GameObject affectedObject)
		{
			CharacterBody component = affectedObject.GetComponent<CharacterBody>();
			if (!victimBodyList.Contains(component))
			{
				victimBodyList.Add(component);
			}
		}
	}
	public class PulseController : NetworkBehaviour
	{
		public delegate void PerformSearchDelegate(PulseController pulseController, UnityEngine.Vector3 origin, float radius, List<PulseSearchResult> dest);

		public delegate void OnPulseHitDelegate(PulseController pulseController, PulseHit hitInfo);

		public struct PulseSearchResult
		{
			public UnityEngine.Object hitObject;

			public UnityEngine.Vector3 hitPos;
		}

		public struct PulseHit
		{
			public UnityEngine.Object hitObject;

			public UnityEngine.Vector3 hitPos;

			public UnityEngine.Vector3 pulseOrigin;

			public float hitDistance;

			public float hitSeverity;
		}

		[Tooltip("How far the pulse can ultimately reach.")]
		[SyncVar]
		public float finalRadius;

		[SyncVar]
		[Tooltip("How long it takes for the pulse to complete.")]
		public float duration;

		[Tooltip("The curve by which normalized time will map to normalized radius.")]
		public AnimationCurveAsset normalizedRadiusCurve;

		[Tooltip("An object which will be enabled and scaled across the duration of the pulse.")]
		public Transform effectTransform;

		[Tooltip("Fires off the normalized time, useful for updating any VFX.")]
		public UnityEventFloat updateVfx;

		[Tooltip("Fired when the pulse is over.")]
		public UnityEvent onPulseEndServer;

		[SyncVar]
		private Run.FixedTimeStamp startTime;

		private List<UnityEngine.Object> hitObjects;

		private float previousVfxNormalizedTime = float.NaN;

		public float NetworkfinalRadius
		{
			get
			{
				return finalRadius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref finalRadius, 1u);
			}
		}

		public float Networkduration
		{
			get
			{
				return duration;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref duration, 2u);
			}
		}

		public Run.FixedTimeStamp NetworkstartTime
		{
			get
			{
				return startTime;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref startTime, 4u);
			}
		}

		public event PerformSearchDelegate performSearch;

		public event OnPulseHitDelegate onPulseHit;

		private void OnEnable()
		{
			if (NetworkServer.active)
			{
				NetworkstartTime = Run.FixedTimeStamp.positiveInfinity;
				hitObjects = CollectionPool<UnityEngine.Object, List<UnityEngine.Object>>.RentCollection();
			}
		}

		private void OnDisable()
		{
			if (NetworkServer.active)
			{
				NetworkstartTime = Run.FixedTimeStamp.positiveInfinity;
				hitObjects = CollectionPool<UnityEngine.Object, List<UnityEngine.Object>>.ReturnCollection(hitObjects);
			}
		}

		private void FixedUpdate()
		{
			float num = Mathf.Clamp01((Run.FixedTimeStamp.now - startTime) / duration);
			if (normalizedRadiusCurve?.value != null)
			{
				num *= normalizedRadiusCurve.value.Evaluate(num);
			}
			float radius = CalcRadius(num);
			if (NetworkServer.active)
			{
				StepPulse(radius);
			}
			if (num == 1f && NetworkServer.active)
			{
				NetworkstartTime = Run.FixedTimeStamp.positiveInfinity;
				onPulseEndServer?.Invoke();
			}
		}

		private void Update()
		{
			float num = Mathf.Clamp01((Run.TimeStamp.now - startTime) / duration);
			if (normalizedRadiusCurve?.value != null)
			{
				num *= normalizedRadiusCurve.value.Evaluate(num);
			}
			float num2 = CalcRadius(num);
			if ((bool)effectTransform)
			{
				bool flag = num > 0f && num < 1f;
				effectTransform.gameObject.SetActive(flag);
				if (flag)
				{
					effectTransform.localScale = new UnityEngine.Vector3(num2, num2, num2);
				}
			}
			if (previousVfxNormalizedTime != num)
			{
				previousVfxNormalizedTime = num;
				updateVfx?.Invoke(num);
			}
		}

		[Server]
		public void StartPulseServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PulseController::StartPulseServer()' called on client");
			}
			else if (base.enabled)
			{
				NetworkstartTime = Run.FixedTimeStamp.now;
				hitObjects.Clear();
			}
		}

		private float CalcRadius(float normalizedTime)
		{
			return normalizedTime * finalRadius;
		}

		private void StepPulse(float radius)
		{
			List<PulseSearchResult> list = CollectionPool<PulseSearchResult, List<PulseSearchResult>>.RentCollection();
			UnityEngine.Vector3 position = base.transform.position;
			try
			{
				this.performSearch?.Invoke(this, position, radius, list);
				for (int i = 0; i < list.Count; i++)
				{
					PulseSearchResult pulseSearchResult = list[i];
					if (hitObjects.Contains(pulseSearchResult.hitObject))
					{
						continue;
					}
					try
					{
						float num = UnityEngine.Vector3.Distance(position, pulseSearchResult.hitPos);
						this.onPulseHit?.Invoke(this, new PulseHit
						{
							hitObject = pulseSearchResult.hitObject,
							hitPos = pulseSearchResult.hitPos,
							pulseOrigin = position,
							hitDistance = num,
							hitSeverity = Mathf.Clamp01(1f - num / finalRadius)
						});
					}
					catch (Exception message)
					{
						UnityEngine.Debug.LogError(message);
					}
					finally
					{
						hitObjects.Add(pulseSearchResult.hitObject);
					}
				}
			}
			finally
			{
				CollectionPool<PulseSearchResult, List<PulseSearchResult>>.RentCollection();
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(finalRadius);
				writer.Write(duration);
				GeneratedNetworkCode._WriteFixedTimeStamp_Run(writer, startTime);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(finalRadius);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(duration);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteFixedTimeStamp_Run(writer, startTime);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				finalRadius = reader.ReadSingle();
				duration = reader.ReadSingle();
				startTime = GeneratedNetworkCode._ReadFixedTimeStamp_Run(reader);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				finalRadius = reader.ReadSingle();
			}
			if (((uint)num & 2u) != 0)
			{
				duration = reader.ReadSingle();
			}
			if (((uint)num & 4u) != 0)
			{
				startTime = GeneratedNetworkCode._ReadFixedTimeStamp_Run(reader);
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class PurchaseAvailabilityIndicator : MonoBehaviour
	{
		public GameObject indicatorObject;

		public GameObject disabledIndicatorObject;

		public Animator animator;

		public string mecanimBool;

		private int mecanimBoolHash;

		private PurchaseInteraction purchaseInteraction;

		private void Awake()
		{
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			mecanimBoolHash = Animator.StringToHash(mecanimBool);
		}

		private void FixedUpdate()
		{
			if ((bool)indicatorObject)
			{
				indicatorObject.SetActive(purchaseInteraction.available);
			}
			if ((bool)disabledIndicatorObject)
			{
				disabledIndicatorObject.SetActive(!purchaseInteraction.available);
			}
			if ((bool)animator)
			{
				animator.SetBool(mecanimBoolHash, purchaseInteraction.available);
			}
		}
	}
	[RequireComponent(typeof(Highlight))]
	public sealed class PurchaseInteraction : NetworkBehaviour, IInteractable, IInspectable, ISupportsMultipleInspectZones, IHologramContentProvider, IDisplayNameProvider
	{
		[SyncVar]
		public string displayNameToken;

		[SyncVar]
		public string contextToken;

		public CostTypeIndex costType;

		[SyncVar]
		public bool available = true;

		[SyncVar]
		public int cost;

		public int solitudeCost;

		public bool automaticallyScaleCostWithDifficulty;

		[Tooltip("The unlockable that a player must have to be able to interact with this terminal.")]
		public string requiredUnlockable = "";

		public bool ignoreSpherecastForInteractability;

		public string[] purchaseStatNames;

		public bool setUnavailableOnTeleporterActivated;

		public bool isShrine;

		public bool isGoldShrine;

		public bool shouldProximityHighlight = true;

		public bool saleStarCompatible;

		[SerializeField]
		public ExpansionDef requiredExpansion;

		private IInspectInfoProvider[] cachedInspectInfoProviders;

		[HideInInspector]
		public Interactor lastActivator;

		[SyncVar]
		public GameObject lockGameObject;

		private Xoroshiro128Plus rng;

		private GameObjectUnlockableFilter gameObjectUnlockableFilter;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		public PurchaseEvent onPurchase;

		private Transform viewerTransform;

		private CharacterBody viewerBody;

		private int currentInspectIndex;

		private NetworkInstanceId ___lockGameObjectNetId;

		public string NetworkdisplayNameToken
		{
			get
			{
				return displayNameToken;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref displayNameToken, 1u);
			}
		}

		public string NetworkcontextToken
		{
			get
			{
				return contextToken;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref contextToken, 2u);
			}
		}

		public bool Networkavailable
		{
			get
			{
				return available;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref available, 4u);
			}
		}

		public int Networkcost
		{
			get
			{
				return cost;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref cost, 8u);
			}
		}

		public GameObject NetworklockGameObject
		{
			get
			{
				return lockGameObject;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref lockGameObject, 16u, ref ___lockGameObjectNetId);
			}
		}

		public static event Action<PurchaseInteraction, Interactor> onItemSpentOnPurchase;

		public static event Action<PurchaseInteraction, Interactor, EquipmentIndex> onEquipmentSpentOnPurchase;

		private void Awake()
		{
			if (NetworkServer.active)
			{
				if (automaticallyScaleCostWithDifficulty)
				{
					Networkcost = Run.instance.GetDifficultyScaledCost(cost);
					solitudeCost = cost;
				}
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			}
			cachedInspectInfoProviders = GetComponents<IInspectInfoProvider>();
		}

		private void Start()
		{
			gameObjectUnlockableFilter = base.gameObject.GetComponent<GameObjectUnlockableFilter>();
		}

		[Server]
		public void SetAvailable(bool newAvailable)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PurchaseInteraction::SetAvailable(System.Boolean)' called on client");
			}
			else
			{
				Networkavailable = newAvailable;
			}
		}

		[Server]
		public void SetUnavailableTemporarily(float time)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PurchaseInteraction::SetUnavailableTemporarily(System.Single)' called on client");
				return;
			}
			Networkavailable = false;
			Invoke("SetAvailableTrue", time);
		}

		private void SetAvailableTrue()
		{
			Networkavailable = true;
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		private static bool ActivatorHasUnlockable(Interactor activator, string unlockableName)
		{
			NetworkUser networkUser = Util.LookUpBodyNetworkUser(activator.gameObject);
			if ((bool)networkUser)
			{
				LocalUser localUser = networkUser.localUser;
				if (localUser != null)
				{
					return localUser.userProfile.HasUnlockable(unlockableName);
				}
			}
			return true;
		}

		public string GetContextString(Interactor activator)
		{
			sharedStringBuilder.Clear();
			sharedStringBuilder.Append(Language.GetString(contextToken));
			if (costType != 0)
			{
				sharedStringBuilder.Append(" <nobr>(");
				if (costType == CostTypeIndex.Money)
				{
					if (TeamManager.LongstandingSolitudesInParty() > 0)
					{
						CostTypeCatalog.GetCostTypeDef(costType).BuildCostStringStyled(cost * (TeamManager.LongstandingSolitudesInParty() + 1), sharedStringBuilder, forWorldDisplay: false);
					}
					else
					{
						CostTypeCatalog.GetCostTypeDef(costType).BuildCostStringStyled(cost, sharedStringBuilder, forWorldDisplay: false);
					}
				}
				else
				{
					CostTypeCatalog.GetCostTypeDef(costType).BuildCostStringStyled(cost, sharedStringBuilder, forWorldDisplay: false);
				}
				sharedStringBuilder.Append(")</nobr>");
			}
			return sharedStringBuilder.ToString();
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (!string.IsNullOrEmpty(requiredUnlockable) && !ActivatorHasUnlockable(activator, requiredUnlockable))
			{
				return Interactability.Disabled;
			}
			if (!available || (bool)lockGameObject)
			{
				return Interactability.Disabled;
			}
			if (gameObjectUnlockableFilter != null)
			{
				NetworkUser networkUser = Util.LookUpBodyNetworkUser(activator.gameObject);
				if ((bool)networkUser)
				{
					LocalUser localUser = networkUser.localUser;
					if (localUser != null && localUser.userProfile.HasAchievement(gameObjectUnlockableFilter.AchievementToDisable))
					{
						return Interactability.Disabled;
					}
				}
			}
			Run instance = Run.instance;
			if ((bool)instance && (bool)requiredExpansion)
			{
				if (!instance.IsExpansionEnabled(requiredExpansion))
				{
					return Interactability.Disabled;
				}
				EntitlementDef requiredEntitlement = requiredExpansion.requiredEntitlement;
				CharacterBody component = activator.GetComponent<CharacterBody>();
				if ((bool)component && (bool)requiredEntitlement)
				{
					PlayerCharacterMasterController playerCharacterMasterController = component.master.playerCharacterMasterController;
					if (!playerCharacterMasterController)
					{
						return Interactability.Disabled;
					}
					PlayerCharacterMasterControllerEntitlementTracker component2 = playerCharacterMasterController.GetComponent<PlayerCharacterMasterControllerEntitlementTracker>();
					if (!component2)
					{
						UnityEngine.Debug.LogWarning("Rejecting interact because the playerCharacterMasterController doesn't have a sibling PlayerCharacterMasterControllerEntitlementTracker");
						return Interactability.Disabled;
					}
					if (!component2.HasEntitlement(requiredEntitlement))
					{
						UnityEngine.Debug.LogWarning("Rejecting interact because the player doesn't have entitlement " + requiredEntitlement.name);
						return Interactability.Disabled;
					}
				}
			}
			if (!CanBeAffordedByInteractor(activator))
			{
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Available;
		}

		public bool CanBeAffordedByInteractor(Interactor activator)
		{
			int num = cost;
			if (costType == CostTypeIndex.Money)
			{
				num = ((activator.GetComponent<CharacterBody>().GetBuffCount(DLC2Content.Buffs.FreeUnlocks) <= 0) ? (cost * (TeamManager.LongstandingSolitudesInParty() + 1)) : 0);
			}
			return CostTypeCatalog.GetCostTypeDef(costType).IsAffordable(num, activator);
		}

		public void OnInteractionBegin(Interactor activator)
		{
			if (!CanBeAffordedByInteractor(activator))
			{
				return;
			}
			CharacterBody component = activator.GetComponent<CharacterBody>();
			CostTypeDef costTypeDef = CostTypeCatalog.GetCostTypeDef(costType);
			ItemIndex itemIndex = ItemIndex.None;
			ShopTerminalBehavior component2 = GetComponent<ShopTerminalBehavior>();
			if ((bool)component2)
			{
				itemIndex = PickupCatalog.GetPickupDef(component2.CurrentPickupIndex())?.itemIndex ?? ItemIndex.None;
			}
			int num = cost;
			if (costType == CostTypeIndex.Money)
			{
				if (activator.GetComponent<CharacterBody>().GetBuffCount(DLC2Content.Buffs.FreeUnlocks) > 0 && !GetComponent<MultiShopController>())
				{
					num = 0;
					activator.GetComponent<CharacterBody>().RemoveBuff(DLC2Content.Buffs.FreeUnlocks);
					Util.PlaySound("Play_item_proc_onLevelUpFreeUnlock_activate", base.gameObject);
				}
				else
				{
					num = cost * (TeamManager.LongstandingSolitudesInParty() + 1);
				}
			}
			if (component.inventory.GetItemCount(DLC2Content.Items.LowerPricedChests) > 0 && saleStarCompatible)
			{
				int itemCount = activator.GetComponent<CharacterBody>().inventory.GetItemCount(DLC2Content.Items.LowerPricedChests);
				int num2 = 0;
				float num3 = 1f;
				if (itemCount == 1)
				{
					num2 = 0;
				}
				else
				{
					for (int i = 1; i < 4; i++)
					{
						switch (i)
						{
						case 1:
							num3 = 30f;
							break;
						case 2:
							num3 = 15f;
							break;
						case 3:
							num3 = 1f;
							break;
						}
						if (itemCount >= 3)
						{
							float num4 = 1f - 1f / ((float)itemCount * 0.05f + 1f);
							if (!Util.CheckRoll(num3 + num4 * 100f, activator.GetComponent<CharacterBody>().master))
							{
								break;
							}
							num2 = i;
						}
						else
						{
							if (!Util.CheckRoll(num3, activator.GetComponent<CharacterBody>().master))
							{
								break;
							}
							num2 = i;
						}
					}
				}
				if ((bool)GetComponent<ChestBehavior>())
				{
					GetComponent<ChestBehavior>().dropCount = 2 + num2;
				}
				else if ((bool)GetComponent<RouletteChestController>())
				{
					GetComponent<RouletteChestController>().dropCount = 2 + num2;
				}
				component.inventory.RemoveItem(DLC2Content.Items.LowerPricedChests, activator.GetComponent<CharacterBody>().inventory.GetItemCount(DLC2Content.Items.LowerPricedChests));
				component.inventory.GiveItem(DLC2Content.Items.LowerPricedChestsConsumed, itemCount);
				CharacterMasterNotificationQueue.SendTransformNotification(component.master, DLC2Content.Items.LowerPricedChests.itemIndex, DLC2Content.Items.LowerPricedChestsConsumed.itemIndex, CharacterMasterNotificationQueue.TransformationType.SaleStarRegen);
				Util.PlaySound("Play_item_proc_lowerPricedChest", base.gameObject);
			}
			CostTypeDef.PayCostResults payCostResults = costTypeDef.PayCost(num, activator, base.gameObject, rng, itemIndex);
			foreach (ItemIndex item in payCostResults.itemsTaken)
			{
				CreateItemTakenOrb(component.corePosition, base.gameObject, item);
				if (item != itemIndex)
				{
					PurchaseInteraction.onItemSpentOnPurchase?.Invoke(this, activator);
				}
			}
			foreach (EquipmentIndex item2 in payCostResults.equipmentTaken)
			{
				PurchaseInteraction.onEquipmentSpentOnPurchase?.Invoke(this, activator, item2);
			}
			IEnumerable<StatDef> statDefsToIncrement = purchaseStatNames.Select(StatDef.Find);
			StatManager.OnPurchase(component, costType, statDefsToIncrement);
			onPurchase.Invoke(activator);
			lastActivator = activator;
		}

		[Server]
		public static void CreateItemTakenOrb(UnityEngine.Vector3 effectOrigin, GameObject targetObject, ItemIndex itemIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PurchaseInteraction::CreateItemTakenOrb(UnityEngine.Vector3,UnityEngine.GameObject,RoR2.ItemIndex)' called on client");
				return;
			}
			GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OrbEffects/ItemTakenOrbEffect");
			EffectData effectData = new EffectData
			{
				origin = effectOrigin,
				genericFloat = 1.5f,
				genericUInt = (uint)(itemIndex + 1)
			};
			effectData.SetNetworkedObjectReference(targetObject);
			EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
		}

		public bool ShouldDisplayHologram(GameObject viewer)
		{
			return available;
		}

		public GameObject GetHologramContentPrefab()
		{
			return LegacyResourcesAPI.Load<GameObject>("Prefabs/CostHologramContent");
		}

		private void CacheViewerBody(Transform _viewer)
		{
			if (!(_viewer == null) && (!viewerBody || !(viewerTransform == _viewer)) && _viewer.TryGetComponent<CharacterBody>(out var component))
			{
				viewerTransform = _viewer;
				viewerBody = component;
			}
		}

		public void ScaleCost(float scalar)
		{
			Networkcost = (int)Mathf.Floor((float)cost * scalar);
		}

		public void UpdateHologramContent(GameObject hologramContentObject, Transform viewer)
		{
			CostHologramContent component = hologramContentObject.GetComponent<CostHologramContent>();
			GetComponent<HologramProjector>();
			CacheViewerBody(viewer);
			if (!component)
			{
				return;
			}
			if ((bool)viewerBody && costType.Equals(CostTypeIndex.Money))
			{
				if (TeamManager.LongstandingSolitudesInParty() > 0)
				{
					component.displayValue = cost * (TeamManager.LongstandingSolitudesInParty() + 1);
				}
				else
				{
					component.displayValue = cost;
				}
			}
			else
			{
				component.displayValue = cost;
			}
			component.costType = costType;
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public bool ShouldShowOnScanner()
		{
			return available;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			TeleporterInteraction.onTeleporterBeginChargingGlobal += OnTeleporterBeginCharging;
		}

		private static void OnTeleporterBeginCharging(TeleporterInteraction teleporterInteraction)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (PurchaseInteraction instances in InstanceTracker.GetInstancesList<PurchaseInteraction>())
			{
				if (instances.setUnavailableOnTeleporterActivated)
				{
					instances.SetAvailable(newAvailable: false);
					instances.CancelInvoke("SetUnavailableTemporarily");
				}
			}
		}

		public IInspectInfoProvider GetInspectInfoProvider()
		{
			if (currentInspectIndex < cachedInspectInfoProviders.Length)
			{
				return cachedInspectInfoProviders[currentInspectIndex];
			}
			return null;
		}

		public void SetInspectInfoProvider(int newInspectIndex)
		{
			currentInspectIndex = newInspectIndex;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(displayNameToken);
				writer.Write(contextToken);
				writer.Write(available);
				writer.WritePackedUInt32((uint)cost);
				writer.Write(lockGameObject);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(displayNameToken);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(contextToken);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(available);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)cost);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(lockGameObject);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				displayNameToken = reader.ReadString();
				contextToken = reader.ReadString();
				available = reader.ReadBoolean();
				cost = (int)reader.ReadPackedUInt32();
				___lockGameObjectNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				displayNameToken = reader.ReadString();
			}
			if (((uint)num & 2u) != 0)
			{
				contextToken = reader.ReadString();
			}
			if (((uint)num & 4u) != 0)
			{
				available = reader.ReadBoolean();
			}
			if (((uint)num & 8u) != 0)
			{
				cost = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x10u) != 0)
			{
				lockGameObject = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___lockGameObjectNetId.IsEmpty())
			{
				NetworklockGameObject = ClientScene.FindLocalObject(___lockGameObjectNetId);
			}
		}
	}
	[Serializable]
	public class PurchaseEvent : UnityEvent<Interactor>
	{
	}
	public class RadialForce : MonoBehaviour
	{
		public float radius;

		public float damping = 0.2f;

		public float forceMagnitude;

		public float forceCoefficientAtEdge = 0.5f;

		public TetherVfxOrigin tetherVfxOrigin;

		private SphereSearch sphereSearch;

		protected new Transform transform { get; private set; }

		protected TeamFilter teamFilter { get; private set; }

		protected void Awake()
		{
			transform = GetComponent<Transform>();
			teamFilter = GetComponent<TeamFilter>();
			sphereSearch = new SphereSearch();
		}

		protected void FixedUpdate()
		{
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			SearchForTargets(list);
			int i = 0;
			for (int count = list.Count; i < count; i++)
			{
				ApplyPullToHurtBox(list[i]);
			}
			if ((bool)tetherVfxOrigin)
			{
				List<Transform> list2 = CollectionPool<Transform, List<Transform>>.RentCollection();
				int j = 0;
				for (int count2 = list.Count; j < count2; j++)
				{
					HurtBox hurtBox = list[j];
					if (!hurtBox)
					{
						continue;
					}
					Transform item = hurtBox.transform;
					HealthComponent healthComponent = hurtBox.healthComponent;
					if ((bool)healthComponent)
					{
						Transform coreTransform = healthComponent.body.coreTransform;
						if ((bool)coreTransform)
						{
							item = coreTransform;
						}
					}
					list2.Add(item);
				}
				tetherVfxOrigin.SetTetheredTransforms(list2);
				CollectionPool<Transform, List<Transform>>.ReturnCollection(list2);
			}
			CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}

		protected void SearchForTargets(List<HurtBox> dest)
		{
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.origin = transform.position;
			sphereSearch.radius = radius;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamFilter.teamIndex));
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			sphereSearch.GetHurtBoxes(dest);
			sphereSearch.ClearCandidates();
		}

		protected void ApplyPullToHurtBox(HurtBox hurtBox)
		{
			if (!hurtBox)
			{
				return;
			}
			HealthComponent healthComponent = hurtBox.healthComponent;
			if (!healthComponent || !healthComponent.body || !hurtBox.transform || !transform || !NetworkServer.active)
			{
				return;
			}
			CharacterMotor characterMotor = healthComponent.body.characterMotor;
			UnityEngine.Vector3 vector = hurtBox.transform.position - transform.position;
			float num = 1f - Mathf.Clamp(vector.magnitude / radius, 0f, 1f - forceCoefficientAtEdge);
			vector = vector.normalized * forceMagnitude * (1f - num);
			UnityEngine.Vector3 vector2 = UnityEngine.Vector3.zero;
			float num2 = 0f;
			if ((bool)characterMotor)
			{
				vector2 = characterMotor.velocity;
				num2 = characterMotor.mass;
			}
			else
			{
				Rigidbody rigidbody = healthComponent.body.rigidbody;
				if ((bool)rigidbody)
				{
					vector2 = rigidbody.velocity;
					num2 = rigidbody.mass;
				}
			}
			vector2.y += Physics.gravity.y * Time.fixedDeltaTime;
			healthComponent.TakeDamageForce(vector - vector2 * damping * num2 * num, alwaysApply: true);
		}
	}
	public class RadiotowerTerminal : NetworkBehaviour
	{
		[SyncVar(hook = "SetHasBeenPurchased")]
		private bool hasBeenPurchased;

		private UnlockableDef unlockableDef;

		public string unlockSoundString;

		public GameObject unlockEffect;

		private static int kRpcRpcSetPingable;

		public bool NetworkhasBeenPurchased
		{
			get
			{
				return hasBeenPurchased;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetHasBeenPurchased(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref hasBeenPurchased, 1u);
			}
		}

		private void SetHasBeenPurchased(bool newHasBeenPurchased)
		{
			if (hasBeenPurchased != newHasBeenPurchased)
			{
				NetworkhasBeenPurchased = newHasBeenPurchased;
			}
		}

		public void Start()
		{
			if (NetworkServer.active)
			{
				FindStageLogUnlockable();
			}
			_ = NetworkClient.active;
		}

		private void FindStageLogUnlockable()
		{
			SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef;
			if ((bool)mostRecentSceneDef)
			{
				unlockableDef = SceneCatalog.GetUnlockableLogFromBaseSceneName(mostRecentSceneDef.baseSceneName);
			}
		}

		[Server]
		public void GrantUnlock(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.RadiotowerTerminal::GrantUnlock(RoR2.Interactor)' called on client");
				return;
			}
			EffectManager.SpawnEffect(unlockEffect, new EffectData
			{
				origin = base.transform.position
			}, transmit: true);
			SetHasBeenPurchased(newHasBeenPurchased: true);
			if ((bool)Run.instance)
			{
				Util.PlaySound(unlockSoundString, interactor.gameObject);
				Run.instance.GrantUnlockToAllParticipatingPlayers(unlockableDef);
				string pickupToken = "???";
				if ((bool)unlockableDef)
				{
					pickupToken = unlockableDef.nameToken;
				}
				Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage
				{
					subjectAsCharacterBody = interactor.GetComponent<CharacterBody>(),
					baseToken = "PLAYER_PICKUP",
					pickupToken = pickupToken,
					pickupColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unlockable),
					pickupQuantity = 1u
				});
				CallRpcSetPingable(value: false);
			}
		}

		[ClientRpc]
		private void RpcSetPingable(bool value)
		{
			NetworkIdentity component = GetComponent<NetworkIdentity>();
			if ((bool)component)
			{
				component.isPingable = value;
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcSetPingable(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetPingable called on server.");
			}
			else
			{
				((RadiotowerTerminal)obj).RpcSetPingable(reader.ReadBoolean());
			}
		}

		public void CallRpcSetPingable(bool value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetPingable called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetPingable);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(value);
			SendRPCInternal(networkWriter, 0, "RpcSetPingable");
		}

		static RadiotowerTerminal()
		{
			kRpcRpcSetPingable = 310061166;
			NetworkBehaviour.RegisterRpcDelegate(typeof(RadiotowerTerminal), kRpcRpcSetPingable, InvokeRpcRpcSetPingable);
			NetworkCRC.RegisterBehaviour("RadiotowerTerminal", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(hasBeenPurchased);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(hasBeenPurchased);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				hasBeenPurchased = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetHasBeenPurchased(reader.ReadBoolean());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class RagdollController : MonoBehaviour
	{
		public Transform[] bones;

		public MonoBehaviour[] componentsToDisableOnRagdoll;

		private Animator animator;

		private void Start()
		{
			animator = GetComponent<Animator>();
			Transform[] array = bones;
			foreach (Transform transform in array)
			{
				Collider component = transform.GetComponent<Collider>();
				Rigidbody component2 = transform.GetComponent<Rigidbody>();
				if (!component)
				{
					UnityEngine.Debug.LogWarningFormat("Bone {0} is missing a collider!", transform);
				}
				else
				{
					component.enabled = false;
					component2.interpolation = RigidbodyInterpolation.None;
					component2.isKinematic = true;
				}
			}
		}

		public void BeginRagdoll(UnityEngine.Vector3 force)
		{
			if ((bool)animator)
			{
				animator.enabled = false;
			}
			Transform[] array = bones;
			foreach (Transform transform in array)
			{
				if (transform.gameObject.layer == LayerIndex.ragdoll.intVal)
				{
					transform.parent = base.transform;
					Rigidbody component = transform.GetComponent<Rigidbody>();
					transform.GetComponent<Collider>().enabled = true;
					component.isKinematic = false;
					component.interpolation = RigidbodyInterpolation.Interpolate;
					component.collisionDetectionMode = CollisionDetectionMode.Continuous;
					component.AddForce(force * UnityEngine.Random.Range(0.9f, 1.2f), ForceMode.VelocityChange);
				}
			}
			MonoBehaviour[] array2 = componentsToDisableOnRagdoll;
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i].enabled = false;
			}
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class RailMotor : MonoBehaviour
	{
		public UnityEngine.Vector3 inputMoveVector;

		public UnityEngine.Vector3 rootMotion;

		private Animator modelAnimator;

		private InputBankTest inputBank;

		private NodeGraph railGraph;

		private NodeGraph.NodeIndex nodeA;

		private NodeGraph.NodeIndex nodeB;

		private NodeGraph.LinkIndex currentLink;

		private CharacterBody characterBody;

		private CharacterDirection characterDirection;

		private float linkLerp;

		private UnityEngine.Vector3 projectedMoveVector;

		private UnityEngine.Vector3 nodeAPosition;

		private UnityEngine.Vector3 nodeBPosition;

		private UnityEngine.Vector3 linkVector;

		private float linkLength;

		private float currentMoveSpeed;

		private bool useRootMotion;

		private static int isMovingParamHash = Animator.StringToHash("isMoving");

		private void Start()
		{
			characterDirection = GetComponent<CharacterDirection>();
			inputBank = GetComponent<InputBankTest>();
			characterBody = GetComponent<CharacterBody>();
			railGraph = SceneInfo.instance.railNodes;
			ModelLocator component = GetComponent<ModelLocator>();
			if ((bool)component)
			{
				modelAnimator = component.modelTransform.GetComponent<Animator>();
			}
			nodeA = railGraph.FindClosestNode(base.transform.position, characterBody.hullClassification);
			NodeGraph.LinkIndex[] activeNodeLinks = railGraph.GetActiveNodeLinks(nodeA);
			currentLink = activeNodeLinks[0];
			UpdateNodeAndLinkInfo();
			useRootMotion = characterBody.rootMotionInMainState;
		}

		private void UpdateNodeAndLinkInfo()
		{
			nodeA = railGraph.GetLinkStartNode(currentLink);
			nodeB = railGraph.GetLinkEndNode(currentLink);
			railGraph.GetNodePosition(nodeA, out nodeAPosition);
			railGraph.GetNodePosition(nodeB, out nodeBPosition);
			linkVector = nodeBPosition - nodeAPosition;
			linkLength = linkVector.magnitude;
		}

		private void FixedUpdate()
		{
			UpdateNodeAndLinkInfo();
			if ((bool)inputBank)
			{
				bool value = false;
				if (inputMoveVector.sqrMagnitude > 0f)
				{
					value = true;
					characterDirection.moveVector = linkVector;
					if (linkLerp == 0f || linkLerp == 1f)
					{
						NodeGraph.NodeIndex nodeIndex = ((linkLerp != 0f) ? nodeB : nodeA);
						NodeGraph.LinkIndex[] activeNodeLinks = railGraph.GetActiveNodeLinks(nodeIndex);
						float num = -1f;
						NodeGraph.LinkIndex linkIndex = currentLink;
						UnityEngine.Debug.DrawRay(base.transform.position, inputMoveVector, UnityEngine.Color.green);
						NodeGraph.LinkIndex[] array = activeNodeLinks;
						foreach (NodeGraph.LinkIndex linkIndex2 in array)
						{
							NodeGraph.NodeIndex linkStartNode = railGraph.GetLinkStartNode(linkIndex2);
							NodeGraph.NodeIndex linkEndNode = railGraph.GetLinkEndNode(linkIndex2);
							if (!(linkStartNode != nodeIndex))
							{
								railGraph.GetNodePosition(linkStartNode, out var position);
								railGraph.GetNodePosition(linkEndNode, out var position2);
								UnityEngine.Vector3 dir = position2 - position;
								UnityEngine.Vector3 rhs = new UnityEngine.Vector3(dir.x, 0f, dir.z);
								UnityEngine.Debug.DrawRay(position, dir, UnityEngine.Color.red);
								float num2 = UnityEngine.Vector3.Dot(inputMoveVector, rhs);
								if (num2 > num)
								{
									num = num2;
									linkIndex = linkIndex2;
								}
							}
						}
						if (linkIndex != currentLink)
						{
							currentLink = linkIndex;
							UpdateNodeAndLinkInfo();
							linkLerp = 0f;
						}
					}
				}
				modelAnimator.SetBool(isMovingParamHash, value);
				if (useRootMotion)
				{
					TravelLink();
				}
				else
				{
					TravelLink();
				}
			}
			base.transform.position = UnityEngine.Vector3.Lerp(nodeAPosition, nodeBPosition, linkLerp);
		}

		private void TravelLink()
		{
			projectedMoveVector = UnityEngine.Vector3.Project(inputMoveVector, linkVector);
			projectedMoveVector = projectedMoveVector.normalized;
			if (characterBody.rootMotionInMainState)
			{
				currentMoveSpeed = rootMotion.magnitude / Time.fixedDeltaTime;
				rootMotion = UnityEngine.Vector3.zero;
			}
			else
			{
				currentMoveSpeed = Mathf.MoveTowards(target: (!(projectedMoveVector.sqrMagnitude > 0f)) ? 0f : (characterBody.moveSpeed * inputMoveVector.magnitude), current: currentMoveSpeed, maxDelta: characterBody.acceleration * Time.fixedDeltaTime);
			}
			if (currentMoveSpeed > 0f)
			{
				UnityEngine.Vector3 lhs = projectedMoveVector * currentMoveSpeed;
				float num = currentMoveSpeed / linkLength * Mathf.Sign(UnityEngine.Vector3.Dot(lhs, linkVector)) * Time.fixedDeltaTime;
				linkLerp = Mathf.Clamp01(linkLerp + num);
			}
		}

		private void OnDrawGizmosSelected()
		{
			Gizmos.color = UnityEngine.Color.green;
			Gizmos.DrawSphere(nodeAPosition, 0.5f);
			Gizmos.color = UnityEngine.Color.yellow;
			Gizmos.DrawSphere(nodeBPosition, 0.5f);
			Gizmos.DrawLine(nodeAPosition, nodeBPosition);
		}
	}
	[ExecuteInEditMode]
	public class RainPostProcess : MonoBehaviour
	{
		public Material mat;

		private RenderTexture renderTex;

		private void Start()
		{
			GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
		}

		private void Update()
		{
		}

		private void OnRenderImage(RenderTexture source, RenderTexture destination)
		{
			Graphics.Blit(source, destination, mat);
		}
	}
	public class RandomizeSplatBias : MonoBehaviour
	{
		public float minRedBias;

		public float maxRedBias;

		public float minGreenBias;

		public float maxGreenBias;

		public float minBlueBias;

		public float maxBlueBias;

		private MaterialPropertyBlock _propBlock;

		private CharacterModel characterModel;

		private List<Material> materialsList;

		private List<Renderer> rendererList;

		private Shader printShader;

		private void Start()
		{
			materialsList = new List<Material>();
			rendererList = new List<Renderer>();
			printShader = LegacyResourcesAPI.Load<Shader>("Shaders/Deferred/HGStandard");
			Setup();
		}

		private void Setup()
		{
			characterModel = GetComponent<CharacterModel>();
			if ((bool)characterModel)
			{
				for (int i = 0; i < characterModel.baseRendererInfos.Length; i++)
				{
					CharacterModel.RendererInfo rendererInfo = characterModel.baseRendererInfos[i];
					Material material = UnityEngine.Object.Instantiate(rendererInfo.defaultMaterial);
					if (material.shader == printShader)
					{
						materialsList.Add(material);
						rendererList.Add(rendererInfo.renderer);
						rendererInfo.defaultMaterial = material;
						characterModel.baseRendererInfos[i] = rendererInfo;
					}
					Renderer renderer = rendererList[i];
					_propBlock = new MaterialPropertyBlock();
					renderer.GetPropertyBlock(_propBlock);
					_propBlock.SetFloat("_RedChannelBias", UnityEngine.Random.Range(minRedBias, maxRedBias));
					_propBlock.SetFloat("_BlueChannelBias", UnityEngine.Random.Range(minBlueBias, maxBlueBias));
					_propBlock.SetFloat("_GreenChannelBias", UnityEngine.Random.Range(minGreenBias, maxGreenBias));
					renderer.SetPropertyBlock(_propBlock);
				}
			}
			else
			{
				Renderer componentInChildren = GetComponentInChildren<Renderer>();
				Material material2 = UnityEngine.Object.Instantiate(componentInChildren.material);
				materialsList.Add(material2);
				componentInChildren.material = material2;
				_propBlock = new MaterialPropertyBlock();
				componentInChildren.GetPropertyBlock(_propBlock);
				_propBlock.SetFloat("_RedChannelBias", UnityEngine.Random.Range(minRedBias, maxRedBias));
				_propBlock.SetFloat("_BlueChannelBias", UnityEngine.Random.Range(minBlueBias, maxBlueBias));
				_propBlock.SetFloat("_GreenChannelBias", UnityEngine.Random.Range(minGreenBias, maxGreenBias));
				componentInChildren.SetPropertyBlock(_propBlock);
			}
		}

		private void OnDestroy()
		{
			if (materialsList != null)
			{
				for (int i = 0; i < materialsList.Count; i++)
				{
					UnityEngine.Object.Destroy(materialsList[i]);
				}
			}
		}
	}
	public class RayAttackIndicator : MonoBehaviour
	{
		private struct HitIndicatorInfo
		{
			public GameObject gameObject;

			public Transform transform;
		}

		private struct RaycastInfo
		{
			public Ray ray;

			public float maxDistance;

			public int hitsStart;

			public int maxHits;
		}

		private struct HitPointIndicatorData
		{
			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;

			public float scale;
		}

		private struct Updater
		{
			private bool running;

			public void ScheduleUpdate()
			{
				if (running)
				{
					return;
				}
				List<RayAttackIndicator> instancesList = InstanceTracker.GetInstancesList<RayAttackIndicator>();
				if (instancesList.Count != 0)
				{
					requestsBuffer = new NativeArray<RaycastInfo>(instancesList.Count, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
					raycastCommandBuffer = new NativeArray<RaycastCommand>(requestsBuffer.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
					raycastRequestersList = CollectionPool<RayAttackIndicator, List<RayAttackIndicator>>.RentCollection();
					int num = 1;
					resultsBuffer = new NativeArray<RaycastHit>(requestsBuffer.Length * num, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
					for (int i = 0; i < instancesList.Count; i++)
					{
						RayAttackIndicator rayAttackIndicator = instancesList[i];
						raycastRequestersList.Add(rayAttackIndicator);
						requestsBuffer[i] = new RaycastInfo
						{
							ray = rayAttackIndicator.attackRay,
							maxDistance = rayAttackIndicator.attackRange,
							hitsStart = i * num,
							maxHits = 1
						};
						raycastCommandBuffer[i] = new RaycastCommand(rayAttackIndicator.attackRay.origin, rayAttackIndicator.attackRay.direction, rayAttackIndicator.attackRange, rayAttackIndicator.layerMask);
					}
					raycastJobHandle = RaycastCommand.ScheduleBatch(raycastCommandBuffer, resultsBuffer, 4);
					running = true;
				}
			}

			public void CompleteUpdate()
			{
				if (!running)
				{
					return;
				}
				raycastJobHandle.Complete();
				for (int i = 0; i < requestsBuffer.Length; i++)
				{
					RaycastInfo raycastInfo = requestsBuffer[i];
					RayAttackIndicator rayAttackIndicator = raycastRequestersList[i];
					if (!rayAttackIndicator)
					{
						continue;
					}
					List<HitPointIndicatorData> list = CollectionPool<HitPointIndicatorData, List<HitPointIndicatorData>>.RentCollection();
					try
					{
						UnityEngine.Vector3 up = rayAttackIndicator.transform.up;
						Ray ray = raycastInfo.ray;
						UnityEngine.Vector3 origin = ray.origin;
						UnityEngine.Vector3 direction = ray.direction;
						if ((bool)rayAttackIndicator.originRecipient)
						{
							rayAttackIndicator.originRecipient.SetPositionAndRotation(origin, UnityEngine.Quaternion.LookRotation(direction, rayAttackIndicator.originRecipient.up));
						}
						float num = raycastInfo.maxDistance;
						float num2 = 0f;
						for (int j = 0; j < raycastInfo.maxHits; j++)
						{
							RaycastHit raycastHit = resultsBuffer[raycastInfo.hitsStart + j];
							bool num3 = (object)raycastHit.collider != null;
							float num4 = (num3 ? raycastHit.distance : raycastInfo.maxDistance);
							num = ((num4 < num) ? num4 : num);
							num2 = ((num4 > num2) ? num4 : num2);
							UnityEngine.Vector3 position = origin + direction * num4;
							if (num3)
							{
								list.Add(new HitPointIndicatorData
								{
									position = position,
									rotation = UnityEngine.Quaternion.LookRotation(-direction, up),
									scale = rayAttackIndicator.attackRadius
								});
							}
						}
						rayAttackIndicator.SetHits(list);
						if ((bool)rayAttackIndicator.nearestHitRecipient)
						{
							rayAttackIndicator.nearestHitRecipient.SetPositionAndRotation(origin + direction * num, UnityEngine.Quaternion.LookRotation(-direction, rayAttackIndicator.nearestHitRecipient.up));
						}
						if ((bool)rayAttackIndicator.furthestHitRecipient)
						{
							rayAttackIndicator.furthestHitRecipient.SetPositionAndRotation(origin + direction * num2, UnityEngine.Quaternion.LookRotation(-direction, rayAttackIndicator.furthestHitRecipient.up));
						}
					}
					catch (Exception exception)
					{
						UnityEngine.Debug.LogException(exception);
						rayAttackIndicator.enabled = false;
					}
					finally
					{
						list = CollectionPool<HitPointIndicatorData, List<HitPointIndicatorData>>.ReturnCollection(list);
					}
				}
				resultsBuffer.Dispose();
				requestsBuffer.Dispose();
				raycastCommandBuffer.Dispose();
				raycastRequestersList = CollectionPool<RayAttackIndicator, List<RayAttackIndicator>>.ReturnCollection(raycastRequestersList);
				running = false;
			}
		}

		[Tooltip("The prefab that will be instantiated and moved to wherever the ray hits.")]
		public GameObject hitIndicatorPrefab;

		[Tooltip("Transform which will be moved to the start of the ray.")]
		public Transform originRecipient;

		[Tooltip("Transform which will be moved to the nearest hit.")]
		public Transform nearestHitRecipient;

		[Tooltip("Transform which will be moved to the furthest hit.")]
		public Transform furthestHitRecipient;

		[Range(1f, 1f)]
		[Tooltip("How many hits this raycast is allowed to make. This is currently limited to 1.")]
		public int maxHits = 1;

		private static readonly Ray defaultRay = new Ray(UnityEngine.Vector3.zero, UnityEngine.Vector3.up);

		[NonSerialized]
		public Ray attackRay = defaultRay;

		[NonSerialized]
		public float attackRange = float.PositiveInfinity;

		[NonSerialized]
		public float attackRadius = 1f;

		[NonSerialized]
		public LayerMask layerMask;

		private List<HitIndicatorInfo> hitIndicators = new List<HitIndicatorInfo>();

		private static bool raysDirty = false;

		private static List<RayAttackIndicator> raycastRequestersList;

		private static NativeArray<RaycastCommand> raycastCommandBuffer;

		private static NativeArray<RaycastHit> resultsBuffer;

		private static NativeArray<RaycastInfo> requestsBuffer;

		private static JobHandle raycastJobHandle;

		private static Updater updater;

		private void Awake()
		{
			layerMask = LayerIndex.CommonMasks.bullet;
		}

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

		private void OnDisable()
		{
			AllocateHitIndicators(0);
			InstanceTracker.Remove(this);
		}

		private void AllocateHitIndicators(int newHitIndicatorCount)
		{
			while (newHitIndicatorCount < hitIndicators.Count)
			{
				UnityEngine.Object.Destroy(ListUtils.TakeLast(hitIndicators).gameObject);
			}
			while (newHitIndicatorCount > hitIndicators.Count)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(hitIndicatorPrefab);
				gameObject.SetActive(value: true);
				hitIndicators.Add(new HitIndicatorInfo
				{
					gameObject = gameObject,
					transform = gameObject.transform
				});
			}
		}

		private void SetHits(List<HitPointIndicatorData> hits)
		{
			if (base.enabled)
			{
				AllocateHitIndicators(hits.Count);
				for (int i = 0; i < hits.Count; i++)
				{
					HitIndicatorInfo hitIndicatorInfo = hitIndicators[i];
					HitPointIndicatorData hitPointIndicatorData = hits[i];
					hitIndicatorInfo.transform.SetPositionAndRotation(hitPointIndicatorData.position, hitPointIndicatorData.rotation);
					hitIndicatorInfo.transform.localScale = new UnityEngine.Vector3(hitPointIndicatorData.scale, hitPointIndicatorData.scale, hitPointIndicatorData.scale);
				}
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			RoR2Application.onUpdate += StaticUpdate;
			RoR2Application.onLateUpdate += StaticLateUpdate;
			RoR2Application.onFixedUpdate += StaticFixedUpdate;
		}

		private static void StaticUpdate()
		{
			if (raysDirty)
			{
				raysDirty = false;
				updater.ScheduleUpdate();
			}
		}

		private static void StaticLateUpdate()
		{
			updater.CompleteUpdate();
		}

		private static void StaticFixedUpdate()
		{
			raysDirty = true;
		}
	}
	public class RemapLightIntensityToParticleAlpha : MonoBehaviour
	{
		public Light light;

		public ParticleSystem particleSystem;

		public float lowerLightIntensity;

		public float upperLightIntensity = 1f;

		public float lowerParticleAlpha;

		public float upperParticleAlpha = 1f;

		private void LateUpdate()
		{
			ParticleSystem.MainModule main = particleSystem.main;
			ParticleSystem.MinMaxGradient startColor = main.startColor;
			UnityEngine.Color color = startColor.color;
			color.a = Util.Remap(light.intensity, lowerLightIntensity, upperLightIntensity, lowerParticleAlpha, upperParticleAlpha);
			startColor.color = color;
			main.startColor = startColor;
		}
	}
	public class RenderSettingsController : MonoBehaviour
	{
		public RenderSettingsState renderSettingsState;

		[ContextMenu("Copy from current render settings")]
		public void FromCurrent()
		{
			renderSettingsState = RenderSettingsState.FromCurrent();
		}

		[ContextMenu("Apply as current render settings")]
		public void Apply()
		{
			renderSettingsState.Apply();
		}

		private void LateUpdate()
		{
			Apply();
		}
	}
	public class ReplaceLightColorsInChildren : MonoBehaviour
	{
		public UnityEngine.Color newLightColor;

		public float intensityMultiplier;

		public Material newParticleSystemMaterial;

		private void Awake()
		{
			Light[] componentsInChildren = GetComponentsInChildren<Light>();
			foreach (Light obj in componentsInChildren)
			{
				obj.color = newLightColor;
				obj.intensity *= intensityMultiplier;
			}
			if (!newParticleSystemMaterial)
			{
				return;
			}
			ParticleSystem[] componentsInChildren2 = GetComponentsInChildren<ParticleSystem>();
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				ParticleSystemRenderer component = componentsInChildren2[i].GetComponent<ParticleSystemRenderer>();
				if ((bool)component)
				{
					component.material = newParticleSystemMaterial;
				}
			}
		}

		private void Update()
		{
		}
	}
	public class ReturnStolenItemsOnGettingHit : MonoBehaviour, IOnTakeDamageServerReceiver, IOnKilledServerReceiver
	{
		public HealthComponent healthComponent;

		[SerializeField]
		[Range(0.01f, 100f)]
		private float minPercentagePerItem;

		[SerializeField]
		[Range(0.01f, 100f)]
		private float maxPercentagePerItem;

		[Range(0f, 100f)]
		[SerializeField]
		private float initialPercentageToFirstItem;

		private List<Inventory> returnOrder;

		private int nextReturnIndex;

		private float damagePerItem;

		private float accumulatedDamage;

		private ItemStealController _itemStealController;

		private bool damageTrackingInitialized;

		public ItemStealController itemStealController
		{
			get
			{
				return _itemStealController;
			}
			set
			{
				if ((object)_itemStealController != null)
				{
					_itemStealController.onLendingFinishServer.RemoveListener(InitializeDamageTracking);
				}
				if ((bool)value)
				{
					value.onLendingFinishServer.AddListener(InitializeDamageTracking);
					_itemStealController = value;
				}
				else
				{
					_itemStealController = null;
				}
			}
		}

		public void OnTakeDamageServer(DamageReport damageReport)
		{
			if ((bool)itemStealController && itemStealController.hasStolen && !damageReport.damageInfo.rejected)
			{
				accumulatedDamage += damageReport.damageDealt;
			}
		}

		private void Awake()
		{
			maxPercentagePerItem = Mathf.Max(minPercentagePerItem, maxPercentagePerItem);
		}

		private void Update()
		{
			if (!NetworkServer.active || !damageTrackingInitialized)
			{
				return;
			}
			if (damagePerItem <= 0f)
			{
				damageTrackingInitialized = false;
				UnityEngine.Debug.LogError("ReturnStolenItemsOnGettingHit.damagePerItem is 0!");
				return;
			}
			while (accumulatedDamage > damagePerItem)
			{
				accumulatedDamage -= damagePerItem;
				bool flag = itemStealController.ReclaimItemForInventory(returnOrder[nextReturnIndex]);
				nextReturnIndex = (nextReturnIndex + 1) % returnOrder.Count;
				int num = 0;
				while (!flag && num < returnOrder.Count - 1)
				{
					flag = itemStealController.ReclaimItemForInventory(returnOrder[nextReturnIndex]);
					num++;
					nextReturnIndex = (nextReturnIndex + 1) % returnOrder.Count;
				}
				if (!flag)
				{
					break;
				}
			}
		}

		private void OnDestroy()
		{
			if ((object)_itemStealController != null)
			{
				_itemStealController.onLendingFinishServer.RemoveListener(InitializeDamageTracking);
				_itemStealController = null;
			}
		}

		public void OnKilledServer(DamageReport damageReport)
		{
			_ = (bool)itemStealController;
		}

		private void InitializeDamageTracking()
		{
			returnOrder = new List<Inventory>();
			if ((bool)itemStealController)
			{
				int num = 0;
				List<Inventory> list = new List<Inventory>();
				itemStealController.AddValidStolenInventoriesToList(list);
				foreach (Inventory item in list)
				{
					if (!item.GetComponent<CharacterMaster>().minionOwnership.ownerMaster)
					{
						returnOrder.Add(item);
						num += itemStealController.GetStolenItemCount(item);
					}
				}
				float num2 = Mathf.Clamp(100f / (float)Math.Max(num, 1), minPercentagePerItem, maxPercentagePerItem) / 100f;
				damagePerItem = healthComponent.fullCombinedHealth * num2;
				accumulatedDamage += damagePerItem * initialPercentageToFirstItem / 100f;
				_itemStealController.onLendingFinishServer.RemoveListener(InitializeDamageTracking);
			}
			damageTrackingInitialized = true;
		}
	}
	[RequireComponent(typeof(QuaternionPID))]
	[RequireComponent(typeof(VectorPID))]
	public class RigidbodyDirection : MonoBehaviour
	{
		public UnityEngine.Vector3 aimDirection = UnityEngine.Vector3.one;

		public Rigidbody rigid;

		public QuaternionPID angularVelocityPID;

		public VectorPID torquePID;

		public bool freezeXRotation;

		public bool freezeYRotation;

		public bool freezeZRotation;

		private ModelLocator modelLocator;

		private Animator animator;

		public string animatorXCycle;

		public string animatorYCycle;

		public string animatorZCycle;

		private int animatorXCycleIndex;

		private int animatorYCycleIndex;

		private int animatorZCycleIndex;

		public float animatorTorqueScale;

		private InputBankTest inputBank;

		private UnityEngine.Vector3 targetTorque;

		private RendererVisiblity visibility;

		private void Start()
		{
			inputBank = GetComponent<InputBankTest>();
			modelLocator = GetComponent<ModelLocator>();
			if ((bool)modelLocator)
			{
				visibility = modelLocator.modelVisibility;
				Transform modelTransform = modelLocator.modelTransform;
				if ((bool)modelTransform)
				{
					animator = modelTransform.GetComponent<Animator>();
					if ((bool)animator)
					{
						animatorXCycleIndex = Animator.StringToHash(animatorXCycle);
						animatorYCycleIndex = Animator.StringToHash(animatorYCycle);
						animatorZCycleIndex = Animator.StringToHash(animatorZCycle);
					}
				}
			}
			aimDirection = base.transform.forward;
		}

		private void Update()
		{
			if ((bool)animator)
			{
				if (animatorXCycle.Length > 0)
				{
					animator.SetFloat(animatorXCycleIndex, Mathf.Clamp(0.5f + targetTorque.x * 0.5f * animatorTorqueScale, -1f, 1f), 0.1f, Time.deltaTime);
				}
				if (animatorYCycle.Length > 0)
				{
					animator.SetFloat(animatorYCycleIndex, Mathf.Clamp(0.5f + targetTorque.y * 0.5f * animatorTorqueScale, -1f, 1f), 0.1f, Time.deltaTime);
				}
				if (animatorZCycle.Length > 0)
				{
					animator.SetFloat(animatorZCycleIndex, Mathf.Clamp(0.5f + targetTorque.z * 0.5f * animatorTorqueScale, -1f, 1f), 0.1f, Time.deltaTime);
				}
			}
		}

		private void FixedUpdate()
		{
			if ((bool)inputBank && (bool)rigid && (bool)angularVelocityPID && (bool)torquePID)
			{
				angularVelocityPID.inputQuat = rigid.rotation;
				UnityEngine.Quaternion targetQuat = Util.QuaternionSafeLookRotation(aimDirection);
				if (freezeXRotation)
				{
					targetQuat.x = 0f;
				}
				if (freezeYRotation)
				{
					targetQuat.y = 0f;
				}
				if (freezeZRotation)
				{
					targetQuat.z = 0f;
				}
				angularVelocityPID.targetQuat = targetQuat;
				UnityEngine.Vector3 targetVector = angularVelocityPID.UpdatePID();
				torquePID.inputVector = rigid.angularVelocity;
				torquePID.targetVector = targetVector;
				UnityEngine.Vector3 torque = torquePID.UpdatePID();
				rigid.AddTorque(torque, ForceMode.Acceleration);
			}
		}
	}
	[RequireComponent(typeof(InputBankTest))]
	[RequireComponent(typeof(CharacterBody))]
	[RequireComponent(typeof(VectorPID))]
	public class RigidbodyMotor : NetworkBehaviour, IPhysMotor, IDisplacementReceiver
	{
		[HideInInspector]
		public UnityEngine.Vector3 moveVector;

		public Rigidbody rigid;

		public VectorPID forcePID;

		public UnityEngine.Vector3 centerOfMassOffset;

		public string animatorForward;

		public string animatorRight;

		public string animatorUp;

		public bool enableOverrideMoveVectorInLocalSpace;

		public bool canTakeImpactDamage = true;

		public UnityEngine.Vector3 overrideMoveVectorInLocalSpace;

		private NetworkIdentity networkIdentity;

		private CharacterBody characterBody;

		private InputBankTest inputBank;

		private ModelLocator modelLocator;

		private Animator animator;

		private BodyAnimatorSmoothingParameters bodyAnimatorSmoothingParameters;

		private HealthComponent healthComponent;

		private UnityEngine.Vector3 rootMotion;

		private const float impactDamageStrength = 0.07f;

		private static int kRpcRpcApplyForceImpulse;

		public bool hasEffectiveAuthority => Util.HasEffectiveAuthority(networkIdentity);

		public float mass => rigid.mass;

		float IPhysMotor.mass => rigid.mass;

		UnityEngine.Vector3 IPhysMotor.velocity => rigid.velocity;

		UnityEngine.Vector3 IPhysMotor.velocityAuthority
		{
			get
			{
				return rigid.velocity;
			}
			set
			{
				rigid.velocity = value;
			}
		}

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			characterBody = GetComponent<CharacterBody>();
			inputBank = GetComponent<InputBankTest>();
			modelLocator = GetComponent<ModelLocator>();
			healthComponent = GetComponent<HealthComponent>();
			bodyAnimatorSmoothingParameters = GetComponent<BodyAnimatorSmoothingParameters>();
		}

		private void Start()
		{
			UpdateAuthority();
			UnityEngine.Vector3 centerOfMass = rigid.centerOfMass;
			centerOfMass += centerOfMassOffset;
			rigid.centerOfMass = centerOfMass;
			if ((bool)modelLocator)
			{
				Transform modelTransform = modelLocator.modelTransform;
				if ((bool)modelTransform)
				{
					animator = modelTransform.GetComponent<Animator>();
				}
			}
		}

		private void OnDrawGizmosSelected()
		{
			Gizmos.color = UnityEngine.Color.red;
			Gizmos.DrawSphere(base.transform.position + rigid.centerOfMass, 0.5f);
		}

		public static float GetPitch(UnityEngine.Vector3 v)
		{
			float x = Mathf.Sqrt(v.x * v.x + v.z * v.z);
			return 0f - Mathf.Atan2(v.y, x);
		}

		private void Update()
		{
			if ((bool)animator)
			{
				UnityEngine.Vector3 vector = base.transform.InverseTransformVector(moveVector) / Mathf.Max(1f, moveVector.magnitude);
				BodyAnimatorSmoothingParameters.SmoothingParameters smoothingParameters = (bodyAnimatorSmoothingParameters ? bodyAnimatorSmoothingParameters.smoothingParameters : BodyAnimatorSmoothingParameters.defaultParameters);
				if (animatorForward.Length > 0)
				{
					animator.SetFloat(animatorForward, vector.z, smoothingParameters.forwardSpeedSmoothDamp, Time.deltaTime);
				}
				if (animatorRight.Length > 0)
				{
					animator.SetFloat(animatorRight, vector.x, smoothingParameters.rightSpeedSmoothDamp, Time.deltaTime);
				}
				if (animatorUp.Length > 0)
				{
					animator.SetFloat(animatorUp, vector.y, smoothingParameters.forwardSpeedSmoothDamp, Time.deltaTime);
				}
			}
		}

		private void FixedUpdate()
		{
			if (!inputBank || !rigid)
			{
				return;
			}
			if ((bool)forcePID)
			{
				if (enableOverrideMoveVectorInLocalSpace)
				{
					moveVector = base.transform.TransformDirection(overrideMoveVectorInLocalSpace) * characterBody.moveSpeed;
				}
				_ = inputBank.aimDirection;
				UnityEngine.Vector3 targetVector = moveVector;
				forcePID.inputVector = rigid.velocity;
				forcePID.targetVector = targetVector;
				UnityEngine.Debug.DrawLine(base.transform.position, base.transform.position + forcePID.targetVector, UnityEngine.Color.red, 0.1f);
				UnityEngine.Vector3 vector = forcePID.UpdatePID();
				rigid.AddForceAtPosition(UnityEngine.Vector3.ClampMagnitude(vector * (characterBody.acceleration / 3f), characterBody.acceleration), base.transform.position, ForceMode.Acceleration);
			}
			if (rootMotion != UnityEngine.Vector3.zero)
			{
				rigid.MovePosition(rigid.position + rootMotion);
				rootMotion = UnityEngine.Vector3.zero;
			}
		}

		private void OnCollisionEnter(Collision collision)
		{
			if (canTakeImpactDamage && collision.gameObject.layer == LayerIndex.world.intVal)
			{
				float num = Mathf.Max(characterBody.moveSpeed, characterBody.baseMoveSpeed) * 4f;
				float magnitude = collision.relativeVelocity.magnitude;
				if (magnitude >= num)
				{
					float num2 = magnitude / characterBody.moveSpeed * 0.07f;
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = Mathf.Min(healthComponent.fullCombinedHealth, healthComponent.fullCombinedHealth * num2);
					damageInfo.procCoefficient = 0f;
					damageInfo.position = collision.contacts[0].point;
					damageInfo.attacker = healthComponent.lastHitAttacker;
					healthComponent.TakeDamage(damageInfo);
				}
			}
		}

		public override void OnStartAuthority()
		{
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			UpdateAuthority();
		}

		public void AddDisplacement(UnityEngine.Vector3 displacement)
		{
			rootMotion += displacement;
		}

		public void ApplyForceImpulse(in PhysForceInfo forceInfo)
		{
			if (NetworkServer.active && !hasEffectiveAuthority)
			{
				CallRpcApplyForceImpulse(forceInfo);
			}
			else
			{
				rigid.AddForce(forceInfo.force, (!forceInfo.massIsOne) ? ForceMode.Impulse : ForceMode.VelocityChange);
			}
		}

		[ClientRpc]
		private void RpcApplyForceImpulse(PhysForceInfo physForceInfo)
		{
			if (!NetworkServer.active)
			{
				ApplyForceImpulse(in physForceInfo);
			}
		}

		private void UpdateAuthority()
		{
			base.enabled = hasEffectiveAuthority;
		}

		void IPhysMotor.ApplyForceImpulse(in PhysForceInfo physForceInfo)
		{
			ApplyForceImpulse(in physForceInfo);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcApplyForceImpulse(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcApplyForceImpulse called on server.");
			}
			else
			{
				((RigidbodyMotor)obj).RpcApplyForceImpulse(GeneratedNetworkCode._ReadPhysForceInfo_None(reader));
			}
		}

		public void CallRpcApplyForceImpulse(PhysForceInfo physForceInfo)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcApplyForceImpulse called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcApplyForceImpulse);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WritePhysForceInfo_None(networkWriter, physForceInfo);
			SendRPCInternal(networkWriter, 0, "RpcApplyForceImpulse");
		}

		static RigidbodyMotor()
		{
			kRpcRpcApplyForceImpulse = 1386350170;
			NetworkBehaviour.RegisterRpcDelegate(typeof(RigidbodyMotor), kRpcRpcApplyForceImpulse, InvokeRpcRpcApplyForceImpulse);
			NetworkCRC.RegisterBehaviour("RigidbodyMotor", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(Collider))]
	[RequireComponent(typeof(Rigidbody))]
	public class RigidbodySoundOnImpact : MonoBehaviour
	{
		private Rigidbody rb;

		public string impactSoundString;

		public NetworkSoundEventDef networkedSoundEvent;

		public float minimumRelativeVelocityMagnitude;

		private float ditherTimer;

		private void Start()
		{
			rb = GetComponent<Rigidbody>();
		}

		private void FixedUpdate()
		{
			ditherTimer -= Time.fixedDeltaTime;
		}

		private void OnCollisionEnter(Collision collision)
		{
			if (!(ditherTimer > 0f) && !rb.isKinematic && collision.transform.gameObject.layer == LayerIndex.world.intVal && collision.relativeVelocity.sqrMagnitude > minimumRelativeVelocityMagnitude * minimumRelativeVelocityMagnitude)
			{
				if (impactSoundString != null)
				{
					Util.PlaySound(impactSoundString, base.gameObject);
				}
				if (networkedSoundEvent != null)
				{
					PointSoundManager.EmitSoundServer(networkedSoundEvent.index, base.transform.position);
				}
				ditherTimer = 0.5f;
			}
		}
	}
	[RequireComponent(typeof(Collider))]
	[RequireComponent(typeof(Rigidbody))]
	public class RigidbodyStickOnImpact : MonoBehaviour
	{
		private Rigidbody rb;

		public string stickSoundString;

		public GameObject stickEffectPrefab;

		public float minimumRelativeVelocityMagnitude;

		public AnimationCurve embedDistanceCurve;

		private bool stuck;

		private float stopwatchSinceStuck;

		private UnityEngine.Vector3 contactNormal;

		private UnityEngine.Vector3 contactPosition;

		private UnityEngine.Vector3 transformPositionWhenContacted;

		private void Awake()
		{
			rb = GetComponent<Rigidbody>();
		}

		private void Update()
		{
			if (stuck)
			{
				stopwatchSinceStuck += Time.deltaTime;
				base.transform.position = transformPositionWhenContacted + embedDistanceCurve.Evaluate(stopwatchSinceStuck) * contactNormal;
			}
		}

		private void OnCollisionEnter(Collision collision)
		{
			if (!stuck && !rb.isKinematic && collision.transform.gameObject.layer == LayerIndex.world.intVal && collision.relativeVelocity.sqrMagnitude > minimumRelativeVelocityMagnitude * minimumRelativeVelocityMagnitude)
			{
				stuck = true;
				ContactPoint contact = collision.GetContact(0);
				contactNormal = contact.normal;
				contactPosition = contact.point;
				transformPositionWhenContacted = base.transform.position;
				EffectManager.SpawnEffect(stickEffectPrefab, new EffectData
				{
					origin = contactPosition,
					rotation = Util.QuaternionSafeLookRotation(contactNormal)
				}, transmit: false);
				Util.PlaySound(stickSoundString, base.gameObject);
				rb.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
				rb.detectCollisions = false;
				rb.isKinematic = true;
				rb.velocity = UnityEngine.Vector3.zero;
			}
		}
	}
	public class RoachController : MonoBehaviour
	{
		[Serializable]
		public struct KeyFrame
		{
			public float time;

			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;
		}

		[Serializable]
		public class Roach
		{
			public KeyFrame[] keyFrames;

			private int frameIndex = 1;

			public KeyFrame lowFrame => keyFrames[frameIndex - 1];

			public KeyFrame highFrame => keyFrames[frameIndex];

			public bool CanBeUpdated(float timeSince)
			{
				return frameIndex < keyFrames.Length - 1;
			}

			public void UpdateRoach(RoachController controller, int roachIndex, float timeSince)
			{
				float num = Mathf.Min(timeSince, keyFrames[keyFrames.Length - 1].time);
				if (highFrame.time <= num)
				{
					Iterate();
				}
				float t = Mathf.InverseLerp(lowFrame.time, highFrame.time, num);
				controller.SetRoachPosition(roachIndex, UnityEngine.Vector3.Lerp(lowFrame.position, highFrame.position, t), UnityEngine.Quaternion.Slerp(lowFrame.rotation, highFrame.rotation, t));
			}

			public void Iterate()
			{
				if (frameIndex < keyFrames.Length - 1)
				{
					frameIndex++;
				}
			}
		}

		private class SimulatedRoach : IDisposable
		{
			private struct RaycastResult
			{
				public bool didHit;

				public UnityEngine.Vector3 point;

				public UnityEngine.Vector3 normal;

				public float distance;
			}

			private UnityEngine.Vector3 initialFleeNormal;

			private UnityEngine.Vector3 desiredMovement;

			private RoachParams roachParams;

			private float reorientTimer;

			private float backupTimer;

			private UnityEngine.Vector3 velocity = UnityEngine.Vector3.zero;

			private float currentSpeed;

			private float turnVelocity;

			private UnityEngine.Vector3 groundNormal;

			private float simulationDuration;

			public Transform transform { get; private set; }

			public float age { get; private set; }

			public bool finished { get; private set; }

			private bool onGround => groundNormal != UnityEngine.Vector3.zero;

			public SimulatedRoach(UnityEngine.Vector3 position, UnityEngine.Vector3 groundNormal, UnityEngine.Vector3 initialFleeNormal, RoachParams roachParams)
			{
				this.roachParams = roachParams;
				GameObject gameObject = new GameObject("SimulatedRoach");
				transform = gameObject.transform;
				transform.position = position;
				transform.up = groundNormal;
				transform.Rotate(transform.up, UnityEngine.Random.Range(0f, 360f));
				transform.forward = UnityEngine.Random.onUnitSphere;
				this.groundNormal = groundNormal;
				this.initialFleeNormal = initialFleeNormal;
				desiredMovement = UnityEngine.Random.onUnitSphere;
				age = UnityEngine.Random.Range(roachParams.minReactionTime, roachParams.maxReactionTime);
				simulationDuration = age + UnityEngine.Random.Range(roachParams.minSimulationDuration, roachParams.maxSimulationDuration);
			}

			private void SetUpVector(UnityEngine.Vector3 desiredUp)
			{
				UnityEngine.Vector3 right = transform.right;
				UnityEngine.Vector3 up = transform.up;
				transform.Rotate(right, UnityEngine.Vector3.SignedAngle(up, desiredUp, right), Space.World);
			}

			public void Simulate(float deltaTime)
			{
				age += deltaTime;
				if (onGround)
				{
					SetUpVector(groundNormal);
					turnVelocity += UnityEngine.Random.Range(0f - roachParams.wiggle, roachParams.wiggle) * deltaTime;
					TurnDesiredMovement(turnVelocity * deltaTime);
					UnityEngine.Vector3 up = transform.up;
					UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(desiredMovement, up).normalized;
					float value = UnityEngine.Vector3.SignedAngle(transform.forward, normalized, up);
					TurnBody(Mathf.Clamp(value, (0f - turnVelocity) * deltaTime, turnVelocity * deltaTime));
					currentSpeed = Mathf.MoveTowards(currentSpeed, roachParams.maxSpeed, deltaTime * roachParams.acceleration);
					StepGround(currentSpeed * deltaTime);
				}
				else
				{
					velocity += Physics.gravity * deltaTime;
					StepAir(velocity);
				}
				reorientTimer -= deltaTime;
				if (reorientTimer <= 0f)
				{
					desiredMovement = initialFleeNormal;
					reorientTimer = UnityEngine.Random.Range(roachParams.reorientTimerMin, roachParams.reorientTimerMax);
				}
				if (age >= simulationDuration)
				{
					finished = true;
				}
			}

			private void OnBump()
			{
				TurnDesiredMovement(UnityEngine.Random.Range(-90f, 90f));
				currentSpeed *= -0.5f;
				if (roachParams.chanceToFinishOnBump < UnityEngine.Random.value)
				{
					finished = true;
				}
			}

			private void TurnDesiredMovement(float degrees)
			{
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(degrees, transform.up);
				desiredMovement = quaternion * desiredMovement;
			}

			private void TurnBody(float degrees)
			{
				transform.Rotate(UnityEngine.Vector3.up, degrees, Space.Self);
			}

			private void StepAir(UnityEngine.Vector3 movement)
			{
				RaycastResult raycastResult = SimpleRaycast(new Ray(transform.position, movement), movement.magnitude);
				UnityEngine.Debug.DrawLine(transform.position, raycastResult.point, UnityEngine.Color.magenta, 10f, depthTest: false);
				if (raycastResult.didHit)
				{
					groundNormal = raycastResult.normal;
					velocity = UnityEngine.Vector3.zero;
				}
				transform.position = raycastResult.point;
			}

			private void StepGround(float distance)
			{
				groundNormal = UnityEngine.Vector3.zero;
				UnityEngine.Vector3 up = transform.up;
				UnityEngine.Vector3 forward = transform.forward;
				float stepSize = roachParams.stepSize;
				UnityEngine.Vector3 vector = up * stepSize;
				UnityEngine.Vector3 position = transform.position;
				position += vector;
				UnityEngine.Debug.DrawLine(transform.position, position, UnityEngine.Color.red, 10f, depthTest: false);
				RaycastResult raycastResult = SimpleRaycast(new Ray(position, forward), distance);
				UnityEngine.Debug.DrawLine(position, raycastResult.point, UnityEngine.Color.green, 10f, depthTest: false);
				position = raycastResult.point;
				if (raycastResult.didHit)
				{
					if (UnityEngine.Vector3.Dot(raycastResult.normal, forward) < -0.5f)
					{
						OnBump();
					}
					groundNormal = raycastResult.normal;
				}
				else
				{
					RaycastResult raycastResult2 = SimpleRaycast(new Ray(position, -vector), stepSize * 2f);
					if (raycastResult2.didHit)
					{
						UnityEngine.Debug.DrawLine(position, raycastResult2.point, UnityEngine.Color.blue, 10f, depthTest: false);
						position = raycastResult2.point;
						groundNormal = raycastResult2.normal;
					}
					else
					{
						UnityEngine.Debug.DrawLine(position, position - vector, UnityEngine.Color.white, 10f);
						position -= vector;
					}
				}
				if (groundNormal == UnityEngine.Vector3.zero)
				{
					currentSpeed = 0f;
				}
				transform.position = position;
			}

			private static RaycastResult SimpleRaycast(Ray ray, float maxDistance)
			{
				RaycastHit hitInfo;
				bool flag = Physics.Raycast(ray, out hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
				RaycastResult result = default(RaycastResult);
				result.didHit = flag;
				result.point = (flag ? hitInfo.point : ray.GetPoint(maxDistance));
				result.normal = (flag ? hitInfo.normal : UnityEngine.Vector3.zero);
				result.distance = (flag ? hitInfo.distance : maxDistance);
				return result;
			}

			public void Dispose()
			{
				UnityEngine.Object.DestroyImmediate(transform.gameObject);
				transform = null;
			}
		}

		public class RoachPathEditorComponent : MonoBehaviour
		{
			public RoachController roachController;

			public int nodeCount => base.transform.childCount;

			public RoachNodeEditorComponent AddNode()
			{
				GameObject obj = new GameObject("Roach Path Node (Temporary)");
				obj.hideFlags = HideFlags.DontSave;
				obj.transform.SetParent(base.transform);
				RoachNodeEditorComponent roachNodeEditorComponent = obj.AddComponent<RoachNodeEditorComponent>();
				roachNodeEditorComponent.path = this;
				return roachNodeEditorComponent;
			}

			private void OnDrawGizmosSelected()
			{
				Gizmos.color = UnityEngine.Color.white;
				for (int i = 0; i + 1 < nodeCount; i++)
				{
					UnityEngine.Vector3 position = base.transform.GetChild(i).transform.position;
					UnityEngine.Vector3 position2 = base.transform.GetChild(i + 1).transform.position;
					Gizmos.DrawLine(position, position2);
				}
			}
		}

		public class RoachNodeEditorComponent : MonoBehaviour
		{
			public RoachPathEditorComponent path;

			public void FacePosition(UnityEngine.Vector3 position)
			{
				UnityEngine.Vector3 position2 = base.transform.position;
				UnityEngine.Vector3 up = base.transform.up;
				UnityEngine.Quaternion rotation = UnityEngine.Quaternion.LookRotation(position - position2, up);
				base.transform.rotation = rotation;
				base.transform.up = up;
			}
		}

		public RoachParams roachParams;

		public int roachCount;

		public float placementSpreadMin = 1f;

		public float placementSpreadMax = 25f;

		public float placementMaxDistance = 10f;

		public Roach[] roaches;

		private Transform[] roachTransforms;

		private bool scattered;

		private Run.TimeStamp scatterStartTime = Run.TimeStamp.positiveInfinity;

		private const string roachScatterSoundString = "Play_env_roach_scatter";

		private void Awake()
		{
			roachTransforms = new Transform[roaches.Length];
			for (int i = 0; i < roachTransforms.Length; i++)
			{
				roachTransforms[i] = UnityEngine.Object.Instantiate(roachParams.roachPrefab, roaches[i].keyFrames[0].position, roaches[i].keyFrames[0].rotation).transform;
			}
		}

		private void OnDestroy()
		{
			for (int i = 0; i < roachTransforms.Length; i++)
			{
				if ((bool)roachTransforms[i])
				{
					UnityEngine.Object.Destroy(roachTransforms[i].gameObject);
				}
			}
		}

		public void BakeRoaches2()
		{
			List<Roach> list = new List<Roach>();
			for (int i = 0; i < roachCount; i++)
			{
				Ray ray = new Ray(base.transform.position, Util.ApplySpread(base.transform.forward, placementSpreadMin, placementSpreadMax, 1f, 1f));
				if (Physics.Raycast(ray, out var hitInfo, placementMaxDistance, LayerIndex.world.mask))
				{
					SimulatedRoach simulatedRoach = new SimulatedRoach(hitInfo.point + hitInfo.normal * 0.01f, hitInfo.normal, ray.direction, roachParams);
					float keyframeInterval = roachParams.keyframeInterval;
					List<KeyFrame> list2 = new List<KeyFrame>();
					while (!simulatedRoach.finished)
					{
						simulatedRoach.Simulate(keyframeInterval);
						list2.Add(new KeyFrame
						{
							position = simulatedRoach.transform.position,
							rotation = simulatedRoach.transform.rotation,
							time = simulatedRoach.age
						});
					}
					KeyFrame value = list2[list2.Count - 1];
					value.position += value.rotation * (UnityEngine.Vector3.down * 0.25f);
					list2[list2.Count - 1] = value;
					simulatedRoach.Dispose();
					list.Add(new Roach
					{
						keyFrames = list2.ToArray()
					});
				}
			}
			roaches = list.ToArray();
		}

		public void BakeRoaches()
		{
			BakeRoaches2();
		}

		private void ClearRoachPathEditors()
		{
			for (int num = base.transform.childCount - 1; num > 0; num--)
			{
				UnityEngine.Object.DestroyImmediate(base.transform.GetChild(num).gameObject);
			}
		}

		public void DebakeRoaches()
		{
			ClearRoachPathEditors();
			for (int i = 0; i < roaches.Length; i++)
			{
				Roach roach = roaches[i];
				RoachPathEditorComponent roachPathEditorComponent = AddPathEditorObject();
				for (int j = 0; j < roach.keyFrames.Length; j++)
				{
					KeyFrame keyFrame = roach.keyFrames[j];
					RoachNodeEditorComponent roachNodeEditorComponent = roachPathEditorComponent.AddNode();
					roachNodeEditorComponent.transform.position = keyFrame.position;
					roachNodeEditorComponent.transform.rotation = keyFrame.rotation;
				}
			}
		}

		public RoachPathEditorComponent AddPathEditorObject()
		{
			GameObject obj = new GameObject("Roach Path (Temporary)");
			obj.hideFlags = HideFlags.DontSave;
			obj.transform.SetParent(base.transform, worldPositionStays: false);
			RoachPathEditorComponent roachPathEditorComponent = obj.AddComponent<RoachPathEditorComponent>();
			roachPathEditorComponent.roachController = this;
			return roachPathEditorComponent;
		}

		private void SetRoachPosition(int i, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			roachTransforms[i].SetPositionAndRotation(position, rotation);
		}

		private void Update()
		{
			if (!scattered)
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < roaches.Length; i++)
			{
				if (roaches[i].CanBeUpdated(scatterStartTime.timeSince))
				{
					roaches[i].UpdateRoach(this, i, scatterStartTime.timeSince);
					num++;
				}
			}
			if (num == 0)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void Scatter()
		{
			if (!scattered)
			{
				Util.PlaySound("Play_env_roach_scatter", base.gameObject);
				scattered = true;
				scatterStartTime = Run.TimeStamp.now;
			}
		}

		private void OnTriggerEnter(Collider other)
		{
			CharacterBody component = other.GetComponent<CharacterBody>();
			if ((object)component != null && component.isPlayerControlled)
			{
				Scatter();
			}
		}

		private void OnDrawGizmos()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			Gizmos.matrix = UnityEngine.Matrix4x4.TRS(base.transform.position, base.transform.rotation, UnityEngine.Vector3.one);
			Gizmos.DrawFrustum(UnityEngine.Vector3.zero, placementSpreadMax * 0.5f, placementMaxDistance, 0f, 1f);
		}
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
	public class InitDuringStartupAttribute : HG.Reflection.SearchableAttribute
	{
		public static bool loadingIsComplete;

		public static IEnumerator Execute()
		{
			int currentPass = 0;
			int maxPassesBeforeYielding = 5;
			RoR2Application.PrintSW("InitDuringStartupAttribute before assembly scan");
			List<HG.Reflection.SearchableAttribute> instances = HG.Reflection.SearchableAttribute.GetInstances<InitDuringStartupAttribute>();
			RoR2Application.PrintSW("InitDuringStartupAttribute after assembly scan");
			int i = 0;
			foreach (InitDuringStartupAttribute item in instances)
			{
				Type declaringType = (item.target as MethodInfo).DeclaringType;
				RoR2Application.PrintSW("InitDuringStartupAttribute running attribute " + i + " " + declaringType.ToString());
				int num = i + 1;
				i = num;
				((Action)Delegate.CreateDelegate(typeof(Action), item.target as MethodInfo))();
				currentPass++;
				if (currentPass >= maxPassesBeforeYielding)
				{
					currentPass = 0;
					yield return null;
				}
			}
			loadingIsComplete = true;
		}
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
	public class InitAfterContentLoaded : HG.Reflection.SearchableAttribute
	{
		public static bool loadingIsComplete;

		public static IEnumerator Execute()
		{
			int currentPass = 0;
			int maxPassesBeforeYielding = 5;
			List<HG.Reflection.SearchableAttribute> instances = HG.Reflection.SearchableAttribute.GetInstances<InitAfterContentLoaded>();
			foreach (InitAfterContentLoaded item in instances)
			{
				((Action)Delegate.CreateDelegate(typeof(Action), item.target as MethodInfo))();
				currentPass++;
				if (currentPass >= maxPassesBeforeYielding)
				{
					currentPass = 0;
					yield return null;
				}
			}
			loadingIsComplete = true;
		}
	}
	public class RoR2Application : MonoBehaviour
	{
		public static readonly string messageForModders = "We don't officially support modding at this time but if you're going to mod the game please change this value to true if you're modding the game. This will disable some things like Prismatic Trials and put players into a separate matchmaking queue from vanilla users to protect their game experience.";

		public static bool isModded = false;

		public GameObject networkManagerPrefab;

		public GameObject platformManagerPrefab;

		public GameObject networkSessionPrefab;

		public GameObject pauseStopController;

		public PostProcessVolume postProcessSettingsController;

		public Canvas mainCanvas;

		public UnityEngine.UI.Image saveIconImage;

		public Behaviour[] BehavioursToEnableDuringStartup;

		public static Stopwatch _stopwatch = new Stopwatch();

		public static long _lastCheckTime;

		private int loadGameContentPercentage;

		public float KCSUpdateFPS = 15f;

		public static int numFixedUpdateCalls = 0;

		public const string gameName = "Risk of Rain 2";

		private const uint ror1AppId = 248820u;

		public const uint ror2AppId = 632360u;

		private const uint ror2DedicatedServerAppId = 1180760u;

		public const bool isDedicatedServer = false;

		public const uint appId = 632360u;

		public static string steamBuildId = "STEAM_UNINITIALIZED";

		private static string buildId;

		public static readonly int hardMaxPlayers = 16;

		public static readonly int maxPlayers = 4;

		public static readonly int maxLocalPlayers = 4;

		public static Type[] AssemblyTypes = null;

		private static IntConVar waitMsConVar = new IntConVar("wait_ms", ConVarFlags.None, "-1", "How many milliseconds to sleep between each frame. -1 for no sleeping between frames.");

		public static readonly TimerQueue timeTimers = new TimerQueue();

		public static readonly TimerQueue fixedTimeTimers = new TimerQueue();

		public static readonly TimerQueue unscaledTimeTimers = new TimerQueue();

		private ulong totalFixedUpdateCount;

		public static FileSystem cloudStorage;

		public static Func<bool> loadSteamworksClient;

		public static Action unloadSteamworksClient;

		private Stack<UnityEngine.ThreadPriority> PriorityStack = new Stack<UnityEngine.ThreadPriority>();

		public static Action onLoad;

		public static Action onLoadFinished;

		public static Action onStart;

		public static Action onShutDown;

		public static bool isInLocalMultiPlayer = false;

		public static readonly Xoroshiro128Plus rng = new Xoroshiro128Plus((ulong)DateTime.UtcNow.Ticks);

		public static long lastDuration => _stopwatch.ElapsedMilliseconds - _lastCheckTime;

		public static Stopwatch stopwatch
		{
			get
			{
				if (!_stopwatch.IsRunning)
				{
					_stopwatch.Start();
				}
				_lastCheckTime = _stopwatch.ElapsedMilliseconds;
				return _stopwatch;
			}
			private set
			{
			}
		}

		public static bool IsMainMenuInitialized { get; private set; } = false;


		public static bool IsEntitlementsUpdated { get; private set; } = false;


		public static bool IsAllUsersEntitlementsUpdated { get; set; } = false;


		public Client steamworksClient { get; private set; }

		public static RoR2Application instance { get; private set; }

		public static bool IsMainScene => SceneManager.GetActiveScene().name == "title";

		public static FileSystem fileSystem { get; private set; }

		public static bool loadFinished { get; private set; } = false;


		public static bool isLoading { get; private set; } = false;


		public static bool isInSinglePlayer
		{
			get
			{
				if (NetworkServer.active && NetworkServer.dontListen)
				{
					return !isInLocalMultiPlayer;
				}
				return false;
			}
		}

		public static bool isInMultiPlayer
		{
			get
			{
				if (NetworkClient.active)
				{
					if (NetworkServer.active && NetworkServer.dontListen)
					{
						return isInLocalMultiPlayer;
					}
					return true;
				}
				return false;
			}
		}

		public static event Action onUpdate;

		public static event Action onFixedUpdate;

		public static event Action onLateUpdate;

		public static event Action onNextUpdate;

		private static void AssignBuildId()
		{
			buildId = Application.version;
		}

		public static string GetBuildId()
		{
			return buildId;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void PrintSW(string message)
		{
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Print(object text)
		{
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void PrintError(object text)
		{
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Print(string text)
		{
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void Print(string format, params object[] arguments)
		{
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void PrintWarning(object text)
		{
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void PrintException(Exception exception)
		{
		}

		private void Awake()
		{
			if (maxPlayers != 4 || (Application.genuineCheckAvailable && !Application.genuine))
			{
				isModded = true;
			}
			UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
			if ((bool)instance)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			instance = this;
			AssignBuildId();
			Print("buildId = " + buildId);
			if (AssemblyTypes == null)
			{
				AssemblyTypes = Assembly.GetExecutingAssembly().GetTypes();
			}
			if (!isLoading)
			{
				isLoading = true;
				StartCoroutine(OnLoad());
			}
			MainMenuController.OnMainMenuInitialised += OnMainMenuControllerInitialized;
			BaseUserEntitlementTracker<LocalUser>.OnUserEntitlementsUpdated = (Action)Delegate.Combine(BaseUserEntitlementTracker<LocalUser>.OnUserEntitlementsUpdated, new Action(OnEntitlementsUpdated));
			BaseUserEntitlementTracker<LocalUser>.OnAllUserEntitlementsUpdated = (Action)Delegate.Combine(BaseUserEntitlementTracker<LocalUser>.OnAllUserEntitlementsUpdated, new Action(OnAllUsersEntitlementsUpdated));
		}

		public static IEnumerator TransferToSceneAdditivelyAsync(string _sceneGuid)
		{
			Scene oldScene = SceneManager.GetActiveScene();
			AsyncOperationHandle<SceneInstance> handler = Addressables.LoadSceneAsync(_sceneGuid, LoadSceneMode.Additive, activateOnLoad: false);
			yield return handler;
			yield return handler.Result.ActivateAsync();
			SceneManager.SetActiveScene(handler.Result.Scene);
			SceneManager.UnloadSceneAsync(oldScene);
		}

		private void Start()
		{
			if (instance == this && onStart != null)
			{
				onStart();
				onStart = null;
			}
			KinematicCharacterMotor.updateTimerMax = 1f / KCSUpdateFPS;
		}

		public static void HardStopPlayInEditor(string windowTitle, string windowMessage)
		{
		}

		private void Update()
		{
			if (waitMsConVar.value > 0)
			{
				Thread.Sleep(waitMsConVar.value);
			}
			UpdateCursorState();
			RoR2Application.onUpdate?.Invoke();
			Interlocked.Exchange(ref RoR2Application.onNextUpdate, null)?.Invoke();
			timeTimers.Update(Time.deltaTime);
			unscaledTimeTimers.Update(Time.unscaledDeltaTime);
		}

		private void OnMainMenuControllerInitialized()
		{
			MainMenuController.OnMainMenuInitialised -= OnMainMenuControllerInitialized;
			IsMainMenuInitialized = true;
		}

		private void OnEntitlementsUpdated()
		{
			BaseUserEntitlementTracker<LocalUser>.OnUserEntitlementsUpdated = (Action)Delegate.Remove(BaseUserEntitlementTracker<LocalUser>.OnUserEntitlementsUpdated, new Action(OnEntitlementsUpdated));
			IsEntitlementsUpdated = true;
		}

		private void OnAllUsersEntitlementsUpdated()
		{
			IsAllUsersEntitlementsUpdated = true;
		}

		public static void UpdateCursorState()
		{
			if (!Application.isBatchMode && MPEventSystemManager.kbmEventSystem != null)
			{
				CursorLockMode cursorLockMode = ((!MPEventSystemManager.kbmEventSystem.isCursorVisible && !MPEventSystemManager.combinedEventSystem.isCursorVisible) ? CursorLockMode.Locked : CursorLockMode.Confined);
				if (cursorLockMode != Cursor.lockState)
				{
					Cursor.lockState = cursorLockMode;
				}
				Cursor.visible = false;
			}
		}

		private void FixedUpdate()
		{
			totalFixedUpdateCount++;
			numFixedUpdateCalls++;
			RoR2Application.onFixedUpdate?.Invoke();
			fixedTimeTimers.Update(Time.fixedDeltaTime);
		}

		private void LateUpdate()
		{
			numFixedUpdateCalls = 0;
			RoR2Application.onLateUpdate?.Invoke();
		}

		private IEnumerator OnLoad()
		{
			return InitializeGameRoutine();
		}

		private void EnableBehaviours()
		{
			int num = BehavioursToEnableDuringStartup.Length;
			for (int i = 0; i < num; i++)
			{
				BehavioursToEnableDuringStartup[i].enabled = true;
			}
		}

		public void PushThreadPriority(UnityEngine.ThreadPriority newPriority)
		{
			Print("Pushing background loading priority to {0}. was:{1}", newPriority.ToString(), Application.backgroundLoadingPriority.ToString());
			PriorityStack.Push(Application.backgroundLoadingPriority);
			PlatformSystems.SetLoadingPriority(newPriority);
		}

		public void PopThreadPriority()
		{
			if (PriorityStack.Count > 0)
			{
				UnityEngine.ThreadPriority backgroundLoadingPriority = PriorityStack.Pop();
				Print("Popping background loading priority to {0}. was:{1}", backgroundLoadingPriority.ToString(), Application.backgroundLoadingPriority.ToString());
				Application.backgroundLoadingPriority = backgroundLoadingPriority;
			}
			else
			{
				Print("No previous background loading priority, keeping this priority: {0}.", Application.backgroundLoadingPriority.ToString());
			}
		}

		private IEnumerator InitializeGameRoutine()
		{
			PushThreadPriority(UnityEngine.ThreadPriority.High);
			isLoading = true;
			UnitySystemConsoleRedirector.Redirect();
			PrintSW("After ConsoleRedirector");
			SceneManager.sceneLoaded += delegate(Scene scene, LoadSceneMode loadSceneMode)
			{
				Print("Loaded scene {0} loadSceneMode={1}", scene.name, loadSceneMode);
			};
			SceneManager.sceneUnloaded += delegate(Scene scene)
			{
				Print("Unloaded scene {0}", scene.name);
			};
			SceneManager.activeSceneChanged += delegate(Scene oldScene, Scene newScene)
			{
				Print("Active scene changed from {0} to {1}", oldScene.name, newScene.name);
			};
			while (SceneManager.GetActiveScene().name != "loadingbasic")
			{
				yield return new WaitForEndOfFrame();
			}
			PrintSW("After loadingbasic");
			SpriteAsNumberManager loadingPercentIndicatorLabel = LoadingScreenCanvas.Instance.percentage;
			int loadDisplayPercentage = 0;
			if ((bool)loadingPercentIndicatorLabel)
			{
				loadingPercentIndicatorLabel.SetPercentValue(0);
			}
			yield return new WaitForEndOfFrame();
			yield return new WaitForEndOfFrame();
			PlatformSystems.SetLoadingPriority(UnityEngine.ThreadPriority.High);
			PrintSW("Before EnableBehaviors");
			EnableBehaviours();
			PrintSW("After EnableBehaviors");
			yield return IncrementPercentageAndWaitFrame();
			WwiseIntegrationManager.Init();
			PrintSW("After WwiseIntegrationManager");
			yield return IncrementPercentageAndWaitFrame();
			PhysicalFileSystem physicalFileSystem = new PhysicalFileSystem();
			SubFileSystem subFileSystem = new SubFileSystem(physicalFileSystem, physicalFileSystem.ConvertPathFromInternal(Application.dataPath));
			Print("application data path is" + Application.dataPath);
			fileSystem = subFileSystem;
			cloudStorage = fileSystem;
			PlatformSystems.Init();
			PrintSW("After PlatformSystems.Init");
			yield return IncrementPercentageAndWaitFrame();
			if (!(loadSteamworksClient?.Invoke() ?? false))
			{
				Application.Quit();
				yield break;
			}
			RewiredIntegrationManager.Init();
			PrintSW("After RewiredIntegrationManager.Init");
			yield return IncrementPercentageAndWaitFrame();
			ModLoader.instance.FlushOutput(UnityEngine.Debug.Log);
			ModLoader.instance.SetGameDataType((Mod mod) => new RoR2Mod(mod));
			ModLoader.instance.PostLaunch();
			ModLoader.instance.FlushOutput(UnityEngine.Debug.Log);
			UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/MPEventSystemManager"));
			GameObject networkManager = UnityEngine.Object.Instantiate(networkManagerPrefab);
			yield return IncrementPercentageAndWaitFrame();
			PlatformSystems.InitNetworkManagerSystem(networkManager);
			yield return IncrementPercentageAndWaitFrame();
			CharacterBody.Init();
			yield return IncrementPercentageAndWaitFrame();
			if (PlatformSystems.textDataManager != null)
			{
				while (!PlatformSystems.textDataManager.InitializedConfigFiles)
				{
					Print("Text config stuff still happening...");
					yield return null;
				}
			}
			PrintSW("After PlatformSystems");
			GameObject obj = new GameObject("Console");
			obj.AddComponent<SetDontDestroyOnLoad>();
			obj.AddComponent<Console>();
			while (!Console.loadingIsComplete)
			{
				yield return null;
			}
			PrintSW("After Console");
			StartCoroutine(InitDuringStartupAttribute.Execute());
			while (!InitDuringStartupAttribute.loadingIsComplete)
			{
				yield return null;
			}
			yield return IncrementPercentageAndWaitFrame();
			PrintSW("After InitDuringStartupAttribute");
			bool hasStartupError = false;
			try
			{
				AkSoundEngine.IsInitialized();
			}
			catch (DllNotFoundException)
			{
				IssueStartupError(new SimpleDialogBox.TokenParamsPair("STARTUP_FAILURE_DIALOG_TITLE"), new SimpleDialogBox.TokenParamsPair("MSVCR_2015_BAD_INSTALL_DIALOG_BODY"), new(string, Action)[1] { ("MSVCR_2015_BAD_INSTALL_DIALOG_DOWNLOAD_BUTTON", OpenVCR2015DownloadPage) });
			}
			QuickStopwatch.Begin("Loading Language");
			Language.collectLanguageRootFolders += delegate(List<string> list)
			{
				list.Add(System.IO.Path.Combine(Application.streamingAssetsPath, "Language"));
			};
			string[] platformStrings = PlatformSystems.platformStrings;
			foreach (string i in platformStrings)
			{
				Language.collectLanguageRootFolders += delegate(List<string> list)
				{
					list.Add(System.IO.Path.Combine(Application.streamingAssetsPath, "LanguageOverrides", i));
				};
			}
			QuickStopwatch.Lap("Collected Language Root Folders");
			yield return Language.Init();
			QuickStopwatch.Lap("Language Init Complete");
			QuickStopwatch.End();
			IncrementPercentageAndWaitFrame();
			PrintSW("After Language");
			MusicController.Init();
			DecaliciousRenderer.InitializeReferencesAsync();
			TypewriteTextController.PreLoadIntroTextFontAsync();
			yield return LegacyShaderAPI.Preload(IncrementPercentageAndWaitFrame());
			SobelCommandBuffer.PreloadShaderReference();
			RoR2Content.Init();
			PrintSW("After RoR2Content.Init");
			yield return null;
			Coroutine loadContentCoroutine = StartCoroutine(LoadGameContent(loadingPercentIndicatorLabel, loadDisplayPercentage));
			PrintSW("Before LoadGameContent");
			while ((float)loadGameContentPercentage < 25f)
			{
				yield return null;
			}
			yield return CameraRigController.InitializeReferences();
			if (!hasStartupError)
			{
				while (Console.instance == null)
				{
					Print("Console not initialized yet...");
					yield return null;
				}
				PrintSW("After splash load start");
				yield return StartCoroutine(LoadHelper.LoadSceneAdditivelyAsync("fe13e00695117284fb0d1b25422a0529"));
				PrintSW("After splash load end");
			}
			yield return LoadHelper.StartLoadSceneAdditiveAsync("330d792ae1727574e969e68ce8e966d2");
			yield return loadContentCoroutine;
			yield return new WaitForEndOfFrame();
			PrintSW("After LoadGameContent");
			if (platformManagerPrefab != null)
			{
				UnityEngine.Object.Instantiate(platformManagerPrefab);
			}
			PrintSW("After platformManager");
			PlatformSystems.InitPlatformManagerObject(base.gameObject);
			PrintSW("After InitPlatformManagerObject");
			GameObject platformVoiceManagerObject = PlatformSystems.GetPlatformVoiceManagerObject();
			if (platformVoiceManagerObject != null)
			{
				PrintError("RoR2Application - VoiceChatManager created?: " + UnityEngine.Object.Instantiate(platformVoiceManagerObject) == null);
			}
			PrintSW("After voiceChatManagerPrefab");
			yield return SystemInitializerAttribute.ExecuteCoroutine();
			PrintSW("After SystemInitializerAttribute");
			yield return AchievementManager.DoInit();
			PrintSW("After AchievementManager");
			SystemInitializerAttribute.RegisterPreInitializedType(typeof(AchievementManager));
			yield return LogBookController.Init();
			PrintSW("After LogBookController.Init()");
			SystemInitializerAttribute.RegisterPreInitializedType(typeof(LogBookController));
			yield return EntityStateCatalog.Init();
			PrintSW("After EntityStateCatalogInit");
			LocalUserManager.Init();
			PrintSW("After LocalUserManager.Init");
			PlatformSystems.saveSystem.LoadUserProfiles();
			if (onLoad != null)
			{
				onLoad();
				onLoad = null;
				PrintSW("After OnLoad event");
			}
			isLoading = false;
			loadFinished = true;
			PopThreadPriority();
			WaitForEndOfFrame IncrementPercentageAndWaitFrame()
			{
				if (loadingPercentIndicatorLabel != null)
				{
					loadingPercentIndicatorLabel.SetPercentValue(++loadDisplayPercentage);
				}
				return new WaitForEndOfFrame();
			}
			void IssueStartupError(SimpleDialogBox.TokenParamsPair headerToken, SimpleDialogBox.TokenParamsPair descriptionToken, (string token, Action action)[] buttons)
			{
				if (!hasStartupError)
				{
					hasStartupError = true;
					LocalUserManager.ClearUsers();
					NetworkManager.singleton.ServerChangeScene("title");
					SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
					simpleDialogBox.headerToken = headerToken;
					simpleDialogBox.descriptionToken = descriptionToken;
					simpleDialogBox.rootObject.transform.SetParent(mainCanvas.transform);
					OnDestroyCallback.AddCallback(simpleDialogBox.rootObject, delegate
					{
						Console.instance.SubmitCmd(null, "quit");
					});
					if (buttons != null)
					{
						for (int k = 0; k < buttons.Length; k++)
						{
							(string, Action) tuple = buttons[k];
							simpleDialogBox.AddActionButton(tuple.Item2.Invoke, tuple.Item1, true);
						}
					}
					simpleDialogBox.AddCancelButton("PAUSE_QUIT_TO_DESKTOP");
				}
			}
			static void OpenVCR2015DownloadPage()
			{
				Application.OpenURL("https://www.microsoft.com/en-us/download/details.aspx?id=48145");
			}
		}

		private IEnumerator LoadGameContent(SpriteAsNumberManager loadingPercentIndicatorLabel, int startPercentage)
		{
			float remainingPercentage = 100f - (float)startPercentage;
			TimeSpan maxLoadTimePerFrame = TimeSpan.FromSeconds(1.0 / 60.0);
			ContentManager.collectContentPackProviders += delegate(ContentManager.AddContentPackProviderDelegate addContentPackProvider)
			{
				addContentPackProvider(new RoR2Content());
				addContentPackProvider(new JunkContent());
				addContentPackProvider(new DLC1Content());
				addContentPackProvider(new CU8Content());
				addContentPackProvider(new DLC2Content());
				foreach (IContentPackProvider item3 in from mod in ModLoader.instance.allEnabledModsReadOnly
					select mod.GetGameData<RoR2Mod>().contentPackProvider into contentPackProvider
					where contentPackProvider != null
					select contentPackProvider)
				{
					addContentPackProvider(item3);
				}
			};
			ReadableProgress<float> contentLoadProgressReceiver = new ReadableProgress<float>();
			IEnumerator item = ContentManager.LoadContentPacks(contentLoadProgressReceiver);
			Stopwatch totalLoadStopwatch = new Stopwatch();
			totalLoadStopwatch.Start();
			Stopwatch thisFrameLoadStopwatch = new Stopwatch();
			int previousProgressPercent = 0;
			Stack<IEnumerator> coroutineStack = new Stack<IEnumerator>();
			coroutineStack.Push(item);
			while (coroutineStack.Count > 0)
			{
				thisFrameLoadStopwatch.Restart();
				int num = 0;
				do
				{
					num++;
					IEnumerator enumerator = coroutineStack.Peek();
					if (enumerator.Current is IEnumerator item2)
					{
						coroutineStack.Push(item2);
						continue;
					}
					while (!enumerator.MoveNext())
					{
						coroutineStack.Pop();
						if (coroutineStack.Count == 0)
						{
							break;
						}
						enumerator = coroutineStack.Peek();
					}
				}
				while (coroutineStack.Count > 0 && thisFrameLoadStopwatch.Elapsed < maxLoadTimePerFrame);
				thisFrameLoadStopwatch.Stop();
				loadGameContentPercentage = Mathf.FloorToInt(contentLoadProgressReceiver.value * 100f);
				int num2 = Math.Min(99, startPercentage + Mathf.FloorToInt(contentLoadProgressReceiver.value * remainingPercentage));
				if (previousProgressPercent != num2)
				{
					previousProgressPercent = num2;
					if ((bool)loadingPercentIndicatorLabel)
					{
						loadingPercentIndicatorLabel.SetPercentValue(num2);
					}
				}
				yield return new WaitForEndOfFrame();
			}
			yield return SceneCatalog.Init();
			SystemInitializerAttribute.RegisterPreInitializedType(typeof(SceneCatalog));
			Print("Game content load completed in {0}ms.", totalLoadStopwatch.ElapsedMilliseconds);
			while (!SoundbankLoader.doneLoading || !RoR2Content.initialized)
			{
				yield return null;
			}
			while (!LegacyResourcesAPI.PendingLoadingAssetsOrTimeout())
			{
				yield return null;
			}
			Print("async game objects loaded in {0}ms.", totalLoadStopwatch.ElapsedMilliseconds);
			onLoadFinished?.Invoke();
		}

		private void OnDestroy()
		{
			if (instance == this && PlatformSystems.EgsToggleConVar.value != 1)
			{
				unloadSteamworksClient?.Invoke();
			}
		}

		private void OnApplicationQuit()
		{
			if ((bool)Console.instance)
			{
				Console.instance.SaveArchiveConVars();
			}
			onShutDown?.Invoke();
			unloadSteamworksClient?.Invoke();
			UnitySystemConsoleRedirector.Disengage();
		}

		[ConCommand(commandName = "quit", flags = ConVarFlags.None, helpText = "Close the application.")]
		private static void CCQuit(ConCommandArgs args)
		{
			Application.Quit();
		}

		[ConCommand(commandName = "locCmd", flags = ConVarFlags.None, helpText = "Redirects a command to be run for a certain local user.")]
		public static void CCRunCmdForLocalUser(ConCommandArgs args)
		{
			int argInt = args.GetArgInt(0);
			if (LocalUserManager.readOnlyLocalUsersList.Count > argInt)
			{
				string argString = args.GetArgString(1);
				Console.instance.SubmitCmd(LocalUserManager.readOnlyLocalUsersList[argInt].currentNetworkUser, argString);
			}
		}

		[NotNull]
		public static string GetBestUserName()
		{
			string text = null;
			text = text ?? Client.Instance?.Username;
			if (LocalUserManager.readOnlyLocalUsersList.Count > 0)
			{
				text = text ?? LocalUserManager.readOnlyLocalUsersList[0].userProfile.name;
			}
			return text ?? "???";
		}

		[ConCommand(commandName = "app_info", flags = ConVarFlags.None, helpText = "Get information about the application, including build and version info.")]
		private static void CCAppInfo(ConCommandArgs args)
		{
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			stringBuilder.Append("====================").AppendLine();
			stringBuilder.Append("= Application Info =").AppendLine();
			stringBuilder.Append("====================").AppendLine();
			stringBuilder.Append("> Product: ").AppendLine();
			stringBuilder.Append(">   Product Name: ").Append(Application.productName).AppendLine();
			stringBuilder.Append(">   Company Name: ").Append(Application.companyName).AppendLine();
			stringBuilder.Append("> Build: ").AppendLine();
			stringBuilder.Append(">   Platform: ").Append(Application.platform).AppendLine();
			stringBuilder.Append(">   Version: ").Append(Application.version).AppendLine();
			stringBuilder.Append(">   Unity Version: ").Append(Application.unityVersion).AppendLine();
			stringBuilder.Append(">   Build GUID: ").Append(Application.buildGUID).AppendLine();
			stringBuilder.Append(">   Build Type: ").Append("Production").AppendLine();
			stringBuilder.Append(">   Is Dedicated Server: ").Append(value: false).AppendLine();
			stringBuilder.Append("> Environment: ").AppendLine();
			stringBuilder.Append(">   Command Line: ").Append(Environment.CommandLine).AppendLine();
			stringBuilder.Append(">   Console Log Path: ").Append(Application.consoleLogPath).AppendLine();
			Client client = Client.Instance;
			if (client != null && client.IsValid)
			{
				stringBuilder.Append("> Steamworks Client: ").AppendLine();
				stringBuilder.Append(">   App ID: ").AppendUint(client.AppId).AppendLine();
				stringBuilder.Append(">   Build ID: ").AppendInt(client.BuildId).AppendLine();
				stringBuilder.Append(">   Branch: ").Append(client.BetaName).AppendLine();
			}
			Server server = Server.Instance;
			if (server != null && server.IsValid)
			{
				stringBuilder.Append("> Steamworks Game Server: ").AppendLine();
				stringBuilder.Append(">   App ID: ").AppendUint(server.AppId).AppendLine();
			}
			args.Log(stringBuilder.ToString());
			stringBuilder = HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}

		public static void SetIsInLocalMultiplayer(bool isLocalMultiplayer)
		{
			isInLocalMultiPlayer = isLocalMultiplayer;
		}

		public static void SetMapsEnabled(bool enabled)
		{
			foreach (Player player in ReInput.players.Players)
			{
				player.controllers.maps.SetAllMapsEnabled(enabled);
			}
		}

		public static void DebugPrintRewired()
		{
			Print("---Rewired Start---");
			Print("Rewired found " + ReInput.controllers.joystickCount + " joysticks attached.");
			for (int i = 0; i < ReInput.controllers.joystickCount; i++)
			{
				Joystick joystick = ReInput.controllers.Joysticks[i];
				Print("[" + i + "] Joystick: " + joystick.name + " \n Hardware GUID: " + joystick.hardwareTypeGuid.ToString() + " \n Hardware Name: " + joystick.hardwareName + " \n Is Recognized: " + ((joystick.hardwareTypeGuid != Guid.Empty) ? "Yes" : "No") + " \n Is Assigned: " + (ReInput.controllers.IsControllerAssigned(joystick.type, joystick) ? "Yes" : "No"));
			}
			foreach (Player player in ReInput.players.Players)
			{
				Print("PlayerId = " + player.id + " is assigned " + player.controllers.joystickCount + " joysticks.");
				foreach (Joystick joystick2 in player.controllers.Joysticks)
				{
					Print("Joystick: " + joystick2.name + "\nIs Recognized: " + ((joystick2.hardwareTypeGuid != Guid.Empty) ? "Yes" : "No"));
					foreach (ControllerMap map in player.controllers.maps.GetMaps(joystick2.type, joystick2.id))
					{
						string text = ReInput.mapping.GetMapCategory(map.categoryId).name;
						string text2 = ReInput.mapping.GetJoystickLayout(map.layoutId).name;
						Print("Controller Map:\nCategory = " + text + "\nLayout = " + text2 + "\nenabled = " + map.enabled);
						ActionElementMap[] elementMaps = map.GetElementMaps();
						foreach (ActionElementMap actionElementMap in elementMaps)
						{
							InputAction action = ReInput.mapping.GetAction(actionElementMap.actionId);
							if (action != null)
							{
								Print("Action \"" + action.name + "\" is bound to \"" + actionElementMap.elementIdentifierName + "\"");
							}
						}
					}
				}
			}
			Print("---Rewired End---");
		}

		private static void AssignJoystickToAvailablePlayer(Controller controller)
		{
			IList<Player> players = ReInput.players.Players;
			for (int i = 0; i < players.Count; i++)
			{
				Player player = players[i];
				if (player.name != "PlayerMain" && player.controllers.joystickCount == 0 && !player.controllers.hasKeyboard && !player.controllers.hasMouse)
				{
					player.controllers.AddController(controller, removeFromOtherPlayers: false);
					break;
				}
			}
		}

		private static void AssignNewController(ControllerStatusChangedEventArgs args)
		{
			AssignNewController(ReInput.controllers.GetController(args.controllerType, args.controllerId));
		}

		public static void ClearControllers()
		{
			ReInput.players.GetPlayer("PlayerMain").controllers.ClearAllControllers();
		}

		private static void AssignNewController(Controller controller)
		{
			ReInput.players.GetPlayer("PlayerMain").controllers.AddController(controller, removeFromOtherPlayers: false);
			if (controller.type == ControllerType.Joystick)
			{
				AssignJoystickToAvailablePlayer(controller);
			}
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	[RequireComponent(typeof(EntityStateMachine))]
	public class RouletteChestController : NetworkBehaviour
	{
		public struct Entry
		{
			public PickupIndex pickupIndex;

			public Run.FixedTimeStamp endTime;
		}

		private class RouletteChestControllerBaseState : EntityState
		{
			protected RouletteChestController rouletteChestController { get; private set; }

			public override void OnEnter()
			{
				base.OnEnter();
				rouletteChestController = GetComponent<RouletteChestController>();
			}

			public virtual void HandleInteractionServer(Interactor activator)
			{
			}
		}

		private class Idle : RouletteChestControllerBaseState
		{
			private static int IdleStateHash = Animator.StringToHash("Idle");

			public override void OnEnter()
			{
				base.OnEnter();
				PlayAnimation("Body", IdleStateHash);
				base.rouletteChestController.purchaseInteraction.Networkavailable = true;
			}

			public override void HandleInteractionServer(Interactor activator)
			{
				base.HandleInteractionServer(activator);
				outer.SetNextState(new Startup());
			}
		}

		private class Startup : RouletteChestControllerBaseState
		{
			public static float baseDuration;

			public static string soundEntryEvent;

			private static int IdleToActiveStateHash = Animator.StringToHash("IdleToActive");

			public override void OnEnter()
			{
				base.OnEnter();
				PlayAnimation("Body", IdleToActiveStateHash);
				base.rouletteChestController.purchaseInteraction.Networkavailable = false;
				base.rouletteChestController.purchaseInteraction.costType = CostTypeIndex.None;
				Util.PlaySound(soundEntryEvent, base.gameObject);
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge > baseDuration)
				{
					outer.SetNextState(new Cycling());
				}
			}
		}

		private class Cycling : RouletteChestControllerBaseState
		{
			public static string soundCycleEvent;

			public static string soundCycleSpeedRtpc;

			public static float soundCycleSpeedRtpcScale;

			private static int ActiveLoopStateHash = Animator.StringToHash("ActiveLoop");

			private static int ActiveLoopParamHash = Animator.StringToHash("ActiveLoop.playbackRate");

			public override void OnEnter()
			{
				base.OnEnter();
				base.rouletteChestController.onChangedEntryClient.AddListener(OnChangedEntryClient);
				if (NetworkServer.active)
				{
					base.rouletteChestController.BeginCycleServer();
					base.rouletteChestController.onCycleCompletedServer.AddListener(OnCycleCompleted);
				}
				base.rouletteChestController.purchaseInteraction.Networkavailable = true;
				base.rouletteChestController.purchaseInteraction.costType = CostTypeIndex.None;
			}

			private void OnCycleCompleted()
			{
				outer.SetNextState(new Opening());
			}

			public override void OnExit()
			{
				base.rouletteChestController.onCycleCompletedServer.RemoveListener(OnCycleCompleted);
				base.rouletteChestController.onChangedEntryClient.RemoveListener(OnChangedEntryClient);
				base.OnExit();
			}

			private void OnChangedEntryClient()
			{
				int entryIndexForTime = base.rouletteChestController.GetEntryIndexForTime(Run.FixedTimeStamp.now);
				float num = base.rouletteChestController.CalcEntryDuration(entryIndexForTime);
				PlayAnimation("Body", ActiveLoopStateHash, ActiveLoopParamHash, num);
				float num2 = Util.Remap(num, minTime, minTime + base.rouletteChestController.bonusTime, 1f, 0f);
				Util.PlaySound(soundCycleEvent, base.gameObject, soundCycleSpeedRtpc, num2 * soundCycleSpeedRtpcScale);
			}

			public override void HandleInteractionServer(Interactor activator)
			{
				base.HandleInteractionServer(activator);
				base.rouletteChestController.EndCycleServer(activator);
			}
		}

		private class Opening : RouletteChestControllerBaseState
		{
			public static float baseDuration;

			public static string soundEntryEvent;

			private static int ActiveToOpeningStateHash = Animator.StringToHash("ActiveToOpening");

			public override void OnEnter()
			{
				base.OnEnter();
				PlayAnimation("Body", ActiveToOpeningStateHash);
				base.rouletteChestController.purchaseInteraction.Networkavailable = false;
				base.rouletteChestController.purchaseInteraction.costType = CostTypeIndex.None;
				Util.PlaySound(soundEntryEvent, base.gameObject);
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active && base.fixedAge > baseDuration)
				{
					outer.SetNextState(new Opened());
				}
			}
		}

		private class Opened : RouletteChestControllerBaseState
		{
			private static int OpenedStateHash = Animator.StringToHash("Opened");

			public override void OnEnter()
			{
				base.OnEnter();
				PlayAnimation("Body", OpenedStateHash);
				base.rouletteChestController.purchaseInteraction.Networkavailable = false;
				base.rouletteChestController.purchaseInteraction.costType = CostTypeIndex.None;
				base.rouletteChestController.networkIdentity.isPingable = false;
			}
		}

		public int maxEntries = 1;

		public float bonusTime;

		public AnimationCurve bonusTimeDecay;

		public PickupDropTable dropTable;

		public Transform ejectionTransform;

		public UnityEngine.Vector3 localEjectionVelocity;

		public Animator modelAnimator;

		public PickupDisplay pickupDisplay;

		private EntityStateMachine stateMachine;

		private PurchaseInteraction purchaseInteraction;

		private NetworkIdentity networkIdentity;

		private static readonly float averageHgReactionTime = 0.20366667f;

		private static readonly float lowestHgReactionTime = 0.15f;

		private static readonly float recognitionWindow = 0.15f;

		private static readonly float minTime = lowestHgReactionTime + recognitionWindow;

		private static readonly float rewindTime = 0.05f;

		private Run.FixedTimeStamp activationTime = Run.FixedTimeStamp.positiveInfinity;

		private Entry[] entries = Array.Empty<Entry>();

		private Xoroshiro128Plus rng;

		private static readonly uint activationTimeDirtyBit = 1u;

		private static readonly uint entriesDirtyBit = 2u;

		private static readonly uint enabledDirtyBit = 4u;

		private static readonly uint allDirtyBitsMask = activationTimeDirtyBit | entriesDirtyBit;

		public int dropCount = 1;

		private int previousEntryIndexClient = -1;

		public UnityEvent onCycleBeginServer;

		public UnityEvent onCycleCompletedServer;

		public UnityEvent onChangedEntryClient;

		private bool isCycling => !activationTime.isPositiveInfinity;

		private float CalcEntryDuration(int i)
		{
			float time = (float)i / (float)maxEntries;
			return bonusTimeDecay.Evaluate(time) * bonusTime + minTime;
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = allDirtyBitsMask;
			}
			writer.WritePackedUInt32(num);
			if ((num & activationTimeDirtyBit) != 0)
			{
				writer.Write(activationTime);
			}
			if ((num & entriesDirtyBit) != 0)
			{
				writer.WritePackedUInt32((uint)entries.Length);
				for (int i = 0; i < entries.Length; i++)
				{
					writer.Write(entries[i].pickupIndex);
				}
			}
			return num != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			uint num = reader.ReadPackedUInt32();
			if ((num & activationTimeDirtyBit) != 0)
			{
				activationTime = reader.ReadFixedTimeStamp();
			}
			if ((num & entriesDirtyBit) != 0)
			{
				Array.Resize(ref entries, (int)reader.ReadPackedUInt32());
				Run.FixedTimeStamp endTime = activationTime;
				for (int i = 0; i < entries.Length; i++)
				{
					ref Entry reference = ref entries[i];
					reference.pickupIndex = reader.ReadPickupIndex();
					reference.endTime = endTime + CalcEntryDuration(i);
					endTime = reference.endTime;
				}
			}
		}

		private void Awake()
		{
			stateMachine = GetComponent<EntityStateMachine>();
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			networkIdentity = GetComponent<NetworkIdentity>();
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			}
		}

		private void OnEnable()
		{
			SetDirtyBit(enabledDirtyBit);
			if ((bool)pickupDisplay)
			{
				pickupDisplay.enabled = true;
			}
		}

		private void OnDisable()
		{
			if ((bool)pickupDisplay)
			{
				pickupDisplay.SetPickupIndex(PickupIndex.none);
				pickupDisplay.enabled = false;
			}
			SetDirtyBit(enabledDirtyBit);
		}

		[Server]
		private void GenerateEntriesServer(Run.FixedTimeStamp startTime)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.RouletteChestController::GenerateEntriesServer(RoR2.Run/FixedTimeStamp)' called on client");
				return;
			}
			Array.Resize(ref entries, maxEntries);
			for (int i = 0; i < entries.Length; i++)
			{
				ref Entry reference = ref entries[i];
				reference.endTime = startTime + CalcEntryDuration(i);
				startTime = reference.endTime;
			}
			PickupIndex pickupIndex = PickupIndex.none;
			for (int j = 0; j < entries.Length; j++)
			{
				ref Entry reference2 = ref entries[j];
				PickupIndex pickupIndex2 = dropTable.GenerateDrop(rng);
				if (pickupIndex2 == pickupIndex)
				{
					pickupIndex2 = dropTable.GenerateDrop(rng);
				}
				reference2.pickupIndex = pickupIndex2;
				pickupIndex = pickupIndex2;
			}
			SetDirtyBit(entriesDirtyBit);
		}

		[Server]
		public void HandleInteractionServer(Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.RouletteChestController::HandleInteractionServer(RoR2.Interactor)' called on client");
			}
			else
			{
				((RouletteChestControllerBaseState)stateMachine.state).HandleInteractionServer(activator);
			}
		}

		[Server]
		private void BeginCycleServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.RouletteChestController::BeginCycleServer()' called on client");
				return;
			}
			activationTime = Run.FixedTimeStamp.now;
			SetDirtyBit(activationTimeDirtyBit);
			GenerateEntriesServer(activationTime);
			onCycleBeginServer?.Invoke();
		}

		[Server]
		private void EndCycleServer([CanBeNull] Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.RouletteChestController::EndCycleServer(RoR2.Interactor)' called on client");
				return;
			}
			float num = 0f;
			if ((bool)activator)
			{
				NetworkUser networkUser = Util.LookUpBodyNetworkUser(activator.gameObject);
				if ((object)networkUser != null)
				{
					num = RttManager.GetConnectionRTT(networkUser.connectionToClient);
				}
			}
			Run.FixedTimeStamp time = Run.FixedTimeStamp.now - num - rewindTime;
			PickupIndex pickupIndexForTime = GetPickupIndexForTime(time);
			EjectPickupServer(pickupIndexForTime);
			activationTime = Run.FixedTimeStamp.positiveInfinity;
			onCycleCompletedServer.Invoke();
		}

		private void FixedUpdate()
		{
			if ((bool)pickupDisplay)
			{
				pickupDisplay.SetPickupIndex(isCycling ? GetPickupIndexForTime(Run.FixedTimeStamp.now) : PickupIndex.none);
			}
			if (NetworkClient.active)
			{
				int entryIndexForTime = GetEntryIndexForTime(Run.FixedTimeStamp.now);
				if (entryIndexForTime != previousEntryIndexClient)
				{
					previousEntryIndexClient = entryIndexForTime;
					onChangedEntryClient.Invoke();
				}
			}
			if (NetworkServer.active && isCycling && entries.Length != 0)
			{
				Run.FixedTimeStamp endTime = entries[entries.Length - 1].endTime;
				if (endTime.hasPassed)
				{
					EndCycleServer(null);
				}
			}
		}

		private int GetEntryIndexForTime(Run.FixedTimeStamp time)
		{
			for (int i = 0; i < entries.Length; i++)
			{
				if (time < entries[i].endTime)
				{
					return i;
				}
			}
			if (entries.Length != 0)
			{
				return entries.Length - 1;
			}
			return -1;
		}

		private PickupIndex GetPickupIndexForTime(Run.FixedTimeStamp time)
		{
			int entryIndexForTime = GetEntryIndexForTime(time);
			if (entryIndexForTime != -1)
			{
				return entries[entryIndexForTime].pickupIndex;
			}
			return PickupIndex.none;
		}

		private void EjectPickupServer(PickupIndex pickupIndex)
		{
			if (!(pickupIndex == PickupIndex.none))
			{
				for (int i = 0; i < dropCount; i++)
				{
					PickupDropletController.CreatePickupDroplet(pickupIndex, ejectionTransform.position, ejectionTransform.rotation * localEjectionVelocity);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class RTPCController : MonoBehaviour
	{
		public string akSoundString;

		public string rtpcString;

		public float rtpcValue;

		public bool useCurveInstead;

		public AnimationCurve rtpcValueCurve;

		private float fixedAge;

		private void Start()
		{
			if (akSoundString.Length > 0)
			{
				Util.PlaySound(akSoundString, base.gameObject, rtpcString, rtpcValue);
			}
			else
			{
				AkSoundEngine.SetRTPCValue(rtpcString, rtpcValue, base.gameObject);
			}
		}

		private void FixedUpdate()
		{
			if (useCurveInstead)
			{
				fixedAge += Time.fixedDeltaTime;
				AkSoundEngine.SetRTPCValue(rtpcString, rtpcValueCurve.Evaluate(fixedAge), base.gameObject);
			}
		}
	}
	[RequireComponent(typeof(Run))]
	[DisallowMultipleComponent]
	public class RunArtifactManager : NetworkBehaviour
	{
		public delegate void ArtifactStateChangeDelegate([NotNull] RunArtifactManager runArtifactManager, [NotNull] ArtifactDef artifactDef);

		public struct RunEnabledArtifacts : IEnumerator<ArtifactDef>, IEnumerator, IDisposable
		{
			private ArtifactIndex artifactIndex;

			public ArtifactDef Current => ArtifactCatalog.GetArtifactDef(artifactIndex);

			object IEnumerator.Current => Current;

			public bool MoveNext()
			{
				RunArtifactManager instance = RunArtifactManager.instance;
				if ((object)instance == null)
				{
					return false;
				}
				while ((int)(++artifactIndex) < ArtifactCatalog.artifactCount)
				{
					if (instance.IsArtifactEnabled(artifactIndex))
					{
						return true;
					}
				}
				return false;
			}

			public void Reset()
			{
				artifactIndex = ArtifactIndex.None;
			}

			public void Dispose()
			{
			}
		}

		private Run run;

		private static readonly uint enabledArtifactsDirtyBit = 1u;

		private static readonly uint allDirtyBits = enabledArtifactsDirtyBit;

		private bool[] _enabledArtifacts;

		private static readonly FixedSizeArrayPool<bool> enabledArtifactMaskPool = new FixedSizeArrayPool<bool>(0);

		public static readonly GenericStaticEnumerable<ArtifactDef, RunEnabledArtifacts> enabledArtifactsEnumerable = default(GenericStaticEnumerable<ArtifactDef, RunEnabledArtifacts>);

		public static RunArtifactManager instance { get; private set; }

		public static event ArtifactStateChangeDelegate onArtifactEnabledGlobal;

		public static event ArtifactStateChangeDelegate onArtifactDisabledGlobal;

		private void Awake()
		{
			_enabledArtifacts = enabledArtifactMaskPool.Request();
			run = GetComponent<Run>();
			Run.onServerRunSetRuleBookGlobal += OnServerRunSetRuleBook;
		}

		private void OnDestroy()
		{
			int i = 0;
			for (int artifactCount = ArtifactCatalog.artifactCount; i < artifactCount; i++)
			{
				SetArtifactEnabled(ArtifactCatalog.GetArtifactDef((ArtifactIndex)i), newEnabled: false);
			}
			Run.onServerRunSetRuleBookGlobal -= OnServerRunSetRuleBook;
			if (_enabledArtifacts != null)
			{
				enabledArtifactMaskPool.Return(_enabledArtifacts);
				_enabledArtifacts = null;
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = (initialState ? allDirtyBits : base.syncVarDirtyBits);
			bool num2 = (num & enabledArtifactsDirtyBit) != 0;
			writer.WritePackedUInt32(num);
			if (num2)
			{
				writer.WriteBitArray(_enabledArtifacts);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if ((reader.ReadPackedUInt32() & enabledArtifactsDirtyBit) != 0)
			{
				bool[] array = enabledArtifactMaskPool.Request();
				reader.ReadBitArray(array);
				int i = 0;
				for (int artifactCount = ArtifactCatalog.artifactCount; i < artifactCount; i++)
				{
					SetArtifactEnabled(ArtifactCatalog.GetArtifactDef((ArtifactIndex)i), array[i]);
				}
			}
		}

		private void OnServerRunSetRuleBook([NotNull] Run run, [NotNull] RuleBook newRuleBook)
		{
			bool[] array = enabledArtifactMaskPool.Request();
			int i = 0;
			for (int ruleCount = RuleCatalog.ruleCount; i < ruleCount; i++)
			{
				RuleChoiceDef ruleChoice = newRuleBook.GetRuleChoice(i);
				if (ruleChoice.artifactIndex != ArtifactIndex.None)
				{
					array[(int)ruleChoice.artifactIndex] = true;
				}
			}
			int j = 0;
			for (int artifactCount = ArtifactCatalog.artifactCount; j < artifactCount; j++)
			{
				SetArtifactEnabled(ArtifactCatalog.GetArtifactDef((ArtifactIndex)j), array[j]);
			}
			enabledArtifactMaskPool.Return(array);
		}

		private void SetArtifactEnabled([NotNull] ArtifactDef artifactDef, bool newEnabled)
		{
			ref bool reference = ref _enabledArtifacts[(int)artifactDef.artifactIndex];
			if (reference != newEnabled)
			{
				if (NetworkServer.active)
				{
					SetDirtyBit(enabledArtifactsDirtyBit);
				}
				reference = newEnabled;
				(reference ? RunArtifactManager.onArtifactEnabledGlobal : RunArtifactManager.onArtifactDisabledGlobal)?.Invoke(this, artifactDef);
			}
		}

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			enabledArtifactMaskPool.lengthOfArrays = ArtifactCatalog.artifactCount;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool IsArtifactEnabled([NotNull] ArtifactDef artifactDef)
		{
			return IsArtifactEnabled(artifactDef.artifactIndex);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool IsArtifactEnabled(ArtifactIndex artifactIndex)
		{
			bool[] enabledArtifacts = _enabledArtifacts;
			bool defaultValue = false;
			return ArrayUtils.GetSafe(enabledArtifacts, (int)artifactIndex, in defaultValue);
		}

		[Server]
		public void SetArtifactEnabledServer(ArtifactDef artifactDef, bool newEnabled)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.RunArtifactManager::SetArtifactEnabledServer(RoR2.ArtifactDef,System.Boolean)' called on client");
			}
			else
			{
				SetArtifactEnabled(artifactDef, newEnabled);
			}
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class RunCameraManager : MonoBehaviour
	{
		public static RunCameraManager instance;

		private readonly Dictionary<string, CameraRigController> cameras = new Dictionary<string, CameraRigController>();

		private readonly Dictionary<string, Canvas> canvases = new Dictionary<string, Canvas>();

		public bool isLobby;

		private bool isLocalMultiplayer = RoR2Application.isInLocalMultiPlayer;

		private bool leavingLobby;

		public GameObject CharacterSelectUIMain;

		public GameObject CharacterSelectUILocal;

		public GameObject MainCamera;

		public GameObject PreGameController;

		private GameObject popOutContainer;

		private int planeDistanceMultiplier = 100;

		private float popOutScaleValue = 1.85f;

		[Header("----------------Splitscreen Lobby----------------")]
		[Tooltip("A relative offset to stagger the camera for each successive splitscreen lobby player viewport.  Defaults roughly match SurvivorMannequinDiorama slots.")]
		public UnityEngine.Vector3 SplitscreenCameraOffset = new UnityEngine.Vector3(-0.9f, 0f, 3f);

		public static readonly UnityEngine.Rect[][] ScreenLayouts = new UnityEngine.Rect[5][]
		{
			new UnityEngine.Rect[0],
			new UnityEngine.Rect[1]
			{
				new UnityEngine.Rect(0f, 0f, 1f, 1f)
			},
			new UnityEngine.Rect[2]
			{
				new UnityEngine.Rect(0f, 0.5f, 1f, 0.5f),
				new UnityEngine.Rect(0f, 0f, 1f, 0.5f)
			},
			new UnityEngine.Rect[3]
			{
				new UnityEngine.Rect(0f, 0.5f, 1f, 0.5f),
				new UnityEngine.Rect(0f, 0f, 0.5f, 0.5f),
				new UnityEngine.Rect(0.5f, 0f, 0.5f, 0.5f)
			},
			new UnityEngine.Rect[4]
			{
				new UnityEngine.Rect(0f, 0.5f, 0.5f, 0.5f),
				new UnityEngine.Rect(0.5f, 0.5f, 0.5f, 0.5f),
				new UnityEngine.Rect(0f, 0f, 0.5f, 0.5f),
				new UnityEngine.Rect(0.5f, 0f, 0.5f, 0.5f)
			}
		};

		private List<CameraRigController> activeCameras = new List<CameraRigController>();

		public IReadOnlyList<CameraRigController> ReadOnlyActiveCameras => activeCameras;

		private void Start()
		{
			instance = this;
		}

		private void OnDestroy()
		{
			if (instance == this)
			{
				instance = null;
			}
		}

		private static GameObject GetNetworkUserBodyObject(NetworkUser networkUser)
		{
			if ((bool)networkUser.masterObject)
			{
				CharacterMaster component = networkUser.masterObject.GetComponent<CharacterMaster>();
				if ((bool)component)
				{
					return component.GetBodyObject();
				}
			}
			return null;
		}

		private static TeamIndex GetNetworkUserTeamIndex(NetworkUser networkUser)
		{
			if ((bool)networkUser.masterObject)
			{
				CharacterMaster component = networkUser.masterObject.GetComponent<CharacterMaster>();
				if ((bool)component)
				{
					return component.teamIndex;
				}
			}
			return TeamIndex.Neutral;
		}

		private void Update()
		{
			if (TransitionCommand.requestPending || leavingLobby)
			{
				leavingLobby = true;
				return;
			}
			bool flag = Stage.instance;
			if (isLobby)
			{
				flag = true;
			}
			if (flag)
			{
				int i = 0;
				for (int count = CameraRigController.readOnlyInstancesList.Count; i < count; i++)
				{
					if (CameraRigController.readOnlyInstancesList[i].suppressPlayerCameras)
					{
						flag = false;
						return;
					}
				}
			}
			if (flag)
			{
				int num = 0;
				ReadOnlyCollection<NetworkUser> readOnlyLocalPlayersList = NetworkUser.readOnlyLocalPlayersList;
				for (int j = 0; j < readOnlyLocalPlayersList.Count; j++)
				{
					NetworkUser networkUser = readOnlyLocalPlayersList[j];
					LocalUser localUser = networkUser?.localUser ?? null;
					if (localUser == null || localUser.inputPlayer == null)
					{
						continue;
					}
					CameraRigController cameraRigController = null;
					if (!cameras.ContainsKey(localUser.inputPlayer.name) || cameras[localUser.inputPlayer.name] == null)
					{
						if (isLobby && localUser.inputPlayer.name == "PlayerMain")
						{
							cameraRigController = MainCamera.GetComponent<CameraRigController>();
							cameras[localUser.inputPlayer.name] = cameraRigController;
							cameraRigController.sceneCam.cullingMask |= 1 << LayerMask.NameToLayer("Splitscreen" + localUser.inputPlayer.name);
						}
						else if (isLobby && isLocalMultiplayer)
						{
							if (!RoR2Application.IsAllUsersEntitlementsUpdated)
							{
								continue;
							}
							cameraRigController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Main Camera")).GetComponent<CameraRigController>();
							cameras[localUser.inputPlayer.name] = cameraRigController;
							if (cameraRigController.sceneCam.GetComponent<AkAudioListener>() != null)
							{
								UnityEngine.Object.Destroy(cameraRigController.sceneCam.GetComponent<AkAudioListener>());
							}
							cameraRigController.CloneCameraContext(MainCamera.GetComponent<CameraRigController>());
							UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
							zero.x = SplitscreenCameraOffset.x * (float)j;
							zero.y = SplitscreenCameraOffset.y * (float)j;
							zero.z = SplitscreenCameraOffset.z * (float)j;
							cameraRigController.sceneCam.transform.localPosition = zero;
							cameraRigController.sceneCam.cullingMask |= 1 << LayerMask.NameToLayer("Splitscreen" + localUser.inputPlayer.name);
						}
						else if (!isLobby)
						{
							cameraRigController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Main Camera")).GetComponent<CameraRigController>();
							cameras[localUser.inputPlayer.name] = cameraRigController;
						}
					}
					else
					{
						cameraRigController = cameras[localUser.inputPlayer.name];
						cameraRigController.enabled = true;
					}
					if (!isLobby)
					{
						cameraRigController.viewer = networkUser;
						networkUser.cameraRigController = cameraRigController;
						GameObject networkUserBodyObject = GetNetworkUserBodyObject(networkUser);
						ForceSpectate forceSpectate = InstanceTracker.FirstOrNull<ForceSpectate>();
						if ((bool)forceSpectate)
						{
							cameraRigController.nextTarget = forceSpectate.target;
							cameraRigController.cameraMode = CameraModePlayerBasic.spectator;
						}
						else if ((bool)networkUserBodyObject)
						{
							cameraRigController.nextTarget = networkUserBodyObject;
							cameraRigController.cameraMode = CameraModePlayerBasic.playerBasic;
						}
						else if (!cameraRigController.disableSpectating)
						{
							cameraRigController.cameraMode = CameraModePlayerBasic.spectator;
							if (!cameraRigController.target)
							{
								cameraRigController.nextTarget = CameraRigControllerSpectateControls.GetNextSpectateGameObject(networkUser, null);
							}
						}
						else
						{
							cameraRigController.cameraMode = CameraModeNone.instance;
						}
					}
					num++;
				}
				if (isLobby)
				{
					if (popOutContainer == null)
					{
						popOutContainer = GameObject.Find("PopoutPanelContainer");
					}
					else
					{
						RectTransform component = popOutContainer.GetComponent<RectTransform>();
						if (1 < readOnlyLocalPlayersList.Count && readOnlyLocalPlayersList.Count < 4 && component != null)
						{
							component.localScale = new UnityEngine.Vector3(popOutScaleValue, popOutScaleValue, popOutScaleValue);
						}
						else if (component != null)
						{
							component.localScale = new UnityEngine.Vector3(1f, 1f, 1f);
						}
					}
					for (int k = 0; k < readOnlyLocalPlayersList.Count; k++)
					{
						LocalUser localUser2 = readOnlyLocalPlayersList[k]?.localUser ?? null;
						if (localUser2 == null)
						{
							continue;
						}
						if (!canvases.ContainsKey(localUser2.inputPlayer.name) || canvases[localUser2.inputPlayer.name] == null)
						{
							GameObject gameObject = null;
							if (localUser2.inputPlayer.name == "PlayerMain")
							{
								gameObject = UnityEngine.Object.Instantiate(CharacterSelectUIMain);
							}
							else if (localUser2.inputPlayer.name == "Player2" && isLocalMultiplayer)
							{
								gameObject = UnityEngine.Object.Instantiate(CharacterSelectUILocal);
								gameObject.GetComponent<MPEventSystemProvider>().fallBackToPlayer2EventSystem = true;
							}
							else if (localUser2.inputPlayer.name == "Player3" && isLocalMultiplayer)
							{
								gameObject = UnityEngine.Object.Instantiate(CharacterSelectUILocal);
								gameObject.GetComponent<MPEventSystemProvider>().fallBackToPlayer3EventSystem = true;
							}
							else if (localUser2.inputPlayer.name == "Player4" && isLocalMultiplayer)
							{
								gameObject = UnityEngine.Object.Instantiate(CharacterSelectUILocal);
								gameObject.GetComponent<MPEventSystemProvider>().fallBackToPlayer4EventSystem = true;
							}
							if (gameObject != null)
							{
								VoteInfoPanelController componentInChildren = gameObject.GetComponentInChildren<VoteInfoPanelController>();
								if (componentInChildren != null)
								{
									componentInChildren.voteController = PreGameController.GetComponent<VoteController>();
								}
							}
							Canvas component2 = gameObject.GetComponent<Canvas>();
							component2.renderMode = RenderMode.ScreenSpaceCamera;
							component2.planeDistance = planeDistanceMultiplier * (k + 1);
							component2.worldCamera = cameras[localUser2.inputPlayer.name].uiCam;
							canvases[localUser2.inputPlayer.name] = component2;
						}
						else if (!canvases[localUser2.inputPlayer.name].enabled)
						{
							RefreshCharacterSelectUI(localUser2.inputPlayer.name);
							canvases[localUser2.inputPlayer.name].enabled = true;
						}
					}
				}
				int num2 = num;
				UnityEngine.Rect[] array = ScreenLayouts[num2];
				activeCameras.Clear();
				for (int l = 0; l < num2; l++)
				{
					CameraRigController cameraRigController2 = cameras[readOnlyLocalPlayersList[l].localUser.inputPlayer.name];
					activeCameras.Add(cameraRigController2);
					if (cameraRigController2.enabled)
					{
						cameraRigController2.viewport = array[l];
					}
				}
				return;
			}
			foreach (string key in cameras.Keys)
			{
				if ((bool)cameras[key])
				{
					UnityEngine.Object.Destroy(cameras[key].gameObject);
					cameras.Remove(key);
				}
			}
		}

		public void RefreshAllCharacterSelectUI()
		{
			if (!isLobby)
			{
				return;
			}
			foreach (string key in canvases.Keys)
			{
				RefreshCharacterSelectUI(key);
			}
		}

		private void RefreshCharacterSelectUI(string playerName)
		{
			if ((bool)canvases[playerName])
			{
				canvases[playerName].gameObject.GetComponent<CharacterSelectController>()?.RebuildOptions();
			}
		}

		public void OnUserRemoved(NetworkUser user)
		{
		}
	}
	public class RunConsoleStringOnEnable : MonoBehaviour
	{
		public string consoleString;

		private void OnEnable()
		{
			Console.instance.SubmitCmd(null, consoleString);
		}
	}
	public class RunEventFlagResponse : MonoBehaviour
	{
		public string flagName;

		public UnityEvent onAwakeWithFlagSetServer;

		public UnityEvent onAwakeWithFlagUnsetServer;

		private void Awake()
		{
			if (NetworkServer.active)
			{
				if ((bool)Run.instance)
				{
					(Run.instance.GetEventFlag(flagName) ? onAwakeWithFlagSetServer : onAwakeWithFlagUnsetServer)?.Invoke();
					return;
				}
				UnityEngine.Debug.LogErrorFormat("Cannot handle run event flag response {0}: No run exists.", base.gameObject.name);
			}
		}
	}
	public class RunFixedTimeRotateObject : NetworkBehaviour
	{
		private const float ERROR_THRESHOLD = 0.1f;

		[SerializeField]
		private UnityEngine.Vector3 eulerVelocity;

		[SerializeField]
		private bool isLocal = true;

		[SyncVar]
		private UnityEngine.Quaternion initialRotation = UnityEngine.Quaternion.identity;

		private float clientFixedTime;

		private UnityEngine.Quaternion desiredRotation = UnityEngine.Quaternion.identity;

		private UnityEngine.Quaternion currentRotation = UnityEngine.Quaternion.identity;

		public UnityEngine.Quaternion NetworkinitialRotation
		{
			get
			{
				return initialRotation;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref initialRotation, 1u);
			}
		}

		private void Start()
		{
			if ((bool)Run.instance)
			{
				clientFixedTime = Run.instance.fixedTime;
			}
			if (isLocal)
			{
				NetworkinitialRotation = base.transform.localRotation;
			}
			else
			{
				NetworkinitialRotation = base.transform.rotation;
			}
		}

		private void FixedUpdate()
		{
			if ((bool)Run.instance && NetworkServer.active)
			{
				desiredRotation = initialRotation * UnityEngine.Quaternion.Euler(eulerVelocity * Run.instance.fixedTime);
				return;
			}
			clientFixedTime += Time.fixedDeltaTime;
			if (Mathf.Abs(Run.instance.fixedTime - clientFixedTime) > 0.1f)
			{
				clientFixedTime = Mathf.Lerp(clientFixedTime, Run.instance.fixedTime, Time.fixedDeltaTime);
			}
			desiredRotation = initialRotation * UnityEngine.Quaternion.Euler(eulerVelocity * clientFixedTime);
		}

		private void Update()
		{
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Lerp(currentRotation, desiredRotation, Time.deltaTime);
			if (isLocal)
			{
				base.transform.localRotation = quaternion;
			}
			else
			{
				base.transform.rotation = quaternion;
			}
			currentRotation = quaternion;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(initialRotation);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(initialRotation);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				initialRotation = reader.ReadQuaternion();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				initialRotation = reader.ReadQuaternion();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class ScaleParticleSystemDuration : MonoBehaviour
	{
		public float initialDuration = 1f;

		private float _newDuration = 1f;

		public ParticleSystem[] particleSystems;

		public float newDuration
		{
			get
			{
				return _newDuration;
			}
			set
			{
				if (_newDuration != value)
				{
					_newDuration = value;
					UpdateParticleDurations();
				}
			}
		}

		private void Start()
		{
			UpdateParticleDurations();
		}

		public void UpdateDuration()
		{
			float simulationSpeed = initialDuration / _newDuration;
			for (int i = 0; i < particleSystems.Length; i++)
			{
				ParticleSystem particleSystem = particleSystems[i];
				if ((bool)particleSystem)
				{
					ParticleSystem.MainModule main = particleSystem.main;
					particleSystem.Stop();
					particleSystem.Clear();
					main.duration = _newDuration;
					main.simulationSpeed = simulationSpeed;
					particleSystem.Play();
				}
			}
		}

		private void UpdateParticleDurations()
		{
			float simulationSpeed = initialDuration / _newDuration;
			for (int i = 0; i < particleSystems.Length; i++)
			{
				ParticleSystem particleSystem = particleSystems[i];
				if ((bool)particleSystem)
				{
					ParticleSystem.MainModule main = particleSystem.main;
					main.simulationSpeed = simulationSpeed;
				}
			}
		}
	}
	public class ScaleSpriteByCamDistance : MonoBehaviour
	{
		public enum ScalingMode
		{
			Direct,
			Square,
			Sqrt,
			Cube,
			CubeRoot
		}

		private static List<ScaleSpriteByCamDistance> instancesList;

		private new Transform transform;

		[Tooltip("The amount by which to scale.")]
		public float scaleFactor = 1f;

		public ScalingMode scalingMode;

		static ScaleSpriteByCamDistance()
		{
			instancesList = new List<ScaleSpriteByCamDistance>();
			SceneCamera.onSceneCameraPreCull += OnSceneCameraPreCull;
		}

		private void Awake()
		{
			transform = base.transform;
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private static void OnSceneCameraPreCull(SceneCamera sceneCamera)
		{
			UnityEngine.Vector3 position = sceneCamera.transform.position;
			for (int i = 0; i < instancesList.Count; i++)
			{
				ScaleSpriteByCamDistance scaleSpriteByCamDistance = instancesList[i];
				Transform transform = scaleSpriteByCamDistance.transform;
				float num = 1f;
				float num2 = UnityEngine.Vector3.Distance(position, transform.position);
				switch (scaleSpriteByCamDistance.scalingMode)
				{
				case ScalingMode.Direct:
					num = num2;
					break;
				case ScalingMode.Square:
					num = num2 * num2;
					break;
				case ScalingMode.Sqrt:
					num = Mathf.Sqrt(num2);
					break;
				case ScalingMode.Cube:
					num = num2 * num2 * num2;
					break;
				case ScalingMode.CubeRoot:
					num = Mathf.Pow(num2, 1f / 3f);
					break;
				}
				num *= scaleSpriteByCamDistance.scaleFactor;
				transform.localScale = new UnityEngine.Vector3(num, num, num);
			}
		}
	}
	public class ScavBackpackBehavior : NetworkBehaviour
	{
		private PickupIndex dropPickup = PickupIndex.none;

		public float tier1Chance = 0.8f;

		public float tier2Chance = 0.2f;

		public float tier3Chance = 0.01f;

		public float lunarChance;

		public int totalItems;

		public float delayBetweenItems;

		public ItemTag requiredItemTag;

		public UnityEvent dropRoller;

		public SerializableEntityStateType openState = new SerializableEntityStateType(typeof(EntityStates.Barrel.Opening));

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		[Server]
		private void PickFromList(List<PickupIndex> dropList)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScavBackpackBehavior::PickFromList(System.Collections.Generic.List`1<RoR2.PickupIndex>)' called on client");
				return;
			}
			dropPickup = PickupIndex.none;
			if (dropList != null && dropList.Count > 0)
			{
				dropPickup = Run.instance.treasureRng.NextElementUniform(dropList);
			}
		}

		[Server]
		public void RollItem()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScavBackpackBehavior::RollItem()' called on client");
				return;
			}
			WeightedSelection<List<PickupIndex>> weightedSelection = new WeightedSelection<List<PickupIndex>>();
			weightedSelection.AddChoice(Run.instance.availableTier1DropList.Where(RollItemTest).ToList(), tier1Chance);
			weightedSelection.AddChoice(Run.instance.availableTier2DropList.Where(RollItemTest).ToList(), tier2Chance);
			weightedSelection.AddChoice(Run.instance.availableTier3DropList.Where(RollItemTest).ToList(), tier3Chance);
			weightedSelection.AddChoice(Run.instance.availableLunarCombinedDropList.Where(RollItemTest).ToList(), lunarChance);
			List<PickupIndex> dropList = weightedSelection.Evaluate(Run.instance.treasureRng.nextNormalizedFloat);
			PickFromList(dropList);
			bool RollItemTest(PickupIndex pickupIndex)
			{
				return ItemCatalog.GetItemDef(PickupCatalog.GetPickupDef(pickupIndex)?.itemIndex ?? ItemIndex.None)?.ContainsTag(requiredItemTag) ?? false;
			}
		}

		[Server]
		public void RollEquipment()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScavBackpackBehavior::RollEquipment()' called on client");
			}
			else
			{
				PickFromList(Run.instance.availableEquipmentDropList);
			}
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				if (dropRoller != null)
				{
					dropRoller.Invoke();
				}
				else
				{
					UnityEngine.Debug.LogFormat("Chest {0} has no item roller assigned!");
				}
			}
		}

		[Server]
		public void Open()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScavBackpackBehavior::Open()' called on client");
				return;
			}
			EntityStateMachine component = GetComponent<EntityStateMachine>();
			if ((bool)component)
			{
				component.SetNextState(EntityStateCatalog.InstantiateState(ref openState));
			}
		}

		[Server]
		public void ItemDrop()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScavBackpackBehavior::ItemDrop()' called on client");
			}
			else if (!(dropPickup == PickupIndex.none))
			{
				PickupDropletController.CreatePickupDroplet(dropPickup, base.transform.position + UnityEngine.Vector3.up * 1.5f, UnityEngine.Vector3.up * 20f + base.transform.forward * 2f);
				dropPickup = PickupIndex.none;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(Inventory))]
	public class ScavengerItemGranter : MonoBehaviour
	{
		[Serializable]
		public struct StackRollData
		{
			public PickupDropTable dropTable;

			public int stacks;

			public int numRolls;
		}

		public bool overwriteEquipment;

		public StackRollData[] stackRollDataList;

		private static readonly Xoroshiro128Plus rng;

		private void Start()
		{
			Inventory component = GetComponent<Inventory>();
			StackRollData[] array = stackRollDataList;
			for (int i = 0; i < array.Length; i++)
			{
				StackRollData stackRollData = array[i];
				if ((bool)stackRollData.dropTable)
				{
					for (int j = 0; j < stackRollData.numRolls; j++)
					{
						PickupDef pickupDef = PickupCatalog.GetPickupDef(stackRollData.dropTable.GenerateDrop(rng));
						component.GiveItem(pickupDef.itemIndex, stackRollData.stacks);
					}
				}
			}
			if (overwriteEquipment || component.currentEquipmentIndex == EquipmentIndex.None)
			{
				component.GiveRandomEquipment(rng);
			}
		}

		static ScavengerItemGranter()
		{
			rng = new Xoroshiro128Plus(0uL);
			Run.onRunStartGlobal += OnRunStart;
		}

		private static void OnRunStart(Run run)
		{
			rng.ResetSeed(run.seed);
		}
	}
	[RequireComponent(typeof(Camera))]
	public class SceneCamera : MonoBehaviour
	{
		public delegate void SceneCameraDelegate(SceneCamera sceneCamera);

		public static Camera _camera;

		public static OpaqueSortMode sortMode = OpaqueSortMode.NoDistanceSort;

		public Camera camera { get; private set; }

		public CameraRigController cameraRigController { get; private set; }

		public static event SceneCameraDelegate onSceneCameraPreCull;

		public static event SceneCameraDelegate onSceneCameraPreRender;

		public static event SceneCameraDelegate onSceneCameraPostRender;

		private void Awake()
		{
			camera = GetComponent<Camera>();
			cameraRigController = GetComponentInParent<CameraRigController>();
			camera.eventMask = ~camera.cullingMask;
			_camera = camera;
			camera.useOcclusionCulling = false;
		}

		private void OnPreCull()
		{
			if (SceneCamera.onSceneCameraPreCull != null)
			{
				SceneCamera.onSceneCameraPreCull(this);
			}
		}

		private void OnPreRender()
		{
			if (SceneCamera.onSceneCameraPreRender != null)
			{
				camera.opaqueSortMode = sortMode;
				SceneCamera.onSceneCameraPreRender(this);
			}
		}

		private void OnPostRender()
		{
			if (SceneCamera.onSceneCameraPostRender != null)
			{
				SceneCamera.onSceneCameraPostRender(this);
			}
		}

		[ConCommand(commandName = "toggleculling", flags = ConVarFlags.None, helpText = "togggle occlusion culling.")]
		private static void CCToggleCulling(ConCommandArgs args)
		{
			_camera.useOcclusionCulling = !_camera.useOcclusionCulling;
		}

		[ConCommand(commandName = "cycleSortMode", flags = ConVarFlags.None, helpText = "togggle occlusion culling.")]
		private static void CCCycleSortMode(ConCommandArgs args)
		{
			sortMode = (OpaqueSortMode)((int)(sortMode + 1) % 3);
		}
	}
	public class SceneDirector : MonoBehaviour
	{
		private struct NodeDistanceSqrPair
		{
			public NodeGraph.NodeIndex nodeIndex;

			public float distanceSqr;
		}

		public delegate void GenerateSpawnPointsDelegate(SceneDirector sceneDirector, ref Action generationMethod);

		public SpawnCard teleporterSpawnCard;

		public float expRewardCoefficient;

		public float eliteBias;

		public float spawnDistanceMultiplier;

		private int monsterCredit;

		public GameObject teleporterInstance;

		private Xoroshiro128Plus rng;

		public DirectorCard lumerianEgg;

		private InteractableSpawnCard halcyonShrine;

		private static readonly WeightedSelection<DirectorCard> cardSelector = new WeightedSelection<DirectorCard>();

		public int interactableCredit { get; set; }

		public float onPopulateCreditMultiplier { get; set; } = 1f;


		public static event Action<SceneDirector, DirectorCardCategorySelection> onGenerateInteractableCardSelection;

		public static event GenerateSpawnPointsDelegate onPreGeneratePlayerSpawnPointsServer;

		public static event Action<SceneDirector> onPrePopulateSceneServer;

		public static event Action<SceneDirector> onPrePopulateMonstersSceneServer;

		public static event Action<SceneDirector> onPostPopulateSceneServer;

		private void Start()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUint);
			float num = 0.5f + (float)Run.instance.participatingPlayerCount * 0.5f;
			ClassicStageInfo component = SceneInfo.instance.GetComponent<ClassicStageInfo>();
			if ((bool)component)
			{
				interactableCredit = (int)((float)component.sceneDirectorInteractibleCredits * num);
				if (component.bonusInteractibleCreditObjects != null)
				{
					for (int i = 0; i < component.bonusInteractibleCreditObjects.Length; i++)
					{
						ClassicStageInfo.BonusInteractibleCreditObject bonusInteractibleCreditObject = component.bonusInteractibleCreditObjects[i];
						if ((bool)bonusInteractibleCreditObject.objectThatGrantsPointsIfEnabled && bonusInteractibleCreditObject.objectThatGrantsPointsIfEnabled.activeSelf)
						{
							interactableCredit += bonusInteractibleCreditObject.points;
						}
					}
				}
				UnityEngine.Debug.LogFormat("Spending {0} credits on interactables...", interactableCredit);
				monsterCredit = (int)((float)component.sceneDirectorMonsterCredits * Run.instance.difficultyCoefficient);
			}
			halcyonShrine = Addressables.LoadAssetAsync<InteractableSpawnCard>("RoR2/DLC2/iscShrineHalcyoniteTier1.asset").WaitForCompletion();
			SceneDirector.onPrePopulateSceneServer?.Invoke(this);
			PopulateScene();
			SceneDirector.onPostPopulateSceneServer?.Invoke(this);
		}

		private void PlaceTeleporter()
		{
			if (!teleporterInstance && (bool)teleporterSpawnCard)
			{
				teleporterInstance = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(teleporterSpawnCard, new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Random
				}, rng));
				Run.instance.OnServerTeleporterPlaced(this, teleporterInstance);
			}
		}

		private static bool IsNodeSuitableForPod(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex)
		{
			if (nodeGraph.GetNodeFlags(nodeIndex, out var flags) && (flags & NodeFlags.NoCeiling) != 0)
			{
				return true;
			}
			return false;
		}

		private void PlacePlayerSpawnsViaNodegraph()
		{
			bool usePod = Stage.instance.usePod;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			NodeFlags requiredFlags = NodeFlags.None;
			NodeFlags nodeFlags = NodeFlags.None;
			nodeFlags |= NodeFlags.NoCharacterSpawn;
			List<NodeGraph.NodeIndex> list = groundNodes.GetActiveNodesForHullMaskWithFlagConditions(HullMask.Golem, requiredFlags, nodeFlags);
			if (usePod)
			{
				int num = list.Count - 1;
				while (num >= 0 && list.Count > 1)
				{
					if (!IsNodeSuitableForPod(groundNodes, list[num]))
					{
						list.RemoveAt(num);
					}
					num--;
				}
			}
			if (PlayerSpawnInhibitor.readOnlyInstancesList.Count > 0)
			{
				List<NodeGraph.NodeIndex> list2 = new List<NodeGraph.NodeIndex>();
				for (int i = 0; i < list.Count; i++)
				{
					bool flag = false;
					foreach (PlayerSpawnInhibitor readOnlyInstances in PlayerSpawnInhibitor.readOnlyInstancesList)
					{
						if (readOnlyInstances.IsInhibiting(groundNodes, list[i]))
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						list2.Add(list[i]);
					}
				}
				if (list2.Count > 0)
				{
					list = list2;
				}
			}
			NodeGraph.NodeIndex nodeIndex;
			if ((bool)teleporterInstance)
			{
				UnityEngine.Vector3 position = teleporterInstance.transform.position;
				List<NodeDistanceSqrPair> list3 = new List<NodeDistanceSqrPair>();
				for (int j = 0; j < list.Count; j++)
				{
					groundNodes.GetNodePosition(list[j], out var position2);
					list3.Add(new NodeDistanceSqrPair
					{
						nodeIndex = list[j],
						distanceSqr = (position - position2).sqrMagnitude
					});
				}
				list3.Sort((NodeDistanceSqrPair a, NodeDistanceSqrPair b) => a.distanceSqr.CompareTo(b.distanceSqr));
				int index = rng.RangeInt(list3.Count * 3 / 4, list3.Count);
				nodeIndex = list3[index].nodeIndex;
			}
			else
			{
				nodeIndex = rng.NextElementUniform(list);
			}
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human);
			nodeGraphSpider.AddNodeForNextStep(nodeIndex);
			while (nodeGraphSpider.PerformStep())
			{
				List<NodeGraphSpider.StepInfo> collectedSteps = nodeGraphSpider.collectedSteps;
				for (int num2 = collectedSteps.Count - 1; num2 >= 0; num2--)
				{
					if ((RoR2Application.maxPlayers <= list.Count && !list.Contains(collectedSteps[num2].node)) || (usePod && !IsNodeSuitableForPod(groundNodes, collectedSteps[num2].node)))
					{
						collectedSteps.RemoveAt(num2);
					}
				}
				if (collectedSteps.Count >= RoR2Application.maxPlayers)
				{
					break;
				}
			}
			List<NodeGraphSpider.StepInfo> collectedSteps2 = nodeGraphSpider.collectedSteps;
			Util.ShuffleList(collectedSteps2, Run.instance.stageRng);
			int num3 = Math.Min(nodeGraphSpider.collectedSteps.Count, RoR2Application.maxPlayers);
			for (int k = 0; k < num3; k++)
			{
				SpawnPoint.AddSpawnPoint(groundNodes, collectedSteps2[k].node, rng);
			}
		}

		private void RemoveAllExistingSpawnPoints()
		{
			List<SpawnPoint> list = new List<SpawnPoint>(SpawnPoint.readOnlyInstancesList);
			for (int i = 0; i < list.Count; i++)
			{
				UnityEngine.Object.Destroy(list[i].gameObject);
			}
		}

		private void CullExistingSpawnPoints()
		{
			List<SpawnPoint> list = new List<SpawnPoint>(SpawnPoint.readOnlyInstancesList);
			if (!teleporterInstance)
			{
				return;
			}
			UnityEngine.Vector3 teleporterPosition = teleporterInstance.transform.position;
			list.Sort((SpawnPoint a, SpawnPoint b) => (teleporterPosition - a.transform.position).sqrMagnitude.CompareTo((teleporterPosition - b.transform.position).sqrMagnitude));
			for (int num = list.Count; num >= 0; num--)
			{
				if (num < list.Count - RoR2Application.maxPlayers)
				{
					UnityEngine.Object.Destroy(list[num].gameObject);
				}
			}
		}

		private void DefaultPlayerSpawnPointGenerator()
		{
			bool num = SpawnPoint.readOnlyInstancesList.Count == 0;
			bool flag = Run.instance.autoGenerateSpawnPoints && (bool)Stage.instance && !Stage.instance.usePod;
			if (num || flag)
			{
				RemoveAllExistingSpawnPoints();
				PlacePlayerSpawnsViaNodegraph();
			}
			else
			{
				CullExistingSpawnPoints();
			}
		}

		private WeightedSelection<DirectorCard> GenerateInteractableCardSelection()
		{
			DirectorCardCategorySelection directorCardCategorySelection = ScriptableObject.CreateInstance<DirectorCardCategorySelection>();
			if ((bool)ClassicStageInfo.instance && (bool)ClassicStageInfo.instance.interactableCategories)
			{
				directorCardCategorySelection.CopyFrom(ClassicStageInfo.instance.interactableCategories);
			}
			SceneDirector.onGenerateInteractableCardSelection?.Invoke(this, directorCardCategorySelection);
			WeightedSelection<DirectorCard> result = directorCardCategorySelection.GenerateDirectorCardWeightedSelection();
			UnityEngine.Object.Destroy(directorCardCategorySelection);
			return result;
		}

		private void PopulateScene()
		{
			Run.instance.RecalculateDifficultyCoefficent();
			WeightedSelection<DirectorCard> deck = GenerateInteractableCardSelection();
			PlaceTeleporter();
			Dictionary<DirectorCard, int> dictionary = new Dictionary<DirectorCard, int>();
			interactableCredit = (int)Mathf.Floor((float)interactableCredit * onPopulateCreditMultiplier);
			while (interactableCredit > 0)
			{
				DirectorCard directorCard = SelectCard(deck, interactableCredit);
				if (directorCard == null)
				{
					break;
				}
				if (!directorCard.IsAvailable())
				{
					continue;
				}
				if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Devotion) && (directorCard.spawnCard as InteractableSpawnCard).skipSpawnWhenDevotionArtifactEnabled)
				{
					directorCard = lumerianEgg;
				}
				if (!dictionary.ContainsKey(directorCard))
				{
					InteractableSpawnCard interactableSpawnCard = directorCard.spawnCard as InteractableSpawnCard;
					if ((bool)interactableSpawnCard)
					{
						int value = int.MaxValue;
						if (interactableSpawnCard.maxSpawnsPerStage >= 0)
						{
							value = interactableSpawnCard.maxSpawnsPerStage;
						}
						dictionary[directorCard] = value;
					}
				}
				if (!dictionary.TryGetValue(directorCard, out var value2) || value2 <= 0)
				{
					continue;
				}
				dictionary[directorCard] = value2 - 1;
				if (Run.instance.isRunWeekly && rng.nextNormalizedFloat > (directorCard.spawnCard as InteractableSpawnCard).prismaticTrialSpawnChance)
				{
					continue;
				}
				interactableCredit -= directorCard.cost;
				if (!Run.instance)
				{
					continue;
				}
				for (int i = 0; i < 10; i++)
				{
					DirectorPlacementRule placementRule = new DirectorPlacementRule
					{
						placementMode = DirectorPlacementRule.PlacementMode.Random
					};
					GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(directorCard.spawnCard, placementRule, rng));
					if ((bool)gameObject)
					{
						PurchaseInteraction component = gameObject.GetComponent<PurchaseInteraction>();
						if ((bool)component && component.costType == CostTypeIndex.Money)
						{
							component.Networkcost = Run.instance.GetDifficultyScaledCost(component.cost);
						}
						break;
					}
				}
			}
			Action generationMethod = DefaultPlayerSpawnPointGenerator;
			SceneDirector.onPreGeneratePlayerSpawnPointsServer?.Invoke(this, ref generationMethod);
			generationMethod?.Invoke();
			Run.instance.OnPlayerSpawnPointsPlaced(this);
			SceneDirector.onPrePopulateMonstersSceneServer?.Invoke(this);
			if ((bool)Run.instance && CombatDirector.cvDirectorCombatDisable.value)
			{
				monsterCredit = 0;
			}
			if (!SceneInfo.instance.sceneDef.hasSafeStart)
			{
				CombatDirector component2 = GetComponent<CombatDirector>();
				if ((bool)component2)
				{
					float num = component2.expRewardCoefficient;
					float num2 = component2.eliteBias;
					float num3 = component2.spawnDistanceMultiplier;
					component2.monsterCredit += monsterCredit;
					component2.expRewardCoefficient = expRewardCoefficient;
					component2.eliteBias = eliteBias;
					component2.spawnDistanceMultiplier = spawnDistanceMultiplier;
					monsterCredit = 0;
					component2.onSpawnedServer.AddListener(OnMonsterSpawnedServer);
					component2.SpendAllCreditsOnMapSpawns(TeleporterInteraction.instance ? TeleporterInteraction.instance.transform : null);
					component2.onSpawnedServer.RemoveListener(OnMonsterSpawnedServer);
					component2.expRewardCoefficient = num;
					component2.eliteBias = num2;
					component2.spawnDistanceMultiplier = num3;
				}
			}
			if (!SceneInfo.instance.countsAsStage && !SceneInfo.instance.sceneDef.allowItemsToSpawnObjects)
			{
				return;
			}
			Xoroshiro128Plus xoroshiro128Plus = new Xoroshiro128Plus(rng.nextUlong);
			int num4 = 0;
			foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
			{
				if (readOnlyInstances.inventory.GetItemCount(RoR2Content.Items.TreasureCache) > 0)
				{
					num4++;
				}
			}
			for (int j = 0; j < num4; j++)
			{
				DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/iscLockbox"), new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Random
				}, xoroshiro128Plus));
			}
			Xoroshiro128Plus xoroshiro128Plus2 = new Xoroshiro128Plus(rng.nextUlong);
			int num5 = 0;
			foreach (CharacterMaster readOnlyInstances2 in CharacterMaster.readOnlyInstancesList)
			{
				if (readOnlyInstances2.inventory.GetItemCount(DLC1Content.Items.TreasureCacheVoid) > 0)
				{
					num5++;
				}
			}
			for (int k = 0; k < num5; k++)
			{
				DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/iscLockboxVoid"), new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Random
				}, xoroshiro128Plus2));
			}
			Xoroshiro128Plus xoroshiro128Plus3 = new Xoroshiro128Plus(rng.nextUlong);
			int num6 = 0;
			foreach (CharacterMaster readOnlyInstances3 in CharacterMaster.readOnlyInstancesList)
			{
				if (readOnlyInstances3.inventory.GetItemCount(DLC1Content.Items.FreeChest) > 0)
				{
					num6++;
				}
			}
			for (int l = 0; l < num6; l++)
			{
				DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/iscFreeChest"), new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Random
				}, xoroshiro128Plus3));
			}
			static void OnMonsterSpawnedServer(GameObject masterObject)
			{
				GameObject bodyObject = masterObject.GetComponent<CharacterMaster>().GetBodyObject();
				if ((bool)bodyObject)
				{
					EntityStateMachine[] components = bodyObject.GetComponents<EntityStateMachine>();
					foreach (EntityStateMachine obj in components)
					{
						obj.initialStateType = obj.mainStateType;
					}
				}
			}
		}

		private DirectorCard SelectCard(WeightedSelection<DirectorCard> deck, int maxCost)
		{
			cardSelector.Clear();
			int i = 0;
			for (int count = deck.Count; i < count; i++)
			{
				WeightedSelection<DirectorCard>.ChoiceInfo choice = deck.GetChoice(i);
				if (choice.value.cost <= maxCost)
				{
					cardSelector.AddChoice(choice);
				}
			}
			if (cardSelector.Count == 0)
			{
				return null;
			}
			return cardSelector.Evaluate(rng.nextNormalizedFloat);
		}

		public void ReduceMonsterCredits(int creditReduction)
		{
			monsterCredit = Mathf.Max(0, monsterCredit - creditReduction);
		}
	}
	public class SceneExitController : MonoBehaviour
	{
		public enum ExitState
		{
			Idle,
			ExtractExp,
			TeleportOut,
			Finished
		}

		public bool useRunNextStageScene;

		public SceneDef destinationScene;

		private const float teleportOutDuration = 4f;

		private float teleportOutTimer;

		public bool isAlternatePath;

		public SceneDef tier1AlternateDestinationScene;

		public SceneDef tier2AlternateDestinationScene;

		public SceneDef tier3AlternateDestinationScene;

		public SceneDef tier4AlternateDestinationScene;

		public SceneDef tier5AlternateDestinationScene;

		public bool isColossusPortal;

		public bool portalUsedAfterTeleporterEventFinish = true;

		private ExitState exitState;

		private ConvertPlayerMoneyToExperience experienceCollector;

		public static bool isRunning { get; private set; }

		public static event Action<SceneExitController> onBeginExit;

		public static event Action<SceneExitController> onFinishExit;

		public void Begin()
		{
			if (NetworkServer.active && exitState == ExitState.Idle)
			{
				SetState((!Run.instance.ruleBook.keepMoneyBetweenStages) ? ExitState.ExtractExp : ExitState.TeleportOut);
			}
		}

		public void SetState(ExitState newState)
		{
			if (newState == exitState)
			{
				return;
			}
			exitState = newState;
			switch (exitState)
			{
			case ExitState.ExtractExp:
				if (!isRunning)
				{
					if ((bool)TeleporterInteraction.instance)
					{
						portalUsedAfterTeleporterEventFinish = TeleporterInteraction.instance.activationState >= TeleporterInteraction.ActivationState.Charged;
					}
					SceneExitController.onBeginExit?.Invoke(this);
				}
				isRunning = true;
				experienceCollector = base.gameObject.AddComponent<ConvertPlayerMoneyToExperience>();
				if (isColossusPortal)
				{
					Util.PlaySound("Play_obj_portalColossus_activate", base.gameObject);
				}
				break;
			case ExitState.TeleportOut:
			{
				ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
				for (int i = 0; i < readOnlyInstancesList.Count; i++)
				{
					CharacterMaster component = readOnlyInstancesList[i].GetComponent<CharacterMaster>();
					if ((bool)component.GetComponent<SetDontDestroyOnLoad>())
					{
						GameObject bodyObject = component.GetBodyObject();
						if ((bool)bodyObject)
						{
							GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/TeleportOutController"), bodyObject.transform.position, UnityEngine.Quaternion.identity);
							obj.GetComponent<TeleportOutController>().Networktarget = bodyObject;
							NetworkServer.Spawn(obj);
						}
					}
				}
				teleportOutTimer = 4f;
				break;
			}
			case ExitState.Finished:
				SceneExitController.onFinishExit?.Invoke(this);
				if (!Run.instance || !Run.instance.isGameOverServer)
				{
					if (useRunNextStageScene)
					{
						Stage.instance.BeginAdvanceStage(Run.instance.nextStageScene);
					}
					else if (isAlternatePath && isAlternateSceneAvailable())
					{
						destinationScene = IfLoopedUseValidLoopStage(destinationScene);
						Stage.instance.BeginAdvanceStage(destinationScene);
					}
					else if ((bool)destinationScene)
					{
						Stage.instance.BeginAdvanceStage(destinationScene);
					}
				}
				break;
			case ExitState.Idle:
				break;
			}
		}

		private bool isAlternateSceneAvailable()
		{
			int stageOrder = Stage.instance.sceneDef.stageOrder;
			int num = Run.instance.nextStageScene.stageOrder;
			if (num != stageOrder + 1 && stageOrder <= 5)
			{
				num = stageOrder + 1;
			}
			if (num == 1 && tier1AlternateDestinationScene != null)
			{
				destinationScene = tier1AlternateDestinationScene;
				return true;
			}
			if (num == 2 && tier2AlternateDestinationScene != null)
			{
				destinationScene = tier2AlternateDestinationScene;
				return true;
			}
			if (num == 3 && tier3AlternateDestinationScene != null)
			{
				destinationScene = tier3AlternateDestinationScene;
				return true;
			}
			if (num == 4 && tier4AlternateDestinationScene != null)
			{
				destinationScene = tier4AlternateDestinationScene;
				return true;
			}
			if (num == 5 && tier5AlternateDestinationScene != null)
			{
				destinationScene = tier5AlternateDestinationScene;
				return true;
			}
			return false;
		}

		private SceneDef IfLoopedUseValidLoopStage(SceneDef sceneDef)
		{
			if (Run.instance.loopClearCount > 0 && Run.instance.stageClearCount > 5 && (bool)sceneDef.loopedSceneDef)
			{
				return sceneDef.loopedSceneDef;
			}
			return sceneDef;
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				UpdateServer();
			}
		}

		private void UpdateServer()
		{
			switch (exitState)
			{
			case ExitState.ExtractExp:
				if (!experienceCollector)
				{
					SetState(ExitState.TeleportOut);
				}
				break;
			case ExitState.TeleportOut:
				teleportOutTimer -= Time.fixedDeltaTime;
				if (teleportOutTimer <= 0f)
				{
					SetState(ExitState.Finished);
				}
				break;
			default:
				throw new ArgumentOutOfRangeException();
			case ExitState.Idle:
			case ExitState.Finished:
				break;
			}
		}

		private void OnDestroy()
		{
			isRunning = false;
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}
	}
	public class SceneExitControllerColossusPortal : MonoBehaviour
	{
		public enum ExitState
		{
			Idle,
			ExtractExp,
			TeleportOut,
			Finished
		}

		public bool useRunNextStageScene;

		private SceneDef destinationScene;

		public SceneDef t2DestinationScene;

		public SceneDef t3DestinationScene;

		public SceneDef t4DestinationScene;

		private const float teleportOutDuration = 4f;

		private float teleportOutTimer;

		private ExitState exitState;

		private ConvertPlayerMoneyToExperience experienceCollector;

		public static bool isRunning { get; private set; }

		public static event Action<SceneExitControllerColossusPortal> onBeginExit;

		public static event Action<SceneExitControllerColossusPortal> onFinishExit;

		public void Begin()
		{
			if (NetworkServer.active && exitState == ExitState.Idle)
			{
				SetState((!Run.instance.ruleBook.keepMoneyBetweenStages) ? ExitState.ExtractExp : ExitState.TeleportOut);
			}
		}

		public void SetState(ExitState newState)
		{
			if (newState == exitState)
			{
				return;
			}
			exitState = newState;
			switch (exitState)
			{
			case ExitState.ExtractExp:
				if (!isRunning)
				{
					SceneExitControllerColossusPortal.onBeginExit?.Invoke(this);
				}
				isRunning = true;
				experienceCollector = base.gameObject.AddComponent<ConvertPlayerMoneyToExperience>();
				break;
			case ExitState.TeleportOut:
			{
				ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
				for (int i = 0; i < readOnlyInstancesList.Count; i++)
				{
					CharacterMaster component = readOnlyInstancesList[i].GetComponent<CharacterMaster>();
					if ((bool)component.GetComponent<SetDontDestroyOnLoad>())
					{
						GameObject bodyObject = component.GetBodyObject();
						if ((bool)bodyObject)
						{
							GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/TeleportOutController"), bodyObject.transform.position, UnityEngine.Quaternion.identity);
							obj.GetComponent<TeleportOutController>().Networktarget = bodyObject;
							NetworkServer.Spawn(obj);
						}
					}
				}
				teleportOutTimer = 4f;
				break;
			}
			case ExitState.Finished:
				SceneExitControllerColossusPortal.onFinishExit?.Invoke(this);
				if ((bool)Run.instance && Run.instance.isGameOverServer)
				{
					break;
				}
				if (useRunNextStageScene)
				{
					Stage.instance.BeginAdvanceStage(Run.instance.nextStageScene);
					break;
				}
				SetNextStage();
				if ((bool)destinationScene)
				{
					Stage.instance.BeginAdvanceStage(destinationScene);
				}
				break;
			case ExitState.Idle:
				break;
			}
		}

		private void SetNextStage()
		{
			switch (Stage.instance.sceneDef.stageOrder)
			{
			case 1:
				destinationScene = t2DestinationScene;
				break;
			case 2:
				destinationScene = t3DestinationScene;
				break;
			default:
				destinationScene = t4DestinationScene;
				break;
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				UpdateServer();
			}
		}

		private void UpdateServer()
		{
			switch (exitState)
			{
			case ExitState.ExtractExp:
				if (!experienceCollector)
				{
					SetState(ExitState.TeleportOut);
				}
				break;
			case ExitState.TeleportOut:
				teleportOutTimer -= Time.fixedDeltaTime;
				if (teleportOutTimer <= 0f)
				{
					SetState(ExitState.Finished);
				}
				break;
			default:
				throw new ArgumentOutOfRangeException();
			case ExitState.Idle:
			case ExitState.Finished:
				break;
			}
		}

		private void OnDestroy()
		{
			isRunning = false;
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}
	}
	public class SceneInfo : MonoBehaviour
	{
		private static class NodeGraphOverlay
		{
			private static Dictionary<(MapNodeGroup.GraphType graphType, HullMask hullMask), (DebugOverlay.MeshDrawer drawer, Action updater)> drawers;

			private static void StaticUpdate()
			{
				foreach (KeyValuePair<(MapNodeGroup.GraphType, HullMask), (DebugOverlay.MeshDrawer, Action)> drawer in drawers)
				{
					drawer.Value.Item2();
				}
			}

			private static void SetGraphDrawEnabled(bool shouldDraw, MapNodeGroup.GraphType graphType, HullMask hullMask)
			{
				(MapNodeGroup.GraphType, HullMask) key = (graphType, hullMask);
				DebugOverlay.MeshDrawer drawer;
				GenericMemoizer<(DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask), Mesh> getNodeGraphMeshMemoizer;
				if (shouldDraw)
				{
					if (drawers == null)
					{
						drawers = new Dictionary<(MapNodeGroup.GraphType, HullMask), (DebugOverlay.MeshDrawer, Action)>();
						RoR2Application.onUpdate += StaticUpdate;
					}
					if (!drawers.ContainsKey(key))
					{
						drawer = DebugOverlay.GetMeshDrawer();
						drawer.hasMeshOwnership = true;
						drawer.material = DebugOverlay.defaultWireMaterial;
						getNodeGraphMeshMemoizer = new GenericMemoizer<(DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask), Mesh>(GetNodeGraphMesh);
						drawers.Add(key, (drawer, Updater));
					}
				}
				else if (drawers != null)
				{
					if (drawers.TryGetValue(key, out (DebugOverlay.MeshDrawer, Action) value))
					{
						value.Item1.Dispose();
						drawers.Remove(key);
					}
					if (drawers.Count == 0)
					{
						drawers = null;
						RoR2Application.onUpdate -= StaticUpdate;
					}
				}
				static Mesh GetNodeGraphMesh(in (DebugOverlay.MeshDrawer, SceneInfo sceneInfo, MapNodeGroup.GraphType graphType, HullMask hullMask) input)
				{
					return input.sceneInfo?.GetNodeGraph(input.graphType).GenerateLinkDebugMesh(input.hullMask);
				}
				void Updater()
				{
					DebugOverlay.MeshDrawer meshDrawer = drawer;
					ref GenericMemoizer<(DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask), Mesh> reference = ref getNodeGraphMeshMemoizer;
					(DebugOverlay.MeshDrawer, SceneInfo, MapNodeGroup.GraphType, HullMask) input2 = (drawer, instance, graphType, hullMask);
					meshDrawer.mesh = reference.Evaluate(in input2);
				}
			}

			[ConCommand(commandName = "debug_scene_draw_nodegraph", flags = ConVarFlags.Cheat, helpText = "Enables/disables overlay drawing of the specified nodegraph. Format: {shouldDraw} {graphType} {hullClassification, ...}")]
			private static void CCDebugSceneDrawNodegraph(ConCommandArgs args)
			{
				bool argBool = args.GetArgBool(0);
				MapNodeGroup.GraphType argEnum = args.GetArgEnum<MapNodeGroup.GraphType>(1);
				HullMask hullMask = (HullMask)(1 << (int)args.GetArgEnum<HullClassification>(2));
				if (hullMask == HullMask.None)
				{
					throw new ConCommandException("Cannot use HullMask.None.");
				}
				for (int i = 3; i < args.Count; i++)
				{
					HullClassification? hullClassification = args.TryGetArgEnum<HullClassification>(i);
					if (hullClassification.HasValue)
					{
						hullMask = (HullMask)((int)hullMask | (1 << (int)hullClassification.Value));
					}
				}
				SetGraphDrawEnabled(argBool, argEnum, hullMask);
			}
		}

		private static SceneInfo _instance;

		[FormerlySerializedAs("groundNodes")]
		public MapNodeGroup groundNodeGroup;

		[FormerlySerializedAs("airNodes")]
		public MapNodeGroup airNodeGroup;

		[FormerlySerializedAs("railNodes")]
		public MapNodeGroup railNodeGroup;

		public MeshRenderer approximateMapBoundMesh;

		[SerializeField]
		private NodeGraph groundNodesAsset;

		[SerializeField]
		private NodeGraph airNodesAsset;

		public static SceneInfo instance => _instance;

		public NodeGraph groundNodes { get; private set; }

		public NodeGraph airNodes { get; private set; }

		public NodeGraph railNodes { get; private set; }

		public SceneDef sceneDef { get; private set; }

		public bool countsAsStage
		{
			get
			{
				if (!sceneDef)
				{
					return false;
				}
				if (sceneDef.sceneType != SceneType.Stage)
				{
					return sceneDef.sceneType == SceneType.UntimedStage;
				}
				return true;
			}
		}

		private void Awake()
		{
			if ((bool)groundNodesAsset)
			{
				groundNodes = UnityEngine.Object.Instantiate(groundNodesAsset);
			}
			else
			{
				UnityEngine.Debug.LogWarning(base.gameObject.scene.name + " has no groundNodesAsset");
			}
			if ((bool)airNodesAsset)
			{
				airNodes = UnityEngine.Object.Instantiate(airNodesAsset);
			}
			else
			{
				UnityEngine.Debug.LogWarning(base.gameObject.scene.name + " has no airNodesAsset");
			}
			sceneDef = SceneCatalog.GetSceneDefFromSceneName(base.gameObject.scene.name);
		}

		private void Start()
		{
		}

		private void RemoveCollisionFromParticleSystems()
		{
			ParticleSystem[] array = UnityEngine.Object.FindObjectsOfType<ParticleSystem>();
			int num = 0;
			ParticleSystem[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				ParticleSystem.CollisionModule collision = array2[i].collision;
				if (collision.enabled)
				{
					num++;
				}
				collision.enabled = false;
			}
		}

		private void OnDestroy()
		{
			UnityEngine.Object.Destroy(groundNodes);
			UnityEngine.Object.Destroy(airNodes);
			UnityEngine.Object.Destroy(railNodes);
		}

		public MapNodeGroup GetNodeGroup(MapNodeGroup.GraphType nodeGraphType)
		{
			return nodeGraphType switch
			{
				MapNodeGroup.GraphType.Ground => groundNodeGroup, 
				MapNodeGroup.GraphType.Air => airNodeGroup, 
				MapNodeGroup.GraphType.Rail => railNodeGroup, 
				_ => null, 
			};
		}

		public NodeGraph GetNodeGraph(MapNodeGroup.GraphType nodeGraphType)
		{
			return nodeGraphType switch
			{
				MapNodeGroup.GraphType.Ground => groundNodes, 
				MapNodeGroup.GraphType.Air => airNodes, 
				MapNodeGroup.GraphType.Rail => railNodes, 
				_ => null, 
			};
		}

		public void SetGateState(string gateName, bool gateEnabled)
		{
			bool flag = false;
			if ((bool)groundNodes)
			{
				flag = groundNodes.TrySetGateState(gateName, gateEnabled) || flag;
			}
			if ((bool)airNodes)
			{
				flag = airNodes.TrySetGateState(gateName, gateEnabled) || flag;
			}
			if ((bool)railNodes)
			{
				flag = railNodes.TrySetGateState(gateName, gateEnabled) || flag;
			}
			if (!flag)
			{
				UnityEngine.Debug.LogError($"Unable to set gate state for {base.gameObject.scene.name}: {gateName}={gateEnabled}");
			}
		}

		private void OnEnable()
		{
			if (!_instance)
			{
				_instance = this;
			}
		}

		private void OnDisable()
		{
			if (_instance == this)
			{
				_instance = null;
			}
		}

		private void OnValidate()
		{
			if ((bool)groundNodeGroup)
			{
				groundNodesAsset = groundNodeGroup.nodeGraph;
			}
			if ((bool)airNodeGroup)
			{
				airNodesAsset = airNodeGroup.nodeGraph;
			}
		}
	}
	[Serializable]
	public struct GameObjectToggleGroup
	{
		public GameObject[] objects;

		public int minEnabled;

		public int maxEnabled;
	}
	public class SceneObjectToggleGroup : NetworkBehaviour
	{
		private struct ToggleGroupRange
		{
			public int start;

			public int count;

			public int minEnabled;

			public int maxEnabled;
		}

		public GameObjectToggleGroup[] toggleGroups;

		private const byte enabledObjectsDirtyBit = 1;

		private const byte initialStateMask = 1;

		private static readonly Queue<SceneObjectToggleGroup> activationsQueue;

		private GameObject[] allToggleableObjects;

		private bool[] activations;

		private ToggleGroupRange[] internalToggleGroups;

		static SceneObjectToggleGroup()
		{
			activationsQueue = new Queue<SceneObjectToggleGroup>();
			NetworkManagerSystem.onServerSceneChangedGlobal += OnServerSceneChanged;
		}

		private static void OnServerSceneChanged(string sceneName)
		{
			while (activationsQueue.Count > 0)
			{
				SceneObjectToggleGroup sceneObjectToggleGroup = activationsQueue.Dequeue();
				if ((bool)sceneObjectToggleGroup)
				{
					sceneObjectToggleGroup.ApplyActivations();
				}
			}
		}

		private void Awake()
		{
			activationsQueue.Enqueue(this);
			int num = 0;
			for (int i = 0; i < toggleGroups.Length; i++)
			{
				num += toggleGroups[i].objects.Length;
			}
			allToggleableObjects = new GameObject[num];
			activations = new bool[num];
			internalToggleGroups = new ToggleGroupRange[toggleGroups.Length];
			int start = 0;
			for (int j = 0; j < toggleGroups.Length; j++)
			{
				GameObject[] objects = toggleGroups[j].objects;
				ToggleGroupRange toggleGroupRange = default(ToggleGroupRange);
				toggleGroupRange.start = start;
				toggleGroupRange.count = objects.Length;
				toggleGroupRange.minEnabled = toggleGroups[j].minEnabled;
				toggleGroupRange.maxEnabled = toggleGroups[j].maxEnabled;
				internalToggleGroups[j] = toggleGroupRange;
				GameObject[] array = objects;
				foreach (GameObject gameObject in array)
				{
					allToggleableObjects[start++] = gameObject;
				}
			}
			if (NetworkServer.active)
			{
				Generate();
			}
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			if (!NetworkServer.active)
			{
				ApplyActivations();
			}
		}

		[Server]
		private void Generate()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SceneObjectToggleGroup::Generate()' called on client");
				return;
			}
			for (int i = 0; i < internalToggleGroups.Length; i++)
			{
				ToggleGroupRange toggleGroupRange = internalToggleGroups[i];
				int num = Run.instance.stageRng.RangeInt(toggleGroupRange.minEnabled, toggleGroupRange.maxEnabled + 1);
				List<int> list = RangeList(toggleGroupRange.start, toggleGroupRange.count);
				Util.ShuffleList(list, Run.instance.stageRng);
				for (int num2 = num - 1; num2 >= 0; num2--)
				{
					activations[list[num2]] = true;
					list.RemoveAt(num2);
				}
				for (int j = 0; j < list.Count; j++)
				{
					activations[list[j]] = false;
				}
			}
			SetDirtyBit(1u);
			static List<int> RangeList(int start, int count)
			{
				List<int> list2 = new List<int>(count);
				int k = start;
				for (int num3 = start + count; k < num3; k++)
				{
					list2.Add(k);
				}
				return list2;
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = (initialState ? 1u : base.syncVarDirtyBits);
			writer.Write((byte)num);
			if ((num & (true ? 1u : 0u)) != 0)
			{
				writer.WriteBitArray(activations);
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (((uint)reader.ReadByte() & (true ? 1u : 0u)) != 0)
			{
				reader.ReadBitArray(activations);
			}
			ApplyActivations();
		}

		private void ApplyActivations()
		{
			for (int i = 0; i < allToggleableObjects.Length; i++)
			{
				GameObject gameObject = allToggleableObjects[i];
				if ((bool)gameObject)
				{
					gameObject.SetActive(activations[i]);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[ExecuteInEditMode]
	public class SceneWeatherController : MonoBehaviour
	{
		[Serializable]
		public struct WeatherParams
		{
			[ColorUsage(true, true)]
			public UnityEngine.Color sunColor;

			public float sunIntensity;

			public float fogStart;

			public float fogScale;

			public float fogIntensity;
		}

		private static SceneWeatherController _instance;

		public WeatherParams initialWeatherParams;

		public WeatherParams finalWeatherParams;

		public Light sun;

		public Material fogMaterial;

		public string rtpcWeather;

		public float rtpcMin;

		public float rtpcMax = 100f;

		public AnimationCurve weatherLerpOverChargeTime;

		[Range(0f, 1f)]
		public float weatherLerp;

		public static SceneWeatherController instance => _instance;

		private void OnEnable()
		{
			if (!_instance)
			{
				_instance = this;
			}
		}

		private void OnDisable()
		{
			if (_instance == this)
			{
				_instance = null;
			}
		}

		private WeatherParams GetWeatherParams(float t)
		{
			WeatherParams result = default(WeatherParams);
			result.sunColor = UnityEngine.Color.Lerp(initialWeatherParams.sunColor, finalWeatherParams.sunColor, t);
			result.sunIntensity = Mathf.Lerp(initialWeatherParams.sunIntensity, finalWeatherParams.sunIntensity, t);
			result.fogStart = Mathf.Lerp(initialWeatherParams.fogStart, finalWeatherParams.fogStart, t);
			result.fogScale = Mathf.Lerp(initialWeatherParams.fogScale, finalWeatherParams.fogScale, t);
			result.fogIntensity = Mathf.Lerp(initialWeatherParams.fogIntensity, finalWeatherParams.fogIntensity, t);
			return result;
		}

		private void Update()
		{
			WeatherParams weatherParams = GetWeatherParams(weatherLerp);
			if ((bool)sun)
			{
				sun.color = weatherParams.sunColor;
				sun.intensity = weatherParams.sunIntensity;
			}
			if ((bool)fogMaterial)
			{
				fogMaterial.SetFloat("_FogPicker", weatherLerp);
				fogMaterial.SetFloat("_FogStart", weatherParams.fogStart);
				fogMaterial.SetFloat("_FogScale", weatherParams.fogScale);
				fogMaterial.SetFloat("_FogIntensity", weatherParams.fogIntensity);
			}
			if (true && rtpcWeather.Length != 0)
			{
				AkSoundEngine.SetRTPCValue(rtpcWeather, Mathf.Lerp(rtpcMin, rtpcMax, weatherLerp), base.gameObject);
			}
		}
	}
	public class ScrapperController : NetworkBehaviour
	{
		public PickupPickerController pickupPickerController;

		public EntityStateMachine esm;

		public int maxItemsToScrapAtATime = 10;

		private Interactor interactor;

		public ItemIndex lastScrappedItemIndex { get; private set; }

		public int itemsEaten { get; set; }

		private void Start()
		{
		}

		private void Update()
		{
		}

		[Server]
		public void AssignPotentialInteractor(Interactor potentialInteractor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScrapperController::AssignPotentialInteractor(RoR2.Interactor)' called on client");
			}
			else
			{
				interactor = potentialInteractor;
			}
		}

		[Server]
		public void BeginScrapping(int intPickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScrapperController::BeginScrapping(System.Int32)' called on client");
				return;
			}
			itemsEaten = 0;
			PickupDef pickupDef = PickupCatalog.GetPickupDef(new PickupIndex(intPickupIndex));
			if (pickupDef != null && (bool)interactor)
			{
				lastScrappedItemIndex = pickupDef.itemIndex;
				CharacterBody component = interactor.GetComponent<CharacterBody>();
				if ((bool)component && (bool)component.inventory)
				{
					int num = Mathf.Min(maxItemsToScrapAtATime, component.inventory.GetItemCount(pickupDef.itemIndex));
					if (num > 0)
					{
						component.inventory.RemoveItem(pickupDef.itemIndex, num);
						itemsEaten += num;
						for (int i = 0; i < num; i++)
						{
							CreateItemTakenOrb(component.corePosition, base.gameObject, pickupDef.itemIndex);
						}
					}
				}
			}
			if ((bool)esm)
			{
				esm.SetNextState(new WaitToBeginScrapping());
			}
		}

		[Server]
		public static void CreateItemTakenOrb(UnityEngine.Vector3 effectOrigin, GameObject targetObject, ItemIndex itemIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ScrapperController::CreateItemTakenOrb(UnityEngine.Vector3,UnityEngine.GameObject,RoR2.ItemIndex)' called on client");
				return;
			}
			GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OrbEffects/ItemTakenOrbEffect");
			EffectData effectData = new EffectData
			{
				origin = effectOrigin,
				genericFloat = 1.5f,
				genericUInt = (uint)(itemIndex + 1)
			};
			effectData.SetNetworkedObjectReference(targetObject);
			EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(CombatSquad))]
	public class ScriptedCombatEncounter : MonoBehaviour
	{
		[Serializable]
		public struct SpawnInfo
		{
			public SpawnCard spawnCard;

			public Transform explicitSpawnPosition;

			[Tooltip("The chance that this spawn card will be culled, removing it from the list. A value of 0 means it is guaranteed.")]
			[Range(0f, 100f)]
			public float cullChance;
		}

		public ulong seed;

		public bool randomizeSeed;

		public TeamIndex teamIndex;

		public SpawnInfo[] spawns;

		public bool spawnOnStart;

		public bool grantUniqueBonusScaling = true;

		private Xoroshiro128Plus rng;

		public CombatSquad combatSquad { get; private set; }

		public bool hasSpawnedServer { get; private set; }

		public event Action<ScriptedCombatEncounter> onBeginEncounter;

		private void Awake()
		{
			combatSquad = GetComponent<CombatSquad>();
			hasSpawnedServer = false;
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(randomizeSeed ? Run.instance.stageRng.nextUlong : seed);
			}
		}

		private void Start()
		{
			if (NetworkServer.active && spawnOnStart)
			{
				BeginEncounter();
			}
		}

		private void Spawn(ref SpawnInfo spawnInfo)
		{
			UnityEngine.Vector3 position = base.transform.position;
			DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
				minDistance = 0f,
				maxDistance = 1000f,
				position = position
			};
			if ((bool)spawnInfo.explicitSpawnPosition)
			{
				directorPlacementRule.placementMode = DirectorPlacementRule.PlacementMode.Direct;
				directorPlacementRule.spawnOnTarget = spawnInfo.explicitSpawnPosition;
			}
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnInfo.spawnCard, directorPlacementRule, rng);
			directorSpawnRequest.ignoreTeamMemberLimit = true;
			directorSpawnRequest.teamIndexOverride = teamIndex;
			directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, new Action<SpawnCard.SpawnResult>(HandleSpawn));
			DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			void HandleSpawn(SpawnCard.SpawnResult spawnResult)
			{
				GameObject spawnedInstance = spawnResult.spawnedInstance;
				if ((bool)spawnedInstance)
				{
					hasSpawnedServer = true;
					CharacterMaster component = spawnedInstance.GetComponent<CharacterMaster>();
					if (grantUniqueBonusScaling)
					{
						float num = 1f;
						float num2 = 1f;
						num += Run.instance.difficultyCoefficient / 2.5f;
						num2 += Run.instance.difficultyCoefficient / 30f;
						int num3 = Mathf.Max(1, Run.instance.livingPlayerCount);
						num *= Mathf.Pow(num3, 0.5f);
						UnityEngine.Debug.LogFormat("Scripted Combat Encounter: currentBoostHpCoefficient={0}, currentBoostDamageCoefficient={1}", num, num2);
						component.inventory.GiveItem(RoR2Content.Items.BoostHp, Mathf.RoundToInt((num - 1f) * 10f));
						component.inventory.GiveItem(RoR2Content.Items.BoostDamage, Mathf.RoundToInt((num2 - 1f) * 10f));
					}
					if (RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.eliteOnlyArtifactDef))
					{
						EliteDef[] array = new EliteDef[4]
						{
							RoR2Content.Elites.Fire,
							RoR2Content.Elites.Lightning,
							RoR2Content.Elites.Ice,
							DLC1Content.Elites.Earth
						};
						int num4 = rng.RangeInt(0, array.Length);
						EquipmentIndex equipmentIndex = array[num4]?.eliteEquipmentDef?.equipmentIndex ?? EquipmentIndex.None;
						if (equipmentIndex != EquipmentIndex.None)
						{
							component.inventory.SetEquipmentIndex(equipmentIndex);
						}
					}
					combatSquad.AddMember(component);
				}
				else
				{
					UnityEngine.Debug.LogFormat("No spawned master from combat group!");
				}
			}
		}

		public void BeginEncounter()
		{
			if (hasSpawnedServer || !NetworkServer.active)
			{
				return;
			}
			for (int i = 0; i < spawns.Length; i++)
			{
				ref SpawnInfo reference = ref spawns[i];
				if (!(rng.nextNormalizedFloat * 100f < reference.cullChance))
				{
					Spawn(ref reference);
				}
			}
			this.onBeginEncounter?.Invoke(this);
		}
	}
	public class SeerStationController : NetworkBehaviour
	{
		[SyncVar(hook = "SetTargetSceneDefIndex")]
		private int targetSceneDefIndex = -1;

		public SceneExitController explicitTargetSceneExitController;

		public bool fallBackToFirstActiveExitController;

		public Renderer targetRenderer;

		public int materialIndexToAssign;

		private static List<Material> sharedSharedMaterialsList = new List<Material>();

		public int NetworktargetSceneDefIndex
		{
			get
			{
				return targetSceneDefIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetTargetSceneDefIndex(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref targetSceneDefIndex, 1u);
			}
		}

		private void SetTargetSceneDefIndex(int newTargetSceneDefIndex)
		{
			NetworktargetSceneDefIndex = newTargetSceneDefIndex;
			OnTargetSceneChanged(SceneCatalog.GetSceneDef((SceneIndex)targetSceneDefIndex));
		}

		[Server]
		public void SetTargetScene(SceneDef sceneDef)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SeerStationController::SetTargetScene(RoR2.SceneDef)' called on client");
			}
			else
			{
				NetworktargetSceneDefIndex = (int)sceneDef.sceneDefIndex;
			}
		}

		public int ReturnTargetSceneDefIndex()
		{
			return targetSceneDefIndex;
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			SceneDef targetScene = null;
			if ((uint)targetSceneDefIndex < SceneCatalog.sceneDefCount)
			{
				targetScene = SceneCatalog.GetSceneDef((SceneIndex)targetSceneDefIndex);
			}
			OnTargetSceneChanged(targetScene);
		}

		private void OnTargetSceneChanged(SceneDef targetScene)
		{
			Material portalMaterial = null;
			if ((bool)targetScene)
			{
				portalMaterial = targetScene.portalMaterial;
			}
			SetPortalMaterial(portalMaterial);
		}

		private void SetPortalMaterial(Material portalMaterial)
		{
			targetRenderer.GetSharedMaterials(sharedSharedMaterialsList);
			sharedSharedMaterialsList[materialIndexToAssign] = portalMaterial;
			targetRenderer.SetSharedMaterials(sharedSharedMaterialsList);
			sharedSharedMaterialsList.Clear();
		}

		[Server]
		public void SetRunNextStageToTarget()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SeerStationController::SetRunNextStageToTarget()' called on client");
				return;
			}
			SceneDef sceneDef = SceneCatalog.GetSceneDef((SceneIndex)targetSceneDefIndex);
			if ((bool)sceneDef)
			{
				SceneExitController sceneExitController = explicitTargetSceneExitController;
				if (!sceneExitController && fallBackToFirstActiveExitController)
				{
					sceneExitController = InstanceTracker.FirstOrNull<SceneExitController>();
				}
				if ((bool)sceneExitController)
				{
					sceneExitController.destinationScene = sceneDef;
					sceneExitController.useRunNextStageScene = false;
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = sceneDef.portalSelectionMessageString
					});
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)targetSceneDefIndex);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)targetSceneDefIndex);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				targetSceneDefIndex = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetTargetSceneDefIndex((int)reader.ReadPackedUInt32());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[ExecuteAlways]
	public class SetAmbientLight : MonoBehaviour
	{
		public bool setSkyboxMaterial;

		public bool setAmbientLightColor;

		public Material skyboxMaterial;

		public AmbientMode ambientMode;

		public float ambientIntensity;

		[ColorUsage(true, true)]
		public UnityEngine.Color ambientSkyColor = UnityEngine.Color.black;

		[ColorUsage(true, true)]
		public UnityEngine.Color ambientEquatorColor = UnityEngine.Color.black;

		[ColorUsage(true, true)]
		public UnityEngine.Color ambientGroundColor = UnityEngine.Color.black;

		private void OnEnable()
		{
		}

		private void ApplyLighting()
		{
			if (setAmbientLightColor)
			{
				RenderSettings.ambientMode = ambientMode;
				RenderSettings.ambientSkyColor = ambientSkyColor * ambientIntensity;
				RenderSettings.ambientEquatorColor = ambientEquatorColor * ambientIntensity;
				RenderSettings.ambientGroundColor = ambientGroundColor * ambientIntensity;
			}
			if (setSkyboxMaterial)
			{
				RenderSettings.skybox = skyboxMaterial;
			}
		}
	}
	public class SetDontDestroyOnLoad : MonoBehaviour
	{
		private void Awake()
		{
			UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
		}
	}
	public class SetGravity : MonoBehaviour
	{
		public float newGravity = -30f;

		private void OnEnable()
		{
			Physics.gravity = new UnityEngine.Vector3(0f, newGravity, 0f);
		}

		private void OnDisable()
		{
			Physics.gravity = new UnityEngine.Vector3(0f, Run.baseGravity, 0f);
		}
	}
	[DisallowMultipleComponent]
	public class SetStateOnHurt : NetworkBehaviour, IOnTakeDamageServerReceiver
	{
		[Tooltip("The percentage of their max HP they need to take to get stunned. Ranges from 0-1.")]
		public float hitThreshold = 0.1f;

		[Tooltip("The state machine to set the state of when this character is hurt.")]
		public EntityStateMachine targetStateMachine;

		[Tooltip("The state machine to set to idle when this character is hurt.")]
		public EntityStateMachine[] idleStateMachine;

		[Tooltip("The state to enter when this character is hurt.")]
		public SerializableEntityStateType hurtState;

		public bool canBeHitStunned = true;

		public bool canBeStunned = true;

		public bool canBeFrozen = true;

		private bool hasEffectiveAuthority = true;

		private static readonly float stunChanceOnHitBaseChancePercent;

		private static int kRpcRpcSetStun;

		private static int kRpcRpcSetFrozen;

		private static int kRpcRpcSetShock;

		private static int kRpcRpcSetPain;

		private static int kRpcRpcCleanse;

		private bool spawnedOverNetwork => base.isServer;

		public static void SetStunOnObject(GameObject target, float duration)
		{
			SetStateOnHurt component = target.GetComponent<SetStateOnHurt>();
			if ((bool)component)
			{
				component.SetStun(duration);
			}
		}

		public override void OnStartAuthority()
		{
			base.OnStartAuthority();
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			base.OnStopAuthority();
			UpdateAuthority();
		}

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
		}

		private void Start()
		{
			UpdateAuthority();
		}

		public void OnTakeDamageServer(DamageReport damageReport)
		{
			if (!targetStateMachine || !spawnedOverNetwork)
			{
				return;
			}
			HealthComponent victim = damageReport.victim;
			DamageInfo damageInfo = damageReport.damageInfo;
			CharacterMaster attackerMaster = damageReport.attackerMaster;
			int num = (attackerMaster ? attackerMaster.inventory.GetItemCount(RoR2Content.Items.StunChanceOnHit) : 0);
			if (num > 0 && Util.CheckRoll(Util.ConvertAmplificationPercentageIntoReductionPercentage(stunChanceOnHitBaseChancePercent * (float)num * damageReport.damageInfo.procCoefficient), attackerMaster))
			{
				EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/ImpactStunGrenade"), damageInfo.position, -damageInfo.force, transmit: true);
				SetStun(2f);
			}
			bool flag = damageInfo.procCoefficient >= Mathf.Epsilon;
			float damageDealt = damageReport.damageDealt;
			if (flag && canBeFrozen && (ulong)(damageInfo.damageType & DamageType.Freeze2s) != 0L)
			{
				SetFrozen(2f * damageInfo.procCoefficient);
			}
			else if (!victim.isInFrozenState)
			{
				if (flag && canBeStunned && (ulong)(damageInfo.damageType & DamageType.Shock5s) != 0L)
				{
					SetShock(5f * damageReport.damageInfo.procCoefficient);
				}
				else if (flag && canBeStunned && (ulong)(damageInfo.damageType & DamageType.Stun1s) != 0L)
				{
					SetStun(1f);
				}
				else if (canBeHitStunned && damageDealt > victim.fullCombinedHealth * hitThreshold)
				{
					SetPain();
				}
			}
		}

		[Server]
		public void SetStun(float duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SetStateOnHurt::SetStun(System.Single)' called on client");
			}
			else if (canBeStunned)
			{
				if (hasEffectiveAuthority)
				{
					SetStunInternal(duration);
				}
				else
				{
					CallRpcSetStun(duration);
				}
			}
		}

		[Server]
		public void SetFrozen(float duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SetStateOnHurt::SetFrozen(System.Single)' called on client");
			}
			else if (canBeFrozen)
			{
				if (hasEffectiveAuthority)
				{
					SetFrozenInternal(duration);
				}
				else
				{
					CallRpcSetFrozen(duration);
				}
			}
		}

		[Server]
		public void SetShock(float duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SetStateOnHurt::SetShock(System.Single)' called on client");
			}
			else if (canBeStunned)
			{
				if (hasEffectiveAuthority)
				{
					SetShockInternal(duration);
				}
				else
				{
					CallRpcSetShock(duration);
				}
			}
		}

		[Server]
		public void SetPain()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SetStateOnHurt::SetPain()' called on client");
			}
			else if (canBeHitStunned)
			{
				if (hasEffectiveAuthority)
				{
					SetPainInternal();
				}
				else
				{
					CallRpcSetPain();
				}
			}
		}

		[Server]
		public void Cleanse()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SetStateOnHurt::Cleanse()' called on client");
			}
			else if (hasEffectiveAuthority)
			{
				CleanseInternal();
			}
			else
			{
				CallRpcCleanse();
			}
		}

		[ClientRpc]
		private void RpcSetStun(float duration)
		{
			if (hasEffectiveAuthority)
			{
				SetStunInternal(duration);
			}
		}

		private void SetStunInternal(float duration)
		{
			if ((bool)targetStateMachine)
			{
				if (targetStateMachine.state is StunState)
				{
					(targetStateMachine.state as StunState).ExtendStun(duration);
				}
				else
				{
					StunState stunState = new StunState();
					stunState.stunDuration = duration;
					targetStateMachine.SetInterruptState(stunState, InterruptPriority.Stun);
				}
			}
			EntityStateMachine[] array = idleStateMachine;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetNextStateToMain();
			}
		}

		[ClientRpc]
		private void RpcSetFrozen(float duration)
		{
			if (hasEffectiveAuthority)
			{
				SetFrozenInternal(duration);
			}
		}

		private void SetFrozenInternal(float duration)
		{
			if ((bool)targetStateMachine)
			{
				FrozenState frozenState = new FrozenState();
				frozenState.freezeDuration = duration;
				targetStateMachine.SetInterruptState(frozenState, InterruptPriority.Frozen);
			}
			EntityStateMachine[] array = idleStateMachine;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetNextState(new EntityStates.Idle());
			}
		}

		[ClientRpc]
		private void RpcSetShock(float duration)
		{
			if (hasEffectiveAuthority)
			{
				SetShockInternal(duration);
			}
		}

		private void SetShockInternal(float duration)
		{
			if ((bool)targetStateMachine)
			{
				ShockState shockState = new ShockState();
				shockState.shockDuration = duration;
				targetStateMachine.SetInterruptState(shockState, InterruptPriority.Pain);
			}
			EntityStateMachine[] array = idleStateMachine;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetNextStateToMain();
			}
		}

		[ClientRpc]
		private void RpcSetPain()
		{
			if (hasEffectiveAuthority)
			{
				SetPainInternal();
			}
		}

		private void SetPainInternal()
		{
			if ((bool)targetStateMachine)
			{
				targetStateMachine.SetInterruptState(EntityStateCatalog.InstantiateState(ref hurtState), InterruptPriority.Pain);
			}
			EntityStateMachine[] array = idleStateMachine;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetNextStateToMain();
			}
		}

		[ClientRpc]
		private void RpcCleanse()
		{
			if (hasEffectiveAuthority)
			{
				CleanseInternal();
			}
		}

		private void CleanseInternal()
		{
			if ((bool)targetStateMachine && (targetStateMachine.state is FrozenState || targetStateMachine.state is StunState || targetStateMachine.state is ShockState))
			{
				targetStateMachine.SetInterruptState(EntityStateCatalog.InstantiateState(ref targetStateMachine.mainStateType), InterruptPriority.Frozen);
			}
		}

		static SetStateOnHurt()
		{
			stunChanceOnHitBaseChancePercent = 5f;
			kRpcRpcSetStun = 788834249;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SetStateOnHurt), kRpcRpcSetStun, InvokeRpcRpcSetStun);
			kRpcRpcSetFrozen = 1781279215;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SetStateOnHurt), kRpcRpcSetFrozen, InvokeRpcRpcSetFrozen);
			kRpcRpcSetShock = -1316305549;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SetStateOnHurt), kRpcRpcSetShock, InvokeRpcRpcSetShock);
			kRpcRpcSetPain = 788726245;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SetStateOnHurt), kRpcRpcSetPain, InvokeRpcRpcSetPain);
			kRpcRpcCleanse = -339360280;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SetStateOnHurt), kRpcRpcCleanse, InvokeRpcRpcCleanse);
			NetworkCRC.RegisterBehaviour("SetStateOnHurt", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcSetStun(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetStun called on server.");
			}
			else
			{
				((SetStateOnHurt)obj).RpcSetStun(reader.ReadSingle());
			}
		}

		protected static void InvokeRpcRpcSetFrozen(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetFrozen called on server.");
			}
			else
			{
				((SetStateOnHurt)obj).RpcSetFrozen(reader.ReadSingle());
			}
		}

		protected static void InvokeRpcRpcSetShock(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetShock called on server.");
			}
			else
			{
				((SetStateOnHurt)obj).RpcSetShock(reader.ReadSingle());
			}
		}

		protected static void InvokeRpcRpcSetPain(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetPain called on server.");
			}
			else
			{
				((SetStateOnHurt)obj).RpcSetPain();
			}
		}

		protected static void InvokeRpcRpcCleanse(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcCleanse called on server.");
			}
			else
			{
				((SetStateOnHurt)obj).RpcCleanse();
			}
		}

		public void CallRpcSetStun(float duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetStun called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetStun);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(duration);
			SendRPCInternal(networkWriter, 0, "RpcSetStun");
		}

		public void CallRpcSetFrozen(float duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetFrozen called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetFrozen);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(duration);
			SendRPCInternal(networkWriter, 0, "RpcSetFrozen");
		}

		public void CallRpcSetShock(float duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetShock called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetShock);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(duration);
			SendRPCInternal(networkWriter, 0, "RpcSetShock");
		}

		public void CallRpcSetPain()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetPain called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetPain);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcSetPain");
		}

		public void CallRpcCleanse()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcCleanse called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcCleanse);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcCleanse");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class SetStateOnWeakened : NetworkBehaviour, IOnTakeDamageServerReceiver
	{
		[Tooltip("The percentage of their max HP they need to take to get weakened. Ranges from 0-1.")]
		public float weakenPercentage = 0.1f;

		[Tooltip("The percentage of their max HP they deal to themselves once weakened. Ranges from 0-1.")]
		public float selfDamagePercentage;

		[Tooltip("The state machine to set the state of when this character is hurt.")]
		public EntityStateMachine targetStateMachine;

		[Tooltip("The state machine to set to idle when this character is hurt.")]
		public EntityStateMachine[] idleStateMachine;

		[Tooltip("The hurtboxes to set to not a weak point once consumed")]
		public HurtBox[] weakHurtBox;

		[Tooltip("The state to enter when this character is hurt.")]
		public SerializableEntityStateType hurtState;

		private float accumulatedDamage;

		private bool consumed;

		private CharacterBody characterBody;

		private void Start()
		{
			characterBody = GetComponent<CharacterBody>();
		}

		public void OnTakeDamageServer(DamageReport damageReport)
		{
			if (consumed || !targetStateMachine || !base.isServer || !characterBody)
			{
				return;
			}
			DamageInfo damageInfo = damageReport.damageInfo;
			float num = (damageInfo.crit ? (damageInfo.damage * 2f) : damageInfo.damage);
			if ((ulong)(damageInfo.damageType & DamageType.WeakPointHit) != 0L)
			{
				accumulatedDamage += num;
				if (accumulatedDamage > characterBody.maxHealth * weakenPercentage)
				{
					consumed = true;
					SetWeak(damageInfo);
				}
			}
		}

		public void SetWeak(DamageInfo damageInfo)
		{
			if ((bool)targetStateMachine)
			{
				targetStateMachine.SetInterruptState(EntityStateCatalog.InstantiateState(ref hurtState), InterruptPriority.Pain);
			}
			EntityStateMachine[] array = idleStateMachine;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetNextState(new EntityStates.Idle());
			}
			HurtBox[] array2 = weakHurtBox;
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i].gameObject.SetActive(value: false);
			}
			if (selfDamagePercentage > 0f)
			{
				DamageInfo damageInfo2 = new DamageInfo();
				damageInfo2.damage = characterBody.maxHealth * selfDamagePercentage / 3f;
				damageInfo2.attacker = damageInfo.attacker;
				damageInfo2.crit = true;
				damageInfo2.position = damageInfo.position;
				damageInfo2.damageType = DamageType.NonLethal | DamageType.WeakPointHit;
				characterBody.healthComponent.TakeDamage(damageInfo2);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(WheelCollider))]
	public class SetWheelVisuals : MonoBehaviour
	{
		public Transform visualTransform;

		private WheelCollider wheelCollider;

		private void Start()
		{
			wheelCollider = GetComponent<WheelCollider>();
		}

		private void FixedUpdate()
		{
			wheelCollider.GetWorldPose(out var pos, out var quat);
			visualTransform.position = pos;
			visualTransform.rotation = quat;
		}
	}
	[DisallowMultipleComponent]
	public class SfxLocator : MonoBehaviour
	{
		public string deathSound;

		public string barkSound;

		public string openSound;

		public string landingSound;

		public string fallDamageSound;

		public string aliveLoopStart;

		public string aliveLoopStop;

		public string sprintLoopStart;

		public string sprintLoopStop;
	}
	public class ShakeEmitter : MonoBehaviour
	{
		public struct MotorBias
		{
			public float deepLeftBias;

			public float quickRightBias;
		}

		private static readonly List<ShakeEmitter> instances = new List<ShakeEmitter>();

		[Tooltip("Whether or not to begin shaking as soon as this instance becomes active.")]
		public bool shakeOnStart = true;

		[Tooltip("Whether or not to begin shaking every time this instance is enabled.")]
		public bool shakeOnEnable;

		[Tooltip("The wave description of this motion.")]
		public Wave wave = new Wave
		{
			amplitude = 1f,
			frequency = 1f,
			cycleOffset = 0f
		};

		[Tooltip("How long the shake lasts, in seconds.")]
		public float duration = 1f;

		[Tooltip("How far the wave reaches.")]
		public float radius = 10f;

		[Tooltip("Whether or not the radius should be multiplied with local scale.")]
		public bool scaleShakeRadiusWithLocalScale;

		[Tooltip("Whether or not the ampitude should decay with time.")]
		public bool amplitudeTimeDecay = true;

		private float stopwatch = float.PositiveInfinity;

		private float halfPeriodTimer;

		private UnityEngine.Vector3 halfPeriodVector;

		private UnityEngine.Vector3 currentOffset;

		private const float deepRumbleFactor = 5f;

		public void StartShake()
		{
			stopwatch = 0f;
			halfPeriodVector = UnityEngine.Random.onUnitSphere;
			halfPeriodTimer = wave.period * 0.5f;
		}

		private void Start()
		{
			if (scaleShakeRadiusWithLocalScale)
			{
				radius *= base.transform.localScale.x;
			}
			if (shakeOnStart)
			{
				StartShake();
			}
		}

		private void OnEnable()
		{
			instances.Add(this);
			if (shakeOnEnable)
			{
				StartShake();
			}
		}

		private void OnDisable()
		{
			instances.Remove(this);
		}

		private void OnValidate()
		{
			if (wave.frequency == 0f)
			{
				wave.frequency = 1f;
			}
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			RoR2Application.onUpdate += UpdateAll;
		}

		public static void UpdateAll()
		{
			float deltaTime = Time.deltaTime;
			if (deltaTime != 0f)
			{
				for (int i = 0; i < instances.Count; i++)
				{
					instances[i].ManualUpdate(deltaTime);
				}
			}
		}

		public float CurrentShakeFade()
		{
			if (!amplitudeTimeDecay)
			{
				return 1f;
			}
			return 1f - stopwatch / duration;
		}

		public void ManualUpdate(float deltaTime)
		{
			stopwatch += deltaTime;
			if (stopwatch < duration)
			{
				float num = CurrentShakeFade();
				halfPeriodTimer -= deltaTime;
				if (halfPeriodTimer < 0f)
				{
					halfPeriodVector = UnityEngine.Vector3.Slerp(UnityEngine.Random.onUnitSphere, -halfPeriodVector, 0.5f);
					halfPeriodTimer += wave.period * 0.5f;
				}
				currentOffset = halfPeriodVector * wave.Evaluate(halfPeriodTimer) * num;
			}
			else
			{
				currentOffset = UnityEngine.Vector3.zero;
			}
		}

		public static void ApplySpacialRumble(LocalUser localUser, Transform cameraTransform)
		{
			UnityEngine.Vector3 right = cameraTransform.right;
			UnityEngine.Vector3 position = cameraTransform.position;
			float num = 0f;
			float num2 = 0f;
			int i = 0;
			for (int count = instances.Count; i < count; i++)
			{
				ShakeEmitter shakeEmitter = instances[i];
				UnityEngine.Vector3 position2 = shakeEmitter.transform.position;
				float value = UnityEngine.Vector3.Dot(position2 - position, right);
				float sqrMagnitude = (position - position2).sqrMagnitude;
				float num3 = shakeEmitter.radius;
				float num4 = 0f;
				if (sqrMagnitude < num3 * num3)
				{
					float num5 = 1f - Mathf.Sqrt(sqrMagnitude) / num3;
					num4 = shakeEmitter.CurrentShakeFade() * shakeEmitter.wave.amplitude * num5;
				}
				float num6 = Mathf.Clamp01(Util.Remap(value, -1f, 1f, 0f, 1f));
				float num7 = num4;
				num += num7 * (1f - num6);
				num2 += num7 * num6;
			}
		}

		public static UnityEngine.Vector3 ComputeTotalShakeAtPoint(UnityEngine.Vector3 position)
		{
			UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
			int i = 0;
			for (int count = instances.Count; i < count; i++)
			{
				ShakeEmitter shakeEmitter = instances[i];
				float sqrMagnitude = (position - shakeEmitter.transform.position).sqrMagnitude;
				float num = shakeEmitter.radius;
				if (sqrMagnitude < num * num)
				{
					float num2 = 1f - Mathf.Sqrt(sqrMagnitude) / num;
					zero += shakeEmitter.currentOffset * num2;
				}
			}
			return zero;
		}

		public static ShakeEmitter CreateSimpleShakeEmitter(UnityEngine.Vector3 position, Wave wave, float duration, float radius, bool amplitudeTimeDecay)
		{
			if (wave.frequency == 0f)
			{
				wave.frequency = 1f;
			}
			GameObject obj = new GameObject("ShakeEmitter", typeof(ShakeEmitter), typeof(DestroyOnTimer));
			ShakeEmitter component = obj.GetComponent<ShakeEmitter>();
			DestroyOnTimer component2 = obj.GetComponent<DestroyOnTimer>();
			obj.transform.position = position;
			component.wave = wave;
			component.duration = duration;
			component.radius = radius;
			component.amplitudeTimeDecay = amplitudeTimeDecay;
			component2.duration = duration;
			return component;
		}

		private void OnDrawGizmosSelected()
		{
			UnityEngine.Matrix4x4 matrix = Gizmos.matrix;
			UnityEngine.Color color = Gizmos.color;
			Gizmos.matrix = UnityEngine.Matrix4x4.TRS(base.transform.position, base.transform.rotation, UnityEngine.Vector3.one);
			Gizmos.color = UnityEngine.Color.yellow;
			Gizmos.DrawWireSphere(UnityEngine.Vector3.zero, radius);
			Gizmos.color = color;
			Gizmos.matrix = matrix;
		}
	}
	public class ShopTerminalBehavior : NetworkBehaviour, IInspectInfoProvider, IHasInspectHintOverride
	{
		[SyncVar(hook = "OnSyncPickupIndex")]
		private PickupIndex pickupIndex = PickupIndex.none;

		[SyncVar(hook = "OnSyncHidden")]
		private bool hidden;

		[SyncVar(hook = "SetHasBeenPurchased")]
		private bool hasBeenPurchased;

		[Tooltip("The PickupDisplay component that should show which item this shop terminal is offering.")]
		public PickupDisplay pickupDisplay;

		[Tooltip("The position from which the drop will be emitted")]
		public Transform dropTransform;

		[Tooltip("The drop table to select a pickup index from - only works if the pickup generates itself")]
		public PickupDropTable dropTable;

		[Tooltip("The velocity with which the drop will be emitted. Rotates with this object.")]
		public UnityEngine.Vector3 dropVelocity;

		public Animator animator;

		[Header("Inspect")]
		public InspectDef MysteryItemInspectDef;

		[Tooltip("Set this to a non-empty token to override the default Inspect hint on the HUD.")]
		public string inspectHintOverrideToken;

		[Tooltip("If the hint token's localization wants to have an item inserted at {0}, this must be set.")]
		public bool hintWantsItemFormatting;

		[Tooltip("Determines if purchasing disables inspection")]
		public bool disablesInspectionOnPurchase = true;

		[Tooltip("Whether or not to inspect shop itself or item in the shop")]
		public bool inspectShop;

		[Tooltip("If inspectShop is true, assign overriding InspectDef to inspect")]
		public InspectDef shopInspectDef;

		private IInspectInfoProvider[] cachedInspectInfoProviders;

		[Tooltip("The tier of items to drop - only works if the pickup generates itself and the dropTable field is empty.")]
		[Header("Deprecated")]
		public ItemTier itemTier;

		public ItemTag bannedItemTag;

		[Tooltip("Whether or not the shop terminal should drive itself")]
		public bool selfGeneratePickup = true;

		private Xoroshiro128Plus rng;

		private bool hasStarted;

		[NonSerialized]
		public MultiShopController serverMultiShopController;

		public bool pickupIndexIsHidden => hidden;

		public PickupIndex NetworkpickupIndex
		{
			get
			{
				return pickupIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncPickupIndex(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref pickupIndex, 1u);
			}
		}

		public bool Networkhidden
		{
			get
			{
				return hidden;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncHidden(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref hidden, 2u);
			}
		}

		public bool NetworkhasBeenPurchased
		{
			get
			{
				return hasBeenPurchased;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetHasBeenPurchased(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref hasBeenPurchased, 4u);
			}
		}

		public void SetHasBeenPurchased(bool newHasBeenPurchased)
		{
			if (hasBeenPurchased != newHasBeenPurchased)
			{
				NetworkhasBeenPurchased = newHasBeenPurchased;
			}
		}

		private void OnSyncHidden(bool newHidden)
		{
			SetPickupIndex(pickupIndex, newHidden);
		}

		private void OnSyncPickupIndex(PickupIndex newPickupIndex)
		{
			SetPickupIndex(newPickupIndex, hidden);
			if (NetworkClient.active)
			{
				UpdatePickupDisplayAndAnimations();
			}
		}

		public void Start()
		{
			hasStarted = true;
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
				if (selfGeneratePickup)
				{
					GenerateNewPickupServer();
				}
			}
			if (NetworkClient.active)
			{
				UpdatePickupDisplayAndAnimations();
			}
		}

		[Server]
		public void GenerateNewPickupServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShopTerminalBehavior::GenerateNewPickupServer()' called on client");
			}
			else
			{
				GenerateNewPickupServer(hidden);
			}
		}

		[Server]
		public void GenerateNewPickupServer(bool newHidden)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShopTerminalBehavior::GenerateNewPickupServer(System.Boolean)' called on client");
			}
			else if (!hasBeenPurchased)
			{
				PickupIndex none = PickupIndex.none;
				if ((bool)dropTable)
				{
					none = dropTable.GenerateDrop(rng);
				}
				else
				{
					List<PickupIndex> list2 = null;
					none = Pick(itemTier switch
					{
						ItemTier.Tier1 => Run.instance.availableTier1DropList, 
						ItemTier.Tier2 => Run.instance.availableTier2DropList, 
						ItemTier.Tier3 => Run.instance.availableTier3DropList, 
						ItemTier.Lunar => Run.instance.availableLunarCombinedDropList, 
						ItemTier.Boss => Run.instance.availableBossDropList, 
						ItemTier.VoidTier1 => Run.instance.availableVoidTier1DropList, 
						ItemTier.VoidTier2 => Run.instance.availableVoidTier2DropList, 
						ItemTier.VoidTier3 => Run.instance.availableVoidTier3DropList, 
						ItemTier.VoidBoss => Run.instance.availableVoidBossDropList, 
						_ => throw new ArgumentOutOfRangeException(), 
					});
				}
				SetPickupIndex(none, newHidden);
			}
			bool PassesFilter(PickupIndex pickupIndex)
			{
				if (bannedItemTag == ItemTag.Any)
				{
					return true;
				}
				PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
				if (pickupDef.itemIndex != ItemIndex.None)
				{
					return !ItemCatalog.GetItemDef(pickupDef.itemIndex).ContainsTag(bannedItemTag);
				}
				return true;
			}
			PickupIndex Pick(List<PickupIndex> list)
			{
				return rng.NextElementUniform(list.Where(PassesFilter).ToList());
			}
		}

		public void SetPickupIndex(PickupIndex newPickupIndex, bool newHidden = false)
		{
			if (pickupIndex != newPickupIndex || hidden != newHidden)
			{
				NetworkpickupIndex = newPickupIndex;
				Networkhidden = newHidden;
			}
		}

		public void SetHidden(bool newHidden)
		{
			SetPickupIndex(pickupIndex, newHidden);
		}

		private void UpdatePickupDisplayAndAnimations()
		{
			if ((bool)pickupDisplay)
			{
				pickupDisplay.SetPickupIndex(pickupIndex, hidden);
			}
			if (!hasStarted)
			{
				return;
			}
			if (pickupIndex == PickupIndex.none)
			{
				Util.PlaySound("Play_UI_tripleChestShutter", base.gameObject);
				if ((bool)animator)
				{
					int layerIndex = animator.GetLayerIndex("Body");
					animator.PlayInFixedTime(hasBeenPurchased ? "Open" : "Closing", layerIndex);
				}
			}
			else if ((bool)animator && !hasBeenPurchased)
			{
				int layerIndex2 = animator.GetLayerIndex("Body");
				animator.PlayInFixedTime("Idle", layerIndex2);
			}
		}

		public PickupIndex CurrentPickupIndex()
		{
			return pickupIndex;
		}

		[Server]
		public void SetNoPickup()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShopTerminalBehavior::SetNoPickup()' called on client");
			}
			else
			{
				SetPickupIndex(PickupIndex.none);
			}
		}

		[Server]
		public void DropPickup()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShopTerminalBehavior::DropPickup()' called on client");
				return;
			}
			SetHasBeenPurchased(newHasBeenPurchased: true);
			PickupDropletController.CreatePickupDroplet(pickupIndex, (dropTransform ? dropTransform : base.transform).position, base.transform.TransformVector(dropVelocity));
		}

		public bool CanBeInspected()
		{
			if ((!hasBeenPurchased || !disablesInspectionOnPurchase) && pickupIndex != PickupIndex.none)
			{
				return pickupIndex.isValid;
			}
			return false;
		}

		public InspectInfo GetInfo()
		{
			if (inspectShop && (bool)shopInspectDef)
			{
				return shopInspectDef;
			}
			if (pickupIndexIsHidden)
			{
				return MysteryItemInspectDef;
			}
			return PickupCatalog.GetPickupDef(CurrentPickupIndex()) ?? throw new InvalidOperationException("Attempted to get info for invalid pickup in shop terminal. Should be impossible. Please investigate.");
		}

		public bool GetInspectHintOverride(out string hintOverride)
		{
			if (inspectHintOverrideToken.Length > 0)
			{
				if (hintWantsItemFormatting)
				{
					string @string = Language.GetString(GetInfo().TitleToken);
					hintOverride = Language.GetStringFormatted(inspectHintOverrideToken, @string);
				}
				else
				{
					hintOverride = Language.GetString(inspectHintOverrideToken);
				}
				return true;
			}
			hintOverride = null;
			return false;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
				writer.Write(hidden);
				writer.Write(hasBeenPurchased);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(hidden);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(hasBeenPurchased);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				hidden = reader.ReadBoolean();
				hasBeenPurchased = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncPickupIndex(GeneratedNetworkCode._ReadPickupIndex_None(reader));
			}
			if (((uint)num & 2u) != 0)
			{
				OnSyncHidden(reader.ReadBoolean());
			}
			if (((uint)num & 4u) != 0)
			{
				SetHasBeenPurchased(reader.ReadBoolean());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class ShrineBehavior : NetworkBehaviour
	{
		private static int kRpcRpcSetPingable;

		[ClientRpc]
		protected virtual void RpcSetPingable(bool value)
		{
			NetworkIdentity component = GetComponent<NetworkIdentity>();
			if ((bool)component)
			{
				component.isPingable = value;
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcSetPingable(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetPingable called on server.");
			}
			else
			{
				((ShrineBehavior)obj).RpcSetPingable(reader.ReadBoolean());
			}
		}

		public void CallRpcSetPingable(bool value)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetPingable called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetPingable);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(value);
			SendRPCInternal(networkWriter, 0, "RpcSetPingable");
		}

		static ShrineBehavior()
		{
			kRpcRpcSetPingable = 85555619;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ShrineBehavior), kRpcRpcSetPingable, InvokeRpcRpcSetPingable);
			NetworkCRC.RegisterBehaviour("ShrineBehavior", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class ShrineBloodBehavior : ShrineBehavior
	{
		public int maxPurchaseCount;

		public float goldToPaidHpRatio = 0.5f;

		public float costMultiplierPerPurchase;

		public Transform symbolTransform;

		private PurchaseInteraction purchaseInteraction;

		private int purchaseCount;

		private float refreshTimer;

		private const float refreshDuration = 2f;

		private bool waitingForRefresh;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		private void Start()
		{
			purchaseInteraction = GetComponent<PurchaseInteraction>();
		}

		public void FixedUpdate()
		{
			if (waitingForRefresh)
			{
				refreshTimer -= Time.fixedDeltaTime;
				if (refreshTimer <= 0f && purchaseCount < maxPurchaseCount)
				{
					purchaseInteraction.SetAvailable(newAvailable: true);
					purchaseInteraction.Networkcost = (int)(100f * (1f - Mathf.Pow(1f - (float)purchaseInteraction.cost / 100f, costMultiplierPerPurchase)));
					waitingForRefresh = false;
				}
			}
		}

		[Server]
		public void AddShrineStack(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineBloodBehavior::AddShrineStack(RoR2.Interactor)' called on client");
				return;
			}
			waitingForRefresh = true;
			CharacterBody component = interactor.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				uint num = (uint)(component.healthComponent.fullCombinedHealth * (float)purchaseInteraction.cost / 100f * goldToPaidHpRatio);
				if ((bool)component.master)
				{
					if (component.inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock) > 0)
					{
						component.master.GiveExperience((ulong)((float)num * 2f));
					}
					else
					{
						component.master.GiveMoney(num);
					}
					Chat.SubjectFormatChatMessage subjectFormatChatMessage = new Chat.SubjectFormatChatMessage();
					subjectFormatChatMessage.subjectAsCharacterBody = component;
					subjectFormatChatMessage.baseToken = "SHRINE_BLOOD_USE_MESSAGE";
					subjectFormatChatMessage.paramTokens = new string[1] { num.ToString() };
					Chat.SendBroadcastChat(subjectFormatChatMessage);
				}
			}
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
			{
				origin = base.transform.position,
				rotation = UnityEngine.Quaternion.identity,
				scale = 1f,
				color = UnityEngine.Color.red
			}, transmit: true);
			purchaseCount++;
			refreshTimer = 2f;
			if (purchaseCount >= maxPurchaseCount)
			{
				symbolTransform.gameObject.SetActive(value: false);
				CallRpcSetPingable(value: false);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class ShrineBossBehavior : ShrineBehavior
	{
		public int maxPurchaseCount;

		public float costMultiplierPerPurchase;

		public Transform symbolTransform;

		private PurchaseInteraction purchaseInteraction;

		private int purchaseCount;

		private float refreshTimer;

		private const float refreshDuration = 2f;

		private bool waitingForRefresh;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		private void Start()
		{
			purchaseInteraction = GetComponent<PurchaseInteraction>();
		}

		public void FixedUpdate()
		{
			if (waitingForRefresh)
			{
				refreshTimer -= Time.fixedDeltaTime;
				if (refreshTimer <= 0f && purchaseCount < maxPurchaseCount)
				{
					purchaseInteraction.SetAvailable(newAvailable: true);
					purchaseInteraction.Networkcost = (int)((float)purchaseInteraction.cost * costMultiplierPerPurchase);
					waitingForRefresh = false;
				}
			}
		}

		[Server]
		public void AddShrineStack(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineBossBehavior::AddShrineStack(RoR2.Interactor)' called on client");
				return;
			}
			waitingForRefresh = true;
			if ((bool)TeleporterInteraction.instance)
			{
				TeleporterInteraction.instance.AddShrineStack();
			}
			CharacterBody component = interactor.GetComponent<CharacterBody>();
			Chat.SendBroadcastChat(new Chat.SubjectFormatChatMessage
			{
				subjectAsCharacterBody = component,
				baseToken = "SHRINE_BOSS_USE_MESSAGE"
			});
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
			{
				origin = base.transform.position,
				rotation = UnityEngine.Quaternion.identity,
				scale = 1f,
				color = new UnityEngine.Color(0.7372549f, 77f / 85f, 0.94509804f)
			}, transmit: true);
			purchaseCount++;
			refreshTimer = 2f;
			if (purchaseCount >= maxPurchaseCount)
			{
				symbolTransform.gameObject.SetActive(value: false);
				CallRpcSetPingable(value: false);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class ShrineChanceBehavior : ShrineBehavior
	{
		public int maxPurchaseCount;

		public float costMultiplierPerPurchase;

		public float failureChance;

		public PickupDropTable dropTable;

		public PickupDropTable chanceDollDropTable;

		public Transform symbolTransform;

		public Transform dropletOrigin;

		public GameObject effectPrefabShrineRewardJackpot;

		public GameObject effectPrefabShrineRewardNormal;

		[FormerlySerializedAs("shrineColor")]
		public UnityEngine.Color colorShrineRewardNormal;

		[FormerlySerializedAs("chanceDollSuccessColor")]
		public UnityEngine.Color colorShrineRewardJackpot;

		private UnityEngine.Color colorToEmit;

		private bool chanceDollWin;

		private PurchaseInteraction purchaseInteraction;

		private int successfulPurchaseCount;

		private float refreshTimer;

		private const float refreshDuration = 2f;

		private bool waitingForRefresh;

		private Xoroshiro128Plus rng;

		public Transform firstDropletOrigin;

		public Transform secondDropletOrigin;

		[Header("Deprecated")]
		public float failureWeight;

		public float equipmentWeight;

		public float tier1Weight;

		public float tier2Weight;

		public float tier3Weight;

		public static event Action<bool, Interactor> onShrineChancePurchaseGlobal;

		private void Awake()
		{
			purchaseInteraction = GetComponent<PurchaseInteraction>();
		}

		public void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			}
		}

		public void FixedUpdate()
		{
			if (waitingForRefresh)
			{
				refreshTimer -= Time.fixedDeltaTime;
				if (refreshTimer <= 0f && successfulPurchaseCount < maxPurchaseCount)
				{
					purchaseInteraction.SetAvailable(newAvailable: true);
					purchaseInteraction.Networkcost = (int)((float)purchaseInteraction.cost * costMultiplierPerPurchase);
					waitingForRefresh = false;
				}
			}
		}

		[Server]
		public void AddShrineStack(Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineChanceBehavior::AddShrineStack(RoR2.Interactor)' called on client");
				return;
			}
			PickupIndex pickupIndex = PickupIndex.none;
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if (component == null)
			{
				return;
			}
			Inventory inventory = component.inventory;
			if (inventory == null)
			{
				return;
			}
			if ((bool)dropTable)
			{
				if (rng.nextNormalizedFloat > failureChance)
				{
					if ((bool)chanceDollDropTable && inventory.GetItemCount(DLC2Content.Items.ExtraShrineItem) > 0)
					{
						int itemCount = inventory.GetItemCount(DLC2Content.Items.ExtraShrineItem);
						if (Util.CheckRoll(30 + itemCount * 10, component.master))
						{
							pickupIndex = chanceDollDropTable.GenerateDrop(rng);
							chanceDollWin = true;
						}
						else
						{
							pickupIndex = dropTable.GenerateDrop(rng);
							chanceDollWin = false;
						}
					}
					else
					{
						pickupIndex = dropTable.GenerateDrop(rng);
						chanceDollWin = false;
					}
				}
				else
				{
					chanceDollWin = false;
				}
			}
			else
			{
				PickupIndex none = PickupIndex.none;
				PickupIndex value = rng.NextElementUniform(Run.instance.availableTier1DropList);
				PickupIndex value2 = rng.NextElementUniform(Run.instance.availableTier2DropList);
				PickupIndex value3 = rng.NextElementUniform(Run.instance.availableTier3DropList);
				PickupIndex value4 = rng.NextElementUniform(Run.instance.availableEquipmentDropList);
				WeightedSelection<PickupIndex> weightedSelection = new WeightedSelection<PickupIndex>();
				weightedSelection.AddChoice(none, failureWeight);
				weightedSelection.AddChoice(value, tier1Weight);
				weightedSelection.AddChoice(value2, tier2Weight);
				weightedSelection.AddChoice(value3, tier3Weight);
				weightedSelection.AddChoice(value4, equipmentWeight);
				pickupIndex = weightedSelection.Evaluate(rng.nextNormalizedFloat);
			}
			bool flag = pickupIndex == PickupIndex.none;
			string baseToken;
			if (flag)
			{
				baseToken = "SHRINE_CHANCE_FAIL_MESSAGE";
			}
			else
			{
				baseToken = "SHRINE_CHANCE_SUCCESS_MESSAGE";
				successfulPurchaseCount++;
				PickupDropletController.CreatePickupDroplet(pickupIndex, dropletOrigin.position, dropletOrigin.forward * 20f);
			}
			Chat.SendBroadcastChat(new Chat.SubjectFormatChatMessage
			{
				subjectAsCharacterBody = component,
				baseToken = baseToken
			});
			ShrineChanceBehavior.onShrineChancePurchaseGlobal?.Invoke(flag, activator);
			waitingForRefresh = true;
			refreshTimer = 2f;
			if (chanceDollWin)
			{
				EffectManager.SpawnEffect(effectPrefabShrineRewardJackpot, new EffectData
				{
					origin = base.transform.position,
					rotation = UnityEngine.Quaternion.identity,
					scale = 1f,
					color = colorShrineRewardJackpot
				}, transmit: true);
			}
			else
			{
				EffectManager.SpawnEffect(effectPrefabShrineRewardNormal, new EffectData
				{
					origin = base.transform.position,
					rotation = UnityEngine.Quaternion.identity,
					scale = 1f,
					color = colorShrineRewardNormal
				}, transmit: true);
			}
			if (successfulPurchaseCount >= maxPurchaseCount)
			{
				symbolTransform.gameObject.SetActive(value: false);
				CallRpcSetPingable(value: false);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class ShrineCleanseBehavior : MonoBehaviour, IInteractable
	{
		public string contextToken;

		public GameObject activationEffectPrefab;

		private static ItemIndex[] cleansableItems = Array.Empty<ItemIndex>();

		private static EquipmentIndex[] cleansableEquipments = Array.Empty<EquipmentIndex>();

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextToken);
		}

		private static bool InventoryIsCleansable(Inventory inventory)
		{
			for (int i = 0; i < cleansableItems.Length; i++)
			{
				if (inventory.GetItemCount(cleansableItems[i]) > 0)
				{
					return true;
				}
			}
			int j = 0;
			for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++)
			{
				EquipmentState equipment = inventory.GetEquipment((uint)j);
				for (int k = 0; k < cleansableEquipments.Length; k++)
				{
					if (equipment.equipmentIndex == cleansableEquipments[k])
					{
						return true;
					}
				}
			}
			return false;
		}

		private static int CleanseInventoryServer(Inventory inventory)
		{
			int num = 0;
			for (int i = 0; i < cleansableItems.Length; i++)
			{
				ItemIndex itemIndex = cleansableItems[i];
				int itemCount = inventory.GetItemCount(itemIndex);
				if (itemCount != 0)
				{
					inventory.RemoveItem(itemIndex, itemCount);
					num += itemCount;
				}
			}
			int num2 = 0;
			int j = 0;
			for (int equipmentSlotCount = inventory.GetEquipmentSlotCount(); j < equipmentSlotCount; j++)
			{
				EquipmentState equipment = inventory.GetEquipment((uint)j);
				for (int k = 0; k < cleansableEquipments.Length; k++)
				{
					if (equipment.equipmentIndex == cleansableEquipments[k])
					{
						inventory.SetEquipment(EquipmentState.empty, (uint)j);
						num2++;
					}
				}
			}
			return num + num2;
		}

		public Interactability GetInteractability(Interactor activator)
		{
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				Inventory inventory = component.inventory;
				if ((bool)inventory && InventoryIsCleansable(inventory))
				{
					return Interactability.Available;
				}
			}
			return Interactability.ConditionsNotMet;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				Inventory inventory = component.inventory;
				if ((bool)inventory)
				{
					CleanseInventoryServer(inventory);
					EffectManager.SimpleEffect(activationEffectPrefab, base.transform.position, base.transform.rotation, transmit: true);
				}
			}
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public bool ShouldShowOnScanner()
		{
			return true;
		}

		public bool ShouldProximityHighlight()
		{
			return true;
		}

		[SystemInitializer(new Type[]
		{
			typeof(ItemCatalog),
			typeof(EquipmentCatalog)
		})]
		private static void Init()
		{
			List<ItemIndex> list = new List<ItemIndex>();
			List<EquipmentIndex> list2 = new List<EquipmentIndex>();
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
				if (itemDef.tier == ItemTier.Lunar || itemDef.ContainsTag(ItemTag.Cleansable))
				{
					list.Add(itemIndex);
				}
			}
			EquipmentIndex equipmentIndex = (EquipmentIndex)0;
			for (EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; equipmentIndex < equipmentCount; equipmentIndex++)
			{
				if (EquipmentCatalog.GetEquipmentDef(equipmentIndex).isLunar)
				{
					list2.Add(equipmentIndex);
				}
			}
			cleansableItems = list.ToArray();
			cleansableEquipments = list2.ToArray();
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public sealed class ShrineColossusAccessBehavior : ShrineBehavior
	{
		[SerializeField]
		private PurchaseInteraction purchaseInteraction;

		private GameObject playerRespawnEffectPrefab;

		private CharacterBody body;

		[SerializeField]
		private Transform symbolTransform;

		private static int kRpcRpcUpdateInteractionClients;

		[Server]
		public void OnInteraction(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineColossusAccessBehavior::OnInteraction(RoR2.Interactor)' called on client");
				return;
			}
			body = interactor.GetComponent<CharacterBody>();
			if ((bool)body && (bool)body.master.playerCharacterMasterController)
			{
				foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
				{
					CharacterBody characterBody = instance.master.GetBody();
					if ((bool)characterBody && characterBody != body)
					{
						int newCount = purchaseInteraction.cost / 10;
						instance.master.GetBody().SetBuffCount(DLC2Content.Buffs.SoulCost.buffIndex, newCount);
					}
				}
			}
			ReviveAlliedPlayers();
			CallRpcSetPingable(value: false);
			CallRpcUpdateInteractionClients();
		}

		[ClientRpc]
		private void RpcUpdateInteractionClients()
		{
			Util.PlaySound("Play_obj_portalShaping_activate", base.gameObject);
			symbolTransform.gameObject.SetActive(value: false);
		}

		[Server]
		private void ReviveAlliedPlayers()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineColossusAccessBehavior::ReviveAlliedPlayers()' called on client");
				return;
			}
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				CharacterMaster master = instance.master;
				if (instance.isConnected && master.IsDeadAndOutOfLivesServer())
				{
					NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
					List<NodeGraph.NodeIndex> source = nodeGraph.FindNodesInRange(base.gameObject.transform.position, 10f, 30f, HullMask.Human);
					UnityEngine.Vector3 position = default(UnityEngine.Vector3);
					nodeGraph.GetNodePosition(source.First(), out position);
					master.Respawn(position, UnityEngine.Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f), wasRevivedMidStage: true);
					CharacterBody characterBody = master.GetBody();
					if ((bool)characterBody)
					{
						characterBody.AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
						EntityStateMachine[] components = characterBody.GetComponents<EntityStateMachine>();
						foreach (EntityStateMachine obj in components)
						{
							obj.initialStateType = obj.mainStateType;
						}
					}
				}
				else if (instance.isConnected && !master.IsDeadAndOutOfLivesServer() && master.GetBody().healthComponent.alive)
				{
					master.GetBody().AddTimedBuff(RoR2Content.Buffs.Immune, 3f);
					master.GetBody().AddBuff(DLC2Content.Buffs.ExtraLifeBuff);
				}
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcUpdateInteractionClients(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcUpdateInteractionClients called on server.");
			}
			else
			{
				((ShrineColossusAccessBehavior)obj).RpcUpdateInteractionClients();
			}
		}

		public void CallRpcUpdateInteractionClients()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcUpdateInteractionClients called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcUpdateInteractionClients);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcUpdateInteractionClients");
		}

		static ShrineColossusAccessBehavior()
		{
			kRpcRpcUpdateInteractionClients = -248324325;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ShrineColossusAccessBehavior), kRpcRpcUpdateInteractionClients, InvokeRpcRpcUpdateInteractionClients);
			NetworkCRC.RegisterBehaviour("ShrineColossusAccessBehavior", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[RequireComponent(typeof(CombatDirector))]
	[RequireComponent(typeof(CombatSquad))]
	[RequireComponent(typeof(PurchaseInteraction))]
	public class ShrineCombatBehavior : ShrineBehavior
	{
		public UnityEngine.Color shrineEffectColor;

		public int maxPurchaseCount;

		public int baseMonsterCredit;

		public float monsterCreditCoefficientPerPurchase;

		public Transform symbolTransform;

		public GameObject spawnPositionEffectPrefab;

		private CombatDirector combatDirector;

		private PurchaseInteraction purchaseInteraction;

		private int purchaseCount;

		private float refreshTimer;

		private const float refreshDuration = 2f;

		private bool waitingForRefresh;

		private DirectorCard chosenDirectorCard;

		private float monsterCredit => (float)baseMonsterCredit * Stage.instance.entryDifficultyCoefficient * (1f + (float)purchaseCount * (monsterCreditCoefficientPerPurchase - 1f));

		public static event Action<ShrineCombatBehavior> onDefeatedServerGlobal;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		private void Awake()
		{
			if (NetworkServer.active)
			{
				purchaseInteraction = GetComponent<PurchaseInteraction>();
				combatDirector = GetComponent<CombatDirector>();
				combatDirector.combatSquad.onDefeatedServer += OnDefeatedServer;
			}
		}

		private void OnDefeatedServer()
		{
			ShrineCombatBehavior.onDefeatedServerGlobal?.Invoke(this);
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				chosenDirectorCard = combatDirector.SelectMonsterCardForCombatShrine(monsterCredit);
				if (chosenDirectorCard == null)
				{
					purchaseInteraction.SetAvailable(newAvailable: false);
				}
			}
		}

		public void FixedUpdate()
		{
			if (waitingForRefresh)
			{
				refreshTimer -= Time.fixedDeltaTime;
				if (refreshTimer <= 0f && purchaseCount < maxPurchaseCount)
				{
					purchaseInteraction.SetAvailable(newAvailable: true);
					waitingForRefresh = false;
				}
			}
		}

		[Server]
		public void AddShrineStack(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineCombatBehavior::AddShrineStack(RoR2.Interactor)' called on client");
				return;
			}
			waitingForRefresh = true;
			combatDirector.CombatShrineActivation(interactor, monsterCredit, chosenDirectorCard);
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
			{
				origin = base.transform.position,
				rotation = UnityEngine.Quaternion.identity,
				scale = 1f,
				color = shrineEffectColor
			}, transmit: true);
			purchaseCount++;
			refreshTimer = 2f;
			if (purchaseCount >= maxPurchaseCount)
			{
				symbolTransform.gameObject.SetActive(value: false);
				CallRpcSetPingable(value: false);
			}
		}

		private void OnValidate()
		{
			if (!GetComponent<CombatDirector>().combatSquad)
			{
				UnityEngine.Debug.LogError("ShrineCombatBehavior's sibling CombatDirector must use a CombatSquad.", base.gameObject);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class ShrineHealingBehavior : ShrineBehavior
	{
		public GameObject wardPrefab;

		private GameObject wardInstance;

		public float baseRadius;

		public float radiusBonusPerPurchase;

		public int maxPurchaseCount;

		public float costMultiplierPerPurchase;

		public Transform symbolTransform;

		private PurchaseInteraction purchaseInteraction;

		private float refreshTimer;

		private const float refreshDuration = 2f;

		private bool waitingForRefresh;

		private HealingWard healingWard;

		public int purchaseCount { get; private set; }

		public static event Action<ShrineHealingBehavior, Interactor> onActivated;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		private void Awake()
		{
			purchaseInteraction = GetComponent<PurchaseInteraction>();
		}

		public void FixedUpdate()
		{
			if (waitingForRefresh)
			{
				refreshTimer -= Time.fixedDeltaTime;
				if (refreshTimer <= 0f && purchaseCount < maxPurchaseCount)
				{
					purchaseInteraction.SetAvailable(newAvailable: true);
					purchaseInteraction.Networkcost = (int)((float)purchaseInteraction.cost * costMultiplierPerPurchase);
					waitingForRefresh = false;
				}
			}
		}

		[Server]
		private void SetWardEnabled(bool enableWard)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineHealingBehavior::SetWardEnabled(System.Boolean)' called on client");
			}
			else if (enableWard != (bool)wardInstance)
			{
				if (enableWard)
				{
					wardInstance = UnityEngine.Object.Instantiate(wardPrefab, base.transform.position, base.transform.rotation);
					wardInstance.GetComponent<TeamFilter>().teamIndex = TeamIndex.Player;
					healingWard = wardInstance.GetComponent<HealingWard>();
					NetworkServer.Spawn(wardInstance);
				}
				else
				{
					UnityEngine.Object.Destroy(wardInstance);
					wardInstance = null;
					healingWard = null;
				}
			}
		}

		[Server]
		public void AddShrineStack(Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineHealingBehavior::AddShrineStack(RoR2.Interactor)' called on client");
				return;
			}
			SetWardEnabled(enableWard: true);
			Chat.SendBroadcastChat(new Chat.SubjectFormatChatMessage
			{
				subjectAsCharacterBody = activator.gameObject.GetComponent<CharacterBody>(),
				baseToken = "SHRINE_HEALING_USE_MESSAGE"
			});
			waitingForRefresh = true;
			purchaseCount++;
			float networkradius = baseRadius + radiusBonusPerPurchase * (float)(purchaseCount - 1);
			healingWard.Networkradius = networkradius;
			refreshTimer = 2f;
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
			{
				origin = base.transform.position,
				rotation = UnityEngine.Quaternion.identity,
				scale = 1f,
				color = UnityEngine.Color.green
			}, transmit: true);
			if (purchaseCount >= maxPurchaseCount)
			{
				symbolTransform.gameObject.SetActive(value: false);
				CallRpcSetPingable(value: false);
			}
			ShrineHealingBehavior.onActivated?.Invoke(this, activator);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class ShrineRestackBehavior : ShrineBehavior
	{
		public int maxPurchaseCount;

		public float costMultiplierPerPurchase;

		public Transform symbolTransform;

		private PurchaseInteraction purchaseInteraction;

		private int purchaseCount;

		private float refreshTimer;

		private const float refreshDuration = 2f;

		private bool waitingForRefresh;

		private Xoroshiro128Plus rng;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		private void Start()
		{
			purchaseInteraction = GetComponent<PurchaseInteraction>();
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong);
			}
		}

		public void FixedUpdate()
		{
			if (waitingForRefresh)
			{
				refreshTimer -= Time.fixedDeltaTime;
				if (refreshTimer <= 0f && purchaseCount < maxPurchaseCount)
				{
					purchaseInteraction.SetAvailable(newAvailable: true);
					purchaseInteraction.Networkcost = (int)((float)purchaseInteraction.cost * costMultiplierPerPurchase);
					waitingForRefresh = false;
				}
			}
		}

		[Server]
		public void AddShrineStack(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineRestackBehavior::AddShrineStack(RoR2.Interactor)' called on client");
				return;
			}
			waitingForRefresh = true;
			CharacterBody component = interactor.GetComponent<CharacterBody>();
			if ((bool)component && (bool)component.master)
			{
				Inventory inventory = component.master.inventory;
				if ((bool)inventory)
				{
					inventory.ShrineRestackInventory(rng);
					Chat.SendBroadcastChat(new Chat.SubjectFormatChatMessage
					{
						subjectAsCharacterBody = component,
						baseToken = "SHRINE_RESTACK_USE_MESSAGE"
					});
				}
			}
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
			{
				origin = base.transform.position,
				rotation = UnityEngine.Quaternion.identity,
				scale = 1f,
				color = new UnityEngine.Color(1f, 0.23f, 0.6337214f)
			}, transmit: true);
			purchaseCount++;
			refreshTimer = 2f;
			if (purchaseCount >= maxPurchaseCount)
			{
				symbolTransform.gameObject.SetActive(value: false);
				CallRpcSetPingable(value: false);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[DefaultExecutionOrder(99999)]
	public class SimpleLeash : MonoBehaviour
	{
		public float minLeashRadius = 1f;

		public float maxLeashRadius = 20f;

		public float maxFollowSpeed = 40f;

		public float smoothTime = 0.15f;

		private new Transform transform;

		[CanBeNull]
		private NetworkIdentity networkIdentity;

		private UnityEngine.Vector3 velocity = UnityEngine.Vector3.zero;

		private bool isNetworkControlled;

		public UnityEngine.Vector3 leashOrigin { get; set; }

		private void Awake()
		{
			transform = base.transform;
			networkIdentity = GetComponent<NetworkIdentity>();
		}

		private void OnEnable()
		{
			leashOrigin = transform.position;
		}

		private void LateUpdate()
		{
			isNetworkControlled = (object)networkIdentity != null && !Util.HasEffectiveAuthority(networkIdentity);
			if (!isNetworkControlled)
			{
				Simulate(Time.deltaTime);
			}
		}

		private void Simulate(float deltaTime)
		{
			UnityEngine.Vector3 position = transform.position;
			UnityEngine.Vector3 vector = leashOrigin;
			UnityEngine.Vector3 vector2 = position - vector;
			float sqrMagnitude = vector2.sqrMagnitude;
			if (sqrMagnitude > minLeashRadius * minLeashRadius)
			{
				float num = Mathf.Sqrt(sqrMagnitude);
				UnityEngine.Vector3 vector3 = vector2 / num;
				UnityEngine.Vector3 target = vector + vector3 * minLeashRadius;
				UnityEngine.Vector3 current = position;
				if (num > maxLeashRadius)
				{
					current = vector + vector3 * maxLeashRadius;
				}
				current = UnityEngine.Vector3.SmoothDamp(current, target, ref velocity, smoothTime, maxFollowSpeed, deltaTime);
				if (current != position)
				{
					transform.position = current;
				}
			}
		}
	}
	[DefaultExecutionOrder(99999)]
	public class SimpleRotateToDirection : MonoBehaviour
	{
		public float smoothTime;

		public float maxRotationSpeed;

		private new Transform transform;

		[CanBeNull]
		private NetworkIdentity networkIdentity;

		private float velocity;

		private bool isNetworkControlled;

		public UnityEngine.Quaternion targetRotation { get; set; }

		private void Awake()
		{
			transform = base.transform;
			networkIdentity = GetComponent<NetworkIdentity>();
		}

		private void OnEnable()
		{
			targetRotation = transform.rotation;
		}

		private void LateUpdate()
		{
			isNetworkControlled = (object)networkIdentity != null && !Util.HasEffectiveAuthority(networkIdentity);
			if (!isNetworkControlled)
			{
				Simulate(Time.deltaTime);
			}
		}

		private void Simulate(float deltaTime)
		{
			transform.rotation = Util.SmoothDampQuaternion(transform.rotation, targetRotation, ref velocity, smoothTime, maxRotationSpeed, deltaTime);
		}
	}
	public class SingleHighlight : MonoBehaviour
	{
	}
	[RequireComponent(typeof(NetworkedBodyAttachment))]
	public class SiphonNearbyController : NetworkBehaviour
	{
		[SyncVar]
		public float radius;

		public float damagePerSecondCoefficient;

		[UnityEngine.Min(float.Epsilon)]
		public float tickRate = 1f;

		[SyncVar]
		public int maxTargets;

		public TetherVfxOrigin tetherVfxOrigin;

		public GameObject activeVfx;

		protected new Transform transform;

		protected NetworkedBodyAttachment networkedBodyAttachment;

		protected SphereSearch sphereSearch;

		protected float timer;

		private bool isTetheredToAtLeastOneObject;

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 1u);
			}
		}

		public int NetworkmaxTargets
		{
			get
			{
				return maxTargets;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref maxTargets, 2u);
			}
		}

		protected void Awake()
		{
			transform = base.transform;
			networkedBodyAttachment = GetComponent<NetworkedBodyAttachment>();
			sphereSearch = new SphereSearch();
			timer = 0f;
		}

		protected void FixedUpdate()
		{
			timer -= Time.fixedDeltaTime;
			if (timer <= 0f)
			{
				timer += 1f / tickRate;
				Tick();
			}
		}

		protected void Tick()
		{
			if (!networkedBodyAttachment || !networkedBodyAttachment.attachedBody || !networkedBodyAttachment.attachedBodyObject)
			{
				return;
			}
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			if (!networkedBodyAttachment.attachedBody.outOfCombat)
			{
				SearchForTargets(list);
			}
			float damage = damagePerSecondCoefficient * networkedBodyAttachment.attachedBody.damage / tickRate;
			float num = 0f;
			List<Transform> list2 = CollectionPool<Transform, List<Transform>>.RentCollection();
			for (int i = 0; i < list.Count; i++)
			{
				HurtBox hurtBox = list[i];
				if ((bool)hurtBox && (bool)hurtBox.healthComponent && hurtBox.healthComponent.alive)
				{
					HealthComponent healthComponent = hurtBox.healthComponent;
					if (hurtBox.healthComponent.body == networkedBodyAttachment.attachedBody)
					{
						continue;
					}
					Transform transform = healthComponent.body?.coreTransform ?? hurtBox.transform;
					list2.Add(transform);
					if (NetworkServer.active)
					{
						float combinedHealth = healthComponent.combinedHealth;
						DamageInfo damageInfo = new DamageInfo();
						damageInfo.attacker = networkedBodyAttachment.attachedBodyObject;
						damageInfo.inflictor = base.gameObject;
						damageInfo.position = transform.position;
						damageInfo.crit = networkedBodyAttachment.attachedBody.RollCrit();
						damageInfo.damage = damage;
						damageInfo.damageColorIndex = DamageColorIndex.Item;
						damageInfo.force = UnityEngine.Vector3.zero;
						damageInfo.procCoefficient = 0f;
						damageInfo.damageType = DamageType.ClayGoo;
						damageInfo.procChainMask = default(ProcChainMask);
						healthComponent.TakeDamage(damageInfo);
						if (!damageInfo.rejected)
						{
							float num2 = Mathf.Max(healthComponent.combinedHealth, 0f);
							num += Mathf.Max(combinedHealth - num2);
						}
					}
				}
				if (list2.Count >= maxTargets)
				{
					break;
				}
			}
			isTetheredToAtLeastOneObject = (float)list2.Count > 0f;
			if (NetworkServer.active && num > 0f && (bool)networkedBodyAttachment.attachedBody.healthComponent)
			{
				networkedBodyAttachment.attachedBody.healthComponent.Heal(num, default(ProcChainMask));
			}
			if ((bool)tetherVfxOrigin)
			{
				tetherVfxOrigin.SetTetheredTransforms(list2);
			}
			if ((bool)activeVfx)
			{
				activeVfx.SetActive(isTetheredToAtLeastOneObject);
			}
			CollectionPool<Transform, List<Transform>>.ReturnCollection(list2);
			CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}

		protected void SearchForTargets(List<HurtBox> dest)
		{
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.origin = transform.position;
			sphereSearch.radius = radius + networkedBodyAttachment.attachedBody.radius;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(networkedBodyAttachment.attachedBody.teamComponent.teamIndex));
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			sphereSearch.GetHurtBoxes(dest);
			sphereSearch.ClearCandidates();
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(radius);
				writer.WritePackedUInt32((uint)maxTargets);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(radius);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)maxTargets);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				radius = reader.ReadSingle();
				maxTargets = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				radius = reader.ReadSingle();
			}
			if (((uint)num & 2u) != 0)
			{
				maxTargets = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(CharacterModel))]
	[RequireComponent(typeof(Animator))]
	public class SkateSparks : MonoBehaviour
	{
		[Serializable]
		private struct FootState
		{
			public float? speed;

			public UnityEngine.Vector3? position;

			public float stressAccumulator;

			public float emissionTimer;

			public float debugAcceleration;

			public float debugOverspeed;
		}

		public float maxStress = 4f;

		public float minStressForEmission = 1f;

		public float overspeedStressCoefficient = 1f;

		public float accelerationStressCoefficient = 1f;

		public float perpendicularTravelStressCoefficient = 1f;

		public float maxEmissionRate = 10f;

		public int landingStress = 4;

		public ParticleSystem leftParticleSystem;

		public ParticleSystem rightParticleSystem;

		private Animator animator;

		private Transform leftFoot;

		private Transform rightFoot;

		private CharacterModel characterModel;

		private static readonly int isGroundedParam = Animator.StringToHash("isGrounded");

		private bool previousIsGrounded = true;

		private FootState leftFootState;

		private FootState rightFootState;

		private float debugWalkSpeed;

		private void Awake()
		{
			animator = GetComponent<Animator>();
			characterModel = GetComponent<CharacterModel>();
			leftFoot = (leftParticleSystem ? leftParticleSystem.transform : null);
			rightFoot = (rightParticleSystem ? rightParticleSystem.transform : null);
		}

		private static void UpdateFoot(ref FootState footState, ParticleSystem particleSystem, Transform transform, float walkSpeed, float overspeedStressCoefficient, float accelerationStressCoefficient, float perpendicularTravelStressCoefficient, bool isGrounded, float maxStress, float minStressForEmission, float maxEmissionRate, float deltaTime)
		{
			UnityEngine.Vector3? position = (transform ? new UnityEngine.Vector3?(transform.position) : null);
			float? speed = null;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
			if (position.HasValue && footState.position.HasValue)
			{
				vector = position.Value - footState.position.Value;
				vector.y = 0f;
			}
			float magnitude = vector.magnitude;
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			if (deltaTime != 0f)
			{
				speed = magnitude / deltaTime;
				if (footState.speed.HasValue)
				{
					num = speed.Value - footState.speed.Value;
				}
				num2 = Mathf.Max(speed.Value - walkSpeed, 0f);
				if ((bool)transform && magnitude > 0f)
				{
					UnityEngine.Vector3 rhs = vector / magnitude;
					num3 = Mathf.Abs(UnityEngine.Vector3.Dot(transform.right, rhs)) * magnitude;
				}
				footState.stressAccumulator += num2 * overspeedStressCoefficient * deltaTime + num * accelerationStressCoefficient + num3 * perpendicularTravelStressCoefficient;
				footState.debugAcceleration = num;
				footState.debugOverspeed = num2;
			}
			if (!isGrounded)
			{
				footState.stressAccumulator = 0f;
			}
			footState.stressAccumulator = Mathf.Clamp(footState.stressAccumulator, 0f, maxStress);
			footState.emissionTimer -= deltaTime * maxEmissionRate;
			if (footState.emissionTimer <= 0f)
			{
				footState.emissionTimer = 1f;
				footState.stressAccumulator -= 1f;
				if (footState.stressAccumulator >= minStressForEmission && (bool)particleSystem)
				{
					particleSystem.Emit(1);
				}
			}
			footState.position = position;
			footState.speed = speed;
		}

		private void Update()
		{
			bool flag = false;
			float num = 0f;
			CharacterBody body = characterModel.body;
			if ((bool)body)
			{
				num = body.moveSpeed;
				if (body.isSprinting)
				{
					num /= body.sprintingSpeedMultiplier;
				}
				CharacterMotor characterMotor = body.characterMotor;
				if ((bool)characterMotor)
				{
					flag = characterMotor.isGrounded;
				}
			}
			if (flag != previousIsGrounded)
			{
				float num2 = landingStress;
				leftFootState.stressAccumulator += num2;
				rightFootState.stressAccumulator += num2;
			}
			float deltaTime = Time.deltaTime;
			UpdateFoot(ref leftFootState, leftParticleSystem, leftFoot, num, overspeedStressCoefficient, accelerationStressCoefficient, perpendicularTravelStressCoefficient, flag, maxStress, minStressForEmission, maxEmissionRate, deltaTime);
			UpdateFoot(ref rightFootState, rightParticleSystem, rightFoot, num, overspeedStressCoefficient, accelerationStressCoefficient, perpendicularTravelStressCoefficient, flag, maxStress, minStressForEmission, maxEmissionRate, deltaTime);
			debugWalkSpeed = num;
			previousIsGrounded = flag;
		}
	}
	[RequireComponent(typeof(NetworkIdentity))]
	public class SkillLocator : NetworkBehaviour
	{
		[Serializable]
		public struct PassiveSkill
		{
			public bool enabled;

			public string skillNameToken;

			public string skillDescriptionToken;

			public string keywordToken;

			public Sprite icon;
		}

		[FormerlySerializedAs("skill1")]
		public GenericSkill primary;

		[FormerlySerializedAs("skill2")]
		public GenericSkill secondary;

		[FormerlySerializedAs("skill3")]
		public GenericSkill utility;

		[FormerlySerializedAs("skill4")]
		public GenericSkill special;

		public PassiveSkill passiveSkill;

		[SerializeField]
		private GenericSkill primaryBonusStockOverrideSkill;

		[SerializeField]
		private GenericSkill secondaryBonusStockOverrideSkill;

		[SerializeField]
		private GenericSkill utilityBonusStockOverrideSkill;

		[SerializeField]
		private GenericSkill specialBonusStockOverrideSkill;

		private NetworkIdentity networkIdentity;

		private GenericSkill[] allSkills;

		private bool hasEffectiveAuthority;

		private uint skillDefDirtyFlags;

		private bool inDeserialize;

		private static int kRpcRpcDeductCooldownFromAllSkillsServer;

		public GenericSkill primaryBonusStockSkill
		{
			get
			{
				if (!primaryBonusStockOverrideSkill)
				{
					return primary;
				}
				return primaryBonusStockOverrideSkill;
			}
		}

		public GenericSkill secondaryBonusStockSkill
		{
			get
			{
				if (!secondaryBonusStockOverrideSkill)
				{
					return secondary;
				}
				return secondaryBonusStockOverrideSkill;
			}
		}

		public GenericSkill utilityBonusStockSkill
		{
			get
			{
				if (!utilityBonusStockOverrideSkill)
				{
					return utility;
				}
				return utilityBonusStockOverrideSkill;
			}
		}

		public GenericSkill specialBonusStockSkill
		{
			get
			{
				if (!specialBonusStockOverrideSkill)
				{
					return special;
				}
				return specialBonusStockOverrideSkill;
			}
		}

		public int skillSlotCount => allSkills.Length;

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			allSkills = GetComponents<GenericSkill>();
		}

		private void Start()
		{
			UpdateAuthority();
		}

		public override void OnStartAuthority()
		{
			base.OnStartAuthority();
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			base.OnStopAuthority();
			UpdateAuthority();
		}

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity);
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				for (int i = 0; i < allSkills.Length; i++)
				{
					GenericSkill genericSkill = allSkills[i];
					if (genericSkill.baseSkill != genericSkill.defaultSkillDef)
					{
						num |= (uint)(1 << i);
					}
				}
			}
			writer.WritePackedUInt32(num);
			for (int j = 0; j < allSkills.Length; j++)
			{
				if ((num & (uint)(1 << j)) != 0)
				{
					GenericSkill genericSkill2 = allSkills[j];
					writer.WritePackedUInt32((uint)((genericSkill2.baseSkill?.skillIndex ?? (-1)) + 1));
				}
			}
			return num != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			inDeserialize = true;
			uint num = reader.ReadPackedUInt32();
			for (int i = 0; i < allSkills.Length; i++)
			{
				if ((num & (uint)(1 << i)) != 0)
				{
					GenericSkill genericSkill = allSkills[i];
					SkillDef skillDef = SkillCatalog.GetSkillDef((int)(reader.ReadPackedUInt32() - 1));
					if (initialState || !hasEffectiveAuthority)
					{
						genericSkill.SetBaseSkill(skillDef);
					}
				}
			}
			inDeserialize = false;
		}

		public GenericSkill FindSkill(string skillName)
		{
			for (int i = 0; i < allSkills.Length; i++)
			{
				if (allSkills[i].skillName == skillName)
				{
					return allSkills[i];
				}
			}
			return null;
		}

		public GenericSkill FindSkillByFamilyName(string skillFamilyName)
		{
			for (int i = 0; i < allSkills.Length; i++)
			{
				if (SkillCatalog.GetSkillFamilyName(allSkills[i].skillFamily.catalogIndex) == skillFamilyName)
				{
					return allSkills[i];
				}
			}
			return null;
		}

		public GenericSkill FindSkillByDef(SkillDef skillDef)
		{
			for (int i = 0; i < allSkills.Length; i++)
			{
				if ((object)allSkills[i].skillDef == skillDef)
				{
					return allSkills[i];
				}
			}
			return null;
		}

		public GenericSkill GetSkill(SkillSlot skillSlot)
		{
			return skillSlot switch
			{
				SkillSlot.Primary => primary, 
				SkillSlot.Secondary => secondary, 
				SkillSlot.Utility => utility, 
				SkillSlot.Special => special, 
				_ => null, 
			};
		}

		public GenericSkill GetSkillAtIndex(int index)
		{
			return ArrayUtils.GetSafe(allSkills, index);
		}

		public int GetSkillSlotIndex(GenericSkill skillSlot)
		{
			return Array.IndexOf(allSkills, skillSlot);
		}

		public SkillSlot FindSkillSlot(GenericSkill skillComponent)
		{
			if (!skillComponent)
			{
				return SkillSlot.None;
			}
			if (skillComponent == primary)
			{
				return SkillSlot.Primary;
			}
			if (skillComponent == secondary)
			{
				return SkillSlot.Secondary;
			}
			if (skillComponent == utility)
			{
				return SkillSlot.Utility;
			}
			if (skillComponent == special)
			{
				return SkillSlot.Special;
			}
			return SkillSlot.None;
		}

		[Server]
		public void ApplyLoadoutServer(Loadout loadout, BodyIndex bodyIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SkillLocator::ApplyLoadoutServer(RoR2.Loadout,RoR2.BodyIndex)' called on client");
			}
			else
			{
				if (bodyIndex == BodyIndex.None)
				{
					return;
				}
				for (int i = 0; i < allSkills.Length; i++)
				{
					uint num = loadout.bodyLoadoutManager.GetSkillVariant(bodyIndex, i);
					GenericSkill obj = allSkills[i];
					SkillFamily.Variant[] variants = obj.skillFamily.variants;
					if (!ArrayUtils.IsInBounds(variants, num))
					{
						num = 0u;
					}
					obj.SetBaseSkill(variants[num].skillDef);
				}
			}
		}

		public void ResetSkills()
		{
			if (NetworkServer.active && networkIdentity.clientAuthorityOwner != null)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				networkWriter.StartMessage(56);
				networkWriter.Write(base.gameObject);
				networkWriter.FinishMessage();
				networkIdentity.clientAuthorityOwner.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
			}
			for (int i = 0; i < allSkills.Length; i++)
			{
				allSkills[i].Reset();
			}
		}

		public void ApplyAmmoPack()
		{
			if (NetworkServer.active && !networkIdentity.hasAuthority)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				networkWriter.StartMessage(63);
				networkWriter.Write(base.gameObject);
				networkWriter.FinishMessage();
				networkIdentity.clientAuthorityOwner?.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
				return;
			}
			GenericSkill[] array = allSkills;
			foreach (GenericSkill genericSkill in array)
			{
				if (genericSkill.CanApplyAmmoPack())
				{
					genericSkill.ApplyAmmoPack();
				}
			}
		}

		[NetworkMessageHandler(msgType = 56, client = true)]
		private static void HandleResetSkills(NetworkMessage netMsg)
		{
			GameObject gameObject = netMsg.reader.ReadGameObject();
			if (!NetworkServer.active && (bool)gameObject)
			{
				SkillLocator component = gameObject.GetComponent<SkillLocator>();
				if ((bool)component)
				{
					component.ResetSkills();
				}
			}
		}

		[NetworkMessageHandler(msgType = 63, client = true)]
		private static void HandleAmmoPackPickup(NetworkMessage netMsg)
		{
			GameObject gameObject = netMsg.reader.ReadGameObject();
			if (!NetworkServer.active && (bool)gameObject)
			{
				SkillLocator component = gameObject.GetComponent<SkillLocator>();
				if ((bool)component)
				{
					component.ApplyAmmoPack();
				}
			}
		}

		public void DeductCooldownFromAllSkillsServer(float deduction)
		{
			if (hasEffectiveAuthority)
			{
				DeductCooldownFromAllSkillsAuthority(deduction);
			}
			else
			{
				CallRpcDeductCooldownFromAllSkillsServer(deduction);
			}
		}

		[ClientRpc]
		private void RpcDeductCooldownFromAllSkillsServer(float deduction)
		{
			if (hasEffectiveAuthority)
			{
				DeductCooldownFromAllSkillsAuthority(deduction);
			}
		}

		private void DeductCooldownFromAllSkillsAuthority(float deduction)
		{
			for (int i = 0; i < allSkills.Length; i++)
			{
				GenericSkill genericSkill = allSkills[i];
				if (genericSkill.stock < genericSkill.maxStock)
				{
					genericSkill.rechargeStopwatch += deduction;
				}
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcDeductCooldownFromAllSkillsServer(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcDeductCooldownFromAllSkillsServer called on server.");
			}
			else
			{
				((SkillLocator)obj).RpcDeductCooldownFromAllSkillsServer(reader.ReadSingle());
			}
		}

		public void CallRpcDeductCooldownFromAllSkillsServer(float deduction)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcDeductCooldownFromAllSkillsServer called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcDeductCooldownFromAllSkillsServer);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(deduction);
			SendRPCInternal(networkWriter, 0, "RpcDeductCooldownFromAllSkillsServer");
		}

		static SkillLocator()
		{
			kRpcRpcDeductCooldownFromAllSkillsServer = -2090076365;
			NetworkBehaviour.RegisterRpcDelegate(typeof(SkillLocator), kRpcRpcDeductCooldownFromAllSkillsServer, InvokeRpcRpcDeductCooldownFromAllSkillsServer);
			NetworkCRC.RegisterBehaviour("SkillLocator", 0);
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(NetworkIdentity))]
	public class SkillReloader : MonoBehaviour
	{
		private NetworkIdentity networkIdentity;

		public GenericSkill skill;

		public EntityStateMachine stateMachine;

		public SerializableEntityStateType reloadState;

		public float reloadDelay = 0.2f;

		private float timer;

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
		}

		private void Start()
		{
			timer = 0f;
		}

		private void FixedUpdate()
		{
			if (Util.HasEffectiveAuthority(networkIdentity))
			{
				bool flag = stateMachine.state.GetType() == typeof(EntityStates.Idle) && !stateMachine.HasPendingState();
				if (skill.stock < skill.maxStock && flag)
				{
					timer += Time.fixedDeltaTime;
				}
				else
				{
					timer = 0f;
				}
				if (timer >= reloadDelay || (skill.stock == 0 && flag))
				{
					stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref reloadState));
				}
			}
		}
	}
	public class SmoothTrailMesh : MonoBehaviour
	{
		[Serializable]
		private struct Point
		{
			public UnityEngine.Vector3 vertex1;

			public UnityEngine.Vector3 vertex2;

			public float time;
		}

		private MeshFilter meshFilter;

		private MeshRenderer meshRenderer;

		private Mesh mesh;

		public float timeStep = 1f / 180f;

		public float width = 1f;

		public Material[] sharedMaterials;

		public float trailLifetime = 1f;

		public bool fadeVertexAlpha = true;

		private UnityEngine.Vector3 previousPosition;

		private UnityEngine.Vector3 previousUp;

		private float previousTime;

		private Queue<Point> pointsQueue = new Queue<Point>();

		private void Awake()
		{
			mesh = new Mesh();
			mesh.MarkDynamic();
			GameObject gameObject = new GameObject("SmoothTrailMeshRenderer");
			meshFilter = gameObject.AddComponent<MeshFilter>();
			meshFilter.mesh = mesh;
			meshRenderer = gameObject.AddComponent<MeshRenderer>();
			meshRenderer.sharedMaterials = sharedMaterials;
		}

		private void AddCurrentPoint()
		{
			float time = Time.time;
			UnityEngine.Vector3 position = base.transform.position;
			UnityEngine.Vector3 vector = base.transform.up * width * 0.5f;
			pointsQueue.Enqueue(new Point
			{
				vertex1 = position + vector,
				vertex2 = position - vector,
				time = time
			});
		}

		private void OnEnable()
		{
			AddCurrentPoint();
		}

		private void OnDisable()
		{
			pointsQueue.Clear();
			mesh.Clear();
		}

		private void OnDestroy()
		{
			if ((bool)meshFilter)
			{
				meshFilter.mesh = null;
				UnityEngine.Object.Destroy(meshFilter.gameObject);
			}
			UnityEngine.Object.Destroy(mesh);
		}

		private void Simulate()
		{
			float time = Time.time;
			UnityEngine.Vector3 position = base.transform.position;
			UnityEngine.Vector3 b = base.transform.up * width * 0.5f;
			float num = time - previousTime;
			if (num > 0f)
			{
				float num2 = 1f / num;
				for (float num3 = previousTime; num3 <= time; num3 += timeStep)
				{
					float t = (num3 - previousTime) * num2;
					UnityEngine.Vector3 vector = UnityEngine.Vector3.LerpUnclamped(previousPosition, position, t);
					UnityEngine.Vector3 vector2 = UnityEngine.Vector3.SlerpUnclamped(previousUp, b, t);
					pointsQueue.Enqueue(new Point
					{
						vertex1 = vector + vector2,
						vertex2 = vector - vector2,
						time = num3
					});
				}
			}
			float num4 = time - trailLifetime;
			while (pointsQueue.Count > 0 && pointsQueue.Peek().time < num4)
			{
				pointsQueue.Dequeue();
			}
			previousTime = time;
			previousPosition = position;
			previousUp = b;
		}

		private void LateUpdate()
		{
			Simulate();
			GenerateMesh();
		}

		private void GenerateMesh()
		{
			UnityEngine.Vector3[] array = new UnityEngine.Vector3[pointsQueue.Count * 2];
			UnityEngine.Vector2[] array2 = new UnityEngine.Vector2[pointsQueue.Count * 2];
			UnityEngine.Color[] array3 = new UnityEngine.Color[pointsQueue.Count * 2];
			_ = 1f / (float)pointsQueue.Count;
			int num = 0;
			if (pointsQueue.Count > 0)
			{
				float time = pointsQueue.Peek().time;
				float time2 = Time.time;
				float num2 = time2 - time;
				float num3 = 1f / num2;
				foreach (Point item in pointsQueue)
				{
					float num4 = (time2 - item.time) * num3;
					array[num] = item.vertex1;
					array2[num] = new UnityEngine.Vector2(1f, num4);
					array3[num] = new UnityEngine.Color(1f, 1f, 1f, fadeVertexAlpha ? (1f - num4) : 1f);
					num++;
					array[num] = item.vertex2;
					array2[num] = new UnityEngine.Vector2(0f, num4);
					num++;
				}
			}
			int num5 = pointsQueue.Count - 1;
			int[] array4 = new int[num5 * 2 * 3];
			int num6 = 0;
			int num7 = 0;
			for (int i = 0; i < num5; i++)
			{
				array4[num6] = num7;
				array4[num6 + 1] = num7 + 1;
				array4[num6 + 2] = num7 + 2;
				array4[num6 + 3] = num7 + 3;
				array4[num6 + 4] = num7 + 1;
				array4[num6 + 5] = num7 + 2;
				num6 += 6;
				num7 += 2;
			}
			mesh.Clear();
			mesh.vertices = array;
			mesh.uv = array2;
			mesh.triangles = array4;
			mesh.colors = array3;
			mesh.RecalculateBounds();
			mesh.UploadMeshData(markNoLongerReadable: false);
		}
	}
	public class SnailAnimator : MonoBehaviour
	{
		public ParticleSystem healEffectSystem;

		private bool lastOutOfDanger;

		private Animator animator;

		private CharacterModel characterModel;

		private static int spawnParamHash = Animator.StringToHash("spawn");

		private static int hideParamHash = Animator.StringToHash("hide");

		private void Start()
		{
			animator = GetComponent<Animator>();
			characterModel = GetComponentInParent<CharacterModel>();
		}

		private void FixedUpdate()
		{
			if (!characterModel)
			{
				return;
			}
			CharacterBody body = characterModel.body;
			if ((bool)body)
			{
				bool outOfDanger = body.outOfDanger;
				if (outOfDanger && !lastOutOfDanger)
				{
					animator.SetBool(spawnParamHash, value: true);
					animator.SetBool(hideParamHash, value: false);
					Util.PlaySound("Play_item_proc_slug_emerge", characterModel.gameObject);
					ParticleSystem.MainModule main = healEffectSystem.main;
					main.loop = true;
					healEffectSystem.Play();
				}
				else if (!outOfDanger && lastOutOfDanger)
				{
					animator.SetBool(hideParamHash, value: true);
					animator.SetBool(spawnParamHash, value: false);
					Util.PlaySound("Play_item_proc_slug_hide", characterModel.gameObject);
					ParticleSystem.MainModule main2 = healEffectSystem.main;
					main2.loop = false;
				}
				lastOutOfDanger = outOfDanger;
			}
		}
	}
	public class SpawnPoint : MonoBehaviour
	{
		private static List<SpawnPoint> instancesList = new List<SpawnPoint>();

		private static ReadOnlyCollection<SpawnPoint> _readOnlyInstancesList = new ReadOnlyCollection<SpawnPoint>(instancesList);

		[Tooltip("Flagged when a player spawns on this position, to stop overlapping spawn positions")]
		public bool consumed;

		private static GameObject prefab;

		private static Mesh commandoMesh;

		private static bool attemptedCommandoMeshLoad = false;

		public static ReadOnlyCollection<SpawnPoint> readOnlyInstancesList => _readOnlyInstancesList;

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

		public static SpawnPoint ConsumeSpawnPoint()
		{
			if (instancesList.Count == 0)
			{
				return null;
			}
			SpawnPoint spawnPoint = null;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				if (!readOnlyInstancesList[i].consumed)
				{
					spawnPoint = readOnlyInstancesList[i];
					readOnlyInstancesList[i].consumed = true;
					break;
				}
			}
			if (!spawnPoint)
			{
				for (int j = 0; j < readOnlyInstancesList.Count; j++)
				{
					readOnlyInstancesList[j].consumed = false;
				}
				spawnPoint = readOnlyInstancesList[0];
			}
			return spawnPoint;
		}

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private static Mesh GetCommandoMesh()
		{
			if (!commandoMesh)
			{
				LoadCommandoMesh();
			}
			return commandoMesh;
		}

		private static void LoadCommandoMesh()
		{
			if (attemptedCommandoMeshLoad)
			{
				return;
			}
			attemptedCommandoMeshLoad = true;
			GameObject gameObject = null;
			gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/CharacterBodies/CommandoBody");
			if (!gameObject)
			{
				return;
			}
			CharacterModel component = gameObject.GetComponent<ModelLocator>().modelTransform.GetComponent<CharacterModel>();
			SkinnedMeshRenderer skinnedMeshRenderer = null;
			for (int i = 0; i < component.baseRendererInfos.Length; i++)
			{
				skinnedMeshRenderer = component.baseRendererInfos[i].renderer as SkinnedMeshRenderer;
				if ((bool)skinnedMeshRenderer)
				{
					break;
				}
			}
			commandoMesh = skinnedMeshRenderer.sharedMesh;
		}

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/SpawnPoint");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				prefab = x.Result;
			};
		}

		public static void AddSpawnPoint(NodeGraph nodeGraph, NodeGraph.NodeIndex nodeIndex, Xoroshiro128Plus rng)
		{
			nodeGraph.GetNodePosition(nodeIndex, out var position);
			List<NodeGraph.LinkIndex> list = CollectionPool<NodeGraph.LinkIndex, List<NodeGraph.LinkIndex>>.RentCollection();
			nodeGraph.GetActiveNodeLinks(nodeIndex, list);
			UnityEngine.Quaternion rotation;
			if (list.Count > 0)
			{
				NodeGraph.LinkIndex linkIndex = rng.NextElementUniform(list);
				nodeGraph.GetNodePosition(nodeGraph.GetLinkEndNode(linkIndex), out var position2);
				rotation = Util.QuaternionSafeLookRotation(position2 - position);
			}
			else
			{
				rotation = UnityEngine.Quaternion.Euler(0f, rng.nextNormalizedFloat * 360f, 0f);
			}
			AddSpawnPoint(position, rotation);
			list = CollectionPool<NodeGraph.LinkIndex, List<NodeGraph.LinkIndex>>.ReturnCollection(list);
		}

		public static void AddSpawnPoint(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			UnityEngine.Object.Instantiate(prefab, position, rotation);
		}

		public void OnDrawGizmos()
		{
			Gizmos.matrix = base.transform.localToWorldMatrix;
			Gizmos.color = UnityEngine.Color.green;
			Gizmos.DrawWireMesh(GetCommandoMesh());
		}
	}
	public class SphereZone : BaseZoneBehavior, IZone
	{
		[Tooltip("The area of effect.")]
		[SyncVar]
		public float radius;

		[Tooltip("The child range indicator object. Will be scaled to the radius.")]
		public Transform rangeIndicator;

		[Tooltip("The time it takes the range indicator to update")]
		public float indicatorSmoothTime = 0.2f;

		[Tooltip("If false, \"IsInBounds\" returns true when inside the sphere.  If true, outside the sphere is considered in bounds.")]
		public bool isInverted;

		private float rangeIndicatorScaleVelocity;

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 1u);
			}
		}

		private void OnEnable()
		{
			if ((bool)rangeIndicator)
			{
				rangeIndicator.gameObject.SetActive(value: true);
			}
		}

		private void OnDisable()
		{
			if ((bool)rangeIndicator)
			{
				rangeIndicator.gameObject.SetActive(value: false);
			}
		}

		private void Update()
		{
			if ((bool)rangeIndicator)
			{
				float num = Mathf.SmoothDamp(rangeIndicator.localScale.x, radius, ref rangeIndicatorScaleVelocity, indicatorSmoothTime);
				rangeIndicator.localScale = new UnityEngine.Vector3(num, num, num);
			}
		}

		public override bool IsInBounds(UnityEngine.Vector3 position)
		{
			UnityEngine.Vector3 vector = position - base.transform.position;
			if (isInverted)
			{
				return vector.sqrMagnitude > radius * radius;
			}
			return vector.sqrMagnitude <= radius * radius;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			if (forceAll)
			{
				writer.Write(radius);
				return true;
			}
			bool flag2 = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag2)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag2 = true;
				}
				writer.Write(radius);
			}
			if (!flag2)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
			if (initialState)
			{
				radius = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				radius = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	[RequireComponent(typeof(DelayBlast))]
	public class SpiteBombController : NetworkBehaviour
	{
		public float radius;

		public float bounce = 0.8f;

		public float minimumBounceVelocity;

		public GameObject[] meshVisuals;

		public string[] bounceSoundStrings;

		private new Transform transform;

		private Rigidbody rb;

		[SyncVar]
		private UnityEngine.Vector3 _bouncePosition;

		[SyncVar]
		private float _initialVelocityY;

		private static readonly int maxBounces = 2;

		private UnityEngine.Vector3 startPosition;

		private UnityEngine.Vector3 velocity;

		private int bounces;

		public DelayBlast delayBlast { get; private set; }

		public UnityEngine.Vector3 bouncePosition
		{
			get
			{
				return _bouncePosition;
			}
			set
			{
				Network_bouncePosition = value;
			}
		}

		public float initialVelocityY
		{
			get
			{
				return _initialVelocityY;
			}
			set
			{
				Network_initialVelocityY = value;
			}
		}

		public UnityEngine.Vector3 Network_bouncePosition
		{
			get
			{
				return _bouncePosition;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _bouncePosition, 1u);
			}
		}

		public float Network_initialVelocityY
		{
			get
			{
				return _initialVelocityY;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _initialVelocityY, 2u);
			}
		}

		private void Awake()
		{
			transform = base.transform;
			rb = GetComponent<Rigidbody>();
			delayBlast = GetComponent<DelayBlast>();
		}

		private void Start()
		{
			startPosition = transform.position;
			float time = Trajectory.CalculateFlightDuration(startPosition.y, bouncePosition.y, initialVelocityY);
			UnityEngine.Vector3 vector = bouncePosition - startPosition;
			vector.y = 0f;
			float magnitude = vector.magnitude;
			float num = Trajectory.CalculateGroundSpeed(time, magnitude);
			velocity = vector / magnitude * num;
			velocity.y = initialVelocityY;
		}

		private void FixedUpdate()
		{
			float fixedDeltaTime = Time.fixedDeltaTime;
			velocity.y += fixedDeltaTime * Physics.gravity.y;
			UnityEngine.Vector3 position = transform.position;
			position += velocity * fixedDeltaTime;
			if (position.y < bouncePosition.y + radius)
			{
				velocity.y = Mathf.Max(velocity.y * (0f - bounce), minimumBounceVelocity);
				velocity.x = 0f;
				velocity.z = 0f;
				position.y = bouncePosition.y + radius;
				OnBounce();
			}
			rb.MovePosition(position);
		}

		private void OnBounce()
		{
			meshVisuals[bounces].SetActive(value: false);
			Util.PlaySound(bounceSoundStrings[bounces], base.gameObject);
			bounces++;
			if (bounces > maxBounces)
			{
				OnFinalBounce();
			}
			else
			{
				meshVisuals[bounces].SetActive(value: true);
			}
		}

		private void OnFinalBounce()
		{
			if (NetworkServer.active)
			{
				delayBlast.position = transform.position;
				delayBlast.Detonate();
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_bouncePosition);
				writer.Write(_initialVelocityY);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_bouncePosition);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_initialVelocityY);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_bouncePosition = reader.ReadVector3();
				_initialVelocityY = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_bouncePosition = reader.ReadVector3();
			}
			if (((uint)num & 2u) != 0)
			{
				_initialVelocityY = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class SplashScreenController : MonoBehaviour
	{
		private static BoolConVar cvSplashSkip = new BoolConVar("splash_skip", ConVarFlags.Archive, "0", "Whether or not to skip startup splash screens.");

		private void Start()
		{
			if (cvSplashSkip.value)
			{
				Finish();
			}
		}

		public void Finish()
		{
			if (IntroCutsceneController.shouldSkip)
			{
				PlatformSystems.networkManager.ServerChangeScene("dafb193bd5aedc74abd11b22f8dce1c2");
			}
			else
			{
				StartCoroutine(LoadHelper.LoadSceneAdditivelyAsync("330d792ae1727574e969e68ce8e966d2"));
			}
		}
	}
	public class SprintEffectController : MonoBehaviour
	{
		public ParticleSystem[] loopSystems;

		public GameObject loopRootObject;

		public bool mustBeGrounded;

		public bool mustBeVisible;

		public CharacterBody characterBody;

		public CharacterModel characterModel;

		private void Awake()
		{
			if ((bool)characterBody && Util.IsPrefab(characterBody.gameObject) && !Util.IsPrefab(base.gameObject))
			{
				characterBody = null;
			}
		}

		private void FixedUpdate()
		{
			bool flag = true;
			if ((bool)characterModel)
			{
				flag = characterModel.visibility > VisibilityLevel.Cloaked;
			}
			if (!characterBody)
			{
				return;
			}
			if ((bool)characterBody.characterMotor && characterBody.healthComponent.alive && characterBody.isSprinting && (!mustBeGrounded || characterBody.characterMotor.isGrounded) && (!mustBeVisible || flag))
			{
				if ((bool)loopRootObject)
				{
					loopRootObject.SetActive(value: true);
				}
				for (int i = 0; i < loopSystems.Length; i++)
				{
					ParticleSystem particleSystem = loopSystems[i];
					ParticleSystem.MainModule main = particleSystem.main;
					main.loop = true;
					if (!particleSystem.isPlaying)
					{
						particleSystem.Play();
					}
				}
			}
			else
			{
				if ((bool)loopRootObject)
				{
					loopRootObject.SetActive(value: false);
				}
				for (int j = 0; j < loopSystems.Length; j++)
				{
					ParticleSystem.MainModule main2 = loopSystems[j].main;
					main2.loop = false;
				}
			}
		}
	}
	public class Stage : NetworkBehaviour
	{
		[SyncVar]
		private float _entryTime;

		[SyncVar]
		private float _entryStopwatchValue;

		[SyncVar]
		private float _entryDifficultyCoefficient;

		[SyncVar]
		private int _singleMonsterTypeBodyIndex = -1;

		private bool spawnedAnyPlayer;

		[NonSerialized]
		public bool usePod = (bool)Run.instance && Run.instance.spawnWithPod && stage1PodConVar.value;

		private static BoolConVar stage1PodConVar = new BoolConVar("stage1_pod", ConVarFlags.Cheat, "1", "Whether or not to use the pod when spawning on the first stage.");

		[SyncVar]
		private float _stageAdvanceTime = float.PositiveInfinity;

		public const float stageAdvanceTransitionDuration = 0.5f;

		public const float stageAdvanceTransitionDelay = 0.75f;

		private SceneDef nextStage;

		public static Stage instance { get; private set; }

		public Run.FixedTimeStamp entryTime
		{
			get
			{
				return Run.FixedTimeStamp.zero + _entryTime;
			}
			private set
			{
				Network_entryTime = value - Run.FixedTimeStamp.zero;
			}
		}

		public float entryStopwatchValue
		{
			get
			{
				return _entryStopwatchValue;
			}
			private set
			{
				Network_entryStopwatchValue = value;
			}
		}

		public float entryDifficultyCoefficient
		{
			get
			{
				return _entryDifficultyCoefficient;
			}
			private set
			{
				Network_entryDifficultyCoefficient = value;
			}
		}

		public BodyIndex singleMonsterTypeBodyIndex
		{
			get
			{
				return (BodyIndex)_singleMonsterTypeBodyIndex;
			}
			set
			{
				Network_singleMonsterTypeBodyIndex = (int)value;
			}
		}

		public SceneDef sceneDef { get; private set; }

		public Run.FixedTimeStamp stageAdvanceTime
		{
			get
			{
				return Run.FixedTimeStamp.zero + _stageAdvanceTime;
			}
			private set
			{
				Network_stageAdvanceTime = value - Run.FixedTimeStamp.zero;
			}
		}

		public bool completed { get; private set; }

		public bool scavPackDroppedServer { get; set; }

		public float Network_entryTime
		{
			get
			{
				return _entryTime;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _entryTime, 1u);
			}
		}

		public float Network_entryStopwatchValue
		{
			get
			{
				return _entryStopwatchValue;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _entryStopwatchValue, 2u);
			}
		}

		public float Network_entryDifficultyCoefficient
		{
			get
			{
				return _entryDifficultyCoefficient;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _entryDifficultyCoefficient, 4u);
			}
		}

		public int Network_singleMonsterTypeBodyIndex
		{
			get
			{
				return _singleMonsterTypeBodyIndex;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _singleMonsterTypeBodyIndex, 8u);
			}
		}

		public float Network_stageAdvanceTime
		{
			get
			{
				return _stageAdvanceTime;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _stageAdvanceTime, 16u);
			}
		}

		public static event Action<Stage> onServerStageBegin;

		public static event Action<Stage> onServerStageComplete;

		public static event Action<Stage> onStageStartGlobal;

		private IEnumerator Start()
		{
			sceneDef = SceneCatalog.GetSceneDefForCurrentScene();
			if (NetworkServer.active)
			{
				entryTime = Run.FixedTimeStamp.now;
				entryStopwatchValue = Run.instance.GetRunStopwatch();
				entryDifficultyCoefficient = Run.instance.difficultyCoefficient;
				RespawnAllNPCs();
				BeginServer();
			}
			if (NetworkClient.active)
			{
				yield return new WaitUntil(() => NetworkUser.readOnlyInstancesList.Any((NetworkUser x) => x.isLocalPlayer));
				RespawnLocalPlayers();
			}
			Stage.onStageStartGlobal?.Invoke(this);
		}

		private void RespawnAllNPCs()
		{
			if (sceneDef.suppressNpcEntry)
			{
				return;
			}
			if (sceneDef.needSkipDevotionRespawn)
			{
				DevotionInventoryController.StartRespawnAllLemurians();
			}
			ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
			Transform playerSpawnTransform = GetPlayerSpawnTransform();
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CharacterMaster characterMaster = readOnlyInstancesList[i];
				if ((sceneDef.needSkipDevotionRespawn && readOnlyInstancesList[i].GetComponent<DevotedLemurianController>() != null) || !characterMaster || (bool)characterMaster.GetComponent<PlayerCharacterMasterController>() || (bool)characterMaster.GetBodyObject() || !Util.IsDontDestroyOnLoad(characterMaster.gameObject))
				{
					continue;
				}
				UnityEngine.Vector3 position = UnityEngine.Vector3.zero;
				UnityEngine.Quaternion rotation = UnityEngine.Quaternion.identity;
				if ((bool)playerSpawnTransform)
				{
					position = playerSpawnTransform.position;
					rotation = playerSpawnTransform.rotation;
					BaseAI component = readOnlyInstancesList[i].GetComponent<BaseAI>();
					CharacterBody component2 = readOnlyInstancesList[i].bodyPrefab.GetComponent<CharacterBody>();
					if ((bool)component && (bool)component2)
					{
						NodeGraph desiredSpawnNodeGraph = component.GetDesiredSpawnNodeGraph();
						if ((bool)desiredSpawnNodeGraph)
						{
							List<NodeGraph.NodeIndex> list = CollectionPool<NodeGraph.NodeIndex, List<NodeGraph.NodeIndex>>.RentCollection();
							desiredSpawnNodeGraph.FindNodesInRange(position, 10f, 100f, (HullMask)(1 << (int)component2.hullClassification), list);
							if ((float)list.Count > 0f)
							{
								desiredSpawnNodeGraph.GetNodePosition(list[UnityEngine.Random.Range(0, list.Count)], out position);
							}
							list = CollectionPool<NodeGraph.NodeIndex, List<NodeGraph.NodeIndex>>.ReturnCollection(list);
						}
					}
				}
				readOnlyInstancesList[i].Respawn(position, rotation, wasRevivedMidStage: true);
			}
		}

		[Client]
		public void RespawnLocalPlayers()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.Stage::RespawnLocalPlayers()' called on server");
			}
			else
			{
				if (sceneDef.suppressPlayerEntry)
				{
					return;
				}
				ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
				for (int i = 0; i < readOnlyInstancesList.Count; i++)
				{
					NetworkUser networkUser = readOnlyInstancesList[i];
					CharacterMaster characterMaster = null;
					if (networkUser.isLocalPlayer && (bool)networkUser.masterObject)
					{
						characterMaster = networkUser.masterObject.GetComponent<CharacterMaster>();
					}
					if ((bool)characterMaster)
					{
						characterMaster.CallCmdRespawn("");
					}
				}
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		[Server]
		public Transform GetPlayerSpawnTransform()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'UnityEngine.Transform RoR2.Stage::GetPlayerSpawnTransform()' called on client");
				return null;
			}
			SpawnPoint spawnPoint = SpawnPoint.ConsumeSpawnPoint();
			if ((bool)spawnPoint)
			{
				return spawnPoint.transform;
			}
			return null;
		}

		[Server]
		public void RespawnCharacter(CharacterMaster characterMaster)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Stage::RespawnCharacter(RoR2.CharacterMaster)' called on client");
			}
			else if ((bool)characterMaster)
			{
				Transform playerSpawnTransform = GetPlayerSpawnTransform();
				UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
				UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.identity;
				if ((bool)playerSpawnTransform)
				{
					vector = playerSpawnTransform.position;
					quaternion = playerSpawnTransform.rotation;
				}
				characterMaster.Respawn(vector, quaternion);
				if ((bool)characterMaster.GetComponent<PlayerCharacterMasterController>())
				{
					spawnedAnyPlayer = true;
				}
				if (usePod)
				{
					Run.instance.HandlePlayerFirstEntryAnimation(characterMaster.GetBody(), vector, quaternion);
				}
			}
		}

		[Server]
		public void BeginAdvanceStage(SceneDef destinationStage)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Stage::BeginAdvanceStage(RoR2.SceneDef)' called on client");
				return;
			}
			stageAdvanceTime = Run.FixedTimeStamp.now + 0.75f;
			nextStage = destinationStage;
		}

		[Server]
		private void BeginServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Stage::BeginServer()' called on client");
			}
			else
			{
				Stage.onServerStageBegin?.Invoke(this);
			}
		}

		[Server]
		public void CompleteServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Stage::CompleteServer()' called on client");
			}
			else if (!completed)
			{
				completed = true;
				Stage.onServerStageComplete?.Invoke(this);
			}
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if ((bool)nextStage && stageAdvanceTime.hasPassed)
			{
				SceneDef nextScene = nextStage;
				nextStage = null;
				Run.instance.AdvanceStage(nextScene);
			}
			if (!spawnedAnyPlayer || !stageAdvanceTime.isInfinity || Run.instance.isGameOverServer)
			{
				return;
			}
			ReadOnlyCollection<PlayerCharacterMasterController> instances = PlayerCharacterMasterController.instances;
			bool flag = false;
			for (int i = 0; i < instances.Count; i++)
			{
				PlayerCharacterMasterController playerCharacterMasterController = instances[i];
				if (playerCharacterMasterController.isConnected && playerCharacterMasterController.preventGameOver)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				Run.instance.BeginGameOver(RoR2Content.GameEndings.StandardLoss);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_entryTime);
				writer.Write(_entryStopwatchValue);
				writer.Write(_entryDifficultyCoefficient);
				writer.WritePackedUInt32((uint)_singleMonsterTypeBodyIndex);
				writer.Write(_stageAdvanceTime);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_entryTime);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_entryStopwatchValue);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_entryDifficultyCoefficient);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)_singleMonsterTypeBodyIndex);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_stageAdvanceTime);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_entryTime = reader.ReadSingle();
				_entryStopwatchValue = reader.ReadSingle();
				_entryDifficultyCoefficient = reader.ReadSingle();
				_singleMonsterTypeBodyIndex = (int)reader.ReadPackedUInt32();
				_stageAdvanceTime = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_entryTime = reader.ReadSingle();
			}
			if (((uint)num & 2u) != 0)
			{
				_entryStopwatchValue = reader.ReadSingle();
			}
			if (((uint)num & 4u) != 0)
			{
				_entryDifficultyCoefficient = reader.ReadSingle();
			}
			if (((uint)num & 8u) != 0)
			{
				_singleMonsterTypeBodyIndex = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 0x10u) != 0)
			{
				_stageAdvanceTime = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class StageCountObjectFilter : MonoBehaviour
	{
		[Tooltip("The minimum stage required to start enabling objects.")]
		public int minimumStageClearCount;

		[Tooltip("The objects to activate or deactivate, depending on the stage count.")]
		public GameObject[] gameObjects;

		private void Start()
		{
			if (!Run.instance)
			{
				return;
			}
			bool active = Run.instance.stageClearCount >= minimumStageClearCount;
			for (int i = 0; i < gameObjects.Length; i++)
			{
				GameObject gameObject = gameObjects[i];
				if ((bool)gameObject)
				{
					gameObject.SetActive(active);
				}
			}
		}
	}
	public class StageSkinVariantController : MonoBehaviour
	{
		[Serializable]
		public struct StageSkinVariant
		{
			public string stageNameToken;

			public CharacterModel.RendererInfo[] replacementRenderInfos;

			public GameObject[] childObjects;
		}

		public StageSkinVariant[] stageSkinVariants;

		public CharacterModel characterModel;

		private void Awake()
		{
			if (!SceneInfo.instance)
			{
				return;
			}
			for (int i = 0; i < stageSkinVariants.Length; i++)
			{
				StageSkinVariant stageSkinVariant = stageSkinVariants[i];
				for (int j = 0; j < stageSkinVariant.childObjects.Length; j++)
				{
					stageSkinVariant.childObjects[j].SetActive(value: false);
				}
			}
			for (int k = 0; k < stageSkinVariants.Length; k++)
			{
				StageSkinVariant stageSkinVariant2 = stageSkinVariants[k];
				if (SceneInfo.instance.sceneDef.nameToken == stageSkinVariant2.stageNameToken)
				{
					for (int l = 0; l < stageSkinVariant2.childObjects.Length; l++)
					{
						stageSkinVariant2.childObjects[l].SetActive(value: true);
					}
					if (stageSkinVariant2.replacementRenderInfos.Length != 0)
					{
						characterModel.baseRendererInfos = stageSkinVariant2.replacementRenderInfos;
					}
					break;
				}
			}
		}
	}
	public class StartEvent : MonoBehaviour
	{
		public bool runOnServerOnly;

		public UnityEvent action;

		private void Start()
		{
			if (!runOnServerOnly || NetworkServer.active)
			{
				action.Invoke();
			}
		}
	}
	public class StriderLegController : MonoBehaviour
	{
		[Serializable]
		public struct FootInfo
		{
			public Transform transform;

			public Transform referenceTransform;

			[HideInInspector]
			public UnityEngine.Vector3 velocity;

			[HideInInspector]
			public FootState footState;

			[HideInInspector]
			public UnityEngine.Vector3 plantPosition;

			[HideInInspector]
			public UnityEngine.Vector3 trailingTargetPosition;

			[HideInInspector]
			public float stopwatch;

			[HideInInspector]
			public float currentYOffsetFromRaycast;

			[HideInInspector]
			public float lastYOffsetFromRaycast;

			[HideInInspector]
			public float footRaycastTimer;
		}

		public enum FootState
		{
			Planted,
			Replanting
		}

		[Header("Foot Settings")]
		public Transform centerOfGravity;

		public FootInfo[] feet;

		public UnityEngine.Vector3 footRaycastDirection;

		public float raycastVerticalOffset;

		public float maxRaycastDistance;

		public float footDampTime;

		public float stabilityRadius;

		public float replantDuration;

		public float replantHeight;

		public float overstepDistance;

		public AnimationCurve lerpCurve;

		public GameObject footPlantEffect;

		public string footPlantString;

		public string footMoveString;

		public float footRaycastFrequency = 0.2f;

		public int maxFeetReplantingAtOnce = 9999;

		[Header("Root Settings")]
		public Transform rootTransform;

		public float rootSpringConstant;

		public float rootDampingConstant;

		public float rootOffsetHeight;

		public float rootSmoothDamp;

		private float rootVelocity;

		public UnityEngine.Vector3 GetCenterOfStance()
		{
			UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
			for (int i = 0; i < feet.Length; i++)
			{
				zero += feet[i].transform.position;
			}
			return zero / feet.Length;
		}

		private void Awake()
		{
			for (int i = 0; i < feet.Length; i++)
			{
				feet[i].footState = FootState.Planted;
				feet[i].plantPosition = feet[i].referenceTransform.position;
				feet[i].trailingTargetPosition = feet[i].plantPosition;
				feet[i].footRaycastTimer = UnityEngine.Random.Range(0f, 1f / footRaycastFrequency);
			}
		}

		private void Update()
		{
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < feet.Length; i++)
			{
				if (feet[i].footState == FootState.Replanting)
				{
					num2++;
				}
			}
			for (int j = 0; j < feet.Length; j++)
			{
				feet[j].footRaycastTimer -= Time.deltaTime;
				Transform transform = feet[j].transform;
				Transform referenceTransform = feet[j].referenceTransform;
				_ = transform.position;
				UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
				float num3 = 0f;
				switch (feet[j].footState)
				{
				case FootState.Planted:
					num++;
					vector = feet[j].plantPosition;
					if ((referenceTransform.position - vector).sqrMagnitude > stabilityRadius * stabilityRadius && num2 < maxFeetReplantingAtOnce)
					{
						feet[j].footState = FootState.Replanting;
						Util.PlaySound(footMoveString, transform.gameObject);
						num2++;
					}
					break;
				case FootState.Replanting:
				{
					feet[j].stopwatch += Time.deltaTime;
					UnityEngine.Vector3 plantPosition = feet[j].plantPosition;
					UnityEngine.Vector3 position = referenceTransform.position;
					position += UnityEngine.Vector3.ProjectOnPlane(position - plantPosition, UnityEngine.Vector3.up).normalized * overstepDistance;
					float num4 = lerpCurve.Evaluate(feet[j].stopwatch / replantDuration);
					vector = UnityEngine.Vector3.Lerp(plantPosition, position, num4);
					num3 = Mathf.Sin(num4 * MathF.PI) * replantHeight;
					if (feet[j].stopwatch >= replantDuration)
					{
						feet[j].plantPosition = position;
						feet[j].stopwatch = 0f;
						feet[j].footState = FootState.Planted;
						Util.PlaySound(footPlantString, transform.gameObject);
						if ((bool)footPlantEffect)
						{
							EffectManager.SimpleEffect(footPlantEffect, transform.position, UnityEngine.Quaternion.identity, transmit: false);
						}
					}
					break;
				}
				}
				Ray ray = default(Ray);
				ray.direction = transform.TransformDirection(footRaycastDirection.normalized);
				ray.origin = vector - ray.direction * raycastVerticalOffset;
				if (feet[j].footRaycastTimer <= 0f)
				{
					feet[j].footRaycastTimer = 1f / footRaycastFrequency;
					feet[j].lastYOffsetFromRaycast = feet[j].currentYOffsetFromRaycast;
					if (Physics.Raycast(ray, out var hitInfo, maxRaycastDistance + raycastVerticalOffset, LayerIndex.world.mask))
					{
						feet[j].currentYOffsetFromRaycast = hitInfo.point.y - vector.y;
					}
					else
					{
						feet[j].currentYOffsetFromRaycast = 0f;
					}
				}
				float num5 = Mathf.Lerp(feet[j].currentYOffsetFromRaycast, feet[j].lastYOffsetFromRaycast, feet[j].footRaycastTimer / (1f / footRaycastFrequency));
				vector.y += num3 + num5;
				feet[j].trailingTargetPosition = UnityEngine.Vector3.SmoothDamp(feet[j].trailingTargetPosition, vector, ref feet[j].velocity, footDampTime);
				transform.position = feet[j].trailingTargetPosition;
			}
			if ((bool)rootTransform)
			{
				UnityEngine.Vector3 localPosition = rootTransform.localPosition;
				float num6 = (1f - (float)num / (float)feet.Length) * rootOffsetHeight;
				float target = localPosition.z - num6;
				float z = Mathf.SmoothDamp(localPosition.z, target, ref rootVelocity, rootSmoothDamp);
				rootTransform.localPosition = new UnityEngine.Vector3(localPosition.x, localPosition.y, z);
			}
		}

		public UnityEngine.Vector3 GetArcPosition(UnityEngine.Vector3 start, UnityEngine.Vector3 end, float arcHeight, float t)
		{
			return UnityEngine.Vector3.Lerp(start, end, Mathf.Sin(t * MathF.PI * 0.5f)) + new UnityEngine.Vector3(0f, Mathf.Sin(t * MathF.PI) * arcHeight, 0f);
		}

		public void OnDrawGizmos()
		{
			for (int i = 0; i < feet.Length; i++)
			{
				Gizmos.color = UnityEngine.Color.green;
				Gizmos.DrawRay(feet[i].transform.position, feet[i].transform.TransformVector(footRaycastDirection));
			}
		}
	}
	public class SubmitCommandCall : MonoBehaviour
	{
		public string cmdPrimary;

		public bool onlyExecutePrimaryOnLocalPlayer;

		public string cmdAlternate;

		public bool onlyExecuteAlternateOnLocalPlayer;

		public string cmdTertiary;

		public bool onlyExecuteTertiaryOnLocalPlayer;

		public bool doForEveryActiveTarget = true;

		public void SubmitPrimaryCmd()
		{
			if (!string.IsNullOrEmpty(cmdPrimary))
			{
				Console.instance.SubmitCmd(null, cmdPrimary);
			}
		}

		public void SubmitAlternateCmd()
		{
			if (!string.IsNullOrEmpty(cmdAlternate))
			{
				Console.instance.SubmitCmd(null, cmdPrimary);
			}
		}

		public void SubmitTertiaryCmd()
		{
			if (!string.IsNullOrEmpty(cmdTertiary))
			{
				Console.instance.SubmitCmd(null, cmdTertiary);
			}
		}

		public void SubmitPrimaryCmdOnLocalPlayer()
		{
			if (string.IsNullOrEmpty(cmdPrimary))
			{
				return;
			}
			if (!onlyExecutePrimaryOnLocalPlayer && doForEveryActiveTarget)
			{
				bool flag = false;
				foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
				{
					if ((bool)readOnlyLocalPlayers)
					{
						Console.instance.SubmitCmd(readOnlyLocalPlayers, cmdPrimary);
						flag = true;
					}
				}
				if (!flag)
				{
					Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], cmdPrimary);
				}
			}
			else
			{
				Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], cmdPrimary);
			}
		}

		public void SubmitAlternateCmdOnLocalPlayer()
		{
			if (string.IsNullOrEmpty(cmdAlternate))
			{
				return;
			}
			if (!onlyExecuteAlternateOnLocalPlayer && doForEveryActiveTarget)
			{
				bool flag = false;
				foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
				{
					if ((bool)readOnlyLocalPlayers)
					{
						Console.instance.SubmitCmd(readOnlyLocalPlayers, cmdAlternate);
						flag = true;
					}
				}
				if (!flag)
				{
					Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], cmdAlternate);
				}
			}
			else
			{
				Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], cmdAlternate);
			}
		}

		public void SubmitTertiaryCmdOnLocalPlayer()
		{
			if (string.IsNullOrEmpty(cmdTertiary))
			{
				return;
			}
			if (!onlyExecuteTertiaryOnLocalPlayer && doForEveryActiveTarget)
			{
				bool flag = false;
				foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
				{
					if ((bool)readOnlyLocalPlayers)
					{
						Console.instance.SubmitCmd(readOnlyLocalPlayers, cmdTertiary);
						flag = true;
					}
				}
				if (!flag)
				{
					Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], cmdTertiary);
				}
			}
			else
			{
				Console.instance.SubmitCmd(NetworkUser.readOnlyLocalPlayersList[0], cmdTertiary);
			}
		}
	}
	public class SummonMasterBehavior : NetworkBehaviour
	{
		[Tooltip("The master to spawn")]
		public GameObject masterPrefab;

		public bool callOnEquipmentSpentOnPurchase;

		public bool destroyAfterSummoning = true;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		[Server]
		public void OpenSummon(Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SummonMasterBehavior::OpenSummon(RoR2.Interactor)' called on client");
			}
			else
			{
				OpenSummonReturnMaster(activator);
			}
		}

		[Server]
		public CharacterMaster OpenSummonReturnMaster(Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterMaster RoR2.SummonMasterBehavior::OpenSummonReturnMaster(RoR2.Interactor)' called on client");
				return null;
			}
			float num = 0f;
			CharacterMaster characterMaster = new MasterSummon
			{
				masterPrefab = masterPrefab,
				position = base.transform.position + UnityEngine.Vector3.up * num,
				rotation = base.transform.rotation,
				summonerBodyObject = activator?.gameObject,
				ignoreTeamMemberLimit = true,
				useAmbientLevel = true
			}.Perform();
			if ((bool)characterMaster)
			{
				GameObject bodyObject = characterMaster.GetBodyObject();
				if ((bool)bodyObject)
				{
					ModelLocator component = bodyObject.GetComponent<ModelLocator>();
					if ((bool)component && (bool)component.modelTransform)
					{
						TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(component.modelTransform.gameObject);
						temporaryOverlayInstance.duration = 0.5f;
						temporaryOverlayInstance.animateShaderAlpha = true;
						temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0f);
						temporaryOverlayInstance.destroyComponentOnEnd = true;
						temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matSummonDrone");
						temporaryOverlayInstance.AddToCharacterModel(component.modelTransform.GetComponent<CharacterModel>());
					}
				}
			}
			if (destroyAfterSummoning)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			return characterMaster;
		}

		public void OnEnable()
		{
			if (callOnEquipmentSpentOnPurchase)
			{
				PurchaseInteraction.onEquipmentSpentOnPurchase += OnEquipmentSpentOnPurchase;
			}
		}

		public void OnDisable()
		{
			if (callOnEquipmentSpentOnPurchase)
			{
				PurchaseInteraction.onEquipmentSpentOnPurchase -= OnEquipmentSpentOnPurchase;
			}
		}

		[Server]
		private void OnEquipmentSpentOnPurchase(PurchaseInteraction purchaseInteraction, Interactor interactor, EquipmentIndex equipmentIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.SummonMasterBehavior::OnEquipmentSpentOnPurchase(RoR2.PurchaseInteraction,RoR2.Interactor,RoR2.EquipmentIndex)' called on client");
			}
			else if (purchaseInteraction == GetComponent<PurchaseInteraction>())
			{
				CharacterMaster characterMaster = OpenSummonReturnMaster(interactor);
				if ((bool)characterMaster)
				{
					characterMaster.inventory.SetEquipmentIndex(equipmentIndex);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class SurfaceDefProvider : MonoBehaviour
	{
		[Tooltip("The primary surface definition. Use this when not tying to a splatmap.")]
		public SurfaceDef surfaceDef;

		public static SurfaceDef GetObjectSurfaceDef(Collider collider, UnityEngine.Vector3 position)
		{
			SurfaceDefProvider component = collider.GetComponent<SurfaceDefProvider>();
			if (!component)
			{
				return null;
			}
			return component.surfaceDef;
		}
	}
	[RequireComponent(typeof(EntityStateMachine))]
	[RequireComponent(typeof(VehicleSeat))]
	public sealed class SurvivorPodController : NetworkBehaviour, ICameraStateProvider
	{
		private EntityStateMachine stateMachine;

		[Tooltip("The bone which controls the camera during the entry animation.")]
		public Transform cameraBone;

		public bool exitAllowed;

		public EntityStateMachine characterStateMachine { get; private set; }

		public VehicleSeat vehicleSeat { get; private set; }

		private void Awake()
		{
			stateMachine = GetComponent<EntityStateMachine>();
			vehicleSeat = GetComponent<VehicleSeat>();
			vehicleSeat.onPassengerEnter += OnPassengerEnter;
			vehicleSeat.onPassengerExit += OnPassengerExit;
			vehicleSeat.enterVehicleAllowedCheck.AddCallback(CheckEnterAllowed);
			vehicleSeat.exitVehicleAllowedCheck.AddCallback(CheckExitAllowed);
		}

		private void OnPassengerEnter(GameObject passenger)
		{
			UpdateCameras(passenger);
		}

		private void OnPassengerExit(GameObject passenger)
		{
			UpdateCameras(null);
			vehicleSeat.enabled = false;
		}

		private void CheckEnterAllowed(CharacterBody characterBody, ref Interactability? resultOverride)
		{
			resultOverride = Interactability.Disabled;
		}

		private void CheckExitAllowed(CharacterBody characterBody, ref Interactability? resultOverride)
		{
			resultOverride = (exitAllowed ? Interactability.Available : Interactability.Disabled);
		}

		private void Update()
		{
			UpdateCameras(vehicleSeat.currentPassengerBody ? vehicleSeat.currentPassengerBody.gameObject : null);
		}

		private void UpdateCameras(GameObject characterBodyObject)
		{
			foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList)
			{
				if ((bool)characterBodyObject && readOnlyInstances.target == characterBodyObject)
				{
					readOnlyInstances.SetOverrideCam(this, 0f);
				}
				else if (readOnlyInstances.IsOverrideCam(this))
				{
					readOnlyInstances.SetOverrideCam(null, 0.05f);
				}
			}
		}

		void ICameraStateProvider.GetCameraState(CameraRigController cameraRigController, ref CameraState cameraState)
		{
			UnityEngine.Vector3 position = base.transform.position;
			UnityEngine.Vector3 position2 = cameraBone.position;
			UnityEngine.Vector3 direction = position2 - position;
			Ray ray = new Ray(position, direction);
			UnityEngine.Vector3 position3 = position2;
			if (Physics.Raycast(ray, out var hitInfo, direction.magnitude, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				position3 = ray.GetPoint(Mathf.Max(hitInfo.distance - 0.25f, 0.25f));
			}
			cameraState = new CameraState
			{
				position = position3,
				rotation = cameraBone.rotation,
				fov = 60f
			};
		}

		bool ICameraStateProvider.IsUserLookAllowed(CameraRigController cameraRigController)
		{
			return false;
		}

		bool ICameraStateProvider.IsUserControlAllowed(CameraRigController cameraRigController)
		{
			return true;
		}

		bool ICameraStateProvider.IsHudAllowed(CameraRigController cameraRigController)
		{
			return true;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class SyncFlickerLightToAnimateShaderAlpha : MonoBehaviour
	{
		[SerializeField]
		private AnimateShaderAlpha animateShaderAlpha;

		[SerializeField]
		private FlickerLight flickerLight;

		private float startingIntensity = 1f;

		private AnimationCurve acCurve;

		private void Start()
		{
			startingIntensity = animateShaderAlpha.alphaCurve.Evaluate(0f);
		}

		private void OnEnable()
		{
			flickerLight.UpdateLightIntensityMultiplier(startingIntensity);
			acCurve = animateShaderAlpha.alphaCurve;
		}

		private void Update()
		{
			if (animateShaderAlpha.enabled && flickerLight.enabled)
			{
				flickerLight.UpdateLightIntensityMultiplier(acCurve.Evaluate(animateShaderAlpha.time / animateShaderAlpha.timeMax));
			}
		}
	}
	[RequireComponent(typeof(ItemFollower))]
	public class TalismanAnimator : MonoBehaviour
	{
		private float lastCooldownTimer;

		private EquipmentSlot equipmentSlot;

		private ItemFollower itemFollower;

		private ParticleSystem[] killEffects;

		private void Start()
		{
			itemFollower = GetComponent<ItemFollower>();
			CharacterModel componentInParent = GetComponentInParent<CharacterModel>();
			if ((bool)componentInParent)
			{
				CharacterBody body = componentInParent.body;
				if ((bool)body)
				{
					equipmentSlot = body.equipmentSlot;
				}
			}
		}

		private void FixedUpdate()
		{
			if (!equipmentSlot)
			{
				return;
			}
			float cooldownTimer = equipmentSlot.cooldownTimer;
			if (lastCooldownTimer - cooldownTimer >= 0.5f && (bool)itemFollower.followerInstance)
			{
				if (killEffects == null || killEffects.Length == 0 || killEffects[0] == null)
				{
					killEffects = itemFollower.followerInstance.GetComponentsInChildren<ParticleSystem>();
				}
				ParticleSystem[] array = killEffects;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].Play();
				}
			}
			lastCooldownTimer = cooldownTimer;
		}
	}
	[RequireComponent(typeof(BezierCurveLine))]
	public class TarTetherController : NetworkBehaviour
	{
		[SyncVar]
		public GameObject targetRoot;

		[SyncVar]
		public GameObject ownerRoot;

		public float reelSpeed = 12f;

		[NonSerialized]
		public float mulchDistanceSqr;

		[NonSerialized]
		public float breakDistanceSqr;

		[NonSerialized]
		public float mulchDamageScale;

		[NonSerialized]
		public float mulchTickIntervalScale;

		[NonSerialized]
		public float damageCoefficientPerTick;

		[NonSerialized]
		public float tickInterval;

		[NonSerialized]
		public float tickTimer;

		public float attachTime;

		private float fixedAge;

		private float age;

		private bool beginSiphon;

		private BezierCurveLine bezierCurveLine;

		private HealthComponent targetHealthComponent;

		private HealthComponent ownerHealthComponent;

		private CharacterBody ownerBody;

		private NetworkInstanceId ___targetRootNetId;

		private NetworkInstanceId ___ownerRootNetId;

		public GameObject NetworktargetRoot
		{
			get
			{
				return targetRoot;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref targetRoot, 1u, ref ___targetRootNetId);
			}
		}

		public GameObject NetworkownerRoot
		{
			get
			{
				return ownerRoot;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref ownerRoot, 2u, ref ___ownerRootNetId);
			}
		}

		private void Awake()
		{
			bezierCurveLine = GetComponent<BezierCurveLine>();
		}

		private void DoDamageTick(bool mulch)
		{
			if (!targetHealthComponent)
			{
				targetHealthComponent = targetRoot.GetComponent<HealthComponent>();
			}
			if (!ownerHealthComponent)
			{
				ownerHealthComponent = ownerRoot.GetComponent<HealthComponent>();
			}
			if (!ownerBody)
			{
				ownerBody = ownerRoot.GetComponent<CharacterBody>();
			}
			if ((bool)ownerRoot)
			{
				DamageInfo damageInfo = new DamageInfo
				{
					position = targetRoot.transform.position,
					attacker = null,
					inflictor = null,
					damage = (mulch ? (damageCoefficientPerTick * mulchDamageScale) : damageCoefficientPerTick) * ownerBody.damage,
					damageColorIndex = DamageColorIndex.Default,
					damageType = DamageType.Generic,
					crit = false,
					force = UnityEngine.Vector3.zero,
					procChainMask = default(ProcChainMask),
					procCoefficient = 0f
				};
				targetHealthComponent.TakeDamage(damageInfo);
				if (!damageInfo.rejected)
				{
					ownerHealthComponent.Heal(damageInfo.damage, default(ProcChainMask));
				}
				if (!targetHealthComponent.alive)
				{
					NetworktargetRoot = null;
				}
			}
		}

		private UnityEngine.Vector3 GetTargetRootPosition()
		{
			if ((bool)targetRoot)
			{
				UnityEngine.Vector3 result = targetRoot.transform.position;
				if ((bool)targetHealthComponent)
				{
					result = targetHealthComponent.body.corePosition;
				}
				return result;
			}
			return base.transform.position;
		}

		private void Update()
		{
			age += Time.deltaTime;
			UnityEngine.Vector3 position = ownerRoot.transform.position;
			if (!beginSiphon)
			{
				UnityEngine.Vector3 position2 = UnityEngine.Vector3.Lerp(position, GetTargetRootPosition(), age / attachTime);
				bezierCurveLine.endTransform.position = position2;
			}
			else if ((bool)targetRoot)
			{
				bezierCurveLine.endTransform.position = targetRoot.transform.position;
			}
		}

		private void FixedUpdate()
		{
			fixedAge += Time.fixedDeltaTime;
			if ((bool)targetRoot && (bool)ownerRoot)
			{
				UnityEngine.Vector3 targetRootPosition = GetTargetRootPosition();
				if (!beginSiphon && fixedAge >= attachTime)
				{
					beginSiphon = true;
					return;
				}
				UnityEngine.Vector3 vector = ownerRoot.transform.position - targetRootPosition;
				if (NetworkServer.active)
				{
					float sqrMagnitude = vector.sqrMagnitude;
					bool flag = sqrMagnitude < mulchDistanceSqr;
					tickTimer -= Time.fixedDeltaTime;
					if (tickTimer <= 0f)
					{
						tickTimer += (flag ? (tickInterval * mulchTickIntervalScale) : tickInterval);
						DoDamageTick(flag);
					}
					if (sqrMagnitude > breakDistanceSqr)
					{
						UnityEngine.Object.Destroy(base.gameObject);
						return;
					}
				}
				if (!Util.HasEffectiveAuthority(targetRoot))
				{
					return;
				}
				UnityEngine.Vector3 vector2 = vector.normalized * (reelSpeed * Time.fixedDeltaTime);
				CharacterMotor component = targetRoot.GetComponent<CharacterMotor>();
				if ((bool)component)
				{
					component.rootMotion += vector2;
					return;
				}
				Rigidbody component2 = targetRoot.GetComponent<Rigidbody>();
				if ((bool)component2)
				{
					component2.velocity += vector2;
				}
			}
			else if (NetworkServer.active)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(targetRoot);
				writer.Write(ownerRoot);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(targetRoot);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(ownerRoot);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___targetRootNetId = reader.ReadNetworkId();
				___ownerRootNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				targetRoot = reader.ReadGameObject();
			}
			if (((uint)num & 2u) != 0)
			{
				ownerRoot = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___targetRootNetId.IsEmpty())
			{
				NetworktargetRoot = ClientScene.FindLocalObject(___targetRootNetId);
			}
			if (!___ownerRootNetId.IsEmpty())
			{
				NetworkownerRoot = ClientScene.FindLocalObject(___ownerRootNetId);
			}
		}
	}
	public class TeamAreaIndicator : MonoBehaviour
	{
		[Serializable]
		public struct TeamMaterialPair
		{
			public TeamIndex teamIndex;

			public Material sharedMaterial;
		}

		public TeamComponent teamComponent;

		public TeamFilter teamFilter;

		public TeamMaterialPair[] teamMaterialPairs;

		public Renderer[] areaIndicatorRenderers;

		private void Start()
		{
			if ((bool)teamFilter || (bool)teamComponent)
			{
				TeamIndex teamIndex = (teamFilter ? teamFilter.teamIndex : (teamComponent ? teamComponent.teamIndex : TeamIndex.None));
				for (int i = 0; i < teamMaterialPairs.Length; i++)
				{
					if (teamMaterialPairs[i].teamIndex == teamIndex)
					{
						Renderer[] array = areaIndicatorRenderers;
						for (int j = 0; j < array.Length; j++)
						{
							array[j].sharedMaterial = teamMaterialPairs[i].sharedMaterial;
						}
					}
				}
			}
			else
			{
				UnityEngine.Debug.LogWarning("No TeamFilter or TeamComponent assigned to TeamAreaIndicator.");
				base.gameObject.SetActive(value: false);
			}
		}
	}
	[DisallowMultipleComponent]
	public class TeamComponent : NetworkBehaviour, ILifeBehavior
	{
		public struct Team
		{
			public List<TeamComponent> members;

			public ReadOnlyCollection<TeamComponent> readOnlyMembers;

			public TeamIndex teamIndex;

			private int importanceCollection_;

			public int averageImportance;

			public int importanceCollection
			{
				get
				{
					return importanceCollection_;
				}
				set
				{
					importanceCollection_ = value;
					averageImportance = importanceCollection_ / ((members.Count == 0) ? 1 : members.Count);
				}
			}

			public void Init(TeamIndex index)
			{
				members = new List<TeamComponent>();
				readOnlyMembers = members.AsReadOnly();
				teamIndex = index;
			}
		}

		public bool hideAllyCardDisplay;

		[SerializeField]
		private TeamIndex _teamIndex = TeamIndex.None;

		private TeamIndex oldTeamIndex = TeamIndex.None;

		private GameObject defaultIndicatorPrefab;

		private GameObject indicator;

		private static readonly Queue<TeamComponent> indicatorSetupQueue;

		private static Team[] teamsList;

		private static ReadOnlyCollection<TeamComponent> emptyTeamMembers;

		public CharacterBody body { get; private set; }

		public TeamIndex teamIndex
		{
			get
			{
				return _teamIndex;
			}
			set
			{
				if (_teamIndex != value)
				{
					_teamIndex = value;
					if (Application.isPlaying)
					{
						SetDirtyBit(1u);
						OnChangeTeam(value);
					}
				}
			}
		}

		public static event Action<TeamComponent, TeamIndex> onJoinTeamGlobal;

		public static event Action<TeamComponent, TeamIndex> onLeaveTeamGlobal;

		private static bool TeamIsValid(TeamIndex teamIndex)
		{
			if (teamIndex >= TeamIndex.Neutral)
			{
				return teamIndex < TeamIndex.Count;
			}
			return false;
		}

		private void OnChangeTeam(TeamIndex newTeamIndex)
		{
			OnLeaveTeam(oldTeamIndex);
			OnJoinTeam(newTeamIndex);
		}

		private void OnLeaveTeam(TeamIndex oldTeamIndex)
		{
			if (TeamIsValid(oldTeamIndex))
			{
				teamsList[(int)oldTeamIndex].members.Remove(this);
			}
			TeamComponent.onLeaveTeamGlobal?.Invoke(this, oldTeamIndex);
		}

		private void OnJoinTeam(TeamIndex newTeamIndex)
		{
			if (TeamIsValid(newTeamIndex))
			{
				teamsList[(int)newTeamIndex].members.Add(this);
			}
			indicatorSetupQueue.Enqueue(this);
			HurtBox[] array = ((!body) ? null : body.hurtBoxGroup?.hurtBoxes);
			if (array != null)
			{
				HurtBox[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i].teamIndex = newTeamIndex;
				}
			}
			oldTeamIndex = newTeamIndex;
			TeamComponent.onJoinTeamGlobal?.Invoke(this, newTeamIndex);
		}

		private static void ProcessIndicatorSetupRequests()
		{
			while (indicatorSetupQueue.Count > 0)
			{
				TeamComponent teamComponent = indicatorSetupQueue.Dequeue();
				if ((bool)teamComponent)
				{
					try
					{
						teamComponent.SetupIndicator();
					}
					catch (Exception message)
					{
						UnityEngine.Debug.LogError(message);
					}
				}
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			RoR2Application.onFixedUpdate += ProcessIndicatorSetupRequests;
		}

		public void RequestDefaultIndicator(GameObject newIndicatorPrefab)
		{
			defaultIndicatorPrefab = newIndicatorPrefab;
			indicatorSetupQueue.Enqueue(this);
		}

		private void SetupIndicator()
		{
			if ((bool)indicator || !body)
			{
				return;
			}
			CharacterMaster master = body.master;
			bool flag = (bool)master && master.isBoss;
			GameObject gameObject = defaultIndicatorPrefab;
			if ((bool)master && teamIndex == TeamIndex.Player)
			{
				gameObject = LegacyResourcesAPI.Load<GameObject>(body.isPlayerControlled ? "Prefabs/PositionIndicators/PlayerPositionIndicator" : "Prefabs/PositionIndicators/NPCPositionIndicator");
			}
			else if (flag)
			{
				gameObject = LegacyResourcesAPI.Load<GameObject>("Prefabs/PositionIndicators/BossPositionIndicator");
			}
			if ((bool)indicator)
			{
				UnityEngine.Object.Destroy(indicator);
				indicator = null;
			}
			if ((bool)gameObject)
			{
				indicator = UnityEngine.Object.Instantiate(gameObject, base.transform);
				indicator.GetComponent<PositionIndicator>().targetTransform = body.coreTransform;
				Nameplate component = indicator.GetComponent<Nameplate>();
				if ((bool)component)
				{
					component.SetBody(body);
				}
			}
		}

		static TeamComponent()
		{
			indicatorSetupQueue = new Queue<TeamComponent>();
			emptyTeamMembers = new List<TeamComponent>().AsReadOnly();
			teamsList = new Team[5];
			for (int i = 0; i < teamsList.Length; i++)
			{
				teamsList[i].Init((TeamIndex)i);
			}
		}

		private void Awake()
		{
			body = GetComponent<CharacterBody>();
		}

		public void Start()
		{
			SetupIndicator();
			if (oldTeamIndex != teamIndex)
			{
				OnChangeTeam(teamIndex);
			}
		}

		private void OnDestroy()
		{
			teamIndex = TeamIndex.None;
		}

		public void OnDeathStart()
		{
			base.enabled = false;
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			writer.Write(teamIndex);
			if (!initialState)
			{
				return base.syncVarDirtyBits != 0;
			}
			return true;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			teamIndex = reader.ReadTeamIndex();
		}

		public static ReadOnlyCollection<TeamComponent> GetTeamMembers(TeamIndex teamIndex)
		{
			if (!TeamIsValid(teamIndex))
			{
				return emptyTeamMembers;
			}
			return teamsList[(int)teamIndex].readOnlyMembers;
		}

		public static TeamIndex GetObjectTeam(GameObject gameObject)
		{
			if ((bool)gameObject)
			{
				TeamComponent component = gameObject.GetComponent<TeamComponent>();
				if ((bool)component)
				{
					return component.teamIndex;
				}
			}
			return TeamIndex.None;
		}

		public static TeamIndex GetObjectTeam(TeamComponent teamComponent)
		{
			if ((bool)teamComponent)
			{
				return teamComponent.teamIndex;
			}
			return TeamIndex.None;
		}

		internal static int GetTeamAverageImportance(TeamComponent teamComponent)
		{
			if ((bool)teamComponent)
			{
				return teamsList[(int)teamComponent.teamIndex].averageImportance;
			}
			UnityEngine.Debug.LogError("Error: Tried to get average team importance using a null component reference");
			return -1;
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class TeamFilter : NetworkBehaviour
	{
		[SyncVar]
		private int teamIndexInternal;

		[SerializeField]
		private TeamIndex defaultTeam = TeamIndex.None;

		public TeamIndex teamIndex
		{
			get
			{
				return (TeamIndex)teamIndexInternal;
			}
			set
			{
				NetworkteamIndexInternal = (int)value;
				defaultTeam = value;
			}
		}

		public int NetworkteamIndexInternal
		{
			get
			{
				return teamIndexInternal;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref teamIndexInternal, 1u);
			}
		}

		public void Awake()
		{
			if (NetworkServer.active)
			{
				teamIndex = defaultTeam;
			}
		}

		[Server]
		public void SetTeamServer(string teamName)
		{
			TeamIndex result;
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeamFilter::SetTeamServer(System.String)' called on client");
			}
			else if (Enum.TryParse<TeamIndex>(teamName, out result))
			{
				teamIndex = result;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)teamIndexInternal);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)teamIndexInternal);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				teamIndexInternal = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				teamIndexInternal = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class TeamManager : NetworkBehaviour
	{
		public static readonly uint naturalLevelCap;

		private static readonly ulong[] levelToExperienceTable;

		public static readonly ulong hardExpCap;

		public static bool hasLongstandingSolitudeInParty;

		private ulong[] teamExperience = new ulong[5];

		private uint[] teamLevels = new uint[5];

		private ulong[] teamCurrentLevelExperience = new ulong[5];

		private ulong[] teamNextLevelExperience = new ulong[5];

		private const uint teamExperienceDirtyBitsMask = 31u;

		public static TeamManager instance { get; private set; }

		static TeamManager()
		{
			List<ulong> list = new List<ulong> { 0uL, 0uL };
			naturalLevelCap = 2u;
			while (true)
			{
				ulong num = (ulong)InitialCalcExperience(naturalLevelCap);
				if (num <= list[list.Count - 1])
				{
					break;
				}
				list.Add(num);
				naturalLevelCap++;
			}
			naturalLevelCap--;
			levelToExperienceTable = list.ToArray();
			hardExpCap = levelToExperienceTable[levelToExperienceTable.Length - 1];
		}

		private static double InitialCalcLevel(double experience, double experienceForFirstLevelUp = 20.0, double growthRate = 1.55)
		{
			return Math.Max(Math.Log(1.0 - experience / experienceForFirstLevelUp * (1.0 - growthRate), growthRate) + 1.0, 1.0);
		}

		public static double InitialCalcExperience(double level, double experienceForFirstLevelUp = 20.0, double growthRate = 1.55)
		{
			return Math.Max(experienceForFirstLevelUp * ((1.0 - Math.Pow(growthRate, level - 1.0)) / (1.0 - growthRate)), 0.0);
		}

		private static uint FindLevelForExperience(ulong experience)
		{
			for (uint num = 1u; num < levelToExperienceTable.Length; num++)
			{
				if (levelToExperienceTable[num] > experience)
				{
					return num - 1;
				}
			}
			return naturalLevelCap;
		}

		public static ulong GetExperienceForLevel(uint level)
		{
			if (level > naturalLevelCap)
			{
				level = naturalLevelCap;
			}
			return levelToExperienceTable[level];
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
				{
					SetTeamExperience(teamIndex, 0uL);
				}
			}
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		[Server]
		public void GiveTeamMoney(TeamIndex teamIndex, uint money)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeamManager::GiveTeamMoney(RoR2.TeamIndex,System.UInt32)' called on client");
				return;
			}
			int num = (Run.instance ? Run.instance.livingPlayerCount : 0);
			if (num != 0)
			{
				money = (uint)Mathf.CeilToInt((float)money / (float)num);
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				CharacterBody component = teamMembers[i].GetComponent<CharacterBody>();
				if ((bool)component && component.isPlayerControlled)
				{
					CharacterMaster master = component.master;
					if ((bool)master)
					{
						master.GiveMoney(money);
					}
				}
			}
		}

		[Server]
		public void GiveTeamExperience(TeamIndex teamIndex, ulong experience)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeamManager::GiveTeamExperience(RoR2.TeamIndex,System.UInt64)' called on client");
				return;
			}
			ulong num = teamExperience[(int)teamIndex];
			ulong num2 = num + experience;
			if (num2 < num)
			{
				num2 = ulong.MaxValue;
			}
			SetTeamExperience(teamIndex, num2);
			if (teamIndex != TeamIndex.Player)
			{
				return;
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				CharacterBody component = teamMembers[i].GetComponent<CharacterBody>();
				if ((bool)component)
				{
					CharacterMaster master = component.master;
					if ((bool)master)
					{
						master.TrackBeadExperience(experience);
					}
				}
			}
		}

		private void SetTeamExperience(TeamIndex teamIndex, ulong newExperience)
		{
			if (newExperience > hardExpCap)
			{
				newExperience = hardExpCap;
			}
			teamExperience[(int)teamIndex] = newExperience;
			uint num = teamLevels[(int)teamIndex];
			uint num2 = FindLevelForExperience(newExperience);
			if (num != num2)
			{
				ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
				for (int i = 0; i < teamMembers.Count; i++)
				{
					CharacterBody component = teamMembers[i].GetComponent<CharacterBody>();
					if ((bool)component)
					{
						component.OnTeamLevelChanged();
					}
				}
				teamLevels[(int)teamIndex] = num2;
				teamCurrentLevelExperience[(int)teamIndex] = GetExperienceForLevel(num2);
				teamNextLevelExperience[(int)teamIndex] = GetExperienceForLevel(num2 + 1);
				if (num < num2)
				{
					GlobalEventManager.OnTeamLevelUp(teamIndex);
				}
			}
			if (NetworkServer.active)
			{
				SetDirtyBit((uint)(1 << (int)teamIndex));
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = (initialState ? 31u : base.syncVarDirtyBits);
			writer.WritePackedUInt32(num);
			if (num == 0)
			{
				return false;
			}
			for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
			{
				if ((num & (uint)(1 << (int)teamIndex)) != 0)
				{
					writer.WritePackedUInt64(teamExperience[(int)teamIndex]);
				}
			}
			return true;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			uint num = reader.ReadPackedUInt32();
			for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
			{
				if ((num & (uint)(1 << (int)teamIndex)) != 0)
				{
					ulong newExperience = reader.ReadPackedUInt64();
					SetTeamExperience(teamIndex, newExperience);
				}
			}
		}

		public ulong GetTeamExperience(TeamIndex teamIndex)
		{
			if (teamIndex < TeamIndex.Neutral || teamIndex >= TeamIndex.Count)
			{
				return 0uL;
			}
			return teamExperience[(int)teamIndex];
		}

		public ulong GetTeamCurrentLevelExperience(TeamIndex teamIndex)
		{
			if (teamIndex < TeamIndex.Neutral || teamIndex >= TeamIndex.Count)
			{
				return 0uL;
			}
			return teamCurrentLevelExperience[(int)teamIndex];
		}

		public ulong GetTeamNextLevelExperience(TeamIndex teamIndex)
		{
			if (teamIndex < TeamIndex.Neutral || teamIndex >= TeamIndex.Count)
			{
				return 0uL;
			}
			return teamNextLevelExperience[(int)teamIndex];
		}

		public uint GetTeamLevel(TeamIndex teamIndex)
		{
			if (teamIndex < TeamIndex.Neutral || teamIndex >= TeamIndex.Count)
			{
				return 0u;
			}
			return teamLevels[(int)teamIndex];
		}

		public void SetTeamLevel(TeamIndex teamIndex, uint newLevel)
		{
			if (teamIndex >= TeamIndex.Neutral && teamIndex < TeamIndex.Count && GetTeamLevel(teamIndex) != newLevel)
			{
				SetTeamExperience(teamIndex, GetExperienceForLevel(newLevel));
			}
		}

		public static bool IsTeamEnemy(TeamIndex teamA, TeamIndex teamB)
		{
			if (teamA != teamB)
			{
				return true;
			}
			return false;
		}

		[ConCommand(commandName = "team_set_level", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Sets the team specified by the first argument to the level specified by the second argument.")]
		private static void CCTeamSetLevel(ConCommandArgs args)
		{
			TeamIndex argEnum = args.GetArgEnum<TeamIndex>(0);
			ulong argULong = args.GetArgULong(1);
			if (!instance)
			{
				throw new ConCommandException("No TeamManager exists.");
			}
			instance.SetTeamLevel(argEnum, (uint)argULong);
		}

		public void GiveTeamMoney(TeamIndex teamIndex, int amount)
		{
			if (teamIndex < TeamIndex.Neutral || teamIndex >= TeamIndex.Count)
			{
				return;
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				CharacterBody component = teamMembers[i].GetComponent<CharacterBody>();
				if ((bool)component)
				{
					component.master.money += (uint)amount;
				}
			}
		}

		[ConCommand(commandName = "team_give_money", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "Gives the team specified by first argument the amount of money set by the second argument")]
		private static void CCTeamGiveMoney(ConCommandArgs args)
		{
			TeamIndex argEnum = args.GetArgEnum<TeamIndex>(0);
			int argInt = args.GetArgInt(1);
			if (!instance)
			{
				throw new ConCommandException("No TeamManager exists.");
			}
			instance.GiveTeamMoney(argEnum, argInt);
		}

		public void GiveTeamItem(TeamIndex teamIndex, ItemIndex itemIndex, int count)
		{
			if (teamIndex < TeamIndex.Neutral || teamIndex >= TeamIndex.Count)
			{
				return;
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				CharacterBody component = teamMembers[i].GetComponent<CharacterBody>();
				if ((bool)component && (bool)component.inventory)
				{
					component.inventory.GiveItem(itemIndex, count);
				}
			}
		}

		[ConCommand(commandName = "team_give_item", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "First argument is team index. Second argument is item. Third argument specifies stack.")]
		private static void CCTeamGiveItem(ConCommandArgs args)
		{
			if (args.Count != 0)
			{
				TeamIndex argEnum = args.GetArgEnum<TeamIndex>(0);
				ItemIndex argItemIndex = args.GetArgItemIndex(1);
				int count = args.TryGetArgInt(2) ?? 1;
				if (!instance)
				{
					throw new ConCommandException("No TeamManager exists.");
				}
				instance.GiveTeamItem(argEnum, argItemIndex, count);
			}
		}

		public static int LongstandingSolitudesInParty()
		{
			int num = 0;
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if ((bool)instance && (bool)instance.master && (bool)instance.master.GetBody())
				{
					CharacterBody body = instance.master.GetBody();
					if ((bool)body && body.inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock) > 0)
					{
						hasLongstandingSolitudeInParty = true;
						num += body.inventory.GetItemCount(DLC2Content.Items.OnLevelUpFreeUnlock);
					}
				}
			}
			return num;
		}

		public uint FindLevelForBeadExperience(ulong experience)
		{
			return FindLevelForExperience(experience);
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(HoldoutZoneController))]
	[RequireComponent(typeof(SceneExitController))]
	public sealed class TeleporterInteraction : NetworkBehaviour, IInteractable
	{
		public enum ActivationState
		{
			Idle,
			IdleToCharging,
			Charging,
			Charged,
			Finished
		}

		private abstract class BaseTeleporterState : BaseState
		{
			protected TeleporterInteraction teleporterInteraction { get; private set; }

			public abstract ActivationState backwardsCompatibleActivationState { get; }

			protected virtual bool shouldEnableChargingSphere => false;

			public override void OnEnter()
			{
				base.OnEnter();
				teleporterInteraction = GetComponent<TeleporterInteraction>();
				teleporterInteraction.holdoutZoneController.enabled = shouldEnableChargingSphere;
			}

			public virtual Interactability GetInteractability(Interactor activator)
			{
				return Interactability.Disabled;
			}

			public virtual string GetContextString(Interactor activator)
			{
				return null;
			}

			public virtual void OnInteractionBegin(Interactor activator)
			{
			}

			protected void SetChildActive(string childLocatorName, bool newActive)
			{
				Transform transform = teleporterInteraction.modelChildLocator.FindChild(childLocatorName);
				if ((bool)transform)
				{
					transform.gameObject.SetActive(newActive);
				}
			}
		}

		private class IdleState : BaseTeleporterState
		{
			private float _tutorialWavePillarTimer;

			private bool _canTutorialWavePillarTrigger = TutorialManager.isTutorialEnabled;

			public override ActivationState backwardsCompatibleActivationState => ActivationState.Idle;

			public override Interactability GetInteractability(Interactor activator)
			{
				return Interactability.Available;
			}

			public override string GetContextString(Interactor activator)
			{
				return Language.GetString(base.teleporterInteraction.beginContextString);
			}

			public override void OnInteractionBegin(Interactor activator)
			{
				Chat.SendBroadcastChat(new SubjectChatMessage
				{
					subjectAsCharacterBody = activator.GetComponent<CharacterBody>(),
					baseToken = "PLAYER_ACTIVATED_TELEPORTER"
				});
				if (base.teleporterInteraction.showExtraBossesIndicator)
				{
					Chat.SendBroadcastChat(new Chat.SimpleChatMessage
					{
						baseToken = "SHRINE_BOSS_BEGIN_TRIAL"
					});
				}
				base.teleporterInteraction.chargeActivatorServer = activator.gameObject;
				outer.SetNextState(new IdleToChargingState());
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (!_canTutorialWavePillarTrigger)
				{
					return;
				}
				_tutorialWavePillarTimer -= Time.fixedDeltaTime;
				if (_tutorialWavePillarTimer < 0f)
				{
					_tutorialWavePillarTimer = base.teleporterInteraction.triggerWavePillarInterval;
					if (Run.instance.ambientLevel >= base.teleporterInteraction.sceneStartAmbientLevel + 2f)
					{
						_canTutorialWavePillarTrigger = false;
						SetChildActive("TutorialWavePillar", newActive: true);
					}
				}
			}

			public override void OnExit()
			{
				base.OnExit();
				SetChildActive("TutorialWavePillar", newActive: false);
			}
		}

		private class IdleToChargingState : BaseTeleporterState
		{
			public override ActivationState backwardsCompatibleActivationState => ActivationState.IdleToCharging;

			public override void OnEnter()
			{
				base.OnEnter();
				SetChildActive("IdleToChargingEffect", newActive: true);
				SetChildActive("PPVolume", newActive: true);
				base.teleporterInteraction.NetworkisActivated = true;
				base.teleporterInteraction.teleporterPositionIndicator.GetComponent<ChargeIndicatorController>().isActivated = true;
			}

			public override void OnExit()
			{
				SetChildActive("IdleToChargingEffect", newActive: false);
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (base.fixedAge > 3f && NetworkServer.active)
				{
					outer.SetNextState(new ChargingState());
				}
			}
		}

		private class ChargingState : BaseTeleporterState
		{
			private CombatDirector bonusDirector => base.teleporterInteraction.bonusDirector;

			private CombatDirector bossDirector => base.teleporterInteraction.bossDirector;

			protected override bool shouldEnableChargingSphere => true;

			public override ActivationState backwardsCompatibleActivationState => ActivationState.Charging;

			public override void OnEnter()
			{
				base.OnEnter();
				TeleporterInteraction.onTeleporterBeginChargingGlobal?.Invoke(base.teleporterInteraction);
				if (NetworkServer.active)
				{
					if ((bool)bonusDirector)
					{
						bonusDirector.enabled = true;
					}
					if ((bool)bossDirector)
					{
						bossDirector.enabled = true;
						bossDirector.monsterCredit += (int)(600f * Mathf.Pow(Run.instance.compensatedDifficultyCoefficient, 0.5f) * (float)(1 + base.teleporterInteraction.shrineBonusStacks));
						bossDirector.currentSpawnTarget = base.gameObject;
						bossDirector.SetNextSpawnAsBoss();
					}
					if ((bool)DirectorCore.instance)
					{
						CombatDirector[] components = DirectorCore.instance.GetComponents<CombatDirector>();
						if (components.Length != 0)
						{
							CombatDirector[] array = components;
							for (int i = 0; i < array.Length; i++)
							{
								array[i].enabled = false;
							}
						}
					}
					if ((bool)base.teleporterInteraction.outsideInteractableLocker)
					{
						base.teleporterInteraction.outsideInteractableLocker.enabled = true;
					}
					ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Player);
					for (int j = 0; j < teamMembers.Count; j++)
					{
						TeamComponent teamComponent = teamMembers[j];
						CharacterBody body = teamComponent.body;
						if (!body)
						{
							continue;
						}
						CharacterMaster master = teamComponent.body.master;
						if ((bool)master)
						{
							int itemCount = master.inventory.GetItemCount(RoR2Content.Items.WardOnLevel);
							if (itemCount > 0)
							{
								GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/WarbannerWard"), body.transform.position, UnityEngine.Quaternion.identity);
								obj.GetComponent<TeamFilter>().teamIndex = TeamIndex.Player;
								obj.GetComponent<BuffWard>().Networkradius = 8f + 8f * (float)itemCount;
								NetworkServer.Spawn(obj);
							}
						}
					}
				}
				SetChildActive("ChargingEffect", newActive: true);
			}

			public override void OnExit()
			{
				if (NetworkServer.active)
				{
					if ((bool)base.teleporterInteraction.outsideInteractableLocker)
					{
						base.teleporterInteraction.outsideInteractableLocker.enabled = false;
					}
					if ((bool)bossDirector)
					{
						bossDirector.enabled = false;
					}
					if ((bool)bonusDirector)
					{
						bonusDirector.enabled = false;
					}
				}
				SetChildActive("ChargingEffect", newActive: false);
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (NetworkServer.active)
				{
					if (base.teleporterInteraction.holdoutZoneController.charge >= 1f)
					{
						if ((bool)bonusDirector)
						{
							bonusDirector.enabled = false;
						}
						if (base.teleporterInteraction.monstersCleared)
						{
							if ((bool)bossDirector)
							{
								bossDirector.enabled = false;
							}
							outer.SetNextState(new ChargedState());
						}
					}
					if ((bool)base.teleporterInteraction.outsideInteractableLocker)
					{
						base.teleporterInteraction.outsideInteractableLocker.radius = base.teleporterInteraction.holdoutZoneController.currentRadius;
					}
				}
				if ((bool)SceneWeatherController.instance)
				{
					SceneWeatherController.instance.weatherLerp = SceneWeatherController.instance.weatherLerpOverChargeTime.Evaluate((float)base.teleporterInteraction.chargePercent * 0.01f);
				}
				base.teleporterInteraction.UpdateMonstersClear();
			}

			public override Interactability GetInteractability(Interactor activator)
			{
				return Interactability.ConditionsNotMet;
			}
		}

		private class ChargedState : BaseTeleporterState
		{
			public override ActivationState backwardsCompatibleActivationState => ActivationState.Charged;

			public override void OnEnter()
			{
				base.OnEnter();
				base.teleporterInteraction.teleporterPositionIndicator.GetComponent<ChargeIndicatorController>().isCharged = true;
				SetChildActive("ChargedEffect", newActive: true);
				if (NetworkServer.active)
				{
					base.teleporterInteraction.AttemptToSpawnAllEligiblePortals();
					if (RunArtifactManager.instance.IsArtifactEnabled(CU8Content.Artifacts.Delusion))
					{
						ResetChests();
					}
				}
				TeleporterInteraction.onTeleporterChargedGlobal?.Invoke(base.teleporterInteraction);
			}

			private void ResetChests()
			{
				foreach (ChestBehavior instances in InstanceTracker.GetInstancesList<ChestBehavior>())
				{
					instances.CallRpcResetChests();
				}
			}

			public override void OnExit()
			{
				SetChildActive("ChargedEffect", newActive: false);
				base.OnExit();
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
			}

			public override Interactability GetInteractability(Interactor activator)
			{
				if (!base.teleporterInteraction.monstersCleared)
				{
					return Interactability.ConditionsNotMet;
				}
				return Interactability.Available;
			}

			public override string GetContextString(Interactor activator)
			{
				return Language.GetString(base.teleporterInteraction.exitContextString);
			}

			public override void OnInteractionBegin(Interactor activator)
			{
				outer.SetNextState(new FinishedState());
			}
		}

		private class FinishedState : BaseTeleporterState
		{
			public override ActivationState backwardsCompatibleActivationState => ActivationState.Finished;

			public override void OnEnter()
			{
				base.OnEnter();
				base.teleporterInteraction.sceneExitController.Begin();
				TeleporterInteraction.onTeleporterFinishGlobal?.Invoke(base.teleporterInteraction);
			}
		}

		[Header("Component and Object References")]
		public CombatDirector bonusDirector;

		public CombatDirector bossDirector;

		public EntityStateMachine mainStateMachine;

		public OutsideInteractableLocker outsideInteractableLocker;

		[Header("Interactability")]
		public string beginContextString;

		public string exitContextString;

		[Header("Teleporter Tutorial")]
		public float triggerWavePillarInterval = 1f;

		private Dictionary<PurchaseInteraction, GameObject> interactableObjectMap;

		private BossGroup bossGroup;

		private ChildLocator modelChildLocator;

		[SyncVar]
		private bool _locked;

		[SyncVar(hook = "OnSyncTeleporterDiscovered")]
		private bool isDiscovered;

		[SyncVar]
		private bool isActivated;

		[SerializeField]
		private float discoveryRadius = 20f;

		private PositionIndicator teleporterPositionIndicator;

		private ChargeIndicatorController teleporterChargeIndicatorController;

		private UnityEngine.Color originalTeleporterColor;

		private GameObject bossShrineIndicator;

		[SyncVar(hook = "OnSyncShouldAttemptToSpawnShopPortal")]
		private bool _shouldAttemptToSpawnShopPortal;

		[SyncVar(hook = "OnSyncShouldAttemptToSpawnGoldshoresPortal")]
		private bool _shouldAttemptToSpawnGoldshoresPortal;

		[SyncVar(hook = "OnSyncShouldAttemptToSpawnMSPortal")]
		private bool _shouldAttemptToSpawnMSPortal;

		private Xoroshiro128Plus rng;

		private GameObject chargeActivatorServer;

		private bool monstersCleared;

		[SyncVar]
		private bool showExtraBossesIndicator;

		public SpawnCard shopPortalSpawnCard;

		public SpawnCard goldshoresPortalSpawnCard;

		public SpawnCard msPortalSpawnCard;

		public PortalSpawner[] portalSpawners;

		public float baseShopSpawnChance = 0.375f;

		private List<PingIndicator> currentPings = new List<PingIndicator>();

		private Particle_SetMinSize cachedParticleMinSizeScript;

		private float particleScaleUpdateTimer;

		private const float particleScaleUpdateInterval = 0.5f;

		private bool shouldScaleParticles;

		private LocalUser cachedLocalUser;

		private static int kRpcRpcClientOnActivated;

		public float sceneStartAmbientLevel { get; private set; }

		public HoldoutZoneController holdoutZoneController { get; private set; }

		public SceneExitController sceneExitController { get; private set; }

		private BaseTeleporterState currentState => mainStateMachine.state as BaseTeleporterState;

		public ActivationState activationState => currentState?.backwardsCompatibleActivationState ?? ActivationState.Idle;

		public bool locked
		{
			get
			{
				return _locked;
			}
			set
			{
				Network_locked = value;
			}
		}

		public bool isIdle => currentState is IdleState;

		public bool isIdleToCharging => currentState is IdleToChargingState;

		public bool isInFinalSequence => currentState is FinishedState;

		public bool isCharging => currentState is ChargingState;

		public bool isCharged => activationState >= ActivationState.Charged;

		public float chargeFraction => holdoutZoneController.charge;

		public int shrineBonusStacks { get; set; }

		private int chargePercent => holdoutZoneController.displayChargePercent;

		public static TeleporterInteraction instance { get; private set; }

		public bool shouldAttemptToSpawnShopPortal
		{
			get
			{
				return _shouldAttemptToSpawnShopPortal;
			}
			set
			{
				if (_shouldAttemptToSpawnShopPortal != value)
				{
					Network_shouldAttemptToSpawnShopPortal = value;
					if (_shouldAttemptToSpawnShopPortal && NetworkServer.active)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "PORTAL_SHOP_WILL_OPEN"
						});
					}
				}
			}
		}

		public bool shouldAttemptToSpawnGoldshoresPortal
		{
			get
			{
				return _shouldAttemptToSpawnGoldshoresPortal;
			}
			set
			{
				if (_shouldAttemptToSpawnGoldshoresPortal != value)
				{
					Network_shouldAttemptToSpawnGoldshoresPortal = value;
					if (_shouldAttemptToSpawnGoldshoresPortal && NetworkServer.active)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "PORTAL_GOLDSHORES_WILL_OPEN"
						});
					}
				}
			}
		}

		public bool shouldAttemptToSpawnMSPortal
		{
			get
			{
				return _shouldAttemptToSpawnMSPortal;
			}
			set
			{
				if (_shouldAttemptToSpawnMSPortal != value)
				{
					Network_shouldAttemptToSpawnMSPortal = value;
					if (_shouldAttemptToSpawnMSPortal && NetworkServer.active)
					{
						Chat.SendBroadcastChat(new Chat.SimpleChatMessage
						{
							baseToken = "PORTAL_MS_WILL_OPEN"
						});
					}
				}
			}
		}

		public bool Network_locked
		{
			get
			{
				return _locked;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _locked, 1u);
			}
		}

		public bool NetworkisDiscovered
		{
			get
			{
				return isDiscovered;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncTeleporterDiscovered(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref isDiscovered, 2u);
			}
		}

		public bool NetworkisActivated
		{
			get
			{
				return isActivated;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref isActivated, 4u);
			}
		}

		public bool Network_shouldAttemptToSpawnShopPortal
		{
			get
			{
				return _shouldAttemptToSpawnShopPortal;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncShouldAttemptToSpawnShopPortal(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref _shouldAttemptToSpawnShopPortal, 8u);
			}
		}

		public bool Network_shouldAttemptToSpawnGoldshoresPortal
		{
			get
			{
				return _shouldAttemptToSpawnGoldshoresPortal;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncShouldAttemptToSpawnGoldshoresPortal(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref _shouldAttemptToSpawnGoldshoresPortal, 16u);
			}
		}

		public bool Network_shouldAttemptToSpawnMSPortal
		{
			get
			{
				return _shouldAttemptToSpawnMSPortal;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncShouldAttemptToSpawnMSPortal(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref _shouldAttemptToSpawnMSPortal, 32u);
			}
		}

		public bool NetworkshowExtraBossesIndicator
		{
			get
			{
				return showExtraBossesIndicator;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref showExtraBossesIndicator, 64u);
			}
		}

		public static event Action<TeleporterInteraction> onTeleporterBeginChargingGlobal;

		public static event Action<TeleporterInteraction> onTeleporterChargedGlobal;

		public static event Action<TeleporterInteraction> onTeleporterFinishGlobal;

		private void OnSyncShouldAttemptToSpawnShopPortal(bool newValue)
		{
			Network_shouldAttemptToSpawnShopPortal = newValue;
			if ((bool)modelChildLocator)
			{
				modelChildLocator.FindChild("ShopPortalIndicator").gameObject.SetActive(newValue);
			}
		}

		private void OnSyncShouldAttemptToSpawnGoldshoresPortal(bool newValue)
		{
			Network_shouldAttemptToSpawnGoldshoresPortal = newValue;
			if ((bool)modelChildLocator)
			{
				modelChildLocator.FindChild("GoldshoresPortalIndicator").gameObject.SetActive(newValue);
			}
		}

		private void OnSyncShouldAttemptToSpawnMSPortal(bool newValue)
		{
			Network_shouldAttemptToSpawnMSPortal = newValue;
			if ((bool)modelChildLocator)
			{
				modelChildLocator.FindChild("MSPortalIndicator").gameObject.SetActive(newValue);
			}
		}

		private void OnSyncTeleporterDiscovered(bool newValue)
		{
			NetworkisDiscovered = newValue;
			ChargeIndicatorController component = teleporterPositionIndicator.GetComponent<ChargeIndicatorController>();
			if ((object)component != null)
			{
				component.isDiscovered = newValue;
				if (newValue)
				{
					component.TriggerPingAnimation();
				}
			}
		}

		private void Awake()
		{
			modelChildLocator = GetComponent<ModelLocator>().modelTransform.GetComponent<ChildLocator>();
			holdoutZoneController = GetComponent<HoldoutZoneController>();
			sceneExitController = GetComponent<SceneExitController>();
			bossShrineIndicator = modelChildLocator.FindChild("BossShrineSymbol").gameObject;
			bossGroup = GetComponent<BossGroup>();
			if (NetworkServer.active && (bool)bossDirector)
			{
				bossDirector.onSpawnedServer.AddListener(OnBossDirectorSpawnedMonsterServer);
			}
			teleporterPositionIndicator = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/PositionIndicators/TeleporterChargingPositionIndicator"), base.transform.position, UnityEngine.Quaternion.identity).GetComponent<PositionIndicator>();
			teleporterPositionIndicator.targetTransform = base.transform;
			teleporterChargeIndicatorController = teleporterPositionIndicator.GetComponent<ChargeIndicatorController>();
			teleporterChargeIndicatorController.holdoutZoneController = holdoutZoneController;
			teleporterPositionIndicator.gameObject.SetActive(value: false);
			Particle_SetMinSize component = modelChildLocator.FindChild("PassiveParticleSphere").GetComponent<Particle_SetMinSize>();
			if ((object)component != null)
			{
				cachedParticleMinSizeScript = component;
			}
			else
			{
				UnityEngine.Debug.LogWarning("TeleporterInteraction could not get PassiveParticleSphere's Particle_SetMinSize. Make sure it's set in the Child Locator");
			}
			cachedLocalUser = ((MPEventSystem)EventSystem.current)?.localUser;
		}

		private void OnDestroy()
		{
			if ((bool)teleporterPositionIndicator)
			{
				UnityEngine.Object.Destroy(teleporterPositionIndicator.gameObject);
				teleporterPositionIndicator = null;
				teleporterChargeIndicatorController = null;
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			InstanceTracker.Add(this);
			sceneStartAmbientLevel = Run.instance.ambientLevel;
		}

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong);
				Run.instance.PickNextStageSceneFromCurrentSceneDestinations();
				float nextNormalizedFloat = rng.nextNormalizedFloat;
				float num = baseShopSpawnChance / (float)(Run.instance.shopPortalCount + 1);
				shouldAttemptToSpawnShopPortal = nextNormalizedFloat < num;
				int stageClearCount = Run.instance.stageClearCount;
				if ((stageClearCount + 1) % Run.stagesPerLoop == 3 && stageClearCount > Run.stagesPerLoop && !Run.instance.GetEventFlag("NoMysterySpace"))
				{
					shouldAttemptToSpawnMSPortal = true;
				}
			}
			if (base.isClient)
			{
				OnSyncTeleporterDiscovered(isDiscovered);
				teleporterPositionIndicator.GetComponent<ChargeIndicatorController>().isActivated = isActivated;
				teleporterPositionIndicator.GetComponent<ChargeIndicatorController>().isCharged = isCharged;
			}
		}

		public void FixedUpdate()
		{
			bossShrineIndicator.SetActive(showExtraBossesIndicator && !isCharged);
			teleporterPositionIndicator.gameObject.SetActive(!isIdle || (isDiscovered && cachedLocalUser.userProfile.useTeleporterDiscoveryIndicator) || currentPings.Count > 0);
			if (base.hasAuthority && !isDiscovered && HoldoutZoneController.CountPlayersInRadius(holdoutZoneController, base.transform.position, discoveryRadius * discoveryRadius, TeamIndex.Player) > 0)
			{
				NetworkisDiscovered = true;
				teleporterPositionIndicator.GetComponent<ChargeIndicatorController>().isDiscovered = true;
				teleporterPositionIndicator.GetComponent<ChargeIndicatorController>().TriggerPingAnimation();
			}
			if (cachedLocalUser != null && cachedLocalUser.userProfile.useTeleporterParticleScaling)
			{
				shouldScaleParticles = true;
				particleScaleUpdateTimer -= Time.fixedDeltaTime;
				if (particleScaleUpdateTimer <= 0f)
				{
					particleScaleUpdateTimer = 0.5f;
					cachedParticleMinSizeScript.SetEnabled(isEnabled: true);
				}
			}
			else if (shouldScaleParticles)
			{
				shouldScaleParticles = false;
				cachedParticleMinSizeScript.SetEnabled(isEnabled: false);
			}
		}

		public string GetContextString(Interactor activator)
		{
			return currentState?.GetContextString(activator);
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (locked)
			{
				return Interactability.Disabled;
			}
			return currentState?.GetInteractability(activator) ?? Interactability.Disabled;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			CallRpcClientOnActivated(activator.gameObject);
			currentState?.OnInteractionBegin(activator);
		}

		public bool ShouldShowOnScanner()
		{
			return true;
		}

		public bool ShouldProximityHighlight()
		{
			return true;
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		[ConCommand(commandName = "activate_teleporter", flags = ConVarFlags.None, helpText = "Activates teleporter")]
		private static void ActivateTeleporter(ConCommandArgs args)
		{
			Interactor component = TeamComponent.GetTeamMembers(TeamIndex.Player)[0].GetComponent<Interactor>();
			if ((bool)component)
			{
				instance.CallRpcClientOnActivated(component.gameObject);
				instance.currentState?.OnInteractionBegin(component);
				CharacterBody component2 = component.GetComponent<CharacterBody>();
				if ((bool)component2)
				{
					TeleportHelper.TeleportBody(component2, instance.transform.position);
				}
			}
		}

		[ClientRpc]
		private void RpcClientOnActivated(GameObject activatorObject)
		{
			Util.PlaySound("Play_env_teleporter_active_button", base.gameObject);
		}

		private void UpdateMonstersClear()
		{
			monstersCleared = !bossGroup.enabled;
		}

		[Server]
		public void AddShrineStack()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeleporterInteraction::AddShrineStack()' called on client");
			}
			else if (activationState <= ActivationState.IdleToCharging)
			{
				BossGroup obj = bossGroup;
				int bonusRewardCount = obj.bonusRewardCount + 1;
				obj.bonusRewardCount = bonusRewardCount;
				shrineBonusStacks++;
				NetworkshowExtraBossesIndicator = true;
			}
		}

		[Obsolete]
		public bool IsInChargingRange(CharacterBody body)
		{
			return holdoutZoneController.IsBodyInChargingRadius(body);
		}

		private void OnBossDirectorSpawnedMonsterServer(GameObject masterObject)
		{
			BaseAI ai;
			if ((bool)chargeActivatorServer)
			{
				ai = masterObject.GetComponent<BaseAI>();
				if ((bool)ai)
				{
					ai.onBodyDiscovered += AiOnBodyDiscovered;
				}
			}
			void AiOnBodyDiscovered(CharacterBody newBody)
			{
				ai.currentEnemy.gameObject = chargeActivatorServer;
				ai.onBodyDiscovered -= AiOnBodyDiscovered;
			}
		}

		[Server]
		private void AttemptToSpawnAllEligiblePortals()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeleporterInteraction::AttemptToSpawnAllEligiblePortals()' called on client");
				return;
			}
			if (shouldAttemptToSpawnShopPortal)
			{
				AttemptToSpawnShopPortal();
			}
			if (shouldAttemptToSpawnGoldshoresPortal)
			{
				AttemptToSpawnGoldshoresPortal();
			}
			if (shouldAttemptToSpawnMSPortal)
			{
				AttemptToSpawnMSPortal();
			}
			PortalSpawner[] array = portalSpawners;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].AttemptSpawnPortalServer();
			}
		}

		private bool AttemptSpawnPortal(SpawnCard portalSpawnCard, float minDistance, float maxDistance, string successChatToken)
		{
			GameObject obj = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(portalSpawnCard, new DirectorPlacementRule
			{
				minDistance = minDistance,
				maxDistance = maxDistance,
				placementMode = DirectorPlacementRule.PlacementMode.Approximate,
				position = base.transform.position,
				spawnOnTarget = base.transform
			}, rng));
			if ((bool)obj)
			{
				Chat.SendBroadcastChat(new Chat.SimpleChatMessage
				{
					baseToken = successChatToken
				});
			}
			return obj;
		}

		[Server]
		private void AttemptToSpawnShopPortal()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeleporterInteraction::AttemptToSpawnShopPortal()' called on client");
			}
			else if (AttemptSpawnPortal(shopPortalSpawnCard, 0f, 30f, "PORTAL_SHOP_OPEN"))
			{
				Run.instance.shopPortalCount++;
			}
		}

		[Server]
		private void AttemptToSpawnGoldshoresPortal()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeleporterInteraction::AttemptToSpawnGoldshoresPortal()' called on client");
			}
			else
			{
				AttemptSpawnPortal(goldshoresPortalSpawnCard, 10f, 40f, "PORTAL_GOLDSHORES_OPEN");
			}
		}

		[Server]
		private void AttemptToSpawnMSPortal()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TeleporterInteraction::AttemptToSpawnMSPortal()' called on client");
			}
			else
			{
				AttemptSpawnPortal(msPortalSpawnCard, 10f, 40f, "PORTAL_MS_OPEN");
			}
		}

		public void PingTeleporter(string pingOwnerName, PingIndicator pingObject)
		{
			if ((bool)pingObject)
			{
				if (base.hasAuthority)
				{
					NetworkisDiscovered = true;
				}
				currentPings.Add(pingObject);
				teleporterPositionIndicator.GetComponent<ChargeIndicatorController>()?.TriggerPing(pingOwnerName);
			}
		}

		public void CancelTeleporterPing(PingIndicator cancelledPingObject)
		{
			if ((bool)cancelledPingObject && currentPings.Contains(cancelledPingObject))
			{
				currentPings.Remove(cancelledPingObject);
			}
			ChargeIndicatorController component = teleporterPositionIndicator.GetComponent<ChargeIndicatorController>();
			if (!component)
			{
				return;
			}
			int num = currentPings.Count - 1;
			while (num >= 0)
			{
				if (!currentPings[num])
				{
					currentPings.RemoveAt(num);
					num--;
					continue;
				}
				component.TriggerPing(currentPings[num].GetOwnerName(), triggerAnimation: false);
				return;
			}
			component.isPinged = false;
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcClientOnActivated(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcClientOnActivated called on server.");
			}
			else
			{
				((TeleporterInteraction)obj).RpcClientOnActivated(reader.ReadGameObject());
			}
		}

		public void CallRpcClientOnActivated(GameObject activatorObject)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcClientOnActivated called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcClientOnActivated);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(activatorObject);
			SendRPCInternal(networkWriter, 0, "RpcClientOnActivated");
		}

		static TeleporterInteraction()
		{
			kRpcRpcClientOnActivated = 1157394167;
			NetworkBehaviour.RegisterRpcDelegate(typeof(TeleporterInteraction), kRpcRpcClientOnActivated, InvokeRpcRpcClientOnActivated);
			NetworkCRC.RegisterBehaviour("TeleporterInteraction", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_locked);
				writer.Write(isDiscovered);
				writer.Write(isActivated);
				writer.Write(_shouldAttemptToSpawnShopPortal);
				writer.Write(_shouldAttemptToSpawnGoldshoresPortal);
				writer.Write(_shouldAttemptToSpawnMSPortal);
				writer.Write(showExtraBossesIndicator);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_locked);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(isDiscovered);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(isActivated);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_shouldAttemptToSpawnShopPortal);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_shouldAttemptToSpawnGoldshoresPortal);
			}
			if ((base.syncVarDirtyBits & 0x20u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_shouldAttemptToSpawnMSPortal);
			}
			if ((base.syncVarDirtyBits & 0x40u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(showExtraBossesIndicator);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_locked = reader.ReadBoolean();
				isDiscovered = reader.ReadBoolean();
				isActivated = reader.ReadBoolean();
				_shouldAttemptToSpawnShopPortal = reader.ReadBoolean();
				_shouldAttemptToSpawnGoldshoresPortal = reader.ReadBoolean();
				_shouldAttemptToSpawnMSPortal = reader.ReadBoolean();
				showExtraBossesIndicator = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_locked = reader.ReadBoolean();
			}
			if (((uint)num & 2u) != 0)
			{
				OnSyncTeleporterDiscovered(reader.ReadBoolean());
			}
			if (((uint)num & 4u) != 0)
			{
				isActivated = reader.ReadBoolean();
			}
			if (((uint)num & 8u) != 0)
			{
				OnSyncShouldAttemptToSpawnShopPortal(reader.ReadBoolean());
			}
			if (((uint)num & 0x10u) != 0)
			{
				OnSyncShouldAttemptToSpawnGoldshoresPortal(reader.ReadBoolean());
			}
			if (((uint)num & 0x20u) != 0)
			{
				OnSyncShouldAttemptToSpawnMSPortal(reader.ReadBoolean());
			}
			if (((uint)num & 0x40u) != 0)
			{
				showExtraBossesIndicator = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class TeleportOutController : NetworkBehaviour
	{
		[NonSerialized]
		[SyncVar]
		public GameObject target;

		public ParticleSystem bodyGlowParticles;

		public static string tpOutSoundString = "Play_UI_teleport_off_map";

		private float fixedAge;

		private const float warmupDuration = 2f;

		public float delayBeforePlayingSFX = 1f;

		private bool hasPlayedSFX;

		private NetworkInstanceId ___targetNetId;

		public GameObject Networktarget
		{
			get
			{
				return target;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref target, 1u, ref ___targetNetId);
			}
		}

		public static void AddTPOutEffect(CharacterModel characterModel, float beginAlpha, float endAlpha, float duration)
		{
			if ((bool)characterModel)
			{
				TemporaryOverlayInstance temporaryOverlayInstance = TemporaryOverlayManager.AddOverlay(characterModel.gameObject);
				temporaryOverlayInstance.duration = duration;
				temporaryOverlayInstance.animateShaderAlpha = true;
				temporaryOverlayInstance.alphaCurve = AnimationCurve.EaseInOut(0f, beginAlpha, 1f, endAlpha);
				temporaryOverlayInstance.destroyComponentOnEnd = true;
				temporaryOverlayInstance.originalMaterial = LegacyResourcesAPI.Load<Material>("Materials/matTPInOut");
				temporaryOverlayInstance.AddToCharacterModel(characterModel);
			}
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			if ((bool)target)
			{
				ModelLocator component = target.GetComponent<ModelLocator>();
				if ((bool)component)
				{
					Transform modelTransform = component.modelTransform;
					if ((bool)modelTransform)
					{
						CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
						if ((bool)component2)
						{
							AddTPOutEffect(component2, 0f, 1f, 2f);
							if (component2.baseRendererInfos.Length != 0)
							{
								Renderer renderer = component2.baseRendererInfos[component2.baseRendererInfos.Length - 1].renderer;
								if ((bool)renderer)
								{
									ParticleSystem.ShapeModule shape = bodyGlowParticles.shape;
									if (renderer is MeshRenderer)
									{
										shape.shapeType = ParticleSystemShapeType.MeshRenderer;
										shape.meshRenderer = renderer as MeshRenderer;
									}
									else if (renderer is SkinnedMeshRenderer)
									{
										shape.shapeType = ParticleSystemShapeType.SkinnedMeshRenderer;
										shape.skinnedMeshRenderer = renderer as SkinnedMeshRenderer;
									}
								}
							}
						}
					}
				}
			}
			bodyGlowParticles.Play();
		}

		public void FixedUpdate()
		{
			fixedAge += Time.fixedDeltaTime;
			if (fixedAge >= delayBeforePlayingSFX && !hasPlayedSFX)
			{
				hasPlayedSFX = true;
				Util.PlaySound(tpOutSoundString, target);
			}
			if (NetworkServer.active && fixedAge >= 2f && (bool)target)
			{
				GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(target);
				if ((bool)teleportEffectPrefab)
				{
					EffectManager.SpawnEffect(teleportEffectPrefab, new EffectData
					{
						origin = target.transform.position
					}, transmit: true);
				}
				UnityEngine.Object.Destroy(target);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(target);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(target);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___targetNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				target = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___targetNetId.IsEmpty())
			{
				Networktarget = ClientScene.FindLocalObject(___targetNetId);
			}
		}
	}
	public class TemporaryOverlay : MonoBehaviour
	{
		[HideInInspector]
		internal TemporaryOverlayInstance instance;

		public Material originalMaterial;

		public CharacterModel inspectorCharacterModel;

		public bool animateShaderAlpha;

		public AnimationCurve alphaCurve;

		public float duration;

		public bool destroyComponentOnEnd;

		public bool destroyObjectOnEnd;

		public GameObject destroyEffectPrefab;

		public string destroyEffectChildString;

		public Material originalMaterialInstance
		{
			get
			{
				InitializeReference();
				return instance.originalMaterial;
			}
			set
			{
				InitializeReference();
				instance.originalMaterial = value;
			}
		}

		[HideInInspector]
		public Material materialInstance
		{
			get
			{
				InitializeReference();
				return instance.materialInstance;
			}
			set
			{
				InitializeReference();
				instance.materialInstance = value;
			}
		}

		public CharacterModel inspectorCharacterModelInstance
		{
			get
			{
				InitializeReference();
				return instance.inspectorCharacterModel;
			}
			set
			{
				InitializeReference();
				instance.inspectorCharacterModel = value;
			}
		}

		public bool animateShaderAlphaInstance
		{
			get
			{
				InitializeReference();
				return instance.animateShaderAlpha;
			}
			set
			{
				InitializeReference();
				instance.animateShaderAlpha = value;
			}
		}

		public AnimationCurve alphaCurveInstance
		{
			get
			{
				InitializeReference();
				return instance.alphaCurve;
			}
			set
			{
				InitializeReference();
				instance.alphaCurve = value;
			}
		}

		public float durationInstance
		{
			get
			{
				InitializeReference();
				return instance.duration;
			}
			set
			{
				InitializeReference();
				instance.duration = value;
			}
		}

		public bool destroyComponentOnEndInstance
		{
			get
			{
				InitializeReference();
				return instance.destroyComponentOnEnd;
			}
			set
			{
				InitializeReference();
				instance.destroyComponentOnEnd = value;
			}
		}

		public bool destroyObjectOnEndInstance
		{
			get
			{
				InitializeReference();
				return instance.destroyObjectOnEnd;
			}
			set
			{
				InitializeReference();
				instance.destroyObjectOnEnd = value;
			}
		}

		public GameObject destroyEffectPrefabInstance
		{
			get
			{
				InitializeReference();
				return instance.destroyEffectPrefab;
			}
			set
			{
				InitializeReference();
				instance.destroyEffectPrefab = value;
			}
		}

		public string destroyEffectChildStringInstance
		{
			get
			{
				InitializeReference();
				return instance.destroyEffectChildString;
			}
			set
			{
				InitializeReference();
				instance.destroyEffectChildString = value;
			}
		}

		private void Awake()
		{
			InitializeReference();
			CopyDataFromPrefabToInstance();
		}

		private void InitializeReference()
		{
			if (instance == null)
			{
				instance = TemporaryOverlayManager.AddOverlay(base.gameObject);
				instance.componentReference = this;
			}
		}

		private void CopyDataFromPrefabToInstance()
		{
			InitializeReference();
			instance.originalMaterial = originalMaterial;
			instance.inspectorCharacterModel = inspectorCharacterModel;
			instance.animateShaderAlpha = animateShaderAlpha;
			instance.alphaCurve = alphaCurve;
			instance.duration = duration;
			instance.destroyComponentOnEnd = destroyComponentOnEnd;
			instance.destroyObjectOnEnd = destroyObjectOnEnd;
			instance.destroyEffectChildString = destroyEffectChildString;
		}

		private void Start()
		{
			InitializeReference();
			instance.Start();
		}

		private void SetupMaterial()
		{
			instance.SetupMaterial();
		}

		public void AddToCharacerModel(CharacterModel characterModel)
		{
			InitializeReference();
			instance.AddToCharacterModel(characterModel);
		}

		public void RemoveFromCharacterModel()
		{
			InitializeReference();
			instance.RemoveFromCharacterModel();
		}

		private void OnDestroy()
		{
			DestroyInstanceReference();
		}

		internal void DestroyInstanceReference()
		{
			instance = null;
		}
	}
	public class TemporaryOverlayInstance
	{
		public GameObject gameObject;

		public int managerIndex;

		private TemporaryOverlay _componentReference;

		public bool hasComponentReference;

		public Material originalMaterial;

		public Material materialInstance;

		private bool isAssigned;

		public CharacterModel assignedCharacterModel;

		public CharacterModel inspectorCharacterModel;

		public bool animateShaderAlpha;

		public AnimationCurve alphaCurve;

		public float duration;

		public bool destroyComponentOnEnd;

		public bool destroyObjectOnEnd;

		public GameObject destroyEffectPrefab;

		public string destroyEffectChildString;

		public float stopwatch;

		public bool initialized;

		public bool transmit = true;

		public TemporaryOverlay componentReference
		{
			get
			{
				return _componentReference;
			}
			set
			{
				_componentReference = value;
				hasComponentReference = hasComponentReference || _componentReference != null;
			}
		}

		public TemporaryOverlayInstance(GameObject _gameObject)
		{
			gameObject = _gameObject;
		}

		public void Start()
		{
			if (!initialized)
			{
				SetupMaterial();
				if ((bool)inspectorCharacterModel)
				{
					AddToCharacterModel(inspectorCharacterModel);
				}
			}
		}

		internal bool ValidateOverlay()
		{
			if (gameObject != null)
			{
				if (hasComponentReference)
				{
					return componentReference != null;
				}
				return true;
			}
			return false;
		}

		public void Destroy()
		{
			CleanupEffect();
		}

		public void CleanupEffect()
		{
			RemoveFromCharacterModel();
			if ((bool)materialInstance)
			{
				UnityEngine.Object.Destroy(materialInstance);
			}
			if (!destroyObjectOnEnd && !destroyComponentOnEnd)
			{
				return;
			}
			if (hasComponentReference && componentReference != null)
			{
				componentReference.DestroyInstanceReference();
				if (destroyComponentOnEnd)
				{
					UnityEngine.Object.Destroy(componentReference);
				}
			}
			componentReference = null;
			if (destroyObjectOnEnd && gameObject != null)
			{
				UnityEngine.Object.Destroy(gameObject);
			}
			gameObject = null;
		}

		public void SetupMaterial()
		{
			if (!materialInstance)
			{
				materialInstance = new Material(originalMaterial);
			}
		}

		public void AddToCharacterModel(CharacterModel characterModel)
		{
			SetupMaterial();
			if ((bool)characterModel)
			{
				characterModel.AddTempOverlay(this);
				characterModel.forceUpdate = true;
				isAssigned = true;
				assignedCharacterModel = characterModel;
			}
			initialized = true;
		}

		public void RemoveFromCharacterModel()
		{
			if ((bool)assignedCharacterModel)
			{
				assignedCharacterModel.RemoveTempOverlay(this);
				assignedCharacterModel.forceUpdate = true;
				isAssigned = false;
				assignedCharacterModel = null;
			}
		}
	}
	public static class TemporaryOverlayManager
	{
		private static int arraySize = 50;

		private static int arrayExpansionSize = 20;

		private static int debugMaxSizeUsed = 0;

		private static TemporaryOverlayInstance[] overlayArray;

		private static TemporaryOverlayInstance temp;

		private static float _delta;

		private static float sample;

		private static ChildLocator childLocator;

		private static Transform childTransform;

		private static int propertyID;

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			overlayArray = new TemporaryOverlayInstance[arraySize];
			arraySize = 0;
			propertyID = Shader.PropertyToID("_ExternalAlpha");
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			RoR2Application.onUpdate += OverlayUpdate;
		}

		private static void OnSceneUnloaded(Scene arg0)
		{
			ClearAllOverlays();
		}

		private static void ClearAllOverlays()
		{
			int num = overlayArray.Length;
			for (int i = 0; i < num; i++)
			{
				overlayArray[i] = null;
			}
			arraySize = 0;
		}

		public static void OverlayUpdate()
		{
			_delta = Time.deltaTime;
			for (int i = 0; i < arraySize; i++)
			{
				temp = overlayArray[i];
				if (temp == null || !temp.ValidateOverlay())
				{
					RemoveOverlay(i);
					i--;
				}
				else
				{
					if (!temp.animateShaderAlpha)
					{
						continue;
					}
					if (!temp.initialized)
					{
						temp.Start();
					}
					temp.stopwatch += _delta;
					sample = temp.alphaCurve.Evaluate(temp.stopwatch / temp.duration);
					temp.materialInstance.SetFloat(propertyID, sample);
					if (!(temp.stopwatch >= temp.duration) || (!temp.destroyComponentOnEnd && !temp.destroyObjectOnEnd))
					{
						continue;
					}
					if ((bool)temp.destroyEffectPrefab)
					{
						childLocator = temp.gameObject.GetComponent<ChildLocator>();
						if ((bool)childLocator)
						{
							childTransform = childLocator.FindChild(temp.destroyEffectChildString);
							if ((bool)childTransform)
							{
								EffectManager.SpawnEffect(temp.destroyEffectPrefab, new EffectData
								{
									origin = childTransform.position,
									rotation = childTransform.rotation
								}, temp.transmit);
							}
						}
					}
					RemoveOverlay(i);
					i--;
				}
			}
		}

		public static TemporaryOverlayInstance AddOverlay(GameObject _gameObject)
		{
			if (arraySize == overlayArray.Length)
			{
				ExpandArray();
			}
			overlayArray[arraySize] = new TemporaryOverlayInstance(_gameObject);
			temp = overlayArray[arraySize];
			temp.managerIndex = arraySize++;
			debugMaxSizeUsed = Mathf.Max(arraySize, debugMaxSizeUsed);
			return temp;
		}

		public static void RemoveOverlay(int index)
		{
			if (index >= 0 && arraySize > index)
			{
				temp = overlayArray[index];
				if (temp != null)
				{
					temp.CleanupEffect();
					temp.managerIndex = -1;
				}
				arraySize--;
				if (arraySize != 0)
				{
					temp = overlayArray[arraySize];
					temp.managerIndex = index;
					overlayArray[index] = temp;
				}
			}
		}

		private static void ExpandArray()
		{
			Array.Resize(ref overlayArray, arraySize + arrayExpansionSize);
		}
	}
	public class TemporaryVisualEffect : MonoBehaviour
	{
		public enum VisualState
		{
			Enter,
			Exit
		}

		public float radius = 1f;

		public Transform parentTransform;

		public Transform visualTransform;

		public MonoBehaviour[] enterComponents;

		public MonoBehaviour[] exitComponents;

		public VisualState visualState;

		private VisualState previousVisualState;

		[HideInInspector]
		public HealthComponent healthComponent;

		private void Start()
		{
			RebuildVisualComponents();
		}

		private void FixedUpdate()
		{
			if (previousVisualState != visualState)
			{
				RebuildVisualComponents();
			}
			previousVisualState = visualState;
		}

		private void RebuildVisualComponents()
		{
			switch (visualState)
			{
			case VisualState.Enter:
			{
				MonoBehaviour[] array = enterComponents;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].enabled = true;
				}
				array = exitComponents;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].enabled = false;
				}
				break;
			}
			case VisualState.Exit:
			{
				MonoBehaviour[] array = enterComponents;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].enabled = false;
				}
				array = exitComponents;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].enabled = true;
				}
				break;
			}
			}
		}

		private void LateUpdate()
		{
			bool flag = healthComponent;
			if ((bool)parentTransform)
			{
				base.transform.position = parentTransform.position;
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			if (!flag || (flag && !healthComponent.alive))
			{
				visualState = VisualState.Exit;
			}
			if ((bool)visualTransform)
			{
				visualTransform.localScale = new UnityEngine.Vector3(radius, radius, radius);
			}
		}
	}
	public class TeslaCoilAnimator : MonoBehaviour
	{
		public GameObject activeEffectParent;

		private CharacterBody characterBody;

		private void Start()
		{
			CharacterModel componentInParent = GetComponentInParent<CharacterModel>();
			if ((bool)componentInParent)
			{
				characterBody = componentInParent.body;
			}
		}

		private void FixedUpdate()
		{
			if ((bool)characterBody)
			{
				activeEffectParent.SetActive(characterBody.HasBuff(RoR2Content.Buffs.TeslaField));
			}
		}
	}
	[RequireComponent(typeof(BezierCurveLine))]
	public class TetherVfx : MonoBehaviour
	{
		public AnimateShaderAlpha fadeOut;

		[Tooltip("The transform to position at the target.")]
		public Transform tetherEndTransform;

		[Tooltip("The transform to position the end to.")]
		public Transform tetherTargetTransform;

		private BezierCurveLine curve;

		private void Start()
		{
			curve = GetComponent<BezierCurveLine>();
		}

		public void Update()
		{
			if ((bool)tetherTargetTransform && (bool)tetherEndTransform)
			{
				tetherEndTransform.position = tetherTargetTransform.position;
			}
			if ((bool)curve && (bool)tetherTargetTransform)
			{
				curve.p1 = tetherTargetTransform.position;
			}
		}

		public void Terminate()
		{
			if ((bool)fadeOut)
			{
				fadeOut.enabled = true;
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	public class TetherVfxOrigin : MonoBehaviour
	{
		public GameObject tetherPrefab;

		private List<Transform> tetheredTransforms;

		private List<TetherVfx> tetherVfxs;

		protected new Transform transform { get; private set; }

		protected void Awake()
		{
			transform = base.transform;
			tetheredTransforms = CollectionPool<Transform, List<Transform>>.RentCollection();
			tetherVfxs = CollectionPool<TetherVfx, List<TetherVfx>>.RentCollection();
		}

		protected void OnDestroy()
		{
			for (int num = tetherVfxs.Count - 1; num >= 0; num--)
			{
				RemoveTetherAt(num);
			}
			tetherVfxs = CollectionPool<TetherVfx, List<TetherVfx>>.ReturnCollection(tetherVfxs);
			tetheredTransforms = CollectionPool<Transform, List<Transform>>.ReturnCollection(tetheredTransforms);
		}

		protected void AddTether(Transform target)
		{
			if ((bool)target)
			{
				TetherVfx tetherVfx = null;
				if ((bool)tetherPrefab)
				{
					tetherVfx = UnityEngine.Object.Instantiate(tetherPrefab, transform).GetComponent<TetherVfx>();
					tetherVfx.tetherTargetTransform = target;
				}
				tetheredTransforms.Add(target);
				tetherVfxs.Add(tetherVfx);
			}
		}

		protected void RemoveTetherAt(int i)
		{
			TetherVfx tetherVfx = tetherVfxs[i];
			if ((bool)tetherVfx)
			{
				tetherVfx.transform.SetParent(null);
				tetherVfx.Terminate();
			}
			tetheredTransforms.RemoveAt(i);
			tetherVfxs.RemoveAt(i);
		}

		public void SetTetheredTransforms(List<Transform> newTetheredTransforms)
		{
			List<Transform> list = CollectionPool<Transform, List<Transform>>.RentCollection();
			List<Transform> list2 = CollectionPool<Transform, List<Transform>>.RentCollection();
			ListUtils.FindExclusiveEntriesByReference(tetheredTransforms, newTetheredTransforms, list2, list);
			int i = 0;
			for (int count = list2.Count; i < count; i++)
			{
				List<Transform> list3 = tetheredTransforms;
				Transform value = list2[i];
				RemoveTetherAt(ListUtils.FirstOccurrenceByReference(list3, in value));
			}
			int j = 0;
			for (int count2 = list.Count; j < count2; j++)
			{
				AddTether(list[j]);
			}
			CollectionPool<Transform, List<Transform>>.ReturnCollection(list2);
			CollectionPool<Transform, List<Transform>>.ReturnCollection(list);
		}
	}
	public sealed class TimedChestController : NetworkBehaviour, IInteractable
	{
		public float lockTime = 600f;

		public TextMeshPro displayTimer;

		public ObjectScaleCurve displayScaleCurve;

		public string contextString;

		public UnityEngine.Color displayIsAvailableColor;

		public UnityEngine.Color displayIsLockedColor;

		public bool purchased;

		public bool shouldProximityHighlight = true;

		private const int minTime = -599;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		private int remainingTime
		{
			get
			{
				float num = 0f;
				if ((bool)Run.instance)
				{
					num = Run.instance.GetRunStopwatch();
				}
				return (int)(lockTime - num);
			}
		}

		private bool locked => remainingTime <= 0;

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextString);
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (!purchased)
			{
				if (!locked)
				{
					return Interactability.Available;
				}
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Disabled;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			GetComponent<EntityStateMachine>().SetNextState(new EntityStates.TimedChest.Opening());
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public void FixedUpdate()
		{
			if (!NetworkClient.active)
			{
				return;
			}
			if (!purchased)
			{
				int num = remainingTime;
				bool flag = num >= 0;
				bool flag2 = true;
				if (num < -599)
				{
					flag2 = (num & 1) != 0;
					num = -599;
				}
				int num2 = (flag ? num : (-num));
				uint num3 = (uint)num2 / 60u;
				uint value = (uint)num2 - num3 * 60;
				sharedStringBuilder.Clear();
				sharedStringBuilder.Append("<mspace=0.75em>");
				if (flag2)
				{
					uint num4 = 2u;
					if (!flag)
					{
						sharedStringBuilder.Append("-");
						num4 = 1u;
					}
					sharedStringBuilder.AppendUint(num3, num4, num4);
					sharedStringBuilder.Append(":");
					sharedStringBuilder.AppendUint(value, 2u, 2u);
				}
				else
				{
					sharedStringBuilder.Append("--:--");
				}
				sharedStringBuilder.Append("</mspace>");
				displayTimer.SetText(sharedStringBuilder);
				displayTimer.color = (locked ? displayIsLockedColor : displayIsAvailableColor);
				displayTimer.SetText(sharedStringBuilder);
				displayScaleCurve.enabled = false;
			}
			else
			{
				displayScaleCurve.enabled = true;
			}
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			return !purchased;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class TimerHologramContent : MonoBehaviour
	{
		public float displayValue;

		public TextMeshPro targetTextMesh;

		private void FixedUpdate()
		{
			if ((bool)targetTextMesh)
			{
				int num = Mathf.FloorToInt(displayValue);
				int num2 = Mathf.FloorToInt((displayValue - (float)num) * 100f);
				targetTextMesh.text = $"{num:D}.{num2:D2}";
			}
		}
	}
	public class TitanRockController : NetworkBehaviour
	{
		[Tooltip("The child transform from which projectiles will be fired.")]
		public Transform fireTransform;

		[Tooltip("How long it takes to start firing.")]
		public float startDelay = 4f;

		[Tooltip("Firing interval.")]
		public float fireInterval = 1f;

		[Tooltip("The prefab to fire as a projectile.")]
		public GameObject projectilePrefab;

		[Tooltip("The damage coefficient to multiply by the owner's damage stat for the projectile's final damage value.")]
		public float damageCoefficient;

		[Tooltip("The force of the projectile's damage.")]
		public float damageForce;

		[SyncVar(hook = "SetOwner")]
		private GameObject owner;

		private Transform targetTransform;

		private UnityEngine.Vector3 velocity;

		private static readonly UnityEngine.Vector3 targetLocalPosition = new UnityEngine.Vector3(0f, 12f, -3f);

		private float fireTimer;

		private InputBankTest ownerInputBank;

		private CharacterBody ownerCharacterBody;

		private bool isCrit;

		private bool foundOwner;

		private NetworkInstanceId ___ownerNetId;

		public GameObject Networkowner
		{
			get
			{
				return owner;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetOwner(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVarGameObject(value, ref owner, 1u, ref ___ownerNetId);
			}
		}

		private void Start()
		{
			if (!NetworkServer.active)
			{
				SetOwner(owner);
			}
			else
			{
				fireTimer = startDelay;
			}
		}

		public void SetOwner(GameObject newOwner)
		{
			ownerInputBank = null;
			ownerCharacterBody = null;
			isCrit = false;
			Networkowner = newOwner;
			if (!owner)
			{
				return;
			}
			ownerInputBank = owner.GetComponent<InputBankTest>();
			ownerCharacterBody = owner.GetComponent<CharacterBody>();
			ModelLocator component = owner.GetComponent<ModelLocator>();
			if ((bool)component)
			{
				Transform modelTransform = component.modelTransform;
				if ((bool)modelTransform)
				{
					ChildLocator component2 = modelTransform.GetComponent<ChildLocator>();
					if ((bool)component2)
					{
						targetTransform = component2.FindChild("Chest");
						if ((bool)targetTransform)
						{
							base.transform.rotation = targetTransform.rotation;
						}
					}
				}
			}
			base.transform.position = owner.transform.position + UnityEngine.Vector3.down * 20f;
			if (NetworkServer.active && (bool)ownerCharacterBody)
			{
				CharacterMaster master = ownerCharacterBody.master;
				if ((bool)master)
				{
					isCrit = Util.CheckRoll(ownerCharacterBody.crit, master);
				}
			}
		}

		public void FixedUpdate()
		{
			if ((bool)targetTransform)
			{
				foundOwner = true;
				base.transform.position = UnityEngine.Vector3.SmoothDamp(base.transform.position, targetTransform.TransformPoint(targetLocalPosition), ref velocity, 1f);
				base.transform.rotation = targetTransform.rotation;
			}
			else if (foundOwner)
			{
				foundOwner = false;
				ParticleSystem[] componentsInChildren = GetComponentsInChildren<ParticleSystem>();
				foreach (ParticleSystem obj in componentsInChildren)
				{
					ParticleSystem.MainModule main = obj.main;
					main.gravityModifier = 1f;
					ParticleSystem.EmissionModule emission = obj.emission;
					emission.enabled = false;
					ParticleSystem.NoiseModule noise = obj.noise;
					noise.enabled = false;
					ParticleSystem.LimitVelocityOverLifetimeModule limitVelocityOverLifetime = obj.limitVelocityOverLifetime;
					limitVelocityOverLifetime.enabled = false;
				}
				ParticleSystem.CollisionModule collision = base.transform.Find("Debris").GetComponent<ParticleSystem>().collision;
				collision.enabled = true;
				Light[] componentsInChildren2 = GetComponentsInChildren<Light>();
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].enabled = false;
				}
				Util.PlaySound("Stop_titanboss_shift_loop", base.gameObject);
			}
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		[Server]
		private void FixedUpdateServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TitanRockController::FixedUpdateServer()' called on client");
				return;
			}
			fireTimer -= Time.fixedDeltaTime;
			if (fireTimer <= 0f)
			{
				Fire();
				fireTimer += fireInterval;
			}
		}

		[Server]
		private void Fire()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.TitanRockController::Fire()' called on client");
			}
			else if ((bool)ownerInputBank)
			{
				UnityEngine.Vector3 position = fireTransform.position;
				UnityEngine.Vector3 forward = ownerInputBank.aimDirection;
				if (Util.CharacterRaycast(owner, new Ray(ownerInputBank.aimOrigin, ownerInputBank.aimDirection), out var hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
				{
					forward = hitInfo.point - position;
				}
				float num = (ownerCharacterBody ? ownerCharacterBody.damage : 1f);
				ProjectileManager.instance.FireProjectile(projectilePrefab, position, Util.QuaternionSafeLookRotation(forward), owner, damageCoefficient * num, damageForce, isCrit);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(owner);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(owner);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___ownerNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetOwner(reader.ReadGameObject());
			}
		}

		public override void PreStartClient()
		{
			if (!___ownerNetId.IsEmpty())
			{
				Networkowner = ClientScene.FindLocalObject(___ownerNetId);
			}
		}
	}
	[RequireComponent(typeof(EffectComponent))]
	public class Tracer : MonoBehaviour
	{
		[Tooltip("A child transform which will be placed at the start of the tracer path upon creation.")]
		public Transform startTransform;

		[Tooltip("Child object to scale to the length of this tracer and burst particles on based on that length. Optional.")]
		public GameObject beamObject;

		[Tooltip("The number of particles to emit per meter of length if using a beam object.")]
		public float beamDensity = 10f;

		[Tooltip("The travel speed of this tracer.")]
		public float speed = 1f;

		[Tooltip("Child transform which will be moved to the head of the tracer.")]
		public Transform headTransform;

		[Tooltip("Child transform which will be moved to the tail of the tracer.")]
		public Transform tailTransform;

		[Tooltip("The maximum distance between head and tail transforms.")]
		public float length = 1f;

		[Tooltip("Reverses the travel direction of the tracer.")]
		public bool reverse;

		[Tooltip("The event that runs when the tail reaches the destination.")]
		public UnityEvent onTailReachedDestination;

		private UnityEngine.Vector3 startPos;

		private UnityEngine.Vector3 endPos;

		private float distanceTraveled;

		private float totalDistance;

		private UnityEngine.Vector3 normal;

		protected EffectComponent _effectComponent;

		protected EffectManagerHelper _effectManagerHelper;

		protected EffectManagerHelper _parentEffectManagerHelper;

		protected EffectData _effectData;

		protected List<LineRenderer> _LineRenderers;

		protected Renderer[] _renderers;

		protected bool _startCalled;

		protected bool orbEffectHasOnArrivalAnimateShaderAlpha;

		public void PrepForPoolUsage()
		{
			if (onTailReachedDestination == null)
			{
				return;
			}
			int num = -1;
			int persistentEventCount = onTailReachedDestination.GetPersistentEventCount();
			for (int i = 0; i < persistentEventCount; i++)
			{
				UnityEngine.Object persistentTarget = onTailReachedDestination.GetPersistentTarget(i);
				switch (onTailReachedDestination.GetPersistentMethodName(i))
				{
				case "UnparentTransform":
					num = i;
					UnityEngine.Debug.LogFormat("Disabled DetachChildren");
					onTailReachedDestination.SetPersistentListenerState(num, UnityEventCallState.Off);
					break;
				case "set_enabled":
					if (persistentTarget.GetType() == typeof(AnimateShaderAlpha))
					{
						orbEffectHasOnArrivalAnimateShaderAlpha = true;
						AnimateShaderAlpha animateShaderAlpha = persistentTarget as AnimateShaderAlpha;
						if (animateShaderAlpha.destroyOnEnd)
						{
							animateShaderAlpha.destroyOnEnd = false;
							animateShaderAlpha.disableOnEnd = true;
						}
					}
					break;
				case "DestroySelf":
					UnityEngine.Debug.LogFormat("Disabled DestroySelf");
					onTailReachedDestination.SetPersistentListenerState(i, UnityEventCallState.Off);
					break;
				}
			}
			if (_LineRenderers != null)
			{
				return;
			}
			LineRenderer[] components = base.gameObject.GetComponents<LineRenderer>();
			if (components != null && components.Length != 0)
			{
				if (_LineRenderers == null)
				{
					_LineRenderers = new List<LineRenderer>();
				}
				_LineRenderers.AddRange(components);
			}
			LineRenderer[] componentsInChildren = base.gameObject.GetComponentsInChildren<LineRenderer>(includeInactive: true);
			if (componentsInChildren != null && componentsInChildren.Length != 0)
			{
				if (_LineRenderers == null)
				{
					_LineRenderers = new List<LineRenderer>();
				}
				_LineRenderers.AddRange(componentsInChildren);
			}
		}

		public void Reset()
		{
			if (!_startCalled)
			{
				return;
			}
			if (_effectManagerHelper == null)
			{
				_effectManagerHelper = base.gameObject.GetComponent<EffectManagerHelper>();
			}
			if (_effectComponent == null)
			{
				_effectComponent = base.gameObject.GetComponent<EffectComponent>();
			}
			if (_parentEffectManagerHelper == null)
			{
				_parentEffectManagerHelper = ((base.gameObject.transform.parent != null) ? base.gameObject.transform.parent.gameObject.GetComponent<EffectManagerHelper>() : null);
			}
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			if (_renderers == null)
			{
				_renderers = GetComponents<Renderer>();
			}
			endPos = _effectComponent.effectData.origin;
			Transform transform = _effectComponent.effectData.ResolveChildLocatorTransformReference();
			startPos = (transform ? transform.position : _effectComponent.effectData.start);
			if (reverse)
			{
				Util.Swap(ref endPos, ref startPos);
			}
			UnityEngine.Vector3 vector = endPos - startPos;
			distanceTraveled = 0f;
			totalDistance = UnityEngine.Vector3.Magnitude(vector);
			if (totalDistance != 0f)
			{
				normal = vector * (1f / totalDistance);
				base.transform.rotation = Util.QuaternionSafeLookRotation(normal);
			}
			else
			{
				normal = UnityEngine.Vector3.zero;
			}
			if ((bool)beamObject)
			{
				beamObject.transform.position = startPos + vector * 0.5f;
				ParticleSystem component = beamObject.GetComponent<ParticleSystem>();
				if ((bool)component)
				{
					ParticleSystem.ShapeModule shape = component.shape;
					shape.radius = totalDistance * 0.5f;
					component.Emit(Mathf.FloorToInt(totalDistance * beamDensity) - 1);
				}
			}
			if ((bool)startTransform)
			{
				startTransform.position = startPos;
			}
			SetRenderers(state: true);
		}

		private void Start()
		{
			_startCalled = true;
			Reset();
		}

		private void Update()
		{
			if (distanceTraveled > totalDistance)
			{
				onTailReachedDestination.Invoke();
				Arrive();
				return;
			}
			distanceTraveled += speed * Time.deltaTime;
			float num = Mathf.Clamp(distanceTraveled, 0f, totalDistance);
			float num2 = Mathf.Clamp(distanceTraveled - length, 0f, totalDistance);
			if ((bool)headTransform)
			{
				headTransform.position = startPos + num * normal;
			}
			if ((bool)tailTransform)
			{
				tailTransform.position = startPos + num2 * normal;
			}
		}

		private void SetRenderers(bool state)
		{
			if (_renderers != null)
			{
				for (int i = 0; i < _renderers.Length; i++)
				{
					_renderers[i].enabled = state;
				}
			}
		}

		private void Arrive()
		{
			if (!EffectManager.UsePools)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			SetRenderers(state: false);
			if (_effectManagerHelper != null && _effectManagerHelper.OwningPool != null)
			{
				if (!_effectManagerHelper.HasDestroyOnTimer && !_effectManagerHelper.HasAnimateShaderAlphas && !orbEffectHasOnArrivalAnimateShaderAlpha)
				{
					_effectManagerHelper.OwningPool.ReturnObject(_effectManagerHelper);
				}
				return;
			}
			if (_effectManagerHelper != null)
			{
				UnityEngine.Debug.LogErrorFormat("Tracer: No owning pool set. {0} ({1})", base.gameObject.name, base.gameObject.GetInstanceID());
			}
			UnityEngine.Object.Destroy(base.gameObject);
		}
	}
	public class TreebotSunBuffGranter : MonoBehaviour
	{
		public Transform referenceTransform;

		public float raycastFrequency;

		public BuffDef buffDef;

		private const float raycastLength = 1000f;

		private float timer;

		private bool hadSunlight;

		private Light sun;

		private CharacterBody characterBody;

		private void Start()
		{
			FindSun();
			characterBody = GetComponent<CharacterBody>();
		}

		private void FixedUpdate()
		{
			timer -= Time.fixedDeltaTime;
			if (timer <= 0f)
			{
				timer = 1f / raycastFrequency;
				CheckSunlight();
			}
		}

		private void FindSun()
		{
			sun = RenderSettings.sun;
		}

		private void CheckSunlight()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if (!sun)
			{
				FindSun();
				if (!sun)
				{
					return;
				}
			}
			bool flag = !Physics.Raycast(base.transform.position, -sun.transform.forward, 1000f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
			if ((bool)buffDef)
			{
				if (hadSunlight && !flag)
				{
					characterBody.RemoveBuff(buffDef.buffIndex);
				}
				else if (flag && !hadSunlight)
				{
					characterBody.AddBuff(buffDef.buffIndex);
				}
			}
			hadSunlight = flag;
		}
	}
	[DisallowMultipleComponent]
	public class TutorialManager : MonoBehaviour
	{
		private static BoolConVar cvIsTutorialEnabled = new BoolConVar("enable_tutorial", ConVarFlags.None, "0", "Enables the tutorial.");

		private LocalUser _cachedLocalUser;

		private Inventory _cachedInventory;

		private float itemTriggerTimeBuffer = 5f;

		public static bool isTutorialEnabled => cvIsTutorialEnabled.value;

		private void Start()
		{
			if (isTutorialEnabled)
			{
				_cachedLocalUser = LocalUserManager.GetFirstLocalUser();
				if (_cachedLocalUser != null)
				{
					_cachedLocalUser.onBodyChanged += OnBodyChanged;
				}
			}
		}

		private void OnBodyChanged()
		{
			_cachedInventory = _cachedLocalUser.cachedMasterController.master.inventory;
			if ((bool)_cachedInventory)
			{
				_cachedLocalUser.onBodyChanged -= OnBodyChanged;
				BindPickups();
			}
		}

		private void BindPickups()
		{
			_cachedInventory.onItemAddedClient += OnItemAddedClient;
			_cachedInventory.onEquipmentChangedClient += OnEquipmentChangedClient;
		}

		private void UnbindPickups()
		{
			_cachedInventory.onItemAddedClient -= OnItemAddedClient;
			_cachedInventory.onEquipmentChangedClient -= OnEquipmentChangedClient;
		}

		private void OnItemAddedClient(ItemIndex itemIndex)
		{
			CameraRigController cameraRigController = _cachedLocalUser.cameraRigController;
			if (!cameraRigController)
			{
				return;
			}
			HUD hud = cameraRigController.hud;
			if (!hud)
			{
				return;
			}
			InspectPanelController inspectPanelController = hud.inspectPanelController;
			if ((bool)inspectPanelController && (!Run.instance || !(Run.instance.GetRunStopwatch() < itemTriggerTimeBuffer)))
			{
				hud.scoreboardPanel.SetActive(value: true);
				if (_cachedLocalUser.userProfile.useInspectFeature)
				{
					InspectInfo inspectInfo = ItemCatalog.GetItemDef(itemIndex);
					inspectInfo.MarkForceShowInfo();
					inspectPanelController.Show(inspectInfo);
				}
				UnbindPickups();
			}
		}

		private void OnEquipmentChangedClient(EquipmentIndex newEquipmentIndex, uint equipmentSlot)
		{
			CameraRigController cameraRigController = _cachedLocalUser.cameraRigController;
			if (!cameraRigController)
			{
				return;
			}
			HUD hud = cameraRigController.hud;
			if (!hud)
			{
				return;
			}
			InspectPanelController inspectPanelController = hud.inspectPanelController;
			if ((bool)inspectPanelController && (!Run.instance || !(Run.instance.GetRunStopwatch() < itemTriggerTimeBuffer)))
			{
				hud.scoreboardPanel.SetActive(value: true);
				if (_cachedLocalUser.userProfile.useInspectFeature)
				{
					InspectInfo inspectInfo = EquipmentCatalog.GetEquipmentDef(newEquipmentIndex);
					inspectInfo.MarkForceShowInfo();
					inspectPanelController.Show(inspectInfo);
				}
				UnbindPickups();
			}
		}
	}
	[ExecuteAlways]
	[RequireComponent(typeof(GridLayoutGroup))]
	public class AdjustGridLayoutCellSize : MonoBehaviour
	{
		public enum ExpandSetting
		{
			X,
			Y,
			Both
		}

		public ExpandSetting expandingSetting;

		public GridLayoutGroup gridlayout;

		private int maxConstraintCount;

		private RectTransform layoutRect;

		private void Update()
		{
			UpdateCellSize();
		}

		private void UpdateCellSize()
		{
			if ((bool)gridlayout)
			{
				maxConstraintCount = gridlayout.constraintCount;
				layoutRect = gridlayout.gameObject.GetComponent<RectTransform>();
				float num = (float)(maxConstraintCount - 1) * gridlayout.spacing.x + (float)gridlayout.padding.left + (float)gridlayout.padding.right;
				float num2 = (float)(maxConstraintCount - 1) * gridlayout.spacing.y + (float)gridlayout.padding.top + (float)gridlayout.padding.bottom;
				float width = layoutRect.rect.width;
				float height = layoutRect.rect.height;
				float num3 = width - num;
				float num4 = height - num2;
				float x = num3 / (float)maxConstraintCount;
				float y = num4 / (float)maxConstraintCount;
				UnityEngine.Vector2 cellSize = new UnityEngine.Vector2(gridlayout.cellSize.x, gridlayout.cellSize.y);
				if (expandingSetting == ExpandSetting.X || expandingSetting == ExpandSetting.Both)
				{
					cellSize.x = x;
				}
				if (expandingSetting == ExpandSetting.Y || expandingSetting == ExpandSetting.Both)
				{
					cellSize.y = y;
				}
				gridlayout.cellSize = cellSize;
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class CharacterSelectBarController : MonoBehaviour
	{
		public struct SurvivorPickInfo
		{
			public LocalUser localUser;

			public SurvivorDef pickedSurvivor;
		}

		[Serializable]
		public class SurvivorPickInfoUnityEvent : UnityEvent<SurvivorPickInfo>
		{
		}

		[Header("Prefabs")]
		public GameObject choiceButtonPrefab;

		public GameObject fillButtonPrefab;

		[ShowFieldObsolete]
		[Obsolete("No longer used.", false)]
		public GameObject WIPButtonPrefab;

		[Header("Required References")]
		[FormerlySerializedAs("gridLayoutGroup")]
		public GridLayoutGroup iconContainerGrid;

		[Header("Events")]
		public SurvivorPickInfoUnityEvent onSurvivorPicked;

		public MPEventSystemLocator eventSystemLocator;

		private UIElementAllocator<SurvivorIconController> survivorIconControllers;

		private UIElementAllocator<RectTransform> fillerIcons;

		private LocalUser currentLocalUser;

		[Obsolete("Use iconContainerGrid instead", false)]
		public ref GridLayoutGroup gridLayoutGroup => ref iconContainerGrid;

		public SurvivorIconController pickedIcon { get; private set; }

		private bool isEclipseRun
		{
			get
			{
				if ((bool)PreGameController.instance)
				{
					return PreGameController.instance.gameModeIndex == GameModeCatalog.FindGameModeIndex("EclipseRun");
				}
				return false;
			}
		}

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			survivorIconControllers = new UIElementAllocator<SurvivorIconController>((RectTransform)iconContainerGrid.transform, choiceButtonPrefab);
			survivorIconControllers.onCreateElement = OnCreateSurvivorIcon;
			fillerIcons = new UIElementAllocator<RectTransform>((RectTransform)iconContainerGrid.transform, fillButtonPrefab);
		}

		private void LateUpdate()
		{
			EnforceValidChoice();
		}

		private void OnEnable()
		{
			eventSystemLocator.onEventSystemDiscovered += OnEventSystemDiscovered;
			if ((bool)eventSystemLocator.eventSystem)
			{
				OnEventSystemDiscovered(eventSystemLocator.eventSystem);
			}
		}

		private void OnDisable()
		{
			eventSystemLocator.onEventSystemDiscovered -= OnEventSystemDiscovered;
		}

		public void ApplyPickToPickerSurvivorPreference(SurvivorPickInfo survivorPickInfo)
		{
			if (survivorPickInfo.localUser != null)
			{
				survivorPickInfo.localUser.userProfile.SetSurvivorPreference(survivorPickInfo.pickedSurvivor);
			}
		}

		public void ApplyPickToEclipseSurvivorPreference(SurvivorPickInfo survivorPickInfo)
		{
		}

		private void OnEventSystemDiscovered(MPEventSystem eventSystem)
		{
			currentLocalUser = eventSystem.localUser;
			Build();
			SurvivorDef localUserExistingSurvivorPreference = GetLocalUserExistingSurvivorPreference();
			PickIconBySurvivorDef(localUserExistingSurvivorPreference);
		}

		private void OnCreateSurvivorIcon(int index, SurvivorIconController survivorIconController)
		{
			survivorIconController.characterSelectBarController = this;
			survivorIconController.hgButton.onClick.AddListener(delegate
			{
				PickIcon(survivorIconController);
			});
		}

		private int FindIconIndexForSurvivorDef(SurvivorDef survivorDef)
		{
			ReadOnlyCollection<SurvivorIconController> elements = survivorIconControllers.elements;
			for (int i = 0; i < elements.Count; i++)
			{
				if ((object)elements[i].survivorDef == survivorDef)
				{
					return i;
				}
			}
			return -1;
		}

		private int FindIconIndex(SurvivorIconController survivorIconController)
		{
			ReadOnlyCollection<SurvivorIconController> elements = survivorIconControllers.elements;
			for (int i = 0; i < elements.Count; i++)
			{
				if ((object)elements[i] == survivorIconController)
				{
					return i;
				}
			}
			return -1;
		}

		private void PickIconBySurvivorDef(SurvivorDef survivorDef)
		{
			int num = FindIconIndexForSurvivorDef(survivorDef);
			if (num >= 0)
			{
				PickIcon(survivorIconControllers.elements[num]);
			}
		}

		private void PickIcon(SurvivorIconController newPickedIcon)
		{
			if ((object)pickedIcon != newPickedIcon)
			{
				pickedIcon = newPickedIcon;
				onSurvivorPicked?.Invoke(new SurvivorPickInfo
				{
					localUser = currentLocalUser,
					pickedSurvivor = newPickedIcon.survivorDef
				});
				Util.PlaySound("Kill_SelectScreen", base.gameObject);
			}
		}

		private bool ShouldDisplaySurvivor(SurvivorDef survivorDef)
		{
			if ((bool)survivorDef && !survivorDef.hidden)
			{
				return survivorDef.CheckUserHasRequiredEntitlement(currentLocalUser);
			}
			return false;
		}

		private SurvivorDef GetLocalUserExistingSurvivorPreference()
		{
			return currentLocalUser?.userProfile.GetSurvivorPreference();
		}

		public void Build()
		{
			List<SurvivorDef> list = new List<SurvivorDef>();
			foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs)
			{
				if (ShouldDisplaySurvivor(orderedSurvivorDef))
				{
					list.Add(orderedSurvivorDef);
				}
			}
			int count = list.Count;
			int desiredCount = Math.Max(CalcGridCellCount(count, iconContainerGrid.constraintCount) - count, 0);
			survivorIconControllers.AllocateElements(count);
			fillerIcons.AllocateElements(desiredCount);
			fillerIcons.MoveElementsToContainerEnd();
			ReadOnlyCollection<SurvivorIconController> elements = survivorIconControllers.elements;
			for (int i = 0; i < count; i++)
			{
				SurvivorDef survivorDef = list[i];
				SurvivorIconController survivorIconController = elements[i];
				survivorIconController.survivorDef = survivorDef;
				survivorIconController.hgButton.defaultFallbackButton = i == 0;
				if (count > 1)
				{
					int num = 0;
					int num2 = 0;
					if (i == 0)
					{
						num = count - 1;
						num2 = i + 1;
					}
					else if (i == count - 1)
					{
						num = i - 1;
						num2 = 0;
					}
					else
					{
						num = i - 1;
						num2 = i + 1;
					}
					UnityEngine.UI.Navigation navigation = survivorIconController.hgButton.navigation;
					navigation.mode = UnityEngine.UI.Navigation.Mode.Explicit;
					navigation.selectOnLeft = elements[num].hgButton;
					navigation.selectOnRight = elements[num2].hgButton;
					if (i - iconContainerGrid.constraintCount >= 0)
					{
						navigation.selectOnUp = elements[i - iconContainerGrid.constraintCount].hgButton;
					}
					if (i + iconContainerGrid.constraintCount < count)
					{
						navigation.selectOnDown = elements[i + iconContainerGrid.constraintCount].hgButton;
					}
					survivorIconController.hgButton.navigation = navigation;
				}
			}
		}

		private static int CalcGridCellCount(int elementCount, int gridFixedDimensionLength)
		{
			return (int)Mathf.Ceil((float)elementCount / (float)gridFixedDimensionLength) * gridFixedDimensionLength;
		}

		private void EnforceValidChoice()
		{
			int num = FindIconIndex(pickedIcon);
			if ((bool)pickedIcon && pickedIcon.survivorIsAvailable)
			{
				return;
			}
			int num2 = -1;
			ReadOnlyCollection<SurvivorIconController> elements = survivorIconControllers.elements;
			while (num2 < elements.Count)
			{
				int num3 = num + num2;
				if (0 <= num3 && num3 < elements.Count)
				{
					SurvivorIconController survivorIconController = elements[num3];
					if (survivorIconController.survivorIsAvailable)
					{
						PickIcon(survivorIconController);
						break;
					}
				}
				if (num2 >= 0)
				{
					num2++;
				}
				num2 = -num2;
			}
		}
	}
	public class ConsoleFunctions : MonoBehaviour
	{
		public void SubmitCmd(string cmd)
		{
			Console.instance.SubmitCmd(null, cmd);
		}
	}
	public interface IInspectable
	{
		IInspectInfoProvider GetInspectInfoProvider();
	}
	public interface ISupportsMultipleInspectZones
	{
		void SetInspectInfoProvider(int newInspectIndex);
	}
	public interface IInspectInfoProvider
	{
		bool CanBeInspected();

		[NotNull]
		InspectInfo GetInfo();
	}
	public interface IHasInspectHintOverride
	{
		bool GetInspectHintOverride(out string hintOverride);
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class InputBindingDisplayController : MonoBehaviour
	{
		public string actionName;

		private bool needsUpdate = true;

		public AxisRange axisRange;

		public bool useExplicitInputSource;

		public MPEventSystem.InputSource explicitInputSource;

		public bool allowFallbackInputSource;

		private MPEventSystemLocator eventSystemLocator;

		private TextMeshProUGUI guiLabel;

		private TextMeshPro label;

		public Action oneFrameAfterTextUpdate;

		public static Action onBindingsChanged;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			guiLabel = GetComponent<TextMeshProUGUI>();
			label = GetComponent<TextMeshPro>();
		}

		private void OnEnable()
		{
			onBindingsChanged = (Action)Delegate.Combine(onBindingsChanged, new Action(Refresh));
			Refresh();
		}

		private void OnDisable()
		{
			onBindingsChanged = (Action)Delegate.Remove(onBindingsChanged, new Action(Refresh));
		}

		private void Start()
		{
			Refresh();
		}

		private void Refresh()
		{
			if (!(eventSystemLocator?.eventSystem))
			{
				UnityEngine.Debug.LogError("MPEventSystem is invalid.");
				return;
			}
			bool flag = useExplicitInputSource;
			if (useExplicitInputSource && allowFallbackInputSource)
			{
				Player player = ReInput.players.GetPlayer(0);
				if (player != null)
				{
					Controller lastActiveController = player.controllers.GetLastActiveController();
					if (lastActiveController != null)
					{
						switch (explicitInputSource)
						{
						case MPEventSystem.InputSource.Gamepad:
							flag = lastActiveController.type == ControllerType.Joystick;
							break;
						case MPEventSystem.InputSource.MouseAndKeyboard:
							flag = lastActiveController.type == ControllerType.Mouse || lastActiveController.type == ControllerType.Keyboard;
							break;
						}
					}
				}
			}
			string empty = string.Empty;
			empty = ((!flag) ? Glyphs.GetGlyphString(eventSystemLocator.eventSystem, actionName) : Glyphs.GetGlyphString(eventSystemLocator.eventSystem, actionName, axisRange, explicitInputSource));
			if (!string.IsNullOrEmpty(empty))
			{
				if ((bool)guiLabel)
				{
					guiLabel.text = empty;
					StartCoroutine(InvokeOneFrameAfterTextUpdateCallback());
				}
				else if ((bool)label)
				{
					label.text = empty;
					StartCoroutine(InvokeOneFrameAfterTextUpdateCallback());
				}
			}
		}

		private IEnumerator InvokeOneFrameAfterTextUpdateCallback()
		{
			yield return null;
			oneFrameAfterTextUpdate?.Invoke();
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class InputStickVisualizer : MonoBehaviour
	{
		[Header("Move")]
		public Scrollbar moveXBar;

		public Scrollbar moveYBar;

		public TextMeshProUGUI moveXLabel;

		public TextMeshProUGUI moveYLabel;

		[Header("Aim")]
		public Scrollbar aimXBar;

		public Scrollbar aimYBar;

		public TextMeshProUGUI aimXLabel;

		public TextMeshProUGUI aimYLabel;

		public Scrollbar aimStickPostSmoothingXBar;

		public Scrollbar aimStickPostSmoothingYBar;

		public Scrollbar aimStickPostDualZoneXBar;

		public Scrollbar aimStickPostDualZoneYBar;

		public Scrollbar aimStickPostExponentXBar;

		public Scrollbar aimStickPostExponentYBar;

		private MPEventSystemLocator eventSystemLocator;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private Player GetPlayer()
		{
			return eventSystemLocator.eventSystem?.player;
		}

		private CameraRigController GetCameraRigController()
		{
			if (CameraRigController.readOnlyInstancesList.Count <= 0)
			{
				return null;
			}
			return CameraRigController.readOnlyInstancesList[0];
		}

		private void SetBarValues(UnityEngine.Vector2 vector, Scrollbar scrollbarX, Scrollbar scrollbarY)
		{
			if ((bool)scrollbarX)
			{
				scrollbarX.value = Util.Remap(vector.x, -1f, 1f, 0f, 1f);
			}
			if ((bool)scrollbarY)
			{
				scrollbarY.value = Util.Remap(vector.y, -1f, 1f, 0f, 1f);
			}
		}

		private void Update()
		{
			Player player = GetPlayer();
			if ((bool)GetCameraRigController() && player != null)
			{
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(player.GetAxis(0), player.GetAxis(1));
				UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(player.GetAxis(16), player.GetAxis(17));
				SetBarValues(vector, moveXBar, moveYBar);
				SetBarValues(vector2, aimXBar, aimYBar);
				moveXLabel.text = $"move.x={vector.x:0.0000}";
				moveYLabel.text = $"move.y={vector.y:0.0000}";
				aimXLabel.text = $"aim.x={vector2.x:0.0000}";
				aimYLabel.text = $"aim.y={vector2.y:0.0000}";
			}
		}
	}
	public class MPEventSystemManager : MonoBehaviour
	{
		private static readonly Dictionary<int, MPEventSystem> eventSystems;

		public static bool initialized;

		public static ResourceAvailability availability;

		public static MPEventSystem combinedEventSystem { get; private set; }

		public static MPEventSystem kbmEventSystem { get; private set; }

		public static MPEventSystem primaryEventSystem { get; private set; }

		public static MPEventSystem FindEventSystem(Player inputPlayer)
		{
			eventSystems.TryGetValue(inputPlayer.id, out var value);
			return value;
		}

		public static void Initialize()
		{
			if (initialized)
			{
				return;
			}
			GameObject original = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/MPEventSystem");
			IList<Player> players = ReInput.players.Players;
			for (int i = 0; i < players.Count; i++)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(original, RoR2Application.instance.transform);
				gameObject.name = string.Format(CultureInfo.InvariantCulture, "MPEventSystem Player{0}", i);
				MPEventSystem component = gameObject.GetComponent<MPEventSystem>();
				RewiredStandaloneInputModule component2 = gameObject.GetComponent<RewiredStandaloneInputModule>();
				Player player = players[i];
				component2.RewiredPlayerIds = new int[1] { player.id };
				gameObject.GetComponent<MPInput>().player = player;
				if (i == 0)
				{
					kbmEventSystem = component;
					component.allowCursorPush = false;
				}
				component.player = players[i];
				eventSystems[players[i].id] = component;
			}
			combinedEventSystem = eventSystems[0];
			combinedEventSystem.isCombinedEventSystem = true;
			RefreshEventSystems();
			initialized = true;
		}

		private static void RefreshEventSystems()
		{
			int count = LocalUserManager.readOnlyLocalUsersList.Count;
			ReadOnlyCollection<MPEventSystem> readOnlyInstancesList = MPEventSystem.readOnlyInstancesList;
			for (int i = 1; i < readOnlyInstancesList.Count; i++)
			{
				readOnlyInstancesList[i].enabled = readOnlyInstancesList[i].localUser != null;
			}
			int num = 0;
			for (int j = 0; j < readOnlyInstancesList.Count; j++)
			{
				readOnlyInstancesList[j].playerSlot = (readOnlyInstancesList[j].enabled ? num++ : (-1));
			}
			primaryEventSystem = ((count > 0) ? LocalUserManager.readOnlyLocalUsersList[0].eventSystem : combinedEventSystem);
			availability.MakeAvailable();
		}

		private void Update()
		{
			if (!initialized)
			{
				if (!ReInput.isReady)
				{
					return;
				}
				Initialize();
			}
			if (!Application.isBatchMode && kbmEventSystem != null)
			{
				CursorLockMode cursorLockMode = ((!kbmEventSystem.isCursorVisible && !combinedEventSystem.isCursorVisible) ? CursorLockMode.Locked : CursorLockMode.Confined);
				if (cursorLockMode != Cursor.lockState)
				{
					Cursor.lockState = cursorLockMode;
				}
				Cursor.visible = false;
			}
		}

		static MPEventSystemManager()
		{
			eventSystems = new Dictionary<int, MPEventSystem>();
			initialized = false;
			LocalUserManager.onLocalUsersUpdated += RefreshEventSystems;
		}
	}
	public class NetworkUserButton : MonoBehaviour
	{
		public NetworkUser targetUser;

		public bool targetState;

		public string targetUserName;

		private RawImage classImage;

		public void SetUser(NetworkUser user)
		{
			targetUser = user;
			classImage = GetComponentInChildren<RawImage>();
			TextMeshProUGUI componentInChildren = GetComponentInChildren<TextMeshProUGUI>();
			if ((bool)classImage)
			{
				GameObject bodyPrefab = BodyCatalog.GetBodyPrefab(user.bodyIndexPreference);
				if ((bool)bodyPrefab)
				{
					CharacterBody component = bodyPrefab.GetComponent<CharacterBody>();
					if ((bool)component && component.portraitIcon != null)
					{
						classImage.texture = bodyPrefab.GetComponent<CharacterBody>().portraitIcon;
					}
				}
			}
			if ((bool)componentInChildren)
			{
				string nameOverride = user.GetNetworkPlayerName().nameOverride;
				if (nameOverride != null)
				{
					string text2 = (componentInChildren.text = nameOverride);
					targetUserName = text2;
				}
				else
				{
					string text2 = (componentInChildren.text = "???");
					targetUserName = text2;
				}
			}
		}

		public void ToggleUserTargetState()
		{
			targetState = !targetState;
			UpdateColor();
		}

		public void SetUserTargetState(bool state)
		{
			targetState = state;
			UpdateColor();
		}

		private void UpdateColor()
		{
			if (targetState)
			{
				classImage.color = UnityEngine.Color.white;
			}
			else
			{
				classImage.color = new UnityEngine.Color(0.5f, 0.5f, 0.5f, 1f);
			}
		}
	}
	[DisallowMultipleComponent]
	public class PositionIndicator : MonoBehaviour
	{
		public Transform targetTransform;

		private new Transform transform;

		private static readonly List<PositionIndicator> instancesList;

		[Tooltip("The child object to enable when the target is within the frame.")]
		public GameObject insideViewObject;

		[Tooltip("The child object to enable when the target is outside the frame.")]
		public GameObject outsideViewObject;

		[Tooltip("The child object to ALWAYS enable, IF its not my own position indicator.")]
		public GameObject alwaysVisibleObject;

		[Tooltip("Whether or not outsideViewObject should be rotated to point to the target.")]
		public bool shouldRotateOutsideViewObject;

		[Tooltip("The offset to apply to the rotation of the outside view object when shouldRotateOutsideViewObject is set.")]
		public float outsideViewRotationOffset;

		private float yOffset;

		private bool generateDefaultPosition;

		private static BoolConVar cvPositionIndicatorsEnable;

		public UnityEngine.Vector3 defaultPosition { get; set; }

		private void Awake()
		{
			transform = base.transform;
		}

		private void Start()
		{
			if (!generateDefaultPosition)
			{
				generateDefaultPosition = true;
				defaultPosition = base.transform.position;
			}
			if ((bool)targetTransform)
			{
				yOffset = CalcHeadOffset(targetTransform) + 1f;
			}
		}

		private static float CalcHeadOffset(Transform transform)
		{
			Collider component = transform.GetComponent<Collider>();
			if ((bool)component)
			{
				return component.bounds.extents.y;
			}
			return 0f;
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void OnValidate()
		{
			if ((bool)insideViewObject && (bool)insideViewObject.GetComponentInChildren<PositionIndicator>())
			{
				UnityEngine.Debug.LogError("insideViewObject may not be assigned another object with another PositionIndicator in its heirarchy!");
				insideViewObject = null;
			}
			if ((bool)outsideViewObject && (bool)outsideViewObject.GetComponentInChildren<PositionIndicator>())
			{
				UnityEngine.Debug.LogError("outsideViewObject may not be assigned another object with another PositionIndicator in its heirarchy!");
				outsideViewObject = null;
			}
		}

		static PositionIndicator()
		{
			instancesList = new List<PositionIndicator>();
			cvPositionIndicatorsEnable = new BoolConVar("position_indicators_enable", ConVarFlags.None, "1", "Enables/Disables position indicators for allies, bosses, pings, etc.");
			UICamera.onUICameraPreCull += UpdatePositions;
		}

		private static void UpdatePositions(UICamera uiCamera)
		{
			Camera sceneCam = uiCamera.cameraRigController.sceneCam;
			Camera camera = uiCamera.camera;
			UnityEngine.Rect pixelRect = camera.pixelRect;
			UnityEngine.Vector2 center = pixelRect.center;
			pixelRect.size *= 0.95f;
			pixelRect.center = center;
			UnityEngine.Vector2 center2 = pixelRect.center;
			float num = 1f / (pixelRect.width * 0.5f);
			float num2 = 1f / (pixelRect.height * 0.5f);
			UnityEngine.Quaternion rotation = uiCamera.transform.rotation;
			CameraRigController cameraRigController = uiCamera.cameraRigController;
			Transform transform = null;
			if ((bool)cameraRigController && (bool)cameraRigController.target)
			{
				CharacterBody component = cameraRigController.target.GetComponent<CharacterBody>();
				transform = ((!component) ? cameraRigController.target.transform : component.coreTransform);
			}
			for (int i = 0; i < instancesList.Count; i++)
			{
				PositionIndicator positionIndicator = instancesList[i];
				bool flag = false;
				bool flag2 = false;
				bool active = false;
				if (!HUD.cvHudEnable.value)
				{
					positionIndicator.insideViewObject.SetActive(value: false);
					positionIndicator.outsideViewObject.SetActive(value: false);
					positionIndicator.alwaysVisibleObject.SetActive(value: false);
					continue;
				}
				float num3 = 0f;
				UnityEngine.Vector3 vector2;
				int num4;
				if (cvPositionIndicatorsEnable.value)
				{
					UnityEngine.Vector3 vector = (positionIndicator.targetTransform ? positionIndicator.targetTransform.position : positionIndicator.defaultPosition);
					if (!positionIndicator.targetTransform || ((bool)positionIndicator.targetTransform && positionIndicator.targetTransform != transform))
					{
						active = true;
						vector2 = sceneCam.WorldToScreenPoint(vector + new UnityEngine.Vector3(0f, positionIndicator.yOffset, 0f));
						bool flag3 = vector2.z <= 0f;
						if (!flag3)
						{
							num4 = (pixelRect.Contains(vector2) ? 1 : 0);
							if (num4 != 0)
							{
								goto IL_0279;
							}
						}
						else
						{
							num4 = 0;
						}
						UnityEngine.Vector2 vector3 = (UnityEngine.Vector2)vector2 - center2;
						float a = Mathf.Abs(vector3.x * num);
						float b = Mathf.Abs(vector3.y * num2);
						float num5 = Mathf.Max(a, b);
						vector3 /= num5;
						vector3 *= (flag3 ? (-1f) : 1f);
						vector2 = vector3 + center2;
						if (positionIndicator.shouldRotateOutsideViewObject)
						{
							num3 = Mathf.Atan2(vector3.y, vector3.x) * 57.29578f;
						}
						goto IL_0279;
					}
				}
				goto IL_02a7;
				IL_0279:
				flag = (byte)num4 != 0;
				flag2 = num4 == 0;
				vector2.z = 1f;
				UnityEngine.Vector3 position = camera.ScreenToWorldPoint(vector2);
				positionIndicator.transform.SetPositionAndRotation(position, rotation);
				goto IL_02a7;
				IL_02a7:
				if ((bool)positionIndicator.alwaysVisibleObject)
				{
					positionIndicator.alwaysVisibleObject.SetActive(active);
				}
				if (positionIndicator.insideViewObject == positionIndicator.outsideViewObject)
				{
					if ((bool)positionIndicator.insideViewObject)
					{
						positionIndicator.insideViewObject.SetActive(flag || flag2);
					}
					continue;
				}
				if ((bool)positionIndicator.insideViewObject)
				{
					positionIndicator.insideViewObject.SetActive(flag);
				}
				if ((bool)positionIndicator.outsideViewObject)
				{
					positionIndicator.outsideViewObject.SetActive(flag2);
					if (flag2 && positionIndicator.shouldRotateOutsideViewObject)
					{
						positionIndicator.outsideViewObject.transform.localEulerAngles = new UnityEngine.Vector3(0f, 0f, num3 + positionIndicator.outsideViewRotationOffset);
					}
				}
			}
		}
	}
	[RequireComponent(typeof(Canvas))]
	public class RefreshCanvasDrawOrder : MonoBehaviour
	{
		public int canvasSortingOrderDelta = 1;

		public Canvas canvas;

		private int originalCanvasSortingOrder;

		private bool cachedOriginalCanvasSortingOrder;

		private void OnEnable()
		{
			if (canvas != null)
			{
				if (!cachedOriginalCanvasSortingOrder)
				{
					originalCanvasSortingOrder = canvas.sortingOrder;
					cachedOriginalCanvasSortingOrder = true;
				}
				canvas.overrideSorting = true;
				canvas.sortingOrder = -1000;
				canvas.sortingOrder = originalCanvasSortingOrder + canvasSortingOrderDelta;
			}
		}
	}
	public class ShrinkWrapLayoutElement : MonoBehaviour, ILayoutElement
	{
		public float minWidth { get; private set; }

		public float preferredWidth { get; private set; }

		public float flexibleWidth { get; private set; }

		public float minHeight { get; private set; }

		public float preferredHeight { get; private set; }

		public float flexibleHeight { get; private set; }

		public int layoutPriority { get; private set; }

		public void CalculateLayoutInputHorizontal()
		{
			preferredWidth = 0f;
			if (base.transform.childCount != 0)
			{
				UnityEngine.Rect rect = ((RectTransform)base.transform.GetChild(0)).rect;
				int i = 1;
				for (int childCount = base.transform.childCount; i < childCount; i++)
				{
					UnityEngine.Rect rect2 = ((RectTransform)base.transform.GetChild(i)).rect;
					rect.xMin = Mathf.Min(rect.xMin, rect2.xMin);
					rect.xMax = Mathf.Max(rect.xMax, rect2.xMax);
				}
				minWidth = rect.width;
				preferredWidth = rect.width;
				flexibleWidth = 0f;
			}
		}

		public void CalculateLayoutInputVertical()
		{
			preferredHeight = 0f;
			if (base.transform.childCount != 0)
			{
				UnityEngine.Rect rect = ((RectTransform)base.transform.GetChild(0)).rect;
				int i = 1;
				for (int childCount = base.transform.childCount; i < childCount; i++)
				{
					UnityEngine.Rect rect2 = ((RectTransform)base.transform.GetChild(i)).rect;
					rect.yMin = Mathf.Min(rect.yMin, rect2.yMin);
					rect.yMax = Mathf.Max(rect.yMax, rect2.yMax);
				}
				minHeight = rect.height;
				preferredHeight = rect.height;
				flexibleHeight = 0f;
			}
		}
	}
	[RequireComponent(typeof(RawImage))]
	public class SocialUserIcon : UIBehaviour
	{
		private SocialUserIconBehavior behavior = SocialUserIconBehaviorFactory.Get();

		[SerializeField]
		private UserManager.AvatarSize avatarSize;

		protected override void OnEnable()
		{
			behavior.OnEnable(base.gameObject, this);
		}

		protected override void Awake()
		{
			behavior.Awake(base.gameObject, this);
		}

		protected override void OnDestroy()
		{
			behavior.OnDestroy();
		}

		public virtual void Refresh(bool shouldForceRefresh = false)
		{
			behavior.Refresh(shouldForceRefresh);
		}

		public virtual void SetFromMaster(CharacterMaster master)
		{
			behavior.SetFromMaster(master);
		}

		public void RefreshWithUser(PlatformID newUserID)
		{
			behavior.RefreshWithUser(newUserID);
		}
	}
	public static class SocialUserIconBehaviorFactory
	{
		public static SocialUserIconBehavior Get()
		{
			return new SocialUserIconBehavior();
		}
	}
	public class VoiceIcon : UIBehaviour
	{
		public GameObject MutedIcon;

		public GameObject SilentIcon;

		public GameObject SpeakingIcon;

		public GameObject UnavailableIcon;

		private PlatformID playerId;

		private bool isLocalMuted;

		private bool waitForInitialization;

		private float retryCount;

		private bool doUserRetry;

		private int togglePressedCount;

		protected override void OnDestroy()
		{
			base.OnDestroy();
		}

		protected override void Awake()
		{
			base.Awake();
			togglePressedCount = 0;
			if (!PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.Voice))
			{
				base.gameObject.SetActive(value: false);
				return;
			}
			MutedIcon.SetActive(value: false);
			SilentIcon.SetActive(value: false);
			SpeakingIcon.SetActive(value: false);
			UnavailableIcon.SetActive(value: false);
		}

		public virtual void Refresh()
		{
		}

		public void Update()
		{
		}

		public void SetFromPlayerId(PlatformID playerUserID)
		{
		}

		public void ToggleMute()
		{
			UnavailableIcon.SetActive(value: false);
			MutedIcon.SetActive(value: false);
			SilentIcon.SetActive(value: true);
			SpeakingIcon.SetActive(value: false);
		}
	}
	[RequireComponent(typeof(Camera))]
	public class UICamera : MonoBehaviour
	{
		public delegate void UICameraDelegate(UICamera sceneCamera);

		private static readonly List<UICamera> instancesList = new List<UICamera>();

		public static readonly ReadOnlyCollection<UICamera> readOnlyInstancesList = new ReadOnlyCollection<UICamera>(instancesList);

		public Camera camera { get; private set; }

		public CameraRigController cameraRigController { get; private set; }

		public static event UICameraDelegate onUICameraPreCull;

		public static event UICameraDelegate onUICameraPreRender;

		public static event UICameraDelegate onUICameraPostRender;

		private void Awake()
		{
			camera = GetComponent<Camera>();
			cameraRigController = GetComponentInParent<CameraRigController>();
			camera.eventMask = ~camera.cullingMask;
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void OnPreCull()
		{
			if (UICamera.onUICameraPreCull != null)
			{
				UICamera.onUICameraPreCull(this);
			}
		}

		private void OnPreRender()
		{
			if (UICamera.onUICameraPreRender != null)
			{
				UICamera.onUICameraPreRender(this);
			}
		}

		private void OnPostRender()
		{
			if (UICamera.onUICameraPostRender != null)
			{
				UICamera.onUICameraPostRender(this);
			}
		}

		public EventSystem GetAssociatedEventSystem()
		{
			if ((bool)cameraRigController.viewer && cameraRigController.viewer.localUser != null)
			{
				return cameraRigController.viewer.localUser.eventSystem;
			}
			return null;
		}

		public static UICamera FindViewerUICamera(LocalUser localUserViewer)
		{
			if (localUserViewer != null)
			{
				for (int i = 0; i < instancesList.Count; i++)
				{
					if (instancesList[i].cameraRigController.viewer.localUser == localUserViewer)
					{
						return instancesList[i];
					}
				}
			}
			return null;
		}
	}
	public class UnlockableGranter : MonoBehaviour
	{
		[Obsolete("'unlockableString' will be discontinued. Use 'unlockableDef' instead.", false)]
		[Tooltip("'unlockableString' will be discontinued. Use 'unlockableDef' instead.")]
		public string unlockableString;

		public UnlockableDef unlockableDef;

		public void GrantUnlockable(Interactor interactor)
		{
			string value = unlockableString;
			if (!unlockableDef && !string.IsNullOrEmpty(value))
			{
				unlockableDef = UnlockableCatalog.GetUnlockableDef(value);
			}
			CharacterBody component = interactor.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				Run.instance.GrantUnlockToSinglePlayer(unlockableDef, component);
			}
		}
	}
	[RequireComponent(typeof(EntityLocator))]
	public class UnlockPickup : MonoBehaviour
	{
		public static string itemPickupSoundString = "Play_UI_item_pickup";

		private bool consumed;

		private float stopWatch;

		public float waitDuration = 0.5f;

		public string displayNameToken;

		[Obsolete("'unlockableName' will be discontinued. Use 'unlockableDef' instead.", false)]
		[Tooltip("'unlockableName' will be discontinued. Use 'unlockableDef' instead.")]
		public string unlockableName;

		public UnlockableDef unlockableDef;

		private void FixedUpdate()
		{
			stopWatch += Time.fixedDeltaTime;
		}

		private void GrantPickup(GameObject activator)
		{
			if ((bool)Run.instance)
			{
				Util.PlaySound(itemPickupSoundString, activator);
				string value = unlockableName;
				if (!unlockableDef && !string.IsNullOrEmpty(value))
				{
					unlockableDef = UnlockableCatalog.GetUnlockableDef(value);
				}
				Run.instance.GrantUnlockToAllParticipatingPlayers(unlockableDef);
				string pickupToken = "???";
				if ((bool)unlockableDef)
				{
					pickupToken = unlockableDef.nameToken;
				}
				Chat.SendBroadcastChat(new Chat.PlayerPickupChatMessage
				{
					subjectAsCharacterBody = activator.GetComponent<CharacterBody>(),
					baseToken = "PLAYER_PICKUP",
					pickupToken = pickupToken,
					pickupColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unlockable),
					pickupQuantity = 1u
				});
				consumed = true;
				GameObject entity = base.gameObject;
				EntityLocator component = GetComponent<EntityLocator>();
				if ((bool)component.entity)
				{
					entity = component.entity;
				}
				UnityEngine.Object.Destroy(entity);
			}
		}

		private static bool BodyHasPickupPermission(CharacterBody body)
		{
			if ((bool)(body.masterObject ? body.masterObject.GetComponent<PlayerCharacterMasterController>() : null))
			{
				return body.inventory;
			}
			return false;
		}

		private void OnTriggerStay(Collider other)
		{
			if (!NetworkServer.active || !(stopWatch >= waitDuration) || consumed)
			{
				return;
			}
			CharacterBody component = other.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				TeamComponent component2 = component.GetComponent<TeamComponent>();
				if ((bool)component2 && component2.teamIndex == TeamIndex.Player && (bool)component.inventory)
				{
					GrantPickup(component.gameObject);
				}
			}
		}
	}
	public class UnparentOnStart : MonoBehaviour
	{
		private void Start()
		{
			base.transform.parent = null;
		}
	}
	[RequireComponent(typeof(Collider))]
	public class VehicleForceZone : MonoBehaviour
	{
		public Rigidbody vehicleRigidbody;

		public float impactMultiplier;

		private Collider collider;

		private void Start()
		{
			collider = GetComponent<Collider>();
		}

		public void OnTriggerEnter(Collider other)
		{
			CharacterMotor component = other.GetComponent<CharacterMotor>();
			HealthComponent component2 = other.GetComponent<HealthComponent>();
			if ((bool)component && (bool)component2)
			{
				UnityEngine.Vector3 position = base.transform.position;
				_ = vehicleRigidbody.velocity.normalized;
				UnityEngine.Vector3 pointVelocity = vehicleRigidbody.GetPointVelocity(position);
				UnityEngine.Vector3 vector = pointVelocity * vehicleRigidbody.mass * impactMultiplier;
				_ = vehicleRigidbody.mass;
				Mathf.Pow(pointVelocity.magnitude, 2f);
				float num = component.mass / (component.mass + vehicleRigidbody.mass);
				vehicleRigidbody.AddForceAtPosition(-vector * num, position);
				UnityEngine.Debug.LogFormat("Impulse: {0}, Ratio: {1}", vector.magnitude, num);
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.attacker = base.gameObject;
				damageInfo.force = vector;
				damageInfo.position = position;
				component2.TakeDamageForce(damageInfo, alwaysApply: true);
			}
		}

		public void OnCollisionEnter(Collision collision)
		{
			UnityEngine.Debug.LogFormat("Hit {0}", collision.gameObject);
			Rigidbody component = collision.collider.GetComponent<Rigidbody>();
			if ((bool)component)
			{
				HealthComponent component2 = component.GetComponent<HealthComponent>();
				if ((bool)component2)
				{
					UnityEngine.Vector3 point = collision.contacts[0].point;
					_ = collision.contacts[0].normal;
					vehicleRigidbody.GetPointVelocity(point);
					UnityEngine.Vector3 impulse = collision.impulse;
					float num = 0f;
					vehicleRigidbody.AddForceAtPosition(impulse * num, point);
					UnityEngine.Debug.LogFormat("Impulse: {0}, Ratio: {1}", impulse, num);
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.attacker = base.gameObject;
					damageInfo.force = -impulse * (1f - num);
					damageInfo.position = point;
					component2.TakeDamageForce(damageInfo, alwaysApply: true);
				}
			}
		}

		private void Update()
		{
		}
	}
	[DisallowMultipleComponent]
	public class VehicleSeat : NetworkBehaviour, IInteractable
	{
		private struct PassengerInfo
		{
			private static readonly List<EntityStateMachine> sharedBuffer = new List<EntityStateMachine>();

			public readonly Transform transform;

			public readonly CharacterBody body;

			public readonly InputBankTest inputBank;

			public readonly InteractionDriver interactionDriver;

			public readonly CharacterMotor characterMotor;

			public readonly EntityStateMachine bodyStateMachine;

			public readonly CharacterModel characterModel;

			public readonly NetworkIdentity networkIdentity;

			public readonly Collider collider;

			public bool hasEffectiveAuthority => Util.HasEffectiveAuthority(networkIdentity);

			public PassengerInfo(GameObject passengerBodyObject)
			{
				transform = passengerBodyObject.transform;
				body = passengerBodyObject.GetComponent<CharacterBody>();
				inputBank = passengerBodyObject.GetComponent<InputBankTest>();
				interactionDriver = passengerBodyObject.GetComponent<InteractionDriver>();
				characterMotor = passengerBodyObject.GetComponent<CharacterMotor>();
				networkIdentity = passengerBodyObject.GetComponent<NetworkIdentity>();
				collider = passengerBodyObject.GetComponent<Collider>();
				bodyStateMachine = null;
				passengerBodyObject.GetComponents(sharedBuffer);
				for (int i = 0; i < sharedBuffer.Count; i++)
				{
					EntityStateMachine entityStateMachine = sharedBuffer[i];
					if (string.CompareOrdinal(entityStateMachine.customName, "Body") == 0)
					{
						bodyStateMachine = entityStateMachine;
						break;
					}
				}
				sharedBuffer.Clear();
				characterModel = null;
				if ((bool)body.modelLocator && (bool)body.modelLocator.modelTransform)
				{
					characterModel = body.modelLocator.modelTransform.GetComponent<CharacterModel>();
				}
			}

			public string GetString()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("transform=").Append(transform).AppendLine();
				stringBuilder.Append("body=").Append(body).AppendLine();
				stringBuilder.Append("inputBank=").Append(inputBank).AppendLine();
				stringBuilder.Append("interactionDriver=").Append(interactionDriver).AppendLine();
				stringBuilder.Append("characterMotor=").Append(characterMotor).AppendLine();
				stringBuilder.Append("bodyStateMachine=").Append(bodyStateMachine).AppendLine();
				stringBuilder.Append("characterModel=").Append(characterModel).AppendLine();
				stringBuilder.Append("networkIdentity=").Append(networkIdentity).AppendLine();
				stringBuilder.Append("hasEffectiveAuthority=").Append(hasEffectiveAuthority).AppendLine();
				return stringBuilder.ToString();
			}
		}

		public delegate void InteractabilityCheckDelegate(CharacterBody activator, ref Interactability? resultOverride);

		public SerializableEntityStateType passengerState;

		public Transform seatPosition;

		public Transform exitPosition;

		public bool ejectOnCollision;

		public bool hidePassenger = true;

		public float exitVelocityFraction = 1f;

		public UnityEvent onPassengerEnterUnityEvent;

		[FormerlySerializedAs("OnPassengerExitUnityEvent")]
		public UnityEvent onPassengerExitUnityEvent;

		public string enterVehicleContextString;

		public string exitVehicleContextString;

		public bool disablePassengerMotor;

		public bool isEquipmentActivationAllowed;

		public bool shouldProximityHighlight = true;

		[SyncVar(hook = "SetPassenger")]
		private GameObject passengerBodyObject;

		private PassengerInfo passengerInfo;

		private Rigidbody rigidbody;

		private Collider collider;

		[HideInInspector]
		public CameraTargetParams targetParams;

		public CallbackCheck<Interactability, CharacterBody> enterVehicleAllowedCheck = new CallbackCheck<Interactability, CharacterBody>();

		public CallbackCheck<Interactability, CharacterBody> exitVehicleAllowedCheck = new CallbackCheck<Interactability, CharacterBody>();

		public CallbackCheck<bool, GameObject> handleVehicleEnterRequestServer = new CallbackCheck<bool, GameObject>();

		public CallbackCheck<bool, GameObject> handleVehicleExitRequestServer = new CallbackCheck<bool, GameObject>();

		private static readonly BoolConVar cvVehicleSeatDebug;

		private Run.FixedTimeStamp passengerAssignmentTime = Run.FixedTimeStamp.negativeInfinity;

		private readonly float passengerAssignmentCooldown = 0.2f;

		private NetworkInstanceId ___passengerBodyObjectNetId;

		private static int kCmdCmdEjectPassenger;

		public CharacterBody currentPassengerBody => passengerInfo.body;

		public InputBankTest currentPassengerInputBank => passengerInfo.inputBank;

		private static bool shouldLog => cvVehicleSeatDebug.value;

		public bool hasPassenger => passengerBodyObject;

		public GameObject NetworkpassengerBodyObject
		{
			get
			{
				return passengerBodyObject;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetPassenger(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVarGameObject(value, ref passengerBodyObject, 1u, ref ___passengerBodyObjectNetId);
			}
		}

		public event Action<GameObject> onPassengerEnter;

		public event Action<GameObject> onPassengerExit;

		public static event Action<VehicleSeat, GameObject> onPassengerEnterGlobal;

		public static event Action<VehicleSeat, GameObject> onPassengerExitGlobal;

		public string GetContextString(Interactor activator)
		{
			if (!passengerBodyObject)
			{
				return Language.GetString(enterVehicleContextString);
			}
			if ((object)passengerBodyObject == activator.gameObject)
			{
				return Language.GetString(exitVehicleContextString);
			}
			return null;
		}

		public Interactability GetInteractability(Interactor activator)
		{
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if (!passengerBodyObject)
			{
				return enterVehicleAllowedCheck.Evaluate(component) ?? Interactability.Available;
			}
			if ((object)passengerBodyObject == activator.gameObject && passengerAssignmentTime.timeSince >= passengerAssignmentCooldown)
			{
				return exitVehicleAllowedCheck.Evaluate(component) ?? Interactability.Available;
			}
			if ((bool)component && (bool)component.currentVehicle && (object)component.currentVehicle != this)
			{
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Disabled;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			if (!passengerBodyObject)
			{
				if (!handleVehicleEnterRequestServer.Evaluate(activator.gameObject).HasValue)
				{
					SetPassenger(activator.gameObject);
				}
			}
			else if ((object)activator.gameObject == passengerBodyObject && !handleVehicleExitRequestServer.Evaluate(activator.gameObject).HasValue)
			{
				SetPassenger(null);
			}
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public bool ShouldShowOnScanner()
		{
			return true;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		private void Awake()
		{
			rigidbody = GetComponent<Rigidbody>();
			collider = GetComponent<Collider>();
			targetParams = GetComponent<CameraTargetParams>();
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			if (!NetworkServer.active && (bool)passengerBodyObject)
			{
				OnPassengerEnter(passengerBodyObject);
			}
		}

		private void SetPassengerInternal(GameObject newPassengerBodyObject)
		{
			if ((bool)passengerBodyObject)
			{
				OnPassengerExit(passengerBodyObject);
			}
			NetworkpassengerBodyObject = newPassengerBodyObject;
			passengerInfo = default(PassengerInfo);
			passengerAssignmentTime = Run.FixedTimeStamp.now;
			if ((bool)passengerBodyObject)
			{
				OnPassengerEnter(passengerBodyObject);
			}
			_ = shouldLog;
		}

		private void SetPassenger(GameObject newPassengerBodyObject)
		{
			string text = (newPassengerBodyObject ? Util.GetBestBodyName(newPassengerBodyObject) : "null");
			if (shouldLog)
			{
				UnityEngine.Debug.LogFormat("SetPassenger passenger={0}", text);
			}
			if (base.syncVarHookGuard)
			{
				_ = shouldLog;
				NetworkpassengerBodyObject = newPassengerBodyObject;
				return;
			}
			_ = shouldLog;
			if ((object)passengerBodyObject == newPassengerBodyObject)
			{
				_ = shouldLog;
				return;
			}
			_ = shouldLog;
			SetPassengerInternal(newPassengerBodyObject);
		}

		private void OnPassengerMovementHit(ref CharacterMotor.MovementHitInfo movementHitInfo)
		{
			if (NetworkServer.active && ejectOnCollision && passengerAssignmentTime.timeSince > Time.fixedDeltaTime)
			{
				SetPassenger(null);
			}
		}

		private void ForcePassengerState()
		{
			if ((bool)passengerInfo.bodyStateMachine && passengerInfo.hasEffectiveAuthority)
			{
				Type type = passengerState.GetType();
				if (passengerInfo.bodyStateMachine.state.GetType() != type)
				{
					passengerInfo.bodyStateMachine.SetInterruptState(EntityStateCatalog.InstantiateState(ref passengerState), InterruptPriority.Vehicle);
				}
			}
		}

		private void FixedUpdate()
		{
			ForcePassengerState();
			UpdatePassengerPosition();
			if ((bool)passengerInfo.characterMotor)
			{
				passengerInfo.characterMotor.velocity = UnityEngine.Vector3.zero;
			}
		}

		private void UpdatePassengerPosition()
		{
			UnityEngine.Vector3 position = seatPosition.position;
			if ((bool)passengerInfo.characterMotor)
			{
				passengerInfo.characterMotor.velocity = UnityEngine.Vector3.zero;
				passengerInfo.characterMotor.Motor.BaseVelocity = UnityEngine.Vector3.zero;
				passengerInfo.characterMotor.Motor.SetPosition(position);
				if (!disablePassengerMotor && Time.inFixedTimeStep)
				{
					passengerInfo.characterMotor.rootMotion = position - passengerInfo.transform.position;
				}
			}
			else if ((bool)passengerInfo.transform)
			{
				passengerInfo.transform.position = position;
			}
		}

		[Server]
		public bool AssignPassenger(GameObject bodyObject)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Boolean RoR2.VehicleSeat::AssignPassenger(UnityEngine.GameObject)' called on client");
				return false;
			}
			if ((bool)passengerBodyObject)
			{
				return false;
			}
			if ((bool)bodyObject)
			{
				CharacterBody component = bodyObject.GetComponent<CharacterBody>();
				if ((bool)component && (bool)component.currentVehicle)
				{
					component.currentVehicle.EjectPassenger(bodyObject);
				}
			}
			SetPassenger(bodyObject);
			return true;
		}

		[Server]
		public void EjectPassenger(GameObject bodyObject)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VehicleSeat::EjectPassenger(UnityEngine.GameObject)' called on client");
			}
			else if ((object)bodyObject == passengerBodyObject)
			{
				SetPassenger(null);
			}
		}

		[Server]
		public void EjectPassenger()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VehicleSeat::EjectPassenger()' called on client");
			}
			else
			{
				SetPassenger(null);
			}
		}

		[Command]
		public void CmdEjectPassenger()
		{
			SetPassenger(null);
		}

		private void OnDestroy()
		{
			SetPassenger(null);
		}

		private void OnPassengerEnter(GameObject passenger)
		{
			passengerInfo = new PassengerInfo(passengerBodyObject);
			if ((bool)passengerInfo.body)
			{
				passengerInfo.body.currentVehicle = this;
			}
			if (hidePassenger && (bool)passengerInfo.characterModel)
			{
				passengerInfo.characterModel.invisibilityCount++;
			}
			ForcePassengerState();
			if ((bool)passengerInfo.characterMotor)
			{
				if (disablePassengerMotor)
				{
					passengerInfo.characterMotor.enabled = false;
				}
				else
				{
					passengerInfo.characterMotor.onMovementHit += OnPassengerMovementHit;
				}
			}
			if ((bool)passengerInfo.collider && (bool)collider)
			{
				Physics.IgnoreCollision(collider, passengerInfo.collider, ignore: true);
			}
			if ((bool)passengerInfo.interactionDriver)
			{
				passengerInfo.interactionDriver.interactableOverride = base.gameObject;
			}
			_ = shouldLog;
			this.onPassengerEnter?.Invoke(passengerBodyObject);
			onPassengerEnterUnityEvent?.Invoke();
			VehicleSeat.onPassengerEnterGlobal?.Invoke(this, passengerBodyObject);
		}

		private void OnPassengerExit(GameObject passenger)
		{
			_ = shouldLog;
			if (hidePassenger && (bool)passengerInfo.characterModel)
			{
				passengerInfo.characterModel.invisibilityCount--;
			}
			if ((bool)passengerInfo.body)
			{
				passengerInfo.body.currentVehicle = null;
			}
			if ((bool)passengerInfo.characterMotor)
			{
				if (disablePassengerMotor)
				{
					passengerInfo.characterMotor.enabled = true;
				}
				else
				{
					passengerInfo.characterMotor.onMovementHit -= OnPassengerMovementHit;
				}
				passengerInfo.characterMotor.velocity = UnityEngine.Vector3.zero;
				passengerInfo.characterMotor.rootMotion = UnityEngine.Vector3.zero;
				passengerInfo.characterMotor.Motor.BaseVelocity = UnityEngine.Vector3.zero;
			}
			if ((bool)passengerInfo.collider && (bool)collider)
			{
				Physics.IgnoreCollision(collider, passengerInfo.collider, ignore: false);
			}
			if (passengerInfo.hasEffectiveAuthority)
			{
				if ((bool)passengerInfo.bodyStateMachine && passengerInfo.bodyStateMachine.CanInterruptState(InterruptPriority.Vehicle))
				{
					passengerInfo.bodyStateMachine.SetNextStateToMain();
				}
				UnityEngine.Vector3 newPosition = (exitPosition ? exitPosition.position : seatPosition.position);
				TeleportHelper.TeleportGameObject(passengerInfo.transform.gameObject, newPosition);
			}
			if ((bool)passengerInfo.interactionDriver && (object)passengerInfo.interactionDriver.interactableOverride == base.gameObject)
			{
				passengerInfo.interactionDriver.interactableOverride = null;
			}
			if ((bool)rigidbody && (bool)passengerInfo.characterMotor)
			{
				passengerInfo.characterMotor.velocity = rigidbody.velocity * exitVelocityFraction;
			}
			this.onPassengerExit?.Invoke(passengerBodyObject);
			onPassengerExitUnityEvent?.Invoke();
			VehicleSeat.onPassengerExitGlobal?.Invoke(this, passengerBodyObject);
		}

		static VehicleSeat()
		{
			cvVehicleSeatDebug = new BoolConVar("vehicle_seat_debug", ConVarFlags.None, "0", "Enables debug logging for VehicleSeat.");
			kCmdCmdEjectPassenger = -1985903462;
			NetworkBehaviour.RegisterCommandDelegate(typeof(VehicleSeat), kCmdCmdEjectPassenger, InvokeCmdCmdEjectPassenger);
			NetworkCRC.RegisterBehaviour("VehicleSeat", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdEjectPassenger(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdEjectPassenger called on client.");
			}
			else
			{
				((VehicleSeat)obj).CmdEjectPassenger();
			}
		}

		public void CallCmdEjectPassenger()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdEjectPassenger called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdEjectPassenger();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdEjectPassenger);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdEjectPassenger");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(passengerBodyObject);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(passengerBodyObject);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___passengerBodyObjectNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetPassenger(reader.ReadGameObject());
			}
		}

		public override void PreStartClient()
		{
			if (!___passengerBodyObjectNetId.IsEmpty())
			{
				NetworkpassengerBodyObject = ClientScene.FindLocalObject(___passengerBodyObjectNetId);
			}
		}
	}
	public class VelocityRandomOnStart : MonoBehaviour
	{
		public enum DirectionMode
		{
			Sphere,
			Hemisphere,
			Cone
		}

		public float minSpeed;

		public float maxSpeed;

		public UnityEngine.Vector3 baseDirection = UnityEngine.Vector3.up;

		public bool localDirection;

		public DirectionMode directionMode;

		public float coneAngle = 30f;

		[Tooltip("Minimum angular speed in degrees/second.")]
		public float minAngularSpeed;

		[Tooltip("Maximum angular speed in degrees/second.")]
		public float maxAngularSpeed;

		private void Start()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			Rigidbody component = GetComponent<Rigidbody>();
			if (!component)
			{
				return;
			}
			float num = ((minSpeed != maxSpeed) ? UnityEngine.Random.Range(minSpeed, maxSpeed) : minSpeed);
			if (num != 0f)
			{
				UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
				UnityEngine.Vector3 vector2 = (localDirection ? (base.transform.rotation * baseDirection) : baseDirection);
				switch (directionMode)
				{
				case DirectionMode.Sphere:
					vector = UnityEngine.Random.onUnitSphere;
					break;
				case DirectionMode.Hemisphere:
					vector = UnityEngine.Random.onUnitSphere;
					if (UnityEngine.Vector3.Dot(vector, vector2) < 0f)
					{
						vector = -vector;
					}
					break;
				case DirectionMode.Cone:
					vector = Util.ApplySpread(vector2, 0f, coneAngle, 1f, 1f);
					break;
				}
				component.velocity = vector * num;
			}
			float num2 = ((minAngularSpeed != maxAngularSpeed) ? UnityEngine.Random.Range(minAngularSpeed, maxAngularSpeed) : minAngularSpeed);
			if (num2 != 0f)
			{
				component.angularVelocity = UnityEngine.Random.onUnitSphere * (num2 * (MathF.PI / 180f));
			}
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class VendingMachineBehavior : NetworkBehaviour
	{
		[SerializeField]
		private int maxPurchases;

		[SerializeField]
		private float healFraction;

		[SerializeField]
		private GameObject detonateEffect;

		[SerializeField]
		private float vendingRadius;

		[SerializeField]
		private int numBonusOrbs;

		[SerializeField]
		private Transform orbOrigin;

		[SerializeField]
		private Animator animator;

		[SerializeField]
		private string animatorTriggerNameVend;

		[SerializeField]
		private string animatorIntNameVendsRemaining;

		private PurchaseInteraction purchaseInteraction;

		private static int kRpcRpcTriggerVendAnimation;

		public int purchaseCount { get; private set; }

		public static event Action<ShrineHealingBehavior, Interactor> onActivated;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		private void Awake()
		{
			purchaseInteraction = GetComponent<PurchaseInteraction>();
		}

		[Server]
		public void Vend(Interactor activator)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VendingMachineBehavior::Vend(RoR2.Interactor)' called on client");
				return;
			}
			int num = purchaseCount + 1;
			purchaseCount = num;
			CallRpcTriggerVendAnimation(maxPurchases - purchaseCount);
			CharacterBody component = activator.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				SendOrbToBody(component);
				BullseyeSearch bullseyeSearch = new BullseyeSearch();
				bullseyeSearch.teamMaskFilter = TeamMask.none;
				if ((bool)component.teamComponent)
				{
					bullseyeSearch.teamMaskFilter.AddTeam(component.teamComponent.teamIndex);
				}
				bullseyeSearch.filterByLoS = false;
				bullseyeSearch.maxDistanceFilter = vendingRadius;
				bullseyeSearch.maxAngleFilter = 360f;
				bullseyeSearch.searchOrigin = base.transform.position;
				bullseyeSearch.searchDirection = UnityEngine.Vector3.up;
				bullseyeSearch.sortMode = BullseyeSearch.SortMode.None;
				bullseyeSearch.RefreshCandidates();
				bullseyeSearch.FilterOutGameObject(activator.gameObject);
				List<HurtBox> list = new List<HurtBox>(bullseyeSearch.GetResults());
				list.Sort(BonusOrbHurtBoxSort);
				for (int i = 0; i < numBonusOrbs && i < list.Count; i++)
				{
					SendOrbToBody(list[i].healthComponent.body);
				}
			}
		}

		private static int BonusOrbHurtBoxSort(HurtBox lhs, HurtBox rhs)
		{
			return (int)(100f * (lhs.healthComponent.combinedHealthFraction - rhs.healthComponent.combinedHealthFraction));
		}

		private void SendOrbToBody(CharacterBody body)
		{
			HealthComponent component = body.GetComponent<HealthComponent>();
			if ((bool)component)
			{
				VendingMachineOrb vendingMachineOrb = new VendingMachineOrb();
				vendingMachineOrb.origin = orbOrigin.position;
				vendingMachineOrb.target = component.body.mainHurtBox;
				vendingMachineOrb.healFraction = healFraction;
				OrbManager.instance.AddOrb(vendingMachineOrb);
			}
		}

		[Server]
		public void Detonate()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VendingMachineBehavior::Detonate()' called on client");
				return;
			}
			EffectData effectData = new EffectData();
			effectData.origin = base.transform.position;
			EffectManager.SpawnEffect(detonateEffect, effectData, transmit: true);
			UnityEngine.Object.Destroy(base.gameObject);
		}

		[Server]
		public void RefreshPurchaseInteractionAvailability()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VendingMachineBehavior::RefreshPurchaseInteractionAvailability()' called on client");
			}
			else
			{
				purchaseInteraction.Networkavailable = purchaseCount < maxPurchases;
			}
		}

		[ClientRpc]
		public void RpcTriggerVendAnimation(int vendsRemaining)
		{
			if ((bool)animator)
			{
				animator.SetTrigger(animatorTriggerNameVend);
				animator.SetInteger(animatorIntNameVendsRemaining, vendsRemaining);
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcTriggerVendAnimation(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcTriggerVendAnimation called on server.");
			}
			else
			{
				((VendingMachineBehavior)obj).RpcTriggerVendAnimation((int)reader.ReadPackedUInt32());
			}
		}

		public void CallRpcTriggerVendAnimation(int vendsRemaining)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcTriggerVendAnimation called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcTriggerVendAnimation);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)vendsRemaining);
			SendRPCInternal(networkWriter, 0, "RpcTriggerVendAnimation");
		}

		static VendingMachineBehavior()
		{
			kRpcRpcTriggerVendAnimation = 2105333433;
			NetworkBehaviour.RegisterRpcDelegate(typeof(VendingMachineBehavior), kRpcRpcTriggerVendAnimation, InvokeRpcRpcTriggerVendAnimation);
			NetworkCRC.RegisterBehaviour("VendingMachineBehavior", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class VerticalTubeZone : BaseZoneBehavior, IZone
	{
		[Tooltip("The area of effect.")]
		[SyncVar]
		public float radius;

		[Tooltip("The child range indicator object. Will be scaled to the radius.")]
		public Transform rangeIndicator;

		[Tooltip("The time it takes the range indicator to update")]
		public float indicatorSmoothTime = 0.2f;

		private float rangeIndicatorScaleVelocity;

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 1u);
			}
		}

		private void OnEnable()
		{
			if ((bool)rangeIndicator)
			{
				rangeIndicator.gameObject.SetActive(value: true);
			}
		}

		private void OnDisable()
		{
			if ((bool)rangeIndicator)
			{
				rangeIndicator.gameObject.SetActive(value: false);
			}
		}

		private void Update()
		{
			if ((bool)rangeIndicator)
			{
				float num = Mathf.SmoothDamp(rangeIndicator.localScale.x, radius, ref rangeIndicatorScaleVelocity, indicatorSmoothTime);
				rangeIndicator.localScale = new UnityEngine.Vector3(num, rangeIndicator.localScale.y, num);
			}
		}

		public override bool IsInBounds(UnityEngine.Vector3 position)
		{
			UnityEngine.Vector3 vector = position - base.transform.position;
			vector.y = 0f;
			return vector.sqrMagnitude <= radius * radius;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			if (forceAll)
			{
				writer.Write(radius);
				return true;
			}
			bool flag2 = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag2)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag2 = true;
				}
				writer.Write(radius);
			}
			if (!flag2)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
			if (initialState)
			{
				radius = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				radius = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class VFXAttributes : MonoBehaviour
	{
		public enum VFXPriority
		{
			Low,
			Medium,
			Always
		}

		public enum VFXIntensity
		{
			Low,
			Medium,
			High
		}

		private static List<VFXAttributes> vfxList = new List<VFXAttributes>();

		private static ReadOnlyCollection<VFXAttributes> _readonlyVFXList = new ReadOnlyCollection<VFXAttributes>(vfxList);

		[Tooltip("Controls whether or not a VFX appears at all - consider if you would notice if this entire VFX never appeared. Also means it has a networking consequence.")]
		public VFXPriority vfxPriority;

		[Tooltip("Define how expensive a particle system is IF it appears.")]
		public VFXIntensity vfxIntensity;

		[Tooltip("If true, do not use pooling for this effect.")]
		public bool DoNotPool;

		[Tooltip("If true, do not allow the system to cull this effect's pool.")]
		public bool DoNotCullPool;

		public Light[] optionalLights;

		[Tooltip("Particle systems that may be deactivated without impacting gameplay.")]
		public ParticleSystem[] secondaryParticleSystem;

		public static ReadOnlyCollection<VFXAttributes> readonlyVFXList => _readonlyVFXList;

		public int GetIntensityScore()
		{
			return vfxIntensity switch
			{
				VFXIntensity.Low => 1, 
				VFXIntensity.Medium => 5, 
				VFXIntensity.High => 25, 
				_ => 0, 
			};
		}

		public void OnEnable()
		{
			vfxList.Add(this);
			VFXBudget.totalCost += GetIntensityScore();
		}

		public void OnDisable()
		{
			vfxList.Remove(this);
			VFXBudget.totalCost -= GetIntensityScore();
		}
	}
	public static class VFXBudget
	{
		public static int totalCost = 0;

		public static int framerateCost = 0;

		public static int realTotalCost = 0;

		public static int costPerLostFrame = 15;

		private static IntConVar lowPriorityCostThreshold = new IntConVar("vfxbudget_low_priority_cost_threshold", ConVarFlags.None, "50", "");

		private static IntConVar mediumPriorityCostThreshold = new IntConVar("vfxbudget_medium_priority_cost_threshold", ConVarFlags.None, "200", "");

		private static IntConVar particleCostBias = new IntConVar("vfxbudget_particle_cost_bias", ConVarFlags.Archive, "0", "");

		private static float chanceFailurePower = 1f;

		public static bool CanAffordSpawn(GameObject prefab)
		{
			return CanAffordSpawn(prefab.GetComponent<VFXAttributes>());
		}

		public static bool CanAffordSpawn(VFXAttributes vfxAttributes)
		{
			if ((object)vfxAttributes == null)
			{
				return true;
			}
			int intensityScore = vfxAttributes.GetIntensityScore();
			realTotalCost = totalCost + intensityScore + particleCostBias.value;
			return vfxAttributes.vfxPriority switch
			{
				VFXAttributes.VFXPriority.Low => Mathf.Pow((float)lowPriorityCostThreshold.value / (float)realTotalCost, chanceFailurePower) > UnityEngine.Random.value, 
				VFXAttributes.VFXPriority.Medium => Mathf.Pow((float)mediumPriorityCostThreshold.value / (float)realTotalCost, chanceFailurePower) > UnityEngine.Random.value, 
				VFXAttributes.VFXPriority.Always => true, 
				_ => true, 
			};
		}
	}
	public class VfxKillBehavior : MonoBehaviour
	{
		public UnityEvent killBehavior;

		public static void KillVfxObject(GameObject gameObject)
		{
			if (!gameObject)
			{
				return;
			}
			List<VfxKillBehavior> list = CollectionPool<VfxKillBehavior, List<VfxKillBehavior>>.RentCollection();
			gameObject.GetComponents(list);
			if (list.Count > 0)
			{
				for (int i = 0; i < list.Count; i++)
				{
					try
					{
						list[i].killBehavior.Invoke();
					}
					catch (Exception exception)
					{
						UnityEngine.Debug.LogException(exception);
					}
				}
			}
			else
			{
				UnityEngine.Object.Destroy(gameObject);
			}
		}
	}
	public class VoidRaidGauntletController : NetworkBehaviour
	{
		[Serializable]
		public class GauntletInfo
		{
			public Transform startPoint;

			public Transform effectRoot;

			public float startRadius = 100f;

			public MapZone exitZone;

			public MapZone entranceZone;

			public string gateName;
		}

		[Serializable]
		public class DonutInfo
		{
			public GameObject root;

			public Transform returnPoint;

			public float returnRadius = 1000f;

			public Transform crabPosition;

			public CombatDirector combatDirector;
		}

		[SerializeField]
		private DonutInfo initialDonut;

		[SerializeField]
		private DonutInfo[] followingDonuts;

		[SerializeField]
		private GauntletInfo[] gauntlets;

		[SerializeField]
		private BuffDef requiredBuffToKill;

		[SerializeField]
		private GameObject donutSkyboxObject;

		[SerializeField]
		private GameObject gauntletSkyboxObject;

		[SerializeField]
		private GameObject gauntletEffectPrefab;

		[SerializeField]
		private int initialSpawnSpiderSteps = 4;

		[SerializeField]
		private int maxInitialSpawnPoints = 16;

		[SerializeField]
		public InteractableSpawnCard outroPortalSpawnCard;

		[SerializeField]
		public float minOutroPortalDistance;

		[SerializeField]
		public float maxOutroPortalDistance;

		[SerializeField]
		private InteractableSpawnCard gauntletExtranceSpawnCard;

		[SerializeField]
		private ScriptedCombatEncounter[] phaseEncounters;

		[SerializeField]
		private LoopSoundDef gauntletActiveLoop;

		private GauntletInfo previousGauntlet;

		private DonutInfo previousDonut;

		private GauntletInfo currentGauntlet;

		private DonutInfo currentDonut;

		private CharacterBody bossBody;

		private LoopSoundManager.SoundLoopPtr gauntletActiveLoopPtr;

		[SyncVar(hook = "TryShuffleData")]
		private ulong rngSeed;

		private bool hasShuffled;

		private int gauntletIndex;

		private static int kRpcRpcStartActiveSoundLoop;

		private static int kRpcRpcActivateGate;

		private static int kRpcRpcActivateDonut;

		private static int kRpcRpcTryShuffleData;

		public static VoidRaidGauntletController instance { get; private set; }

		public ulong NetworkrngSeed
		{
			get
			{
				return rngSeed;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					TryShuffleData(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref rngSeed, 1u);
			}
		}

		public void SetCurrentDonutCombatDirectorEnabled(bool isEnabled)
		{
			if ((bool)currentDonut?.combatDirector)
			{
				currentDonut.combatDirector.enabled = isEnabled;
			}
		}

		public bool TryOpenGauntlet(UnityEngine.Vector3 entrancePosition, NetworkInstanceId bossMasterId)
		{
			if (gauntletIndex >= phaseEncounters.Length)
			{
				return false;
			}
			if (bossMasterId != NetworkInstanceId.Invalid)
			{
				ScriptedCombatEncounter scriptedCombatEncounter = phaseEncounters[gauntletIndex];
				if (!scriptedCombatEncounter || scriptedCombatEncounter.combatSquad.memberCount != 0 || !scriptedCombatEncounter.combatSquad.HasContainedMember(bossMasterId))
				{
					return false;
				}
			}
			int destinationGauntletIndex = gauntletIndex;
			previousGauntlet = currentGauntlet;
			previousDonut = currentDonut;
			if (previousDonut != null && (bool)previousDonut.combatDirector)
			{
				previousDonut.combatDirector.monsterCredit = 0f;
				previousDonut.combatDirector.enabled = false;
			}
			int num = gauntletIndex % followingDonuts.Length;
			currentDonut = followingDonuts[num];
			currentGauntlet = gauntlets[gauntletIndex % gauntlets.Length];
			gauntletIndex++;
			CallRpcTryShuffleData(rngSeed);
			if ((bool)currentDonut.root)
			{
				currentDonut.root.SetActive(value: true);
				CallRpcActivateDonut(num);
			}
			if (SceneInfo.instance != null && !string.IsNullOrEmpty(currentGauntlet?.gateName))
			{
				SceneInfo.instance.SetGateState(currentGauntlet.gateName, gateEnabled: true);
				CallRpcActivateGate(currentGauntlet?.gateName);
			}
			if ((bool)currentGauntlet.effectRoot && (bool)gauntletEffectPrefab)
			{
				EffectData effectData = new EffectData
				{
					origin = currentGauntlet.effectRoot.position,
					rotation = currentGauntlet.effectRoot.rotation
				};
				EffectManager.SpawnEffect(gauntletEffectPrefab, effectData, transmit: false);
			}
			if ((bool)previousDonut?.combatDirector)
			{
				previousDonut.combatDirector.enabled = false;
			}
			Xoroshiro128Plus rng = new Xoroshiro128Plus(rngSeed + (ulong)gauntletIndex);
			DirectorPlacementRule placementRule = new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
				position = entrancePosition
			};
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(gauntletExtranceSpawnCard, placementRule, rng);
			directorSpawnRequest.onSpawnedServer = delegate(SpawnCard.SpawnResult result)
			{
				OnEntranceSpawned(result, destinationGauntletIndex);
			};
			DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			return true;
		}

		private void OnEntranceSpawned(SpawnCard.SpawnResult result, int destinationGauntletIndex)
		{
			if (result.success)
			{
				CallRpcStartActiveSoundLoop();
				currentGauntlet.entranceZone = result.spawnedInstance.GetComponentInChildren<MapZone>();
				result.spawnedInstance.GetComponent<VoidRaidGauntletEntranceController>().SetGauntletIndex(destinationGauntletIndex);
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			SceneDirector.onPreGeneratePlayerSpawnPointsServer += OnPreGeneratePlayerSpawnPointsServer;
		}

		private void OnDisable()
		{
			StopActiveSoundLoop();
			SceneDirector.onPreGeneratePlayerSpawnPointsServer -= OnPreGeneratePlayerSpawnPointsServer;
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void OnPreGeneratePlayerSpawnPointsServer(SceneDirector sceneDirector, ref Action generationMethod)
		{
			generationMethod = GeneratePlayerSpawnPointsServer;
		}

		private void GeneratePlayerSpawnPointsServer()
		{
			if (!SceneInfo.instance || initialDonut == null || !initialDonut.returnPoint)
			{
				return;
			}
			Transform returnPoint = initialDonut.returnPoint;
			UnityEngine.Vector3 position = returnPoint.position;
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			if (!groundNodes)
			{
				UnityEngine.Debug.LogError("VoidRaidGauntletController.GeneratePlayerSpawnPointsServer: No ground nodegraph found to place spawn points.", this);
				return;
			}
			NodeGraphSpider nodeGraphSpider = new NodeGraphSpider(groundNodes, HullMask.Human);
			nodeGraphSpider.AddNodeForNextStep(groundNodes.FindClosestNode(position, HullClassification.Human));
			for (int i = 0; i < initialSpawnSpiderSteps; i++)
			{
				nodeGraphSpider.PerformStep();
				if (nodeGraphSpider.collectedSteps.Count > maxInitialSpawnPoints)
				{
					break;
				}
			}
			for (int j = 0; j < nodeGraphSpider.collectedSteps.Count; j++)
			{
				NodeGraphSpider.StepInfo stepInfo = nodeGraphSpider.collectedSteps[j];
				groundNodes.GetNodePosition(stepInfo.node, out var position2);
				UnityEngine.Quaternion rotation = returnPoint.rotation;
				SpawnPoint.AddSpawnPoint(position2, rotation);
			}
		}

		private void Start()
		{
			previousDonut = initialDonut;
			DonutInfo[] array = followingDonuts;
			foreach (DonutInfo donutInfo in array)
			{
				if ((bool)donutInfo?.root)
				{
					donutInfo.root.SetActive(value: false);
				}
			}
			if (NetworkServer.active)
			{
				TryShuffleData(Run.instance.stageRng.nextUlong);
				CallRpcTryShuffleData(rngSeed);
			}
		}

		public override void OnStartServer()
		{
			base.OnStartServer();
			CallRpcTryShuffleData(rngSeed);
		}

		private void TryShuffleData(ulong seed)
		{
			NetworkrngSeed = seed;
			if (hasShuffled)
			{
				return;
			}
			Xoroshiro128Plus rng = new Xoroshiro128Plus(seed);
			Util.ShuffleArray(followingDonuts, rng);
			Util.ShuffleArray(gauntlets, rng);
			for (int i = 1; i < phaseEncounters.Length && i - 1 < followingDonuts.Length; i++)
			{
				DonutInfo donutInfo = followingDonuts[i - 1];
				ScriptedCombatEncounter scriptedCombatEncounter = phaseEncounters[i];
				int encounterIndex = i;
				scriptedCombatEncounter.onBeginEncounter += delegate(ScriptedCombatEncounter argEncounter)
				{
					OnBeginEncounter(argEncounter, encounterIndex);
				};
				if (scriptedCombatEncounter.spawns.Length != 0)
				{
					scriptedCombatEncounter.spawns[0].explicitSpawnPosition = donutInfo.crabPosition;
				}
			}
			for (int j = 0; j < gauntlets.Length && j < followingDonuts.Length; j++)
			{
				GauntletInfo gauntletInfo = gauntlets[j];
				DonutInfo donutInfo2 = followingDonuts[j];
				if ((bool)gauntletInfo.exitZone && (bool)donutInfo2.returnPoint)
				{
					gauntletInfo.exitZone.explicitDestination = donutInfo2.returnPoint;
					gauntletInfo.exitZone.destinationIdealRadius = donutInfo2.returnRadius;
				}
			}
			hasShuffled = true;
		}

		private void OnBeginEncounter(ScriptedCombatEncounter encounter, int encounterIndex)
		{
			while (gauntletIndex < encounterIndex)
			{
				TryOpenGauntlet(currentDonut.crabPosition.position, NetworkInstanceId.Invalid);
			}
		}

		public void SpawnOutroPortal()
		{
			if (NetworkServer.active && currentDonut != null && (bool)currentDonut.returnPoint)
			{
				Xoroshiro128Plus rng = new Xoroshiro128Plus(rngSeed + 1);
				DirectorPlacementRule placementRule = new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Approximate,
					minDistance = minOutroPortalDistance,
					maxDistance = maxOutroPortalDistance,
					spawnOnTarget = currentDonut.returnPoint
				};
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(outroPortalSpawnCard, placementRule, rng);
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			}
		}

		[ClientRpc]
		private void RpcStartActiveSoundLoop()
		{
			if ((bool)gauntletActiveLoop)
			{
				gauntletActiveLoopPtr = LoopSoundManager.PlaySoundLoopLocal(RoR2Application.instance.gameObject, gauntletActiveLoop);
			}
		}

		[ClientRpc]
		private void RpcActivateGate(string gateName)
		{
			if (!string.IsNullOrEmpty(gateName))
			{
				SceneInfo.instance.SetGateState(gateName, gateEnabled: true);
			}
		}

		[ClientRpc]
		private void RpcActivateDonut(int donutIndex)
		{
			if (donutIndex < followingDonuts.Length)
			{
				followingDonuts[donutIndex]?.root.SetActive(value: true);
			}
		}

		[ClientRpc]
		private void RpcTryShuffleData(ulong seed)
		{
			TryShuffleData(seed);
		}

		private void StopActiveSoundLoop()
		{
			if ((bool)gauntletActiveLoop)
			{
				LoopSoundManager.StopSoundLoopLocal(gauntletActiveLoopPtr);
			}
		}

		private void SetSkyboxToGauntlet()
		{
			if ((bool)donutSkyboxObject)
			{
				donutSkyboxObject.SetActive(value: false);
			}
			if ((bool)gauntletSkyboxObject)
			{
				gauntletSkyboxObject.SetActive(value: true);
			}
		}

		private void SetSkyboxToDonut()
		{
			if ((bool)donutSkyboxObject)
			{
				donutSkyboxObject.SetActive(value: true);
			}
			if ((bool)gauntletSkyboxObject)
			{
				gauntletSkyboxObject.SetActive(value: false);
			}
		}

		public void OnAuthorityPlayerEnter()
		{
			SetSkyboxToGauntlet();
		}

		public void OnAuthorityPlayerExit()
		{
			SetSkyboxToDonut();
			StopActiveSoundLoop();
		}

		public void PointZoneToGauntlet(int destinationGauntletIndex, MapZone zone)
		{
			if (destinationGauntletIndex < gauntlets.Length)
			{
				GauntletInfo gauntletInfo = gauntlets[destinationGauntletIndex];
				zone.explicitDestination = gauntletInfo.startPoint;
				zone.destinationIdealRadius = gauntletInfo.startRadius;
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcStartActiveSoundLoop(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcStartActiveSoundLoop called on server.");
			}
			else
			{
				((VoidRaidGauntletController)obj).RpcStartActiveSoundLoop();
			}
		}

		protected static void InvokeRpcRpcActivateGate(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcActivateGate called on server.");
			}
			else
			{
				((VoidRaidGauntletController)obj).RpcActivateGate(reader.ReadString());
			}
		}

		protected static void InvokeRpcRpcActivateDonut(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcActivateDonut called on server.");
			}
			else
			{
				((VoidRaidGauntletController)obj).RpcActivateDonut((int)reader.ReadPackedUInt32());
			}
		}

		protected static void InvokeRpcRpcTryShuffleData(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcTryShuffleData called on server.");
			}
			else
			{
				((VoidRaidGauntletController)obj).RpcTryShuffleData(reader.ReadPackedUInt64());
			}
		}

		public void CallRpcStartActiveSoundLoop()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcStartActiveSoundLoop called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcStartActiveSoundLoop);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcStartActiveSoundLoop");
		}

		public void CallRpcActivateGate(string gateName)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcActivateGate called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcActivateGate);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(gateName);
			SendRPCInternal(networkWriter, 0, "RpcActivateGate");
		}

		public void CallRpcActivateDonut(int donutIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcActivateDonut called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcActivateDonut);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)donutIndex);
			SendRPCInternal(networkWriter, 0, "RpcActivateDonut");
		}

		public void CallRpcTryShuffleData(ulong seed)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcTryShuffleData called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcTryShuffleData);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt64(seed);
			SendRPCInternal(networkWriter, 0, "RpcTryShuffleData");
		}

		static VoidRaidGauntletController()
		{
			kRpcRpcStartActiveSoundLoop = -755317963;
			NetworkBehaviour.RegisterRpcDelegate(typeof(VoidRaidGauntletController), kRpcRpcStartActiveSoundLoop, InvokeRpcRpcStartActiveSoundLoop);
			kRpcRpcActivateGate = -1148984728;
			NetworkBehaviour.RegisterRpcDelegate(typeof(VoidRaidGauntletController), kRpcRpcActivateGate, InvokeRpcRpcActivateGate);
			kRpcRpcActivateDonut = -1261146843;
			NetworkBehaviour.RegisterRpcDelegate(typeof(VoidRaidGauntletController), kRpcRpcActivateDonut, InvokeRpcRpcActivateDonut);
			kRpcRpcTryShuffleData = 20528402;
			NetworkBehaviour.RegisterRpcDelegate(typeof(VoidRaidGauntletController), kRpcRpcTryShuffleData, InvokeRpcRpcTryShuffleData);
			NetworkCRC.RegisterBehaviour("VoidRaidGauntletController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt64(rngSeed);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt64(rngSeed);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				rngSeed = reader.ReadPackedUInt64();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				TryShuffleData(reader.ReadPackedUInt64());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class VoidRaidGauntletEntranceController : NetworkBehaviour
	{
		[SerializeField]
		private MapZone entranceZone;

		[SyncVar(hook = "UpdateGauntletIndex")]
		private int gauntletIndex;

		private static int kRpcRpcUpdateGauntletIndex;

		public int NetworkgauntletIndex
		{
			get
			{
				return gauntletIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					UpdateGauntletIndex(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref gauntletIndex, 1u);
			}
		}

		[Server]
		public void SetGauntletIndex(int newGauntletIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoidRaidGauntletEntranceController::SetGauntletIndex(System.Int32)' called on client");
				return;
			}
			NetworkgauntletIndex = newGauntletIndex;
			UpdateGauntletIndex(gauntletIndex);
			CallRpcUpdateGauntletIndex(gauntletIndex);
		}

		private void OnEnable()
		{
			if ((bool)entranceZone)
			{
				entranceZone.onBodyTeleport += OnBodyTeleport;
			}
		}

		private void OnDisable()
		{
			if ((bool)entranceZone)
			{
				entranceZone.onBodyTeleport -= OnBodyTeleport;
			}
		}

		private void OnBodyTeleport(CharacterBody body)
		{
			if (Util.HasEffectiveAuthority(body.gameObject) && (bool)body.masterObject.GetComponent<PlayerCharacterMasterController>() && (bool)VoidRaidGauntletController.instance)
			{
				body.healthComponent.CallCmdHealFull();
				body.healthComponent.CallCmdRechargeShieldFull();
				VoidRaidGauntletController.instance.OnAuthorityPlayerEnter();
			}
		}

		private void UpdateGauntletIndex(int newGauntletIndex)
		{
			if (newGauntletIndex != gauntletIndex)
			{
				NetworkgauntletIndex = newGauntletIndex;
			}
			if ((bool)entranceZone && (bool)VoidRaidGauntletController.instance)
			{
				VoidRaidGauntletController.instance.PointZoneToGauntlet(newGauntletIndex, entranceZone);
			}
		}

		[ClientRpc]
		private void RpcUpdateGauntletIndex(int newGauntletIndex)
		{
			UpdateGauntletIndex(newGauntletIndex);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcUpdateGauntletIndex(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcUpdateGauntletIndex called on server.");
			}
			else
			{
				((VoidRaidGauntletEntranceController)obj).RpcUpdateGauntletIndex((int)reader.ReadPackedUInt32());
			}
		}

		public void CallRpcUpdateGauntletIndex(int newGauntletIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcUpdateGauntletIndex called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcUpdateGauntletIndex);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)newGauntletIndex);
			SendRPCInternal(networkWriter, 0, "RpcUpdateGauntletIndex");
		}

		static VoidRaidGauntletEntranceController()
		{
			kRpcRpcUpdateGauntletIndex = -330092625;
			NetworkBehaviour.RegisterRpcDelegate(typeof(VoidRaidGauntletEntranceController), kRpcRpcUpdateGauntletIndex, InvokeRpcRpcUpdateGauntletIndex);
			NetworkCRC.RegisterBehaviour("VoidRaidGauntletEntranceController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)gauntletIndex);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)gauntletIndex);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				gauntletIndex = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				UpdateGauntletIndex((int)reader.ReadPackedUInt32());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class VoidRaidGauntletExitController : MonoBehaviour
	{
		[SerializeField]
		private MapZone exitZone;

		private void OnEnable()
		{
			if ((bool)exitZone)
			{
				exitZone.onBodyTeleport += OnBodyTeleport;
			}
		}

		private void OnDisable()
		{
			if ((bool)exitZone)
			{
				exitZone.onBodyTeleport -= OnBodyTeleport;
			}
		}

		private void OnBodyTeleport(CharacterBody body)
		{
			if (Util.HasEffectiveAuthority(body.gameObject) && (bool)body.masterObject.GetComponent<PlayerCharacterMasterController>() && (bool)VoidRaidGauntletController.instance)
			{
				VoidRaidGauntletController.instance.OnAuthorityPlayerExit();
			}
		}
	}
	public class VoidStageMissionController : NetworkBehaviour
	{
		public class FogRequest : IDisposable
		{
			public readonly IZone safeZone;

			private Action<FogRequest> disposeCallback;

			public FogRequest(IZone zone, Action<FogRequest> onDispose)
			{
				safeZone = zone;
				disposeCallback = onDispose;
			}

			public void Dispose()
			{
				disposeCallback?.Invoke(this);
				disposeCallback = null;
			}
		}

		[SerializeField]
		private InteractableSpawnCard batterySpawnCard;

		[SerializeField]
		private int batteryCount;

		[SerializeField]
		private Transform portalRoot;

		[SerializeField]
		private string portalOpenChatToken;

		[SerializeField]
		private GenericObjectiveProvider deepVoidPortalObjectiveProvider;

		[SerializeField]
		private InteractableSpawnCard deepVoidPortalSpawnCard;

		[SerializeField]
		private InteractableSpawnCard voidPortalSpawnCard;

		[SerializeField]
		public string batteryObjectiveToken;

		[SerializeField]
		private FogDamageController fogDamageController;

		private Xoroshiro128Plus rng;

		private GameObject voidPortal;

		private int fogRefCount;

		[SyncVar]
		private int _numBatteriesSpawned;

		[SyncVar]
		private int _numBatteriesActivated;

		public int numBatteriesSpawned => _numBatteriesSpawned;

		public int numBatteriesActivated => _numBatteriesActivated;

		public static VoidStageMissionController instance { get; private set; }

		public int Network_numBatteriesSpawned
		{
			get
			{
				return _numBatteriesSpawned;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _numBatteriesSpawned, 1u);
			}
		}

		public int Network_numBatteriesActivated
		{
			get
			{
				return _numBatteriesActivated;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _numBatteriesActivated, 2u);
			}
		}

		public FogRequest RequestFog(IZone zone)
		{
			if ((bool)fogDamageController)
			{
				if (!fogDamageController.enabled)
				{
					fogDamageController.enabled = true;
				}
				fogRefCount++;
				fogDamageController.AddSafeZone(zone);
				return new FogRequest(zone, OnFogUnrequested);
			}
			return null;
		}

		private void OnFogUnrequested(FogRequest request)
		{
			if ((bool)fogDamageController)
			{
				fogDamageController.RemoveSafeZone(request.safeZone);
				fogDamageController.enabled = --fogRefCount > 0;
			}
		}

		private void Start()
		{
			if ((bool)deepVoidPortalObjectiveProvider)
			{
				deepVoidPortalObjectiveProvider.enabled = false;
			}
			if (!NetworkServer.active)
			{
				return;
			}
			rng = new Xoroshiro128Plus(Run.instance.stageRng.nextUlong);
			Network_numBatteriesSpawned = 0;
			for (int i = 0; i < batteryCount; i++)
			{
				DirectorPlacementRule placementRule = new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Random
				};
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(batterySpawnCard, placementRule, rng);
				GameObject gameObject = DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
				if ((bool)gameObject && (bool)gameObject.GetComponent<PurchaseInteraction>())
				{
					Network_numBatteriesSpawned = _numBatteriesSpawned + 1;
				}
			}
		}

		private void FixedUpdate()
		{
			if ((bool)deepVoidPortalObjectiveProvider && numBatteriesActivated >= numBatteriesSpawned && numBatteriesSpawned > 0)
			{
				deepVoidPortalObjectiveProvider.enabled = true;
			}
		}

		public void OnBatteryActivated()
		{
			Network_numBatteriesActivated = _numBatteriesActivated + 1;
			if (_numBatteriesActivated >= _numBatteriesSpawned && (bool)portalRoot)
			{
				CombatDirector[] array = new CombatDirector[CombatDirector.instancesList.Count];
				CombatDirector.instancesList.CopyTo(array);
				CombatDirector[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i].enabled = false;
				}
				DirectorPlacementRule placementRule = new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Direct,
					spawnOnTarget = portalRoot
				};
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(deepVoidPortalSpawnCard, placementRule, rng);
				voidPortal = DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
				voidPortal.transform.rotation = portalRoot.rotation;
				NetworkServer.Spawn(voidPortal);
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
			ObjectivePanelController.collectObjectiveSources += OnCollectObjectiveSources;
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
			ObjectivePanelController.collectObjectiveSources -= OnCollectObjectiveSources;
		}

		private void OnCollectObjectiveSources(CharacterMaster master, List<ObjectivePanelController.ObjectiveSourceDescriptor> objectiveSourcesList)
		{
			if (_numBatteriesSpawned > 0 && _numBatteriesActivated < _numBatteriesSpawned)
			{
				objectiveSourcesList.Add(new ObjectivePanelController.ObjectiveSourceDescriptor
				{
					master = master,
					objectiveType = typeof(VoidStageBatteryMissionObjectiveTracker),
					source = this
				});
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32((uint)_numBatteriesSpawned);
				writer.WritePackedUInt32((uint)_numBatteriesActivated);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)_numBatteriesSpawned);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)_numBatteriesActivated);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_numBatteriesSpawned = (int)reader.ReadPackedUInt32();
				_numBatteriesActivated = (int)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_numBatteriesSpawned = (int)reader.ReadPackedUInt32();
			}
			if (((uint)num & 2u) != 0)
			{
				_numBatteriesActivated = (int)reader.ReadPackedUInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(PurchaseInteraction))]
	public class VoidSuppressorBehavior : NetworkBehaviour
	{
		public class SyncListPickupIndex : SyncListStruct<PickupIndex>
		{
			public override void SerializeItem(NetworkWriter writer, PickupIndex item)
			{
				writer.WritePackedUInt32((uint)item.value);
			}

			public override PickupIndex DeserializeItem(NetworkReader reader)
			{
				PickupIndex result = default(PickupIndex);
				result.value = (int)reader.ReadPackedUInt32();
				return result;
			}
		}

		[SerializeField]
		private int maxPurchaseCount;

		[SerializeField]
		private int itemsSuppressedPerPurchase;

		[SerializeField]
		private float costMultiplierPerPurchase;

		[SerializeField]
		private Transform symbolTransform;

		[SerializeField]
		private PurchaseInteraction purchaseInteraction;

		[SerializeField]
		private GameObject effectPrefab;

		[SerializeField]
		private UnityEngine.Color effectColor;

		[SerializeField]
		private PickupDisplay[] pickupDisplays;

		[SerializeField]
		private int numItemsToReveal;

		[SerializeField]
		private bool transformItems;

		[SerializeField]
		private string animatorSuppressName;

		[SerializeField]
		private string animatorIsAvailableName;

		[SerializeField]
		private string animatorIsPlayerNearbyName;

		[SerializeField]
		private Animator animator;

		[SerializeField]
		private NetworkAnimator networkAnimator;

		[SerializeField]
		private string revealedName;

		[SerializeField]
		private string revealedContext;

		[SerializeField]
		private float useRefreshDelay = 2f;

		[SerializeField]
		private float itemRefreshDelay = 1f;

		private int purchaseCount;

		private float timeUntilUseRefresh;

		private float timeUntilItemRefresh;

		private Xoroshiro128Plus rng;

		private SyncListPickupIndex nextItemsToSuppress = new SyncListPickupIndex();

		private ItemIndex transformItemIndex;

		private bool hasRevealed;

		private static int kListnextItemsToSuppress;

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				rng = new Xoroshiro128Plus(Run.instance.treasureRng.nextUlong);
			}
		}

		public override void OnStartClient()
		{
			nextItemsToSuppress.Callback = OnItemsUpdated;
		}

		public void FixedUpdate()
		{
			if (purchaseCount >= maxPurchaseCount)
			{
				return;
			}
			if (timeUntilUseRefresh > 0f)
			{
				timeUntilUseRefresh -= Time.fixedDeltaTime;
				if (timeUntilUseRefresh <= 0f)
				{
					animator.SetBool(animatorSuppressName, value: false);
					purchaseInteraction.SetAvailable(newAvailable: true);
					purchaseInteraction.Networkcost = (int)((float)purchaseInteraction.cost * costMultiplierPerPurchase);
				}
			}
			if (timeUntilItemRefresh > 0f)
			{
				timeUntilItemRefresh -= Time.fixedDeltaTime;
				if (timeUntilItemRefresh <= 0f)
				{
					nextItemsToSuppress.Clear();
					RefreshItems();
				}
			}
		}

		[Server]
		public void OnInteraction(Interactor interactor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoidSuppressorBehavior::OnInteraction(RoR2.Interactor)' called on client");
				return;
			}
			timeUntilUseRefresh = useRefreshDelay;
			if (hasRevealed)
			{
				timeUntilItemRefresh = itemRefreshDelay;
				if (nextItemsToSuppress != null)
				{
					CharacterBody component = interactor.GetComponent<CharacterBody>();
					for (int i = 0; i < itemsSuppressedPerPurchase && i < nextItemsToSuppress.Count; i++)
					{
						ItemIndex itemIndex = nextItemsToSuppress[i].itemIndex;
						if (SuppressedItemManager.SuppressItem(itemIndex, transformItemIndex))
						{
							ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
							ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(itemDef.tier);
							ColoredTokenChatMessage coloredTokenChatMessage = new ColoredTokenChatMessage();
							coloredTokenChatMessage.subjectAsCharacterBody = component;
							coloredTokenChatMessage.baseToken = "VOID_SUPPRESSOR_USE_MESSAGE";
							coloredTokenChatMessage.paramTokens = new string[1] { itemDef.nameToken };
							coloredTokenChatMessage.paramColors = new Color32[1] { ColorCatalog.GetColor(itemTierDef.colorIndex) };
							Chat.SendBroadcastChat(coloredTokenChatMessage);
						}
					}
				}
				EffectManager.SpawnEffect(effectPrefab, new EffectData
				{
					origin = base.transform.position,
					rotation = UnityEngine.Quaternion.identity,
					scale = 1f,
					color = effectColor
				}, transmit: true);
				purchaseCount++;
				if (purchaseCount >= maxPurchaseCount)
				{
					if ((bool)symbolTransform)
					{
						symbolTransform.gameObject.SetActive(value: false);
					}
					animator.SetBool(animatorIsAvailableName, value: false);
				}
				animator.SetBool(animatorSuppressName, value: true);
			}
			else
			{
				hasRevealed = true;
				animator.SetBool(animatorIsAvailableName, value: true);
				purchaseInteraction.NetworkcontextToken = revealedContext;
				purchaseInteraction.NetworkdisplayNameToken = revealedName;
				RefreshItems();
			}
		}

		[Server]
		public void RefreshItems()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoidSuppressorBehavior::RefreshItems()' called on client");
			}
			else
			{
				if (timeUntilItemRefresh > 0f)
				{
					return;
				}
				for (int num = nextItemsToSuppress.Count - 1; num >= 0; num--)
				{
					if (SuppressedItemManager.HasItemBeenSuppressed(nextItemsToSuppress[num].itemIndex))
					{
						nextItemsToSuppress.RemoveAt(num);
					}
				}
				int num2 = itemsSuppressedPerPurchase - nextItemsToSuppress.Count;
				if (num2 > 0)
				{
					List<PickupIndex> list = null;
					PickupIndex item = PickupIndex.none;
					switch (purchaseCount)
					{
					case 0:
						list = new List<PickupIndex>(Run.instance.availableTier1DropList);
						item = PickupCatalog.FindPickupIndex(DLC1Content.Items.ScrapWhiteSuppressed.itemIndex);
						transformItemIndex = (transformItems ? DLC1Content.Items.ScrapWhiteSuppressed.itemIndex : ItemIndex.None);
						break;
					case 1:
						list = new List<PickupIndex>(Run.instance.availableTier2DropList);
						item = PickupCatalog.FindPickupIndex(DLC1Content.Items.ScrapGreenSuppressed.itemIndex);
						transformItemIndex = (transformItems ? DLC1Content.Items.ScrapGreenSuppressed.itemIndex : ItemIndex.None);
						break;
					case 2:
						list = new List<PickupIndex>(Run.instance.availableTier3DropList);
						item = PickupCatalog.FindPickupIndex(DLC1Content.Items.ScrapRedSuppressed.itemIndex);
						transformItemIndex = (transformItems ? DLC1Content.Items.ScrapRedSuppressed.itemIndex : ItemIndex.None);
						break;
					}
					if (list != null && list.Count > 0)
					{
						list.Remove(item);
						foreach (PickupIndex item2 in nextItemsToSuppress)
						{
							list.Remove(item2);
						}
						Util.ShuffleList(list, rng);
						int num3 = list.Count - num2;
						if (num3 > 0)
						{
							list.RemoveRange(num2, num3);
						}
						foreach (PickupIndex item3 in list)
						{
							nextItemsToSuppress.Add(item3);
						}
					}
				}
				RefreshPickupDisplays();
				if (nextItemsToSuppress.Count != 0)
				{
					return;
				}
				if (purchaseCount < maxPurchaseCount)
				{
					purchaseCount++;
					RefreshItems();
					return;
				}
				if ((bool)symbolTransform)
				{
					symbolTransform.gameObject.SetActive(value: false);
				}
				purchaseInteraction.SetAvailable(newAvailable: false);
				animator.SetBool(animatorIsAvailableName, value: false);
			}
		}

		public void OnPlayerNearby()
		{
			animator.SetBool(animatorIsPlayerNearbyName, value: true);
		}

		public void OnPlayerFar()
		{
			animator.SetBool(animatorIsPlayerNearbyName, value: false);
		}

		private void OnItemsUpdated(SyncList<PickupIndex>.Operation op, int index)
		{
			RefreshPickupDisplays();
		}

		private void RefreshPickupDisplays()
		{
			for (int i = 0; i < pickupDisplays.Length; i++)
			{
				if (i < nextItemsToSuppress.Count)
				{
					pickupDisplays[i].gameObject.SetActive(value: true);
					pickupDisplays[i].SetPickupIndex(nextItemsToSuppress[i], i >= numItemsToReveal);
				}
				else
				{
					pickupDisplays[i].gameObject.SetActive(value: false);
				}
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeSyncListnextItemsToSuppress(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("SyncList nextItemsToSuppress called on server.");
			}
			else
			{
				((VoidSuppressorBehavior)obj).nextItemsToSuppress.HandleMsg(reader);
			}
		}

		static VoidSuppressorBehavior()
		{
			kListnextItemsToSuppress = 164192093;
			NetworkBehaviour.RegisterSyncListDelegate(typeof(VoidSuppressorBehavior), kListnextItemsToSuppress, InvokeSyncListnextItemsToSuppress);
			NetworkCRC.RegisterBehaviour("VoidSuppressorBehavior", 0);
		}

		private void Awake()
		{
			nextItemsToSuppress.InitializeBehaviour(this, kListnextItemsToSuppress);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WriteStructSyncListPickupIndex_VoidSuppressorBehavior(writer, nextItemsToSuppress);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteStructSyncListPickupIndex_VoidSuppressorBehavior(writer, nextItemsToSuppress);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				GeneratedNetworkCode._ReadStructSyncListPickupIndex_VoidSuppressorBehavior(reader, nextItemsToSuppress);
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				GeneratedNetworkCode._ReadStructSyncListPickupIndex_VoidSuppressorBehavior(reader, nextItemsToSuppress);
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(InputBankTest))]
	[RequireComponent(typeof(TeamComponent))]
	[RequireComponent(typeof(CharacterBody))]
	public class VoidSurvivorController : NetworkBehaviour, IOnTakeDamageServerReceiver, IOnDamageDealtServerReceiver
	{
		[Header("Cached Components")]
		public CharacterBody characterBody;

		public Animator characterAnimator;

		public EntityStateMachine corruptionModeStateMachine;

		public EntityStateMachine bodyStateMachine;

		public EntityStateMachine weaponStateMachine;

		[Header("Corruption Values")]
		public float maxCorruption;

		public float minimumCorruptionPerVoidItem;

		public float corruptionPerSecondInCombat;

		public float corruptionPerSecondOutOfCombat;

		public float corruptionForFullDamage;

		public float corruptionForFullHeal;

		public float corruptionPerCrit;

		public float corruptionDeltaThresholdToAnimate;

		[Header("Corruption Mode")]
		public BuffDef corruptedBuffDef;

		public float corruptionFractionPerSecondWhileCorrupted;

		[SerializeField]
		[Header("UI")]
		public GameObject overlayPrefab;

		[SerializeField]
		public string overlayChildLocatorEntry;

		private ChildLocator overlayInstanceChildLocator;

		private Animator overlayInstanceAnimator;

		private OverlayController overlayController;

		private List<ImageFillController> fillUiList = new List<ImageFillController>();

		private TextMeshProUGUI uiCorruptionText;

		private int voidItemCount;

		[SyncVar(hook = "OnCorruptionModified")]
		private float _corruption;

		private static int isCorruptedParamHash = Animator.StringToHash("isCorrupted");

		private static int corruptionParamHash = Animator.StringToHash("corruption");

		public float corruption => _corruption;

		public float corruptionFraction => corruption / maxCorruption;

		public float corruptionPercentage => corruptionFraction * 100f;

		public float minimumCorruption => minimumCorruptionPerVoidItem * (float)voidItemCount;

		public bool isFullCorruption => corruption >= maxCorruption;

		public bool isCorrupted
		{
			get
			{
				if ((bool)characterBody)
				{
					return characterBody.HasBuff(corruptedBuffDef);
				}
				return false;
			}
		}

		public bool isPermanentlyCorrupted => minimumCorruption >= maxCorruption;

		private HealthComponent bodyHealthComponent => characterBody.healthComponent;

		public float Network_corruption
		{
			get
			{
				return _corruption;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnCorruptionModified(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref _corruption, 1u);
			}
		}

		private void OnEnable()
		{
			OverlayCreationParams overlayCreationParams = default(OverlayCreationParams);
			overlayCreationParams.prefab = overlayPrefab;
			overlayCreationParams.childLocatorEntry = overlayChildLocatorEntry;
			OverlayCreationParams overlayCreationParams2 = overlayCreationParams;
			overlayController = HudOverlayManager.AddOverlay(base.gameObject, overlayCreationParams2);
			overlayController.onInstanceAdded += OnOverlayInstanceAdded;
			overlayController.onInstanceRemove += OnOverlayInstanceRemoved;
			if ((bool)characterBody)
			{
				characterBody.onInventoryChanged += OnInventoryChanged;
				if (NetworkServer.active)
				{
					HealthComponent.onCharacterHealServer += OnCharacterHealServer;
				}
			}
		}

		private void OnDisable()
		{
			if (overlayController != null)
			{
				overlayController.onInstanceAdded -= OnOverlayInstanceAdded;
				overlayController.onInstanceRemove -= OnOverlayInstanceRemoved;
				fillUiList.Clear();
				HudOverlayManager.RemoveOverlay(overlayController);
			}
			if ((bool)characterBody)
			{
				characterBody.onInventoryChanged -= OnInventoryChanged;
				if (NetworkServer.active)
				{
					HealthComponent.onCharacterHealServer -= OnCharacterHealServer;
				}
			}
		}

		private void FixedUpdate()
		{
			float num = 0f;
			num = ((!characterBody.HasBuff(corruptedBuffDef)) ? (characterBody.outOfCombat ? corruptionPerSecondOutOfCombat : corruptionPerSecondInCombat) : (num + corruptionFractionPerSecondWhileCorrupted * (maxCorruption - minimumCorruption)));
			if (NetworkServer.active && !characterBody.HasBuff(RoR2Content.Buffs.HiddenInvincibility))
			{
				AddCorruption(num * Time.fixedDeltaTime);
			}
			UpdateUI();
			if ((bool)characterAnimator)
			{
				characterAnimator.SetFloat("corruptionFraction", corruptionFraction);
			}
		}

		private void UpdateUI()
		{
			foreach (ImageFillController fillUi in fillUiList)
			{
				fillUi.SetTValue(corruption / maxCorruption);
			}
			if ((bool)overlayInstanceChildLocator)
			{
				overlayInstanceChildLocator.FindChild("CorruptionThreshold").rotation = UnityEngine.Quaternion.Euler(0f, 0f, Mathf.InverseLerp(0f, maxCorruption, corruption) * -360f);
				overlayInstanceChildLocator.FindChild("MinCorruptionThreshold").rotation = UnityEngine.Quaternion.Euler(0f, 0f, Mathf.InverseLerp(0f, maxCorruption, minimumCorruption) * -360f);
			}
			if ((bool)overlayInstanceAnimator)
			{
				overlayInstanceAnimator.SetFloat(isCorruptedParamHash, corruption);
				overlayInstanceAnimator.SetBool(corruptionParamHash, isCorrupted);
			}
			if ((bool)uiCorruptionText)
			{
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				stringBuilder.AppendInt(Mathf.FloorToInt(corruption), 1u, 3u).Append("%");
				uiCorruptionText.SetText(stringBuilder);
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			}
		}

		private void OnOverlayInstanceAdded(OverlayController controller, GameObject instance)
		{
			fillUiList.Add(instance.GetComponent<ImageFillController>());
			uiCorruptionText = instance.GetComponentInChildren<TextMeshProUGUI>();
			overlayInstanceChildLocator = instance.GetComponent<ChildLocator>();
			overlayInstanceAnimator = instance.GetComponent<Animator>();
		}

		private void OnOverlayInstanceRemoved(OverlayController controller, GameObject instance)
		{
			fillUiList.Remove(instance.GetComponent<ImageFillController>());
		}

		private void OnCharacterHealServer(HealthComponent healthComponent, float amount, ProcChainMask procChainMask)
		{
			if ((object)healthComponent == bodyHealthComponent && !procChainMask.HasProc(ProcType.VoidSurvivorCrush))
			{
				float num = amount / bodyHealthComponent.fullCombinedHealth;
				AddCorruption(num * corruptionForFullHeal);
			}
		}

		public void OnDamageDealtServer(DamageReport damageReport)
		{
			if (damageReport.damageInfo.crit)
			{
				AddCorruption(damageReport.damageInfo.procCoefficient * corruptionPerCrit);
			}
		}

		public void OnTakeDamageServer(DamageReport damageReport)
		{
			float num = damageReport.damageDealt / bodyHealthComponent.fullCombinedHealth;
			if (!damageReport.damageInfo.procChainMask.HasProc(ProcType.VoidSurvivorCrush))
			{
				AddCorruption(num * corruptionForFullDamage);
			}
		}

		private void OnInventoryChanged()
		{
			voidItemCount = 0;
			Inventory inventory = characterBody.inventory;
			if ((bool)inventory)
			{
				voidItemCount = inventory.GetTotalItemCountOfTier(ItemTier.VoidTier1) + inventory.GetTotalItemCountOfTier(ItemTier.VoidTier2) + inventory.GetTotalItemCountOfTier(ItemTier.VoidTier3) + inventory.GetTotalItemCountOfTier(ItemTier.VoidBoss);
			}
		}

		[Server]
		public void AddCorruption(float amount)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoidSurvivorController::AddCorruption(System.Single)' called on client");
			}
			else
			{
				Network_corruption = Mathf.Clamp(corruption + amount, minimumCorruption, maxCorruption);
			}
		}

		private void OnCorruptionModified(float newCorruption)
		{
			if ((bool)overlayInstanceAnimator && Mathf.Abs(newCorruption - corruption) > corruptionDeltaThresholdToAnimate)
			{
				overlayInstanceAnimator.SetTrigger("corruptionIncreased");
			}
			Network_corruption = newCorruption;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_corruption);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_corruption);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_corruption = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnCorruptionModified(reader.ReadSingle());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[Serializable]
	public struct UserVote : IEquatable<UserVote>
	{
		public GameObject networkUserObject;

		public int voteChoiceIndex;

		public bool receivedVote => voteChoiceIndex >= 0;

		public bool Equals(UserVote other)
		{
			if (other.networkUserObject.Equals(networkUserObject))
			{
				return other.voteChoiceIndex.Equals(voteChoiceIndex);
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			return (obj as UserVote?)?.Equals(this) ?? false;
		}

		public override int GetHashCode()
		{
			return (-555733029 * -1521134295 + EqualityComparer<GameObject>.Default.GetHashCode(networkUserObject)) * -1521134295 + voteChoiceIndex.GetHashCode();
		}
	}
	public class SyncListUserVote : SyncListStruct<UserVote>
	{
		public override void SerializeItem(NetworkWriter writer, UserVote item)
		{
			writer.Write(item.networkUserObject);
			writer.WritePackedUInt32((uint)item.voteChoiceIndex);
		}

		public override UserVote DeserializeItem(NetworkReader reader)
		{
			UserVote result = default(UserVote);
			result.networkUserObject = reader.ReadGameObject();
			result.voteChoiceIndex = (int)reader.ReadPackedUInt32();
			return result;
		}
	}
	public class VoteController : NetworkBehaviour
	{
		public enum TimerStartCondition
		{
			Immediate,
			OnAnyVoteReceived,
			WhileAnyVoteReceived,
			WhileAllVotesReceived,
			Never
		}

		[Tooltip("Custom name for this component to help describe its role.")]
		public string customName;

		[Tooltip("Whether or not users must be participating in the run to be allowed to vote.")]
		public bool onlyAllowParticipatingPlayers = true;

		[Tooltip("Whether or not to add new players to the voting pool when they connect.")]
		public bool addNewPlayers;

		[Tooltip("Whether or not users are allowed to change their choice after submitting it.")]
		public bool canChangeVote;

		[Tooltip("Whether or not users are allowed to revoke their vote entirely after submitting it.")]
		public bool canRevokeVote;

		[Tooltip("If set, the vote cannot be completed early by all users submitting, and the timeout must occur.")]
		public bool mustTimeOut;

		[Tooltip("Whether or not this vote must reset and be unvotable while someone is connecting or disconnecting.")]
		public bool resetOnConnectionsChanged;

		[Tooltip("How long it takes for the vote to forcibly complete once the timer begins.")]
		public float timeoutDuration = 15f;

		[Tooltip("How long it takes for action to be taken after the vote is complete.")]
		public float minimumTimeBeforeProcessing = 3f;

		[Tooltip("What causes the timer to start counting down.")]
		public TimerStartCondition timerStartCondition;

		[Tooltip("An array of functions to be called based on the user vote.")]
		public UnityEvent[] choices;

		[Tooltip("The choice to use when nobody votes or everybody who can vote quits.")]
		public int defaultChoiceIndex;

		[Tooltip("Whether or not to destroy the attached GameObject when the vote completes.")]
		public bool destroyGameObjectOnComplete = true;

		private SyncListUserVote votes = new SyncListUserVote();

		[SyncVar]
		public bool timerIsActive;

		[SyncVar]
		public float timer;

		private static int kListvotes;

		public bool NetworktimerIsActive
		{
			get
			{
				return timerIsActive;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref timerIsActive, 2u);
			}
		}

		public float Networktimer
		{
			get
			{
				return timer;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref timer, 4u);
			}
		}

		[Server]
		private void StartTimer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoteController::StartTimer()' called on client");
			}
			else if (!timerIsActive)
			{
				NetworktimerIsActive = true;
				Networktimer = timeoutDuration;
			}
		}

		[Server]
		private void StopTimer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoteController::StopTimer()' called on client");
				return;
			}
			NetworktimerIsActive = false;
			Networktimer = timeoutDuration;
		}

		[Server]
		private void InitializeVoters()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoteController::InitializeVoters()' called on client");
				return;
			}
			StopTimer();
			if (votes.Count > 0)
			{
				votes.Clear();
			}
			IEnumerable<NetworkUser> source = NetworkUser.readOnlyInstancesList;
			if (onlyAllowParticipatingPlayers)
			{
				source = source.Where((NetworkUser v) => v.isParticipating);
			}
			foreach (GameObject item in source.Select((NetworkUser v) => v.gameObject))
			{
				votes.Add(new UserVote
				{
					networkUserObject = item,
					voteChoiceIndex = -1
				});
			}
		}

		[Server]
		private void AddUserToVoters(NetworkUser networkUser)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoteController::AddUserToVoters(RoR2.NetworkUser)' called on client");
			}
			else if ((!onlyAllowParticipatingPlayers || networkUser.isParticipating) && !votes.Any((UserVote v) => v.networkUserObject == networkUser.gameObject))
			{
				votes.Add(new UserVote
				{
					networkUserObject = networkUser.gameObject,
					voteChoiceIndex = -1
				});
			}
		}

		private void Awake()
		{
			if (NetworkServer.active)
			{
				if (timerStartCondition == TimerStartCondition.Immediate)
				{
					StartTimer();
				}
				if (addNewPlayers)
				{
					NetworkUser.OnPostNetworkUserStart += AddUserToVoters;
				}
				NetworkManagerSystem.onServerConnectGlobal += OnServerConnectGlobal;
				NetworkManagerSystem.onServerDisconnectGlobal += OnServerDisconnectGlobal;
			}
			votes.InitializeBehaviour(this, kListvotes);
		}

		private void OnServerConnectGlobal(NetworkConnection conn)
		{
			if (resetOnConnectionsChanged)
			{
				InitializeVoters();
			}
		}

		private void OnServerDisconnectGlobal(NetworkConnection conn)
		{
			if (resetOnConnectionsChanged)
			{
				InitializeVoters();
			}
		}

		private void OnDestroy()
		{
			NetworkUser.OnPostNetworkUserStart -= AddUserToVoters;
			NetworkManagerSystem.onServerConnectGlobal -= OnServerConnectGlobal;
			NetworkManagerSystem.onServerDisconnectGlobal -= OnServerDisconnectGlobal;
		}

		public override void OnStartServer()
		{
			base.OnStartServer();
			InitializeVoters();
		}

		[Server]
		public void ReceiveUserVote(NetworkUser networkUser, int voteChoiceIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoteController::ReceiveUserVote(RoR2.NetworkUser,System.Int32)' called on client");
				return;
			}
			if (resetOnConnectionsChanged)
			{
				int connectingClientCount = PlatformSystems.networkManager.GetConnectingClientCount();
				if (connectingClientCount > 0)
				{
					UnityEngine.Debug.LogFormat("Vote from user \"{0}\" rejected: {1} clients are currently still in the process of connecting.", networkUser.userName, connectingClientCount);
					return;
				}
			}
			if ((voteChoiceIndex < 0 && !canRevokeVote) || voteChoiceIndex >= choices.Length)
			{
				return;
			}
			GameObject gameObject = networkUser.gameObject;
			for (int i = 0; i < votes.Count; i++)
			{
				if (gameObject == votes[i].networkUserObject)
				{
					if (votes[i].receivedVote && !canChangeVote)
					{
						break;
					}
					votes[i] = new UserVote
					{
						networkUserObject = gameObject,
						voteChoiceIndex = voteChoiceIndex
					};
				}
			}
		}

		private void Update()
		{
			if (NetworkServer.active)
			{
				ServerUpdate();
			}
		}

		[Server]
		private void ServerUpdate()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoteController::ServerUpdate()' called on client");
				return;
			}
			if (timerIsActive)
			{
				Networktimer = timer - Time.deltaTime;
				if (timer < 0f)
				{
					Networktimer = 0f;
				}
			}
			int num = 0;
			for (int num2 = votes.Count - 1; num2 >= 0; num2--)
			{
				if (!votes[num2].networkUserObject)
				{
					votes.RemoveAt(num2);
				}
				else if (votes[num2].receivedVote)
				{
					num++;
				}
			}
			bool flag = num > 0;
			bool num3 = num == votes.Count;
			if (flag)
			{
				if (timerStartCondition == TimerStartCondition.OnAnyVoteReceived || timerStartCondition == TimerStartCondition.WhileAnyVoteReceived)
				{
					StartTimer();
				}
			}
			else if (timerStartCondition == TimerStartCondition.WhileAnyVoteReceived)
			{
				StopTimer();
			}
			if (num3)
			{
				if (timerStartCondition == TimerStartCondition.WhileAllVotesReceived)
				{
					StartTimer();
				}
				else if (RoR2Application.isInSinglePlayer)
				{
					Networktimer = 0f;
				}
				else
				{
					Networktimer = Mathf.Min(timer, minimumTimeBeforeProcessing);
				}
			}
			else if (timerStartCondition == TimerStartCondition.WhileAllVotesReceived)
			{
				StopTimer();
			}
			if ((num3 && !mustTimeOut) || (timerIsActive && timer <= 0f))
			{
				FinishVote();
			}
		}

		[Server]
		private void FinishVote()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.VoteController::FinishVote()' called on client");
				return;
			}
			int num = (from v in votes
				where v.receivedVote
				group v by v.voteChoiceIndex into v
				orderby v.Count() descending
				select v).FirstOrDefault()?.Key ?? defaultChoiceIndex;
			if (num >= choices.Length)
			{
				num = defaultChoiceIndex;
			}
			if (num < choices.Length)
			{
				choices[num].Invoke();
			}
			base.enabled = false;
			NetworktimerIsActive = false;
			Networktimer = 0f;
			if (destroyGameObjectOnComplete)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		public int GetVoteCount()
		{
			return votes.Count;
		}

		public UserVote GetVote(int i)
		{
			return votes[i];
		}

		public void SubmitVoteForAllLocalUsers(int choiceIndex)
		{
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				readOnlyLocalPlayers.CallCmdSubmitVote(base.gameObject, choiceIndex);
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeSyncListvotes(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("SyncList votes called on server.");
			}
			else
			{
				((VoteController)obj).votes.HandleMsg(reader);
			}
		}

		static VoteController()
		{
			kListvotes = 458257089;
			NetworkBehaviour.RegisterSyncListDelegate(typeof(VoteController), kListvotes, InvokeSyncListvotes);
			NetworkCRC.RegisterBehaviour("VoteController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WriteStructSyncListUserVote_None(writer, votes);
				writer.Write(timerIsActive);
				writer.Write(timer);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WriteStructSyncListUserVote_None(writer, votes);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(timerIsActive);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(timer);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				GeneratedNetworkCode._ReadStructSyncListUserVote_None(reader, votes);
				timerIsActive = reader.ReadBoolean();
				timer = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				GeneratedNetworkCode._ReadStructSyncListUserVote_None(reader, votes);
			}
			if (((uint)num & 2u) != 0)
			{
				timerIsActive = reader.ReadBoolean();
			}
			if (((uint)num & 4u) != 0)
			{
				timer = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[Obsolete]
	public class WarCryOnCombatDisplayController : MonoBehaviour
	{
		private CharacterBody body;

		[Tooltip("The child gameobject to enable when the warcry is ready.")]
		public GameObject readyIndicator;

		public void Start()
		{
			CharacterModel component = base.transform.root.gameObject.GetComponent<CharacterModel>();
			if ((bool)component)
			{
				body = component.body;
			}
			UpdateReadyIndicator();
		}

		public void FixedUpdate()
		{
			UpdateReadyIndicator();
		}

		private void UpdateReadyIndicator()
		{
			bool active = (bool)body && IsBodyWarCryReady(body);
			readyIndicator.SetActive(active);
		}

		private static bool IsBodyWarCryReady(CharacterBody body)
		{
			return false;
		}
	}
	public class WeatherParticles : MonoBehaviour
	{
		public bool resetPositionToZero;

		public bool lockPosition = true;

		public bool lockRotation = true;

		private static List<WeatherParticles> instancesList;

		static WeatherParticles()
		{
			instancesList = new List<WeatherParticles>();
			SceneCamera.onSceneCameraPreRender += OnSceneCameraPreRender;
		}

		private void UpdateForCamera(CameraRigController cameraRigController, bool lockPosition, bool lockRotation)
		{
			Transform transform = cameraRigController.transform;
			base.transform.SetPositionAndRotation(lockPosition ? transform.position : base.transform.position, lockRotation ? transform.rotation : base.transform.rotation);
		}

		private static void OnSceneCameraPreRender(SceneCamera sceneCamera)
		{
			if ((bool)sceneCamera.cameraRigController)
			{
				for (int i = 0; i < instancesList.Count; i++)
				{
					WeatherParticles weatherParticles = instancesList[i];
					weatherParticles.UpdateForCamera(sceneCamera.cameraRigController, weatherParticles.lockPosition, weatherParticles.lockRotation);
				}
			}
		}

		private void OnEnable()
		{
			instancesList.Add(this);
			if (resetPositionToZero)
			{
				base.transform.position = UnityEngine.Vector3.zero;
			}
		}

		private void OnDisable()
		{
			instancesList.Remove(this);
		}
	}
	public class WheelVehicleMotor : MonoBehaviour
	{
		[HideInInspector]
		public UnityEngine.Vector3 moveVector;

		public WheelCollider[] driveWheels;

		public WheelCollider[] steerWheels;

		public float motorTorque;

		public float maxSteerAngle;

		public float wheelMass = 20f;

		public float wheelRadius = 0.5f;

		public float wheelWellDistance = 2.7f;

		public float wheelSuspensionDistance = 0.3f;

		public float wheelForceAppPointDistance;

		public float wheelSuspensionSpringSpring = 35000f;

		public float wheelSuspensionSpringDamper = 4500f;

		public float wheelSuspensionSpringTargetPosition = 0.5f;

		public float forwardFrictionExtremumSlip = 0.4f;

		public float forwardFrictionValue = 1f;

		public float forwardFrictionAsymptoticSlip = 0.8f;

		public float forwardFrictionAsymptoticValue = 0.5f;

		public float forwardFrictionStiffness = 1f;

		public float sidewaysFrictionExtremumSlip = 0.2f;

		public float sidewaysFrictionValue = 1f;

		public float sidewaysFrictionAsymptoticSlip = 0.5f;

		public float sidewaysFrictionAsymptoticValue = 0.75f;

		public float sidewaysFrictionStiffness = 1f;

		private InputBankTest inputBank;

		private void Start()
		{
			inputBank = GetComponent<InputBankTest>();
		}

		private void UpdateWheelParameter(WheelCollider wheel)
		{
			wheel.mass = wheelMass;
			wheel.radius = wheelRadius;
			wheel.suspensionDistance = wheelSuspensionDistance;
			wheel.forceAppPointDistance = wheelForceAppPointDistance;
			wheel.transform.localPosition = new UnityEngine.Vector3(wheel.transform.localPosition.x, 0f - wheelWellDistance, wheel.transform.localPosition.z);
			JointSpring suspensionSpring = default(JointSpring);
			suspensionSpring.spring = wheelSuspensionSpringSpring;
			suspensionSpring.damper = wheelSuspensionSpringDamper;
			suspensionSpring.targetPosition = wheelSuspensionSpringTargetPosition;
			wheel.suspensionSpring = suspensionSpring;
			WheelFrictionCurve forwardFriction = default(WheelFrictionCurve);
			forwardFriction.extremumSlip = forwardFrictionExtremumSlip;
			forwardFriction.extremumValue = forwardFrictionValue;
			forwardFriction.asymptoteSlip = forwardFrictionAsymptoticSlip;
			forwardFriction.asymptoteValue = forwardFrictionAsymptoticValue;
			forwardFriction.stiffness = forwardFrictionStiffness;
			wheel.forwardFriction = forwardFriction;
			WheelFrictionCurve sidewaysFriction = default(WheelFrictionCurve);
			sidewaysFriction.extremumSlip = sidewaysFrictionExtremumSlip;
			sidewaysFriction.extremumValue = sidewaysFrictionValue;
			sidewaysFriction.asymptoteSlip = sidewaysFrictionAsymptoticSlip;
			sidewaysFriction.asymptoteValue = sidewaysFrictionAsymptoticValue;
			sidewaysFriction.stiffness = sidewaysFrictionStiffness;
			wheel.sidewaysFriction = sidewaysFriction;
		}

		private void UpdateAllWheelParameters()
		{
			WheelCollider[] array = driveWheels;
			foreach (WheelCollider wheel in array)
			{
				UpdateWheelParameter(wheel);
			}
			array = steerWheels;
			foreach (WheelCollider wheel2 in array)
			{
				UpdateWheelParameter(wheel2);
			}
		}

		private void FixedUpdate()
		{
			UpdateAllWheelParameters();
			if ((bool)inputBank)
			{
				moveVector = inputBank.moveVector;
				float f = 0f;
				if (moveVector.sqrMagnitude > 0f)
				{
					f = Util.AngleSigned(base.transform.forward, moveVector, UnityEngine.Vector3.up);
				}
				WheelCollider[] array = steerWheels;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].steerAngle = Mathf.Min(maxSteerAngle, Mathf.Abs(f)) * Mathf.Sign(f);
				}
				array = driveWheels;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].motorTorque = moveVector.magnitude * motorTorque;
				}
			}
		}
	}
	public class WinchControl : MonoBehaviour
	{
		public Transform tailTransform;

		public string attachmentString;

		private ProjectileGhostController projectileGhostController;

		private Transform attachmentTransform;

		private void Start()
		{
			attachmentTransform = FindAttachmentTransform();
			if ((bool)attachmentTransform)
			{
				tailTransform.position = attachmentTransform.position;
			}
		}

		private void Update()
		{
			if (!attachmentTransform)
			{
				attachmentTransform = FindAttachmentTransform();
			}
			if ((bool)attachmentTransform)
			{
				tailTransform.position = attachmentTransform.position;
			}
		}

		private Transform FindAttachmentTransform()
		{
			projectileGhostController = GetComponent<ProjectileGhostController>();
			if ((bool)projectileGhostController)
			{
				Transform authorityTransform = projectileGhostController.authorityTransform;
				if ((bool)authorityTransform)
				{
					ProjectileController component = authorityTransform.GetComponent<ProjectileController>();
					if ((bool)component)
					{
						GameObject owner = component.owner;
						if ((bool)owner)
						{
							ModelLocator component2 = owner.GetComponent<ModelLocator>();
							if ((bool)component2)
							{
								Transform modelTransform = component2.modelTransform;
								if ((bool)modelTransform)
								{
									ChildLocator component3 = modelTransform.GetComponent<ChildLocator>();
									if ((bool)component3)
									{
										return component3.FindChild(attachmentString);
									}
								}
							}
						}
					}
				}
			}
			return null;
		}
	}
	public class WispAI : MonoBehaviour
	{
		private struct TargetSearchCandidate
		{
			public Transform transform;

			public UnityEngine.Vector3 positionDiff;

			public float sqrDistance;
		}

		[Tooltip("The character to control.")]
		public GameObject body;

		[Tooltip("The enemy to target.")]
		public Transform targetTransform;

		[Tooltip("The skill to activate for a ranged attack.")]
		public GenericSkill fireSkill;

		[Tooltip("How close the character must be to the enemy to use a ranged attack.")]
		public float fireRange;

		private CharacterDirection bodyDirectionComponent;

		private CharacterMotor bodyMotorComponent;

		private static List<TargetSearchCandidate> candidateList = new List<TargetSearchCandidate>();

		private void Awake()
		{
			bodyDirectionComponent = body.GetComponent<CharacterDirection>();
			bodyMotorComponent = body.GetComponent<CharacterMotor>();
		}

		private void FixedUpdate()
		{
			if (!body)
			{
				return;
			}
			if (!targetTransform)
			{
				targetTransform = SearchForTarget();
			}
			if ((bool)targetTransform)
			{
				UnityEngine.Vector3 vector = targetTransform.position - body.transform.position;
				bodyMotorComponent.moveDirection = vector;
				bodyDirectionComponent.moveVector = UnityEngine.Vector3.Lerp(bodyDirectionComponent.moveVector, vector, Time.deltaTime);
				if ((bool)fireSkill && vector.sqrMagnitude < fireRange * fireRange)
				{
					fireSkill.ExecuteIfReady();
				}
			}
		}

		private Transform SearchForTarget()
		{
			UnityEngine.Vector3 position = body.transform.position;
			UnityEngine.Vector3 forward = bodyDirectionComponent.forward;
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Player);
			for (int i = 0; i < teamMembers.Count; i++)
			{
				Transform transform = teamMembers[i].transform;
				UnityEngine.Vector3 vector = transform.position - position;
				if (UnityEngine.Vector3.Dot(forward, vector) > 0f)
				{
					candidateList.Add(new TargetSearchCandidate
					{
						transform = transform,
						positionDiff = vector,
						sqrDistance = vector.sqrMagnitude
					});
				}
			}
			candidateList.Sort((TargetSearchCandidate a, TargetSearchCandidate b) => (!(a.sqrDistance < b.sqrDistance)) ? ((a.sqrDistance != b.sqrDistance) ? 1 : 0) : (-1));
			Transform result = null;
			for (int j = 0; j < candidateList.Count; j++)
			{
				if (!Physics.Raycast(position, candidateList[j].positionDiff, Mathf.Sqrt(candidateList[j].sqrDistance), LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					result = candidateList[j].transform;
					break;
				}
			}
			candidateList.Clear();
			return result;
		}
	}
	public class WokController : NetworkBehaviour, IInteractable, IDisplayNameProvider
	{
		[Serializable]
		public class WokIngredientData : IEquatable<WokIngredientData>
		{
			public NetworkInstanceId playerNetId;

			public bool unlockedChef;

			public bool previouslyStoredIngredient1;

			public bool previouslyStoredIngredient2;

			public bool previouslyStoredIngredient3;

			public WokIngredientData()
			{
				playerNetId = default(NetworkInstanceId);
				unlockedChef = false;
				previouslyStoredIngredient1 = false;
				previouslyStoredIngredient2 = false;
				previouslyStoredIngredient3 = false;
			}

			public WokIngredientData(NetworkInstanceId _playerNetId)
			{
				playerNetId = _playerNetId;
				unlockedChef = false;
				previouslyStoredIngredient1 = false;
				previouslyStoredIngredient2 = false;
				previouslyStoredIngredient3 = false;
			}

			public WokIngredientData(PlayerCharacterMasterController playerController)
			{
				playerNetId = playerController.networkUser.netId;
				if (playerController.hasAuthority)
				{
					UserProfile userProfile = playerController.networkUser.localUser.userProfile;
					if (userProfile != null)
					{
						previouslyStoredIngredient1 = userProfile.chefAchievementIngredient1;
						previouslyStoredIngredient2 = userProfile.chefAchievementIngredient2;
						previouslyStoredIngredient3 = userProfile.chefAchievementIngredient3;
						UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef("Characters.Chef");
						unlockedChef = userProfile.HasUnlockable(unlockableDef);
					}
				}
			}

			public bool Equals(WokIngredientData other)
			{
				if (playerNetId == other.playerNetId && previouslyStoredIngredient1 == other.previouslyStoredIngredient1 && previouslyStoredIngredient2 == other.previouslyStoredIngredient2 && previouslyStoredIngredient3 == other.previouslyStoredIngredient3)
				{
					return unlockedChef == other.unlockedChef;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (int)playerNetId.Value;
			}
		}

		[SerializeField]
		private ItemDef Ingredient1;

		[SerializeField]
		private ItemDef Ingredient2;

		[SerializeField]
		private ItemDef Ingredient3;

		[SerializeField]
		private GameObject IngredientObject1;

		[SerializeField]
		private GameObject IngredientObject1Received;

		[SerializeField]
		private GameObject IngredientObject2;

		[SerializeField]
		private GameObject IngredientObject2Received;

		[SerializeField]
		private GameObject IngredientObject3;

		[SerializeField]
		private GameObject IngredientObject3Received;

		[SerializeField]
		private ChildLocator childLocator;

		[SerializeField]
		private GameObject dissolveVFX;

		[SerializeField]
		private GameObject wokCookingVFX;

		[SerializeField]
		private GameObject chefUnlockVFX;

		[SerializeField]
		private GameObject chefModelToAnimate;

		[SerializeField]
		public ExpansionDef requiredExpansion;

		private bool Ingredient1Received;

		private bool Ingredient2Received;

		private bool Ingredient3Received;

		private Interactor cachedCookInteractor;

		private CharacterBody cookBody;

		[SerializeField]
		private string chefAchievement = "ActivateChef";

		[SerializeField]
		private string chefUnlockable = "Characters.Chef";

		private int validRecipe;

		public string displayNameToken = "WOK_NAME";

		public string contextToken = "WOK_CONTEXT";

		private bool receivedAllIngredients;

		private bool storingIngredient = true;

		[SerializeField]
		private float storingIngredientDuration = 0.75f;

		private WokIngredientData localWokData;

		private bool serverDisableHidingChef;

		[SyncVar]
		private PickupIndex pickupIndex;

		private float fixedAge;

		[SerializeField]
		private float mixingDuration = 1.5f;

		[SyncVar]
		private bool mixingBegin;

		[SyncVar]
		private bool mixingFinished;

		private bool interactorPresent;

		private float interactorDelay = 3f;

		private static Dictionary<NetworkInstanceId, WokIngredientData> wokDataDictionary;

		[SerializeField]
		public Animator WokAnimator;

		private static int kRpcRpcSetRecipeVariables;

		private static int kRpcRpcHideChef;

		private static int kRpcRpcUpdateLocalClientData;

		private static int kCmdCmdTransmitLocalPlayerWokDataToServer;

		public PickupIndex NetworkpickupIndex
		{
			get
			{
				return pickupIndex;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref pickupIndex, 1u);
			}
		}

		public bool NetworkmixingBegin
		{
			get
			{
				return mixingBegin;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref mixingBegin, 2u);
			}
		}

		public bool NetworkmixingFinished
		{
			get
			{
				return mixingFinished;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref mixingFinished, 4u);
			}
		}

		public static event Action<Interactor> onOpened;

		public static event Action<Interactor> chefRecipeComplete;

		public void OnInteractionBegin(Interactor activator)
		{
			cachedCookInteractor = activator;
			cookBody = cachedCookInteractor.GetComponent<CharacterBody>();
			if (!(cookBody == null))
			{
				NetworkInstanceId key = cookBody.master.playerCharacterMasterController.networkUser.netId;
				if (wokDataDictionary.ContainsKey(key))
				{
					ReceiveIngredient(cookBody, wokDataDictionary[key]);
				}
			}
		}

		[ClientRpc]
		private void RpcSetRecipeVariables(bool _storingIngredient, bool _receivedAllIngredients)
		{
			if (!NetworkServer.active)
			{
				storingIngredient |= _storingIngredient;
				receivedAllIngredients = _receivedAllIngredients;
				if (_storingIngredient || _receivedAllIngredients)
				{
					fixedAge = 0f;
				}
			}
		}

		[ClientRpc]
		private void RpcHideChef()
		{
			WokAnimator.gameObject.SetActive(value: false);
		}

		[Server]
		private void EvaluateChefVisibility()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WokController::EvaluateChefVisibility()' called on client");
			}
			else if (!serverDisableHidingChef && CheckForCompletePlayerUnlock())
			{
				WokAnimator.gameObject.SetActive(value: false);
				serverDisableHidingChef = true;
				CallRpcHideChef();
			}
		}

		private bool CheckForCompletePlayerUnlock()
		{
			foreach (KeyValuePair<NetworkInstanceId, WokIngredientData> item in wokDataDictionary)
			{
				if (!item.Value.unlockedChef)
				{
					return false;
				}
			}
			return true;
		}

		private void FixedUpdate()
		{
			fixedAge += Time.deltaTime;
			if (storingIngredient && fixedAge > storingIngredientDuration)
			{
				storingIngredient = false;
				UpdateIngredientVisibility(localWokData);
				if (NetworkServer.active)
				{
					EvaluateChefVisibility();
				}
			}
			if (!receivedAllIngredients || fixedAge < mixingDuration)
			{
				return;
			}
			if (!mixingBegin)
			{
				NetworkmixingBegin = true;
				MixIngredients();
				fixedAge = 0f;
				mixingDuration = 0.25f;
			}
			else if (!mixingFinished)
			{
				NetworkmixingFinished = true;
				RecipeComplete();
				if ((bool)WokAnimator)
				{
					WokAnimator.SetBool("Activated", value: true);
				}
				if (NetworkServer.active)
				{
					WokController.chefRecipeComplete?.Invoke(cachedCookInteractor);
				}
				DisableAllIngredientVisibility();
			}
		}

		[Server]
		private void ReceiveIngredient(CharacterBody cookBody, WokIngredientData wokData)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WokController::ReceiveIngredient(RoR2.CharacterBody,RoR2.WokController/WokIngredientData)' called on client");
			}
			else if (TryGrabIngredient(cookBody, wokData))
			{
				serverDisableHidingChef = true;
				fixedAge = 0f;
				storingIngredient = true;
				if (CheckRecipeComplete(wokData))
				{
					wokData.unlockedChef = true;
					fixedAge = 0f;
					receivedAllIngredients = true;
					cachedCookInteractor = cookBody.GetComponent<Interactor>();
				}
				CallRpcSetRecipeVariables(storingIngredient, receivedAllIngredients);
				wokDataDictionary[wokData.playerNetId] = wokData;
				CallRpcUpdateLocalClientData(wokData);
			}
		}

		private bool TryGrabIngredient(CharacterBody cookBody, WokIngredientData wokData)
		{
			if (Ingredient1 != null && TryTakeSpecificIngredient(Ingredient1.itemIndex, IngredientObject1, ref wokData.previouslyStoredIngredient1))
			{
				return true;
			}
			if (Ingredient2 != null && TryTakeSpecificIngredient(Ingredient2.itemIndex, IngredientObject2, ref wokData.previouslyStoredIngredient2))
			{
				return true;
			}
			if (Ingredient3 != null && TryTakeSpecificIngredient(Ingredient3.itemIndex, IngredientObject3, ref wokData.previouslyStoredIngredient3))
			{
				return true;
			}
			return false;
			bool TryTakeSpecificIngredient(ItemIndex itemIndex, GameObject ingredientObject, ref bool wokContainsIngredient)
			{
				if (wokContainsIngredient)
				{
					return false;
				}
				if (!cookBody.inventory.itemAcquisitionOrder.Contains(itemIndex))
				{
					return false;
				}
				wokContainsIngredient = true;
				cookBody.inventory.RemoveItem(itemIndex);
				return true;
			}
		}

		private void UpdateIngredientVisibility(WokIngredientData wokData)
		{
			if (wokData != null)
			{
				UpdateIngredientAppearance(IngredientObject1Received, IngredientObject1, wokData.unlockedChef || wokData.previouslyStoredIngredient1);
				UpdateIngredientAppearance(IngredientObject2Received, IngredientObject2, wokData.unlockedChef || wokData.previouslyStoredIngredient2);
				UpdateIngredientAppearance(IngredientObject3Received, IngredientObject3, wokData.unlockedChef || wokData.previouslyStoredIngredient3);
			}
			static void UpdateIngredientAppearance(GameObject ingredientObjReceived, GameObject ingredientObj, bool shouldUnlock)
			{
				ingredientObjReceived.SetActive(shouldUnlock);
				ingredientObj.SetActive(!shouldUnlock);
			}
		}

		private void DisableAllIngredientVisibility()
		{
			IngredientObject1Received.SetActive(value: false);
			IngredientObject1.SetActive(value: false);
			IngredientObject2Received.SetActive(value: false);
			IngredientObject2.SetActive(value: false);
			IngredientObject3Received.SetActive(value: false);
			IngredientObject3.SetActive(value: false);
		}

		private void MixIngredients()
		{
			IngredientObject1Received.SetActive(value: false);
			EffectData effectData = new EffectData
			{
				origin = IngredientObject1.transform.position,
				genericFloat = mixingDuration,
				genericUInt = (uint)(Ingredient1.itemIndex + 1)
			};
			effectData.SetNetworkedObjectReference(base.gameObject);
			EffectManager.SpawnEffect(dissolveVFX, effectData, transmit: false);
			IngredientObject2Received.SetActive(value: false);
			EffectData effectData2 = new EffectData
			{
				origin = IngredientObject2.transform.position,
				genericFloat = mixingDuration,
				genericUInt = (uint)(Ingredient2.itemIndex + 1)
			};
			effectData2.SetNetworkedObjectReference(base.gameObject);
			EffectManager.SpawnEffect(dissolveVFX, effectData2, transmit: false);
			IngredientObject3Received.SetActive(value: false);
			EffectData effectData3 = new EffectData
			{
				origin = IngredientObject3.transform.position,
				genericFloat = mixingDuration,
				genericUInt = (uint)(Ingredient3.itemIndex + 1)
			};
			effectData3.SetNetworkedObjectReference(base.gameObject);
			EffectManager.SpawnEffect(dissolveVFX, effectData3, transmit: false);
			Transform transform = childLocator.FindChild("ModelPivot");
			EffectData effectData4 = new EffectData
			{
				origin = transform.position,
				genericFloat = mixingDuration,
				genericUInt = (uint)(Ingredient1.itemIndex + 1)
			};
			EffectManager.SpawnEffect(wokCookingVFX, effectData4, transmit: false);
			Util.PlaySound("Play_obj_chefWok_cook_all", base.gameObject);
		}

		private void RecipeComplete()
		{
			Transform transform = childLocator.FindChild("ModelPivot");
			EffectData effectData = new EffectData
			{
				origin = transform.position,
				genericFloat = 1.5f,
				genericUInt = (uint)(Ingredient1.itemIndex + 1)
			};
			EffectManager.SpawnEffect(chefUnlockVFX, effectData, transmit: false);
			Util.PlaySound("Play_obj_chefWok_cook_complete", base.gameObject);
			if (NetworkServer.active)
			{
				serverDisableHidingChef = true;
			}
		}

		private bool CheckRecipeComplete(WokIngredientData wokData)
		{
			if (wokData.previouslyStoredIngredient1 && wokData.previouslyStoredIngredient2)
			{
				return wokData.previouslyStoredIngredient3;
			}
			return false;
		}

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextToken);
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public Interactability GetInteractability(Interactor activator)
		{
			cookBody = activator.GetComponent<CharacterBody>();
			Run instance = Run.instance;
			if ((bool)instance && (bool)requiredExpansion)
			{
				if (!instance.IsExpansionEnabled(requiredExpansion))
				{
					return Interactability.Disabled;
				}
				EntitlementDef requiredEntitlement = requiredExpansion.requiredEntitlement;
				if ((bool)requiredEntitlement)
				{
					PlayerCharacterMasterController playerCharacterMasterController = cookBody.master.playerCharacterMasterController;
					if (!playerCharacterMasterController)
					{
						return Interactability.Disabled;
					}
					PlayerCharacterMasterControllerEntitlementTracker component = playerCharacterMasterController.GetComponent<PlayerCharacterMasterControllerEntitlementTracker>();
					if (!component)
					{
						UnityEngine.Debug.LogWarning("Rejecting interact because the playerCharacterMasterController doesn't have a sibling PlayerCharacterMasterControllerEntitlementTracker");
						return Interactability.Disabled;
					}
					if (!component.HasEntitlement(requiredEntitlement))
					{
						UnityEngine.Debug.LogWarning("Rejecting interact because the player doesn't have entitlement " + requiredEntitlement.name);
						return Interactability.Disabled;
					}
				}
			}
			if (receivedAllIngredients || storingIngredient)
			{
				return Interactability.Disabled;
			}
			if (cookBody == null)
			{
				return Interactability.Disabled;
			}
			NetworkInstanceId key = cookBody.master.playerCharacterMasterController.networkUser.netId;
			if (!wokDataDictionary.ContainsKey(key))
			{
				return Interactability.Disabled;
			}
			WokIngredientData wokIngredientData = wokDataDictionary[key];
			if (wokIngredientData.unlockedChef)
			{
				return Interactability.Disabled;
			}
			if (!((cookBody.inventory.itemAcquisitionOrder.Contains(Ingredient1.itemIndex) && !wokIngredientData.previouslyStoredIngredient1) | (cookBody.inventory.itemAcquisitionOrder.Contains(Ingredient2.itemIndex) && !wokIngredientData.previouslyStoredIngredient2) | (cookBody.inventory.itemAcquisitionOrder.Contains(Ingredient3.itemIndex) && !wokIngredientData.previouslyStoredIngredient3)))
			{
				return Interactability.Disabled;
			}
			return Interactability.Available;
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public void OnEnable()
		{
			InstanceTracker.Add(this);
			UpdateAndSendLocalPlayerDataToServer();
		}

		public void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			return !receivedAllIngredients;
		}

		public bool ShouldProximityHighlight()
		{
			return false;
		}

		public void UpdateAndSendLocalPlayerDataToServer()
		{
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (!(instance == null) && instance.networkUser.hasAuthority && instance.networkUser.localUser.userProfile != null)
				{
					WokIngredientData wokData = new WokIngredientData(instance);
					UpdateIngredientVisibility(wokData);
					CacheAndSendWokData(wokData);
					localWokData = wokData;
				}
			}
		}

		private void CacheAndSendWokData(WokIngredientData wokData)
		{
			wokDataDictionary[wokData.playerNetId] = wokData;
			if (!NetworkServer.active)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				networkWriter.StartMessage(80);
				networkWriter.Write(wokData.playerNetId.Value);
				networkWriter.Write(wokData.unlockedChef);
				networkWriter.Write(wokData.previouslyStoredIngredient1);
				networkWriter.Write(wokData.previouslyStoredIngredient2);
				networkWriter.Write(wokData.previouslyStoredIngredient3);
				networkWriter.FinishMessage();
				ClientScene.readyConnection.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
			}
		}

		[NetworkMessageHandler(msgType = 80, server = true)]
		private static void ServerReceiveWokData(NetworkMessage netMsg)
		{
			WokIngredientData wokIngredientData = new WokIngredientData(new NetworkInstanceId(netMsg.reader.ReadUInt32()));
			wokIngredientData.unlockedChef = netMsg.reader.ReadBoolean();
			wokIngredientData.previouslyStoredIngredient1 = netMsg.reader.ReadBoolean();
			wokIngredientData.previouslyStoredIngredient2 = netMsg.reader.ReadBoolean();
			wokIngredientData.previouslyStoredIngredient3 = netMsg.reader.ReadBoolean();
			wokDataDictionary[wokIngredientData.playerNetId] = wokIngredientData;
		}

		private PlayerCharacterMasterController FindLocalPlayerCharacterMasterControllerByNetId(NetworkInstanceId netId)
		{
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (!(instance == null) && instance.networkUser.netId == netId && instance.networkUser.hasAuthority)
				{
					return instance;
				}
			}
			return null;
		}

		[ClientRpc]
		public void RpcUpdateLocalClientData(WokIngredientData wokData)
		{
			PlayerCharacterMasterController playerCharacterMasterController = FindLocalPlayerCharacterMasterControllerByNetId(wokData.playerNetId);
			if (playerCharacterMasterController == null)
			{
				return;
			}
			UserProfile userProfile = playerCharacterMasterController.networkUser?.localUser?.userProfile;
			if (userProfile != null)
			{
				bool flag = userProfile.HasAchievement(chefAchievement);
				wokData.unlockedChef |= flag;
				if (!wokData.unlockedChef || (wokData.unlockedChef && !flag))
				{
					GameObject playerObject = playerCharacterMasterController.master.GetBody()?.gameObject;
					TryAddNewIngredientClient(ref userProfile.chefAchievementIngredient1, wokData.previouslyStoredIngredient1, Ingredient1.itemIndex, IngredientObject1, playerObject);
					TryAddNewIngredientClient(ref userProfile.chefAchievementIngredient2, wokData.previouslyStoredIngredient2, Ingredient2.itemIndex, IngredientObject2, playerObject);
					TryAddNewIngredientClient(ref userProfile.chefAchievementIngredient3, wokData.previouslyStoredIngredient3, Ingredient3.itemIndex, IngredientObject3, playerObject);
				}
				else
				{
					userProfile.chefAchievementIngredient1 = false;
					userProfile.chefAchievementIngredient2 = false;
					userProfile.chefAchievementIngredient3 = false;
				}
				wokDataDictionary[wokData.playerNetId] = wokData;
				localWokData = wokData;
			}
		}

		private void TryAddNewIngredientClient(ref bool profileHasIngredient, bool wokDataHasIngredient, ItemIndex itemIndex, GameObject ingredientObject, GameObject playerObject)
		{
			if (profileHasIngredient != wokDataHasIngredient && wokDataHasIngredient)
			{
				profileHasIngredient = true;
				GameObject effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/DelusionItemDissolveVFX");
				EffectData effectData = new EffectData
				{
					origin = playerObject.transform.position,
					genericFloat = storingIngredientDuration,
					genericUInt = (uint)(itemIndex + 1)
				};
				if (playerObject != null)
				{
					effectData.SetNetworkedObjectReference(ingredientObject);
				}
				EffectManager.SpawnEffect(effectPrefab, effectData, transmit: false);
				Util.PlaySound("Play_obj_chefWok_item1_place", base.gameObject);
				fixedAge = 0f;
			}
		}

		[Command]
		public void CmdTransmitLocalPlayerWokDataToServer(WokIngredientData wokData)
		{
			wokDataDictionary[wokData.playerNetId] = wokData;
		}

		static WokController()
		{
			wokDataDictionary = new Dictionary<NetworkInstanceId, WokIngredientData>();
			kCmdCmdTransmitLocalPlayerWokDataToServer = -976766546;
			NetworkBehaviour.RegisterCommandDelegate(typeof(WokController), kCmdCmdTransmitLocalPlayerWokDataToServer, InvokeCmdCmdTransmitLocalPlayerWokDataToServer);
			kRpcRpcSetRecipeVariables = 429636140;
			NetworkBehaviour.RegisterRpcDelegate(typeof(WokController), kRpcRpcSetRecipeVariables, InvokeRpcRpcSetRecipeVariables);
			kRpcRpcHideChef = -1575737907;
			NetworkBehaviour.RegisterRpcDelegate(typeof(WokController), kRpcRpcHideChef, InvokeRpcRpcHideChef);
			kRpcRpcUpdateLocalClientData = -667434414;
			NetworkBehaviour.RegisterRpcDelegate(typeof(WokController), kRpcRpcUpdateLocalClientData, InvokeRpcRpcUpdateLocalClientData);
			NetworkCRC.RegisterBehaviour("WokController", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdTransmitLocalPlayerWokDataToServer(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdTransmitLocalPlayerWokDataToServer called on client.");
			}
			else
			{
				((WokController)obj).CmdTransmitLocalPlayerWokDataToServer(GeneratedNetworkCode._ReadWokIngredientData_WokController(reader));
			}
		}

		public void CallCmdTransmitLocalPlayerWokDataToServer(WokIngredientData wokData)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdTransmitLocalPlayerWokDataToServer called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdTransmitLocalPlayerWokDataToServer(wokData);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdTransmitLocalPlayerWokDataToServer);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteWokIngredientData_WokController(networkWriter, wokData);
			SendCommandInternal(networkWriter, 0, "CmdTransmitLocalPlayerWokDataToServer");
		}

		protected static void InvokeRpcRpcSetRecipeVariables(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSetRecipeVariables called on server.");
			}
			else
			{
				((WokController)obj).RpcSetRecipeVariables(reader.ReadBoolean(), reader.ReadBoolean());
			}
		}

		protected static void InvokeRpcRpcHideChef(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcHideChef called on server.");
			}
			else
			{
				((WokController)obj).RpcHideChef();
			}
		}

		protected static void InvokeRpcRpcUpdateLocalClientData(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcUpdateLocalClientData called on server.");
			}
			else
			{
				((WokController)obj).RpcUpdateLocalClientData(GeneratedNetworkCode._ReadWokIngredientData_WokController(reader));
			}
		}

		public void CallRpcSetRecipeVariables(bool _storingIngredient, bool _receivedAllIngredients)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSetRecipeVariables called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSetRecipeVariables);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(_storingIngredient);
			networkWriter.Write(_receivedAllIngredients);
			SendRPCInternal(networkWriter, 0, "RpcSetRecipeVariables");
		}

		public void CallRpcHideChef()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcHideChef called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcHideChef);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcHideChef");
		}

		public void CallRpcUpdateLocalClientData(WokIngredientData wokData)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcUpdateLocalClientData called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcUpdateLocalClientData);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteWokIngredientData_WokController(networkWriter, wokData);
			SendRPCInternal(networkWriter, 0, "RpcUpdateLocalClientData");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
				writer.Write(mixingBegin);
				writer.Write(mixingFinished);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				GeneratedNetworkCode._WritePickupIndex_None(writer, pickupIndex);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(mixingBegin);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(mixingFinished);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
				mixingBegin = reader.ReadBoolean();
				mixingFinished = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				pickupIndex = GeneratedNetworkCode._ReadPickupIndex_None(reader);
			}
			if (((uint)num & 2u) != 0)
			{
				mixingBegin = reader.ReadBoolean();
			}
			if (((uint)num & 4u) != 0)
			{
				mixingFinished = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class WormBodyPositions : MonoBehaviour
	{
		private struct Keyframe
		{
			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;

			public UnityEngine.Vector3 fromPreviousNormal;

			public float fromPreviousLength;
		}

		public UnityEngine.Vector3 headVelocity = UnityEngine.Vector3.zero;

		public Transform[] segments;

		public float segmentRadius = 1f;

		private List<Keyframe> positionHistory = new List<Keyframe>();

		private void Start()
		{
			positionHistory.Add(new Keyframe
			{
				rotation = segments[0].rotation,
				position = segments[0].position,
				fromPreviousNormal = UnityEngine.Vector3.zero,
				fromPreviousLength = 0f
			});
		}

		private void FixedUpdate()
		{
			UnityEngine.Vector3 position = segments[0].position;
			UnityEngine.Vector3 vector = position - positionHistory[positionHistory.Count - 1].position;
			float magnitude = vector.magnitude;
			if (magnitude != 0f)
			{
				UnityEngine.Quaternion rotation = segments[0].rotation;
				segments[0].up = -vector;
				UnityEngine.Quaternion rotation2 = segments[0].rotation;
				segments[0].rotation = UnityEngine.Quaternion.RotateTowards(rotation, rotation2, 360f * Time.fixedDeltaTime);
				positionHistory.Add(new Keyframe
				{
					rotation = segments[0].rotation,
					position = position,
					fromPreviousNormal = vector * (1f / magnitude),
					fromPreviousLength = magnitude
				});
			}
			float num = segmentRadius * 2f;
			float num2 = num;
			UnityEngine.Vector3 a = position;
			int num3 = 1;
			for (int num4 = positionHistory.Count - 1; num4 >= 1; num4--)
			{
				UnityEngine.Vector3 position2 = positionHistory[num4 - 1].position;
				float fromPreviousLength = positionHistory[num4].fromPreviousLength;
				if (num2 < fromPreviousLength)
				{
					float t = num2 / fromPreviousLength;
					segments[num3].position = UnityEngine.Vector3.Lerp(a, position2, t);
					num3++;
					if (num3 >= segments.Length)
					{
						positionHistory.RemoveRange(0, num4 - 1);
						break;
					}
					num2 += num;
				}
				num2 -= fromPreviousLength;
				a = position2;
			}
			if (segments.Length <= 1)
			{
				return;
			}
			UnityEngine.Quaternion rotation3 = segments[0].rotation;
			UnityEngine.Vector3 vector2 = segments[0].position;
			UnityEngine.Vector3 vector3 = segments[1].position;
			for (int i = 1; i < segments.Length - 1; i++)
			{
				UnityEngine.Vector3 position3 = segments[i + 1].position;
				UnityEngine.Vector3 vector4 = position3 - vector2;
				if (vector4 != UnityEngine.Vector3.zero)
				{
					segments[i].rotation = rotation3;
					segments[i].up = vector4;
				}
				vector2 = vector3;
				vector3 = position3;
			}
		}
	}
	[RequireComponent(typeof(CharacterBody))]
	public class WormBodyPositions2 : NetworkBehaviour, ITeleportHandler, IEventSystemHandler, ILifeBehavior, IPainAnimationHandler
	{
		private struct PositionRotationPair
		{
			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;
		}

		[Serializable]
		public struct KeyFrame
		{
			public CubicBezier3 curve;

			public float length;

			public float time;
		}

		public delegate void BurrowExpectedCallback(float expectedTime, UnityEngine.Vector3 hitPosition, UnityEngine.Vector3 hitNormal);

		public delegate void BreachExpectedCallback(float expectedTime, UnityEngine.Vector3 hitPosition, UnityEngine.Vector3 hitNormal);

		public struct TravelCallback
		{
			public float time;

			public Action callback;
		}

		public Transform[] bones;

		public float[] segmentLengths;

		[Tooltip("How far behind the chaser the head is, in seconds.")]
		public float followDelay = 2f;

		[Tooltip("Whether or not the jaw will close/open.")]
		public bool animateJaws;

		public Animator animator;

		public string jawMecanimCycleParameter;

		public float jawMecanimDampTime;

		public float jawClosedDistance;

		public float jawOpenDistance;

		public GameObject warningEffectPrefab;

		public GameObject burrowEffectPrefab;

		public float maxPainDisplacementMagnitude = 2f;

		public float painDisplacementRecoverySpeed = 8f;

		public bool shouldFireMeatballsOnImpact = true;

		public bool shouldFireBlastAttackOnImpact = true;

		public bool enableSurfaceTests = true;

		public float undergroundTestYOffset;

		private CharacterBody characterBody;

		private CharacterDirection characterDirection;

		private PositionRotationPair[] boneTransformationBuffer;

		private UnityEngine.Vector3[] boneDisplacements;

		private float headDistance;

		private float totalLength;

		private const float endBonusLength = 4f;

		private const float fakeEndSegmentLength = 2f;

		private readonly List<KeyFrame> keyFrames = new List<KeyFrame>();

		private float keyFramesTotalLength;

		public float spawnDepth = 30f;

		private Collider entranceCollider;

		private Collider exitCollider;

		private UnityEngine.Vector3 previousSurfaceTestEnd;

		private List<TravelCallback> travelCallbacks;

		private const float impactSoundPrestartDuration = 0.5f;

		public float impactCooldownDuration = 0.1f;

		private float enterTriggerCooldownTimer;

		private float exitTriggerCooldownTimer;

		private bool shouldTriggerDeathEffectOnNextImpact;

		private float deathTime = float.NegativeInfinity;

		public GameObject meatballProjectile;

		public GameObject blastAttackEffect;

		public int meatballCount;

		public float meatballAngle;

		public float meatballDamageCoefficient;

		public float meatballProcCoefficient;

		public float meatballForce;

		public float blastAttackDamageCoefficient;

		public float blastAttackProcCoefficient;

		public float blastAttackRadius;

		public float blastAttackForce;

		public float blastAttackBonusVerticalForce;

		public float speedMultiplier = 2f;

		private bool _playingBurrowSound;

		private static int kRpcRpcSendKeyFrame;

		private static int kRpcRpcPlaySurfaceImpactSound;

		public KeyFrame newestKeyFrame { get; private set; }

		public bool underground { get; private set; }

		private bool playingBurrowSound
		{
			get
			{
				return _playingBurrowSound;
			}
			set
			{
				if (value != _playingBurrowSound)
				{
					_playingBurrowSound = value;
					Util.PlaySound(value ? "Play_magmaWorm_burrowed_loop" : "Stop_magmaWorm_burrowed_loop", bones[0].gameObject);
				}
			}
		}

		public event BurrowExpectedCallback onPredictedBurrowDiscovered;

		public event BreachExpectedCallback onPredictedBreachDiscovered;

		private void Awake()
		{
			characterBody = GetComponent<CharacterBody>();
			characterDirection = GetComponent<CharacterDirection>();
			boneTransformationBuffer = new PositionRotationPair[bones.Length + 1];
			totalLength = 0f;
			for (int i = 0; i < segmentLengths.Length; i++)
			{
				totalLength += segmentLengths[i];
			}
			if (NetworkServer.active)
			{
				travelCallbacks = new List<TravelCallback>();
			}
			boneDisplacements = new UnityEngine.Vector3[bones.Length];
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				PopulateInitialKeyFrames();
				previousSurfaceTestEnd = newestKeyFrame.curve.Evaluate(1f);
			}
		}

		private void OnDestroy()
		{
			travelCallbacks = null;
			_playingBurrowSound = false;
		}

		private void BakeSegmentLengths()
		{
			segmentLengths = new float[bones.Length];
			UnityEngine.Vector3 vector = bones[0].position;
			for (int i = 1; i < bones.Length; i++)
			{
				UnityEngine.Vector3 position = bones[i].position;
				float magnitude = (vector - position).magnitude;
				segmentLengths[i - 1] = magnitude;
				vector = position;
			}
			segmentLengths[bones.Length - 1] = 2f;
		}

		[Server]
		private void PopulateInitialKeyFrames()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WormBodyPositions2::PopulateInitialKeyFrames()' called on client");
				return;
			}
			bool flag = enableSurfaceTests;
			enableSurfaceTests = false;
			UnityEngine.Vector3 vector = base.transform.position + UnityEngine.Vector3.down * spawnDepth;
			float synchronizedTimeStamp = GetSynchronizedTimeStamp();
			newestKeyFrame = new KeyFrame
			{
				curve = CubicBezier3.FromVelocities(vector + UnityEngine.Vector3.down * 2f, UnityEngine.Vector3.up, vector + UnityEngine.Vector3.down * 1f, UnityEngine.Vector3.down),
				time = synchronizedTimeStamp - 2f,
				length = 1f
			};
			AttemptToGenerateKeyFrame(synchronizedTimeStamp - 1f, vector + UnityEngine.Vector3.down, UnityEngine.Vector3.up);
			AttemptToGenerateKeyFrame(synchronizedTimeStamp, vector, UnityEngine.Vector3.up);
			headDistance = 0f;
			enableSurfaceTests = flag;
		}

		private UnityEngine.Vector3 EvaluatePositionAlongCurve(float positionDownBody)
		{
			float num = 0f;
			foreach (KeyFrame keyFrame in keyFrames)
			{
				float b = num;
				num += keyFrame.length;
				if (num >= positionDownBody)
				{
					float t = Mathf.InverseLerp(num, b, positionDownBody);
					CubicBezier3 curve = keyFrame.curve;
					return curve.Evaluate(t);
				}
			}
			if (keyFrames.Count > 0)
			{
				return keyFrames[keyFrames.Count - 1].curve.Evaluate(1f);
			}
			return UnityEngine.Vector3.zero;
		}

		private void UpdateBones()
		{
			float num = totalLength;
			boneTransformationBuffer[boneTransformationBuffer.Length - 1] = new PositionRotationPair
			{
				position = EvaluatePositionAlongCurve(headDistance + num),
				rotation = UnityEngine.Quaternion.identity
			};
			for (int num2 = boneTransformationBuffer.Length - 2; num2 >= 0; num2--)
			{
				num -= segmentLengths[num2];
				UnityEngine.Vector3 vector = EvaluatePositionAlongCurve(headDistance + num);
				UnityEngine.Quaternion rotation = Util.QuaternionSafeLookRotation(vector - boneTransformationBuffer[num2 + 1].position, UnityEngine.Vector3.up);
				boneTransformationBuffer[num2] = new PositionRotationPair
				{
					position = vector,
					rotation = rotation
				};
			}
			if (bones.Length == 0 || !bones[0])
			{
				return;
			}
			UnityEngine.Vector3 forward = bones[0].forward;
			for (int i = 0; i < bones.Length; i++)
			{
				Transform transform = bones[i];
				if ((bool)transform)
				{
					transform.position = boneTransformationBuffer[i].position + boneDisplacements[i];
					transform.forward = forward;
					transform.up = boneTransformationBuffer[i].rotation * -UnityEngine.Vector3.forward;
					forward = transform.forward;
				}
			}
		}

		public void AddKeyFrame(in KeyFrame newKeyFrame)
		{
			newestKeyFrame = newKeyFrame;
			keyFrames.Insert(0, newKeyFrame);
			keyFramesTotalLength += newKeyFrame.length;
			headDistance += newKeyFrame.length;
			bool flag = false;
			float num = keyFramesTotalLength;
			float num2 = totalLength + headDistance + 4f;
			while (keyFrames.Count > 0 && (num -= keyFrames[keyFrames.Count - 1].length) > num2)
			{
				keyFrames.RemoveAt(keyFrames.Count - 1);
				flag = true;
			}
			if (flag)
			{
				keyFramesTotalLength = 0f;
				foreach (KeyFrame keyFrame in keyFrames)
				{
					keyFramesTotalLength += keyFrame.length;
				}
			}
			if (NetworkServer.active)
			{
				CallRpcSendKeyFrame(newKeyFrame);
				if (enableSurfaceTests)
				{
					SurfaceTest(newKeyFrame.curve.p1, ref previousSurfaceTestEnd, newKeyFrame.time, OnPredictedBurrowDiscovered, OnPredictedBreachDiscovered);
				}
			}
		}

		[Server]
		public void AttemptToGenerateKeyFrame(float arrivalTime, UnityEngine.Vector3 position, UnityEngine.Vector3 velocity)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WormBodyPositions2::AttemptToGenerateKeyFrame(System.Single,UnityEngine.Vector3,UnityEngine.Vector3)' called on client");
				return;
			}
			KeyFrame keyFrame = newestKeyFrame;
			float num = arrivalTime - keyFrame.time;
			CubicBezier3 curve = CubicBezier3.FromVelocities(keyFrame.curve.p1, -keyFrame.curve.v1, position, -velocity * (num * 0.25f));
			float length = curve.ApproximateLength(50);
			KeyFrame keyFrame2 = default(KeyFrame);
			keyFrame2.curve = curve;
			keyFrame2.length = length;
			keyFrame2.time = arrivalTime;
			KeyFrame newKeyFrame = keyFrame2;
			if (newKeyFrame.length >= 0f)
			{
				AddKeyFrame(in newKeyFrame);
			}
		}

		[ClientRpc]
		private void RpcSendKeyFrame(KeyFrame newKeyFrame)
		{
			if (!NetworkServer.active)
			{
				AddKeyFrame(in newKeyFrame);
			}
		}

		private void Update()
		{
			UpdateBoneDisplacements(Time.deltaTime);
			UpdateHeadOffset();
			if (animateJaws)
			{
				UpdateJaws();
			}
		}

		private void UpdateJaws()
		{
			if ((bool)animator)
			{
				float value = Mathf.Clamp01(Util.Remap((bones[0].position - base.transform.position).magnitude, jawClosedDistance, jawOpenDistance, 0f, 1f));
				animator.SetFloat(jawMecanimCycleParameter, value, jawMecanimDampTime, Time.deltaTime);
			}
		}

		private void UpdateHeadOffset()
		{
			float num = headDistance;
			int num2 = keyFrames.Count - 1;
			float num3 = 0f;
			float synchronizedTimeStamp = GetSynchronizedTimeStamp();
			for (int i = 0; i < num2; i++)
			{
				float time = keyFrames[i + 1].time;
				float length = keyFrames[i].length;
				if (time < synchronizedTimeStamp)
				{
					num = num3 + length * Mathf.InverseLerp(keyFrames[i].time, time, synchronizedTimeStamp);
					break;
				}
				num3 += length;
			}
			OnTravel(headDistance - num);
		}

		private void OnTravel(float distance)
		{
			headDistance -= distance;
			UpdateBones();
		}

		private void OnPredictedBurrowDiscovered(float expectedTime, UnityEngine.Vector3 point, UnityEngine.Vector3 surfaceNormal)
		{
			AddTravelCallback(new TravelCallback
			{
				time = expectedTime,
				callback = delegate
				{
					OnEnterSurface(point, surfaceNormal);
				}
			});
			AddTravelCallback(new TravelCallback
			{
				time = expectedTime - 0.5f,
				callback = RpcPlaySurfaceImpactSound
			});
			this.onPredictedBurrowDiscovered?.Invoke(expectedTime, point, surfaceNormal);
		}

		private void OnPredictedBreachDiscovered(float expectedTime, UnityEngine.Vector3 point, UnityEngine.Vector3 surfaceNormal)
		{
			if ((bool)warningEffectPrefab)
			{
				EffectManager.SpawnEffect(warningEffectPrefab, new EffectData
				{
					origin = point,
					rotation = Util.QuaternionSafeLookRotation(surfaceNormal)
				}, transmit: true);
			}
			AddTravelCallback(new TravelCallback
			{
				time = expectedTime,
				callback = delegate
				{
					OnExitSurface(point, surfaceNormal);
				}
			});
			AddTravelCallback(new TravelCallback
			{
				time = expectedTime - 0.5f,
				callback = RpcPlaySurfaceImpactSound
			});
			this.onPredictedBreachDiscovered?.Invoke(expectedTime, point, surfaceNormal);
		}

		[Server]
		private static void SurfaceTest(UnityEngine.Vector3 currentPosition, ref UnityEngine.Vector3 previousPosition, float arrivalTime, BurrowExpectedCallback onPredictedBurrowDiscovered, BreachExpectedCallback onPredictedBreachDiscovered)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WormBodyPositions2::SurfaceTest(UnityEngine.Vector3,UnityEngine.Vector3&,System.Single,RoR2.WormBodyPositions2/BurrowExpectedCallback,RoR2.WormBodyPositions2/BreachExpectedCallback)' called on client");
				return;
			}
			UnityEngine.Vector3 vector = currentPosition - previousPosition;
			float magnitude = vector.magnitude;
			if (Physics.Raycast(previousPosition, vector, out var hitInfo, magnitude, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				onPredictedBurrowDiscovered?.Invoke(arrivalTime, hitInfo.point, hitInfo.normal);
			}
			if (Physics.Raycast(currentPosition, -vector, out hitInfo, magnitude, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
			{
				onPredictedBreachDiscovered?.Invoke(arrivalTime, hitInfo.point, hitInfo.normal);
			}
			previousPosition = currentPosition;
		}

		public void AddTravelCallback(TravelCallback newTravelCallback)
		{
			int index = travelCallbacks.Count;
			float time = newTravelCallback.time;
			for (int i = 0; i < travelCallbacks.Count; i++)
			{
				if (time < travelCallbacks[i].time)
				{
					index = i;
					break;
				}
			}
			travelCallbacks.Insert(index, newTravelCallback);
		}

		[ClientRpc]
		private void RpcPlaySurfaceImpactSound()
		{
		}

		[Server]
		private void OnEnterSurface(UnityEngine.Vector3 point, UnityEngine.Vector3 surfaceNormal)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WormBodyPositions2::OnEnterSurface(UnityEngine.Vector3,UnityEngine.Vector3)' called on client");
			}
			else
			{
				if (enterTriggerCooldownTimer > 0f)
				{
					return;
				}
				if (shouldTriggerDeathEffectOnNextImpact && Run.instance.fixedTime - deathTime >= EntityStates.MagmaWorm.DeathState.duration - 3f)
				{
					shouldTriggerDeathEffectOnNextImpact = false;
					return;
				}
				enterTriggerCooldownTimer = impactCooldownDuration;
				EffectManager.SpawnEffect(burrowEffectPrefab, new EffectData
				{
					origin = point,
					rotation = Util.QuaternionSafeLookRotation(surfaceNormal),
					scale = 1f
				}, transmit: true);
				if (shouldFireMeatballsOnImpact)
				{
					FireMeatballs(surfaceNormal, point + surfaceNormal * 3f, characterDirection.forward, meatballCount, meatballAngle, meatballForce);
				}
				if (shouldFireBlastAttackOnImpact)
				{
					FireImpactBlastAttack(point + surfaceNormal);
				}
			}
		}

		public void OnDeathStart()
		{
			deathTime = Run.instance.fixedTime;
			shouldTriggerDeathEffectOnNextImpact = true;
		}

		[Server]
		private void PerformDeath()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WormBodyPositions2::PerformDeath()' called on client");
				return;
			}
			for (int i = 0; i < bones.Length; i++)
			{
				if ((bool)bones[i])
				{
					EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/MagmaWormDeathDust"), new EffectData
					{
						origin = bones[i].position,
						rotation = UnityEngine.Random.rotation,
						scale = 1f
					}, transmit: true);
				}
			}
			UnityEngine.Object.Destroy(base.gameObject);
		}

		[Server]
		private void OnExitSurface(UnityEngine.Vector3 point, UnityEngine.Vector3 surfaceNormal)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.WormBodyPositions2::OnExitSurface(UnityEngine.Vector3,UnityEngine.Vector3)' called on client");
			}
			else if (!(exitTriggerCooldownTimer > 0f))
			{
				exitTriggerCooldownTimer = impactCooldownDuration;
				EffectManager.SpawnEffect(burrowEffectPrefab, new EffectData
				{
					origin = point,
					rotation = Util.QuaternionSafeLookRotation(surfaceNormal),
					scale = 1f
				}, transmit: true);
				if (shouldFireMeatballsOnImpact)
				{
					FireMeatballs(surfaceNormal, point + surfaceNormal * 3f, characterDirection.forward, meatballCount, meatballAngle, meatballForce);
				}
			}
		}

		private void FireMeatballs(UnityEngine.Vector3 impactNormal, UnityEngine.Vector3 impactPosition, UnityEngine.Vector3 forward, int meatballCount, float meatballAngle, float meatballForce)
		{
			float num = 360f / (float)meatballCount;
			UnityEngine.Vector3 normalized = UnityEngine.Vector3.ProjectOnPlane(forward, impactNormal).normalized;
			UnityEngine.Vector3 vector = UnityEngine.Vector3.RotateTowards(impactNormal, normalized, meatballAngle * (MathF.PI / 180f), float.PositiveInfinity);
			for (int i = 0; i < meatballCount; i++)
			{
				UnityEngine.Vector3 forward2 = UnityEngine.Quaternion.AngleAxis(num * (float)i, impactNormal) * vector;
				ProjectileManager.instance.FireProjectile(meatballProjectile, impactPosition, Util.QuaternionSafeLookRotation(forward2), base.gameObject, characterBody.damage * meatballDamageCoefficient, meatballForce, Util.CheckRoll(characterBody.crit, characterBody.master));
			}
		}

		private void FireImpactBlastAttack(UnityEngine.Vector3 impactPosition)
		{
			BlastAttack obj = new BlastAttack
			{
				baseDamage = characterBody.damage * blastAttackDamageCoefficient,
				procCoefficient = blastAttackProcCoefficient,
				baseForce = blastAttackForce,
				bonusForce = UnityEngine.Vector3.up * blastAttackBonusVerticalForce,
				crit = Util.CheckRoll(characterBody.crit, characterBody.master),
				radius = blastAttackRadius,
				damageType = DamageType.IgniteOnHit,
				falloffModel = BlastAttack.FalloffModel.SweetSpot,
				attacker = base.gameObject
			};
			obj.teamIndex = TeamComponent.GetObjectTeam(obj.attacker);
			obj.position = impactPosition;
			obj.attackerFiltering = AttackerFiltering.NeverHitSelf;
			obj.Fire();
			if (NetworkServer.active)
			{
				EffectManager.SpawnEffect(blastAttackEffect, new EffectData
				{
					origin = impactPosition,
					scale = blastAttackRadius
				}, transmit: true);
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				enterTriggerCooldownTimer -= Time.fixedDeltaTime;
				exitTriggerCooldownTimer -= Time.fixedDeltaTime;
				float synchronizedTimeStamp = GetSynchronizedTimeStamp();
				while (travelCallbacks.Count > 0 && travelCallbacks[0].time <= synchronizedTimeStamp)
				{
					TravelCallback travelCallback = travelCallbacks[0];
					travelCallbacks.RemoveAt(0);
					travelCallback.callback();
				}
			}
			if (bones.Length != 0 && (bool)bones[0] && (bool)bones[0].transform && (bool)base.transform)
			{
				bool flag = bones[0].transform.position.y - base.transform.position.y < undergroundTestYOffset;
				playingBurrowSound = flag;
			}
		}

		private void DrawKeyFrame(KeyFrame keyFrame)
		{
			Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.green, UnityEngine.Color.black, 0.5f);
			Gizmos.DrawRay(keyFrame.curve.p0, keyFrame.curve.v0);
			Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.red, UnityEngine.Color.black, 0.5f);
			Gizmos.DrawRay(keyFrame.curve.p1, keyFrame.curve.v1);
			for (int i = 1; i <= 20; i++)
			{
				float num = (float)i * 0.05f;
				Gizmos.color = UnityEngine.Color.Lerp(UnityEngine.Color.red, UnityEngine.Color.green, num);
				UnityEngine.Vector3 vector = keyFrame.curve.Evaluate(num - 0.05f);
				UnityEngine.Vector3 vector2 = keyFrame.curve.Evaluate(num);
				Gizmos.DrawRay(vector, vector2 - vector);
			}
		}

		private void OnDrawGizmos()
		{
			foreach (KeyFrame keyFrame in keyFrames)
			{
				DrawKeyFrame(keyFrame);
			}
			for (int i = 0; i < boneTransformationBuffer.Length; i++)
			{
				Gizmos.matrix = UnityEngine.Matrix4x4.TRS(boneTransformationBuffer[i].position, boneTransformationBuffer[i].rotation, UnityEngine.Vector3.one * 3f);
				Gizmos.DrawRay(-UnityEngine.Vector3.forward, UnityEngine.Vector3.forward * 2f);
				Gizmos.DrawRay(-UnityEngine.Vector3.right, UnityEngine.Vector3.right * 2f);
				Gizmos.DrawRay(-UnityEngine.Vector3.up, UnityEngine.Vector3.up * 2f);
			}
		}

		public void OnTeleport(UnityEngine.Vector3 oldPosition, UnityEngine.Vector3 newPosition)
		{
			UnityEngine.Vector3 vector = newPosition - oldPosition;
			for (int i = 0; i < keyFrames.Count; i++)
			{
				KeyFrame value = keyFrames[i];
				CubicBezier3 curve = value.curve;
				curve.a += vector;
				curve.b += vector;
				curve.c += vector;
				curve.d += vector;
				value.curve = curve;
				keyFrames[i] = value;
			}
			previousSurfaceTestEnd += vector;
		}

		private int FindNearestBone(UnityEngine.Vector3 worldPosition)
		{
			int result = -1;
			float num = float.PositiveInfinity;
			for (int i = 0; i < bones.Length; i++)
			{
				float sqrMagnitude = (bones[i].transform.position - worldPosition).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					result = i;
				}
			}
			return result;
		}

		private void UpdateBoneDisplacements(float deltaTime)
		{
			int i = 0;
			for (int num = boneDisplacements.Length; i < num; i++)
			{
				boneDisplacements[i] = UnityEngine.Vector3.MoveTowards(boneDisplacements[i], UnityEngine.Vector3.zero, painDisplacementRecoverySpeed * deltaTime);
			}
		}

		void IPainAnimationHandler.HandlePain(float damage, UnityEngine.Vector3 damagePosition)
		{
			int num = FindNearestBone(damagePosition);
			if (num != -1)
			{
				boneDisplacements[num] = UnityEngine.Random.onUnitSphere * maxPainDisplacementMagnitude;
			}
		}

		public float GetSynchronizedTimeStamp()
		{
			return Run.instance.time;
		}

		private static void WriteKeyFrame(NetworkWriter writer, KeyFrame keyFrame)
		{
			writer.Write(keyFrame.curve.a);
			writer.Write(keyFrame.curve.b);
			writer.Write(keyFrame.curve.c);
			writer.Write(keyFrame.curve.d);
			writer.Write(keyFrame.length);
			writer.Write(keyFrame.time);
		}

		private static KeyFrame ReadKeyFrame(NetworkReader reader)
		{
			KeyFrame result = default(KeyFrame);
			result.curve.a = reader.ReadVector3();
			result.curve.b = reader.ReadVector3();
			result.curve.c = reader.ReadVector3();
			result.curve.d = reader.ReadVector3();
			result.length = reader.ReadSingle();
			result.time = reader.ReadSingle();
			return result;
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				writer.Write((ushort)keyFrames.Count);
				for (int i = 0; i < keyFrames.Count; i++)
				{
					WriteKeyFrame(writer, keyFrames[i]);
				}
			}
			if (!initialState)
			{
				return num != 0;
			}
			return false;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				keyFrames.Clear();
				int num = reader.ReadUInt16();
				for (int i = 0; i < num; i++)
				{
					keyFrames.Add(ReadKeyFrame(reader));
				}
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcSendKeyFrame(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcSendKeyFrame called on server.");
			}
			else
			{
				((WormBodyPositions2)obj).RpcSendKeyFrame(GeneratedNetworkCode._ReadKeyFrame_WormBodyPositions2(reader));
			}
		}

		protected static void InvokeRpcRpcPlaySurfaceImpactSound(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcPlaySurfaceImpactSound called on server.");
			}
			else
			{
				((WormBodyPositions2)obj).RpcPlaySurfaceImpactSound();
			}
		}

		public void CallRpcSendKeyFrame(KeyFrame newKeyFrame)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcSendKeyFrame called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcSendKeyFrame);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteKeyFrame_WormBodyPositions2(networkWriter, newKeyFrame);
			SendRPCInternal(networkWriter, 0, "RpcSendKeyFrame");
		}

		public void CallRpcPlaySurfaceImpactSound()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcPlaySurfaceImpactSound called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcPlaySurfaceImpactSound);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcPlaySurfaceImpactSound");
		}

		static WormBodyPositions2()
		{
			kRpcRpcSendKeyFrame = 874152969;
			NetworkBehaviour.RegisterRpcDelegate(typeof(WormBodyPositions2), kRpcRpcSendKeyFrame, InvokeRpcRpcSendKeyFrame);
			kRpcRpcPlaySurfaceImpactSound = 2010133795;
			NetworkBehaviour.RegisterRpcDelegate(typeof(WormBodyPositions2), kRpcRpcPlaySurfaceImpactSound, InvokeRpcRpcPlaySurfaceImpactSound);
			NetworkCRC.RegisterBehaviour("WormBodyPositions2", 0);
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(WormBodyPositions2))]
	public class WormBodyPositionsDriver : MonoBehaviour
	{
		public Transform referenceTransform;

		public Transform chasePositionVisualizer;

		public float maxTurnSpeed = 180f;

		public float verticalTurnSquashFactor = 2f;

		public float ySpringConstant = 100f;

		public float yDamperConstant = 1f;

		public bool allowShoving;

		public float yShoveVelocityThreshold;

		public float yShovePositionThreshold;

		public float yShoveForce;

		public float turnRateCoefficientAboveGround;

		public float wormForceCoefficientAboveGround;

		public float keyFrameGenerationInterval = 0.25f;

		public float maxBreachSpeed = 40f;

		private WormBodyPositions2 wormBodyPositions;

		private CharacterDirection characterDirection;

		private UnityEngine.Vector3 chaserPreviousVelocity;

		private bool chaserIsUnderground;

		private float keyFrameGenerationTimer;

		public UnityEngine.Vector3 chaserVelocity { get; set; }

		public UnityEngine.Vector3 chaserPosition { get; private set; }

		private void Awake()
		{
			wormBodyPositions = GetComponent<WormBodyPositions2>();
			characterDirection = GetComponent<CharacterDirection>();
		}

		private void OnEnable()
		{
			wormBodyPositions.onPredictedBreachDiscovered += OnPredictedBreachDiscovered;
		}

		private void OnDisable()
		{
			wormBodyPositions.onPredictedBreachDiscovered -= OnPredictedBreachDiscovered;
		}

		private void Start()
		{
			if (NetworkServer.active)
			{
				chaserPosition = base.transform.position;
				chaserVelocity = characterDirection.forward;
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		public void OnTeleport(UnityEngine.Vector3 oldPosition, UnityEngine.Vector3 newPosition)
		{
			UnityEngine.Vector3 vector = newPosition - oldPosition;
			chaserPosition += vector;
		}

		private void OnPredictedBreachDiscovered(float expectedTime, UnityEngine.Vector3 hitPosition, UnityEngine.Vector3 hitNormal)
		{
			float magnitude = chaserVelocity.magnitude;
			if (magnitude > maxBreachSpeed)
			{
				chaserVelocity /= magnitude / maxBreachSpeed;
			}
		}

		private void FixedUpdateServer()
		{
			UnityEngine.Vector3 position = referenceTransform.position;
			float speedMultiplier = wormBodyPositions.speedMultiplier;
			UnityEngine.Vector3 normalized = (position - chaserPosition).normalized;
			float num = (chaserIsUnderground ? maxTurnSpeed : (maxTurnSpeed * turnRateCoefficientAboveGround)) * (MathF.PI / 180f);
			UnityEngine.Vector3 current = new UnityEngine.Vector3(chaserVelocity.x, 0f, chaserVelocity.z);
			UnityEngine.Vector3 vector = new UnityEngine.Vector3(normalized.x, 0f, normalized.z);
			current = UnityEngine.Vector3.RotateTowards(current, vector * speedMultiplier, num * Time.fixedDeltaTime, float.PositiveInfinity).normalized * speedMultiplier;
			float num2 = position.y - chaserPosition.y;
			float num3 = (0f - chaserVelocity.y) * yDamperConstant;
			float num4 = num2 * ySpringConstant;
			UnityEngine.Vector3 vec;
			if (allowShoving && Mathf.Abs(chaserVelocity.y) < yShoveVelocityThreshold && num2 > yShovePositionThreshold)
			{
				vec = chaserVelocity;
				chaserVelocity = vec.XAZ(chaserVelocity.y + yShoveForce * Time.fixedDeltaTime);
			}
			if (!chaserIsUnderground)
			{
				num4 *= wormForceCoefficientAboveGround;
				num3 *= wormForceCoefficientAboveGround;
			}
			vec = chaserVelocity;
			chaserVelocity = vec.XAZ(chaserVelocity.y + (num4 + num3) * Time.fixedDeltaTime);
			chaserVelocity += Physics.gravity * Time.fixedDeltaTime;
			chaserVelocity = new UnityEngine.Vector3(current.x, chaserVelocity.y, current.z);
			chaserPosition += chaserVelocity * Time.fixedDeltaTime;
			chasePositionVisualizer.position = chaserPosition;
			chaserIsUnderground = 0f - num2 < wormBodyPositions.undergroundTestYOffset;
			keyFrameGenerationTimer -= Time.deltaTime;
			if (keyFrameGenerationTimer <= 0f)
			{
				keyFrameGenerationTimer = keyFrameGenerationInterval;
				wormBodyPositions.AttemptToGenerateKeyFrame(wormBodyPositions.GetSynchronizedTimeStamp() + wormBodyPositions.followDelay, chaserPosition, chaserVelocity);
			}
		}
	}
	public class ZiplineController : NetworkBehaviour
	{
		[SyncVar(hook = "SetPointAPosition")]
		private UnityEngine.Vector3 pointAPosition;

		[SyncVar(hook = "SetPointBPosition")]
		private UnityEngine.Vector3 pointBPosition;

		[SerializeField]
		private Transform pointATransform;

		[SerializeField]
		private Transform pointBTransform;

		public GameObject ziplineVehiclePrefab;

		private ZiplineVehicle currentZiplineA;

		private ZiplineVehicle currentZiplineB;

		public UnityEngine.Vector3 NetworkpointAPosition
		{
			get
			{
				return pointAPosition;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetPointAPosition(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref pointAPosition, 1u);
			}
		}

		public UnityEngine.Vector3 NetworkpointBPosition
		{
			get
			{
				return pointBPosition;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetPointBPosition(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref pointBPosition, 2u);
			}
		}

		public void SetPointAPosition(UnityEngine.Vector3 position)
		{
			NetworkpointAPosition = position;
			pointATransform.position = pointAPosition;
			pointATransform.LookAt(pointBTransform);
			pointBTransform.LookAt(pointATransform);
		}

		public void SetPointBPosition(UnityEngine.Vector3 position)
		{
			NetworkpointBPosition = position;
			pointBTransform.position = pointBPosition;
			pointATransform.LookAt(pointBTransform);
			pointBTransform.LookAt(pointATransform);
		}

		private void RebuildZiplineVehicle(ref ZiplineVehicle ziplineVehicle, UnityEngine.Vector3 startPos, UnityEngine.Vector3 endPos)
		{
			if ((bool)ziplineVehicle && ziplineVehicle.vehicleSeat.hasPassenger)
			{
				ziplineVehicle = null;
			}
			if (!ziplineVehicle)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(ziplineVehiclePrefab, startPos, UnityEngine.Quaternion.identity);
				ziplineVehicle = gameObject.GetComponent<ZiplineVehicle>();
				ziplineVehicle.NetworkendPoint = endPos;
				NetworkServer.Spawn(gameObject);
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				RebuildZiplineVehicle(ref currentZiplineA, pointAPosition, pointBPosition);
				RebuildZiplineVehicle(ref currentZiplineB, pointBPosition, pointAPosition);
			}
		}

		private void OnDestroy()
		{
			if (NetworkServer.active)
			{
				if ((bool)currentZiplineA)
				{
					UnityEngine.Object.Destroy(currentZiplineA.gameObject);
				}
				if ((bool)currentZiplineB)
				{
					UnityEngine.Object.Destroy(currentZiplineB.gameObject);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(pointAPosition);
				writer.Write(pointBPosition);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(pointAPosition);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(pointBPosition);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				pointAPosition = reader.ReadVector3();
				pointBPosition = reader.ReadVector3();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetPointAPosition(reader.ReadVector3());
			}
			if (((uint)num & 2u) != 0)
			{
				SetPointBPosition(reader.ReadVector3());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(VehicleSeat))]
	[RequireComponent(typeof(Rigidbody))]
	public class ZiplineVehicle : NetworkBehaviour
	{
		public float maxSpeed = 30f;

		public float acceleration = 2f;

		private Rigidbody rigidbody;

		private UnityEngine.Vector3 startPoint;

		[SyncVar]
		public UnityEngine.Vector3 endPoint;

		private UnityEngine.Vector3 travelDirection;

		private GameObject currentPassenger;

		private Run.FixedTimeStamp startTravelFixedTime = Run.FixedTimeStamp.positiveInfinity;

		private Run.TimeStamp startTravelTime = Run.TimeStamp.positiveInfinity;

		public VehicleSeat vehicleSeat { get; private set; }

		public UnityEngine.Vector3 NetworkendPoint
		{
			get
			{
				return endPoint;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref endPoint, 1u);
			}
		}

		private void Awake()
		{
			vehicleSeat = GetComponent<VehicleSeat>();
			rigidbody = GetComponent<Rigidbody>();
			vehicleSeat.onPassengerEnter += OnPassengerEnter;
			vehicleSeat.onPassengerExit += OnPassengerExit;
		}

		private void OnPassengerEnter(GameObject passenger)
		{
			currentPassenger = passenger;
			startPoint = base.transform.position;
			startTravelFixedTime = Run.FixedTimeStamp.now;
			startTravelTime = Run.TimeStamp.now;
		}

		private void SetTravelDistance(float time)
		{
			UnityEngine.Vector3 vector = endPoint - startPoint;
			float magnitude = vector.magnitude;
			UnityEngine.Vector3 vector2 = vector / magnitude;
			float num = HGPhysics.CalculateDistance(0f, acceleration, time);
			bool flag = false;
			if (num > magnitude)
			{
				num = magnitude;
				flag = true;
			}
			rigidbody.MovePosition(startPoint + vector2 * num);
			rigidbody.velocity = vector2 * (acceleration * time);
			if (NetworkServer.active && flag)
			{
				vehicleSeat.EjectPassenger(currentPassenger);
			}
		}

		private void Update()
		{
			_ = startTravelTime.hasPassed;
		}

		private void FixedUpdate()
		{
			if (startTravelFixedTime.hasPassed)
			{
				SetTravelDistance(startTravelFixedTime.timeSince);
			}
			if (!NetworkServer.active || !currentPassenger)
			{
				return;
			}
			UnityEngine.Vector3 normalized = (endPoint - base.transform.position).normalized;
			if (UnityEngine.Vector3.Dot(normalized, travelDirection) < 0f)
			{
				vehicleSeat.EjectPassenger(currentPassenger);
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			UnityEngine.Vector3 velocity = rigidbody.velocity;
			velocity += travelDirection * (acceleration * fixedDeltaTime);
			float sqrMagnitude = velocity.sqrMagnitude;
			if (sqrMagnitude > maxSpeed * maxSpeed)
			{
				float num = Mathf.Sqrt(sqrMagnitude);
				velocity *= maxSpeed / num;
			}
			rigidbody.velocity = velocity;
			travelDirection = normalized;
		}

		private void OnPassengerExit(GameObject passenger)
		{
			currentPassenger = null;
			vehicleSeat.enabled = false;
			if (NetworkServer.active)
			{
				base.gameObject.AddComponent<DestroyOnTimer>().duration = 0.1f;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(endPoint);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(endPoint);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				endPoint = reader.ReadVector3();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				endPoint = reader.ReadVector3();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class GameCompletionStatsHelper
	{
		private HashSet<UnlockableDef> unlockablesForGameCompletion = new HashSet<UnlockableDef>();

		private HashSet<AchievementDef> achievementsWithoutUnlockables = new HashSet<AchievementDef>();

		private HashSet<UnlockableDef> unlockablesWithoutAchievements = new HashSet<UnlockableDef>();

		private HashSet<PickupDef> encounterablePickups = new HashSet<PickupDef>();

		private int completableTotal;

		public GameCompletionStatsHelper()
		{
			HashSet<UnlockableDef> unlockablesFromAchievements = new HashSet<UnlockableDef>();
			foreach (SurvivorDef allSurvivorDef in SurvivorCatalog.allSurvivorDefs)
			{
				AddSurvivor(allSurvivorDef);
				void AddSurvivor(SurvivorDef survivorDef)
				{
					AddUnlockable(survivorDef.unlockableDef);
					BodyIndex bodyIndexFromSurvivorIndex = SurvivorCatalog.GetBodyIndexFromSurvivorIndex(survivorDef.survivorIndex);
					GenericSkill[] bodyPrefabSkillSlots = BodyCatalog.GetBodyPrefabSkillSlots(bodyIndexFromSurvivorIndex);
					if (bodyPrefabSkillSlots != null)
					{
						GenericSkill[] array = bodyPrefabSkillSlots;
						for (int i = 0; i < array.Length; i++)
						{
							SkillFamily skillFamily = array[i].skillFamily;
							if ((bool)skillFamily)
							{
								SkillFamily.Variant[] variants = skillFamily.variants;
								for (int j = 0; j < variants.Length; j++)
								{
									SkillFamily.Variant variant = variants[j];
									AddUnlockable(variant.unlockableDef);
								}
							}
						}
					}
					SkinDef[] bodySkins = BodyCatalog.GetBodySkins(bodyIndexFromSurvivorIndex);
					foreach (SkinDef skinDef in bodySkins)
					{
						AddUnlockable(skinDef.unlockableDef);
					}
					bool AddUnlockable(UnlockableDef unlockableDef)
					{
						if (unlockableDef == null)
						{
							return false;
						}
						unlockablesForGameCompletion.Add(unlockableDef);
						return true;
					}
				}
			}
			foreach (CharacterBody allBodyPrefabBodyBodyComponent in BodyCatalog.allBodyPrefabBodyBodyComponents)
			{
				AddMonster(allBodyPrefabBodyBodyComponent);
				void AddMonster(CharacterBody characterBody)
				{
					_003C_002Ector_003Eg__AddUnlockable_007C5_0(characterBody.GetComponent<DeathRewards>()?.logUnlockableDef);
				}
			}
			foreach (AchievementDef allAchievementDef in AchievementManager.allAchievementDefs)
			{
				AddAchievement(allAchievementDef);
			}
			foreach (PickupDef allPickup in PickupCatalog.allPickups)
			{
				AddPickup(allPickup);
				void AddPickup(PickupDef pickupDef)
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
					EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(pickupDef.equipmentIndex);
					if (((object)itemDef != null && itemDef.inDroppableTier) || ((object)equipmentDef != null && equipmentDef.canDrop))
					{
						encounterablePickups.Add(pickupDef);
					}
				}
			}
			unlockablesWithoutAchievements.UnionWith(unlockablesForGameCompletion);
			unlockablesWithoutAchievements.ExceptWith(unlockablesFromAchievements);
			completableTotal = 0;
			completableTotal += unlockablesForGameCompletion.Count;
			completableTotal += achievementsWithoutUnlockables.Count;
			completableTotal += encounterablePickups.Count;
			completableTotal += SurvivorCatalog.survivorCount * 2;
			void AddAchievement(AchievementDef achievementDef)
			{
				UnlockableDef unlockableDef2 = UnlockableCatalog.GetUnlockableDef(achievementDef.unlockableRewardIdentifier);
				if (!_003C_002Ector_003Eg__AddUnlockable_007C5_0(unlockableDef2))
				{
					achievementsWithoutUnlockables.Add(achievementDef);
				}
				else
				{
					unlockablesFromAchievements.Add(unlockableDef2);
				}
			}
		}

		public IntFraction GetTotalCompletion(UserProfile userProfile)
		{
			IntFraction result = new IntFraction(0, 0);
			AddResult(GetUnlockableCompletion(userProfile));
			AddResult(GetAchievementWithoutUnlockableCompletion(userProfile));
			AddResult(GetPickupEncounterCompletion(userProfile));
			AddResult(GetSurvivorPickCompletion(userProfile));
			AddResult(GetSurvivorWinCompletion(userProfile));
			return result;
			void AddResult(IntFraction incoming)
			{
				result = new IntFraction(result.numerator + incoming.numerator, result.denominator + incoming.denominator);
			}
		}

		public IntFraction GetUnlockableCompletion(UserProfile userProfile)
		{
			int num = 0;
			foreach (UnlockableDef item in unlockablesForGameCompletion)
			{
				if (userProfile.HasUnlockable(item))
				{
					num++;
				}
			}
			return new IntFraction(num, unlockablesForGameCompletion.Count);
		}

		public IntFraction GetCollectibleCompletion(UserProfile userProfile)
		{
			int num = 0;
			foreach (UnlockableDef unlockablesWithoutAchievement in unlockablesWithoutAchievements)
			{
				if (userProfile.HasUnlockable(unlockablesWithoutAchievement))
				{
					num++;
				}
			}
			return new IntFraction(num, unlockablesWithoutAchievements.Count);
		}

		public IntFraction GetAchievementCompletion(UserProfile userProfile)
		{
			int num = 0;
			foreach (AchievementDef allAchievementDef in AchievementManager.allAchievementDefs)
			{
				if (userProfile.HasAchievement(allAchievementDef.identifier))
				{
					num++;
				}
			}
			return new IntFraction(num, AchievementManager.achievementCount);
		}

		private IntFraction GetAchievementWithoutUnlockableCompletion(UserProfile userProfile)
		{
			int num = 0;
			foreach (AchievementDef achievementsWithoutUnlockable in achievementsWithoutUnlockables)
			{
				if (userProfile.HasAchievement(achievementsWithoutUnlockable.identifier))
				{
					num++;
				}
			}
			return new IntFraction(num, achievementsWithoutUnlockables.Count);
		}

		public IntFraction GetPickupEncounterCompletion(UserProfile userProfile)
		{
			int num = 0;
			foreach (PickupDef allPickup in PickupCatalog.allPickups)
			{
				if (encounterablePickups.Contains(allPickup) && userProfile.HasDiscoveredPickup(allPickup.pickupIndex))
				{
					num++;
				}
			}
			return new IntFraction(num, encounterablePickups.Count);
		}

		public IntFraction GetSurvivorPickCompletion(UserProfile userProfile)
		{
			return GetSurvivorULongStatCompletion(userProfile, PerBodyStatDef.timesPicked, ignoreHidden: true);
		}

		public IntFraction GetSurvivorWinCompletion(UserProfile userProfile)
		{
			return GetSurvivorULongStatCompletion(userProfile, PerBodyStatDef.totalWins, ignoreHidden: true);
		}

		private IntFraction GetSurvivorULongStatCompletion(UserProfile userProfile, PerBodyStatDef perBodyStatDef, bool ignoreHidden)
		{
			int num = 0;
			int num2 = 0;
			foreach (SurvivorDef allSurvivorDef in SurvivorCatalog.allSurvivorDefs)
			{
				if (!ignoreHidden || !allSurvivorDef.hidden)
				{
					num2++;
					string bodyName = BodyCatalog.GetBodyName(SurvivorCatalog.GetBodyIndexFromSurvivorIndex(allSurvivorDef.survivorIndex));
					if (userProfile.statSheet.GetStatValueULong(perBodyStatDef, bodyName) != 0)
					{
						num++;
					}
				}
			}
			return new IntFraction(num, num2);
		}
	}
	public enum GameModeIndex
	{
		Invalid = -1
	}
	public static class GameModeCatalog
	{
		private static readonly Dictionary<string, int> nameToIndex = new Dictionary<string, int>();

		private static Run[] indexToPrefabComponents = Array.Empty<Run>();

		private static string[] indexToName = Array.Empty<string>();

		private static readonly Dictionary<string, Run> nameToPrefabComponents = new Dictionary<string, Run>();

		public static ResourceAvailability availability;

		public static int gameModeCount => indexToPrefabComponents.Length;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<GameObject>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.GameModeCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.gameModePrefabs);
			}
			remove
			{
			}
		}

		[SystemInitializer(new Type[] { typeof(RuleCatalog) })]
		private static void LoadGameModes()
		{
			SetGameModes(ContentManager.gameModePrefabs.Select((GameObject v) => v.GetComponent<Run>()).ToArray());
			availability.MakeAvailable();
		}

		private static void SetGameModes(Run[] newGameModePrefabComponents)
		{
			Run[] array = indexToPrefabComponents;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].gameModeIndex = GameModeIndex.Invalid;
			}
			ArrayUtils.CloneTo(newGameModePrefabComponents, ref indexToPrefabComponents);
			Array.Sort(newGameModePrefabComponents, (Run a, Run b) => string.CompareOrdinal(a.name, b.name));
			nameToIndex.Clear();
			nameToPrefabComponents.Clear();
			Array.Resize(ref indexToName, indexToPrefabComponents.Length);
			int j = 0;
			for (int num = indexToPrefabComponents.Length; j < num; j++)
			{
				Run run = indexToPrefabComponents[j];
				string name = run.gameObject.name;
				string key = name + "(Clone)";
				nameToIndex.Add(name, j);
				nameToIndex.Add(key, j);
				nameToPrefabComponents.Add(name, run);
				nameToPrefabComponents.Add(key, run);
				run.gameModeIndex = (GameModeIndex)j;
				indexToName[j] = name;
			}
		}

		[CanBeNull]
		public static Run FindGameModePrefabComponent([NotNull] string name)
		{
			nameToPrefabComponents.TryGetValue(name, out var value);
			return value;
		}

		[CanBeNull]
		public static Run GetGameModePrefabComponent(GameModeIndex index)
		{
			return ArrayUtils.GetSafe(indexToPrefabComponents, (int)index);
		}

		public static GameModeIndex FindGameModeIndex([NotNull] string name)
		{
			if (nameToIndex.TryGetValue(name, out var value))
			{
				return (GameModeIndex)value;
			}
			return GameModeIndex.Invalid;
		}

		[CanBeNull]
		public static string GetGameModeName(GameModeIndex index)
		{
			return ArrayUtils.GetSafe(indexToName, (int)index);
		}
	}
	public enum GameResultType
	{
		Lost,
		Won,
		Unknown
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct GenericStaticEnumerable<T, TEnumerator> : IEnumerable<T>, IEnumerable where TEnumerator : struct, IEnumerator<T>
	{
		private static readonly TEnumerator defaultValue;

		static GenericStaticEnumerable()
		{
			defaultValue = default(TEnumerator);
			defaultValue.Reset();
		}

		public TEnumerator GetEnumerator()
		{
			return defaultValue;
		}

		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			return defaultValue;
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return defaultValue;
		}
	}
	public class GeodeController : NetworkBehaviour, IInteractable, IDisplayNameProvider
	{
		[SyncVar]
		public string displayNameToken = "GEODE_NAME";

		[SyncVar]
		public string contextToken = "GEODE_CONTEXT";

		public bool ShouldDropReward = true;

		public bool ShouldRegenerate;

		[SerializeField]
		private EntityStateMachine stateMachine;

		[SyncVar]
		private bool available = true;

		public Interactor lastInteractor;

		[SyncVar]
		public float geodeBuffRadius = 12f;

		public float barrierToHealthPercentage;

		[SerializeField]
		private bool isSecretMissionGeode;

		[SerializeField]
		private GeodeSecretMissionController geodeSecretMissionController;

		public bool shouldProximityHighlight = true;

		public float idleVFXRegenerationTimer;

		public float printTime;

		public float startingPrintHeight;

		public float maxPrintHeight;

		public AnimationCurve printCurve;

		public string NetworkdisplayNameToken
		{
			get
			{
				return displayNameToken;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref displayNameToken, 1u);
			}
		}

		public string NetworkcontextToken
		{
			get
			{
				return contextToken;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref contextToken, 2u);
			}
		}

		public bool Networkavailable
		{
			get
			{
				return available;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref available, 4u);
			}
		}

		public float NetworkgeodeBuffRadius
		{
			get
			{
				return geodeBuffRadius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref geodeBuffRadius, 8u);
			}
		}

		public void OnInteractionBegin(Interactor activator)
		{
			SetAvailable(activeState: false);
			lastInteractor = activator;
			if (geodeSecretMissionController != null && isSecretMissionGeode)
			{
				geodeSecretMissionController.AdvanceGeodeSecretMission();
			}
			stateMachine.SetNextStateToMain();
		}

		[Server]
		public void SetAvailable(bool activeState)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.GeodeController::SetAvailable(System.Boolean)' called on client");
			}
			else
			{
				Networkavailable = activeState;
			}
		}

		public string GetContextString(Interactor activator)
		{
			return Language.GetString(contextToken);
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (!available)
			{
				return Interactability.Disabled;
			}
			if (!available)
			{
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Available;
		}

		public string GetDisplayName()
		{
			return Language.GetString(displayNameToken);
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public void OnEnable()
		{
			InstanceTracker.Add(this);
		}

		public void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public bool ShouldShowOnScanner()
		{
			return !available;
		}

		public bool ShouldProximityHighlight()
		{
			return shouldProximityHighlight;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(displayNameToken);
				writer.Write(contextToken);
				writer.Write(available);
				writer.Write(geodeBuffRadius);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(displayNameToken);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(contextToken);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(available);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(geodeBuffRadius);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				displayNameToken = reader.ReadString();
				contextToken = reader.ReadString();
				available = reader.ReadBoolean();
				geodeBuffRadius = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				displayNameToken = reader.ReadString();
			}
			if (((uint)num & 2u) != 0)
			{
				contextToken = reader.ReadString();
			}
			if (((uint)num & 4u) != 0)
			{
				available = reader.ReadBoolean();
			}
			if (((uint)num & 8u) != 0)
			{
				geodeBuffRadius = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public static class GetComponentsCache<T>
	{
		private static readonly Stack<List<T>> buffers = new Stack<List<T>>();

		public static void ReturnBuffer(List<T> buffer)
		{
			buffer.Clear();
			buffers.Push(buffer);
		}

		private static List<T> RequestBuffer()
		{
			if (buffers.Count == 0)
			{
				return new List<T>();
			}
			return buffers.Pop();
		}

		public static List<T> GetGameObjectComponents(GameObject gameObject)
		{
			List<T> list = RequestBuffer();
			gameObject.GetComponents(list);
			return list;
		}

		public static List<T> GetGameObjectComponentsInChildren(GameObject gameObject, bool includeInactive = false)
		{
			List<T> list = RequestBuffer();
			gameObject.GetComponentsInChildren(includeInactive, list);
			return list;
		}
	}
	public static class Glyphs
	{
		private struct GlyphKey : IEquatable<GlyphKey>
		{
			public readonly string deviceName;

			public readonly int elementId;

			public GlyphKey(string deviceName, int elementId)
			{
				this.deviceName = deviceName;
				this.elementId = elementId;
			}

			public bool Equals(GlyphKey other)
			{
				if (string.Equals(deviceName, other.deviceName))
				{
					return elementId == other.elementId;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is GlyphKey)
				{
					return Equals((GlyphKey)obj);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((deviceName != null) ? deviceName.GetHashCode() : 0) * 397) ^ elementId;
			}
		}

		private static readonly Dictionary<GlyphKey, string> glyphMap;

		private static Controller lastConnectedJoystick;

		private static readonly Dictionary<string, string> keyboardRawNameToGlyphName;

		private static readonly Dictionary<string, string> mouseElementRenameMap;

		private static readonly List<ActionElementMap> resultsList;

		private static void AddGlyph(string controllerName, int elementIndex, string assetName, string glyphName)
		{
			glyphMap[new GlyphKey(controllerName, elementIndex)] = string.Format(CultureInfo.InvariantCulture, "<sprite=\"{0}\" name=\"{1}\">", assetName, glyphName);
		}

		private static void RegisterXboxController(string controllerName)
		{
			AddGlyph(controllerName, 0, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_4");
			AddGlyph(controllerName, 1, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_4");
			AddGlyph(controllerName, 2, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_8");
			AddGlyph(controllerName, 3, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_8");
			AddGlyph(controllerName, 4, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_5");
			AddGlyph(controllerName, 5, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_9");
			AddGlyph(controllerName, 10, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_2");
			AddGlyph(controllerName, 11, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_6");
			AddGlyph(controllerName, 6, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_0");
			AddGlyph(controllerName, 7, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_1");
			AddGlyph(controllerName, 8, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_7");
			AddGlyph(controllerName, 9, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_11");
			AddGlyph(controllerName, 12, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_10");
			AddGlyph(controllerName, 13, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_3");
			AddGlyph(controllerName, 14, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_4");
			AddGlyph(controllerName, 15, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_8");
			AddGlyph(controllerName, 19, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_12");
			AddGlyph(controllerName, 17, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_13");
			AddGlyph(controllerName, 16, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_14");
			AddGlyph(controllerName, 18, "tmpsprXboxOneGlyphs", "texXBoxOneGlyphs_15");
		}

		private static void RegisterDS4Controller(string controllerName)
		{
			AddGlyph(controllerName, 0, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_25");
			AddGlyph(controllerName, 1, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_25");
			AddGlyph(controllerName, 2, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_24");
			AddGlyph(controllerName, 3, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_24");
			AddGlyph(controllerName, 4, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_6");
			AddGlyph(controllerName, 5, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_7");
			AddGlyph(controllerName, 10, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_4");
			AddGlyph(controllerName, 11, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_5");
			AddGlyph(controllerName, 6, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_0");
			AddGlyph(controllerName, 7, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_2");
			AddGlyph(controllerName, 8, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_3");
			AddGlyph(controllerName, 9, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_1");
			AddGlyph(controllerName, 15, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_26");
			AddGlyph(controllerName, 16, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_15");
			AddGlyph(controllerName, 17, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_16");
			AddGlyph(controllerName, 18, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_21");
			AddGlyph(controllerName, 19, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_19");
			AddGlyph(controllerName, 20, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_22");
			AddGlyph(controllerName, 21, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_20");
			AddGlyph(controllerName, 12, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_9");
			AddGlyph(controllerName, 13, "tmpsprPS4GlyphsUnified", "texPS4GlyphsUnified_8");
		}

		private static void RegisterSwitchController(string controllerName)
		{
			AddGlyph(controllerName, 1, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_62");
			AddGlyph(controllerName, 0, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_62");
			AddGlyph(controllerName, 3, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_63");
			AddGlyph(controllerName, 2, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_63");
			AddGlyph(controllerName, 10, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_6");
			AddGlyph(controllerName, 11, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_7");
			AddGlyph(controllerName, 8, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_4");
			AddGlyph(controllerName, 9, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_5");
			AddGlyph(controllerName, 4, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_1");
			AddGlyph(controllerName, 5, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_0");
			AddGlyph(controllerName, 6, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_3");
			AddGlyph(controllerName, 7, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_2");
			AddGlyph(controllerName, 12, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_19");
			AddGlyph(controllerName, 13, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_18");
			AddGlyph(controllerName, 16, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_74");
			AddGlyph(controllerName, 17, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_75");
			AddGlyph(controllerName, 18, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_12");
			AddGlyph(controllerName, 19, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_14");
			AddGlyph(controllerName, 20, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_13");
			AddGlyph(controllerName, 21, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_15");
		}

		private static void RegisterSwitchProController(string controllerName)
		{
			AddGlyph(controllerName, 1, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_62");
			AddGlyph(controllerName, 0, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_62");
			AddGlyph(controllerName, 3, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_63");
			AddGlyph(controllerName, 2, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_63");
			AddGlyph(controllerName, 10, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_6");
			AddGlyph(controllerName, 11, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_7");
			AddGlyph(controllerName, 8, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_4");
			AddGlyph(controllerName, 9, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_5");
			AddGlyph(controllerName, 4, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_1");
			AddGlyph(controllerName, 5, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_0");
			AddGlyph(controllerName, 6, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_3");
			AddGlyph(controllerName, 7, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_2");
			AddGlyph(controllerName, 12, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_19");
			AddGlyph(controllerName, 13, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_18");
			AddGlyph(controllerName, 16, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_74");
			AddGlyph(controllerName, 17, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_75");
			AddGlyph(controllerName, 18, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_50");
			AddGlyph(controllerName, 19, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_53");
			AddGlyph(controllerName, 20, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_51");
			AddGlyph(controllerName, 21, "tmpsprSwitchGlyphsUnified", "texSwitchGlyphsUnified_52");
		}

		private static void RegisterStadiaController(string controllerName)
		{
			AddGlyph(controllerName, 0, "tmpsprStadiaGlyphs", "texStadiaGlyphs_28");
			AddGlyph(controllerName, 1, "tmpsprStadiaGlyphs", "texStadiaGlyphs_15");
			AddGlyph(controllerName, 2, "tmpsprStadiaGlyphs", "texStadiaGlyphs_10");
			AddGlyph(controllerName, 3, "tmpsprStadiaGlyphs", "texStadiaGlyphs_0");
			AddGlyph(controllerName, 9, "tmpsprStadiaGlyphs", "texStadiaGlyphs_16");
			AddGlyph(controllerName, 11, "tmpsprStadiaGlyphs", "texStadiaGlyphs_1");
			AddGlyph(controllerName, 8, "tmpsprStadiaGlyphs", "texStadiaGlyphs_21");
			AddGlyph(controllerName, 10, "tmpsprStadiaGlyphs", "texStadiaGlyphs_19");
			AddGlyph(controllerName, 4, "tmpsprStadiaGlyphs", "texStadiaGlyphs_29");
			AddGlyph(controllerName, 5, "tmpsprStadiaGlyphs", "texStadiaGlyphs_31");
			AddGlyph(controllerName, 6, "tmpsprStadiaGlyphs", "texStadiaGlyphs_3");
			AddGlyph(controllerName, 7, "tmpsprStadiaGlyphs", "texStadiaGlyphs_4");
			AddGlyph(controllerName, 13, "tmpsprStadiaGlyphs", "texStadiaGlyphs_17");
			AddGlyph(controllerName, 14, "tmpsprStadiaGlyphs", "texStadiaGlyphs_18");
			AddGlyph(controllerName, 15, "tmpsprStadiaGlyphs", "texStadiaGlyphs_30");
			AddGlyph(controllerName, 16, "tmpsprStadiaGlyphs", "texStadiaGlyphs_32");
			AddGlyph(controllerName, 17, "tmpsprStadiaGlyphs", "texStadiaGlyphs_2");
			AddGlyph(controllerName, 18, "tmpsprStadiaGlyphs", "texStadiaGlyphs_22");
			AddGlyph(controllerName, 19, "tmpsprStadiaGlyphs", "texStadiaGlyphs_20");
			AddGlyph(controllerName, 20, "tmpsprStadiaGlyphs", "texStadiaGlyphs_36");
			AddGlyph(controllerName, 21, "tmpsprStadiaGlyphs", "texStadiaGlyphs_35");
			AddGlyph(controllerName, 22, "tmpsprStadiaGlyphs", "texStadiaGlyphs_33");
			AddGlyph(controllerName, 23, "tmpsprStadiaGlyphs", "texStadiaGlyphs_34");
		}

		private static void RegisterPS5Controller(string controllerName)
		{
			AddGlyph(controllerName, 0, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_LS");
			AddGlyph(controllerName, 1, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_LS");
			AddGlyph(controllerName, 2, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_RS");
			AddGlyph(controllerName, 3, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_RS");
			AddGlyph(controllerName, 4, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_L2");
			AddGlyph(controllerName, 5, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_R2");
			AddGlyph(controllerName, 10, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_L1");
			AddGlyph(controllerName, 11, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_R1");
			AddGlyph(controllerName, 6, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Cross");
			AddGlyph(controllerName, 7, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Circle");
			AddGlyph(controllerName, 8, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Square");
			AddGlyph(controllerName, 9, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Triangle");
			AddGlyph(controllerName, 15, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Touch");
			AddGlyph(controllerName, 16, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_L3");
			AddGlyph(controllerName, 17, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_R3");
			AddGlyph(controllerName, 18, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Up");
			AddGlyph(controllerName, 19, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Right");
			AddGlyph(controllerName, 20, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Down");
			AddGlyph(controllerName, 21, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Left");
			AddGlyph(controllerName, 12, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Create");
			AddGlyph(controllerName, 13, "tmpsprPS5GlyphsUnified", "texPS5GlyphsUnified_Options");
		}

		private static void RegisterMouse(string controllerName)
		{
			AddGlyph(controllerName, 3, "tmpsprSteamGlyphs", "texSteamGlyphs_17");
			AddGlyph(controllerName, 4, "tmpsprSteamGlyphs", "texSteamGlyphs_18");
			AddGlyph(controllerName, 5, "tmpsprSteamGlyphs", "texSteamGlyphs_19");
		}

		private static void RegisterKeyboard(string controllerName)
		{
		}

		static Glyphs()
		{
			glyphMap = new Dictionary<GlyphKey, string>();
			keyboardRawNameToGlyphName = new Dictionary<string, string>();
			mouseElementRenameMap = new Dictionary<string, string>
			{
				["Left Mouse Button"] = "M1",
				["Right Mouse Button"] = "M2",
				["Mouse Button 3"] = "M3",
				["Mouse Button 4"] = "M4",
				["Mouse Button 5"] = "M5",
				["Mouse Button 6"] = "M6",
				["Mouse Button 7"] = "M7",
				["Mouse Wheel"] = "MW",
				["Mouse Wheel +"] = "MW+",
				["Mouse Wheel -"] = "MW-"
			};
			resultsList = new List<ActionElementMap>();
			RegisterXboxController(DefaultControllerMaps.xbox360ControllerName);
			RegisterXboxController("XInput Gamepad");
			for (int i = 0; i < 4; i++)
			{
				RegisterXboxController("XInput Gamepad " + i);
			}
			RegisterXboxController(DefaultControllerMaps.xboxOneControllerName);
			RegisterXboxController("Gamepad");
			RegisterXboxController("Controller");
			RegisterDS4Controller(DefaultControllerMaps.dualshock4ControllerName);
			RegisterDS4Controller(DefaultControllerMaps.dualshock4ControllerNameAlt);
			RegisterPS5Controller(DefaultControllerMaps.dualSenseController);
			RegisterSwitchController(DefaultControllerMaps.switchControllerName);
			RegisterSwitchProController(DefaultControllerMaps.switchProControllerName);
			RegisterSwitchProController(DefaultControllerMaps.switchProControllerNameAlt);
			RegisterStadiaController(DefaultControllerMaps.stadiaControllerName);
		}

		private static string GetKeyboardGlyphString(string actionName)
		{
			if (!keyboardRawNameToGlyphName.TryGetValue(actionName, out var value))
			{
				if (!(actionName == "Left Shift"))
				{
					if (actionName == "Left Control")
					{
						actionName = "Ctrl";
					}
				}
				else
				{
					actionName = "Shift";
				}
				value = actionName;
				keyboardRawNameToGlyphName[actionName] = value;
			}
			return value;
		}

		public static string GetGlyphString(MPEventSystemLocator eventSystemLocator, string actionName)
		{
			MPEventSystem eventSystem = eventSystemLocator.eventSystem;
			if ((bool)eventSystem)
			{
				return GetGlyphString(eventSystem, actionName);
			}
			return "UNKNOWN";
		}

		public static string GetGlyphString(MPEventSystem eventSystem, string actionName, AxisRange axisRange = AxisRange.Full)
		{
			return GetGlyphString(eventSystem, actionName, axisRange, eventSystem.currentInputSource);
		}

		public static string GetGlyphString(MPEventSystem eventSystem, string actionName, AxisRange axisRange, MPEventSystem.InputSource currentInputSource)
		{
			DefaultControllerMaps.RewiredDebugLog("GetGlyphString: action " + actionName + ", source " + currentInputSource);
			Player inputPlayer = eventSystem.player;
			ActionElementMap actionElementMap = null;
			InputAction action = ReInput.mapping.GetAction(actionName);
			if (action == null)
			{
				UnityEngine.Debug.LogError("ERROR in Glyphs.cs: Action with name " + actionName + " does not exist!");
				return "[NO GAMEPAD BINDING]";
			}
			int inputActionId = action.id;
			string controllerName = PlatformManager.DefaultControllerName;
			ControllerType controllerType = (ControllerType)(-1);
			bool axisContributionMatters = axisRange != AxisRange.Full;
			Pole axisContribution = Pole.Positive;
			if (axisRange == AxisRange.Negative)
			{
				axisContribution = Pole.Negative;
			}
			switch (currentInputSource)
			{
			case MPEventSystem.InputSource.MouseAndKeyboard:
				SetController(inputPlayer.controllers.Keyboard);
				if (actionElementMap == null)
				{
					SetController(inputPlayer.controllers.Mouse);
				}
				if (actionElementMap == null)
				{
					return "[NO KB/M BINDING]";
				}
				break;
			case MPEventSystem.InputSource.Gamepad:
			{
				controllerType = ControllerType.Joystick;
				Controller lastActiveController = inputPlayer.controllers.GetLastActiveController(ControllerType.Joystick);
				if (lastActiveController != null)
				{
					DefaultControllerMaps.RewiredDebugLog($"**** GetGlyphString> LastActiveController {lastActiveController.hardwareTypeGuid}");
				}
				else
				{
					DefaultControllerMaps.RewiredDebugLog("**** GetGlyphString> LastActiveController NULL");
				}
				SetController(lastActiveController);
				if (actionElementMap == null)
				{
					foreach (Controller controller in inputPlayer.controllers.Controllers)
					{
						if (controller.type == ControllerType.Joystick)
						{
							SetController(controller);
							if (actionElementMap != null)
							{
								DefaultControllerMaps.RewiredDebugLog($"**** GetGlyphString> Using {controller.hardwareTypeGuid}");
								break;
							}
						}
					}
				}
				if (actionElementMap == null && eventSystem.localUser != null && lastConnectedJoystick != null)
				{
					using IEnumerator<ActionElementMap> enumerator2 = eventSystem.localUser.userProfile.GetJoystickMap(lastConnectedJoystick.hardwareTypeGuid).ElementMapsWithAction(inputActionId).GetEnumerator();
					if (enumerator2.MoveNext())
					{
						ActionElementMap current2 = enumerator2.Current;
						actionElementMap = current2;
						controllerName = lastConnectedJoystick.name;
					}
				}
				if (actionElementMap == null && eventSystem.localUser != null)
				{
					using IEnumerator<ActionElementMap> enumerator2 = eventSystem.localUser.userProfile.joystickMap.ElementMapsWithAction(inputActionId).GetEnumerator();
					if (enumerator2.MoveNext())
					{
						ActionElementMap current3 = enumerator2.Current;
						actionElementMap = current3;
					}
				}
				if (actionElementMap == null)
				{
					return Language.GetString("INPUT_GAMEPAD_UNBOUND");
				}
				break;
			}
			default:
				throw new ArgumentOutOfRangeException();
			}
			int elementIdentifierId = actionElementMap.elementIdentifierId;
			GlyphKey key = new GlyphKey(controllerName, elementIdentifierId);
			if (glyphMap.TryGetValue(key, out var value))
			{
				DefaultControllerMaps.RewiredDebugLog("GetGlyphString: Action " + actionName + ", " + $"ElementId {elementIdentifierId}, " + $"ElementIdent {actionElementMap.elementIdentifierId}, " + "GlyphString: " + value);
				return value;
			}
			DefaultControllerMaps.RewiredDebugWarn("GetGlyphString: Action " + actionName + ", " + $"ElementId {elementIdentifierId}, " + $"ElementIdent {actionElementMap.elementIdentifierId}, " + "GlyphString: ** NOT FOUND **");
			if (controllerType == ControllerType.Keyboard)
			{
				return GetKeyboardGlyphString(actionElementMap.elementIdentifierName);
			}
			if (controllerType == ControllerType.Mouse)
			{
				string text = actionElementMap.elementIdentifierName;
				if (mouseElementRenameMap.TryGetValue(text, out var value2))
				{
					text = value2;
				}
				return text;
			}
			return actionElementMap.elementIdentifierName;
			void SetController(Controller newController)
			{
				if (newController != null)
				{
					controllerName = newController.name;
					controllerType = newController.type;
					if (newController.type == ControllerType.Joystick)
					{
						lastConnectedJoystick = newController;
					}
				}
				actionElementMap = null;
				if (newController != null)
				{
					resultsList.Clear();
					inputPlayer.controllers.maps.GetElementMapsWithAction(newController.type, newController.id, inputActionId, skipDisabledMaps: false, resultsList);
					DefaultControllerMaps.RewiredDebugLog($"**** GetGlyphString> Controller {newController.hardwareTypeGuid}, action {inputActionId}, found {resultsList.Count} mappings...");
					foreach (ActionElementMap results in resultsList)
					{
						if (!axisContributionMatters || results.axisContribution == axisContribution)
						{
							actionElementMap = results;
							break;
						}
					}
				}
			}
		}

		private static void RewiredDebugLog(string v)
		{
			throw new NotImplementedException();
		}
	}
	public static class GoldTitanManager
	{
		private class RemoveItemStealOnDeath : MonoBehaviour
		{
		}

		private static CharacterSpawnCard goldTitanSpawnCard;

		private static ItemIndex goldTitanItemIndex;

		private static MasterCatalog.MasterIndex brotherHurtMasterIndex;

		private static MasterCatalog.MasterIndex falseSonBossLunarShardBrokenMasterIndex;

		private static bool isFalseSonBossLunarShardBrokenMaster = false;

		private static readonly Xoroshiro128Plus rng = new Xoroshiro128Plus(0uL);

		private static object currentChanneler;

		private static readonly List<CharacterMaster> currentTitans = new List<CharacterMaster>();

		private static readonly Func<ItemIndex, bool> goldTitanItemFilterDelegate = GoldTitanItemFilter;

		private static readonly Func<ItemIndex, bool> noItemFilterDelegate = NoItemFilter;

		private static readonly Func<CharacterMaster, bool> allCharacterMastersFilterDelegate = AllCharacterMastersFilter;

		private static event Action onChannelEnd;

		public static event Action onGoldTitanSpawned;

		[SystemInitializer(new Type[]
		{
			typeof(ItemCatalog),
			typeof(MasterCatalog)
		})]
		private static void Init()
		{
			Run.onRunStartGlobal += OnRunStartGlobal;
			Run.onRunDestroyGlobal += OnRunDestroyGlobal;
			TeleporterInteraction.onTeleporterBeginChargingGlobal += OnTeleporterBeginChargingGlobal;
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterChargedGlobal;
			BossGroup.onBossGroupStartServer += OnBossGroupStartServer;
			LegacyResourcesAPI.LoadAsyncCallback("SpawnCards/CharacterSpawnCards/cscTitanGoldAlly", delegate(CharacterSpawnCard operationResult)
			{
				goldTitanSpawnCard = operationResult;
			});
			goldTitanItemIndex = RoR2Content.Items.TitanGoldDuringTP?.itemIndex ?? ItemIndex.None;
			brotherHurtMasterIndex = MasterCatalog.FindMasterIndex("BrotherHurtMaster");
			falseSonBossLunarShardBrokenMasterIndex = MasterCatalog.FindMasterIndex("FalseSonBossLunarShardBrokenMaster");
		}

		private static void CalcTitanPowerAndBestTeam(out int totalItemCount, out TeamIndex teamIndex)
		{
			TeamIndex teamIndex2 = TeamIndex.None;
			int num = 0;
			totalItemCount = 0;
			for (TeamIndex teamIndex3 = TeamIndex.Neutral; teamIndex3 < TeamIndex.Count; teamIndex3++)
			{
				int itemCountForTeam = Util.GetItemCountForTeam(teamIndex3, goldTitanItemIndex, requiresAlive: true);
				if (itemCountForTeam > num)
				{
					num = itemCountForTeam;
					teamIndex2 = teamIndex3;
				}
				totalItemCount += itemCountForTeam;
			}
			teamIndex = teamIndex2;
		}

		private static void KillTitansInList(List<CharacterMaster> titansList)
		{
			try
			{
				foreach (CharacterMaster titans in titansList)
				{
					if ((bool)titans)
					{
						titans.TrueKill();
					}
				}
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private static bool GoldTitanItemFilter(ItemIndex itemIndex)
		{
			return itemIndex == goldTitanItemIndex;
		}

		private static bool NoItemFilter(ItemIndex itemIndex)
		{
			return false;
		}

		private static bool AllCharacterMastersFilter(CharacterMaster characterMaster)
		{
			return true;
		}

		private static bool TryStartChannelingTitansServer(object channeler, UnityEngine.Vector3 approximatePosition, UnityEngine.Vector3? lookAtPosition = null, Action channelEndCallback = null)
		{
			CalcTitanPowerAndBestTeam(out var totalItemCount, out var _);
			if (totalItemCount <= 0)
			{
				return false;
			}
			List<CharacterMaster> newTitans = CollectionPool<CharacterMaster, List<CharacterMaster>>.RentCollection();
			float currentBoostHpCoefficient;
			float currentBoostDamageCoefficient;
			try
			{
				DirectorPlacementRule placementRule = new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
					minDistance = 20f,
					maxDistance = 130f,
					position = approximatePosition
				};
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(goldTitanSpawnCard, placementRule, rng);
				directorSpawnRequest.ignoreTeamMemberLimit = true;
				directorSpawnRequest.teamIndexOverride = TeamIndex.Player;
				currentBoostHpCoefficient = 1f;
				currentBoostDamageCoefficient = 1f;
				if (isFalseSonBossLunarShardBrokenMaster)
				{
					GoldTitanManager.onGoldTitanSpawned();
					directorSpawnRequest.teamIndexOverride = TeamIndex.Monster;
					currentBoostDamageCoefficient += Run.instance.difficultyCoefficient / 8f;
					currentBoostHpCoefficient += Run.instance.difficultyCoefficient / 2f;
				}
				currentBoostHpCoefficient *= Mathf.Pow(totalItemCount, 1f);
				currentBoostDamageCoefficient *= Mathf.Pow(totalItemCount, 0.5f);
				directorSpawnRequest.onSpawnedServer = OnSpawnedServer;
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
				if (newTitans.Count > 0)
				{
					EndChannelingTitansServer(currentChanneler);
					GoldTitanManager.onChannelEnd = channelEndCallback;
					currentChanneler = channeler;
					ListUtils.AddRange(currentTitans, newTitans);
				}
				return true;
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
				KillTitansInList(newTitans);
				return false;
			}
			finally
			{
				CollectionPool<CharacterMaster, List<CharacterMaster>>.ReturnCollection(newTitans);
			}
			void OnSpawnedServer(SpawnCard.SpawnResult spawnResult)
			{
				GameObject spawnedInstance = spawnResult.spawnedInstance;
				ItemStealController titanItemStealController;
				if ((bool)spawnedInstance)
				{
					CharacterMaster component = spawnedInstance.GetComponent<CharacterMaster>();
					if ((bool)component)
					{
						newTitans.Add(component);
						component.inventory.GiveItem(RoR2Content.Items.BoostHp, Mathf.RoundToInt((currentBoostHpCoefficient - 1f) * 10f));
						component.inventory.GiveItem(RoR2Content.Items.BoostDamage, Mathf.RoundToInt((currentBoostDamageCoefficient - 1f) * 10f));
						if (lookAtPosition.HasValue)
						{
							CharacterBody body = component.GetBody();
							if ((bool)body)
							{
								if ((bool)body.characterDirection)
								{
									body.characterDirection.forward = lookAtPosition.Value - body.corePosition;
								}
								if ((bool)body.inputBank)
								{
									body.inputBank.aimDirection = lookAtPosition.Value - body.aimOrigin;
								}
							}
						}
						titanItemStealController = component.gameObject.AddComponent<ItemStealController>();
						titanItemStealController.itemStealFilter = goldTitanItemFilterDelegate;
						titanItemStealController.itemLendFilter = noItemFilterDelegate;
						titanItemStealController.stealInterval = 0f;
						component.onBodyStart += OnBodyDiscovered;
						component.onBodyDeath.AddListener(OnBodyLost);
						CharacterBody body2 = component.GetBody();
						if ((bool)body2)
						{
							OnBodyDiscovered(body2);
						}
					}
				}
				void OnBodyDiscovered(CharacterBody titanBody)
				{
					titanItemStealController.orbDestinationHurtBoxOverride = titanBody.mainHurtBox;
					titanItemStealController.StartSteal(allCharacterMastersFilterDelegate);
				}
				void OnBodyLost()
				{
					titanItemStealController?.ReclaimAllItems();
				}
			}
		}

		private static void EndChannelingTitansServer(object channeler)
		{
			if (channeler == null || channeler != currentChanneler)
			{
				return;
			}
			currentChanneler = null;
			KillTitansInList(currentTitans);
			currentTitans.Clear();
			Action action = GoldTitanManager.onChannelEnd;
			GoldTitanManager.onChannelEnd = null;
			try
			{
				action?.Invoke();
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private static bool TryStartChannelingAgainstCombatSquadServer(CombatSquad combatSquad)
		{
			if (!combatSquad)
			{
				return false;
			}
			List<UnityEngine.Vector3> list = CollectionPool<UnityEngine.Vector3, List<UnityEngine.Vector3>>.RentCollection();
			List<UnityEngine.Vector3> list2 = CollectionPool<UnityEngine.Vector3, List<UnityEngine.Vector3>>.RentCollection();
			try
			{
				combatSquad.onDefeatedServer += EndChannelingWhenDefeated;
				foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
				{
					CharacterBody body = readOnlyInstances.GetBody();
					if ((bool)body && readOnlyInstances.inventory.GetItemCount(goldTitanItemIndex) > 0)
					{
						list2.Add(body.corePosition);
					}
				}
				foreach (CharacterMaster readOnlyMembers in combatSquad.readOnlyMembersList)
				{
					CharacterBody body2 = readOnlyMembers.GetBody();
					if ((bool)body2)
					{
						list.Add(body2.corePosition);
					}
				}
				if (list2.Count == 0 || list.Count == 0)
				{
					if (list2.Count == list.Count)
					{
						UnityEngine.Vector3 position = combatSquad.transform.position;
						list2.Add(position);
						list.Add(position);
					}
					else
					{
						List<UnityEngine.Vector3> dest = ((list2.Count == 0) ? list2 : list);
						List<UnityEngine.Vector3> src = ((list2.Count != 0) ? list2 : list);
						ListUtils.AddRange(dest, src);
					}
				}
				UnityEngine.Vector3 vector = Vector3Utils.AveragePrecise(list);
				UnityEngine.Vector3 approximatePosition = UnityEngine.Vector3.Lerp(Vector3Utils.AveragePrecise(list2), vector, 0.15f);
				return TryStartChannelingTitansServer(combatSquad, approximatePosition, vector, delegate
				{
					combatSquad.onDefeatedServer -= EndChannelingWhenDefeated;
				});
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
				return false;
			}
			finally
			{
				CollectionPool<UnityEngine.Vector3, List<UnityEngine.Vector3>>.ReturnCollection(list2);
				CollectionPool<UnityEngine.Vector3, List<UnityEngine.Vector3>>.ReturnCollection(list);
			}
			void EndChannelingWhenDefeated()
			{
				EndChannelingTitansServer(combatSquad);
			}
		}

		private static void OnRunStartGlobal(Run run)
		{
			if (NetworkServer.active)
			{
				rng.ResetSeed(run.seed + 88888888);
			}
		}

		private static void OnRunDestroyGlobal(Run run)
		{
			if (NetworkServer.active)
			{
				EndChannelingTitansServer(currentChanneler);
			}
		}

		private static void OnTeleporterBeginChargingGlobal(TeleporterInteraction teleporter)
		{
			if (NetworkServer.active)
			{
				TryStartChannelingTitansServer(teleporter, teleporter.transform.position);
			}
		}

		private static void OnTeleporterChargedGlobal(TeleporterInteraction teleporter)
		{
			if (NetworkServer.active)
			{
				EndChannelingTitansServer(teleporter);
			}
		}

		private static void OnBossGroupStartServer(BossGroup bossGroup)
		{
			CombatSquad combatSquad = bossGroup.combatSquad;
			bool flag = false;
			isFalseSonBossLunarShardBrokenMaster = false;
			foreach (CharacterMaster readOnlyMembers in combatSquad.readOnlyMembersList)
			{
				if (readOnlyMembers.masterIndex == brotherHurtMasterIndex)
				{
					flag = true;
					break;
				}
				if (readOnlyMembers.masterIndex == falseSonBossLunarShardBrokenMasterIndex)
				{
					isFalseSonBossLunarShardBrokenMaster = true;
					break;
				}
			}
			float timer;
			if (flag || isFalseSonBossLunarShardBrokenMaster)
			{
				timer = 2f;
				RoR2Application.onFixedUpdate += Check;
			}
			void Check()
			{
				bool flag2 = true;
				try
				{
					if ((bool)combatSquad)
					{
						ReadOnlyCollection<CharacterMaster> readOnlyMembersList = combatSquad.readOnlyMembersList;
						for (int i = 0; i < readOnlyMembersList.Count; i++)
						{
							CharacterMaster characterMaster = readOnlyMembersList[i];
							if ((bool)characterMaster)
							{
								CharacterBody body = characterMaster.GetBody();
								if (body.HasBuff(RoR2Content.Buffs.Immune) || body.outOfCombat)
								{
									flag2 = false;
								}
								else
								{
									timer -= Time.fixedDeltaTime;
									if (timer > 0f)
									{
										flag2 = false;
									}
								}
							}
						}
						if (flag2)
						{
							TryStartChannelingAgainstCombatSquadServer(combatSquad);
						}
					}
				}
				catch (Exception)
				{
				}
				if (flag2)
				{
					RoR2Application.onFixedUpdate -= Check;
				}
			}
		}
	}
	public class HealingFollowerController : NetworkBehaviour
	{
		public float fractionHealthHealing = 0.01f;

		public float fractionHealthBurst = 0.05f;

		public float healingInterval = 1f;

		public float rotationAngularVelocity;

		public float acceleration = 20f;

		public float damping = 0.1f;

		public bool enableSpringMotion;

		[SyncVar]
		public GameObject ownerBodyObject;

		[SyncVar]
		public GameObject targetBodyObject;

		public GameObject indicator;

		private GameObject cachedTargetBodyObject;

		private HealthComponent cachedTargetHealthComponent;

		private float healingTimer;

		private UnityEngine.Vector3 velocity;

		private NetworkInstanceId ___ownerBodyObjectNetId;

		private NetworkInstanceId ___targetBodyObjectNetId;

		public GameObject NetworkownerBodyObject
		{
			get
			{
				return ownerBodyObject;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref ownerBodyObject, 1u, ref ___ownerBodyObjectNetId);
			}
		}

		public GameObject NetworktargetBodyObject
		{
			get
			{
				return targetBodyObject;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref targetBodyObject, 2u, ref ___targetBodyObjectNetId);
			}
		}

		private void FixedUpdate()
		{
			if (cachedTargetBodyObject != targetBodyObject)
			{
				cachedTargetBodyObject = targetBodyObject;
				OnTargetChanged();
			}
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		[Server]
		public void AssignNewTarget(GameObject target)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealingFollowerController::AssignNewTarget(UnityEngine.GameObject)' called on client");
				return;
			}
			NetworktargetBodyObject = (target ? target : ownerBodyObject);
			cachedTargetBodyObject = targetBodyObject;
			cachedTargetHealthComponent = (cachedTargetBodyObject ? cachedTargetBodyObject.GetComponent<HealthComponent>() : null);
			OnTargetChanged();
		}

		private void OnTargetChanged()
		{
			cachedTargetHealthComponent = (cachedTargetBodyObject ? cachedTargetBodyObject.GetComponent<HealthComponent>() : null);
		}

		private void FixedUpdateServer()
		{
			healingTimer -= Time.fixedDeltaTime;
			if (healingTimer <= 0f)
			{
				healingTimer = healingInterval;
				DoHeal(fractionHealthHealing * healingInterval);
			}
			if (!targetBodyObject)
			{
				NetworktargetBodyObject = ownerBodyObject;
			}
			if (!ownerBodyObject)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void Update()
		{
			UpdateMotion();
			base.transform.position += velocity * Time.deltaTime;
			base.transform.rotation = UnityEngine.Quaternion.AngleAxis(rotationAngularVelocity * Time.deltaTime, UnityEngine.Vector3.up) * base.transform.rotation;
			if ((bool)targetBodyObject)
			{
				indicator.transform.position = GetTargetPosition();
			}
		}

		[Server]
		private void DoHeal(float healFraction)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.HealingFollowerController::DoHeal(System.Single)' called on client");
			}
			else if ((bool)cachedTargetHealthComponent)
			{
				cachedTargetHealthComponent.HealFraction(healFraction, default(ProcChainMask));
			}
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			base.transform.position = GetDesiredPosition();
		}

		private UnityEngine.Vector3 GetTargetPosition()
		{
			GameObject gameObject = targetBodyObject ?? ownerBodyObject;
			if ((bool)gameObject)
			{
				CharacterBody component = gameObject.GetComponent<CharacterBody>();
				if (!component)
				{
					return gameObject.transform.position;
				}
				return component.corePosition;
			}
			return base.transform.position;
		}

		private UnityEngine.Vector3 GetDesiredPosition()
		{
			return GetTargetPosition();
		}

		private void UpdateMotion()
		{
			UnityEngine.Vector3 desiredPosition = GetDesiredPosition();
			if (enableSpringMotion)
			{
				UnityEngine.Vector3 vector = desiredPosition - base.transform.position;
				if (vector != UnityEngine.Vector3.zero)
				{
					UnityEngine.Vector3 vector2 = vector.normalized * acceleration;
					UnityEngine.Vector3 vector3 = velocity * (0f - damping);
					velocity += (vector2 + vector3) * Time.deltaTime;
				}
			}
			else
			{
				base.transform.position = UnityEngine.Vector3.SmoothDamp(base.transform.position, desiredPosition, ref velocity, damping);
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(ownerBodyObject);
				writer.Write(targetBodyObject);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(ownerBodyObject);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(targetBodyObject);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___ownerBodyObjectNetId = reader.ReadNetworkId();
				___targetBodyObjectNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				ownerBodyObject = reader.ReadGameObject();
			}
			if (((uint)num & 2u) != 0)
			{
				targetBodyObject = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___ownerBodyObjectNetId.IsEmpty())
			{
				NetworkownerBodyObject = ClientScene.FindLocalObject(___ownerBodyObjectNetId);
			}
			if (!___targetBodyObjectNetId.IsEmpty())
			{
				NetworktargetBodyObject = ClientScene.FindLocalObject(___targetBodyObjectNetId);
			}
		}
	}
	public class HealingPulse
	{
		public static float duration;

		public float healAmount;

		public UnityEngine.Vector3 origin;

		public TeamIndex teamIndex;

		public float radius;

		public GameObject effectPrefab;

		public float overShield;

		private readonly List<HealthComponent> healedTargets = new List<HealthComponent>();

		private readonly SphereSearch sphereSearch;

		private TeamMask teamMask;

		private readonly List<HurtBox> hurtBoxesList = new List<HurtBox>();

		public void Fire()
		{
			SphereSearch obj = new SphereSearch
			{
				mask = LayerIndex.entityPrecise.mask,
				origin = origin,
				queryTriggerInteraction = QueryTriggerInteraction.Collide,
				radius = radius
			};
			teamMask = default(TeamMask);
			teamMask.AddTeam(teamIndex);
			obj.RefreshCandidates();
			obj.FilterCandidatesByDistinctHurtBoxEntities();
			obj.RefreshCandidates().FilterCandidatesByHurtBoxTeam(teamMask).FilterCandidatesByDistinctHurtBoxEntities()
				.GetHurtBoxes(hurtBoxesList);
			int i = 0;
			for (int count = hurtBoxesList.Count; i < count; i++)
			{
				HealthComponent healthComponent = hurtBoxesList[i].healthComponent;
				if (!healedTargets.Contains(healthComponent))
				{
					healedTargets.Add(healthComponent);
					HealTarget(healthComponent);
					if (overShield > 0f)
					{
						healthComponent.AddBarrierAuthority(overShield);
					}
				}
			}
			EffectManager.SimpleEffect(effectPrefab, origin, UnityEngine.Quaternion.identity, transmit: true);
			hurtBoxesList.Clear();
		}

		private void HealTarget(HealthComponent target)
		{
			target.Heal(healAmount, default(ProcChainMask));
			Util.PlaySound("Play_item_proc_TPhealingNova_hitPlayer", target.gameObject);
		}
	}
	public static class HGPhysics
	{
		private const int INITIAL_POOL_SIZE = 4;

		private const int MAX_COLLIDERS = 100;

		private const int MAX_RAYCASTHIT = 100;

		private static List<Collider[]> ColliderPool;

		private static List<RaycastHit[]> RaycastPool;

		private static int _colliderCallCount;

		private static int _raycastHitCallCount;

		private static bool _useSharedRaycast;

		private static bool _trackRaycasts;

		private static bool _useSharedColliders;

		private static bool _doCompare;

		private static int _maxHits;

		private static int _highRaycastCount;

		private static int _highColiderCount;

		public static bool useSharedRaycast
		{
			get
			{
				return _useSharedRaycast;
			}
			set
			{
				_useSharedRaycast = value;
				UnityEngine.Debug.LogFormat("Use Non-Alloc Raycasts: {0}", value.ToString());
			}
		}

		public static bool trackRaycasts
		{
			get
			{
				return _trackRaycasts;
			}
			set
			{
				_trackRaycasts = value;
			}
		}

		public static bool useSharedColliders
		{
			get
			{
				return _useSharedColliders;
			}
			set
			{
				_useSharedColliders = value;
				UnityEngine.Debug.LogFormat("Use Non-Alloc Casts: {0}", value.ToString());
			}
		}

		static HGPhysics()
		{
			_colliderCallCount = 0;
			_raycastHitCallCount = 0;
			_useSharedRaycast = true;
			_trackRaycasts = true;
			_useSharedColliders = true;
			_doCompare = false;
			_maxHits = 0;
			_highRaycastCount = 0;
			_highColiderCount = 0;
			ColliderPool = new List<Collider[]>(4);
			for (int i = 0; i < 4; i++)
			{
				Collider[] item = new Collider[100];
				ColliderPool.Add(item);
			}
			RaycastPool = new List<RaycastHit[]>(4);
			for (int j = 0; j < 4; j++)
			{
				RaycastHit[] item2 = new RaycastHit[100];
				RaycastPool.Add(item2);
			}
		}

		private static void AddColliderArray()
		{
			UnityEngine.Debug.LogWarning("HGPhysics allocating new collider array.  consider upping the initial value");
			ColliderPool.Add(new Collider[100]);
		}

		private static void AddRaycastArray()
		{
			UnityEngine.Debug.LogWarning("HGPhysics allocating new RaycastHit array.  consider upping the initial value");
			RaycastPool.Add(new RaycastHit[100]);
		}

		public static int OverlapSphere(out Collider[] colliders, UnityEngine.Vector3 position, float radius, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)
		{
			int num = 0;
			if (useSharedColliders)
			{
				_colliderCallCount++;
				if (ColliderPool.Count < 1)
				{
					AddColliderArray();
				}
				Collider[] array = ColliderPool[ColliderPool.Count - 1];
				ColliderPool.RemoveAt(ColliderPool.Count - 1);
				num = Physics.OverlapSphereNonAlloc(position, radius, array, layerMask, queryTriggerInteraction);
				colliders = array;
			}
			else
			{
				colliders = Physics.OverlapSphere(position, radius, layerMask, queryTriggerInteraction);
				num = colliders.Length;
			}
			return num;
		}

		public static bool DoesOverlapSphere(UnityEngine.Vector3 position, float radius, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)
		{
			Collider[] colliders;
			int num = OverlapSphere(out colliders, position, radius, layerMask, queryTriggerInteraction);
			ReturnResults(colliders);
			return num > 0;
		}

		public static int OverlapBox(out Collider[] colliders, UnityEngine.Vector3 center, UnityEngine.Vector3 halfExtents, UnityEngine.Quaternion orientation, int layerMask, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)
		{
			int num = 0;
			if (useSharedColliders)
			{
				_colliderCallCount++;
				if (ColliderPool.Count < 1)
				{
					AddColliderArray();
				}
				Collider[] array = ColliderPool[ColliderPool.Count - 1];
				ColliderPool.RemoveAt(ColliderPool.Count - 1);
				num = Physics.OverlapBoxNonAlloc(center, halfExtents, array, orientation, layerMask, queryTriggerInteraction);
				colliders = array;
			}
			else
			{
				colliders = Physics.OverlapBox(center, halfExtents, orientation, layerMask, queryTriggerInteraction);
				num = colliders.Length;
			}
			return num;
		}

		public static int SphereCastAll(out RaycastHit[] hits, UnityEngine.Vector3 origin, float radius, UnityEngine.Vector3 direction, float maxDistance = float.PositiveInfinity, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)
		{
			int num = 0;
			if (useSharedRaycast)
			{
				_raycastHitCallCount++;
				if (RaycastPool.Count < 1)
				{
					AddRaycastArray();
				}
				RaycastHit[] array = RaycastPool[RaycastPool.Count - 1];
				RaycastPool.RemoveAt(RaycastPool.Count - 1);
				num = Physics.SphereCastNonAlloc(origin, radius, direction, array, maxDistance, layerMask, queryTriggerInteraction);
				hits = array;
			}
			else
			{
				hits = Physics.SphereCastAll(origin, radius, direction, maxDistance, layerMask, queryTriggerInteraction);
				num = hits.Length;
			}
			return num;
		}

		public static int RaycastAll(out RaycastHit[] hits, UnityEngine.Vector3 origin, UnityEngine.Vector3 normal, float maxDistance = float.PositiveInfinity, int layerMask = -1, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)
		{
			int num = 0;
			if (useSharedRaycast)
			{
				_raycastHitCallCount++;
				if (RaycastPool.Count < 1)
				{
					AddRaycastArray();
				}
				RaycastHit[] array = RaycastPool[RaycastPool.Count - 1];
				RaycastPool.RemoveAt(RaycastPool.Count - 1);
				num = Physics.RaycastNonAlloc(origin, normal, array, maxDistance, layerMask, queryTriggerInteraction);
				hits = array;
			}
			else
			{
				hits = Physics.RaycastAll(origin, normal, maxDistance, layerMask, queryTriggerInteraction);
				num = hits.Length;
			}
			return num;
		}

		public static void ReturnResults(Collider[] colliders)
		{
			if (useSharedColliders)
			{
				_colliderCallCount--;
				ColliderPool.Add(colliders);
			}
		}

		public static void ReturnResults(RaycastHit[] hits)
		{
			if (useSharedRaycast)
			{
				_raycastHitCallCount--;
				RaycastPool.Add(hits);
			}
		}

		public static float CalculateDistance(float initialVelocity, float acceleration, float time)
		{
			return initialVelocity * time + 0.5f * acceleration * time * time;
		}

		[Conditional("DEBUG")]
		public static void TrackHits(ref int hits, int newHits)
		{
			if (hits < newHits)
			{
				hits = newHits;
				if (newHits > _maxHits)
				{
					_maxHits = newHits;
				}
			}
		}
	}
	public enum HullClassification
	{
		Human,
		Golem,
		BeetleQueen,
		Count
	}
	[Flags]
	public enum HullMask
	{
		None = 0,
		Human = 1,
		Golem = 2,
		BeetleQueen = 4
	}
	public struct HullDef
	{
		public float height;

		public float radius;

		private static HullDef[] hullDefs;

		static HullDef()
		{
			hullDefs = new HullDef[3];
			hullDefs[0] = new HullDef
			{
				height = 2f,
				radius = 0.5f
			};
			hullDefs[1] = new HullDef
			{
				height = 8f,
				radius = 1.8f
			};
			hullDefs[2] = new HullDef
			{
				height = 20f,
				radius = 5f
			};
		}

		public static HullDef Find(HullClassification hullClassification)
		{
			return hullDefs[(int)hullClassification];
		}
	}
	public class Indicator
	{
		private static class IndicatorManager
		{
			private static readonly List<Indicator> runningIndicators;

			public static void AddIndicator([NotNull] Indicator indicator)
			{
				runningIndicators.Add(indicator);
				RebuildVisualizer(indicator);
			}

			public static void RemoveIndicator([NotNull] Indicator indicator)
			{
				indicator.SetVisualizerInstantiated(newVisualizerInstantiated: false);
				runningIndicators.Remove(indicator);
			}

			static IndicatorManager()
			{
				runningIndicators = new List<Indicator>();
				CameraRigController.onCameraTargetChanged += delegate
				{
					RebuildVisualizerForAll();
				};
				UICamera.onUICameraPreRender += OnPreRenderUI;
				UICamera.onUICameraPostRender += OnPostRenderUI;
				RoR2Application.onUpdate += Update;
			}

			private static void RebuildVisualizerForAll()
			{
				foreach (Indicator runningIndicator in runningIndicators)
				{
					RebuildVisualizer(runningIndicator);
				}
			}

			private static void Update()
			{
				foreach (Indicator runningIndicator in runningIndicators)
				{
					if (runningIndicator.hasVisualizer)
					{
						runningIndicator.UpdateVisualizer();
					}
				}
			}

			private static void RebuildVisualizer(Indicator indicator)
			{
				bool visualizerInstantiated = false;
				foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList)
				{
					if (readOnlyInstances.target == indicator.owner)
					{
						visualizerInstantiated = true;
						break;
					}
				}
				indicator.SetVisualizerInstantiated(visualizerInstantiated);
			}

			private static void OnPreRenderUI(UICamera uiCam)
			{
				GameObject target = uiCam.cameraRigController.target;
				Camera sceneCam = uiCam.cameraRigController.sceneCam;
				foreach (Indicator runningIndicator in runningIndicators)
				{
					bool num = target == runningIndicator.owner;
					runningIndicator.SetVisible(target == runningIndicator.owner);
					if (num)
					{
						runningIndicator.PositionForUI(sceneCam, uiCam.camera);
					}
				}
			}

			private static void OnPostRenderUI(UICamera uiCamera)
			{
				foreach (Indicator runningIndicator in runningIndicators)
				{
					runningIndicator.SetVisible(newVisible: true);
				}
			}
		}

		private GameObject _visualizerPrefab;

		public readonly GameObject owner;

		public Transform targetTransform;

		protected List<Renderer> visualizerRenderers = new List<Renderer>();

		private bool _active;

		private bool visible = true;

		public GameObject visualizerPrefab
		{
			get
			{
				return _visualizerPrefab;
			}
			set
			{
				if (!(_visualizerPrefab == value))
				{
					_visualizerPrefab = value;
					if ((bool)visualizerInstance)
					{
						DestroyVisualizer();
						InstantiateVisualizer();
					}
				}
			}
		}

		protected GameObject visualizerInstance { get; private set; }

		protected Transform visualizerTransform { get; private set; }

		public bool hasVisualizer => visualizerInstance;

		public bool active
		{
			get
			{
				return _active;
			}
			set
			{
				if (_active != value)
				{
					_active = value;
					if (active)
					{
						IndicatorManager.AddIndicator(this);
					}
					else
					{
						IndicatorManager.RemoveIndicator(this);
					}
				}
			}
		}

		public Indicator(GameObject owner, GameObject visualizerPrefab)
		{
			this.owner = owner;
			_visualizerPrefab = visualizerPrefab;
		}

		public void SetVisualizerInstantiated(bool newVisualizerInstantiated)
		{
			if ((bool)visualizerInstance != newVisualizerInstantiated)
			{
				if (newVisualizerInstantiated)
				{
					InstantiateVisualizer();
				}
				else
				{
					DestroyVisualizer();
				}
			}
		}

		private void InstantiateVisualizer()
		{
			visualizerInstance = UnityEngine.Object.Instantiate(visualizerPrefab);
			OnInstantiateVisualizer();
		}

		private void DestroyVisualizer()
		{
			OnDestroyVisualizer();
			UnityEngine.Object.Destroy(visualizerInstance);
			visualizerInstance = null;
		}

		protected void FindRenderers(Transform root)
		{
			visualizerRenderers.AddRange(root.GetComponentsInChildren<Renderer>(includeInactive: true));
		}

		private void FindInputBindingDisplayControllers(Transform root)
		{
			InputBindingDisplayController[] componentsInChildren = root.GetComponentsInChildren<InputBindingDisplayController>(includeInactive: true);
			foreach (InputBindingDisplayController ibdc in componentsInChildren)
			{
				InputBindingDisplayController inputBindingDisplayController = ibdc;
				inputBindingDisplayController.oneFrameAfterTextUpdate = (Action)Delegate.Combine(inputBindingDisplayController.oneFrameAfterTextUpdate, (Action)delegate
				{
					FindRenderers(ibdc.transform);
				});
			}
		}

		public void OnInstantiateVisualizer()
		{
			visualizerTransform = visualizerInstance.transform;
			FindRenderers(visualizerTransform);
			FindInputBindingDisplayControllers(visualizerTransform);
			SetVisibleInternal(visible);
		}

		public virtual void OnDestroyVisualizer()
		{
			visualizerTransform = null;
			visualizerRenderers.Clear();
		}

		public virtual void UpdateVisualizer()
		{
		}

		public virtual void PositionForUI(Camera sceneCamera, Camera uiCamera)
		{
			if ((bool)targetTransform)
			{
				UnityEngine.Vector3 position = targetTransform.position;
				UnityEngine.Vector3 position2 = sceneCamera.WorldToScreenPoint(position);
				position2.z = ((position2.z > 0f) ? 1f : (-1f));
				UnityEngine.Vector3 position3 = uiCamera.ScreenToWorldPoint(position2);
				if (visualizerTransform != null)
				{
					visualizerTransform.position = position3;
				}
			}
		}

		public void SetVisible(bool newVisible)
		{
			newVisible &= (bool)targetTransform;
			if (visible != newVisible)
			{
				SetVisibleInternal(newVisible);
			}
		}

		private void SetVisibleInternal(bool newVisible)
		{
			visible = newVisible;
			foreach (Renderer visualizerRenderer in visualizerRenderers)
			{
				visualizerRenderer.enabled = newVisible;
			}
		}
	}
	public static class InputCatalog
	{
		private struct ActionAxisPair : IEquatable<ActionAxisPair>
		{
			[NotNull]
			private readonly string actionName;

			private readonly AxisRange axisRange;

			public ActionAxisPair([NotNull] string actionName, AxisRange axisRange)
			{
				this.actionName = actionName;
				this.axisRange = axisRange;
			}

			public bool Equals(ActionAxisPair other)
			{
				if (string.Equals(actionName, other.actionName))
				{
					return axisRange == other.axisRange;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is ActionAxisPair)
				{
					return Equals((ActionAxisPair)obj);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return ((-1879861323 * -1521134295 + base.GetHashCode()) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(actionName)) * -1521134295 + axisRange.GetHashCode();
			}
		}

		private static readonly Dictionary<ActionAxisPair, string> actionToToken;

		static InputCatalog()
		{
			actionToToken = new Dictionary<ActionAxisPair, string>();
			Add("MoveHorizontal", "ACTION_MOVE_HORIZONTAL", AxisRange.Full);
			Add("MoveVertical", "ACTION_MOVE_VERTICAL", AxisRange.Full);
			Add("AimHorizontalMouse", "ACTION_AIM_HORIZONTAL_MOUSE", AxisRange.Full);
			Add("AimVerticalMouse", "ACTION_AIM_VERTICAL_MOUSE", AxisRange.Full);
			Add("AimHorizontalStick", "ACTION_AIM_HORIZONTAL_STICK", AxisRange.Full);
			Add("AimVerticalStick", "ACTION_AIM_VERTICAL_STICK", AxisRange.Full);
			Add("Jump", "ACTION_JUMP", AxisRange.Full);
			Add("Sprint", "ACTION_SPRINT", AxisRange.Full);
			Add("Interact", "ACTION_INTERACT", AxisRange.Full);
			Add("Equipment", "ACTION_EQUIPMENT", AxisRange.Full);
			Add("PrimarySkill", "ACTION_PRIMARY_SKILL", AxisRange.Full);
			Add("SecondarySkill", "ACTION_SECONDARY_SKILL", AxisRange.Full);
			Add("UtilitySkill", "ACTION_UTILITY_SKILL", AxisRange.Full);
			Add("SpecialSkill", "ACTION_SPECIAL_SKILL", AxisRange.Full);
			Add("Info", "ACTION_INFO", AxisRange.Full);
			Add("Ping", "ACTION_PING", AxisRange.Full);
			Add("MoveHorizontal", "ACTION_MOVE_HORIZONTAL_POSITIVE", AxisRange.Positive);
			Add("MoveHorizontal", "ACTION_MOVE_HORIZONTAL_NEGATIVE", AxisRange.Negative);
			Add("MoveVertical", "ACTION_MOVE_VERTICAL_POSITIVE", AxisRange.Positive);
			Add("MoveVertical", "ACTION_MOVE_VERTICAL_NEGATIVE", AxisRange.Negative);
			static void Add(string actionName, string token, AxisRange axisRange)
			{
				actionToToken[new ActionAxisPair(actionName, axisRange)] = token;
			}
		}

		public static string GetActionNameToken(string actionName, AxisRange axisRange = AxisRange.Full)
		{
			if (actionToToken.TryGetValue(new ActionAxisPair(actionName, axisRange), out var value))
			{
				return value;
			}
			throw new ArgumentException($"Bad action/axis pair {actionName} {axisRange}.");
		}
	}
	public class InputMapperHelper : IDisposable
	{
		private readonly MPEventSystem eventSystem;

		private readonly List<InputMapper> inputMappers = new List<InputMapper>();

		private ControllerMap[] maps = Array.Empty<ControllerMap>();

		private SimpleDialogBox dialogBox;

		public float timeout = 5f;

		private float timer;

		private Player currentPlayer;

		private InputAction currentAction;

		private AxisRange currentAxisRange;

		public static bool anyRemapperListening = false;

		public static float anyRemapperListeningStopTimestamp = -1f;

		protected Player _player;

		private Action<InputMapper.ConflictResponse> conflictResponseCallback;

		private static readonly HashSet<string> forbiddenElements = new HashSet<string>
		{
			"Left Stick X",
			"left stick x",
			"Left Stick Y",
			"left stick y",
			"Right Stick X",
			"right stick x",
			"Right Stick Y",
			"right stick y",
			"Mouse Horizontal",
			"Mouse Vertical",
			"Menu",
			"Menu Button",
			"OPTIONS button",
			"options button",
			"Left SL",
			"Left SR",
			"Right SL",
			"Right SR",
			"+ Button",
			Keyboard.GetKeyName(KeyCode.Escape),
			Keyboard.GetKeyName(KeyCode.KeypadEnter),
			Keyboard.GetKeyName(KeyCode.Return)
		};

		public bool isListening { get; private set; }

		public InputMapperHelper(MPEventSystem eventSystem)
		{
			this.eventSystem = eventSystem;
		}

		private InputMapper AddInputMapper()
		{
			InputMapper inputMapper = new InputMapper();
			inputMapper.ConflictFoundEvent += InputMapperOnConflictFoundEvent;
			inputMapper.CanceledEvent += InputMapperOnCanceledEvent;
			inputMapper.ErrorEvent += InputMapperOnErrorEvent;
			inputMapper.InputMappedEvent += InputMapperOnInputMappedEvent;
			inputMapper.StartedEvent += InputMapperOnStartedEvent;
			inputMapper.StoppedEvent += InputMapperOnStoppedEvent;
			inputMapper.TimedOutEvent += InputMapperOnTimedOutEvent;
			inputMapper.options = new InputMapper.Options
			{
				allowAxes = true,
				allowButtons = true,
				allowKeyboardKeysWithModifiers = false,
				allowKeyboardModifierKeyAsPrimary = true,
				checkForConflicts = true,
				checkForConflictsWithAllPlayers = false,
				checkForConflictsWithPlayerIds = Array.Empty<int>(),
				checkForConflictsWithSelf = true,
				checkForConflictsWithSystemPlayer = false,
				defaultActionWhenConflictFound = InputMapper.ConflictResponse.Add,
				holdDurationToMapKeyboardModifierKeyAsPrimary = 0f,
				ignoreMouseXAxis = true,
				ignoreMouseYAxis = true,
				timeout = float.PositiveInfinity
			};
			inputMappers.Add(inputMapper);
			return inputMapper;
		}

		private void RemoveInputMapper(InputMapper inputMapper)
		{
			inputMapper.ConflictFoundEvent -= InputMapperOnConflictFoundEvent;
			inputMapper.CanceledEvent -= InputMapperOnCanceledEvent;
			inputMapper.ErrorEvent -= InputMapperOnErrorEvent;
			inputMapper.InputMappedEvent -= InputMapperOnInputMappedEvent;
			inputMapper.StartedEvent -= InputMapperOnStartedEvent;
			inputMapper.StoppedEvent -= InputMapperOnStoppedEvent;
			inputMapper.TimedOutEvent -= InputMapperOnTimedOutEvent;
			inputMappers.Remove(inputMapper);
		}

		public void Start(Player player, IList<Controller> controllers, InputAction action, AxisRange axisRange)
		{
			Stop();
			anyRemapperListening = true;
			isListening = true;
			currentPlayer = player;
			currentAction = action;
			currentAxisRange = axisRange;
			maps = (from controller in controllers
				select player.controllers.maps.GetFirstMapInCategory(controller, 0) into map
				where map != null
				select map).ToArray();
			DefaultControllerMaps.RewiredDebugLog("InputMapperHelper: Found {0} control maps", maps.Length);
			_player = player;
			Controller lastActiveController = player.controllers.GetLastActiveController();
			Controller lastActiveController2 = player.controllers.GetLastActiveController(ControllerType.Joystick);
			DefaultControllerMaps.RewiredDebugLog("InputMapHelper.Start: active {0} ({1}), activeJoystick {2} ({3})", (lastActiveController != null) ? lastActiveController.type.ToString() : "**null**", (lastActiveController != null) ? lastActiveController.hardwareTypeGuid.ToString() : "**null**", (lastActiveController2 != null) ? lastActiveController2.type.ToString() : "**null**", (lastActiveController2 != null) ? lastActiveController2.hardwareTypeGuid.ToString() : "**null**");
			if (lastActiveController2 != null && lastActiveController == lastActiveController2)
			{
				ControllerMap[] array = maps;
				foreach (ControllerMap controllerMap in array)
				{
					DefaultControllerMaps.RewiredDebugLog("\tProcessing map: {0}", controllerMap.ToJsonString());
					InputMapper.Context mappingContext = new InputMapper.Context
					{
						actionId = action.id,
						controllerMap = controllerMap,
						actionRange = currentAxisRange
					};
					AddInputMapper().Start(mappingContext);
				}
			}
			else
			{
				ControllerMap[] array = maps;
				foreach (ControllerMap controllerMap2 in array)
				{
					if (controllerMap2.controllerType != ControllerType.Joystick)
					{
						InputMapper.Context mappingContext2 = new InputMapper.Context
						{
							actionId = action.id,
							controllerMap = controllerMap2,
							actionRange = currentAxisRange
						};
						AddInputMapper().Start(mappingContext2);
					}
				}
			}
			dialogBox = SimpleDialogBox.Create(eventSystem);
			timer = timeout;
			UpdateDialogBoxString();
			RoR2Application.onUpdate += Update;
		}

		public void Stop()
		{
			if (isListening)
			{
				anyRemapperListening = false;
				anyRemapperListeningStopTimestamp = Time.unscaledTime;
				maps = Array.Empty<ControllerMap>();
				currentPlayer = null;
				currentAction = null;
				for (int num = inputMappers.Count - 1; num >= 0; num--)
				{
					InputMapper inputMapper = inputMappers[num];
					inputMapper.Stop();
					RemoveInputMapper(inputMapper);
				}
				if ((bool)dialogBox)
				{
					UnityEngine.Object.Destroy(dialogBox.rootObject);
					dialogBox = null;
				}
				isListening = false;
				RoR2Application.onUpdate -= Update;
			}
		}

		private void Update()
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			if (isListening)
			{
				timer -= unscaledDeltaTime;
				if (timer < 0f)
				{
					Stop();
				}
				else if (currentPlayer.GetButtonDown(25))
				{
					ShowCancledDialog();
				}
				else
				{
					UpdateDialogBoxString();
				}
			}
		}

		private void ShowCancledDialog()
		{
			Stop();
			SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create(eventSystem);
			simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair("OPTION_REBIND_DIALOG_TITLE");
			simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair("OPTION_REBIND_CANCELLED_DIALOG_DESCRIPTION");
			simpleDialogBox.AddCancelButton(CommonLanguageTokens.ok);
		}

		private void UpdateDialogBoxString()
		{
			if ((bool)dialogBox && timer >= 0f)
			{
				string @string = Language.GetString(InputCatalog.GetActionNameToken(currentAction.name));
				dialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
				{
					token = CommonLanguageTokens.optionRebindDialogTitle,
					formatParams = Array.Empty<object>()
				};
				dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
				{
					token = CommonLanguageTokens.optionRebindDialogDescription,
					formatParams = new object[2] { @string, timer }
				};
			}
		}

		private void InputMapperOnTimedOutEvent(InputMapper.TimedOutEventData timedOutEventData)
		{
		}

		private void InputMapperOnStoppedEvent(InputMapper.StoppedEventData stoppedEventData)
		{
		}

		private void InputMapperOnStartedEvent(InputMapper.StartedEventData startedEventData)
		{
		}

		private void InputMapperOnInputMappedEvent(InputMapper.InputMappedEventData inputMappedEventData)
		{
			ActionElementMap incomingActionElementMap = inputMappedEventData.actionElementMap;
			int incomingActionId = inputMappedEventData.actionElementMap.actionId;
			int incomingElementIndex = inputMappedEventData.actionElementMap.elementIndex;
			ControllerElementType incomingElementType = inputMappedEventData.actionElementMap.elementType;
			ControllerMap map = inputMappedEventData.actionElementMap.controllerMap;
			Controller activeController = null;
			ControllerMap defaultMap = null;
			ControllerMap uiMap = null;
			if (_player != null)
			{
				activeController = _player.controllers.GetLastActiveController();
				if (activeController != null && activeController.type == ControllerType.Joystick)
				{
					if (!DefaultControllerMaps.HardwareGuidsMatch(activeController.hardwareTypeGuid, map.hardwareGuid))
					{
						DefaultControllerMaps.RewiredDebugLog($"Skipping hardware {map.hardwareGuid} (activeController {activeController.hardwareTypeGuid}");
						return;
					}
					DefaultControllerMaps.RewiredDebugLog($"Hardware match: {map.hardwareGuid} (activeController {activeController.hardwareTypeGuid}");
				}
			}
			if (activeController != null && activeController.type == ControllerType.Joystick)
			{
				defaultMap = ReInput.mapping.GetJoystickMapInstance(activeController.hardwareTypeGuid, 0, 0);
				uiMap = ReInput.mapping.GetJoystickMapInstance(activeController.hardwareTypeGuid, 2, 0);
			}
			DefaultControllerMaps.RewiredDebugLog($"NEWMAP: elementIdentifierID: {inputMappedEventData.actionElementMap.elementIdentifierId} ({inputMappedEventData.actionElementMap.actionDescriptiveName})");
			if (forbiddenElements.Contains(inputMappedEventData.actionElementMap.elementIdentifierName))
			{
				ShowCancledDialog();
				return;
			}
			ControllerMap[] array = maps;
			foreach (ControllerMap controllerMap in array)
			{
				if (controllerMap != map)
				{
					controllerMap.DeleteElementMapsWithAction(incomingActionId);
				}
			}
			while (DeleteFirstConflictingElementMap())
			{
			}
			if (activeController != null)
			{
				if (map is JoystickMap inJoystickMap)
				{
					eventSystem?.localUser?.userProfile.UpdateJoystickMap(activeController.hardwareTypeGuid, inJoystickMap);
				}
				else
				{
					DefaultControllerMaps.RewiredDebugWarn($"NOT A JOYSTICK MAP for controller {activeController.hardwareTypeGuid}");
				}
			}
			eventSystem?.localUser?.userProfile.RequestEventualSave();
			Stop();
			if (InputBindingDisplayController.onBindingsChanged != null)
			{
				InputBindingDisplayController.onBindingsChanged();
			}
			bool ActionElementMapConflicts(ActionElementMap actionElementMap)
			{
				if (actionElementMap == incomingActionElementMap)
				{
					return false;
				}
				bool num = actionElementMap.elementIndex == incomingElementIndex && actionElementMap.elementType == incomingElementType;
				bool flag = actionElementMap.actionId == incomingActionId && actionElementMap.axisContribution == incomingActionElementMap.axisContribution;
				return num || flag;
			}
			bool DeleteFirstConflictingElementMap()
			{
				foreach (ActionElementMap allMap in map.AllMaps)
				{
					if ((defaultMap != null || uiMap != null) && allMap.controllerMap != null)
					{
						bool num2 = allMap.controllerMap == defaultMap;
						bool flag2 = allMap.controllerMap != uiMap;
						if (!num2 && !flag2)
						{
							DefaultControllerMaps.RewiredDebugLog("Skipping map as it is for wrong controller... active {0} vs checking {1}", activeController.hardwareTypeGuid, allMap.controllerMap.controller.hardwareTypeGuid);
							continue;
						}
					}
					if (ActionElementMapConflicts(allMap))
					{
						UnityEngine.Debug.LogFormat("Deleting conflicting mapping {0}", allMap);
						DefaultControllerMaps.RewiredDebugLog("***** Deleting conflicting mapping {0} ({1})", allMap, allMap.controllerMap.controller.hardwareTypeGuid);
						map.DeleteElementMap(allMap.id);
						return true;
					}
				}
				return false;
			}
		}

		private void InputMapperOnErrorEvent(InputMapper.ErrorEventData errorEventData)
		{
		}

		private void InputMapperOnCanceledEvent(InputMapper.CanceledEventData canceledEventData)
		{
		}

		private void InputMapperOnConflictFoundEvent(InputMapper.ConflictFoundEventData conflictFoundEventData)
		{
			InputMapper.ConflictResponse obj = ((!conflictFoundEventData.conflicts.Any((ElementAssignmentConflictInfo elementAssignmentConflictInfo) => forbiddenElements.Contains(elementAssignmentConflictInfo.elementIdentifier.name))) ? InputMapper.ConflictResponse.Add : InputMapper.ConflictResponse.Ignore);
			conflictFoundEventData.responseCallback(obj);
		}

		public void Dispose()
		{
			Stop();
		}
	}
	public static class InstanceTracker
	{
		private static class TypeData<T> where T : MonoBehaviour
		{
			public static readonly List<T> instancesList;

			static TypeData()
			{
				instancesList = new List<T>();
				instancesLists[typeof(T)] = instancesList;
			}

			public static void Add(T instance)
			{
				instancesList.Add(instance);
			}

			public static void Remove(T instance)
			{
				instancesList.Remove(instance);
			}
		}

		private static readonly Dictionary<Type, IEnumerable<MonoBehaviour>> instancesLists = new Dictionary<Type, IEnumerable<MonoBehaviour>>();

		public static void Add<T>([NotNull] T instance) where T : MonoBehaviour
		{
			TypeData<T>.Add(instance);
		}

		public static void Remove<T>([NotNull] T instance) where T : MonoBehaviour
		{
			TypeData<T>.Remove(instance);
		}

		[NotNull]
		public static List<T> GetInstancesList<T>() where T : MonoBehaviour
		{
			return TypeData<T>.instancesList;
		}

		public static T FirstOrNull<T>() where T : MonoBehaviour
		{
			if (TypeData<T>.instancesList.Count == 0)
			{
				return null;
			}
			return TypeData<T>.instancesList[0];
		}

		public static bool Any<T>() where T : MonoBehaviour
		{
			return TypeData<T>.instancesList.Count != 0;
		}

		[NotNull]
		public static IEnumerable<MonoBehaviour> FindInstancesEnumerable([NotNull] Type t)
		{
			if (!instancesLists.TryGetValue(t, out var value))
			{
				return Enumerable.Empty<MonoBehaviour>();
			}
			return value;
		}
	}
	public readonly struct IntFraction : IEquatable<IntFraction>
	{
		public readonly int numerator;

		public readonly int denominator;

		public IntFraction(int numerator, int denominator)
		{
			this.numerator = numerator;
			this.denominator = denominator;
		}

		public override string ToString()
		{
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			AppendToStringBuilder(stringBuilder);
			string result = stringBuilder.ToString();
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			return result;
		}

		public void AppendToStringBuilder(StringBuilder stringBuilder)
		{
			stringBuilder.AppendInt(numerator).Append("/").AppendInt(denominator);
		}

		private static bool TryParse(string str, int startIndex, int length, out int result)
		{
			result = 0;
			int i = startIndex;
			int num = startIndex + length;
			if (startIndex < 0 || str.Length < num)
			{
				return false;
			}
			bool flag = false;
			if (i < num && str[i] == '-')
			{
				flag = true;
				i++;
			}
			if (i >= num || !char.IsDigit(str[i]))
			{
				return false;
			}
			for (; i < num; i++)
			{
				int num2 = str[i] - 48;
				if (num2 <= 0 || num2 >= 10)
				{
					break;
				}
				result *= 10;
				result += num2;
			}
			if (flag)
			{
				result = -result;
			}
			return true;
		}

		public static bool TryParse(string str, out IntFraction result)
		{
			result = default(IntFraction);
			int num = 0;
			int num2 = str.IndexOf('/');
			if (num2 == -1)
			{
				return false;
			}
			if (!TryParse(str, 0, num2, out var result2))
			{
				return false;
			}
			num = num2 + 1;
			num2 = str.Length - num;
			if (!TryParse(str, num, str.Length - num2, out var result3))
			{
				return false;
			}
			result = new IntFraction(result2, result3);
			return true;
		}

		public bool Equals(IntFraction other)
		{
			if (numerator == other.numerator)
			{
				return denominator == other.denominator;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is IntFraction other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (numerator * 397) ^ denominator;
		}

		public static explicit operator float(in IntFraction value)
		{
			return (float)value.numerator / (float)value.denominator;
		}
	}
	public enum ItemIndex
	{
		None = -1,
		Count
	}
	[Serializable]
	public class ItemMask : ICollection<ItemIndex>, IEnumerable<ItemIndex>, IEnumerable
	{
		public struct Enumerator : IEnumerator<ItemIndex>, IEnumerator, IDisposable
		{
			private bool[] target;

			public ItemIndex Current { get; private set; }

			object IEnumerator.Current => Current;

			public Enumerator(bool[] array)
			{
				Current = ItemIndex.None;
				target = array;
			}

			public bool MoveNext()
			{
				ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount;
				while (Current < itemCount)
				{
					if (target[(int)Current])
					{
						return true;
					}
					ItemIndex current = Current + 1;
					Current = current;
				}
				return false;
			}

			public void Reset()
			{
				Current = ItemIndex.None;
			}

			public void Dispose()
			{
			}
		}

		private readonly bool[] array;

		public int Count => array.Length;

		public bool IsReadOnly => false;

		public ItemMask()
		{
			array = new bool[ItemCatalog.itemCount];
		}

		public static ItemMask Rent()
		{
			return CollectionPool<ItemIndex, ItemMask>.RentCollection();
		}

		public static void Return(ItemMask itemMask)
		{
			if (itemMask.array.Length == ItemCatalog.itemCount)
			{
				CollectionPool<ItemIndex, ItemMask>.ReturnCollection(itemMask);
			}
		}

		public bool Contains(ItemIndex itemIndex)
		{
			bool[] obj = array;
			bool defaultValue = false;
			return ArrayUtils.GetSafe(obj, (int)itemIndex, in defaultValue);
		}

		public void Add(ItemIndex itemIndex)
		{
			if (ArrayUtils.IsInBounds(array, (int)itemIndex))
			{
				array[(int)itemIndex] = true;
			}
		}

		public bool Remove(ItemIndex itemIndex)
		{
			if (ArrayUtils.IsInBounds(array, (int)itemIndex))
			{
				ref bool reference = ref array[(int)itemIndex];
				bool result = reference;
				reference = false;
				return result;
			}
			return false;
		}

		public void Clear()
		{
			bool[] obj = array;
			bool value = false;
			ArrayUtils.SetAll(obj, in value);
		}

		public void CopyTo(ItemIndex[] array, int arrayIndex)
		{
			for (int i = 0; i < this.array.Length; i++)
			{
				if (this.array[i])
				{
					array[arrayIndex++] = (ItemIndex)i;
				}
			}
		}

		public Enumerator GetEnumerator()
		{
			return new Enumerator(array);
		}

		IEnumerator<ItemIndex> IEnumerable<ItemIndex>.GetEnumerator()
		{
			return GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	public enum ItemTier
	{
		Tier1,
		Tier2,
		Tier3,
		Lunar,
		Boss,
		NoTier,
		VoidTier1,
		VoidTier2,
		VoidTier3,
		VoidBoss,
		AssignedAtRuntime
	}
	public enum ItemTag
	{
		Any,
		Damage,
		Healing,
		Utility,
		AIBlacklist,
		Cleansable,
		OnKillEffect,
		EquipmentRelated,
		SprintRelated,
		WorldUnique,
		Scrap,
		BrotherBlacklist,
		CannotSteal,
		CannotCopy,
		PriorityScrap,
		CannotDuplicate,
		LowHealth,
		HoldoutZoneRelated,
		InteractableRelated,
		ObliterationRelated,
		OnStageBeginEffect,
		HalcyoniteShrine,
		RebirthBlacklist,
		Count
	}
	public static class ItemCatalog
	{
		public struct AllItemsEnumerator : IEnumerator<ItemIndex>, IEnumerator, IDisposable
		{
			private ItemIndex position;

			public ItemIndex Current => position;

			object IEnumerator.Current => Current;

			public bool MoveNext()
			{
				position++;
				return (int)position < itemCount;
			}

			public void Reset()
			{
				position = ItemIndex.None;
			}

			void IDisposable.Dispose()
			{
			}
		}

		public static List<ItemIndex> tier1ItemList = new List<ItemIndex>();

		public static List<ItemIndex> tier2ItemList = new List<ItemIndex>();

		public static List<ItemIndex> tier3ItemList = new List<ItemIndex>();

		public static List<ItemIndex> lunarItemList = new List<ItemIndex>();

		public static ResourceAvailability availability = default(ResourceAvailability);

		public static string[] itemNames = Array.Empty<string>();

		private static readonly Dictionary<string, ItemIndex> itemNameToIndex = new Dictionary<string, ItemIndex>();

		private static ItemIndex[][] itemIndicesByTag = Array.Empty<ItemIndex[]>();

		private static Dictionary<ItemRelationshipType, ItemDef.Pair[]> itemRelationships = new Dictionary<ItemRelationshipType, ItemDef.Pair[]>();

		private static readonly Stack<ItemIndex[]> itemOrderBuffers = new Stack<ItemIndex[]>();

		private static readonly Stack<int[]> itemStackArrays = new Stack<int[]>();

		public static readonly GenericStaticEnumerable<ItemIndex, AllItemsEnumerator> allItems;

		public static int itemCount
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (ContentManager._itemDefs == null)
				{
					return 0;
				}
				return ContentManager._itemDefs.Length;
			}
		}

		public static ReadOnlyArray<ItemDef> allItemDefs => ContentManager._itemDefs;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<ItemDef>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.ItemCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.itemDefs);
			}
			remove
			{
			}
		}

		[SystemInitializer(new Type[] { typeof(ItemTierCatalog) })]
		private static void Init()
		{
			HGXml.Register(delegate(XElement element, ItemIndex[] obj)
			{
				element.Value = string.Join(" ", obj.Select((ItemIndex v) => GetItemDef(v)?.name));
			}, delegate(XElement element, ref ItemIndex[] output)
			{
				output = (from v in element.Value.Split(' ')
					select GetItemDef(FindItemIndex(v))?.itemIndex ?? ItemIndex.None).ToArray();
				return true;
			});
			SetItemDefs(ContentManager.itemDefs);
			SetItemRelationships(ContentManager.itemRelationshipProviders);
			availability.MakeAvailable();
		}

		private static void SetItemDefs(ItemDef[] newItemDefs)
		{
			ItemDef[] itemDefs = ContentManager._itemDefs;
			for (int i = 0; i < itemDefs.Length; i++)
			{
				itemDefs[i].itemIndex = ItemIndex.None;
			}
			ArrayUtils.CloneTo(newItemDefs, ref ContentManager._itemDefs);
			itemNameToIndex.Clear();
			itemOrderBuffers.Clear();
			itemStackArrays.Clear();
			Array.Resize(ref itemNames, newItemDefs.Length);
			for (int j = 0; j < newItemDefs.Length; j++)
			{
				itemNames[j] = newItemDefs[j].name;
			}
			Array.Sort(itemNames, ContentManager._itemDefs, StringComparer.Ordinal);
			for (ItemIndex itemIndex = ItemIndex.Count; (int)itemIndex < ContentManager._itemDefs.Length; itemIndex++)
			{
				ItemDef obj = ContentManager._itemDefs[(int)itemIndex];
				string key = itemNames[(int)itemIndex];
				obj.itemIndex = itemIndex;
				switch (obj.tier)
				{
				case ItemTier.Tier1:
					tier1ItemList.Add(itemIndex);
					break;
				case ItemTier.Tier2:
					tier2ItemList.Add(itemIndex);
					break;
				case ItemTier.Tier3:
					tier3ItemList.Add(itemIndex);
					break;
				case ItemTier.Lunar:
					lunarItemList.Add(itemIndex);
					break;
				}
				itemNameToIndex[key] = itemIndex;
			}
			int num = 23;
			Array.Resize(ref itemIndicesByTag, num);
			ItemIndex[][] array = itemIndicesByTag;
			ItemIndex[] value = Array.Empty<ItemIndex>();
			ArrayUtils.SetAll(array, in value);
			List<ItemIndex>[] array2 = new List<ItemIndex>[num];
			for (ItemTag itemTag = ItemTag.Any; (int)itemTag < num; itemTag++)
			{
				array2[(int)itemTag] = CollectionPool<ItemIndex, List<ItemIndex>>.RentCollection();
			}
			for (ItemIndex itemIndex2 = ItemIndex.Count; (int)itemIndex2 < ContentManager._itemDefs.Length; itemIndex2++)
			{
				ItemTag[] tags = ContentManager._itemDefs[(int)itemIndex2].tags;
				foreach (ItemTag itemTag2 in tags)
				{
					array2[(int)itemTag2].Add(itemIndex2);
				}
			}
			for (ItemTag itemTag3 = ItemTag.Any; (int)itemTag3 < num; itemTag3++)
			{
				ref List<ItemIndex> reference = ref array2[(int)itemTag3];
				itemIndicesByTag[(int)itemTag3] = reference.ToArray();
				reference = CollectionPool<ItemIndex, List<ItemIndex>>.ReturnCollection(reference);
			}
		}

		private static void SetItemRelationships(ItemRelationshipProvider[] newProviders)
		{
			Dictionary<ItemRelationshipType, HashSet<ItemDef.Pair>> dictionary = new Dictionary<ItemRelationshipType, HashSet<ItemDef.Pair>>();
			foreach (ItemRelationshipProvider itemRelationshipProvider in newProviders)
			{
				if (!dictionary.ContainsKey(itemRelationshipProvider.relationshipType))
				{
					dictionary.Add(itemRelationshipProvider.relationshipType, new HashSet<ItemDef.Pair>());
				}
				dictionary[itemRelationshipProvider.relationshipType].UnionWith(itemRelationshipProvider.relationships);
			}
			itemRelationships.Clear();
			foreach (KeyValuePair<ItemRelationshipType, HashSet<ItemDef.Pair>> item in dictionary)
			{
				IEnumerable<ItemDef.Pair> enumerable = item.Value.Where((ItemDef.Pair pair) => !pair.itemDef1 || !pair.itemDef2);
				foreach (ItemDef.Pair item2 in enumerable)
				{
					UnityEngine.Debug.LogError("Trying to define a " + item.Key.name + " relationship between " + item2.itemDef1?.name + " and " + item2.itemDef2?.name + ".");
				}
				item.Value.ExceptWith(enumerable);
				itemRelationships.Add(item.Key, item.Value.ToArray());
			}
		}

		public static ItemIndex[] RequestItemOrderBuffer()
		{
			if (itemOrderBuffers.Count > 0)
			{
				return itemOrderBuffers.Pop();
			}
			return new ItemIndex[itemCount];
		}

		public static void ReturnItemOrderBuffer(ItemIndex[] buffer)
		{
			itemOrderBuffers.Push(buffer);
		}

		public static int[] RequestItemStackArray()
		{
			if (itemStackArrays.Count > 0)
			{
				return itemStackArrays.Pop();
			}
			return new int[itemCount];
		}

		public static void ReturnItemStackArray(int[] itemStackArray)
		{
			if (itemStackArray.Length == itemCount)
			{
				Array.Clear(itemStackArray, 0, itemStackArray.Length);
				itemStackArrays.Push(itemStackArray);
			}
		}

		public static ItemDef GetItemDef(ItemIndex itemIndex)
		{
			return ArrayUtils.GetSafe(ContentManager._itemDefs, (int)itemIndex);
		}

		public static ItemIndex FindItemIndex(string itemName)
		{
			if (itemNameToIndex.TryGetValue(itemName, out var value))
			{
				return value;
			}
			return ItemIndex.None;
		}

		public static T[] GetPerItemBuffer<T>()
		{
			return new T[itemCount];
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static bool IsIndexValid(in ItemIndex itemIndex)
		{
			return (uint)itemIndex < (uint)itemCount;
		}

		public static ReadOnlyArray<ItemIndex> GetItemsWithTag(ItemTag itemTag)
		{
			ItemIndex[][] array = itemIndicesByTag;
			ItemIndex[] defaultValue = Array.Empty<ItemIndex>();
			return ArrayUtils.GetSafe(array, (int)itemTag, in defaultValue);
		}

		public static ReadOnlyArray<ItemDef.Pair> GetItemPairsForRelationship(ItemRelationshipType relationshipType)
		{
			if (itemRelationships.ContainsKey(relationshipType))
			{
				return itemRelationships[relationshipType];
			}
			return Array.Empty<ItemDef.Pair>();
		}

		[ConCommand(commandName = "item_list", flags = ConVarFlags.None, helpText = "Lists internal names of all items registered to the item catalog.")]
		private static void CCEquipmentList(ConCommandArgs args)
		{
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			ItemDef[] itemDefs = ContentManager._itemDefs;
			foreach (ItemDef itemDef in itemDefs)
			{
				string colorHexString = ColorCatalog.GetColorHexString(itemDef.colorIndex);
				stringBuilder.AppendLine("<color=#" + colorHexString + ">" + itemDef.name + "  (" + Language.GetString(itemDef.nameToken) + ")</color>");
			}
			args.Log(stringBuilder.ToString());
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}

		private static void DefineItems()
		{
		}
	}
	[Serializable]
	public struct ItemCountPair
	{
		public ItemDef itemDef;

		public int count;
	}
	public class IncreaseDamageOnMultiKillItemDisplayUpdater : MonoBehaviour
	{
		private CharacterBody body;

		[SerializeField]
		private TextMeshPro textMesh;

		private void Start()
		{
			body = GetComponentInParent<CharacterModel>().body;
			body.increaseDamageOnMultiKillItemDisplayUpdater = this;
		}

		public void UpdateKillCounterText(int killCounter)
		{
			string text = killCounter.ToString();
			string text2 = "00";
			if (killCounter > 9)
			{
				text2 = "0";
			}
			else if (killCounter > 99)
			{
				text2 = "";
			}
			else if (killCounter > 999)
			{
				text2 = "G0D";
				text = "";
			}
			text = text2 + text;
			textMesh.text = text;
		}
	}
	public class IncreasePrimaryDamageEffectUpdater : MonoBehaviour
	{
		private CharacterBody body;

		[SerializeField]
		private MeshRenderer shotRingTop;

		[SerializeField]
		private MeshRenderer shotRingMiddle;

		[SerializeField]
		private MeshRenderer shotRingBottom;

		[SerializeField]
		private Material luminousEnergyMaterial;

		[SerializeField]
		private Material unlitEnergyMaterial;

		private void OnEnable()
		{
			body = GetComponentInParent<CharacterModel>().body;
			CharacterBody characterBody = body;
			characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Combine(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
		}

		private void OnDisable()
		{
			if ((bool)body)
			{
				CharacterBody characterBody = body;
				characterBody.OnNetworkItemBehaviorUpdate = (Action<CharacterBody.NetworkItemBehaviorData>)Delegate.Remove(characterBody.OnNetworkItemBehaviorUpdate, new Action<CharacterBody.NetworkItemBehaviorData>(HandleNetworkItemUpdate));
			}
		}

		private void HandleNetworkItemUpdate(CharacterBody.NetworkItemBehaviorData itemBehaviorData)
		{
			if (itemBehaviorData.itemIndex == DLC2Content.Items.IncreasePrimaryDamage.itemIndex)
			{
				LightUpRings((int)itemBehaviorData.floatValue);
			}
		}

		public void LightUpRings(int ringsToLight)
		{
			if (ringsToLight == 0)
			{
				shotRingBottom.material = unlitEnergyMaterial;
				shotRingMiddle.material = unlitEnergyMaterial;
				shotRingTop.material = unlitEnergyMaterial;
				return;
			}
			if (ringsToLight >= 1)
			{
				shotRingBottom.material = luminousEnergyMaterial;
			}
			if (ringsToLight >= 2)
			{
				shotRingMiddle.material = luminousEnergyMaterial;
			}
			if (ringsToLight >= 3)
			{
				shotRingTop.material = luminousEnergyMaterial;
			}
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/IncreasePrimaryDamageDisplayCrackle"), new EffectData
			{
				origin = base.gameObject.transform.position
			}, transmit: false);
		}
	}
	public static class MissileUtils
	{
		public static void FireMissile(UnityEngine.Vector3 position, CharacterBody attackerBody, ProcChainMask procChainMask, GameObject victim, float missileDamage, bool isCrit, GameObject projectilePrefab, DamageColorIndex damageColorIndex, bool addMissileProc)
		{
			FireMissile(position, attackerBody, procChainMask, victim, missileDamage, isCrit, projectilePrefab, damageColorIndex, UnityEngine.Vector3.up + UnityEngine.Random.insideUnitSphere * 0.1f, 200f, addMissileProc);
		}

		public static void FireMissile(UnityEngine.Vector3 position, CharacterBody attackerBody, ProcChainMask procChainMask, GameObject victim, float missileDamage, bool isCrit, GameObject projectilePrefab, DamageColorIndex damageColorIndex, UnityEngine.Vector3 initialDirection, float force, bool addMissileProc)
		{
			int valueOrDefault = (attackerBody?.inventory?.GetItemCount(DLC1Content.Items.MoreMissile)).GetValueOrDefault();
			float num = Mathf.Max(1f, 1f + 0.5f * (float)(valueOrDefault - 1));
			InputBankTest component = attackerBody.GetComponent<InputBankTest>();
			ProcChainMask procChainMask2 = procChainMask;
			if (addMissileProc)
			{
				procChainMask2.AddProc(ProcType.Missile);
			}
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = projectilePrefab;
			fireProjectileInfo.position = position;
			fireProjectileInfo.rotation = Util.QuaternionSafeLookRotation(initialDirection);
			fireProjectileInfo.procChainMask = procChainMask2;
			fireProjectileInfo.target = victim;
			fireProjectileInfo.owner = attackerBody.gameObject;
			fireProjectileInfo.damage = missileDamage * num;
			fireProjectileInfo.crit = isCrit;
			fireProjectileInfo.force = force;
			fireProjectileInfo.damageColorIndex = damageColorIndex;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			if (valueOrDefault > 0)
			{
				UnityEngine.Vector3 axis = (component ? component.aimDirection : attackerBody.transform.position);
				FireProjectileInfo fireProjectileInfo3 = fireProjectileInfo2;
				fireProjectileInfo3.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Quaternion.AngleAxis(45f, axis) * initialDirection);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo3);
				FireProjectileInfo fireProjectileInfo4 = fireProjectileInfo2;
				fireProjectileInfo4.rotation = Util.QuaternionSafeLookRotation(UnityEngine.Quaternion.AngleAxis(-45f, axis) * initialDirection);
				ProjectileManager.instance.FireProjectile(fireProjectileInfo4);
			}
		}
	}
	public class OnLevelUpFreeUnlocksBodyBehavior : MonoBehaviour
	{
		public ParticleSystem onLevelUpFreeUnlocksFire;

		private void OnEnable()
		{
			GlobalEventManager.onCharacterLevelUp += BurstOfFire;
		}

		private void OnDisable()
		{
			GlobalEventManager.onCharacterLevelUp -= BurstOfFire;
		}

		private void BurstOfFire(CharacterBody characterBody)
		{
			ParticleSystem.EmissionModule emission = onLevelUpFreeUnlocksFire.emission;
			emission.rateOverTime = 50f;
			emission.rateOverTime = 5f;
			EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/OnLevelUpFreeUnlockDroneFlash"), new EffectData
			{
				origin = base.gameObject.transform.position
			}, transmit: true);
			Util.PlaySound("Play_item_proc_onLevelUpFreeUnlock_activate", base.gameObject);
		}
	}
	public static class StrengthenBurnUtils
	{
		public static void CheckDotForUpgrade(Inventory inventory, ref InflictDotInfo dotInfo)
		{
			if (dotInfo.dotIndex == DotController.DotIndex.Burn || dotInfo.dotIndex == DotController.DotIndex.Helfire)
			{
				int itemCount = inventory.GetItemCount(DLC1Content.Items.StrengthenBurn);
				if (itemCount > 0)
				{
					dotInfo.preUpgradeDotIndex = dotInfo.dotIndex;
					dotInfo.dotIndex = DotController.DotIndex.StrongerBurn;
					float num = 1 + 3 * itemCount;
					dotInfo.damageMultiplier *= num;
					dotInfo.totalDamage *= num;
				}
			}
		}
	}
	public static class ItemTierCatalog
	{
		private static ItemTierDef[] itemTierDefs = Array.Empty<ItemTierDef>();

		public static ResourceAvailability availability = default(ResourceAvailability);

		private static readonly Dictionary<ItemTier, ItemTierDef> itemTierToDef = new Dictionary<ItemTier, ItemTierDef>();

		public static ReadOnlyArray<ItemTierDef> allItemTierDefs => itemTierDefs;

		public static int itemCount => itemTierDefs.Length;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			ArrayUtils.CloneTo(ContentManager.itemTierDefs, ref itemTierDefs);
			itemTierToDef.Clear();
			int num = 0;
			ItemTierDef[] array = itemTierDefs;
			foreach (ItemTierDef itemTierDef in array)
			{
				if (itemTierDef.tier == ItemTier.AssignedAtRuntime)
				{
					itemTierDef.tier = (ItemTier)(++num + 10);
				}
				if (itemTierToDef.ContainsKey(itemTierDef.tier))
				{
					UnityEngine.Debug.LogError($"Duplicate TierDef for tier {itemTierDef.tier}");
				}
				else
				{
					itemTierToDef.Add(itemTierDef.tier, itemTierDef);
				}
			}
			availability.MakeAvailable();
		}

		public static ItemTierDef GetItemTierDef(ItemTier itemTier)
		{
			if (itemTierToDef.TryGetValue(itemTier, out var value))
			{
				return value;
			}
			return null;
		}

		public static ItemTierDef FindTierDef(string tierName)
		{
			ItemTierDef[] array = itemTierDefs;
			foreach (ItemTierDef itemTierDef in array)
			{
				if (itemTierDef.name == tierName)
				{
					return itemTierDef;
				}
			}
			return null;
		}
	}
	public class Language
	{
		public class LanguageLoaderCoroutine
		{
			private Language language;

			public LanguageLoaderCoroutine(Language language)
			{
				this.language = language;
			}

			public IEnumerator LoadStringsWithYield()
			{
				if (!language.stringsLoaded)
				{
					language.stringsLoaded = true;
					List<KeyValuePair<string, string>> tokenStringPairs = new List<KeyValuePair<string, string>>();
					LoadAllTokensFromFolders(language.folders, tokenStringPairs);
					yield return null;
					yield return SetStringsByTokenYield(tokenStringPairs);
				}
			}

			private IEnumerator SetStringsByTokenYield(List<KeyValuePair<string, string>> tokenStringPairs)
			{
				int maxStringsPerYield = 200;
				int stringsThisYield = 0;
				foreach (KeyValuePair<string, string> tokenStringPair in tokenStringPairs)
				{
					language.SetStringByToken(tokenStringPair.Key, tokenStringPair.Value);
					if (stringsThisYield++ >= maxStringsPerYield)
					{
						stringsThisYield = 0;
						yield return null;
					}
				}
			}
		}

		private struct SteamLanguageDef
		{
			public readonly string englishName;

			public readonly string nativeName;

			public readonly string apiName;

			public readonly string webApiName;

			public SteamLanguageDef(string englishName, string nativeName, string apiName, string webApiName)
			{
				this.englishName = englishName;
				this.nativeName = nativeName;
				this.apiName = apiName;
				this.webApiName = webApiName;
			}
		}

		public class LanguageConVar : BaseConVar
		{
			private static readonly string platformString = "platform";

			public static LanguageConVar instance = new LanguageConVar("language", ConVarFlags.Archive, platformString, "Which language to use.");

			private string internalValue = platformString;

			public LanguageConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (!IsAnyLanguageLoaded())
				{
					internalValue = newValue;
					return;
				}
				if (string.Equals(newValue, "EN_US", StringComparison.Ordinal) || FindLanguageByName(newValue) == null)
				{
					newValue = platformString;
				}
				internalValue = newValue;
				if (string.Equals(internalValue, platformString, StringComparison.Ordinal))
				{
					newValue = GetPlatformLanguageName() ?? "en";
				}
				SetCurrentLanguage(newValue);
			}

			public override string GetString()
			{
				return internalValue;
			}
		}

		private static readonly Dictionary<string, Language> languagesByName = new Dictionary<string, Language>(StringComparer.OrdinalIgnoreCase);

		private static bool isDebugStringOverrideEnabled = false;

		private static bool isDummyStringOverrideEnabled = false;

		private static string dummyString = ".•.";

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

		private Language fallbackLanguage;

		private string[] folders = Array.Empty<string>();

		private bool foundManifest;

		public readonly string name;

		private static readonly Dictionary<string, SteamLanguageDef> steamLanguageTable = new Dictionary<string, SteamLanguageDef>(StringComparer.OrdinalIgnoreCase)
		{
			["arabic"] = new SteamLanguageDef("Arabic", "العربية", "arabic", "ar"),
			["bulgarian"] = new SteamLanguageDef("Bulgarian", "български език", "bulgarian", "bg"),
			["schinese"] = new SteamLanguageDef("Chinese (Simplified)", "简体中文", "schinese", "zh-CN"),
			["tchinese"] = new SteamLanguageDef("Chinese (Traditional)", "繁體中文", "tchinese", "zh-TW"),
			["czech"] = new SteamLanguageDef("Czech", "čeština", "czech", "cs"),
			["danish"] = new SteamLanguageDef("Danish", "Dansk", "danish", "da"),
			["dutch"] = new SteamLanguageDef("Dutch", "Nederlands", "dutch", "nl"),
			["english"] = new SteamLanguageDef("English", "English", "english", "en"),
			["finnish"] = new SteamLanguageDef("Finnish", "Suomi", "finnish", "fi"),
			["french"] = new SteamLanguageDef("French", "Français", "french", "fr"),
			["german"] = new SteamLanguageDef("German", "Deutsch", "german", "de"),
			["greek"] = new SteamLanguageDef("Greek", "Ελληνικά", "greek", "el"),
			["hungarian"] = new SteamLanguageDef("Hungarian", "Magyar", "hungarian", "hu"),
			["italian"] = new SteamLanguageDef("Italian", "Italiano", "italian", "it"),
			["japanese"] = new SteamLanguageDef("Japanese", "日本語", "japanese", "ja"),
			["koreana"] = new SteamLanguageDef("Korean", "한국어", "koreana", "ko"),
			["korean"] = new SteamLanguageDef("Korean", "한국어", "korean", "ko"),
			["norwegian"] = new SteamLanguageDef("Norwegian", "Norsk", "norwegian", "no"),
			["polish"] = new SteamLanguageDef("Polish", "Polski", "polish", "pl"),
			["portuguese"] = new SteamLanguageDef("Portuguese", "Português", "portuguese", "pt"),
			["brazilian"] = new SteamLanguageDef("Portuguese-Brazil", "Português-Brasil", "brazilian", "pt-BR"),
			["romanian"] = new SteamLanguageDef("Romanian", "Română", "romanian", "ro"),
			["russian"] = new SteamLanguageDef("Russian", "Русский", "russian", "ru"),
			["spanish"] = new SteamLanguageDef("Spanish-Spain", "Español-España", "spanish", "es"),
			["latam"] = new SteamLanguageDef("Spanish-Latin America", "Español-Latinoamérica", "latam", "es-419"),
			["swedish"] = new SteamLanguageDef("Swedish", "Svenska", "swedish", "sv"),
			["thai"] = new SteamLanguageDef("Thai", "ไทย", "thai", "th"),
			["turkish"] = new SteamLanguageDef("Turkish", "Türkçe", "turkish", "tr"),
			["ukrainian"] = new SteamLanguageDef("Ukrainian", "Українська", "ukrainian", "uk"),
			["vietnamese"] = new SteamLanguageDef("Vietnamese", "Tiếng Việt", "vietnamese", "vn")
		};

		public string selfName { get; private set; } = string.Empty;


		public Sprite iconSprite { get; private set; }

		public bool stringsLoaded { get; private set; }

		public bool hasEntries => stringsByToken.Count > 0;

		public static string currentLanguageName { get; private set; } = "";


		public static Language currentLanguage { get; private set; } = null;


		public static Language english { get; private set; }

		public static event Action onCurrentLanguageChanged;

		public static event Action<List<string>> collectLanguageRootFolders;

		private Language()
		{
		}

		private Language(string name)
		{
			this.name = name;
		}

		private void SetFolders([NotNull] IEnumerable<string> newFolders)
		{
			folders = newFolders.ToArray();
			foundManifest = false;
			for (int num = folders.Length - 1; num >= 0; num--)
			{
				string path = folders[num];
				if (Directory.Exists(path))
				{
					string text = Directory.EnumerateFiles(path, "language.json").FirstOrDefault();
					foundManifest |= text != null;
					if (text != null)
					{
						LoadManifest(text);
					}
					string text2 = Directory.EnumerateFiles(path, "icon.png").FirstOrDefault();
					if (text2 != null)
					{
						SetIconSprite(BuildSpriteFromTextureFile(text2));
						break;
					}
				}
			}
		}

		private void SetIconSprite(Sprite newIconSprite)
		{
			if ((bool)iconSprite)
			{
				UnityEngine.Object.Destroy(iconSprite.texture);
				UnityEngine.Object.Destroy(iconSprite);
			}
			iconSprite = newIconSprite;
		}

		private void LoadManifest(string file)
		{
			using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read);
			using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
			JSONNode jSONNode = JSON.Parse(streamReader.ReadToEnd());
			if (!(jSONNode != null))
			{
				return;
			}
			JSONNode jSONNode2 = jSONNode["language"];
			if (jSONNode2 != null)
			{
				string text = jSONNode2["selfname"];
				if (text != null)
				{
					selfName = text;
				}
			}
		}

		[NotNull]
		public string GetLocalizedStringByToken([NotNull] string token)
		{
			if (isDummyStringOverrideEnabled)
			{
				return dummyString;
			}
			if (isDebugStringOverrideEnabled)
			{
				return token;
			}
			if (stringsByToken.TryGetValue(token, out var value))
			{
				return value;
			}
			if (fallbackLanguage != null)
			{
				return fallbackLanguage.GetLocalizedStringByToken(token);
			}
			return token;
		}

		[NotNull]
		public string GetLocalizedFormattedStringByToken([NotNull] string token, params object[] args)
		{
			return string.Format(GetLocalizedStringByToken(token), args);
		}

		public void SetStringByToken([NotNull] string token, [NotNull] string localizedString)
		{
			stringsByToken[token] = localizedString;
		}

		public void SetStringsByTokens([NotNull] IEnumerable<KeyValuePair<string, string>> tokenPairs)
		{
			foreach (KeyValuePair<string, string> tokenPair in tokenPairs)
			{
				SetStringByToken(tokenPair.Key, tokenPair.Value);
			}
		}

		public void LoadStrings()
		{
			if (!stringsLoaded)
			{
				stringsLoaded = true;
				List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
				LoadAllTokensFromFolders(folders, list);
				SetStringsByTokens(list);
			}
		}

		public void UnloadStrings()
		{
			if (stringsLoaded)
			{
				stringsLoaded = false;
				stringsByToken.Clear();
			}
		}

		public bool TokenIsRegistered([NotNull] string token)
		{
			return stringsByToken.ContainsKey(token);
		}

		[CanBeNull]
		public static Language FindLanguageByName([NotNull] string languageName)
		{
			if (languagesByName.TryGetValue(languageName, out var value))
			{
				return value;
			}
			return null;
		}

		[NotNull]
		public static string GetString([NotNull] string token, [NotNull] string language)
		{
			return FindLanguageByName(language)?.GetLocalizedStringByToken(token) ?? token;
		}

		[NotNull]
		public static string GetString([NotNull] string token)
		{
			return currentLanguage?.GetLocalizedStringByToken(token) ?? token;
		}

		[NotNull]
		public static string GetStringFormatted([NotNull] string token, params object[] args)
		{
			return currentLanguage?.GetLocalizedFormattedStringByToken(token, args) ?? string.Format(token, args);
		}

		public static bool IsTokenInvalid([NotNull] string token)
		{
			return !(currentLanguage?.TokenIsRegistered(token) ?? false);
		}

		public static IEnumerable<Language> GetAllLanguages()
		{
			return languagesByName.Values;
		}

		[NotNull]
		private static Language GetOrCreateLanguage([NotNull] string languageName)
		{
			if (!languagesByName.TryGetValue(languageName, out var value))
			{
				value = (languagesByName[languageName] = new Language(languageName));
			}
			return value;
		}

		private static void LoadAllTokensFromFolders([NotNull] IEnumerable<string> folders, [NotNull] List<KeyValuePair<string, string>> output)
		{
			foreach (string folder in folders)
			{
				LoadAllTokensFromFolder(folder, output);
			}
		}

		private static void LoadAllTokensFromFolder([NotNull] string folder, [NotNull] List<KeyValuePair<string, string>> output)
		{
			PlatformSystems.textDataManager.GetLocFiles(folder, delegate(string[] contents)
			{
				int num = contents.Length;
				for (int i = 0; i < num; i++)
				{
					LoadTokensFromData(contents[i], output);
				}
			});
		}

		private static void LoadTokensFromData([NotNull] string contents, [NotNull] List<KeyValuePair<string, string>> output)
		{
			JSONNode jSONNode = JSON.Parse(contents);
			if (!(jSONNode != null))
			{
				return;
			}
			JSONNode jSONNode2 = jSONNode["strings"];
			if (!(jSONNode2 != null))
			{
				return;
			}
			foreach (string key in jSONNode2.Keys)
			{
				output.Add(new KeyValuePair<string, string>(key, jSONNode2[key].Value));
			}
		}

		private static void LoadTokensFromFile([NotNull] string file, [NotNull] List<KeyValuePair<string, string>> output)
		{
			using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read);
			using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
			JSONNode jSONNode = JSON.Parse(streamReader.ReadToEnd());
			if (!(jSONNode != null))
			{
				return;
			}
			JSONNode jSONNode2 = jSONNode["strings"];
			if (!(jSONNode2 != null))
			{
				return;
			}
			foreach (string key in jSONNode2.Keys)
			{
				output.Add(new KeyValuePair<string, string>(key, jSONNode2[key].Value));
			}
		}

		[NotNull]
		private static List<string> GetLanguageRootFolders()
		{
			List<string> list = new List<string>();
			try
			{
				Language.collectLanguageRootFolders?.Invoke(list);
			}
			catch (Exception ex)
			{
				UnityEngine.Debug.LogErrorFormat("Encountered error loading language folders: {0}", ex);
			}
			return list;
		}

		private static IEnumerator BuildLanguagesFromFolders()
		{
			List<string> languageRootFolders = GetLanguageRootFolders();
			IGrouping<string, string>[] allLanguageFolderGroups = languageRootFolders.Where((string i) => Directory.Exists(i)).SelectMany((string languageRootFolder) => Directory.EnumerateDirectories(languageRootFolder)).GroupBy((string languageRootFolder) => new DirectoryInfo(languageRootFolder).Name, StringComparer.OrdinalIgnoreCase)
				.ToArray();
			yield return null;
			IGrouping<string, string>[] array = allLanguageFolderGroups;
			foreach (IGrouping<string, string> grouping in array)
			{
				Language orCreateLanguage = GetOrCreateLanguage(grouping.Key);
				orCreateLanguage.SetFolders(grouping);
				if (!orCreateLanguage.foundManifest)
				{
					languagesByName.Remove(grouping.Key);
				}
			}
			yield return null;
		}

		private static bool IsAnyLanguageLoaded()
		{
			return languagesByName.Count > 0;
		}

		private static void SetCurrentLanguage([NotNull] string newCurrentLanguageName)
		{
			UnityEngine.Debug.LogFormat("Setting current language to \"{0}\"", newCurrentLanguageName);
			if (currentLanguage != english)
			{
				currentLanguage?.UnloadStrings();
			}
			currentLanguageName = newCurrentLanguageName;
			currentLanguage = FindLanguageByName(currentLanguageName);
			if (currentLanguage == null && string.Compare(currentLanguageName, "en", StringComparison.OrdinalIgnoreCase) != 0)
			{
				UnityEngine.Debug.LogFormat("Could not load files for language \"{0}\". Falling back to \"en\".", newCurrentLanguageName);
				currentLanguageName = "en";
				currentLanguage = FindLanguageByName(currentLanguageName);
			}
			CultureInfo.CurrentCulture = new CultureInfo(currentLanguage.name);
			currentLanguage?.LoadStrings();
			Language.onCurrentLanguageChanged?.Invoke();
		}

		public static IEnumerator Init()
		{
			yield return BuildLanguagesFromFolders();
			if (LanguageConVar.instance != null)
			{
				LanguageConVar.instance.SetString(LanguageConVar.instance.GetString());
			}
			english = GetOrCreateLanguage("en");
			LanguageLoaderCoroutine languageLoaderCoroutine = new LanguageLoaderCoroutine(english);
			yield return languageLoaderCoroutine.LoadStringsWithYield();
			foreach (Language allLanguage in GetAllLanguages())
			{
				if (allLanguage != english)
				{
					allLanguage.fallbackLanguage = english;
				}
			}
		}

		private static Sprite BuildSpriteFromTextureFile(string file)
		{
			Texture2D texture2D = new Texture2D(2, 2, TextureFormat.ARGB32, mipChain: false, linear: false);
			texture2D.wrapMode = TextureWrapMode.Clamp;
			texture2D.LoadImage(File.ReadAllBytes(file), markNonReadable: true);
			return Sprite.Create(texture2D, new UnityEngine.Rect(0f, 0f, texture2D.width, texture2D.height), new UnityEngine.Vector2(0.5f, 0.5f), 1f, 1u, SpriteMeshType.FullRect, UnityEngine.Vector4.zero);
		}

		[CanBeNull]
		public static string GetPlatformLanguageName()
		{
			string text = Client.Instance?.CurrentLanguage;
			if (text == null)
			{
				return null;
			}
			if (steamLanguageTable.TryGetValue(text, out var value))
			{
				return value.webApiName;
			}
			return null;
		}

		[ConCommand(commandName = "language_reload", flags = ConVarFlags.None, helpText = "Reloads the current language.")]
		public static void CCLanguageReload(ConCommandArgs args)
		{
			SetCurrentLanguage(currentLanguageName);
		}

		[ConCommand(commandName = "language_dump_to_json", flags = ConVarFlags.None, helpText = "Combines all files for the given language into a single JSON file.")]
		private static void CCLanguageDumpToJson(ConCommandArgs args)
		{
			string argString = args.GetArgString(0);
			Language obj = FindLanguageByName(argString) ?? throw new ConCommandException($"'{argString}' is not a valid language name.");
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
			LoadAllTokensFromFolders(obj.folders, list);
			new StringBuilder();
			JSONNode jSONNode = new JSONObject();
			JSONNode jSONNode3 = (jSONNode["strings"] = new JSONObject());
			foreach (KeyValuePair<string, string> item in list)
			{
				jSONNode3[item.Key] = item.Value;
			}
			File.WriteAllText("output.json", jSONNode.ToString(1), Encoding.UTF8);
		}

		[ConCommand(commandName = "language_dummy_strings", flags = ConVarFlags.None, helpText = "Toggles use of a dummy string for all text")]
		private static void CCLanguageDummyStringsToggle(ConCommandArgs args)
		{
			isDummyStringOverrideEnabled = !isDummyStringOverrideEnabled;
		}

		[ConCommand(commandName = "language_debug_strings", flags = ConVarFlags.None, helpText = "Toggles use of debug strings for all text")]
		private static void CCLanguageDebugStringsToggle(ConCommandArgs args)
		{
			isDebugStringOverrideEnabled = !isDebugStringOverrideEnabled;
			UnityEngine.Debug.Log($"isDummyStringOverrideEnabled={isDummyStringOverrideEnabled}");
		}
	}
	public struct LayerIndex
	{
		public static class CommonMasks
		{
			public static readonly LayerMask bullet = (int)world.mask | (int)entityPrecise.mask;

			public static readonly LayerMask laser = (int)world.mask | (int)characterBodiesOrDefault | (int)entityPrecise.mask;

			public static readonly LayerMask interactable = (int)defaultLayer.mask | (int)world.mask | (int)pickups.mask;

			public static readonly LayerMask characterBodies = (int)playerBody.mask | (int)enemyBody.mask;

			public static readonly LayerMask characterBodiesOrDefault = (int)defaultLayer.mask | (int)characterBodies;

			public static readonly LayerMask fakeActorLayers = (int)fakeActor.mask | (int)playerFakeActor.mask;
		}

		public int intVal;

		private static uint assignedLayerMask;

		public static readonly LayerIndex invalidLayer;

		public static readonly LayerIndex defaultLayer;

		public static readonly LayerIndex transparentFX;

		public static readonly LayerIndex ignoreRaycast;

		public static readonly LayerIndex water;

		public static readonly LayerIndex ui;

		public static readonly LayerIndex fakeActor;

		public static readonly LayerIndex playerFakeActor;

		public static readonly LayerIndex noCollision;

		public static readonly LayerIndex pickups;

		public static readonly LayerIndex world;

		public static readonly LayerIndex entityPrecise;

		public static readonly LayerIndex debris;

		public static readonly LayerIndex projectile;

		public static readonly LayerIndex manualRender;

		public static readonly LayerIndex collideWithCharacterHullOnly;

		public static readonly LayerIndex ragdoll;

		public static readonly LayerIndex noDraw;

		public static readonly LayerIndex prefabBrush;

		public static readonly LayerIndex postProcess;

		public static readonly LayerIndex uiWorldSpace;

		public static readonly LayerIndex projectileWorldOnly;

		public static readonly string modderMessage;

		public static readonly LayerIndex playerBody;

		public static readonly LayerIndex enemyBody;

		public static readonly LayerIndex triggerZone;

		public static readonly LayerIndex enemyBarrier;

		private static readonly LayerMask[] collisionMasks;

		public LayerMask mask => (intVal >= 0) ? (1 << intVal) : intVal;

		public LayerMask collisionMask => collisionMasks[intVal];

		static LayerIndex()
		{
			assignedLayerMask = 0u;
			invalidLayer = new LayerIndex
			{
				intVal = -1
			};
			defaultLayer = GetLayerIndex("Default");
			transparentFX = GetLayerIndex("TransparentFX");
			ignoreRaycast = GetLayerIndex("Ignore Raycast");
			water = GetLayerIndex("Water");
			ui = GetLayerIndex("UI");
			fakeActor = GetLayerIndex("FakeActor");
			playerFakeActor = GetLayerIndex("PlayerFakeActor");
			noCollision = GetLayerIndex("NoCollision");
			pickups = GetLayerIndex("Pickups");
			world = GetLayerIndex("World");
			entityPrecise = GetLayerIndex("EntityPrecise");
			debris = GetLayerIndex("Debris");
			projectile = GetLayerIndex("Projectile");
			manualRender = GetLayerIndex("ManualRender");
			collideWithCharacterHullOnly = GetLayerIndex("CollideWithCharacterHullOnly");
			ragdoll = GetLayerIndex("Ragdoll");
			noDraw = GetLayerIndex("NoDraw");
			prefabBrush = GetLayerIndex("PrefabBrush");
			postProcess = GetLayerIndex("PostProcess");
			uiWorldSpace = GetLayerIndex("UI, WorldSpace");
			projectileWorldOnly = GetLayerIndex("ProjectileWorldOnly");
			modderMessage = "Layers below are used only by console versions.";
			playerBody = GetLayerIndex("PlayerBody");
			enemyBody = GetLayerIndex("EnemyBody");
			triggerZone = GetLayerIndex("TriggerZone");
			enemyBarrier = GetLayerIndex("EnemyBarrier");
			collisionMasks = CalcCollisionMasks();
			for (int i = 0; i < 32; i++)
			{
				string text = LayerMask.LayerToName(i);
				if (text != "" && (assignedLayerMask & (uint)(1 << i)) == 0)
				{
					UnityEngine.Debug.LogWarningFormat("Layer \"{0}\" is defined in this project's \"Tags and Layers\" settings but is not defined in LayerIndex!", text);
				}
			}
		}

		private static LayerIndex GetLayerIndex(string layerName)
		{
			LayerIndex layerIndex = default(LayerIndex);
			layerIndex.intVal = LayerMask.NameToLayer(layerName);
			LayerIndex result = layerIndex;
			if (result.intVal == invalidLayer.intVal)
			{
				UnityEngine.Debug.LogErrorFormat("Layer \"{0}\" is not defined in this project's \"Tags and Layers\" settings.", layerName);
			}
			else
			{
				assignedLayerMask |= (uint)(1 << result.intVal);
			}
			return result;
		}

		private static LayerMask[] CalcCollisionMasks()
		{
			LayerMask[] array = new LayerMask[32];
			for (int i = 0; i < 32; i++)
			{
				LayerMask layerMask = default(LayerMask);
				for (int j = 0; j < 32; j++)
				{
					if (!Physics.GetIgnoreLayerCollision(i, j))
					{
						layerMask = (int)layerMask | (1 << j);
					}
				}
				array[i] = layerMask;
			}
			return array;
		}

		public static int GetAppropriateLayerForTeam(TeamIndex teamIndex)
		{
			switch (teamIndex)
			{
			case TeamIndex.Player:
				return playerBody.intVal;
			case TeamIndex.Monster:
			case TeamIndex.Lunar:
				return enemyBody.intVal;
			default:
				return defaultLayer.intVal;
			}
		}

		public static LayerIndex GetAppropriateFakeLayerForTeam(TeamIndex teamIndex)
		{
			if (teamIndex == TeamIndex.Player)
			{
				return playerFakeActor;
			}
			return fakeActor;
		}
	}
	public class LevelUpEffectManager
	{
		private static float levelUpEffectInterval = 0.25f;

		private static float levelUpEffectJitter = 0.25f;

		private static int pendingLevelUpEffects = 0;

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			GlobalEventManager.onTeamLevelUp += OnTeamLevelUp;
			GlobalEventManager.onCharacterLevelUp += OnCharacterLevelUp;
			Run.onRunAmbientLevelUp += OnRunAmbientLevelUp;
		}

		private static void OnTeamLevelUp(TeamIndex teamIndex)
		{
			if (TeamComponent.GetTeamMembers(teamIndex).Count > 0)
			{
				Util.PlaySound(TeamCatalog.GetTeamDef(teamIndex)?.levelUpSound, RoR2Application.instance.gameObject);
			}
		}

		private static void OnCharacterLevelUp(CharacterBody characterBody)
		{
			GameObject levelUpEffect = TeamCatalog.GetTeamDef(characterBody.teamComponent.teamIndex)?.levelUpEffect;
			if (!characterBody)
			{
				return;
			}
			Transform transform = (characterBody.mainHurtBox ? characterBody.mainHurtBox.transform : characterBody.transform);
			EffectData effectData = new EffectData
			{
				origin = transform.position
			};
			if ((bool)characterBody.mainHurtBox)
			{
				effectData.SetHurtBoxReference(characterBody.gameObject);
				effectData.scale = characterBody.radius;
			}
			RoR2Application.fixedTimeTimers.CreateTimer((float)pendingLevelUpEffects * levelUpEffectInterval + UnityEngine.Random.value * levelUpEffectJitter, delegate
			{
				if ((bool)characterBody)
				{
					EffectManager.SpawnEffect(levelUpEffect, effectData, transmit: false);
				}
				levelUpEffectInterval -= 1f;
			});
			levelUpEffectInterval += 1f;
		}

		private static void OnRunAmbientLevelUp(Run run)
		{
			Util.PlaySound("Play_UI_levelUp_enemy", RoR2Application.instance.gameObject);
		}
	}
	public class Loadout
	{
		public class BodyLoadoutManager
		{
			private sealed class BodyLoadout
			{
				public BodyIndex bodyIndex;

				public uint skinPreference;

				public uint[] skillPreferences;

				[NotNull]
				public BodyLoadout Clone()
				{
					return new BodyLoadout
					{
						bodyIndex = bodyIndex,
						skinPreference = skinPreference,
						skillPreferences = (uint[])skillPreferences.Clone()
					};
				}

				public bool ValueEquals(BodyLoadout other)
				{
					if (this == other)
					{
						return true;
					}
					if (other == null)
					{
						return false;
					}
					if (bodyIndex.Equals(other.bodyIndex))
					{
						if (skinPreference.Equals(other.skinPreference))
						{
							return ((IStructuralEquatable)skillPreferences).Equals((object)other.skillPreferences, (IEqualityComparer)EqualityComparer<uint>.Default);
						}
						return false;
					}
					return false;
				}

				public uint GetSkillVariant(int skillSlotIndex)
				{
					if ((uint)skillSlotIndex < skillPreferences.Length)
					{
						return skillPreferences[skillSlotIndex];
					}
					return 0u;
				}

				public bool SetSkillVariant(int skillSlotIndex, uint skillVariant)
				{
					if ((uint)skillSlotIndex < skillPreferences.Length)
					{
						skillPreferences[skillSlotIndex] = HGMath.Clamp(skillVariant, 0u, (uint)LookUpMaxSkillVariants(skillSlotIndex));
						return true;
					}
					return false;
				}

				private bool IsSkillVariantValid(int skillSlotIndex)
				{
					SkillFamily skillFamily = GetSkillFamily(skillSlotIndex);
					if (!skillFamily)
					{
						return false;
					}
					if (GetSkillVariant(skillSlotIndex) < skillFamily.variants.Length)
					{
						return true;
					}
					return false;
				}

				private bool IsSkillVariantLocked(int skillSlotIndex, UserProfile userProfile)
				{
					SkillFamily skillFamily = GetSkillFamily(skillSlotIndex);
					if (!skillFamily)
					{
						return false;
					}
					uint skillVariant = GetSkillVariant(skillSlotIndex);
					bool num = (bool)skillFamily.variants[skillVariant].unlockableDef && (bool)skillFamily.variants[skillVariant].unlockableDef.requiredExpansion;
					bool flag = false;
					if (num)
					{
						flag = EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(skillFamily.variants[skillVariant].unlockableDef.requiredExpansion.requiredEntitlement);
					}
					if (!num || flag)
					{
						return !userProfile.HasUnlockable(skillFamily.variants[skillVariant].unlockableDef);
					}
					return true;
				}

				private void ResetSkillVariant(int skillSlotIndex)
				{
					if ((uint)skillSlotIndex < skillPreferences.Length)
					{
						skillPreferences[skillSlotIndex] = GetSkillFamily(skillSlotIndex)?.defaultVariantIndex ?? 0;
					}
				}

				private bool IsSkinValid()
				{
					SkinDef[] bodySkins = BodyCatalog.GetBodySkins(bodyIndex);
					return skinPreference < bodySkins.Length;
				}

				private bool IsSkinLocked(UserProfile userProfile)
				{
					SkinDef safe = ArrayUtils.GetSafe(BodyCatalog.GetBodySkins(bodyIndex), (int)skinPreference);
					if (!safe)
					{
						return true;
					}
					bool num = (bool)safe.unlockableDef && (bool)safe.unlockableDef.requiredExpansion;
					bool flag = false;
					if (num)
					{
						EntitlementDef requiredEntitlement = safe.unlockableDef.requiredExpansion.requiredEntitlement;
						flag = EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(requiredEntitlement);
					}
					if (!num || flag)
					{
						return !userProfile.HasUnlockable(safe.unlockableDef);
					}
					return true;
				}

				private void ResetSkin()
				{
					skinPreference = 0u;
				}

				public void EnforceValidity()
				{
					for (int i = 0; i < skillPreferences.Length; i++)
					{
						if (!IsSkillVariantValid(i))
						{
							ResetSkillVariant(i);
						}
					}
					if (!IsSkinValid())
					{
						ResetSkin();
					}
				}

				public void EnforceUnlockables(UserProfile userProfile)
				{
					bool flag = false;
					for (int i = 0; i < skillPreferences.Length; i++)
					{
						if (IsSkillVariantLocked(i, userProfile))
						{
							ResetSkillVariant(i);
							flag = true;
						}
					}
					if (IsSkinLocked(userProfile))
					{
						ResetSkin();
						flag = true;
					}
					if (flag)
					{
						userProfile.OnLoadoutChanged();
					}
				}

				[CanBeNull]
				private SkillFamily GetSkillFamily(int skillSlotIndex)
				{
					return BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex)[skillSlotIndex].skillFamily;
				}

				public int LookUpMaxSkillVariants(int skillSlotIndex)
				{
					if ((uint)skillSlotIndex < skillPreferences.Length)
					{
						SkillFamily skillFamily = GetSkillFamily(skillSlotIndex);
						if ((object)skillFamily == null)
						{
							return 0;
						}
						return skillFamily.variants.Length;
					}
					return 0;
				}

				public void Serialize(NetworkWriter writer)
				{
					writer.WriteBodyIndex(bodyIndex);
					writer.WritePackedUInt32(skinPreference);
					for (int i = 0; i < skillPreferences.Length; i++)
					{
						writer.WritePackedUInt32(skillPreferences[i]);
					}
				}

				public void Deserialize(NetworkReader reader)
				{
					bodyIndex = reader.ReadBodyIndex();
					if (bodyIndex < (BodyIndex)0)
					{
						bodyIndex = (BodyIndex)0;
					}
					if ((int)bodyIndex >= BodyCatalog.bodyCount)
					{
						bodyIndex = (BodyIndex)(BodyCatalog.bodyCount - 1);
					}
					skinPreference = reader.ReadPackedUInt32();
					Array.Resize(ref skillPreferences, GetSkillSlotCountForBody(bodyIndex));
					for (int i = 0; i < skillPreferences.Length; i++)
					{
						SetSkillVariant(i, reader.ReadPackedUInt32());
					}
				}

				public XElement ToXml(string elementName)
				{
					XElement xElement = new XElement(elementName);
					xElement.SetAttributeValue("bodyName", BodyCatalog.GetBodyName(bodyIndex));
					xElement.Add(new XElement("Skin", skinPreference.ToString()));
					ref BodyInfo reference = ref allBodyInfos[(int)bodyIndex];
					for (int i = 0; i < reference.prefabSkillSlots.Length; i++)
					{
						int skillFamilyIndex = reference.skillFamilyIndices[i];
						SkillFamily skillFamily = SkillCatalog.GetSkillFamily(skillFamilyIndex);
						string skillFamilyName = SkillCatalog.GetSkillFamilyName(skillFamilyIndex);
						string variantName = skillFamily.GetVariantName((int)skillPreferences[i]);
						if (variantName != null)
						{
							XElement xElement2 = new XElement("SkillPreference", variantName);
							xElement2.SetAttributeValue("skillFamily", skillFamilyName);
							xElement.Add(xElement2);
						}
					}
					return xElement;
				}

				public bool FromXml(XElement element)
				{
					uint.TryParse(element.Element("Skin")?.Value ?? string.Empty, out skinPreference);
					string text = element.Attribute("bodyName")?.Value;
					if (text == null)
					{
						return false;
					}
					bodyIndex = BodyCatalog.FindBodyIndex(text);
					if (bodyIndex == BodyIndex.None)
					{
						UnityEngine.Debug.LogFormat("Could not find body index for bodyName={0}", text);
						return false;
					}
					GenericSkill[] prefabSkillSlots = allBodyInfos[(int)bodyIndex].prefabSkillSlots;
					skillPreferences = new uint[prefabSkillSlots.Length];
					foreach (XElement item in element.Elements("SkillPreference"))
					{
						string text2 = item.Attribute("skillFamily")?.Value;
						string value = item.Value;
						if (text2 == null)
						{
							continue;
						}
						int num = FindSkillSlotIndex(text2);
						if (num != -1)
						{
							int variantIndex = prefabSkillSlots[num].skillFamily.GetVariantIndex(value);
							if (variantIndex != -1)
							{
								skillPreferences[num] = (uint)variantIndex;
								continue;
							}
							UnityEngine.Debug.LogFormat("Could not find variant index for elementSkillFamilyName={0} elementSkillName={1}", text2, value);
						}
						else
						{
							UnityEngine.Debug.LogFormat("Could not find skill slot index for elementSkillFamilyName={0} elementSkillName={1}", text2, value);
						}
					}
					return true;
					int FindSkillSlotIndex(string requestedSkillFamilyName)
					{
						for (int i = 0; i < prefabSkillSlots.Length; i++)
						{
							if (SkillCatalog.GetSkillFamilyName(prefabSkillSlots[i].skillFamily.catalogIndex).Equals(requestedSkillFamilyName, StringComparison.Ordinal))
							{
								return i;
							}
						}
						return -1;
					}
				}
			}

			private struct BodyInfo
			{
				public int[] skillFamilyIndices;

				public GenericSkill[] prefabSkillSlots;

				public int skillSlotCount => prefabSkillSlots.Length;
			}

			private BodyLoadout[] modifiedBodyLoadouts = Array.Empty<BodyLoadout>();

			private static BodyLoadout[] defaultBodyLoadouts;

			private static BodyInfo[] allBodyInfos;

			private int FindModifiedBodyLoadoutIndexByBodyIndex(BodyIndex bodyIndex)
			{
				for (int i = 0; i < modifiedBodyLoadouts.Length; i++)
				{
					if (modifiedBodyLoadouts[i].bodyIndex == bodyIndex)
					{
						return i;
					}
				}
				return -1;
			}

			private BodyLoadout GetReadOnlyBodyLoadout(BodyIndex bodyIndex)
			{
				int num = FindModifiedBodyLoadoutIndexByBodyIndex(bodyIndex);
				if (num == -1)
				{
					return defaultBodyLoadouts[(int)bodyIndex];
				}
				return modifiedBodyLoadouts[num];
			}

			private BodyLoadout GetOrCreateModifiedBodyLoadout(BodyIndex bodyIndex)
			{
				int num = FindModifiedBodyLoadoutIndexByBodyIndex(bodyIndex);
				if (num != -1)
				{
					return modifiedBodyLoadouts[num];
				}
				BodyLoadout value = GetDefaultLoadoutForBody(bodyIndex).Clone();
				ArrayUtils.ArrayAppend(ref modifiedBodyLoadouts, in value);
				return value;
			}

			public uint GetSkillVariant(BodyIndex bodyIndex, int skillSlot)
			{
				return GetReadOnlyBodyLoadout(bodyIndex).skillPreferences[skillSlot];
			}

			public void SetSkillVariant(BodyIndex bodyIndex, int skillSlot, uint skillVariant)
			{
				if ((uint)bodyIndex >= BodyCatalog.bodyCount)
				{
					throw new ArgumentOutOfRangeException("bodyIndex", (int)bodyIndex, $"Value provided for 'bodyIndex' is outside range [0, {(int)bodyIndex}]");
				}
				if (GetSkillVariant(bodyIndex, skillSlot) != skillVariant)
				{
					int skillSlotCountForBody = GetSkillSlotCountForBody(bodyIndex);
					if ((uint)skillSlot >= skillSlotCountForBody)
					{
						throw new ArgumentOutOfRangeException("skillSlot", skillSlot, $"Value provided for 'skillSlot' is outside range [0, {skillSlotCountForBody}) for body=[{(int)bodyIndex}]");
					}
					int num = allBodyInfos[(int)bodyIndex].prefabSkillSlots[skillSlot].skillFamily.variants.Length;
					if (skillVariant >= num)
					{
						throw new ArgumentOutOfRangeException("skillVariant", skillVariant, $"Value provided for 'skillVariant' is outside range [0, {num}) for body=[{(int)bodyIndex}] skillSlot=[{skillSlot}]");
					}
					BodyLoadout orCreateModifiedBodyLoadout = GetOrCreateModifiedBodyLoadout(bodyIndex);
					orCreateModifiedBodyLoadout.SetSkillVariant(skillSlot, skillVariant);
					RemoveBodyLoadoutIfDefault(orCreateModifiedBodyLoadout);
				}
			}

			public uint GetSkinIndex(BodyIndex bodyIndex)
			{
				return GetReadOnlyBodyLoadout(bodyIndex).skinPreference;
			}

			public void SetSkinIndex(BodyIndex bodyIndex, uint skinIndex)
			{
				BodyLoadout orCreateModifiedBodyLoadout = GetOrCreateModifiedBodyLoadout(bodyIndex);
				orCreateModifiedBodyLoadout.skinPreference = skinIndex;
				RemoveBodyLoadoutIfDefault(orCreateModifiedBodyLoadout);
			}

			private void RemoveBodyLoadoutIfDefault(BodyLoadout bodyLoadout)
			{
				RemoveBodyLoadoutIfDefault(FindModifiedBodyLoadoutIndexByBodyIndex(bodyLoadout.bodyIndex));
			}

			private void RemoveBodyLoadoutIfDefault(int modifiedBodyLoadoutIndex)
			{
				BodyLoadout obj = modifiedBodyLoadouts[modifiedBodyLoadoutIndex];
				if (obj.ValueEquals(GetDefaultLoadoutForBody(obj.bodyIndex)))
				{
					RemoveBodyLoadoutAt(modifiedBodyLoadoutIndex);
				}
			}

			private void RemoveBodyLoadoutAt(int i)
			{
				ArrayUtils.ArrayRemoveAtAndResize(ref modifiedBodyLoadouts, i);
			}

			private static BodyLoadout GetDefaultLoadoutForBody(BodyIndex bodyIndex)
			{
				return defaultBodyLoadouts[(int)bodyIndex];
			}

			private static int GetSkillSlotCountForBody(BodyIndex bodyIndex)
			{
				return allBodyInfos[(int)bodyIndex].skillSlotCount;
			}

			[SystemInitializer(new Type[]
			{
				typeof(SkillCatalog),
				typeof(BodyCatalog)
			})]
			private static void Init()
			{
				defaultBodyLoadouts = new BodyLoadout[BodyCatalog.bodyCount];
				allBodyInfos = new BodyInfo[defaultBodyLoadouts.Length];
				for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < defaultBodyLoadouts.Length; bodyIndex++)
				{
					BodyInfo bodyInfo = default(BodyInfo);
					bodyInfo.prefabSkillSlots = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndex).GetComponents<GenericSkill>();
					bodyInfo.skillFamilyIndices = new int[bodyInfo.skillSlotCount];
					for (int i = 0; i < bodyInfo.prefabSkillSlots.Length; i++)
					{
						bodyInfo.skillFamilyIndices[i] = bodyInfo.prefabSkillSlots[i].skillFamily?.catalogIndex ?? (-1);
					}
					allBodyInfos[(int)bodyIndex] = bodyInfo;
					uint[] array = new uint[bodyInfo.skillSlotCount];
					for (int j = 0; j < bodyInfo.prefabSkillSlots.Length; j++)
					{
						array[j] = bodyInfo.prefabSkillSlots[j].skillFamily.defaultVariantIndex;
					}
					defaultBodyLoadouts[(int)bodyIndex] = new BodyLoadout
					{
						bodyIndex = bodyIndex,
						skinPreference = 0u,
						skillPreferences = array
					};
				}
				GenerateViewables();
			}

			public void Copy(BodyLoadoutManager dest)
			{
				Array.Resize(ref dest.modifiedBodyLoadouts, modifiedBodyLoadouts.Length);
				for (int i = 0; i < modifiedBodyLoadouts.Length; i++)
				{
					dest.modifiedBodyLoadouts[i] = modifiedBodyLoadouts[i].Clone();
				}
			}

			public void Clear()
			{
				modifiedBodyLoadouts = Array.Empty<BodyLoadout>();
			}

			public void Serialize(NetworkWriter writer)
			{
				writer.WritePackedUInt32((uint)modifiedBodyLoadouts.Length);
				for (int i = 0; i < modifiedBodyLoadouts.Length; i++)
				{
					modifiedBodyLoadouts[i].Serialize(writer);
				}
			}

			public void Deserialize(NetworkReader reader)
			{
				try
				{
					int num = (int)reader.ReadPackedUInt32();
					if (num > BodyCatalog.bodyCount)
					{
						num = BodyCatalog.bodyCount;
					}
					Array.Resize(ref modifiedBodyLoadouts, num);
					for (int i = 0; i < num; i++)
					{
						BodyLoadout bodyLoadout = new BodyLoadout();
						bodyLoadout.Deserialize(reader);
						modifiedBodyLoadouts[i] = bodyLoadout;
					}
				}
				catch (Exception)
				{
					modifiedBodyLoadouts = Array.Empty<BodyLoadout>();
					throw;
				}
			}

			public bool ValueEquals(BodyLoadoutManager other)
			{
				if (this == other)
				{
					return true;
				}
				if (other == null)
				{
					return false;
				}
				if (modifiedBodyLoadouts.Length != other.modifiedBodyLoadouts.Length)
				{
					return false;
				}
				for (int i = 0; i < modifiedBodyLoadouts.Length; i++)
				{
					if (!modifiedBodyLoadouts[i].ValueEquals(other.modifiedBodyLoadouts[i]))
					{
						return false;
					}
				}
				return true;
			}

			public XElement ToXml(string elementName)
			{
				XElement xElement = new XElement(elementName);
				for (int i = 0; i < modifiedBodyLoadouts.Length; i++)
				{
					xElement.Add(modifiedBodyLoadouts[i].ToXml("BodyLoadout"));
				}
				return xElement;
			}

			public bool FromXml(XElement element)
			{
				List<BodyLoadout> bodyLoadouts = new List<BodyLoadout>();
				foreach (XElement item in element.Elements("BodyLoadout"))
				{
					BodyLoadout bodyLoadout = new BodyLoadout();
					if (bodyLoadout.FromXml(item) && !BodyLoadoutAlreadyDefined(bodyLoadout.bodyIndex) && !bodyLoadout.ValueEquals(GetDefaultLoadoutForBody(bodyLoadout.bodyIndex)))
					{
						bodyLoadouts.Add(bodyLoadout);
					}
				}
				modifiedBodyLoadouts = bodyLoadouts.ToArray();
				return true;
				bool BodyLoadoutAlreadyDefined(BodyIndex bodyIndex)
				{
					for (int i = 0; i < bodyLoadouts.Count; i++)
					{
						if (bodyLoadouts[i].bodyIndex == bodyIndex)
						{
							return true;
						}
					}
					return false;
				}
			}

			public void EnforceUnlockables(UserProfile userProfile)
			{
				for (int num = modifiedBodyLoadouts.Length - 1; num >= 0; num--)
				{
					modifiedBodyLoadouts[num].EnforceUnlockables(userProfile);
					RemoveBodyLoadoutIfDefault(num);
				}
			}

			public void EnforceValidity()
			{
				for (int num = modifiedBodyLoadouts.Length - 1; num >= 0; num--)
				{
					modifiedBodyLoadouts[num].EnforceValidity();
					RemoveBodyLoadoutIfDefault(num);
				}
			}
		}

		public readonly BodyLoadoutManager bodyLoadoutManager = new BodyLoadoutManager();

		private static readonly Stack<Loadout> instancePool = new Stack<Loadout>();

		public void Serialize(NetworkWriter writer)
		{
			bodyLoadoutManager.Serialize(writer);
		}

		public void Deserialize(NetworkReader reader)
		{
			bodyLoadoutManager.Deserialize(reader);
		}

		public void Copy(Loadout dest)
		{
			bodyLoadoutManager.Copy(dest.bodyLoadoutManager);
		}

		public void Clear()
		{
			bodyLoadoutManager.Clear();
		}

		public bool ValueEquals(Loadout other)
		{
			if (this == other)
			{
				return true;
			}
			if (other == null)
			{
				return false;
			}
			return bodyLoadoutManager.ValueEquals(other.bodyLoadoutManager);
		}

		public XElement ToXml(string elementName)
		{
			XElement xElement = new XElement(elementName);
			xElement.Add(bodyLoadoutManager.ToXml("BodyLoadouts"));
			return xElement;
		}

		public bool FromXml(XElement element)
		{
			bool flag = true;
			XElement xElement = element.Element("BodyLoadouts");
			flag = xElement != null && (flag & bodyLoadoutManager.FromXml(xElement));
			EnforceValidity();
			return flag;
		}

		public void EnforceValidity()
		{
			bodyLoadoutManager.EnforceValidity();
		}

		public void EnforceUnlockables(UserProfile userProfile)
		{
			bodyLoadoutManager.EnforceUnlockables(userProfile);
		}

		private static void GenerateViewables()
		{
			StringBuilder stringBuilder = new StringBuilder();
			ViewablesCatalog.Node node = new ViewablesCatalog.Node("Loadout", isFolder: true);
			ViewablesCatalog.Node parent = new ViewablesCatalog.Node("Bodies", isFolder: true, node);
			for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < BodyCatalog.bodyCount; bodyIndex++)
			{
				if (SurvivorCatalog.GetSurvivorIndexFromBodyIndex(bodyIndex) == SurvivorIndex.None)
				{
					continue;
				}
				string bodyName = BodyCatalog.GetBodyName(bodyIndex);
				GenericSkill[] bodyPrefabSkillSlots = BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex);
				ViewablesCatalog.Node parent2 = new ViewablesCatalog.Node(bodyName, isFolder: true, parent);
				for (int i = 0; i < bodyPrefabSkillSlots.Length; i++)
				{
					SkillFamily skillFamily = bodyPrefabSkillSlots[i].skillFamily;
					if (skillFamily.variants.Length <= 1)
					{
						continue;
					}
					string skillFamilyName = SkillCatalog.GetSkillFamilyName(skillFamily.catalogIndex);
					for (uint num = 0u; num < skillFamily.variants.Length; num++)
					{
						ref SkillFamily.Variant reference = ref skillFamily.variants[num];
						UnlockableDef unlockableDef = reference.unlockableDef;
						string skillName = SkillCatalog.GetSkillName(reference.skillDef.skillIndex);
						stringBuilder.Append(skillFamilyName).Append(".").Append(skillName);
						string name = stringBuilder.ToString();
						stringBuilder.Clear();
						ViewablesCatalog.Node variantNode = new ViewablesCatalog.Node(name, isFolder: false, parent2);
						reference.viewableNode = variantNode;
						variantNode.shouldShowUnviewed = (UserProfile userProfile) => !userProfile.HasViewedViewable(variantNode.fullName) && userProfile.HasUnlockable(unlockableDef);
					}
				}
				SkinDef[] bodySkins = BodyCatalog.GetBodySkins(bodyIndex);
				if (bodySkins.Length <= 1)
				{
					continue;
				}
				ViewablesCatalog.Node parent3 = new ViewablesCatalog.Node("Skins", isFolder: true, parent2);
				for (int j = 0; j < bodySkins.Length; j++)
				{
					UnlockableDef unlockableDef2 = bodySkins[j].unlockableDef;
					if ((bool)unlockableDef2)
					{
						ViewablesCatalog.Node skinNode = new ViewablesCatalog.Node(bodySkins[j].name, isFolder: false, parent3);
						skinNode.shouldShowUnviewed = (UserProfile userProfile) => !userProfile.HasViewedViewable(skinNode.fullName) && userProfile.HasUnlockable(unlockableDef2);
					}
				}
			}
			ViewablesCatalog.AddNodeToRoot(node);
		}

		public static Loadout RequestInstance()
		{
			if (instancePool.Count == 0)
			{
				return new Loadout();
			}
			return instancePool.Pop();
		}

		public static Loadout ReturnInstance(Loadout instance)
		{
			instance.Clear();
			instancePool.Push(instance);
			return null;
		}

		[SystemInitializer(new Type[]
		{
			typeof(BodyCatalog),
			typeof(SkillCatalog),
			typeof(SkinCatalog)
		})]
		private static void Init()
		{
		}
	}
	public class LocalNavigator
	{
		private readonly struct BodyComponents
		{
			public readonly CharacterBody body;

			public readonly Transform transform;

			public readonly CharacterMotor motor;

			public readonly Collider bodyCollider;

			public BodyComponents(CharacterBody body)
			{
				this = default(BodyComponents);
				this.body = body;
				if ((bool)body)
				{
					transform = body.transform;
					motor = body.characterMotor;
					if ((bool)motor)
					{
						bodyCollider = body.characterMotor.Motor.Capsule;
					}
				}
			}
		}

		private readonly struct BodySnapshot
		{
			public readonly UnityEngine.Vector3 position;

			public readonly UnityEngine.Vector3 chestPosition;

			public readonly UnityEngine.Vector3 footPosition;

			public readonly UnityEngine.Vector3 motorMoveDirection;

			public readonly UnityEngine.Vector3 motorVelocity;

			public readonly float maxMoveSpeed;

			public readonly float acceleration;

			public readonly float maxJumpHeight;

			public readonly float maxJumpSpeed;

			public readonly bool isGrounded;

			public readonly float time;

			public readonly float bodyRadius;

			public readonly bool isFlying;

			public readonly bool isJumping;

			private readonly bool hasBody;

			private readonly bool hasBodyCollider;

			private readonly bool hasMotor;

			public bool isValid => hasBody;

			public bool canJump
			{
				get
				{
					if (isGrounded)
					{
						return maxJumpSpeed > 0f;
					}
					return false;
				}
			}

			public BodySnapshot(in BodyComponents bodyComponents, float time)
			{
				this = default(BodySnapshot);
				this.time = time;
				hasBody = bodyComponents.body;
				hasBodyCollider = bodyComponents.bodyCollider;
				hasMotor = bodyComponents.motor;
				if ((bool)bodyComponents.body)
				{
					position = bodyComponents.transform.position;
					chestPosition = position;
					footPosition = position;
					maxMoveSpeed = bodyComponents.body.moveSpeed;
					acceleration = bodyComponents.body.acceleration;
					maxJumpHeight = bodyComponents.body.maxJumpHeight;
					maxJumpSpeed = bodyComponents.body.jumpPower;
					bodyRadius = bodyComponents.body.radius;
					isFlying = bodyComponents.body.isFlying;
				}
				if ((bool)bodyComponents.bodyCollider)
				{
					Bounds bounds = bodyComponents.bodyCollider.bounds;
					bounds.center = UnityEngine.Vector3.zero;
					chestPosition.y += bounds.max.y * 0.5f;
					footPosition.y += bounds.min.y;
				}
				if ((bool)bodyComponents.motor)
				{
					isGrounded = bodyComponents.motor.isGrounded;
					motorVelocity = bodyComponents.motor.velocity;
					isJumping = !isGrounded;
				}
			}
		}

		private readonly struct SnapshotDelta
		{
			public readonly float deltaTime;

			public readonly UnityEngine.Vector3 estimatedVelocity;

			public readonly bool isValid;

			public SnapshotDelta(in BodySnapshot oldSnapshot, in BodySnapshot newSnapshot)
			{
				this = default(SnapshotDelta);
				if (oldSnapshot.isValid && newSnapshot.isValid)
				{
					deltaTime = newSnapshot.time - oldSnapshot.time;
					isValid = deltaTime > 0f;
					if (isValid)
					{
						estimatedVelocity = (newSnapshot.position - oldSnapshot.position) / deltaTime;
					}
				}
			}
		}

		private struct RaycastResults
		{
			public bool forwardObstructed;

			public bool leftObstructed;

			public bool rightObstructed;
		}

		private UnityEngine.Vector3 previousMoveVector;

		public UnityEngine.Vector3 targetPosition;

		public float avoidanceDuration = 0.5f;

		private float avoidanceTimer;

		public bool allowWalkOffCliff;

		public bool wasObstructedLastUpdate;

		private float localTime;

		private float raycastTimer;

		private static readonly float raycastUpdateInterval = 0.2f;

		private static readonly float avoidanceAngle = 45f;

		private const bool enableFrustration = true;

		private const bool enableWhiskers = true;

		private const bool enableCliffAvoidance = true;

		private BodyComponents bodyComponents;

		private float walkFrustration;

		private const float frustrationLimit = 1f;

		private const float frustrationDecayRate = 0.25f;

		private const float frustrationMinimumSpeed = 0.1f;

		private float aiStopwatch;

		private UnityEngine.Vector3 velocityDelta;

		private UnityEngine.Vector3 estimatedAcceleration;

		private float accelerationAccuracy;

		private float moveDirectionAccuracy;

		private bool hasMadeSharpTurn;

		private float speedAsFractionOfTopSpeed;

		private bool isAlreadyMovingAtSufficientSpeed;

		private BodySnapshot currentSnapshot;

		private BodySnapshot previousSnapshot;

		private SnapshotDelta currentSnapshotDelta;

		private SnapshotDelta previousSnapshotDelta;

		private RaycastResults raycastResults;

		private static readonly BoolConVar cvLocalNavigatorDebugDraw = new BoolConVar("local_navigator_debug_draw", ConVarFlags.None, "0", "Enables debug drawing of LocalNavigator (drawing visible in editor only).\n  Orange Line: Current position to target position\n  Yellow Line: Raycasts\n  Red Point: Raycast hit position\n  Green Line: Final chosen move vector");

		public UnityEngine.Vector3 moveVector { get; private set; }

		public float jumpSpeed { get; private set; }

		public void SetBody(CharacterBody newBody)
		{
			bodyComponents = new BodyComponents(newBody);
			PushSnapshot();
			PushSnapshot();
		}

		private void PushSnapshot()
		{
			previousSnapshot = currentSnapshot;
			currentSnapshot = new BodySnapshot(in bodyComponents, localTime);
			previousSnapshotDelta = currentSnapshotDelta;
			currentSnapshotDelta = new SnapshotDelta(in previousSnapshot, in currentSnapshot);
		}

		public void Update(float deltaTime)
		{
			localTime += deltaTime;
			PushSnapshot();
			if (cvLocalNavigatorDebugDraw.value)
			{
				UnityEngine.Debug.DrawLine(currentSnapshot.position, targetPosition, new Color32(byte.MaxValue, 127, 39, 127), deltaTime);
			}
			wasObstructedLastUpdate = false;
			jumpSpeed = 0f;
			previousMoveVector = moveVector;
			UnityEngine.Vector3 vector = targetPosition - currentSnapshot.position;
			if (!currentSnapshot.isFlying)
			{
				vector.y = 0f;
			}
			float magnitude = vector.magnitude;
			UnityEngine.Vector3 positionToTargetNormalized = vector / magnitude;
			UnityEngine.Vector3 vector2 = moveVector;
			CompensateForVelocityByRefinement(deltaTime, ref vector2, in positionToTargetNormalized);
			moveVector = vector2;
			if (magnitude == 0f)
			{
				moveVector = UnityEngine.Vector3.zero;
			}
			else
			{
				raycastResults = GetRaycasts(in currentSnapshot, moveVector, deltaTime);
				if (raycastResults.forwardObstructed)
				{
					int num = ((!raycastResults.leftObstructed) ? (-1) : 0) + ((!raycastResults.rightObstructed) ? 1 : 0);
					if (num == 0)
					{
						num = ((UnityEngine.Random.Range(0, 1) != 1) ? 1 : (-1));
					}
					moveVector = UnityEngine.Quaternion.Euler(0f, (0f - avoidanceAngle) * (float)num, 0f) * moveVector;
					wasObstructedLastUpdate = raycastResults.leftObstructed || raycastResults.rightObstructed;
				}
				float deltaTime2 = deltaTime + 0.4f;
				ref BodySnapshot reference = ref currentSnapshot;
				ref SnapshotDelta reference2 = ref currentSnapshotDelta;
				UnityEngine.Vector3 currentMoveVector = moveVector;
				if (CheckCliffAhead(in reference, in reference2, in currentMoveVector, deltaTime2))
				{
					wasObstructedLastUpdate = true;
					moveVector = -moveVector;
					ref BodySnapshot reference3 = ref currentSnapshot;
					ref SnapshotDelta reference4 = ref currentSnapshotDelta;
					currentMoveVector = moveVector;
					if (CheckCliffAhead(in reference3, in reference4, in currentMoveVector, deltaTime2))
					{
						moveVector *= 0.25f;
					}
				}
				CalculateFrustration(deltaTime, ref walkFrustration);
				if (walkFrustration >= 1f)
				{
					jumpSpeed = currentSnapshot.maxJumpSpeed;
				}
			}
			avoidanceTimer -= deltaTime;
			walkFrustration = Mathf.Clamp(walkFrustration - deltaTime * 0.25f, 0f, 1f);
			if (cvLocalNavigatorDebugDraw.value)
			{
				UnityEngine.Debug.DrawRay(currentSnapshot.position, moveVector * 5f, UnityEngine.Color.green, deltaTime, depthTest: false);
			}
		}

		private void CompensateForVelocityByRefinement(float nextExpectedDeltaTime, ref UnityEngine.Vector3 moveVector, in UnityEngine.Vector3 positionToTargetNormalized)
		{
			UnityEngine.Vector3 estimatedVelocity = currentSnapshotDelta.estimatedVelocity;
			_ = currentSnapshot.acceleration;
			float num = UnityEngine.Vector3.Dot(estimatedVelocity, positionToTargetNormalized);
			UnityEngine.Vector3 vector = positionToTargetNormalized;
			UnityEngine.Vector3 vector2 = vector;
			int num2 = 8;
			if (!currentSnapshot.isJumping)
			{
				for (int i = 0; i < num2; i++)
				{
					EstimateNextMovement(in currentSnapshot, in currentSnapshotDelta, in vector2, nextExpectedDeltaTime, out var nextPosition, out var nextVelocity);
					UnityEngine.Vector3 vector3 = targetPosition - nextPosition;
					if (!currentSnapshot.isFlying)
					{
						vector3.y = 0f;
					}
					UnityEngine.Vector3 normalized = vector3.normalized;
					vector2 = normalized;
					if (UnityEngine.Vector3.Dot(nextVelocity, normalized) > num)
					{
						vector = normalized;
					}
				}
			}
			moveVector = vector;
		}

		private void CompensateForVelocityByBruteForce(float nextExpectedDeltaTime, ref UnityEngine.Vector3 moveVector, in UnityEngine.Vector3 positionToTargetNormalized)
		{
			UnityEngine.Vector3 estimatedVelocity = currentSnapshotDelta.estimatedVelocity;
			_ = currentSnapshot;
			float num = UnityEngine.Vector3.Dot(estimatedVelocity.normalized, positionToTargetNormalized);
			UnityEngine.Vector3 vector = moveVector;
			int num2 = 16;
			float num3 = 360f / (float)num2;
			for (int i = 0; i < num2; i++)
			{
				UnityEngine.Vector3 vector2 = UnityEngine.Quaternion.AngleAxis((float)i * num3, UnityEngine.Vector3.up) * UnityEngine.Vector3.forward;
				EstimateNextMovement(in currentSnapshot, in currentSnapshotDelta, in vector2, nextExpectedDeltaTime, out var nextPosition, out var nextVelocity);
				float num4 = UnityEngine.Vector3.Dot((targetPosition - nextPosition).normalized, nextVelocity.normalized);
				if (num4 > num)
				{
					num = num4;
					vector = vector2;
				}
			}
			moveVector = vector;
		}

		private static void EstimateNextMovement(in BodySnapshot currentSnapshot, in SnapshotDelta currentSnapshotDelta, in UnityEngine.Vector3 moveVector, float nextDeltaTime, out UnityEngine.Vector3 nextPosition, out UnityEngine.Vector3 nextVelocity)
		{
			UnityEngine.Vector3 estimatedVelocity = currentSnapshotDelta.estimatedVelocity;
			float acceleration = currentSnapshot.acceleration;
			nextVelocity = UnityEngine.Vector3.MoveTowards(estimatedVelocity, moveVector * currentSnapshot.maxMoveSpeed, acceleration * nextDeltaTime);
			float num = Mathf.Min((nextVelocity - estimatedVelocity).magnitude / acceleration, nextDeltaTime);
			float num2 = nextDeltaTime - num;
			UnityEngine.Vector3 vector = (nextVelocity - estimatedVelocity) / num;
			UnityEngine.Vector3 vector2 = nextVelocity * num + vector * (0.5f * num * num);
			UnityEngine.Vector3 vector3 = nextVelocity * num2;
			nextPosition = currentSnapshot.position + vector2 + vector3;
		}

		private RaycastResults GetRaycasts(in BodySnapshot currentSnapshot, UnityEngine.Vector3 positionToTargetNormalized, float lookaheadTime)
		{
			RaycastResults result = default(RaycastResults);
			UnityEngine.Vector3 origin = currentSnapshot.chestPosition;
			LayerMask layerMask = (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault;
			float maxDistance = currentSnapshot.bodyRadius + currentSnapshot.maxMoveSpeed * lookaheadTime;
			result.forwardObstructed = Raycast(in origin, in positionToTargetNormalized, out var hitInfo, maxDistance, layerMask);
			if (result.forwardObstructed)
			{
				UnityEngine.Vector3 direction = UnityEngine.Quaternion.Euler(0f, avoidanceAngle, 0f) * positionToTargetNormalized;
				result.leftObstructed = Raycast(in origin, in direction, out hitInfo, maxDistance, layerMask);
				direction = UnityEngine.Quaternion.Euler(0f, 0f - avoidanceAngle, 0f) * positionToTargetNormalized;
				result.rightObstructed = Raycast(in origin, in direction, out hitInfo, maxDistance, layerMask);
			}
			return result;
		}

		private bool Raycast(in UnityEngine.Vector3 origin, in UnityEngine.Vector3 direction, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask)
		{
			bool flag = Physics.Raycast(origin, direction, out hitInfo, maxDistance, layerMask);
			if (cvLocalNavigatorDebugDraw.value)
			{
				UnityEngine.Debug.DrawRay(origin, direction.normalized * maxDistance, UnityEngine.Color.yellow, raycastUpdateInterval);
				if (flag)
				{
					Util.DebugCross(hitInfo.point, 1f, UnityEngine.Color.red, raycastUpdateInterval);
				}
			}
			return flag;
		}

		private bool Linecast(in UnityEngine.Vector3 start, in UnityEngine.Vector3 end, out RaycastHit hitInfo, LayerMask layerMask)
		{
			bool flag = Physics.Linecast(start, end, out hitInfo, layerMask);
			if (cvLocalNavigatorDebugDraw.value)
			{
				UnityEngine.Debug.DrawLine(start, end, UnityEngine.Color.yellow, raycastUpdateInterval);
				if (flag)
				{
					Util.DebugCross(hitInfo.point, 1f, UnityEngine.Color.red, raycastUpdateInterval);
				}
			}
			return flag;
		}

		private bool CheckCliffAhead(in BodySnapshot currentSnapshot, in SnapshotDelta currentSnapshotDelta, in UnityEngine.Vector3 currentMoveVector, float deltaTime)
		{
			if (!allowWalkOffCliff && currentSnapshot.isGrounded)
			{
				EstimateNextMovement(in currentSnapshot, in currentSnapshotDelta, in currentMoveVector, deltaTime, out var nextPosition, out var _);
				float num = currentSnapshot.chestPosition.y - currentSnapshot.position.y;
				float num2 = currentSnapshot.footPosition.y - currentSnapshot.position.y;
				UnityEngine.Vector3 start = nextPosition;
				start.y += num;
				UnityEngine.Vector3 end = start;
				end.y += num2;
				end.y -= 4f;
				RaycastHit hitInfo;
				return !Linecast(in start, in end, out hitInfo, LayerIndex.world.mask);
			}
			return false;
		}

		private void CalculateFrustration(float deltaTime, ref float frustration)
		{
			if (!currentSnapshot.canJump)
			{
				frustration = 0f;
			}
			else
			{
				if (!currentSnapshot.isValid || !currentSnapshotDelta.isValid || !currentSnapshotDelta.isValid || !previousSnapshotDelta.isValid)
				{
					return;
				}
				if (true)
				{
					UnityEngine.Vector3 rhs = FlattenDirection(moveVector);
					UnityEngine.Vector3 vector2 = FlattenDirection(currentSnapshotDelta.estimatedVelocity);
					UnityEngine.Vector3 vector3 = FlattenDirection(previousSnapshotDelta.estimatedVelocity);
					float num = UnityEngine.Vector3.Dot(vector2, rhs);
					velocityDelta = vector2 - vector3;
					estimatedAcceleration = velocityDelta / deltaTime;
					float num2 = UnityEngine.Vector3.Dot(estimatedAcceleration, rhs);
					float num3 = estimatedAcceleration.magnitude - num2;
					speedAsFractionOfTopSpeed = num / currentSnapshot.maxMoveSpeed;
					isAlreadyMovingAtSufficientSpeed = speedAsFractionOfTopSpeed >= 0.45f;
					if (isAlreadyMovingAtSufficientSpeed)
					{
						frustration = 0f;
					}
					else if (num3 > num2 * 2f)
					{
						frustration += 1.25f * deltaTime;
					}
					return;
				}
				float num4 = currentSnapshot.motorVelocity.magnitude + bodyComponents.motor.rootMotion.magnitude / deltaTime;
				float magnitude = (targetPosition - currentSnapshot.position).magnitude;
				if (currentSnapshot.maxMoveSpeed != 0f && num4 != 0f && magnitude > Mathf.Epsilon)
				{
					float magnitude2 = currentSnapshotDelta.estimatedVelocity.magnitude;
					if (magnitude2 <= num4 || magnitude2 <= 0.1f)
					{
						frustration += 1.25f * deltaTime;
					}
				}
			}
			static UnityEngine.Vector3 FlattenDirection(UnityEngine.Vector3 vector)
			{
				if (Mathf.Abs(vector.y) > 0f)
				{
					vector.y = 0f;
				}
				return vector;
			}
		}
	}
	public class LocalUser
	{
		private Player _inputPlayer;

		private UserProfile _userProfile;

		public int id;

		public PauseScreenController pauseScreenController;

		private CameraRigController _cameraRigController;

		public Player inputPlayer
		{
			get
			{
				return _inputPlayer;
			}
			set
			{
				if (_inputPlayer != value)
				{
					if (_inputPlayer != null)
					{
						OnRewiredPlayerLost(_inputPlayer);
					}
					_inputPlayer = value;
					eventSystem = MPEventSystemManager.FindEventSystem(_inputPlayer);
					if (_inputPlayer != null)
					{
						OnRewiredPlayerDiscovered(_inputPlayer);
					}
				}
			}
		}

		public MPEventSystem eventSystem { get; private set; }

		public UserProfile userProfile
		{
			get
			{
				return _userProfile;
			}
			set
			{
				_userProfile = value;
				ApplyUserProfileBindingsToRewiredPlayer();
			}
		}

		public bool isUIFocused
		{
			get
			{
				if (!eventSystem.currentSelectedGameObject && !eventSystem.IsPointerOverGameObject())
				{
					return pauseScreenController != null;
				}
				return true;
			}
		}

		public NetworkUser currentNetworkUser { get; private set; }

		public PlayerCharacterMasterController cachedMasterController { get; private set; }

		public CharacterMaster cachedMaster { get; private set; }

		public GameObject cachedMasterObject { get; private set; }

		public CharacterBody cachedBody { get; private set; }

		public GameObject cachedBodyObject { get; private set; }

		public PlayerStatsComponent cachedStatsComponent { get; private set; }

		public CameraRigController cameraRigController
		{
			get
			{
				return _cameraRigController;
			}
			set
			{
				if ((object)_cameraRigController != value)
				{
					if ((object)_cameraRigController != null)
					{
						this.onCameraLost?.Invoke(_cameraRigController);
					}
					_cameraRigController = value;
					if ((object)_cameraRigController != null)
					{
						this.onCameraDiscovered?.Invoke(_cameraRigController);
					}
				}
			}
		}

		public event Action onBodyChanged;

		public event Action onMasterChanged;

		public event Action<CameraRigController> onCameraDiscovered;

		public event Action<CameraRigController> onCameraLost;

		public event Action<NetworkUser> onNetworkUserFound;

		public event Action<NetworkUser> onNetworkUserLost;

		static LocalUser()
		{
			ReInput.ControllerConnectedEvent += OnControllerConnected;
			ReInput.ControllerDisconnectedEvent += OnControllerDisconnected;
		}

		private static void OnControllerConnected(ControllerStatusChangedEventArgs args)
		{
			DefaultControllerMaps.RewiredDebugLog($"OnControllerConnected: Name {args.name}, Type {args.controllerType}, Id {args.controllerId}");
			int count = LocalUserManager.readOnlyLocalUsersList.Count;
			for (int i = 0; i < count; i++)
			{
				LocalUser localUser = LocalUserManager.readOnlyLocalUsersList[i];
				if (localUser.inputPlayer.controllers.ContainsController(args.controllerType, args.controllerId))
				{
					localUser.OnControllerDiscovered(ReInput.controllers.GetController(args.controllerType, args.controllerId));
				}
			}
		}

		private static void OnControllerDisconnected(ControllerStatusChangedEventArgs args)
		{
			DefaultControllerMaps.RewiredDebugLog($"OnControllerDisconnected: Name {args.name}, Type {args.controllerType}, Id {args.controllerId}");
			int count = LocalUserManager.readOnlyLocalUsersList.Count;
			for (int i = 0; i < count; i++)
			{
				LocalUser localUser = LocalUserManager.readOnlyLocalUsersList[i];
				if (localUser.inputPlayer.controllers.ContainsController(args.controllerType, args.controllerId))
				{
					if (args.controllerType == ControllerType.Joystick && ReInput.controllers.GetControllers(ControllerType.Joystick).Length == 1)
					{
						break;
					}
					localUser.OnControllerLost(ReInput.controllers.GetController(args.controllerType, args.controllerId));
				}
			}
		}

		public static void DumpControllerMap(ControllerMap inControllerMap, StringBuilder inDumpSB = null, bool inForceDump = false)
		{
			if ((!DefaultControllerMaps.RewiredLoggingEnabled() && !inForceDump) || inControllerMap == null)
			{
				return;
			}
			if (inDumpSB == null)
			{
				new StringBuilder();
			}
			foreach (ActionElementMap allMap in inControllerMap.AllMaps)
			{
				_ = allMap;
			}
		}

		private void OnRewiredPlayerDiscovered(Player player)
		{
			foreach (Controller controller in player.controllers.Controllers)
			{
				DefaultControllerMaps.RewiredDebugLog("- HERE -------------------------------------------------------------------------");
				DefaultControllerMaps.RewiredDebugLog($"Dumping maps for controller {controller.hardwareName} (Ident {controller.hardwareIdentifier}, HWGUID {controller.hardwareTypeGuid})");
				DumpControllerMap(player.controllers.maps.GetMap(controller, "Default", "Default"));
				DumpControllerMap(player.controllers.maps.GetMap(controller, "UI", "UI"));
				OnControllerDiscovered(controller);
			}
		}

		private void OnRewiredPlayerLost(Player player)
		{
			foreach (Controller controller in player.controllers.Controllers)
			{
				OnControllerLost(controller);
			}
		}

		private void OnControllerDiscovered(Controller controller)
		{
			ApplyUserProfileBindingsToRewiredPlayer();
		}

		private void OnControllerLost(Controller controller)
		{
			inputPlayer.controllers.maps.ClearMapsForController(controller.type, controller.id, userAssignableOnly: true);
		}

		private static bool UseJpLayout()
		{
			return false;
		}

		public static void LoadInitialUIMap()
		{
			bool flag = UseJpLayout();
			foreach (Player player in ReInput.players.Players)
			{
				player.controllers.maps.ClearAllMaps(userAssignableOnly: false);
				foreach (Controller controller in player.controllers.Controllers)
				{
					if (controller.type == ControllerType.Joystick && flag)
					{
						player.controllers.maps.LoadMap(controller.type, controller.id, 2, 1);
						if (InputBindingDisplayController.onBindingsChanged != null)
						{
							InputBindingDisplayController.onBindingsChanged();
						}
						continue;
					}
					try
					{
						player.controllers.maps.LoadMap(controller.type, controller.id, 2, 0);
					}
					catch (FormatException exception)
					{
						UnityEngine.Debug.LogWarning($"Excepting loading controller mapping (type:{controller.type},id:{controller.id}) for player (name:{player.name},id:{player.id}).");
						UnityEngine.Debug.LogException(exception);
					}
				}
				player.controllers.maps.SetAllMapsEnabled(state: true);
			}
		}

		public void ApplyUserProfileBindingsToRewiredPlayer(bool requirePlayer = true)
		{
			if (inputPlayer == null || userProfile == null)
			{
				return;
			}
			bool flag = UseJpLayout();
			foreach (Player player in ReInput.players.Players)
			{
				foreach (Controller controller in player.controllers.Controllers)
				{
					DefaultControllerMaps.RewiredDebugLog("***** ApplyUserProfileBindingsToRewiredPlayer> Player {0}, Controller {1} (Type {2}, HWName {3}, HWGUID {4})", (player != null) ? player.name : "*null*", (controller != null) ? controller.name : "*null*", (controller != null) ? controller.type.ToString() : "*null*", (controller != null) ? controller.hardwareName : "*null*", (controller != null) ? controller.hardwareTypeGuid.ToString() : "-----");
					if (controller.type == ControllerType.Joystick && flag)
					{
						player.controllers.maps.RemoveMap(controller.type, controller.id, 2, 0);
						player.controllers.maps.LoadMap(controller.type, controller.id, 2, 1);
						if (InputBindingDisplayController.onBindingsChanged != null)
						{
							InputBindingDisplayController.onBindingsChanged();
						}
					}
					else if (controller.type != ControllerType.Joystick)
					{
						try
						{
							player.controllers.maps.LoadMap(controller.type, controller.id, 2, 0);
						}
						catch (FormatException exception)
						{
							UnityEngine.Debug.LogWarning($"Excepting loading controller mapping (type:{controller.type},id:{controller.id}) for player (name:{player.name},id:{player.id}).");
							UnityEngine.Debug.LogException(exception);
						}
					}
					ApplyUserProfileBindingstoRewiredController(player, controller);
				}
				player.controllers.maps.SetAllMapsEnabled(state: true);
			}
			RoR2Application.DebugPrintRewired();
			void ApplyUserProfileBindingstoRewiredController(Player iterPlayer, Controller controller)
			{
				if (userProfile != null)
				{
					ControllerMap controllerMap = null;
					switch (controller.type)
					{
					case ControllerType.Keyboard:
						controllerMap = userProfile.keyboardMap;
						break;
					case ControllerType.Mouse:
						controllerMap = userProfile.mouseMap;
						break;
					case ControllerType.Joystick:
						controllerMap = userProfile.GetJoystickMap(controller.hardwareTypeGuid);
						break;
					}
					if (controllerMap != null)
					{
						DefaultControllerMaps.RewiredDebugLog("***** ApplyUserProfileBindingstoRewiredController> Player {0}, Controller {1} (Type {2}, HWName {3}, HWGUID {4})", (iterPlayer != null) ? iterPlayer.name : "*null*", (controller != null) ? controller.name : "*null*", (controller != null) ? controller.type.ToString() : "*null*", (controller != null) ? controller.hardwareName : "*null*", (controller != null) ? controller.hardwareTypeGuid.ToString() : "-----");
						DumpControllerMap(controllerMap);
						inputPlayer.controllers.maps.AddMap(controller, controllerMap);
					}
				}
			}
		}

		public UIInputPassthrough GetUIPassthrough()
		{
			if ((bool)eventSystem && (bool)eventSystem.currentSelectedGameObject)
			{
				return eventSystem.currentSelectedGameObject.GetComponent<UIInputPassthrough>();
			}
			return null;
		}

		public void RebuildControlChain()
		{
			PlayerCharacterMasterController playerCharacterMasterController = cachedMasterController;
			cachedMasterController = null;
			cachedMasterObject = null;
			cachedMaster = null;
			cachedStatsComponent = null;
			CharacterBody characterBody = cachedBody;
			cachedBody = null;
			cachedBodyObject = null;
			if ((bool)currentNetworkUser)
			{
				cachedMasterObject = currentNetworkUser.masterObject;
				if ((bool)cachedMasterObject)
				{
					cachedMasterController = cachedMasterObject.GetComponent<PlayerCharacterMasterController>();
				}
				if ((bool)cachedMasterController)
				{
					cachedMaster = cachedMasterController.master;
					if ((bool)cachedMaster)
					{
						cachedStatsComponent = cachedMaster.playerStatsComponent;
					}
					cachedBody = cachedMaster.GetBody();
					if ((bool)cachedBody)
					{
						cachedBodyObject = cachedBody.gameObject;
					}
				}
			}
			if ((object)characterBody != cachedBody)
			{
				this.onBodyChanged?.Invoke();
			}
			if ((object)playerCharacterMasterController != cachedMasterController)
			{
				this.onMasterChanged?.Invoke();
			}
		}

		public void LinkNetworkUser(NetworkUser newNetworkUser)
		{
			if (!currentNetworkUser)
			{
				currentNetworkUser = newNetworkUser;
				newNetworkUser.localUser = this;
				this.onNetworkUserFound?.Invoke(newNetworkUser);
			}
		}

		public void UnlinkNetworkUser()
		{
			this.onNetworkUserLost?.Invoke(currentNetworkUser);
			currentNetworkUser.localUser = null;
			currentNetworkUser = null;
			cachedMasterController = null;
			cachedMasterObject = null;
			cachedBody = null;
			cachedBodyObject = null;
		}
	}
	public static class LocalUserManager
	{
		public struct LocalUserInitializationInfo
		{
			public Player player;

			public UserProfile profile;
		}

		private class UserProfileMainConVar : BaseConVar
		{
			public static UserProfileMainConVar instance = new UserProfileMainConVar("user_profile_main", ConVarFlags.Archive, null, "The current user profile.");

			public string lastReceivedValue;

			public UserProfileMainConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				lastReceivedValue = newValue;
				if (!isAnyUserSignedIn && ready)
				{
					AddMainUser(newValue);
				}
			}

			public override string GetString()
			{
				int num = FindUserIndex(GetRewiredMainPlayer());
				if (num == -1)
				{
					return "";
				}
				return localUsersList[num].userProfile.fileName;
			}
		}

		private static readonly List<LocalUser> localUsersList = new List<LocalUser>();

		public static readonly ReadOnlyCollection<LocalUser> readOnlyLocalUsersList = localUsersList.AsReadOnly();

		public static Player startPlayer;

		private static bool ready = false;

		public static bool isAnyUserSignedIn => localUsersList.Count > 0;

		public static bool HasUsers => localUsersList.Count > 0;

		public static event Action<LocalUser> onUserSignIn;

		public static event Action<LocalUser> onUserSignOut;

		public static event Action onLocalUsersUpdated;

		public static bool UserExists(Player inputPlayer)
		{
			for (int i = 0; i < localUsersList.Count; i++)
			{
				if (localUsersList[i].inputPlayer == inputPlayer)
				{
					return true;
				}
			}
			return false;
		}

		private static int FindUserIndex(int userId)
		{
			for (int i = 0; i < localUsersList.Count; i++)
			{
				if (localUsersList[i].id == userId)
				{
					return i;
				}
			}
			return -1;
		}

		public static LocalUser FindLocalUser(int userId)
		{
			for (int i = 0; i < localUsersList.Count; i++)
			{
				if (localUsersList[i].id == userId)
				{
					return localUsersList[i];
				}
			}
			return null;
		}

		public static LocalUser FindLocalUser(Player inputPlayer)
		{
			for (int i = 0; i < localUsersList.Count; i++)
			{
				if (localUsersList[i].inputPlayer == inputPlayer)
				{
					return localUsersList[i];
				}
			}
			return null;
		}

		public static LocalUser FindLocalUserByPlayerName(string playerName)
		{
			for (int i = 0; i < localUsersList.Count; i++)
			{
				if (localUsersList[i].inputPlayer.name == playerName)
				{
					return localUsersList[i];
				}
			}
			UnityEngine.Debug.LogError("Failed to find player " + playerName);
			return null;
		}

		public static LocalUser GetFirstLocalUser()
		{
			if (localUsersList.Count <= 0)
			{
				return null;
			}
			return localUsersList[0];
		}

		private static int FindUserIndex(Player inputPlayer)
		{
			for (int i = 0; i < localUsersList.Count; i++)
			{
				if (localUsersList[i].inputPlayer == inputPlayer)
				{
					return i;
				}
			}
			return -1;
		}

		private static int GetFirstAvailableId()
		{
			int i;
			for (i = 0; i < localUsersList.Count; i++)
			{
				if (FindUserIndex(i) == -1)
				{
					return i;
				}
			}
			return i;
		}

		private static void AddUser(Player inputPlayer, UserProfile userProfile)
		{
			RoR2Application.IsAllUsersEntitlementsUpdated = false;
			if (!UserExists(inputPlayer))
			{
				int firstAvailableId = GetFirstAvailableId();
				LocalUser localUser = new LocalUser
				{
					inputPlayer = inputPlayer,
					id = firstAvailableId,
					userProfile = userProfile
				};
				localUsersList.Add(localUser);
				userProfile.OnLogin();
				MPEventSystem.FindByPlayer(inputPlayer).localUser = localUser;
				if (LocalUserManager.onUserSignIn != null)
				{
					LocalUserManager.onUserSignIn(localUser);
				}
				if (LocalUserManager.onLocalUsersUpdated != null)
				{
					LocalUserManager.onLocalUsersUpdated();
				}
			}
		}

		public static bool IsUserChangeSafe()
		{
			if (SceneManager.GetActiveScene().name == "title")
			{
				return true;
			}
			return false;
		}

		public static void SetLocalUsers(LocalUserInitializationInfo[] initializationInfo)
		{
			if (localUsersList.Count > 0)
			{
				UnityEngine.Debug.LogError("Cannot call LocalUserManager.SetLocalUsers while users are already signed in!");
				return;
			}
			if (!IsUserChangeSafe())
			{
				UnityEngine.Debug.LogError("Cannot call LocalUserManager.SetLocalUsers at this time, user login changes are not safe at this time.");
				return;
			}
			if (initializationInfo.Length == 1)
			{
				initializationInfo[0].player = GetRewiredMainPlayer();
			}
			for (int i = 0; i < initializationInfo.Length; i++)
			{
				AddUser(initializationInfo[i].player, initializationInfo[i].profile);
			}
		}

		private static Player GetRewiredMainPlayer()
		{
			return ReInput.players.GetPlayer("PlayerMain");
		}

		private static void AddMainUser(UserProfile userProfile)
		{
			AddUser(GetRewiredMainPlayer(), userProfile);
		}

		private static bool AddMainUser(string userProfileName)
		{
			UserProfile profile = PlatformSystems.saveSystem.GetProfile(userProfileName);
			if (profile != null && !profile.isCorrupted)
			{
				AddMainUser(profile);
				return true;
			}
			return false;
		}

		public static void RemoveUser(Player inputPlayer)
		{
			int num = FindUserIndex(inputPlayer);
			if (num != -1)
			{
				RemoveUser(num);
			}
		}

		private static void RemoveUser(int userIndex)
		{
			LocalUser localUser = localUsersList[userIndex];
			if (LocalUserManager.onUserSignOut != null)
			{
				LocalUserManager.onUserSignOut(localUser);
			}
			localUser.userProfile.OnLogout();
			MPEventSystem.FindByPlayer(localUser.inputPlayer).localUser = null;
			localUsersList.RemoveAt(userIndex);
			if (LocalUserManager.onLocalUsersUpdated != null)
			{
				LocalUserManager.onLocalUsersUpdated();
			}
		}

		public static void ClearUsers()
		{
			if (!IsUserChangeSafe())
			{
				UnityEngine.Debug.LogError("Cannot call LocalUserManager.SetLocalUsers at this time, user login changes are not safe at this time.");
				return;
			}
			for (int num = localUsersList.Count - 1; num >= 0; num--)
			{
				RemoveUser(num);
			}
		}

		private static Player ListenForStartSignIn()
		{
			IList<Player> players = ReInput.players.Players;
			for (int i = 0; i < players.Count; i++)
			{
				Player player = players[i];
				if (!(player.name == "PlayerMain") && !UserExists(player) && player.GetButtonDown(11))
				{
					return player;
				}
			}
			return null;
		}

		public static void Init()
		{
			ready = true;
			RoR2Application.onUpdate += Update;
			SaveSystem.onAvailableUserProfilesChanged += LogInWithPreviousSessionUser;
			static void LogInWithPreviousSessionUser()
			{
				if (UserProfileMainConVar.instance.lastReceivedValue != null)
				{
					AddMainUser(UserProfileMainConVar.instance.lastReceivedValue);
				}
				else if (PlatformSystems.saveSystem.loadedUserProfiles.Count != 0)
				{
					AddMainUser(PlatformSystems.saveSystem.loadedUserProfiles.First().Key);
				}
				SaveSystem.onAvailableUserProfilesChanged -= LogInWithPreviousSessionUser;
			}
		}

		private static void Update()
		{
			for (int i = 0; i < localUsersList.Count; i++)
			{
				localUsersList[i].RebuildControlChain();
			}
		}

		[ConCommand(commandName = "remove_all_local_users", flags = ConVarFlags.None, helpText = "Removes all local users.")]
		private static void CCRemoveAllLocalUsers(ConCommandArgs args)
		{
			ClearUsers();
		}

		[ConCommand(commandName = "remove_all_local_users_menu", flags = ConVarFlags.None, helpText = "Removes all local users. (invoked via the profile button on applicable platforms)")]
		private static void CCRemoveAllLocalUsersMenu(ConCommandArgs args)
		{
			ClearUsers();
		}

		[ConCommand(commandName = "print_local_users", flags = ConVarFlags.None, helpText = "Prints a list of all local users.")]
		private static void CCPrintLocalUsers(ConCommandArgs args)
		{
			string[] array = new string[localUsersList.Count];
			for (int i = 0; i < localUsersList.Count; i++)
			{
				if (localUsersList[i] != null)
				{
					array[i] = string.Format("localUsersList[{0}] id={1} userProfile={2}", i, localUsersList[i].id, (localUsersList[i].userProfile != null) ? localUsersList[i].userProfile.fileName : "null");
				}
				else
				{
					array[i] = $"localUsersList[{i}] null";
				}
			}
		}

		[ConCommand(commandName = "test_splitscreen", flags = ConVarFlags.None, helpText = "Logs in the specified number of guest users, or two by default.")]
		private static void CCTestSplitscreen(ConCommandArgs args)
		{
			int num = 2;
			if (args.Count >= 1 && TextSerialization.TryParseInvariant(args[0], out int result))
			{
				num = Mathf.Clamp(result, 1, 4);
			}
			if (NetworkClient.active)
			{
				return;
			}
			ClearUsers();
			LocalUserInitializationInfo[] array = new LocalUserInitializationInfo[num];
			for (int i = 0; i < num; i++)
			{
				string text = "Player";
				switch (i)
				{
				case 0:
					text += "Main";
					break;
				case 1:
					text += "2";
					break;
				case 2:
					text += "3";
					break;
				case 3:
					text += "4";
					break;
				}
				array[i] = new LocalUserInitializationInfo
				{
					player = ReInput.players.GetPlayer(text),
					profile = PlatformSystems.saveSystem.CreateGuestProfile()
				};
			}
			SetLocalUsers(array);
		}

		[ConCommand(commandName = "export_controller_maps", flags = ConVarFlags.None, helpText = "Prints all Rewired ControllerMaps of the first player as xml.")]
		public static void CCExportControllerMaps(ConCommandArgs args)
		{
			if (localUsersList.Count <= 0)
			{
				return;
			}
			foreach (string item in from v in localUsersList[0].inputPlayer.controllers.maps.GetAllMaps()
				select v.ToXmlString())
			{
				_ = item;
			}
		}
	}
	[Serializable]
	public enum MageElement : byte
	{
		None,
		Fire,
		Ice,
		Lightning,
		Count
	}
	public static class MasterCatalog
	{
		public struct MasterIndex : IEquatable<MasterIndex>
		{
			private readonly int i;

			public static readonly MasterIndex none = new MasterIndex(-1);

			public bool isValid => i >= 0;

			public MasterIndex(int i)
			{
				this.i = i;
			}

			public static explicit operator int(MasterIndex masterIndex)
			{
				return masterIndex.i;
			}

			public static explicit operator MasterIndex(int value)
			{
				return new MasterIndex(value);
			}

			public bool Equals(MasterIndex other)
			{
				return i == other.i;
			}

			public override bool Equals(object obj)
			{
				if (obj is MasterIndex other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return i;
			}

			public static bool operator ==(MasterIndex a, MasterIndex b)
			{
				return a.i == b.i;
			}

			public static bool operator !=(MasterIndex a, MasterIndex b)
			{
				return a.i != b.i;
			}
		}

		[Serializable]
		public struct NetworkMasterIndex : IEquatable<NetworkMasterIndex>
		{
			public uint i;

			public static implicit operator NetworkMasterIndex(MasterIndex masterIndex)
			{
				NetworkMasterIndex result = default(NetworkMasterIndex);
				result.i = (uint)((int)masterIndex + 1);
				return result;
			}

			public static implicit operator MasterIndex(NetworkMasterIndex networkMasterIndex)
			{
				return new MasterIndex((int)(networkMasterIndex.i - 1));
			}

			public bool Equals(NetworkMasterIndex other)
			{
				return i == other.i;
			}

			public override bool Equals(object obj)
			{
				if (obj is MasterIndex masterIndex)
				{
					return Equals(masterIndex);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (int)i;
			}
		}

		private static bool isInitialized = false;

		private static GameObject[] masterPrefabs;

		private static CharacterMaster[] masterPrefabMasterComponents;

		private static CharacterMaster[] aiMasterPrefabs;

		private static readonly Dictionary<string, MasterIndex> nameToIndexMap = new Dictionary<string, MasterIndex>();

		public static IEnumerable<CharacterMaster> allMasters => masterPrefabMasterComponents;

		public static IEnumerable<CharacterMaster> allAiMasters => aiMasterPrefabs;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<GameObject>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.MasterCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.masterPrefabs);
			}
			remove
			{
			}
		}

		public static GameObject GetMasterPrefab(MasterIndex masterIndex)
		{
			return ArrayUtils.GetSafe(masterPrefabs, (int)masterIndex);
		}

		public static MasterIndex FindMasterIndex([NotNull] string masterName)
		{
			if (nameToIndexMap.TryGetValue(masterName, out var value))
			{
				return value;
			}
			return MasterIndex.none;
		}

		public static MasterIndex FindMasterIndex(GameObject masterObject)
		{
			if (!masterObject)
			{
				return MasterIndex.none;
			}
			return FindMasterIndex(masterObject.name);
		}

		public static GameObject FindMasterPrefab([NotNull] string bodyName)
		{
			MasterIndex masterIndex = FindMasterIndex(bodyName);
			if (masterIndex.isValid)
			{
				return GetMasterPrefab(masterIndex);
			}
			return null;
		}

		public static MasterIndex FindAiMasterIndexForBody(BodyIndex bodyIndex)
		{
			CharacterMaster[] array = aiMasterPrefabs;
			foreach (CharacterMaster characterMaster in array)
			{
				if (characterMaster.bodyPrefab.GetComponent<CharacterBody>().bodyIndex == bodyIndex)
				{
					return characterMaster.masterIndex;
				}
			}
			return MasterIndex.none;
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			if (!isInitialized)
			{
				SetEntries(ContentManager.masterPrefabs);
				isInitialized = true;
			}
		}

		private static void SetEntries(GameObject[] newEntries)
		{
			masterPrefabs = ArrayUtils.Clone(newEntries);
			Array.Sort(masterPrefabs, (GameObject a, GameObject b) => string.CompareOrdinal(a.name, b.name));
			masterPrefabMasterComponents = new CharacterMaster[masterPrefabs.Length];
			for (int i = 0; i < masterPrefabs.Length; i++)
			{
				MasterIndex masterIndex = new MasterIndex(i);
				GameObject obj = masterPrefabs[i];
				string name = obj.name;
				CharacterMaster component = obj.GetComponent<CharacterMaster>();
				nameToIndexMap.Add(name, masterIndex);
				nameToIndexMap.Add(name + "(Clone)", masterIndex);
				masterPrefabMasterComponents[i] = component;
				component.masterIndex = masterIndex;
			}
			aiMasterPrefabs = masterPrefabMasterComponents.Where((CharacterMaster master) => master.GetComponent<BaseAI>()).ToArray();
		}
	}
	public class MasterSummon
	{
		public struct MasterSummonReport
		{
			public CharacterMaster summonMasterInstance;

			public CharacterMaster leaderMasterInstance;
		}

		public interface IInventorySetupCallback
		{
			void SetupSummonedInventory([NotNull] MasterSummon masterSummon, [NotNull] Inventory summonedInventory);
		}

		public GameObject masterPrefab;

		public UnityEngine.Vector3 position;

		public UnityEngine.Quaternion rotation;

		public GameObject summonerBodyObject;

		public TeamIndex? teamIndexOverride;

		public bool ignoreTeamMemberLimit;

		public Action<CharacterMaster> preSpawnSetupCallback;

		public Loadout loadout;

		public bool? useAmbientLevel;

		[CanBeNull]
		public Inventory inventoryToCopy;

		[CanBeNull]
		public Func<ItemIndex, bool> inventoryItemCopyFilter;

		public IInventorySetupCallback inventorySetupCallback;

		public static event Action<MasterSummonReport> onServerMasterSummonGlobal;

		public CharacterMaster Perform()
		{
			TeamIndex teamIndex = TeamIndex.None;
			if (teamIndexOverride.HasValue)
			{
				teamIndex = teamIndexOverride.Value;
			}
			else
			{
				if (!summonerBodyObject)
				{
					UnityEngine.Debug.LogErrorFormat("Cannot spawn master {0}: No team specified.", masterPrefab);
					return null;
				}
				teamIndex = TeamComponent.GetObjectTeam(summonerBodyObject);
			}
			if (!ignoreTeamMemberLimit)
			{
				TeamDef teamDef = TeamCatalog.GetTeamDef(teamIndex);
				if (teamDef == null)
				{
					UnityEngine.Debug.LogErrorFormat("Attempting to spawn master {0} on TeamIndex.None. Is this intentional?", masterPrefab);
					return null;
				}
				if (teamDef != null && teamDef.softCharacterLimit <= TeamComponent.GetTeamMembers(teamIndex).Count)
				{
					return null;
				}
			}
			CharacterBody characterBody = null;
			CharacterMaster characterMaster = null;
			SkinDef skinDef = null;
			if ((bool)summonerBodyObject)
			{
				characterBody = summonerBodyObject.GetComponent<CharacterBody>();
				skinDef = SkinCatalog.FindCurrentSkinDefForBodyInstance(summonerBodyObject);
			}
			if ((bool)characterBody)
			{
				characterMaster = characterBody.master;
			}
			Inventory inventory = characterMaster?.inventory;
			GameObject gameObject = UnityEngine.Object.Instantiate(masterPrefab, position, rotation);
			CharacterMaster component = gameObject.GetComponent<CharacterMaster>();
			component.teamIndex = teamIndex;
			Loadout loadout = Loadout.RequestInstance();
			this.loadout?.Copy(loadout);
			if ((bool)skinDef)
			{
				SkinDef.MinionSkinReplacement[] minionSkinReplacements = skinDef.minionSkinReplacements;
				if (minionSkinReplacements.Length != 0)
				{
					for (int i = 0; i < minionSkinReplacements.Length; i++)
					{
						BodyIndex bodyIndex = BodyCatalog.FindBodyIndex(minionSkinReplacements[i].minionBodyPrefab);
						int num = SkinCatalog.FindLocalSkinIndexForBody(bodyIndex, minionSkinReplacements[i].minionSkin);
						if (num != -1)
						{
							loadout.bodyLoadoutManager.SetSkinIndex(bodyIndex, (uint)num);
						}
					}
				}
			}
			component.SetLoadoutServer(loadout);
			Loadout.ReturnInstance(loadout);
			CharacterMaster characterMaster2 = characterMaster;
			if ((bool)characterMaster2 && (bool)characterMaster2.minionOwnership.ownerMaster)
			{
				characterMaster2 = characterMaster2.minionOwnership.ownerMaster;
			}
			component.minionOwnership.SetOwner(characterMaster2);
			if ((bool)summonerBodyObject)
			{
				AIOwnership component2 = gameObject.GetComponent<AIOwnership>();
				if ((bool)component2)
				{
					if ((bool)characterMaster)
					{
						component2.ownerMaster = characterMaster;
					}
					CharacterBody component3 = summonerBodyObject.GetComponent<CharacterBody>();
					if ((bool)component3)
					{
						CharacterMaster master = component3.master;
						if ((bool)master)
						{
							component2.ownerMaster = master;
						}
					}
				}
				BaseAI component4 = gameObject.GetComponent<BaseAI>();
				if ((bool)component4)
				{
					component4.leader.gameObject = summonerBodyObject;
				}
			}
			if ((bool)inventoryToCopy)
			{
				component.inventory.CopyEquipmentFrom(inventoryToCopy);
				component.inventory.CopyItemsFrom(inventoryToCopy, inventoryItemCopyFilter ?? Inventory.defaultItemCopyFilterDelegate);
			}
			inventorySetupCallback?.SetupSummonedInventory(this, component.inventory);
			bool flag = false;
			if (!useAmbientLevel.HasValue)
			{
				if ((bool)inventory && inventory.GetItemCount(RoR2Content.Items.UseAmbientLevel) > 0)
				{
					flag = true;
				}
			}
			else
			{
				flag = useAmbientLevel.Value;
			}
			if (flag)
			{
				component.inventory.GiveItem(RoR2Content.Items.UseAmbientLevel);
			}
			if ((bool)inventory && useAmbientLevel != false)
			{
				component.inventory.GiveItem(RoR2Content.Items.UseAmbientLevel, inventory.GetItemCount(RoR2Content.Items.UseAmbientLevel));
			}
			preSpawnSetupCallback?.Invoke(component);
			NetworkServer.Spawn(gameObject);
			component.Respawn(position, rotation, wasRevivedMidStage: true);
			MasterSummon.onServerMasterSummonGlobal?.Invoke(new MasterSummonReport
			{
				leaderMasterInstance = characterMaster2,
				summonMasterInstance = component
			});
			return component;
		}
	}
	public struct MemoizedGetComponent<TComponent> where TComponent : Component
	{
		private GameObject cachedGameObject;

		private TComponent cachedValue;

		public TComponent Get(GameObject gameObject)
		{
			if (cachedGameObject != gameObject)
			{
				cachedGameObject = gameObject;
				cachedValue = (gameObject ? gameObject.GetComponent<TComponent>() : null);
			}
			return cachedValue;
		}
	}
	public enum MiscPickupIndex
	{
		None = -1
	}
	public static class MiscPickupCatalog
	{
		private static MiscPickupDef[] _miscPickupDefs = Array.Empty<MiscPickupDef>();

		public static ResourceAvailability availability = default(ResourceAvailability);

		public static IReadOnlyList<MiscPickupDef> miscPickupDefs => _miscPickupDefs;

		public static int pickupCount => _miscPickupDefs.Length;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			ArrayUtils.CloneTo(ContentManager.miscPickupDefs, ref _miscPickupDefs);
			for (int i = 0; i < _miscPickupDefs.Length; i++)
			{
				_miscPickupDefs[i].miscPickupIndex = (MiscPickupIndex)i;
			}
			availability.MakeAvailable();
		}

		public static MiscPickupDef GetMiscDef(MiscPickupIndex miscIndex)
		{
			return ArrayUtils.GetSafe(_miscPickupDefs, (int)miscIndex);
		}
	}
	public static class MorgueManager
	{
		private struct HistoryFileInfo
		{
			public UPath path;

			public DateTime lastModified;

			public FileEntry fileEntry;

			public RunReport LoadRunReport()
			{
				RunReport value = new RunReport();
				HGXml.FromXml(XDocument.Parse(fileEntry.ReadAllText()).Root, ref value);
				return value;
			}

			public void Delete()
			{
				fileEntry.Delete();
			}
		}

		private static readonly IntConVar morgueHistoryLimit = new IntConVar("morgue_history_limit", ConVarFlags.Archive, "30", "How many non-favorited entries we can store in the morgue before old ones are deleted.");

		private static readonly UPath historyDirectory = new UPath("/RunReports/History/");

		private static IFileSystem storage => RoR2Application.fileSystem;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			Run.onClientGameOverGlobal += OnClientGameOverGlobal;
		}

		private static void OnClientGameOverGlobal(Run run, RunReport runReport)
		{
			AddRunReportToHistory(runReport);
		}

		private static int CompareHistoryFileLastModified(HistoryFileInfo a, HistoryFileInfo b)
		{
			return b.lastModified.CompareTo(a.lastModified);
		}

		private static void AddRunReportToHistory(RunReport runReport)
		{
			EnforceHistoryLimit();
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			string fileName = stringBuilder.Append(runReport.runGuid).Append(".xml").ToString();
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				if (!runReport.HasUserParticipated(readOnlyLocalUsers))
				{
					continue;
				}
				using Stream stream = GetHistoryFile(fileName, readOnlyLocalUsers.userProfile.saveID);
				if (stream != null)
				{
					XDocument xDocument = new XDocument();
					xDocument.Add(HGXml.ToXml("RunReport", RunReport.GetLocalUserRunReport(runReport, readOnlyLocalUsers)));
					xDocument.Save(stream);
					stream.Flush();
					stream.Dispose();
				}
			}
		}

		private static void EnforceHistoryLimit()
		{
			List<HistoryFileInfo> list = CollectionPool<HistoryFileInfo, List<HistoryFileInfo>>.RentCollection();
			GetHistoryFiles(list);
			list.Sort(CompareHistoryFileLastModified);
			int num = list.Count - 1;
			int num2 = Math.Max(morgueHistoryLimit.value, 0);
			while (num >= num2)
			{
				list[num].Delete();
				num--;
			}
			CollectionPool<HistoryFileInfo, List<HistoryFileInfo>>.ReturnCollection(list);
		}

		public static void LoadHistoryRunReports(List<RunReport> dest)
		{
			List<HistoryFileInfo> list = CollectionPool<HistoryFileInfo, List<HistoryFileInfo>>.RentCollection();
			GetHistoryFiles(list);
			list.Sort(CompareHistoryFileLastModified);
			for (int i = 0; i < list.Count; i++)
			{
				HistoryFileInfo historyFileInfo = list[i];
				try
				{
					UnityEngine.Debug.LogFormat("loading RunReport {0}", historyFileInfo.path);
					RunReport item = historyFileInfo.LoadRunReport();
					dest.Add(item);
				}
				catch (Exception ex)
				{
					UnityEngine.Debug.LogFormat("Could not load RunReport \"{0}\": {1}", historyFileInfo, ex);
				}
			}
			CollectionPool<HistoryFileInfo, List<HistoryFileInfo>>.ReturnCollection(list);
		}

		private static Stream GetHistoryFile(string fileName)
		{
			UPath path = historyDirectory / fileName;
			storage.CreateDirectory(historyDirectory);
			return storage.OpenFile(path, FileMode.Create, FileAccess.Write);
		}

		private static Stream GetHistoryFile(string fileName, ulong inSaveID)
		{
			return GetHistoryFile(fileName);
		}

		private static void GetHistoryFiles(List<HistoryFileInfo> dest)
		{
			foreach (UPath item in storage.DirectoryExists(historyDirectory) ? storage.EnumeratePaths(historyDirectory) : Enumerable.Empty<UPath>())
			{
				if (storage.FileExists(item) && item.GetExtensionWithDot().Equals(".xml", StringComparison.OrdinalIgnoreCase))
				{
					dest.Add(new HistoryFileInfo
					{
						path = item,
						lastModified = storage.GetLastWriteTime(item),
						fileEntry = storage.GetFileEntry(item)
					});
				}
			}
		}
	}
	public enum MusicTrackIndex
	{
		Invalid = -1
	}
	public static class MusicTrackCatalog
	{
		private static MusicTrackDef[] musicTrackDefs = Array.Empty<MusicTrackDef>();

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<MusicTrackDef>> collectEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.MusicTrackCatalog.collectEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.musicTrackDefs);
			}
			remove
			{
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetEntries(ContentManager.musicTrackDefs);
		}

		private static void SetEntries(MusicTrackDef[] newMusicTrackDefs)
		{
			MusicTrackDef[] array = musicTrackDefs;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].catalogIndex = MusicTrackIndex.Invalid;
			}
			ArrayUtils.CloneTo(newMusicTrackDefs, ref musicTrackDefs);
			Array.Sort(musicTrackDefs, (MusicTrackDef a, MusicTrackDef b) => string.CompareOrdinal(a.cachedName, b.cachedName));
			for (int j = 0; j < musicTrackDefs.Length; j++)
			{
				musicTrackDefs[j].catalogIndex = (MusicTrackIndex)j;
			}
		}

		public static MusicTrackDef GetMusicTrackDef(MusicTrackIndex musicTrackIndex)
		{
			return ArrayUtils.GetSafe(musicTrackDefs, (int)musicTrackIndex);
		}

		public static MusicTrackDef FindMusicTrackDef(string name)
		{
			return GetMusicTrackDef(FindMusicTrackIndex(name));
		}

		public static MusicTrackIndex FindMusicTrackIndex(string name)
		{
			for (int i = 0; i < musicTrackDefs.Length; i++)
			{
				if (string.CompareOrdinal(musicTrackDefs[i].cachedName, name) == 0)
				{
					return (MusicTrackIndex)i;
				}
			}
			return MusicTrackIndex.Invalid;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/MusicTrackDef")]
	public class MusicTrackDef : ScriptableObject
	{
		public Bank soundBank;

		public State[] states;

		[Multiline]
		public string comment;

		private string _cachedName;

		public MusicTrackIndex catalogIndex { get; set; }

		[Obsolete(".name should not be used. Use .cachedName instead. If retrieving the value from the engine is absolutely necessary, cast to ScriptableObject first.", true)]
		public new string name
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public string cachedName
		{
			get
			{
				return _cachedName;
			}
			set
			{
				base.name = value;
				_cachedName = value;
			}
		}

		private void Awake()
		{
			_cachedName = base.name;
		}

		private void OnValidate()
		{
			_cachedName = base.name;
		}

		public virtual void Preload()
		{
			soundBank?.Load();
		}

		public virtual void Play()
		{
			Preload();
			State[] array = states;
			foreach (State state in array)
			{
				AkSoundEngine.SetState(state.GroupId, state.Id);
			}
		}

		public virtual void Stop()
		{
			if (states != null)
			{
				State[] array = states;
				for (int i = 0; i < array.Length; i++)
				{
					AkSoundEngine.SetState(array[i].GroupId, 0u);
				}
			}
		}
	}
	[Serializable]
	public struct NetworkUserId : IEquatable<NetworkUserId>
	{
		[SerializeField]
		public ulong value;

		[SerializeField]
		public string strValue;

		[SerializeField]
		public readonly byte subId;

		public PlatformID steamId => new PlatformID(value);

		private NetworkUserId(ulong value, byte subId)
		{
			this.value = value;
			this.subId = subId;
			strValue = null;
		}

		public NetworkUserId(string strValue, byte subId)
		{
			value = 0uL;
			this.subId = subId;
			this.strValue = strValue;
		}

		public NetworkUserId(PlatformID userId, byte subId)
		{
			if (userId.isSteam)
			{
				value = userId.ID;
				strValue = null;
			}
			else
			{
				strValue = userId.stringID;
				value = 0uL;
			}
			this.subId = subId;
		}

		public static NetworkUserId FromIp(string ip, byte subId)
		{
			return new NetworkUserId((ulong)ip.GetHashCode(), subId);
		}

		public static NetworkUserId FromId(ulong id, byte subId)
		{
			return new NetworkUserId(id, subId);
		}

		public bool HasValidValue()
		{
			if (value == 0L)
			{
				return strValue != null;
			}
			return true;
		}

		public bool Equals(NetworkUserId other)
		{
			if (value == other.value && strValue == other.strValue)
			{
				return subId == other.subId;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is NetworkUserId)
			{
				return Equals((NetworkUserId)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (value.GetHashCode() * 397) ^ subId.GetHashCode();
		}
	}
	public static class TransitionCommand
	{
		private static float timer;

		private static string commandString;

		public static bool requestPending { get; private set; }

		private static void Update()
		{
			if (FadeToBlackManager.fullyFaded)
			{
				RoR2Application.onUpdate -= Update;
				requestPending = false;
				FadeToBlackManager.fadeCount--;
				string cmd = commandString;
				commandString = null;
				Console.instance.SubmitCmd(null, cmd);
			}
		}

		[ConCommand(commandName = "transition_command", flags = ConVarFlags.None, helpText = "Fade out and execute a command at the end of the fadeout.")]
		private static void CCTransitionCommand(ConCommandArgs args)
		{
			args.CheckArgumentCount(1);
			if (!requestPending)
			{
				requestPending = true;
				commandString = args[0];
				FadeToBlackManager.fadeCount++;
				RoR2Application.onUpdate += Update;
			}
		}

		public static void ForceClearFadeToBlack()
		{
			RoR2Application.onUpdate -= Update;
			requestPending = false;
			commandString = null;
		}
	}
	public static class NetworkModCompatibilityHelper
	{
		[NotNull]
		public delegate byte[] ModListHasherDelegate([NotNull] IEnumerable<string> modList);

		public static readonly string steamworksGameserverGameDataValuePrefix;

		public static readonly string steamworksGameserverRulesBaseName;

		private static string[] _networkModList;

		private static ModListHasherDelegate _modListHasher;

		public static string networkModHash { get; private set; }

		public static string steamworksGameserverGameDataValue { get; private set; }

		public static string steamworksGameserverGameRulesValue { get; private set; }

		public static IEnumerable<string> networkModList
		{
			get
			{
				return _networkModList;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				List<string> list = CollectionPool<string, List<string>>.RentCollection();
				foreach (string item in value)
				{
					if (item == null)
					{
						throw new ArgumentException("Argument cannot contain null entries.", "value");
					}
					list.Add(item);
				}
				_networkModList = list.ToArray();
				CollectionPool<string, List<string>>.ReturnCollection(list);
				Rebuild();
			}
		}

		public static ModListHasherDelegate modListHasher
		{
			get
			{
				return _modListHasher;
			}
			set
			{
				_modListHasher = value ?? throw new ArgumentNullException("value");
				Rebuild();
			}
		}

		public static event Action onUpdated;

		public static byte[] DefaultModListHasher([NotNull] IEnumerable<string> networkModList)
		{
			HashAlgorithm hashAlgorithm = MD5.Create();
			byte[] result = hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(string.Join(",", networkModList)));
			hashAlgorithm.Dispose();
			return result;
		}

		private static void Rebuild()
		{
			byte[] array = modListHasher(networkModList);
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			for (int i = 0; i < array.Length; i++)
			{
				stringBuilder.AppendByteHexValue(array[i]);
			}
			networkModHash = stringBuilder.ToString();
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			steamworksGameserverGameDataValue = steamworksGameserverGameDataValuePrefix + networkModHash;
			steamworksGameserverGameRulesValue = string.Join(",", _networkModList);
			NetworkModCompatibilityHelper.onUpdated?.Invoke();
		}

		static NetworkModCompatibilityHelper()
		{
			networkModHash = string.Empty;
			steamworksGameserverGameDataValuePrefix = "modHash=";
			steamworksGameserverGameDataValue = string.Empty;
			steamworksGameserverRulesBaseName = "mods";
			steamworksGameserverGameRulesValue = string.Empty;
			_networkModList = Array.Empty<string>();
			_modListHasher = DefaultModListHasher;
			Rebuild();
		}
	}
	public struct NetworkPlayerName
	{
		public PlatformID playerId;

		public string nameOverride;

		public void Deserialize(NetworkReader reader)
		{
			if (reader.ReadBoolean())
			{
				playerId = PlatformID.nil;
				nameOverride = reader.ReadString();
			}
			else
			{
				playerId = new PlatformID(reader.ReadUInt64());
				nameOverride = null;
			}
		}

		public void Serialize(NetworkWriter writer)
		{
			bool flag = nameOverride != null;
			writer.Write(flag);
			if (flag)
			{
				writer.Write(nameOverride);
			}
			else
			{
				writer.Write((ulong)playerId.value);
			}
		}

		public string GetResolvedName()
		{
			if (!string.IsNullOrEmpty(nameOverride))
			{
				return (PlatformSystems.lobbyManager as EOSLobbyManager).GetUserDisplayNameFromProductIdString(nameOverride);
			}
			if (PlatformSystems.ShouldUseEpicOnlineSystems)
			{
				EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
				PlatformID user = playerId;
				return obj.GetUserDisplayName(user);
			}
			Client instance = Client.Instance;
			if (instance != null)
			{
				return instance.Friends.GetName(playerId.ID);
			}
			return "???";
		}
	}
	public static class OffScreenMissHelper
	{
		public static bool IsPositionOffScreen(UnityEngine.Vector3 position, float offScreenThreshold = -0.5f, float minDistance = 5f, float maxDistance = 120f)
		{
			bool result = true;
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				CharacterBody currentBody = readOnlyInstances.GetCurrentBody();
				if ((object)currentBody == null)
				{
					continue;
				}
				NetworkedViewAngles component = readOnlyInstances.GetComponent<NetworkedViewAngles>();
				if ((object)component == null)
				{
					continue;
				}
				UnityEngine.Vector3 vector = currentBody.transform.position - position;
				float magnitude = vector.magnitude;
				if (!(magnitude > maxDistance))
				{
					if (magnitude < minDistance)
					{
						result = false;
						break;
					}
					if (UnityEngine.Vector3.Dot(UnityEngine.Quaternion.Euler(component.viewAngles.pitch, component.viewAngles.yaw, 0f) * UnityEngine.Vector3.forward, vector.normalized) < offScreenThreshold)
					{
						result = false;
						break;
					}
				}
			}
			return result;
		}

		public static UnityEngine.Vector3 ApplyRandomTrajectoryOffset(UnityEngine.Vector3 hitTrajectory, float magnitude = 4f)
		{
			return Util.ApplySpread(hitTrajectory, magnitude, magnitude, 1f, 1f);
		}
	}
	public class BullseyeSearchOpt
	{
		public enum SortMode
		{
			None,
			Distance,
			Angle,
			DistanceAndAngle
		}

		private struct CandidateInfo : IEquatable<CandidateInfo>
		{
			[StructLayout(LayoutKind.Sequential, Size = 1)]
			public struct EntityEqualityComparer : IEqualityComparer<CandidateInfo>
			{
				public bool Equals(CandidateInfo a, CandidateInfo b)
				{
					return (object)a.hurtBox.healthComponent == b.hurtBox.healthComponent;
				}

				public int GetHashCode(CandidateInfo obj)
				{
					return obj.hurtBox.healthComponent.GetHashCode();
				}
			}

			public HurtBox hurtBox;

			public UnityEngine.Vector3 position;

			public UnityEngine.Vector3 toTarget;

			public float dot;

			public float distanceSqr;

			public bool Equals(CandidateInfo other)
			{
				return hurtBox == other.hurtBox;
			}

			public override bool Equals(object obj)
			{
				if (obj is CandidateInfo)
				{
					return hurtBox == ((CandidateInfo)obj).hurtBox;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return hurtBox.GetHashCode();
			}

			public static bool CandidatesEqual(CandidateInfo a, CandidateInfo b)
			{
				return a.distanceSqr == b.distanceSqr;
			}
		}

		public CharacterBody viewer;

		public UnityEngine.Vector3 searchOrigin;

		public UnityEngine.Vector3 searchDirection;

		public float minDistanceFilter;

		public float maxDistanceFilter = float.PositiveInfinity;

		public TeamMask teamMaskFilter = TeamMask.allButNeutral;

		public bool filterByLoS = true;

		public bool filterByDistinctEntity;

		public QueryTriggerInteraction queryTriggerInteraction;

		public BullseyeSearch.SortMode sortMode = BullseyeSearch.SortMode.Distance;

		private float minThetaDot = -1f;

		private bool InUse;

		private List<CandidateInfo> candidates = new List<CandidateInfo>(10);

		private Func<CandidateInfo, CandidateInfo, int> CompareDistSqFunc = CompareDistanceSq;

		private Func<CandidateInfo, CandidateInfo, int> CompareDistSqAndAngleFunc = CompareDistSqAndAngle;

		private Func<CandidateInfo, CandidateInfo, int> CompareAngleFunc = CompareAngle;

		private static readonly float fullVisionMinThetaDot = Mathf.Cos(MathF.PI);

		private static BullseyeSearchOpt _search = new BullseyeSearchOpt();

		public float maxAngleFilter
		{
			set
			{
				SetMinAngleDeg(value);
			}
		}

		private bool filterByDistance
		{
			get
			{
				if (!(minDistanceFilter > 0f))
				{
					return maxDistanceFilter < float.PositiveInfinity;
				}
				return true;
			}
		}

		private bool filterByAngle => minThetaDot > fullVisionMinThetaDot;

		public int Count => candidates.Count;

		public void SetMinAngleDeg(float inAngle)
		{
			if (inAngle >= 180f)
			{
				minThetaDot = fullVisionMinThetaDot;
			}
			else
			{
				minThetaDot = Mathf.Cos(inAngle * (MathF.PI / 180f));
			}
		}

		public void RefreshCandidates(bool wantAll = false)
		{
			int count = HurtBox.readOnlyBullseyesList.Count;
			candidates.Clear();
			for (int i = 0; i < count; i++)
			{
				HurtBox hurtBox = HurtBox.readOnlyBullseyesList[i];
				CharacterBody characterBody = null;
				if (!teamMaskFilter.HasTeam(hurtBox.teamIndex))
				{
					continue;
				}
				CandidateInfo item = default(CandidateInfo);
				UnityEngine.Vector3 position = hurtBox.transform.position;
				UnityEngine.Vector3 vector = position - searchOrigin;
				item.hurtBox = hurtBox;
				item.position = position;
				item.toTarget = vector;
				bool flag = true;
				bool flag2 = true;
				bool flag3 = true;
				float num = minDistanceFilter * minDistanceFilter;
				float num2 = maxDistanceFilter * maxDistanceFilter;
				float num3 = (item.distanceSqr = vector.sqrMagnitude);
				if (filterByDistance)
				{
					flag = num3 >= num && num3 <= num2;
					flag3 = flag3 && flag;
				}
				if (filterByAngle && flag3)
				{
					float num4 = Mathf.Sqrt(num3);
					UnityEngine.Vector3 rhs = vector / num4;
					float num5 = UnityEngine.Vector3.Dot(searchDirection, rhs);
					flag2 = num5 >= minThetaDot;
					item.dot = num5;
					item.distanceSqr = num3;
					flag3 = flag3 && flag2;
				}
				if (!filterByAngle && flag3 && sortMode == BullseyeSearch.SortMode.Angle)
				{
					float num6 = Mathf.Sqrt(num3);
					UnityEngine.Vector3 rhs2 = vector / num6;
					float num7 = UnityEngine.Vector3.Dot(searchDirection, rhs2);
					flag2 = num7 >= minThetaDot;
					item.dot = num7;
					item.distanceSqr = num3;
				}
				if (filterByDistinctEntity && flag3)
				{
					for (int j = 0; j < candidates.Count; j++)
					{
						if ((object)candidates[j].hurtBox.healthComponent == hurtBox.healthComponent)
						{
							flag3 = false;
							break;
						}
					}
				}
				if (flag3 && (bool)viewer)
				{
					characterBody = hurtBox.healthComponent.body;
					flag3 &= characterBody.GetVisibilityLevel(viewer) >= VisibilityLevel.Revealed;
				}
				if (wantAll && flag3 && filterByLoS)
				{
					float num8 = Mathf.Sqrt(num3);
					UnityEngine.Vector3 direction = vector / num8;
					RaycastHit hitInfo;
					bool flag4 = Physics.Raycast(searchOrigin, direction, out hitInfo, num8, LayerIndex.world.mask, queryTriggerInteraction);
					flag3 = flag3 && !flag4;
				}
				if (flag3)
				{
					candidates.Add(item);
				}
			}
			switch (sortMode)
			{
			case BullseyeSearch.SortMode.Angle:
				HeapSort<CandidateInfo>.Sort(candidates, CompareAngleFunc);
				break;
			case BullseyeSearch.SortMode.Distance:
				HeapSort<CandidateInfo>.Sort(candidates, CompareDistSqFunc);
				break;
			case BullseyeSearch.SortMode.DistanceAndAngle:
				HeapSort<CandidateInfo>.Sort(candidates, CompareDistSqAndAngleFunc);
				break;
			}
		}

		public HurtBox GetClosestCandidate(List<HealthComponent> exclude)
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers((!teamMaskFilter.HasTeam(TeamIndex.Monster)) ? TeamIndex.Player : TeamIndex.Monster);
			int count = teamMembers.Count;
			CandidateInfo candidateInfo = default(CandidateInfo);
			candidateInfo.distanceSqr = float.PositiveInfinity;
			bool flag = false;
			for (int i = 0; i < count; i++)
			{
				CharacterBody body = teamMembers[i].body;
				if (!exclude.Contains(body.healthComponent))
				{
					CandidateInfo candidateInfo2 = default(CandidateInfo);
					UnityEngine.Vector3 corePosition = body.corePosition;
					UnityEngine.Vector3 vector = corePosition - searchOrigin;
					candidateInfo2.hurtBox = body.mainHurtBox;
					candidateInfo2.position = corePosition;
					bool flag2 = true;
					bool flag3 = true;
					bool flag4 = true;
					float num = minDistanceFilter * minDistanceFilter;
					float num2 = maxDistanceFilter * maxDistanceFilter;
					float num3 = (candidateInfo2.distanceSqr = vector.sqrMagnitude);
					if (filterByDistance)
					{
						flag2 = num3 >= num && num3 <= num2;
						flag4 = flag4 && flag2;
					}
					if (filterByAngle && flag4)
					{
						float num4 = Mathf.Sqrt(num3);
						UnityEngine.Vector3 rhs = vector / num4;
						float num5 = UnityEngine.Vector3.Dot(searchDirection, rhs);
						flag3 = num5 >= minThetaDot;
						candidateInfo2.dot = num5;
						candidateInfo2.distanceSqr = num3;
						flag4 = flag4 && flag3;
					}
					if (flag4 && (bool)viewer)
					{
						flag4 &= body.GetVisibilityLevel(viewer) >= VisibilityLevel.Revealed;
					}
					if (flag4 && filterByLoS)
					{
						float num6 = Mathf.Sqrt(num3);
						UnityEngine.Vector3 direction = vector / num6;
						RaycastHit hitInfo;
						bool flag5 = Physics.Raycast(searchOrigin, direction, out hitInfo, num6, LayerIndex.world.mask, queryTriggerInteraction);
						flag4 = flag4 && !flag5;
					}
					if (flag4 && candidateInfo2.distanceSqr < candidateInfo.distanceSqr)
					{
						candidateInfo = candidateInfo2;
						flag = true;
					}
				}
			}
			if (flag)
			{
				return candidateInfo.hurtBox;
			}
			return null;
		}

		public HurtBox GetClosestCandidateFromList(List<HealthComponent> validTargets, HealthComponent prevTarget, out int resultIndex)
		{
			CandidateInfo candidateInfo = default(CandidateInfo);
			candidateInfo.distanceSqr = float.PositiveInfinity;
			bool flag = false;
			int count = validTargets.Count;
			resultIndex = -1;
			for (int i = 0; i < count; i++)
			{
				HealthComponent healthComponent = validTargets[i];
				if (!healthComponent || !healthComponent.alive || healthComponent == prevTarget)
				{
					continue;
				}
				CharacterBody body = healthComponent.body;
				if ((bool)body && (bool)body.mainHurtBox)
				{
					CandidateInfo candidateInfo2 = default(CandidateInfo);
					UnityEngine.Vector3 corePosition = body.corePosition;
					UnityEngine.Vector3 vector = corePosition - searchOrigin;
					candidateInfo2.hurtBox = body.mainHurtBox;
					candidateInfo2.position = corePosition;
					bool flag2 = true;
					bool flag3 = true;
					bool flag4 = true;
					if (flag4 && !candidateInfo2.hurtBox.gameObject.activeInHierarchy)
					{
						flag4 = false;
					}
					float num = minDistanceFilter * minDistanceFilter;
					float num2 = maxDistanceFilter * maxDistanceFilter;
					float num3 = (candidateInfo2.distanceSqr = vector.sqrMagnitude);
					if (filterByDistance && flag4)
					{
						flag2 = num3 >= num && num3 <= num2;
						flag4 = flag4 && flag2;
					}
					if (filterByAngle && flag4)
					{
						float num4 = Mathf.Sqrt(num3);
						UnityEngine.Vector3 rhs = vector / num4;
						float num5 = UnityEngine.Vector3.Dot(searchDirection, rhs);
						flag3 = num5 >= minThetaDot;
						candidateInfo2.dot = num5;
						candidateInfo2.distanceSqr = num3;
						flag4 = flag4 && flag3;
					}
					if (flag4 && (bool)viewer)
					{
						flag4 &= body.GetVisibilityLevel(viewer) >= VisibilityLevel.Revealed;
					}
					if (flag4 && filterByLoS)
					{
						float num6 = Mathf.Sqrt(num3);
						UnityEngine.Vector3 direction = vector / num6;
						RaycastHit hitInfo;
						bool flag5 = Physics.Raycast(searchOrigin, direction, out hitInfo, num6, LayerIndex.world.mask, queryTriggerInteraction);
						flag4 = flag4 && !flag5;
					}
					if (flag4 && candidateInfo2.distanceSqr < candidateInfo.distanceSqr)
					{
						candidateInfo = candidateInfo2;
						flag = true;
						resultIndex = i;
					}
				}
			}
			if (flag)
			{
				return candidateInfo.hurtBox;
			}
			return null;
		}

		public void RefreshCandidates_Cheap()
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers((!teamMaskFilter.HasTeam(TeamIndex.Monster)) ? TeamIndex.Player : TeamIndex.Monster);
			int count = teamMembers.Count;
			candidates.Clear();
			for (int i = 0; i < count; i++)
			{
				CharacterBody body = teamMembers[i].body;
				CandidateInfo item = default(CandidateInfo);
				UnityEngine.Vector3 corePosition = body.corePosition;
				UnityEngine.Vector3 vector = corePosition - searchOrigin;
				item.hurtBox = body.mainHurtBox;
				item.position = corePosition;
				item.toTarget = vector;
				bool flag = true;
				bool flag2 = true;
				bool flag3 = true;
				float num = minDistanceFilter * minDistanceFilter;
				float num2 = maxDistanceFilter * maxDistanceFilter;
				float num3 = (item.distanceSqr = vector.sqrMagnitude);
				if (filterByDistance)
				{
					flag = num3 >= num && num3 <= num2;
					flag3 = flag3 && flag;
				}
				if (filterByAngle)
				{
					float num4 = Mathf.Sqrt(num3);
					UnityEngine.Vector3 rhs = vector / num4;
					float num5 = UnityEngine.Vector3.Dot(searchDirection, rhs);
					flag2 = num5 >= minThetaDot;
					item.dot = num5;
					item.distanceSqr = num3;
					flag3 = flag3 && flag2;
				}
				if (flag3 && (bool)viewer)
				{
					flag3 &= body.GetVisibilityLevel(viewer) >= VisibilityLevel.Revealed;
				}
				if (flag3 && filterByLoS)
				{
					float num6 = Mathf.Sqrt(num3);
					UnityEngine.Vector3 direction = vector / num6;
					RaycastHit hitInfo;
					bool flag4 = Physics.Raycast(searchOrigin, direction, out hitInfo, num6, LayerIndex.world.mask, queryTriggerInteraction);
					flag3 = flag3 && !flag4;
				}
				if (flag3)
				{
					candidates.Add(item);
				}
			}
			switch (sortMode)
			{
			case BullseyeSearch.SortMode.Angle:
				HeapSort<CandidateInfo>.Sort(candidates, CompareAngleFunc);
				break;
			case BullseyeSearch.SortMode.Distance:
				HeapSort<CandidateInfo>.Sort(candidates, CompareDistSqFunc);
				break;
			case BullseyeSearch.SortMode.DistanceAndAngle:
				HeapSort<CandidateInfo>.Sort(candidates, CompareDistSqAndAngleFunc);
				break;
			}
		}

		public void FilterOutGameObject(GameObject gameObject)
		{
			for (int num = candidates.Count - 1; num >= 0; num--)
			{
				if (candidates[num].hurtBox.healthComponent.gameObject == gameObject)
				{
					candidates.RemoveAt(num);
				}
			}
		}

		public void FilterToComponent<T>() where T : Component
		{
			for (int num = candidates.Count - 1; num >= 0; num--)
			{
				if (candidates[num].hurtBox.healthComponent.GetComponent<T>() == null)
				{
					candidates.RemoveAt(num);
				}
			}
		}

		public void FilterNotInList(List<HealthComponent> list)
		{
			for (int num = candidates.Count - 1; num >= 0; num--)
			{
				HurtBox hurtBox = candidates[num].hurtBox;
				if (list.Contains(hurtBox.healthComponent))
				{
					candidates.RemoveAt(num);
				}
			}
		}

		public void FilterInList(List<HealthComponent> list)
		{
			for (int num = candidates.Count - 1; num >= 0; num--)
			{
				HurtBox hurtBox = candidates[num].hurtBox;
				if (!list.Contains(hurtBox.healthComponent))
				{
					candidates.RemoveAt(num);
				}
			}
		}

		public HurtBox FirstInList(List<HealthComponent> list)
		{
			HurtBox result = null;
			for (int i = 0; i < candidates.Count; i++)
			{
				HurtBox hurtBox = candidates[i].hurtBox;
				if (!list.Contains(hurtBox.healthComponent))
				{
					result = hurtBox;
					break;
				}
			}
			return result;
		}

		public void FilterCandidatesByHealthFraction(float minHealthFraction = 0f, float maxHealthFraction = 1f)
		{
			if (minHealthFraction > 0f)
			{
				if (maxHealthFraction < 1f)
				{
					for (int num = candidates.Count - 1; num > 0; num--)
					{
						float combinedHealthFraction = candidates[num].hurtBox.healthComponent.combinedHealthFraction;
						if (combinedHealthFraction >= minHealthFraction && !(combinedHealthFraction <= maxHealthFraction))
						{
							candidates.RemoveAt(num);
						}
					}
					return;
				}
				for (int num2 = candidates.Count - 1; num2 > 0; num2--)
				{
					if (!(candidates[num2].hurtBox.healthComponent.combinedHealthFraction >= minHealthFraction))
					{
						candidates.RemoveAt(num2);
					}
				}
			}
			else
			{
				if (!(maxHealthFraction < 1f))
				{
					return;
				}
				for (int num3 = candidates.Count - 1; num3 > 0; num3--)
				{
					if (!(candidates[num3].hurtBox.healthComponent.combinedHealthFraction <= maxHealthFraction))
					{
						candidates.RemoveAt(num3);
					}
				}
			}
		}

		public HurtBox FirstOrDefault()
		{
			HurtBox result = null;
			if (candidates.Count > 0)
			{
				if (filterByLoS)
				{
					for (int i = 0; i < candidates.Count; i++)
					{
						float num = Mathf.Sqrt(candidates[i].distanceSqr);
						UnityEngine.Vector3 direction = candidates[i].toTarget / num;
						if (!Physics.Raycast(searchOrigin, direction, out var _, num, LayerIndex.world.mask, queryTriggerInteraction))
						{
							return candidates[i].hurtBox;
						}
					}
				}
				else
				{
					result = candidates[0].hurtBox;
				}
			}
			return result;
		}

		public void DebugPrint()
		{
			for (int i = 0; i < candidates.Count; i++)
			{
				UnityEngine.Debug.LogError("C" + i + ": " + candidates[i].hurtBox.healthComponent.gameObject.name + ", " + candidates[i].distanceSqr + ", " + candidates[i].dot);
			}
		}

		public HurtBox FirstOrDefaultNotInList(List<HealthComponent> list)
		{
			HurtBox result = null;
			if (candidates.Count > 0)
			{
				for (int i = 0; i < candidates.Count; i++)
				{
					HurtBox hurtBox = candidates[i].hurtBox;
					if (!list.Contains(hurtBox.healthComponent))
					{
						return hurtBox;
					}
				}
			}
			return result;
		}

		public HurtBox RandomSelect()
		{
			HurtBox result = null;
			if (candidates.Count > 0)
			{
				int index = UnityEngine.Random.Range(0, candidates.Count);
				result = candidates[index].hurtBox;
			}
			return result;
		}

		public void Reset()
		{
			candidates.Clear();
			viewer = null;
			searchOrigin = UnityEngine.Vector3.zero;
			searchDirection = UnityEngine.Vector3.zero;
			minDistanceFilter = 0f;
			maxDistanceFilter = float.PositiveInfinity;
			teamMaskFilter = TeamMask.allButNeutral;
			filterByLoS = true;
			filterByDistinctEntity = false;
			queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sortMode = BullseyeSearch.SortMode.Distance;
			minThetaDot = -1f;
			InUse = false;
		}

		private static float DistSq(UnityEngine.Vector3 a, UnityEngine.Vector3 b)
		{
			return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) * ((a.z - b.z) * (a.z - b.z));
		}

		private static int CompareDistanceSq(CandidateInfo left, CandidateInfo right)
		{
			float num = left.distanceSqr - right.distanceSqr;
			if (num < 0f)
			{
				return -1;
			}
			if (num > 0f)
			{
				return 1;
			}
			return 0;
		}

		private static int CompareAngle(CandidateInfo left, CandidateInfo right)
		{
			float num = 0f - left.dot;
			float num2 = 0f - right.dot;
			float num3 = num - num2;
			if (num3 < 0f)
			{
				return -1;
			}
			if (num3 > 0f)
			{
				return 1;
			}
			return 0;
		}

		private static int CompareDistSqAndAngle(CandidateInfo left, CandidateInfo right)
		{
			float num = (0f - left.dot) * left.distanceSqr;
			float num2 = (0f - right.dot) * right.distanceSqr;
			float num3 = num - num2;
			if (num3 < 0f)
			{
				return -1;
			}
			if (num3 > 0f)
			{
				return 1;
			}
			return 0;
		}

		public HurtBox GetHurtBox(int idx)
		{
			return candidates[idx].hurtBox;
		}

		public static BullseyeSearchOpt FromPool()
		{
			if (!_search.InUse)
			{
				_search.InUse = true;
			}
			else
			{
				UnityEngine.Debug.LogErrorFormat("BullseyeSearch at limit");
			}
			return _search;
		}

		public static void ReturnPool(BullseyeSearchOpt inSearch)
		{
			if (_search == inSearch)
			{
				_search.Reset();
			}
			else
			{
				UnityEngine.Debug.LogError("BullseyeSearch in use!");
			}
		}
	}
	public class EffectManagerHelper : MonoBehaviour
	{
		protected List<ParticleSystem> _ParticleSystems;

		protected EffectComponent _effectComponent;

		protected VFXAttributes _vfxAttributes;

		protected HoverOverHead _hoverOverHead;

		protected List<Tracer> _tracers;

		protected EffectPool _OwningPool;

		protected bool _IsInitialized;

		protected DestroyOnTimer _destroyOnTimer;

		protected OrbEffect _orbEffect;

		protected Tracer _tracer;

		protected List<AnimateShaderAlpha> _AnimateShaderAlphasDestroyOnEnd;

		protected List<AnimateShaderAlpha> _ActiveAnimateShaderAlphasDestroyOnEnd;

		protected List<AnimateShaderAlpha> _AnimateShaderAlphasDisableOnEnd;

		protected List<AnimateShaderAlpha> _ActiveAnimateShaderAlphasDisableOnEnd;

		protected List<AnimateShaderAlpha> _AnimateShaderAlphas;

		protected List<AnimateShaderAlpha> _ActiveAnimateShaderAlphas;

		protected List<TrailRenderer> _TrailRenderers;

		protected List<LineRenderer> _LineRenderers;

		protected LineRenderer _RootLineRenderer;

		protected List<AkEvent> _AkEvents_Start;

		protected List<AkEvent> _AkEvents_Destroy;

		protected List<DestroyOnParticleEnd> _DestroyOnParticleEnds;

		protected List<DetachParticleOnDestroyAndEndEmission> _DetachParticlesOnDestroyAndEndEmissions;

		protected bool _TriggeredDisable;

		protected List<GameObject> _ActiveGameObjects;

		protected List<ShakeEmitter> _ShakeEmitters;

		protected List<OmniEffect> _OmniEffects;

		[Tooltip("Some projectile scripts will prematurely pool ghosts that don't appear to need to exist after the projectile is gone. If your ghost is being prematurely pooled by a projectile script, enable this.")]
		[FormerlySerializedAs("SimulateDestroyOnTimer")]
		[SerializeField]
		public bool DontAllowProjectilesToPrematurelyPool;

		public EffectComponent effectComponent => _effectComponent;

		public EffectPool OwningPool => _OwningPool;

		public bool HasDestroyOnTimer
		{
			get
			{
				if (!DontAllowProjectilesToPrematurelyPool)
				{
					return _destroyOnTimer != null;
				}
				return true;
			}
		}

		public bool HasAnimateShaderAlphas
		{
			get
			{
				if (_ActiveAnimateShaderAlphasDestroyOnEnd == null || _ActiveAnimateShaderAlphasDestroyOnEnd.Count <= 0)
				{
					if (_ActiveAnimateShaderAlphasDisableOnEnd != null)
					{
						return _ActiveAnimateShaderAlphasDisableOnEnd.Count > 0;
					}
					return false;
				}
				return true;
			}
		}

		public bool HasDetachParticlesOnDestroy
		{
			get
			{
				if (_DetachParticlesOnDestroyAndEndEmissions != null)
				{
					return _DetachParticlesOnDestroyAndEndEmissions.Count > 0;
				}
				return false;
			}
		}

		public bool HasDestroyOnParticleEnd
		{
			get
			{
				if (_DestroyOnParticleEnds != null)
				{
					return _DestroyOnParticleEnds.Count > 0;
				}
				return false;
			}
		}

		private void OnDestroy()
		{
			if (OwningPool != null)
			{
				OwningPool.RemoveObject(this);
				SetOwningPool(null);
			}
		}

		public void SetOwningPool(EffectPool inOwner)
		{
			_OwningPool = inOwner;
		}

		protected void FindAndCacheComponents<T>(ref List<T> refList) where T : Component
		{
			T[] componentsInChildren = base.gameObject.GetComponentsInChildren<T>(includeInactive: true);
			if (componentsInChildren != null && componentsInChildren.Length != 0)
			{
				if (refList == null)
				{
					refList = new List<T>();
				}
				T[] array = componentsInChildren;
				foreach (T item in array)
				{
					refList.Add(item);
				}
			}
		}

		protected void RecursiveFindActiveObjects(Transform inTransform, Transform inRootTransform, List<GameObject> inWhitelistObjects)
		{
			if (inWhitelistObjects.Contains(inTransform.gameObject))
			{
				return;
			}
			int childCount = inTransform.childCount;
			for (int i = 0; i < childCount; i++)
			{
				RecursiveFindActiveObjects(inTransform.GetChild(i), inRootTransform, inWhitelistObjects);
			}
			if (inTransform != inRootTransform && inTransform.gameObject.activeSelf)
			{
				if (_ActiveGameObjects == null)
				{
					_ActiveGameObjects = new List<GameObject>();
				}
				_ActiveGameObjects.Add(inTransform.gameObject);
			}
		}

		public void Initialize()
		{
			if (_IsInitialized)
			{
				return;
			}
			_effectComponent = base.gameObject.GetComponent<EffectComponent>();
			_vfxAttributes = base.gameObject.GetComponent<VFXAttributes>();
			_hoverOverHead = base.gameObject.GetComponent<HoverOverHead>();
			if ((bool)_vfxAttributes && _OwningPool != null)
			{
				_OwningPool.DoNotCull = _vfxAttributes.DoNotCullPool;
			}
			if (EffectManager.UsePools)
			{
				FindAndCacheComponents(ref _tracers);
				FindAndCacheComponents(ref _ParticleSystems);
				if (_ParticleSystems != null)
				{
					foreach (ParticleSystem particleSystem in _ParticleSystems)
					{
						if (particleSystem.main.stopAction == ParticleSystemStopAction.Destroy)
						{
							ParticleSystem.MainModule main = particleSystem.main;
							main.stopAction = ParticleSystemStopAction.None;
						}
					}
				}
				_orbEffect = GetComponent<OrbEffect>();
				if (_orbEffect != null)
				{
					_orbEffect.PrepForPoolUsage();
				}
				_tracer = GetComponent<Tracer>();
				if (_tracer != null)
				{
					_tracer.PrepForPoolUsage();
				}
				AnimateShaderAlpha[] componentsInChildren = base.gameObject.GetComponentsInChildren<AnimateShaderAlpha>(includeInactive: true);
				if (componentsInChildren != null && componentsInChildren.Length != 0)
				{
					AnimateShaderAlpha[] array = componentsInChildren;
					foreach (AnimateShaderAlpha animateShaderAlpha in array)
					{
						animateShaderAlpha.initialyEnabled = animateShaderAlpha.enabled;
						if (!animateShaderAlpha.continueExistingAfterTimeMaxIsReached)
						{
							animateShaderAlpha.OnFinished.AddListener(OnAnimateShaderAlphaComplete);
						}
						if (animateShaderAlpha.destroyOnEnd)
						{
							if (_AnimateShaderAlphasDestroyOnEnd == null)
							{
								_AnimateShaderAlphasDestroyOnEnd = new List<AnimateShaderAlpha>();
							}
							_AnimateShaderAlphasDestroyOnEnd.Add(animateShaderAlpha);
							if (animateShaderAlpha.enabled)
							{
								if (_ActiveAnimateShaderAlphasDestroyOnEnd == null)
								{
									_ActiveAnimateShaderAlphasDestroyOnEnd = new List<AnimateShaderAlpha>();
								}
								_ActiveAnimateShaderAlphasDestroyOnEnd.Add(animateShaderAlpha);
							}
							continue;
						}
						if (animateShaderAlpha.disableOnEnd)
						{
							if (_AnimateShaderAlphasDisableOnEnd == null)
							{
								_AnimateShaderAlphasDisableOnEnd = new List<AnimateShaderAlpha>();
							}
							_AnimateShaderAlphasDisableOnEnd.Add(animateShaderAlpha);
							if (animateShaderAlpha.enabled)
							{
								if (_ActiveAnimateShaderAlphasDisableOnEnd == null)
								{
									_ActiveAnimateShaderAlphasDisableOnEnd = new List<AnimateShaderAlpha>();
								}
								_ActiveAnimateShaderAlphasDisableOnEnd.Add(animateShaderAlpha);
							}
							continue;
						}
						if (_AnimateShaderAlphas == null)
						{
							_AnimateShaderAlphas = new List<AnimateShaderAlpha>();
						}
						_AnimateShaderAlphas.Add(animateShaderAlpha);
						if (animateShaderAlpha.enabled)
						{
							if (_ActiveAnimateShaderAlphas == null)
							{
								_ActiveAnimateShaderAlphas = new List<AnimateShaderAlpha>();
							}
							_ActiveAnimateShaderAlphas.Add(animateShaderAlpha);
						}
					}
				}
				if (_ActiveAnimateShaderAlphasDestroyOnEnd != null && OwningPool != null)
				{
					foreach (AnimateShaderAlpha item in _ActiveAnimateShaderAlphasDestroyOnEnd)
					{
						item.destroyOnEnd = false;
						item.disableOnEnd = true;
					}
				}
				FindAndCacheComponents(ref _TrailRenderers);
				if (_TrailRenderers != null)
				{
					foreach (TrailRenderer trailRenderer in _TrailRenderers)
					{
						trailRenderer.autodestruct = false;
					}
				}
				FindAndCacheComponents(ref _LineRenderers);
				_RootLineRenderer = base.gameObject.GetComponent<LineRenderer>();
				if (_RootLineRenderer != null && !_RootLineRenderer.enabled)
				{
					_RootLineRenderer = null;
				}
				AkEvent[] componentsInChildren2 = base.gameObject.GetComponentsInChildren<AkEvent>();
				if (componentsInChildren2 != null && componentsInChildren2.Length != 0)
				{
					AkEvent[] array2 = componentsInChildren2;
					foreach (AkEvent akEvent in array2)
					{
						if (akEvent.triggerList.Contains(1281810935))
						{
							if (_AkEvents_Start == null)
							{
								_AkEvents_Start = new List<AkEvent>();
							}
							_AkEvents_Start.Add(akEvent);
						}
						if (akEvent.triggerList.Contains(-358577003))
						{
							if (_AkEvents_Destroy == null)
							{
								_AkEvents_Destroy = new List<AkEvent>();
							}
							_AkEvents_Destroy.Add(akEvent);
						}
					}
				}
				FindAndCacheComponents(ref _DestroyOnParticleEnds);
				if (_DestroyOnParticleEnds != null && _DestroyOnParticleEnds.Count > 0)
				{
					for (int num = _DestroyOnParticleEnds.Count - 1; num >= 0; num--)
					{
						if (_DestroyOnParticleEnds[num] != null && !_DestroyOnParticleEnds[num].enabled)
						{
							_DestroyOnParticleEnds.RemoveAt(num);
						}
					}
				}
				if (base.gameObject.name.Contains("SlashMercEvis"))
				{
					_ = 0;
				}
				FindAndCacheComponents(ref _ShakeEmitters);
				FindAndCacheComponents(ref _OmniEffects);
				if (_OmniEffects != null && _ParticleSystems != null)
				{
					foreach (OmniEffect omniEffect in _OmniEffects)
					{
						OmniEffect.OmniEffectGroup[] omniEffectGroups = omniEffect.omniEffectGroups;
						for (int i = 0; i < omniEffectGroups.Length; i++)
						{
							OmniEffect.OmniEffectElement[] omniEffectElements = omniEffectGroups[i].omniEffectElements;
							foreach (OmniEffect.OmniEffectElement omniEffectElement in omniEffectElements)
							{
								if (omniEffectElement.particleSystem != null && _ParticleSystems.Contains(omniEffectElement.particleSystem))
								{
									_ParticleSystems.Remove(omniEffectElement.particleSystem);
								}
							}
						}
					}
				}
			}
			_IsInitialized = true;
		}

		public void Reset(bool inActivate)
		{
			if (_effectComponent != null)
			{
				_effectComponent.Reset();
			}
			if (_hoverOverHead != null)
			{
				_hoverOverHead.Reset();
			}
			if (_ParticleSystems != null)
			{
				foreach (ParticleSystem particleSystem in _ParticleSystems)
				{
					try
					{
						particleSystem.Stop();
						particleSystem.Clear();
						if (inActivate)
						{
							particleSystem.Play();
						}
					}
					catch (Exception ex)
					{
						UnityEngine.Debug.LogFormat("ERROR: GameObject {0}\n{1}", base.gameObject.name, ex.Message);
					}
				}
			}
			if (_TrailRenderers != null)
			{
				foreach (TrailRenderer trailRenderer in _TrailRenderers)
				{
					trailRenderer.Clear();
				}
			}
			if (_LineRenderers != null)
			{
				for (int i = 0; i < _LineRenderers.Count; i++)
				{
					if (!(_LineRenderers[i] != null))
					{
						continue;
					}
					LineRenderer lineRenderer = _LineRenderers[i];
					if (lineRenderer.positionCount > 1)
					{
						UnityEngine.Vector3 position = lineRenderer.GetPosition(0);
						for (int j = 1; j < lineRenderer.positionCount; j++)
						{
							lineRenderer.SetPosition(j, position);
						}
					}
				}
			}
			if (_AnimateShaderAlphasDestroyOnEnd != null)
			{
				foreach (AnimateShaderAlpha item in _AnimateShaderAlphasDestroyOnEnd)
				{
					item.Reset();
				}
			}
			if (_ActiveAnimateShaderAlphasDestroyOnEnd != null)
			{
				foreach (AnimateShaderAlpha item2 in _ActiveAnimateShaderAlphasDestroyOnEnd)
				{
					if (!item2.enabled)
					{
						item2.enabled = true;
					}
				}
			}
			if (_AnimateShaderAlphasDisableOnEnd != null)
			{
				foreach (AnimateShaderAlpha item3 in _AnimateShaderAlphasDisableOnEnd)
				{
					item3.Reset();
				}
			}
			if (_ActiveAnimateShaderAlphasDisableOnEnd != null)
			{
				foreach (AnimateShaderAlpha item4 in _ActiveAnimateShaderAlphasDisableOnEnd)
				{
					if (!item4.enabled)
					{
						item4.enabled = true;
					}
				}
			}
			if (_AnimateShaderAlphas != null)
			{
				foreach (AnimateShaderAlpha animateShaderAlpha in _AnimateShaderAlphas)
				{
					animateShaderAlpha.Reset();
				}
			}
			if (_orbEffect != null)
			{
				_orbEffect.Reset();
			}
			if (_tracer != null)
			{
				_tracer.Reset();
			}
			if (_AkEvents_Start != null)
			{
				foreach (AkEvent item5 in _AkEvents_Start)
				{
					item5.HandleEvent(item5.gameObject);
				}
			}
			if (HasDetachParticlesOnDestroy)
			{
				_TriggeredDisable = false;
				if (_RootLineRenderer != null)
				{
					_RootLineRenderer.enabled = true;
				}
			}
		}

		public void ResetPostActivate()
		{
			if (_ShakeEmitters == null)
			{
				return;
			}
			foreach (ShakeEmitter shakeEmitter in _ShakeEmitters)
			{
				shakeEmitter.StartShake();
			}
		}

		public void StopAllParticleSystems()
		{
			if (_ParticleSystems == null)
			{
				return;
			}
			foreach (ParticleSystem particleSystem in _ParticleSystems)
			{
				try
				{
					particleSystem.Stop();
					particleSystem.Clear();
				}
				catch (Exception ex)
				{
					UnityEngine.Debug.LogFormat("ERROR: GameObject {0}\n{1}", base.gameObject.name, ex.Message);
				}
			}
		}

		public void OnAnimateShaderAlphaComplete()
		{
			if (OwningPool != null)
			{
				OwningPool.ReturnObject(this);
				return;
			}
			UnityEngine.Debug.LogErrorFormat("No Owning Pool on object {0} ({1})", base.gameObject.name, base.gameObject.GetInstanceID());
			UnityEngine.Object.Destroy(base.gameObject);
		}

		public void OnReturnToPool()
		{
			if (_AkEvents_Destroy != null)
			{
				foreach (AkEvent item in _AkEvents_Destroy)
				{
					if (item.enabled)
					{
						item.HandleEvent(base.gameObject);
					}
				}
			}
			if (_ActiveGameObjects == null)
			{
				return;
			}
			foreach (GameObject activeGameObject in _ActiveGameObjects)
			{
				activeGameObject.SetActive(value: true);
			}
		}

		public void ReturnToPool()
		{
			EffectComplete();
			OwningPool.ReturnObject(this);
		}

		public bool EffectComplete()
		{
			bool result = true;
			if (HasDetachParticlesOnDestroy && !_TriggeredDisable && _RootLineRenderer != null)
			{
				_RootLineRenderer.enabled = false;
			}
			if (!_TriggeredDisable)
			{
				if (_ActiveGameObjects != null)
				{
					foreach (GameObject activeGameObject in _ActiveGameObjects)
					{
						activeGameObject.SetActive(value: false);
					}
				}
				_TriggeredDisable = true;
			}
			return result;
		}
	}
	public class EffectPool : PrefabComponentPool<EffectManagerHelper>
	{
		protected List<EffectManagerHelper> _RemoveHelperList;

		protected List<EffectManagerHelper> _OrphanedEffects = new List<EffectManagerHelper>();

		protected const int MAX_EFFECT_POOL_CAPACITY = 20;

		protected override void PreDestroyObject(EffectManagerHelper inKillObject)
		{
			inKillObject.SetOwningPool(null);
		}

		public void Tick(float inDeltaTime)
		{
			for (int num = _OrphanedEffects.Count - 1; num >= 0; num--)
			{
				EffectManagerHelper effectManagerHelper = _OrphanedEffects[num];
				if (effectManagerHelper != null && effectManagerHelper.EffectComplete())
				{
					ReturnObject(effectManagerHelper);
					_OrphanedEffects.RemoveAt(num);
				}
			}
		}

		public override void ReturnObject(EffectManagerHelper inReturnObject)
		{
			if (inReturnObject.EffectComplete())
			{
				inReturnObject.OnReturnToPool();
				if (inReturnObject.OwningPool.PoolCount() >= 20)
				{
					DestroyObject(inReturnObject);
				}
				else
				{
					base.ReturnObject(inReturnObject);
				}
			}
			else
			{
				_OrphanedEffects.Add(inReturnObject);
			}
		}

		public void RemoveObject(EffectManagerHelper inReturnObject)
		{
			if (_InUse != null && _InUse.Contains(inReturnObject))
			{
				_InUse.Remove(inReturnObject);
			}
			if (_Pool == null || !_Pool.Contains(inReturnObject))
			{
				return;
			}
			if (_RemoveHelperList == null)
			{
				_RemoveHelperList = new List<EffectManagerHelper>();
			}
			if (_Pool == null || _Pool.Count <= 0)
			{
				return;
			}
			EffectManagerHelper effectManagerHelper = _Pool.Pop();
			while (effectManagerHelper != null)
			{
				if (!(effectManagerHelper == inReturnObject))
				{
					_RemoveHelperList.Add(effectManagerHelper);
				}
				effectManagerHelper = ((_Pool.Count <= 0) ? null : _Pool.Pop());
			}
			for (int num = _RemoveHelperList.Count - 1; num >= 0; num--)
			{
				_Pool.Push(_RemoveHelperList[num]);
			}
			_RemoveHelperList.Clear();
		}
	}
	public class OverlapAttack
	{
		private struct OverlapInfo
		{
			public HurtBox hurtBox;

			public UnityEngine.Vector3 hitPosition;

			public UnityEngine.Vector3 pushDirection;
		}

		public struct AttackInfo
		{
			public GameObject attacker;

			public GameObject inflictor;

			public float damage;

			public bool isCrit;

			public float procCoefficient;

			public DamageColorIndex damageColorIndex;

			public DamageTypeCombo damageType;

			public UnityEngine.Vector3 forceVector;
		}

		private class OverlapAttackMessage : MessageBase
		{
			public GameObject attacker;

			public GameObject inflictor;

			public float damage;

			public bool isCrit;

			public ProcChainMask procChainMask;

			public float procCoefficient;

			public DamageColorIndex damageColorIndex;

			public DamageTypeCombo damageType;

			public UnityEngine.Vector3 forceVector;

			public float pushAwayForce;

			public readonly List<OverlapInfo> overlapInfoList = new List<OverlapInfo>();

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
				writer.Write(attacker);
				writer.Write(inflictor);
				writer.Write(damage);
				writer.Write(isCrit);
				writer.Write(procChainMask);
				writer.Write(procCoefficient);
				writer.Write(damageColorIndex);
				writer.WriteDamageType(damageType);
				writer.Write(forceVector);
				writer.Write(pushAwayForce);
				writer.WritePackedUInt32((uint)overlapInfoList.Count);
				foreach (OverlapInfo overlapInfo in overlapInfoList)
				{
					writer.Write(HurtBoxReference.FromHurtBox(overlapInfo.hurtBox));
					writer.Write(overlapInfo.hitPosition);
					writer.Write(overlapInfo.pushDirection);
				}
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
				attacker = reader.ReadGameObject();
				inflictor = reader.ReadGameObject();
				damage = reader.ReadSingle();
				isCrit = reader.ReadBoolean();
				procChainMask = reader.ReadProcChainMask();
				procCoefficient = reader.ReadSingle();
				damageColorIndex = reader.ReadDamageColorIndex();
				damageType = reader.ReadDamageType();
				forceVector = reader.ReadVector3();
				pushAwayForce = reader.ReadSingle();
				overlapInfoList.Clear();
				int i = 0;
				for (int num = (int)reader.ReadPackedUInt32(); i < num; i++)
				{
					OverlapInfo item = default(OverlapInfo);
					item.hurtBox = reader.ReadHurtBoxReference().ResolveGameObject()?.GetComponent<HurtBox>();
					item.hitPosition = reader.ReadVector3();
					item.pushDirection = reader.ReadVector3();
					overlapInfoList.Add(item);
				}
			}
		}

		public GameObject attacker;

		public GameObject inflictor;

		public TeamIndex teamIndex;

		public AttackerFiltering attackerFiltering = AttackerFiltering.NeverHitSelf;

		public UnityEngine.Vector3 forceVector = UnityEngine.Vector3.zero;

		public float pushAwayForce;

		public float damage = 1f;

		public bool isCrit;

		public ProcChainMask procChainMask;

		public float procCoefficient = 1f;

		public HitBoxGroup hitBoxGroup;

		public GameObject hitEffectPrefab;

		public NetworkSoundEventIndex impactSound = NetworkSoundEventIndex.Invalid;

		public DamageColorIndex damageColorIndex;

		public DamageTypeCombo damageType;

		public int maximumOverlapTargets = 100;

		private readonly List<HealthComponent> ignoredHealthComponentList = new List<HealthComponent>();

		public float retriggerTimeout = float.PositiveInfinity;

		private Queue<(HealthComponent, float)> ignoredRemovalList = new Queue<(HealthComponent, float)>();

		private readonly List<OverlapInfo> overlapList = new List<OverlapInfo>();

		private static readonly OverlapAttackMessage incomingMessage = new OverlapAttackMessage();

		private static readonly OverlapAttackMessage outgoingMessage = new OverlapAttackMessage();

		public UnityEngine.Vector3 lastFireAverageHitPosition { get; private set; }

		private bool HurtBoxPassesFilter(HurtBox hurtBox)
		{
			if (!hurtBox.healthComponent)
			{
				return true;
			}
			if (hurtBox.healthComponent.gameObject == attacker && attackerFiltering == AttackerFiltering.NeverHitSelf)
			{
				return false;
			}
			if (attacker == null && hurtBox.healthComponent.gameObject.GetComponent<MaulingRock>() != null)
			{
				return false;
			}
			if (ignoredHealthComponentList.Contains(hurtBox.healthComponent))
			{
				return false;
			}
			if (!FriendlyFireManager.ShouldDirectHitProceed(hurtBox.healthComponent, teamIndex))
			{
				return false;
			}
			return true;
		}

		public bool Fire(List<HurtBox> hitResults = null)
		{
			if (!hitBoxGroup)
			{
				return false;
			}
			HitBox[] hitBoxes = hitBoxGroup.hitBoxes;
			foreach (HitBox hitBox in hitBoxes)
			{
				if (!hitBox || !hitBox.enabled || !hitBox.gameObject || !hitBox.gameObject.activeInHierarchy || !hitBox.transform)
				{
					continue;
				}
				Transform transform = hitBox.transform;
				UnityEngine.Vector3 position = transform.position;
				UnityEngine.Vector3 halfExtents = transform.lossyScale * 0.5f;
				UnityEngine.Quaternion rotation = transform.rotation;
				if (float.IsInfinity(halfExtents.x) || float.IsInfinity(halfExtents.y) || float.IsInfinity(halfExtents.z))
				{
					Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxHalfExtents are infinite.");
					continue;
				}
				if (float.IsNaN(halfExtents.x) || float.IsNaN(halfExtents.y) || float.IsNaN(halfExtents.z))
				{
					Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxHalfExtents are NaN.");
					continue;
				}
				if (float.IsInfinity(position.x) || float.IsInfinity(position.y) || float.IsInfinity(position.z))
				{
					Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxCenter is infinite.");
					continue;
				}
				if (float.IsNaN(position.x) || float.IsNaN(position.y) || float.IsNaN(position.z))
				{
					Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxCenter is NaN.");
					continue;
				}
				if (float.IsInfinity(rotation.x) || float.IsInfinity(rotation.y) || float.IsInfinity(rotation.z) || float.IsInfinity(rotation.w))
				{
					Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxRotation is infinite.");
					continue;
				}
				if (float.IsNaN(rotation.x) || float.IsNaN(rotation.y) || float.IsNaN(rotation.z) || float.IsNaN(rotation.w))
				{
					Chat.AddMessage("Aborting OverlapAttack.Fire: hitBoxRotation is NaN.");
					continue;
				}
				Collider[] colliders;
				int num = HGPhysics.OverlapBox(out colliders, position, halfExtents, rotation, LayerIndex.entityPrecise.mask);
				cleanupRetriggerList();
				int num2 = 0;
				for (int j = 0; j < num; j++)
				{
					if ((bool)colliders[j])
					{
						HurtBox component = colliders[j].GetComponent<HurtBox>();
						if ((bool)component && HurtBoxPassesFilter(component) && (bool)component.transform)
						{
							UnityEngine.Vector3 position2 = component.transform.position;
							overlapList.Add(new OverlapInfo
							{
								hurtBox = component,
								hitPosition = position2,
								pushDirection = (position2 - position).normalized
							});
							addIgnoredHitList(component.healthComponent);
							hitResults?.Add(component);
							num2++;
						}
						if (num2 >= maximumOverlapTargets)
						{
							break;
						}
					}
				}
				HGPhysics.ReturnResults(colliders);
			}
			ProcessHits(overlapList);
			bool result = overlapList.Count > 0;
			overlapList.Clear();
			return result;
		}

		public void addIgnoredHitList(HealthComponent component)
		{
			if (retriggerTimeout != float.PositiveInfinity)
			{
				ignoredRemovalList.Enqueue((component, Time.realtimeSinceStartup + retriggerTimeout));
			}
			ignoredHealthComponentList.Add(component);
		}

		public void cleanupRetriggerList()
		{
			while (ignoredRemovalList.Count > 0 && Time.realtimeSinceStartup > ignoredRemovalList.Peek().Item2)
			{
				(HealthComponent, float) tuple = ignoredRemovalList.Dequeue();
				ignoredHealthComponentList.Remove(tuple.Item1);
			}
		}

		[NetworkMessageHandler(msgType = 71, client = false, server = true)]
		public static void HandleOverlapAttackHits(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(incomingMessage);
			PerformDamage(incomingMessage.attacker, incomingMessage.inflictor, incomingMessage.damage, incomingMessage.isCrit, incomingMessage.procChainMask, incomingMessage.procCoefficient, incomingMessage.damageColorIndex, incomingMessage.damageType, incomingMessage.forceVector, incomingMessage.pushAwayForce, incomingMessage.overlapInfoList);
		}

		private void ProcessHits(List<OverlapInfo> hitList)
		{
			if (hitList.Count == 0)
			{
				return;
			}
			UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
			float num = 1f / (float)hitList.Count;
			for (int i = 0; i < hitList.Count; i++)
			{
				OverlapInfo overlapInfo = hitList[i];
				if ((bool)hitEffectPrefab)
				{
					UnityEngine.Vector3 forward = -hitList[i].pushDirection;
					EffectManager.SpawnEffect(hitEffectPrefab, new EffectData
					{
						origin = overlapInfo.hitPosition,
						rotation = Util.QuaternionSafeLookRotation(forward),
						networkSoundEventIndex = impactSound
					}, transmit: true);
				}
				zero += overlapInfo.hitPosition * num;
				SurfaceDefProvider surfaceDefProvider = (overlapInfo.hurtBox ? overlapInfo.hurtBox.GetComponent<SurfaceDefProvider>() : null);
				if (!surfaceDefProvider || !surfaceDefProvider.surfaceDef)
				{
					continue;
				}
				SurfaceDef objectSurfaceDef = SurfaceDefProvider.GetObjectSurfaceDef(hitList[i].hurtBox.collider, hitList[i].hitPosition);
				if ((bool)objectSurfaceDef)
				{
					if ((bool)objectSurfaceDef.impactEffectPrefab)
					{
						EffectManager.SpawnEffect(objectSurfaceDef.impactEffectPrefab, new EffectData
						{
							origin = overlapInfo.hitPosition,
							rotation = ((overlapInfo.pushDirection == UnityEngine.Vector3.zero) ? UnityEngine.Quaternion.identity : Util.QuaternionSafeLookRotation(overlapInfo.pushDirection)),
							color = objectSurfaceDef.approximateColor,
							scale = 2f
						}, transmit: true);
					}
					if (objectSurfaceDef.impactSoundString != null && objectSurfaceDef.impactSoundString.Length != 0)
					{
						Util.PlaySound(objectSurfaceDef.impactSoundString, hitList[i].hurtBox.gameObject);
					}
				}
			}
			lastFireAverageHitPosition = zero;
			if (NetworkServer.active)
			{
				PerformDamage(attacker, inflictor, damage, isCrit, procChainMask, procCoefficient, damageColorIndex, damageType, forceVector, pushAwayForce, hitList);
				return;
			}
			outgoingMessage.attacker = attacker;
			outgoingMessage.inflictor = inflictor;
			outgoingMessage.damage = damage;
			outgoingMessage.isCrit = isCrit;
			outgoingMessage.procChainMask = procChainMask;
			outgoingMessage.procCoefficient = procCoefficient;
			outgoingMessage.damageColorIndex = damageColorIndex;
			outgoingMessage.damageType = damageType;
			outgoingMessage.forceVector = forceVector;
			outgoingMessage.pushAwayForce = pushAwayForce;
			Util.CopyList(hitList, outgoingMessage.overlapInfoList);
			PlatformSystems.networkManager.client.connection.SendByChannel(71, outgoingMessage, QosChannelIndex.defaultReliable.intVal);
		}

		private static void PerformDamage(GameObject attacker, GameObject inflictor, float damage, bool isCrit, ProcChainMask procChainMask, float procCoefficient, DamageColorIndex damageColorIndex, DamageTypeCombo damageType, UnityEngine.Vector3 forceVector, float pushAwayForce, List<OverlapInfo> hitList)
		{
			for (int i = 0; i < hitList.Count; i++)
			{
				OverlapInfo overlapInfo = hitList[i];
				if ((bool)overlapInfo.hurtBox)
				{
					HealthComponent healthComponent = overlapInfo.hurtBox.healthComponent;
					if ((bool)healthComponent)
					{
						DamageInfo damageInfo = new DamageInfo();
						damageInfo.attacker = attacker;
						damageInfo.inflictor = inflictor;
						damageInfo.force = forceVector + pushAwayForce * overlapInfo.pushDirection;
						damageInfo.damage = damage;
						damageInfo.crit = isCrit;
						damageInfo.position = overlapInfo.hitPosition;
						damageInfo.procChainMask = procChainMask;
						damageInfo.procCoefficient = procCoefficient;
						damageInfo.damageColorIndex = damageColorIndex;
						damageInfo.damageType = damageType;
						damageInfo.ModifyDamageInfo(overlapInfo.hurtBox.damageModifier);
						healthComponent.TakeDamage(damageInfo);
						GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
						GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
					}
				}
			}
		}

		public void ResetIgnoredHealthComponents()
		{
			ignoredHealthComponentList.Clear();
			ignoredRemovalList.Clear();
		}

		public void Reset()
		{
			attacker = null;
			inflictor = null;
			teamIndex = TeamIndex.Neutral;
			forceVector = UnityEngine.Vector3.zero;
			pushAwayForce = 0f;
			damage = 1f;
			isCrit = false;
			procChainMask.mask = 0u;
			procCoefficient = 1f;
			hitBoxGroup = null;
			hitEffectPrefab = null;
			damageColorIndex = DamageColorIndex.Default;
			damageType = DamageType.Generic;
			ignoredHealthComponentList.Clear();
			ignoredRemovalList.Clear();
		}
	}
	[Serializable]
	public struct PackedUnitVector3
	{
		[SerializeField]
		public ushort value;

		private static readonly float[] uvAdjustment;

		private const ushort signMask = 57344;

		private const ushort invSignMask = 8191;

		private const ushort xSignMask = 32768;

		private const ushort ySignMask = 16384;

		private const ushort zSignMask = 8192;

		private const ushort topMask = 8064;

		private const ushort bottomMask = 127;

		static PackedUnitVector3()
		{
			uvAdjustment = new float[8192];
			for (int i = 0; i < uvAdjustment.Length; i++)
			{
				int num = i >> 7;
				int num2 = i & 0x7F;
				if (num + num2 >= 127)
				{
					num = 127 - num;
					num2 = 127 - num2;
				}
				UnityEngine.Vector3 vector = new UnityEngine.Vector3(num, num2, 126 - num - num2);
				uvAdjustment[i] = 1f / vector.magnitude;
			}
		}

		public PackedUnitVector3(ushort value)
		{
			this.value = value;
		}

		public PackedUnitVector3(UnityEngine.Vector3 src)
		{
			value = 0;
			if (src.x < 0f)
			{
				value |= 32768;
				src.x = 0f - src.x;
			}
			if (src.y < 0f)
			{
				value |= 16384;
				src.y = 0f - src.y;
			}
			if (src.z < 0f)
			{
				value |= 8192;
				src.z = 0f - src.z;
			}
			float num = 126f / (src.x + src.y + src.z);
			int num2 = (int)(src.x * num);
			int num3 = (int)(src.y * num);
			if (num2 >= 64)
			{
				num2 = 127 - num2;
				num3 = 127 - num3;
			}
			value |= (ushort)(num2 << 7);
			value |= (ushort)num3;
		}

		public UnityEngine.Vector3 Unpack()
		{
			int num = (value & 0x1F80) >> 7;
			int num2 = value & 0x7F;
			if (num + num2 >= 127)
			{
				num = 127 - num;
				num2 = 127 - num2;
			}
			float num3 = uvAdjustment[value & 0x1FFF];
			UnityEngine.Vector3 result = new UnityEngine.Vector3(num3 * (float)num, num3 * (float)num2, num3 * (float)(126 - num - num2));
			if ((value & 0x8000u) != 0)
			{
				result.x = 0f - result.x;
			}
			if ((value & 0x4000u) != 0)
			{
				result.y = 0f - result.y;
			}
			if ((value & 0x2000u) != 0)
			{
				result.z = 0f - result.z;
			}
			return result;
		}
	}
	public enum PathStatus
	{
		Valid,
		Incomplete,
		Invalid
	}
	public class Path : IDisposable
	{
		public struct Waypoint : IEquatable<Waypoint>
		{
			public NodeGraph.NodeIndex nodeIndex;

			public float minJumpHeight;

			public bool Equals(Waypoint other)
			{
				if (nodeIndex.Equals(other.nodeIndex))
				{
					return minJumpHeight.Equals(other.minJumpHeight);
				}
				return false;
			}

			public override bool Equals(object other)
			{
				if (other is Waypoint other2)
				{
					return Equals(other2);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (nodeIndex.GetHashCode() * 397) ^ minJumpHeight.GetHashCode();
			}
		}

		private static readonly Stack<Waypoint[]> waypointsBufferPool = new Stack<Waypoint[]>();

		private const int pooledBufferSize = 64;

		private Waypoint[] waypointsBuffer;

		private int firstWaypointIndex;

		public NodeGraph nodeGraph { get; private set; }

		public PathStatus status { get; set; }

		public int waypointsCount { get; private set; }

		public Waypoint this[int i] => waypointsBuffer[firstWaypointIndex + i];

		private static Waypoint[] GetWaypointsBuffer()
		{
			if (waypointsBufferPool.Count == 0)
			{
				return new Waypoint[64];
			}
			return waypointsBufferPool.Pop();
		}

		private static void FreeWaypointsBuffer(Waypoint[] buffer)
		{
			if (buffer.Length == 64)
			{
				waypointsBufferPool.Push(buffer);
			}
		}

		public Path(NodeGraph nodeGraph)
		{
			this.nodeGraph = nodeGraph;
			waypointsBuffer = GetWaypointsBuffer();
			firstWaypointIndex = waypointsBuffer.Length;
		}

		public void Dispose()
		{
			FreeWaypointsBuffer(waypointsBuffer);
		}

		public void PushWaypointToFront(NodeGraph.NodeIndex nodeIndex, float minJumpHeight)
		{
			if (waypointsCount + 1 >= waypointsBuffer.Length)
			{
				Waypoint[] array = waypointsBuffer;
				waypointsBuffer = new Waypoint[waypointsCount + 32];
				Array.Copy(array, 0, waypointsBuffer, waypointsBuffer.Length - array.Length, array.Length);
				FreeWaypointsBuffer(array);
			}
			firstWaypointIndex = waypointsBuffer.Length - ++waypointsCount;
			waypointsBuffer[firstWaypointIndex] = new Waypoint
			{
				nodeIndex = nodeIndex,
				minJumpHeight = minJumpHeight
			};
		}

		public void WriteWaypointsToList(List<Waypoint> waypointsList)
		{
			if (waypointsList.Capacity < waypointsList.Count + waypointsCount)
			{
				waypointsList.Capacity = waypointsList.Count + waypointsCount;
			}
			for (int i = firstWaypointIndex; i < waypointsBuffer.Length; i++)
			{
				waypointsList.Add(waypointsBuffer[i]);
			}
		}

		public void Clear()
		{
			status = PathStatus.Invalid;
			waypointsCount = 0;
			firstWaypointIndex = waypointsBuffer.Length;
		}
	}
	public class PathFollower
	{
		public class Drawer : IDisposable
		{
			private PathFollower _target;

			private WireMeshBuilder wireMeshBuilder;

			private DebugOverlay.MeshDrawer passDistanceDrawer;

			private DebugOverlay.MeshDrawer pathDrawer;

			private List<Path.Waypoint> waypointCache;

			private int cachedCurrentWaypoint;

			public PathFollower target
			{
				get
				{
					return _target;
				}
				set
				{
					if (_target != value)
					{
						_target = value;
						pathDrawer.enabled = _target != null;
						passDistanceDrawer.enabled &= _target != null;
						waypointCache.Clear();
					}
				}
			}

			public Drawer(PathFollower target)
			{
				cachedCurrentWaypoint = -1;
				waypointCache = new List<Path.Waypoint>();
				wireMeshBuilder = new WireMeshBuilder();
				passDistanceDrawer = DebugOverlay.GetMeshDrawer();
				pathDrawer = DebugOverlay.GetMeshDrawer();
				int num = 32;
				float sliceSize = 360f / (float)num;
				UnityEngine.Vector3 halfForward = UnityEngine.Vector3.forward * 0.5f;
				UnityEngine.Vector3 p = GetCirclePosition(-1);
				for (int j = 0; j < num; j++)
				{
					UnityEngine.Vector3 vector = GetCirclePosition(j);
					wireMeshBuilder.AddLine(p, UnityEngine.Color.yellow, vector, UnityEngine.Color.yellow);
					p = vector;
				}
				passDistanceDrawer.hasMeshOwnership = true;
				passDistanceDrawer.mesh = wireMeshBuilder.GenerateMesh();
				wireMeshBuilder.Clear();
				pathDrawer.mesh = new Mesh();
				RoR2Application.onFixedUpdate += FixedUpdate;
				this.target = target;
				UnityEngine.Vector3 GetCirclePosition(int i)
				{
					return UnityEngine.Quaternion.AngleAxis((float)i * sliceSize, UnityEngine.Vector3.up) * halfForward;
				}
			}

			private void SetWaypoints(List<Path.Waypoint> newWaypoints, int newCurrentWaypoint)
			{
				if (!ListUtils.SequenceEquals(waypointCache, newWaypoints) || !cachedCurrentWaypoint.Equals(newCurrentWaypoint))
				{
					waypointCache.Clear();
					waypointCache.AddRange(newWaypoints);
					cachedCurrentWaypoint = newCurrentWaypoint;
					RebuildPathMesh();
				}
			}

			private void RebuildPathMesh()
			{
				List<Path.Waypoint> waypoints = target.waypoints;
				UnityEngine.Color nodeColor;
				UnityEngine.Color traversedPathColor;
				UnityEngine.Color currentPathColor;
				UnityEngine.Color untraversedPathColor;
				UnityEngine.Color drawPathColor;
				if (waypoints.Count > 1)
				{
					nodeColor = new UnityEngine.Color(1f, 0.5f, 0.5f, 0.25f);
					traversedPathColor = new UnityEngine.Color(0.5f, 0.5f, 0.5f, 0.25f);
					currentPathColor = new UnityEngine.Color(1f, 0.5f, 0.5f, 1f);
					untraversedPathColor = new UnityEngine.Color(0.5f, 0f, 0f, 0.25f);
					target.nodeGraph.GetNodePosition(waypoints[0].nodeIndex, out var position2);
					drawPathColor = untraversedPathColor;
					DrawNode(position2);
					for (int j = 1; j < waypoints.Count; j++)
					{
						UpdateDrawPathColor(j);
						target.nodeGraph.GetNodePosition(waypoints[j].nodeIndex, out var position3);
						wireMeshBuilder.AddLine(position2, drawPathColor, position3, drawPathColor);
						DrawNode(position3);
						position2 = position3;
					}
				}
				wireMeshBuilder.GenerateMesh(pathDrawer.mesh);
				wireMeshBuilder.Clear();
				void DrawNode(UnityEngine.Vector3 position)
				{
					wireMeshBuilder.AddLine(position - UnityEngine.Vector3.up, nodeColor, position + UnityEngine.Vector3.up, nodeColor);
				}
				void UpdateDrawPathColor(int i)
				{
					if (cachedCurrentWaypoint == i)
					{
						drawPathColor = currentPathColor;
					}
					else if (cachedCurrentWaypoint < i)
					{
						drawPathColor = untraversedPathColor;
					}
					else
					{
						drawPathColor = traversedPathColor;
					}
				}
			}

			private void FixedUpdate()
			{
				if (target != null)
				{
					passDistanceDrawer.enabled = target.currentWaypoint < target.waypoints.Count;
					if (passDistanceDrawer.enabled)
					{
						target.nodeGraph.GetNodePosition(target.waypoints[target.currentWaypoint].nodeIndex, out var position);
						passDistanceDrawer.transform.position = position;
						passDistanceDrawer.transform.localScale = UnityEngine.Vector3.one * target.debugPassDistance;
					}
					SetWaypoints(target.waypoints, target.currentWaypoint);
				}
			}

			public void Dispose()
			{
				target = null;
				RoR2Application.onFixedUpdate -= FixedUpdate;
				pathDrawer.Dispose();
				passDistanceDrawer.Dispose();
				wireMeshBuilder.Dispose();
			}
		}

		private UnityEngine.Vector3 currentPosition;

		private const float waypointPassDistance = 2f;

		private const float waypointPassYTolerance = 2f;

		private List<Path.Waypoint> waypoints = new List<Path.Waypoint>();

		private int currentWaypoint;

		private NodeGraph.NodeIndex previousNode = NodeGraph.NodeIndex.invalid;

		private float debugPassDistance;

		public NodeGraph nodeGraph { get; private set; }

		public NodeGraph.NodeIndex nextNode { get; private set; } = NodeGraph.NodeIndex.invalid;


		public bool isFinished => currentWaypoint >= waypoints.Count;

		public bool isOnJumpLink => false;

		public bool hasPassedFirstWaypoint => currentWaypoint > 0;

		public bool nextWaypointNeedsJump
		{
			get
			{
				if (waypoints.Count > 0 && currentWaypoint < waypoints.Count)
				{
					return waypoints[currentWaypoint].minJumpHeight > 0f;
				}
				return false;
			}
		}

		private static float DistanceXZ(UnityEngine.Vector3 a, UnityEngine.Vector3 b)
		{
			a.y = 0f;
			b.y = 0f;
			return UnityEngine.Vector3.Distance(a, b);
		}

		public float CalculateJumpVelocityNeededToReachNextWaypoint(float moveSpeed)
		{
			if (!nextWaypointNeedsJump)
			{
				return 0f;
			}
			UnityEngine.Vector3 a = currentPosition;
			if (!GetNextNodePosition(out var nextPosition))
			{
				return 0f;
			}
			return Trajectory.CalculateInitialYSpeed(Trajectory.CalculateGroundTravelTime(moveSpeed, DistanceXZ(a, nextPosition)), nextPosition.y - a.y);
		}

		public void UpdatePosition(UnityEngine.Vector3 newPosition)
		{
			UnityEngine.Vector3 vector = currentPosition;
			currentPosition = newPosition;
			if (GetNextNodePosition(out var nextPosition))
			{
				UnityEngine.Vector3 vector2 = nextPosition - currentPosition;
				UnityEngine.Vector3 vector3 = vector2;
				vector3.y = 0f;
				float num = 2f;
				UnityEngine.Vector3 inNormal = currentPosition - vector;
				UnityEngine.Plane plane = new UnityEngine.Plane(inNormal, nextPosition);
				if (plane.GetSide(currentPosition) != plane.GetSide(vector))
				{
					num += 2f;
				}
				if (waypoints.Count > currentWaypoint + 1 && waypoints[currentWaypoint + 1].minJumpHeight > 0f)
				{
					num = 0.5f;
				}
				debugPassDistance = num;
				if (num * num >= vector3.sqrMagnitude && Mathf.Abs(vector2.y) <= 2f)
				{
					SetWaypoint(currentWaypoint + 1);
				}
			}
			_ = nextNode != NodeGraph.NodeIndex.invalid;
		}

		private void SetWaypoint(int newWaypoint)
		{
			currentWaypoint = Math.Min(newWaypoint, waypoints.Count);
			if (currentWaypoint == waypoints.Count)
			{
				nextNode = NodeGraph.NodeIndex.invalid;
				previousNode = NodeGraph.NodeIndex.invalid;
			}
			else
			{
				nextNode = waypoints[currentWaypoint].nodeIndex;
				previousNode = ((currentWaypoint > 0) ? waypoints[currentWaypoint - 1].nodeIndex : NodeGraph.NodeIndex.invalid);
			}
		}

		public void Reset()
		{
			nodeGraph = null;
			nextNode = NodeGraph.NodeIndex.invalid;
			previousNode = NodeGraph.NodeIndex.invalid;
			waypoints.Clear();
			currentWaypoint = 0;
		}

		public void SetPath(Path newPath)
		{
			if (nodeGraph != newPath.nodeGraph)
			{
				Reset();
				nodeGraph = newPath.nodeGraph;
			}
			waypoints.Clear();
			newPath.WriteWaypointsToList(waypoints);
			currentWaypoint = 0;
			for (int i = 1; i < waypoints.Count; i++)
			{
				if (waypoints[i].nodeIndex == nextNode && waypoints[i - 1].nodeIndex == previousNode)
				{
					currentWaypoint = i;
					break;
				}
			}
			SetWaypoint(currentWaypoint);
		}

		private void GetPreviousAndNextNodePositions(out UnityEngine.Vector3? previousPosition, out UnityEngine.Vector3? nextPosition)
		{
			previousPosition = null;
			nextPosition = null;
			if (!(nodeGraph == null))
			{
				if (nodeGraph.GetNodePosition(previousNode, out var position))
				{
					previousPosition = position;
				}
				if (nodeGraph.GetNodePosition(nextNode, out position))
				{
					nextPosition = position;
				}
			}
		}

		private bool GetNextNodePosition(out UnityEngine.Vector3 nextPosition)
		{
			if (nodeGraph != null && nextNode != NodeGraph.NodeIndex.invalid && nodeGraph.GetNodePosition(nextNode, out nextPosition))
			{
				return true;
			}
			nextPosition = currentPosition;
			return false;
		}

		public UnityEngine.Vector3? GetNextPosition()
		{
			if (GetNextNodePosition(out var nextPosition))
			{
				return nextPosition;
			}
			return null;
		}

		public void DebugDrawPath(UnityEngine.Color color, float duration)
		{
			for (int i = 1; i < waypoints.Count; i++)
			{
				nodeGraph.GetNodePosition(waypoints[i].nodeIndex, out var position);
				nodeGraph.GetNodePosition(waypoints[i - 1].nodeIndex, out var position2);
				UnityEngine.Debug.DrawLine(position, position2, color, duration);
			}
			for (int j = 0; j < waypoints.Count; j++)
			{
				nodeGraph.GetNodePosition(waypoints[j].nodeIndex, out var position3);
				UnityEngine.Debug.DrawLine(position3 + UnityEngine.Vector3.up, position3 - UnityEngine.Vector3.up, color, duration);
			}
		}
	}
	public static class PauseManager
	{
		private static GameObject pauseScreenInstance;

		private static GameObject pauseScreenSource;

		public static AsyncOperationHandle<GameObject> loadOperationHandle;

		public static bool IsAbleToPause = true;

		public static int PausingPlayerID = 0;

		public static Action onPauseStartGlobal;

		public static Action onPauseEndGlobal;

		public static bool isPaused = false;

		public static void InitializeLoad()
		{
			if (LegacyResourcesAPI.GetGuid("Prefabs/UI/PauseScreen", out var guid))
			{
				loadOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>(guid);
				loadOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> g)
				{
					pauseScreenSource = g.Result;
				};
			}
		}

		public static bool PauseScreenIsOpen()
		{
			return pauseScreenInstance != null;
		}

		[ConCommand(commandName = "pause", flags = ConVarFlags.None, helpText = "Toggles game pause state.")]
		private static void CCTogglePause(ConCommandArgs args)
		{
			TogglePauseScreen();
		}

		[ConCommand(commandName = "minimal_pause", flags = ConVarFlags.None, helpText = "Toggles game pause state.")]
		private static void CCToggleMinimalPause(ConCommandArgs args)
		{
			OpenMinimalPauseScreen();
		}

		public static void TogglePauseScreen()
		{
			if (!IsAbleToPause)
			{
				return;
			}
			if ((bool)pauseScreenInstance)
			{
				PauseScreenController component = pauseScreenInstance.GetComponent<PauseScreenController>();
				if (component.isMinimallyPause)
				{
					component.OpenGameMenu();
					return;
				}
				component.DestroyPauseScreen(shouldResumeOnDisable: true);
				pauseScreenInstance = null;
			}
			else if (NetworkManager.singleton.isNetworkActive)
			{
				GameObject gameObject = PauseScreenController.InstantiatePauseScreen(NetworkServer.dontListen);
				if (!(gameObject == null))
				{
					pauseScreenInstance = gameObject;
				}
			}
		}

		public static void ClosePauseScreen(bool shouldResume)
		{
			if ((bool)pauseScreenInstance)
			{
				PauseScreenController component = pauseScreenInstance.GetComponent<PauseScreenController>();
				if ((object)component != null)
				{
					component.DestroyPauseScreen(shouldResume);
					pauseScreenInstance = null;
				}
			}
		}

		public static void OpenMinimalPauseScreen()
		{
			if (!pauseScreenInstance && NetworkManager.singleton.isNetworkActive)
			{
				GameObject gameObject = PauseScreenController.InstantiateMinimalPauseScreen();
				if (!(gameObject == null))
				{
					pauseScreenInstance = gameObject;
				}
			}
		}

		public static void CloseMinimalPauseScreen()
		{
			if ((bool)pauseScreenInstance)
			{
				PauseScreenController component = pauseScreenInstance.GetComponent<PauseScreenController>();
				if (!component.isMinimallyPause)
				{
					component.GameplayResumed();
				}
				else if (NetworkManager.singleton.isNetworkActive)
				{
					component.DestroyPauseScreen(shouldResumeOnDisable: false);
					pauseScreenInstance = null;
				}
			}
		}
	}
	public class PauseStopController : NetworkBehaviour
	{
		private class PauseMessage : MessageBase
		{
			public bool shouldPause;

			public string playerName;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(shouldPause);
				writer.Write(playerName);
			}

			public override void Deserialize(NetworkReader reader)
			{
				shouldPause = reader.ReadBoolean();
				playerName = reader.ReadString();
			}
		}

		[SyncVar]
		private bool _allowMultiplayerPause;

		[SyncVar]
		public bool isPaused;

		private float _oldTimeScale;

		private LocalUser _localUser;

		private Coroutine pauseMsgCoroutine;

		private static int kRpcRpcPauseStop;

		public static PauseStopController instance { get; private set; }

		public bool allowMultiplayerPause
		{
			get
			{
				return _allowMultiplayerPause;
			}
			set
			{
				Network_allowMultiplayerPause = value;
			}
		}

		public bool canControlPause
		{
			get
			{
				if (_localUser != null && (bool)_localUser.currentNetworkUser && _localUser.currentNetworkUser.isParticipating)
				{
					if (!_allowMultiplayerPause)
					{
						return RoR2Application.isInSinglePlayer;
					}
					return true;
				}
				return false;
			}
		}

		public bool Network_allowMultiplayerPause
		{
			get
			{
				return _allowMultiplayerPause;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref _allowMultiplayerPause, 1u);
			}
		}

		public bool NetworkisPaused
		{
			get
			{
				return isPaused;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref isPaused, 2u);
			}
		}

		private void Awake()
		{
			_localUser = ((MPEventSystem)EventSystem.current)?.localUser;
			_oldTimeScale = Time.timeScale;
		}

		private void Start()
		{
			UnityEngine.Object.DontDestroyOnLoad(base.gameObject);
			if (NetworkServer.active)
			{
				NetworkServer.Spawn(base.gameObject);
			}
		}

		public override void OnStartClient()
		{
			if (isPaused)
			{
				ClientPauseStop(shouldPause: true);
			}
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void OnDestroy()
		{
			ClientPauseStop(shouldPause: false);
		}

		public void Pause(bool shouldPause)
		{
			PauseStopInternal(shouldPause);
		}

		public void ForceClientUnpause()
		{
			ClientPauseStop(shouldPause: false);
		}

		private void PauseStopInternal(bool shouldPause)
		{
			if (!NetworkManager.singleton.isNetworkActive)
			{
				ClientPauseStop(shouldPause: false);
			}
			else if (canControlPause)
			{
				PauseMessage msg = new PauseMessage
				{
					shouldPause = shouldPause,
					playerName = _localUser.currentNetworkUser.GetNetworkPlayerName().GetResolvedName()
				};
				QosChannelIndex defaultReliable = QosChannelIndex.defaultReliable;
				ClientScene.readyConnection.SendByChannel(79, msg, defaultReliable.intVal);
			}
		}

		[NetworkMessageHandler(msgType = 79, client = true, server = true)]
		private static void HandlePauseStop(NetworkMessage netMsg)
		{
			PauseMessage pauseMessage = netMsg.ReadMessage<PauseMessage>();
			instance.PauseStop(pauseMessage);
		}

		private void PauseStop(PauseMessage pauseMessage)
		{
			if (isPaused == pauseMessage.shouldPause)
			{
				return;
			}
			NetworkisPaused = pauseMessage.shouldPause;
			CallRpcPauseStop(pauseMessage.shouldPause);
			if (!NetworkServer.dontListen)
			{
				if (isPaused)
				{
					Chat.SendPlayerPausedMessage(pauseMessage.playerName);
				}
				else
				{
					Chat.SendPlayerResumedMessage(pauseMessage.playerName);
				}
			}
		}

		[ClientRpc]
		private void RpcPauseStop(bool shouldPause)
		{
			ClientPauseStop(shouldPause);
		}

		private void ClientPauseStop(bool shouldPause)
		{
			NetworkisPaused = shouldPause;
			if (shouldPause)
			{
				_oldTimeScale = Time.timeScale;
				Time.timeScale = 0f;
				if (PauseManager.onPauseStartGlobal != null)
				{
					PauseManager.onPauseStartGlobal();
					if (!HUD.IsScoreboardActive(_localUser))
					{
						PauseManager.OpenMinimalPauseScreen();
					}
				}
				pauseMsgCoroutine = StartCoroutine(SendPauseMsg());
			}
			else
			{
				Time.timeScale = _oldTimeScale;
				if (PauseManager.onPauseEndGlobal != null)
				{
					PauseManager.onPauseEndGlobal();
					PauseManager.CloseMinimalPauseScreen();
				}
				if (pauseMsgCoroutine != null)
				{
					StopCoroutine(pauseMsgCoroutine);
				}
			}
		}

		private IEnumerator SendPauseMsg()
		{
			while (true)
			{
				yield return new WaitForSecondsRealtime(2f);
				PauseMessage msg = new PauseMessage
				{
					shouldPause = isPaused,
					playerName = _localUser.currentNetworkUser.GetNetworkPlayerName().GetResolvedName()
				};
				QosChannelIndex defaultReliable = QosChannelIndex.defaultReliable;
				ClientScene.readyConnection.SendByChannel(79, msg, defaultReliable.intVal);
			}
		}

		private void ServerPauseStop(bool shouldPause)
		{
			if (shouldPause)
			{
				_oldTimeScale = Time.timeScale;
				Time.timeScale = 0f;
			}
			else
			{
				Time.timeScale = _oldTimeScale;
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcPauseStop(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcPauseStop called on server.");
			}
			else
			{
				((PauseStopController)obj).RpcPauseStop(reader.ReadBoolean());
			}
		}

		public void CallRpcPauseStop(bool shouldPause)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcPauseStop called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcPauseStop);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(shouldPause);
			SendRPCInternal(networkWriter, 0, "RpcPauseStop");
		}

		static PauseStopController()
		{
			kRpcRpcPauseStop = -1375384466;
			NetworkBehaviour.RegisterRpcDelegate(typeof(PauseStopController), kRpcRpcPauseStop, InvokeRpcRpcPauseStop);
			NetworkCRC.RegisterBehaviour("PauseStopController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(_allowMultiplayerPause);
				writer.Write(isPaused);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(_allowMultiplayerPause);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(isPaused);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				_allowMultiplayerPause = reader.ReadBoolean();
				isPaused = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				_allowMultiplayerPause = reader.ReadBoolean();
			}
			if (((uint)num & 2u) != 0)
			{
				isPaused = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public struct PhysForceInfo
	{
		[SerializeField]
		public UnityEngine.Vector3 force;

		[SerializeField]
		private int flags;

		private static readonly int ignoreGroundStickFlag = 1;

		private static readonly int disableAirControlUntilCollisionFlag = 2;

		private static readonly int massIsOneFlag = 4;

		public bool ignoreGroundStick
		{
			get
			{
				return (flags & ignoreGroundStickFlag) != 0;
			}
			set
			{
				SetFlag(ref flags, ignoreGroundStickFlag, value);
			}
		}

		public bool disableAirControlUntilCollision
		{
			get
			{
				return (flags & disableAirControlUntilCollisionFlag) != 0;
			}
			set
			{
				SetFlag(ref flags, disableAirControlUntilCollisionFlag, value);
			}
		}

		public bool massIsOne
		{
			get
			{
				return (flags & massIsOneFlag) != 0;
			}
			set
			{
				SetFlag(ref flags, massIsOneFlag, value);
			}
		}

		private static void SetFlag(ref int flags, int flag, bool value)
		{
			flags = (value ? (flags | flag) : (flags & ~flag));
		}

		public static PhysForceInfo Create()
		{
			PhysForceInfo result = default(PhysForceInfo);
			result.force = UnityEngine.Vector3.zero;
			result.flags = 0;
			result.ignoreGroundStick = false;
			result.disableAirControlUntilCollision = false;
			result.massIsOne = false;
			return result;
		}
	}
	public static class PickupCatalog
	{
		public struct Enumerator : IEnumerator<PickupIndex>, IEnumerator, IDisposable
		{
			private PickupIndex position;

			public PickupIndex Current => position;

			object IEnumerator.Current => Current;

			public bool MoveNext()
			{
				++position;
				return position.value < pickupCount;
			}

			public void Reset()
			{
				position = PickupIndex.none;
			}

			void IDisposable.Dispose()
			{
			}
		}

		private static PickupDef[] entries = Array.Empty<PickupDef>();

		private static PickupIndex[] itemIndexToPickupIndex = Array.Empty<PickupIndex>();

		private static PickupIndex[] equipmentIndexToPickupIndex = Array.Empty<PickupIndex>();

		private static PickupIndex[] artifactIndexToPickupIndex = Array.Empty<PickupIndex>();

		private static PickupIndex[] miscPickupIndexToPickupIndex = Array.Empty<PickupIndex>();

		private static readonly Dictionary<string, PickupIndex> nameToPickupIndex = new Dictionary<string, PickupIndex>();

		private static readonly Dictionary<ItemTier, PickupIndex> itemTierToPickupIndex = new Dictionary<ItemTier, PickupIndex>();

		public static readonly UnityEngine.Color invalidPickupColor = UnityEngine.Color.black;

		public static readonly string invalidPickupToken = "???";

		public static Action<List<PickupDef>> modifyPickups;

		public static int pickupCount { get; private set; }

		public static GenericStaticEnumerable<PickupIndex, Enumerator> allPickupIndices => default(GenericStaticEnumerable<PickupIndex, Enumerator>);

		public static IEnumerable<PickupDef> allPickups => entries;

		[NotNull]
		public static T[] GetPerPickupBuffer<T>()
		{
			return new T[pickupCount];
		}

		public static void SetEntries([NotNull] PickupDef[] pickupDefs)
		{
			Array.Resize(ref entries, pickupDefs.Length);
			pickupCount = pickupDefs.Length;
			Array.Copy(pickupDefs, entries, entries.Length);
			Array.Resize(ref itemIndexToPickupIndex, ItemCatalog.itemCount);
			Array.Resize(ref equipmentIndexToPickupIndex, EquipmentCatalog.equipmentCount);
			Array.Resize(ref artifactIndexToPickupIndex, ArtifactCatalog.artifactCount);
			Array.Resize(ref miscPickupIndexToPickupIndex, MiscPickupCatalog.pickupCount);
			nameToPickupIndex.Clear();
			itemTierToPickupIndex.Clear();
			for (int i = 0; i < entries.Length; i++)
			{
				PickupDef pickupDef = entries[i];
				PickupIndex pickupIndex2 = (pickupDef.pickupIndex = new PickupIndex(i));
				if (pickupDef.itemIndex != ItemIndex.None)
				{
					itemIndexToPickupIndex[(int)pickupDef.itemIndex] = pickupIndex2;
				}
				else if (pickupDef.itemTier != ItemTier.NoTier)
				{
					itemTierToPickupIndex.Add(pickupDef.itemTier, pickupDef.pickupIndex);
				}
				if (pickupDef.equipmentIndex != EquipmentIndex.None)
				{
					equipmentIndexToPickupIndex[(int)pickupDef.equipmentIndex] = pickupIndex2;
				}
				if (pickupDef.artifactIndex != ArtifactIndex.None)
				{
					artifactIndexToPickupIndex[(int)pickupDef.artifactIndex] = pickupIndex2;
				}
				if (pickupDef.miscPickupIndex != MiscPickupIndex.None)
				{
					miscPickupIndexToPickupIndex[(int)pickupDef.miscPickupIndex] = pickupIndex2;
				}
			}
			for (int j = 0; j < entries.Length; j++)
			{
				PickupDef pickupDef2 = entries[j];
				nameToPickupIndex[pickupDef2.internalName] = pickupDef2.pickupIndex;
			}
		}

		[SystemInitializer(new Type[]
		{
			typeof(ItemCatalog),
			typeof(EquipmentCatalog),
			typeof(ArtifactCatalog),
			typeof(MiscPickupCatalog)
		})]
		public static IEnumerator Init()
		{
			AsyncOperationHandle<GameObject> equipmentDefPreload = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/ItemPickups/EquipmentOrb");
			while (!equipmentDefPreload.IsDone)
			{
				yield return null;
			}
			EquipmentDef.SetDropletDisplayPrefab(equipmentDefPreload.Result);
			List<PickupDef> pickupDefs = new List<PickupDef>();
			foreach (ItemTierDef allItemTierDef in ItemTierCatalog.allItemTierDefs)
			{
				PickupDef pickupDef = new PickupDef();
				pickupDef.internalName = "ItemTier." + allItemTierDef.tier;
				pickupDef.itemTier = allItemTierDef.tier;
				pickupDef.dropletDisplayPrefab = allItemTierDef?.dropletDisplayPrefab;
				pickupDef.baseColor = ColorCatalog.GetColor(allItemTierDef.colorIndex);
				pickupDef.darkColor = ColorCatalog.GetColor(allItemTierDef.darkColorIndex);
				pickupDef.interactContextToken = "ITEM_PICKUP_CONTEXT";
				pickupDef.isLunar = allItemTierDef.tier == ItemTier.Lunar;
				pickupDef.isBoss = allItemTierDef.tier == ItemTier.Boss;
				pickupDefs.Add(pickupDef);
			}
			yield return null;
			for (int i = 0; i < ItemCatalog.itemCount; i++)
			{
				PickupDef item = ItemCatalog.GetItemDef((ItemIndex)i).CreatePickupDef();
				pickupDefs.Add(item);
			}
			yield return null;
			for (int j = 0; j < EquipmentCatalog.equipmentCount; j++)
			{
				PickupDef item2 = EquipmentCatalog.GetEquipmentDef((EquipmentIndex)j).CreatePickupDef();
				pickupDefs.Add(item2);
			}
			yield return null;
			for (int k = 0; k < MiscPickupCatalog.pickupCount; k++)
			{
				PickupDef item3 = MiscPickupCatalog.miscPickupDefs[k].CreatePickupDef();
				pickupDefs.Add(item3);
			}
			yield return null;
			for (int l = 0; l < ArtifactCatalog.artifactCount; l++)
			{
				PickupDef item4 = ArtifactCatalog.GetArtifactDef((ArtifactIndex)l).CreatePickupDef();
				pickupDefs.Add(item4);
			}
			yield return null;
			modifyPickups?.Invoke(pickupDefs);
			SetEntries(pickupDefs.ToArray());
		}

		public static PickupIndex FindScrapIndexForItemTier(ItemTier tier)
		{
			PickupIndex result = PickupIndex.none;
			switch (tier)
			{
			case ItemTier.Tier1:
				result = FindPickupIndex("ItemIndex.ScrapWhite");
				break;
			case ItemTier.Tier2:
				result = FindPickupIndex("ItemIndex.ScrapGreen");
				break;
			case ItemTier.Tier3:
				result = FindPickupIndex("ItemIndex.ScrapRed");
				break;
			case ItemTier.Boss:
				result = FindPickupIndex("ItemIndex.ScrapYellow");
				break;
			}
			return result;
		}

		public static PickupIndex FindPickupIndex([NotNull] string pickupName)
		{
			if (nameToPickupIndex.TryGetValue(pickupName, out var value))
			{
				return value;
			}
			return PickupIndex.none;
		}

		public static PickupIndex FindPickupIndex(ItemIndex itemIndex)
		{
			return ArrayUtils.GetSafe(itemIndexToPickupIndex, (int)itemIndex, in PickupIndex.none);
		}

		public static PickupIndex FindPickupIndex(ItemTier tier)
		{
			if (itemTierToPickupIndex.TryGetValue(tier, out var value))
			{
				return value;
			}
			return PickupIndex.none;
		}

		public static PickupIndex FindPickupIndex(EquipmentIndex equipmentIndex)
		{
			return ArrayUtils.GetSafe(equipmentIndexToPickupIndex, (int)equipmentIndex, in PickupIndex.none);
		}

		public static PickupIndex FindPickupIndex(ArtifactIndex artifactIndex)
		{
			return ArrayUtils.GetSafe(artifactIndexToPickupIndex, (int)artifactIndex, in PickupIndex.none);
		}

		public static PickupIndex FindPickupIndex(MiscPickupIndex miscIndex)
		{
			return ArrayUtils.GetSafe(miscPickupIndexToPickupIndex, (int)miscIndex, in PickupIndex.none);
		}

		[CanBeNull]
		public static PickupDef GetPickupDef(PickupIndex pickupIndex)
		{
			return ArrayUtils.GetSafe(entries, pickupIndex.value);
		}

		[NotNull]
		public static GameObject GetHiddenPickupDisplayPrefab()
		{
			return LegacyResourcesAPI.Load<GameObject>("Prefabs/PickupModels/PickupMystery");
		}

		[ConCommand(commandName = "pickup_print_all", flags = ConVarFlags.None, helpText = "Prints all pickup definitions.")]
		private static void CCPickupPrintAll(ConCommandArgs args)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < pickupCount; i++)
			{
				PickupDef pickupDef = GetPickupDef(new PickupIndex(i));
				stringBuilder.Append("[").Append(i).Append("]={internalName=")
					.Append(pickupDef.internalName)
					.Append("}")
					.AppendLine();
			}
		}
	}
	public class PickupDef
	{
		public struct GrantContext
		{
			public CharacterBody body;

			public GenericPickupController controller;

			public bool shouldDestroy;

			public bool shouldNotify;
		}

		public delegate void AttemptGrantDelegate(ref GrantContext context);

		public string internalName;

		public GameObject displayPrefab;

		public GameObject dropletDisplayPrefab;

		public string nameToken = "???";

		public UnityEngine.Color baseColor;

		public UnityEngine.Color darkColor;

		public ItemIndex itemIndex = ItemIndex.None;

		public EquipmentIndex equipmentIndex = EquipmentIndex.None;

		public ArtifactIndex artifactIndex = ArtifactIndex.None;

		public MiscPickupIndex miscPickupIndex = MiscPickupIndex.None;

		public ItemTier itemTier = ItemTier.NoTier;

		public uint coinValue;

		public UnlockableDef unlockableDef;

		public string interactContextToken;

		public bool isLunar;

		public bool isBoss;

		public Texture iconTexture;

		public Sprite iconSprite;

		public AttemptGrantDelegate attemptGrant;

		public PickupIndex pickupIndex { get; set; } = PickupIndex.none;

	}
	public abstract class PickupDropTable : ScriptableObject
	{
		public bool canDropBeReplaced = true;

		private static readonly List<PickupDropTable> instancesList;

		protected static PickupIndex[] GenerateUniqueDropsFromWeightedSelection(int maxDrops, Xoroshiro128Plus rng, WeightedSelection<PickupIndex> weightedSelection)
		{
			int num = Math.Min(maxDrops, weightedSelection.Count);
			int[] array = Array.Empty<int>();
			PickupIndex[] array2 = new PickupIndex[num];
			for (int i = 0; i < num; i++)
			{
				int num2 = weightedSelection.EvaluateToChoiceIndex(rng.nextNormalizedFloat, array);
				array2[i] = weightedSelection.GetChoice(num2).value;
				Array.Resize(ref array, i + 1);
				array[i] = num2;
			}
			return array2;
		}

		protected static PickupIndex GenerateDropFromWeightedSelection(Xoroshiro128Plus rng, WeightedSelection<PickupIndex> weightedSelection)
		{
			if (weightedSelection.Count > 0)
			{
				return weightedSelection.Evaluate(rng.nextNormalizedFloat);
			}
			return PickupIndex.none;
		}

		public abstract int GetPickupCount();

		protected abstract PickupIndex GenerateDropPreReplacement(Xoroshiro128Plus rng);

		public PickupIndex GenerateDrop(Xoroshiro128Plus rng)
		{
			PickupIndex pickupIndex = GenerateDropPreReplacement(rng);
			if (pickupIndex == PickupIndex.none)
			{
				UnityEngine.Debug.LogError("Could not generate pickup index from droptable.");
			}
			if (!pickupIndex.isValid)
			{
				UnityEngine.Debug.LogError("Pickup index from droptable is invalid.");
			}
			if (canDropBeReplaced)
			{
				return RandomlyLunarUtils.CheckForLunarReplacement(pickupIndex, rng);
			}
			return pickupIndex;
		}

		protected abstract PickupIndex[] GenerateUniqueDropsPreReplacement(int maxDrops, Xoroshiro128Plus rng);

		public PickupIndex[] GenerateUniqueDrops(int maxDrops, Xoroshiro128Plus rng)
		{
			PickupIndex[] array = GenerateUniqueDropsPreReplacement(maxDrops, rng);
			if (canDropBeReplaced)
			{
				RandomlyLunarUtils.CheckForLunarReplacementUniqueArray(array, rng);
			}
			return array;
		}

		protected virtual void Regenerate(Run run)
		{
		}

		protected virtual void OnEnable()
		{
			instancesList.Add(this);
			if ((bool)Run.instance)
			{
				Regenerate(Run.instance);
			}
		}

		protected virtual void OnDisable()
		{
			instancesList.Remove(this);
		}

		static PickupDropTable()
		{
			instancesList = new List<PickupDropTable>();
			Run.onRunStartGlobal += RegenerateAll;
			Run.onAvailablePickupsModified += RegenerateAll;
		}

		private static void RegenerateAll(Run run)
		{
			for (int i = 0; i < instancesList.Count; i++)
			{
				instancesList[i].Regenerate(run);
			}
		}

		public void ModifyTierWeights(float tier1, float tier2, float tier3)
		{
		}
	}
	[Serializable]
	public struct PickupIndex : IEquatable<PickupIndex>
	{
		public struct Enumerator : IEnumerator<PickupIndex>, IEnumerator, IDisposable
		{
			private PickupIndex position;

			public PickupIndex Current => position;

			object IEnumerator.Current => Current;

			public bool MoveNext()
			{
				++position;
				return position.value < PickupCatalog.pickupCount;
			}

			public void Reset()
			{
				position = none;
			}

			void IDisposable.Dispose()
			{
			}
		}

		public static readonly PickupIndex none = new PickupIndex(-1);

		[SerializeField]
		public readonly int value;

		public bool isValid => (uint)value < PickupCatalog.pickupCount;

		private PickupDef pickupDef => PickupCatalog.GetPickupDef(this);

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public ItemIndex itemIndex => pickupDef?.itemIndex ?? ItemIndex.None;

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public EquipmentIndex equipmentIndex => pickupDef?.equipmentIndex ?? EquipmentIndex.None;

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public uint coinValue => pickupDef?.coinValue ?? 0;

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public static GenericStaticEnumerable<PickupIndex, Enumerator> allPickups => default(GenericStaticEnumerable<PickupIndex, Enumerator>);

		public PickupIndex(int value)
		{
			this.value = ((value < 0) ? (-1) : value);
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public PickupIndex(ItemIndex itemIndex)
		{
			value = PickupCatalog.FindPickupIndex(itemIndex).value;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public PickupIndex(EquipmentIndex equipmentIndex)
		{
			value = PickupCatalog.FindPickupIndex(equipmentIndex).value;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public GameObject GetHiddenPickupDisplayPrefab()
		{
			return PickupCatalog.GetHiddenPickupDisplayPrefab();
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public GameObject GetPickupDisplayPrefab()
		{
			return pickupDef?.displayPrefab;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public GameObject GetPickupDropletDisplayPrefab()
		{
			return pickupDef?.dropletDisplayPrefab;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public UnityEngine.Color GetPickupColor()
		{
			return pickupDef?.baseColor ?? UnityEngine.Color.black;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public string GetPickupNameToken()
		{
			return pickupDef?.nameToken ?? "???";
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public UnlockableDef GetUnlockable()
		{
			return pickupDef?.unlockableDef;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public bool IsLunar()
		{
			return pickupDef?.isLunar ?? false;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public bool IsBoss()
		{
			return pickupDef?.isBoss ?? false;
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public string GetInteractContextToken()
		{
			return pickupDef?.interactContextToken ?? "";
		}

		public static bool operator ==(PickupIndex a, PickupIndex b)
		{
			return a.value == b.value;
		}

		public static bool operator !=(PickupIndex a, PickupIndex b)
		{
			return a.value != b.value;
		}

		public static bool operator <(PickupIndex a, PickupIndex b)
		{
			return a.value < b.value;
		}

		public static bool operator >(PickupIndex a, PickupIndex b)
		{
			return a.value > b.value;
		}

		public static bool operator <=(PickupIndex a, PickupIndex b)
		{
			return a.value >= b.value;
		}

		public static bool operator >=(PickupIndex a, PickupIndex b)
		{
			return a.value <= b.value;
		}

		public static PickupIndex operator ++(PickupIndex a)
		{
			return new PickupIndex(a.value + 1);
		}

		public static PickupIndex operator --(PickupIndex a)
		{
			return new PickupIndex(a.value - 1);
		}

		public override bool Equals(object obj)
		{
			if (obj is PickupIndex)
			{
				return this == (PickupIndex)obj;
			}
			return false;
		}

		public bool Equals(PickupIndex other)
		{
			return value == other.value;
		}

		public override int GetHashCode()
		{
			return value.GetHashCode();
		}

		public static void WriteToNetworkWriter(NetworkWriter writer, PickupIndex value)
		{
			writer.WritePackedIndex32(value.value);
		}

		public static PickupIndex ReadFromNetworkReader(NetworkReader reader)
		{
			return new PickupIndex(reader.ReadPackedIndex32());
		}

		public override string ToString()
		{
			return pickupDef?.internalName ?? $"BadPickupIndex{value}";
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public static PickupIndex Find(string name)
		{
			return PickupCatalog.FindPickupIndex(name);
		}

		[Obsolete("PickupIndex methods are deprecated. Use PickupCatalog instead.")]
		public static Enumerator GetEnumerator()
		{
			return default(Enumerator);
		}
	}
	[Serializable]
	public struct SerializablePickupIndex
	{
		[SerializeField]
		public string pickupName;

		public static explicit operator PickupIndex(SerializablePickupIndex serializablePickupIndex)
		{
			return PickupCatalog.FindPickupIndex(serializablePickupIndex.pickupName);
		}
	}
	public static class PickupTransmutationManager
	{
		private static PickupIndex[][] pickupGroups = Array.Empty<PickupIndex[]>();

		private static PickupIndex[][] pickupGroupMap = Array.Empty<PickupIndex[]>();

		private static PickupIndex[] itemTier1Group;

		private static PickupIndex[] itemTier2Group;

		private static PickupIndex[] itemTier3Group;

		private static PickupIndex[] itemTierBossGroup;

		private static PickupIndex[] itemTierLunarGroup;

		private static PickupIndex[] equipmentNormalGroup;

		private static PickupIndex[] equipmentLunarGroup;

		private static PickupIndex[] equipmentBossGroup;

		private static PickupIndex[] itemVoidTier1Group;

		private static PickupIndex[] itemVoidTier2Group;

		private static PickupIndex[] itemVoidTier3Group;

		private static PickupIndex[] itemVoidBossGroup;

		private static PickupIndex[][] availablePickupGroups = Array.Empty<PickupIndex[]>();

		private static PickupIndex[][] availablePickupGroupMap = Array.Empty<PickupIndex[]>();

		[SystemInitializer(new Type[] { typeof(PickupCatalog) })]
		public static IEnumerator Init()
		{
			RebuildPickupGroups();
			Run.onRunStartGlobal += RebuildAvailablePickupGroups;
			yield return null;
		}

		public static void RebuildPickupGroups()
		{
			pickupGroupMap = new PickupIndex[PickupCatalog.pickupCount][];
			List<PickupIndex[]> groups = new List<PickupIndex[]>();
			itemTier1Group = AddItemTierGroup(ItemTier.Tier1);
			itemTier2Group = AddItemTierGroup(ItemTier.Tier2);
			itemTier3Group = AddItemTierGroup(ItemTier.Tier3);
			itemTierBossGroup = AddItemTierGroup(ItemTier.Boss);
			itemTierLunarGroup = AddItemTierGroup(ItemTier.Lunar);
			equipmentNormalGroup = AddGroup(GetEquipmentGroup(isBoss: false, isLunar: false));
			equipmentLunarGroup = AddGroup(GetEquipmentGroup(isBoss: false, isLunar: true));
			equipmentBossGroup = AddGroup(GetEquipmentGroup(isBoss: true, isLunar: false));
			itemVoidTier1Group = AddItemTierGroup(ItemTier.VoidTier1);
			itemVoidTier2Group = AddItemTierGroup(ItemTier.VoidTier2);
			itemVoidTier3Group = AddItemTierGroup(ItemTier.VoidTier3);
			itemVoidBossGroup = AddItemTierGroup(ItemTier.VoidBoss);
			pickupGroups = groups.ToArray();
			PickupIndex[] AddGroup(PickupIndex[] group)
			{
				groups.Add(group);
				for (int i = 0; i < group.Length; i++)
				{
					PickupIndex pickupIndex = group[i];
					pickupGroupMap[pickupIndex.value] = group;
				}
				return group;
			}
			PickupIndex[] AddItemTierGroup(ItemTier tier)
			{
				PickupIndex[] itemTierGroup = GetItemTierGroup(tier);
				AddGroup(itemTierGroup);
				PickupIndex pickupIndex2 = PickupCatalog.FindPickupIndex(tier);
				if (pickupIndex2 != PickupIndex.none)
				{
					pickupGroupMap[pickupIndex2.value] = itemTierGroup;
				}
				return itemTierGroup;
			}
			static PickupIndex[] GetEquipmentGroup(bool isBoss, bool isLunar)
			{
				return (from equipmentDef in EquipmentCatalog.allEquipment.Select(EquipmentCatalog.GetEquipmentDef)
					where equipmentDef.canDrop && equipmentDef.isBoss == isBoss && equipmentDef.isLunar == isLunar
					select PickupCatalog.FindPickupIndex(equipmentDef.equipmentIndex)).ToArray();
			}
			static PickupIndex[] GetItemTierGroup(ItemTier itemTier)
			{
				return (from itemDef in ItemCatalog.allItems.Select(ItemCatalog.GetItemDef)
					where itemDef.tier == itemTier && !itemDef.ContainsTag(ItemTag.WorldUnique)
					select PickupCatalog.FindPickupIndex(itemDef.itemIndex)).ToArray();
			}
		}

		private static void RebuildAvailablePickupGroups([NotNull] Run source)
		{
			Array.Resize(ref availablePickupGroups, pickupGroups.Length);
			Array.Resize(ref availablePickupGroupMap, pickupGroupMap.Length);
			Func<PickupIndex, bool> predicate = source.IsPickupAvailable;
			for (int i = 0; i < availablePickupGroups.Length; i++)
			{
				PickupIndex[] array = pickupGroups[i];
				PickupIndex[] array2 = array.Where(predicate).ToArray();
				availablePickupGroups[i] = array2;
				for (int j = 0; j < array.Length; j++)
				{
					availablePickupGroupMap[array[j].value] = array2;
				}
			}
		}

		[CanBeNull]
		public static PickupIndex[] GetGroupFromPickupIndex(PickupIndex pickupIndex)
		{
			return ArrayUtils.GetSafe(pickupGroupMap, pickupIndex.value);
		}

		[CanBeNull]
		public static PickupIndex[] GetAvailableGroupFromPickupIndex(PickupIndex pickupIndex)
		{
			return ArrayUtils.GetSafe(availablePickupGroupMap, pickupIndex.value);
		}
	}
	[Serializable]
	public struct PitchYawPair
	{
		public static readonly PitchYawPair zero = new PitchYawPair(0f, 0f);

		public float pitch;

		public float yaw;

		public PitchYawPair(float pitch, float yaw)
		{
			this.pitch = pitch;
			this.yaw = yaw;
		}

		public static PitchYawPair Lerp(PitchYawPair a, PitchYawPair b, float t)
		{
			float num = Mathf.LerpAngle(a.pitch, b.pitch, t);
			float num2 = Mathf.LerpAngle(a.yaw, b.yaw, t);
			return new PitchYawPair(num, num2);
		}

		public static PitchYawPair SmoothDamp(PitchYawPair current, PitchYawPair target, ref PitchYawPair velocity, float smoothTime, float maxSpeed)
		{
			float num = Mathf.SmoothDampAngle(current.pitch, target.pitch, ref velocity.pitch, smoothTime, maxSpeed);
			float num2 = Mathf.SmoothDampAngle(current.yaw, target.yaw, ref velocity.yaw, smoothTime, maxSpeed);
			return new PitchYawPair(num, num2);
		}
	}
	public abstract class AchievementSystem
	{
		internal const int ACHIEVEMENT_COUNT = 38;

		public abstract void AddAchievement(string achievementName);

		public virtual void UpdateAchievementProgress(string achievementName, ulong statProgress, ulong statRequirement, ulong id)
		{
		}
	}
	public class AddressablesTextDataManager : TextDataManager
	{
		private bool configInitialized;

		private bool locInitialized;

		private List<TextAsset> configFiles = new List<TextAsset>();

		public override bool InitializedConfigFiles => configInitialized;

		public override bool InitializedLocFiles => locInitialized;

		public AddressablesTextDataManager()
		{
			AsyncOperationHandle<IList<IResourceLocation>> asyncOperationHandle = Addressables.LoadResourceLocationsAsync("Config");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<IList<IResourceLocation>> addressesResult)
			{
				AsyncOperationHandle<IList<TextAsset>> asyncOperationHandle2 = Addressables.LoadAssetsAsync(addressesResult.Result, delegate(TextAsset conf)
				{
					configFiles.Add(conf);
				});
				asyncOperationHandle2.Completed += delegate
				{
					configInitialized = true;
				};
			};
			locInitialized = true;
		}

		public override string GetConfFile(string fileName, string path)
		{
			string fileNameLower = fileName.ToLower();
			TextAsset textAsset = configFiles.Find((TextAsset x) => x.name.ToLower().Contains(fileNameLower));
			if (textAsset != null)
			{
				return textAsset.text;
			}
			return null;
		}

		public override void GetLocFiles(string folderPath, Action<string[]> callback)
		{
			AsyncOperationHandle<IList<IResourceLocation>> asyncOperationHandle = Addressables.LoadResourceLocationsAsync("Localization");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<IList<IResourceLocation>> addressesResult)
			{
				List<IResourceLocation> list = new List<IResourceLocation>();
				for (int num = addressesResult.Result.Count - 1; num >= 0; num--)
				{
					if (addressesResult.Result[num].PrimaryKey.StartsWith(folderPath))
					{
						list.Add(addressesResult.Result[num]);
					}
				}
				List<TextAsset> textAssetResults = new List<TextAsset>(list.Count);
				AsyncOperationHandle<IList<TextAsset>> asyncOperationHandle2 = Addressables.LoadAssetsAsync(list, delegate(TextAsset x)
				{
					if (x != null)
					{
						textAssetResults.Add(x);
					}
				});
				asyncOperationHandle2.Completed += delegate
				{
					int count = textAssetResults.Count;
					string[] array = new string[count];
					for (int i = 0; i < count; i++)
					{
						array[i] = textAssetResults[i].text;
					}
					callback?.Invoke(array);
				};
			};
		}
	}
	public class ConsoleAssetsTextDataManager : TextDataManager
	{
		public override bool InitializedConfigFiles => true;

		public override bool InitializedLocFiles => true;

		public override string GetConfFile(string fileName, string path)
		{
			MemoryStream configData = PlatformSystems.saveSystem.configData;
			if (configData != null)
			{
				MemoryStream memoryStream = new MemoryStream();
				configData.CopyTo(memoryStream);
				using TextReader textReader = new StreamReader(memoryStream);
				memoryStream.Seek(0L, SeekOrigin.Begin);
				return textReader.ReadToEnd();
			}
			return "";
		}

		public override void GetLocFiles(string folderPath, Action<string[]> callback)
		{
			List<string> list = new List<string>();
			foreach (string item in Directory.EnumerateFiles(folderPath))
			{
				if (string.Compare(System.IO.Path.GetFileName(item), "language.json", StringComparison.OrdinalIgnoreCase) != 0)
				{
					string extension = System.IO.Path.GetExtension(item);
					if (MatchesExtension(extension, ".txt") || MatchesExtension(extension, ".json"))
					{
						list.Add(item);
					}
				}
			}
			callback?.Invoke(list.ConvertAll((string x) => File.ReadAllText(x)).ToArray());
			static bool MatchesExtension(string fileExtension, string testExtension)
			{
				return string.Compare(fileExtension, testExtension, StringComparison.OrdinalIgnoreCase) == 0;
			}
		}
	}
	public class AchievementSystemEOS : AchievementSystem
	{
		private AchievementsInterface _achievementsInterface;

		public AchievementSystemEOS()
		{
			_achievementsInterface = EOSPlatformManager.GetPlatformInterface().GetAchievementsInterface();
			QueryPlayerAchievementsOptions options = new QueryPlayerAchievementsOptions
			{
				LocalUserId = EOSLoginManager.loggedInProductId,
				TargetUserId = EOSLoginManager.loggedInProductId
			};
			_achievementsInterface.QueryPlayerAchievements(ref options, null, null);
		}

		public override void AddAchievement(string achievementName)
		{
			if (!string.IsNullOrEmpty(achievementName))
			{
				achievementName = achievementName.ToUpper();
			}
			else
			{
				UnityEngine.Debug.LogError("Invalid achievement name. Achievement is null or empty.");
			}
			if (IsValidAchievement(achievementName))
			{
				UnlockAchievementsOptions unlockAchievementsOptions = default(UnlockAchievementsOptions);
				unlockAchievementsOptions.AchievementIds = new Utf8String[1]
				{
					new Utf8String(achievementName)
				};
				unlockAchievementsOptions.UserId = EOSLoginManager.loggedInProductId;
				UnlockAchievementsOptions options = unlockAchievementsOptions;
				_achievementsInterface.UnlockAchievements(ref options, null, null);
			}
			else
			{
				UnityEngine.Debug.LogError("Invalid achievement name: " + achievementName + ". Make sure the achievement's name is defined in the EOS Developer Portal.");
			}
		}

		private bool IsValidAchievement(string achievementName)
		{
			CopyAchievementDefinitionV2ByAchievementIdOptions copyAchievementDefinitionV2ByAchievementIdOptions = default(CopyAchievementDefinitionV2ByAchievementIdOptions);
			copyAchievementDefinitionV2ByAchievementIdOptions.AchievementId = achievementName;
			CopyAchievementDefinitionV2ByAchievementIdOptions options = copyAchievementDefinitionV2ByAchievementIdOptions;
			_achievementsInterface.CopyAchievementDefinitionV2ByAchievementId(ref options, out var outDefinition);
			if (outDefinition.HasValue)
			{
				return !outDefinition.Value.IsHidden;
			}
			return false;
		}
	}
	public class EOSFriendsManager
	{
		public static FriendsInterface Interface;

		private static ConnectInterface _connectInterface;

		public static List<ProductUserId> FriendsProductUserIds { get; } = new List<ProductUserId>();


		private static EpicAccountId LocalUserEpicAccountId => EOSLoginManager.loggedInAuthId;

		private static ProductUserId LocalUserProductUserId => EOSLoginManager.loggedInProductId;

		public EOSFriendsManager()
		{
			Interface = EOSPlatformManager.GetPlatformInterface().GetFriendsInterface();
			_connectInterface = EOSPlatformManager.GetPlatformInterface().GetConnectInterface();
			EOSLoginManager.OnAuthLoggedIn += Initialize;
		}

		private static void Initialize(EpicAccountId obj)
		{
			QueryFriendsRefresh(null, delegate
			{
				PopulateFriendsEpicAccountIds();
			});
			AddNotifyFriendsUpdateOptions options = default(AddNotifyFriendsUpdateOptions);
			Interface.AddNotifyFriendsUpdate(ref options, null, FriendsUpdateHandler);
		}

		private static void FriendsUpdateHandler(ref OnFriendsUpdateInfo data)
		{
			switch (data.CurrentStatus)
			{
			case FriendsStatus.NotFriends:
				FriendsProductUserIds.Remove(data.TargetUserId.ToProductUserId());
				break;
			case FriendsStatus.Friends:
				QueryFriendsRefresh(null, TryAddFriend);
				break;
			}
		}

		private static void TryAddFriend(ref QueryFriendsCallbackInfo data)
		{
			ProductUserId productUserId = data.LocalUserId.ToProductUserId();
			if (productUserId != null && !FriendsProductUserIds.Contains(productUserId))
			{
				FriendsProductUserIds.Add(productUserId);
			}
		}

		private static void QueryFriendsRefresh(object clientData = null, OnQueryFriendsCallback callback = null)
		{
			QueryFriendsOptions queryFriendsOptions = default(QueryFriendsOptions);
			queryFriendsOptions.LocalUserId = LocalUserEpicAccountId;
			QueryFriendsOptions options = queryFriendsOptions;
			Interface.QueryFriends(ref options, clientData, callback);
		}

		private static void PopulateFriendsEpicAccountIds()
		{
			GetFriendsCountOptions getFriendsCountOptions = default(GetFriendsCountOptions);
			getFriendsCountOptions.LocalUserId = LocalUserEpicAccountId;
			GetFriendsCountOptions options = getFriendsCountOptions;
			int friendsCount = Interface.GetFriendsCount(ref options);
			Utf8String[] array = new Utf8String[friendsCount];
			EpicAccountId[] array2 = new EpicAccountId[friendsCount];
			for (int i = 0; i < friendsCount; i++)
			{
				GetFriendAtIndexOptions getFriendAtIndexOptions = default(GetFriendAtIndexOptions);
				getFriendAtIndexOptions.Index = i;
				getFriendAtIndexOptions.LocalUserId = LocalUserEpicAccountId;
				GetFriendAtIndexOptions options2 = getFriendAtIndexOptions;
				EpicAccountId friendAtIndex = Interface.GetFriendAtIndex(ref options2);
				array[i] = friendAtIndex.ToString();
				array2[i] = friendAtIndex;
			}
			QueryExternalAccountMappingsOptions queryExternalAccountMappingsOptions = default(QueryExternalAccountMappingsOptions);
			queryExternalAccountMappingsOptions.AccountIdType = ExternalAccountType.Epic;
			queryExternalAccountMappingsOptions.ExternalAccountIds = array;
			queryExternalAccountMappingsOptions.LocalUserId = LocalUserProductUserId;
			QueryExternalAccountMappingsOptions options3 = queryExternalAccountMappingsOptions;
			_connectInterface.QueryExternalAccountMappings(ref options3, array2, PopulateFriendsProductUserId);
		}

		private static void PopulateFriendsProductUserId(ref QueryExternalAccountMappingsCallbackInfo data)
		{
			if (data.ResultCode == Result.Success && data.ClientData is EpicAccountId[] array)
			{
				EpicAccountId[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					ProductUserId productUserId = array2[i].ToProductUserId();
					FriendsProductUserIds.Add(productUserId);
					(PlatformSystems.userManager as UserManagerEOS)?.QueryForDisplayNames(productUserId);
				}
				FriendsProductUserIds.Add(EOSLoginManager.loggedInProductId);
				(PlatformSystems.userManager as UserManagerEOS)?.QueryForDisplayNames(EOSLoginManager.loggedInProductId);
			}
		}
	}
	public class EOSLibraryManager
	{
		private IntPtr _libraryPointer;

		private bool _initialized;

		[DllImport("Kernel32.dll")]
		private static extern IntPtr LoadLibrary(string lpLibFileName);

		[DllImport("Kernel32.dll")]
		private static extern int FreeLibrary(IntPtr hLibModule);

		[DllImport("Kernel32.dll")]
		private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

		public EOSLibraryManager()
		{
			Initialize();
		}

		private void Initialize()
		{
			if (!_initialized)
			{
				_initialized = true;
			}
		}

		public void Shutdown()
		{
			_initialized = false;
		}
	}
	[DefaultExecutionOrder(-5)]
	public class EOSLinkAccountButtonVisibilitycontroller : MonoBehaviour
	{
		public GameObject egsLinkAccountButton;

		private void OnEnable()
		{
		}
	}
	public class EOSLobbyManager : PCLobbyManager
	{
		public class Filter
		{
			public List<AttributeData> SearchData = new List<AttributeData>();
		}

		private struct LobbyRefreshRequest
		{
			public object requester;

			public Filter filter;

			public Action<List<LobbyDetails>> callback;
		}

		private const MPFeatures PlatformFeatureFlags = MPFeatures.HostGame | MPFeatures.FindGame;

		private const MPLobbyFeatures PlatformLobbyUIFlags = MPLobbyFeatures.CreateLobby | MPLobbyFeatures.SocialIcon | MPLobbyFeatures.HostPromotion | MPLobbyFeatures.Clipboard | MPLobbyFeatures.Invite | MPLobbyFeatures.UserIcon | MPLobbyFeatures.LeaveLobby | MPLobbyFeatures.LobbyDropdownOptions;

		private bool _ownsLobby;

		private int minimumPlayerCount = 2;

		private string currentLobbyId = string.Empty;

		private LobbyDetails currentLobbyDetails;

		private LobbyModification currentLobbyModificationHandle;

		private LobbySearch currentSearchHandle;

		private LobbySearch joinClipboardLobbySearchHandle;

		private const int MaxSearchResults = 50;

		public const string mdEdition = "v";

		public const string mdAppId = "appid";

		public const string mdTotalMaxPlayers = "total_max_players";

		public const string mdPlayerCount = "player_count";

		public const string mdQuickplayQueued = "qp";

		public const string mdQuickplayCutoffTime = "qp_cutoff_time";

		public const string mdStarting = "starting";

		public const string mdBuildId = "build_id";

		public const string mdServerId = "server_id";

		public const string mdServerAddress = "server_address";

		public const string mdMap = "_map";

		public const string mdRuleBook = "rulebook";

		public const string mdMigrationId = "migration_id";

		public const string mdHasPassword = "_pw";

		public const string mdIsDedicatedServer = "_ds";

		public const string mdServerName = "_svnm";

		public const string mdServerTags = "_svtags";

		public const string mdServerMaxPlayers = "_svmpl";

		public const string mdServerPlayerCount = "_svplc";

		public const string mdGameModeName = "_svgm";

		public const string mdModHash = "_mh";

		public const string BucketName = "gbx_internal";

		private LobbyInterface lobbyInterface;

		private readonly List<int> playerCountsList = new List<int>();

		private MemoizedToString<int, ToStringImplementationInvariant> localPlayerCountToString = MemoizedToString<int, ToStringImplementationInvariant>.GetNew();

		private const string LobbyJoinIndicator = "ClipboardJoin";

		private bool startingFadeSet;

		private string lastHostingLobbyId;

		private const float quickplayCutoffTime = 30f;

		private Queue<LobbyRefreshRequest> lobbyRefreshRequests = new Queue<LobbyRefreshRequest>();

		private LobbyRefreshRequest? currentRefreshRequest;

		private bool hostingServer;

		private PlatformID currentServerId;

		private static readonly char[] charactersToCheck = "abcdef".ToCharArray();

		public override bool isInLobby
		{
			get
			{
				return currentLobbyId != string.Empty;
			}
			protected set
			{
			}
		}

		public override bool ownsLobby
		{
			get
			{
				return _ownsLobby;
			}
			protected set
			{
				if (value != _ownsLobby)
				{
					_ownsLobby = value;
					if (_ownsLobby)
					{
						OnLobbyOwnershipGained();
						UpdatePlayerCount();
					}
					else
					{
						OnLobbyOwnershipLost();
					}
				}
			}
		}

		public override bool hasMinimumPlayerCount => newestLobbyData.totalPlayerCount >= minimumPlayerCount;

		public int remoteMachineCount { get; private set; }

		public string CurrentLobbyId
		{
			get
			{
				return currentLobbyId;
			}
			private set
			{
			}
		}

		public LobbyDetails CurrentLobbyDetails
		{
			get
			{
				return currentLobbyDetails;
			}
			private set
			{
			}
		}

		public LobbyModification CurrentLobbyModification
		{
			get
			{
				return currentLobbyModificationHandle;
			}
			private set
			{
			}
		}

		public PlatformID serverId => newestLobbyData.serverId;

		public override LobbyData newestLobbyData { get; protected set; }

		public override int calculatedTotalPlayerCount { get; protected set; }

		public override int calculatedExtraPlayersCount { get; protected set; }

		public override LobbyType currentLobbyType
		{
			get
			{
				if (currentLobbyDetails != null)
				{
					LobbyDetailsCopyInfoOptions options = default(LobbyDetailsCopyInfoOptions);
					currentLobbyDetails.CopyInfo(ref options, out var outLobbyDetailsInfo);
					return PermissionLevelToType(outLobbyDetailsInfo.Value.PermissionLevel);
				}
				return LobbyType.Error;
			}
			set
			{
			}
		}

		public override bool IsBusy { get; set; }

		public override MPFeatures GetPlatformMPFeatureFlags()
		{
			return MPFeatures.HostGame | MPFeatures.FindGame;
		}

		public override MPLobbyFeatures GetPlatformMPLobbyFeatureFlags()
		{
			return MPLobbyFeatures.CreateLobby | MPLobbyFeatures.SocialIcon | MPLobbyFeatures.HostPromotion | MPLobbyFeatures.Clipboard | MPLobbyFeatures.Invite | MPLobbyFeatures.UserIcon | MPLobbyFeatures.LeaveLobby | MPLobbyFeatures.LobbyDropdownOptions;
		}

		public static EOSLobbyManager GetFromPlatformSystems()
		{
			return PlatformSystems.lobbyManager as EOSLobbyManager;
		}

		private void UpdateOwnsLobby()
		{
			LobbyDetailsGetLobbyOwnerOptions options = default(LobbyDetailsGetLobbyOwnerOptions);
			ownsLobby = currentLobbyDetails != null && currentLobbyDetails.GetLobbyOwner(ref options) == EOSLoginManager.loggedInProductId;
		}

		public void Init()
		{
			lobbyInterface = EOSPlatformManager.GetPlatformInterface().GetLobbyInterface();
			if (lobbyInterface == null)
			{
				UnityEngine.Debug.LogError("Unable to Obtain EOS Lobby Interface!");
			}
			SetupLobbyCallbacks();
			RoR2Application.onUpdate += StaticUpdate;
			LobbyDataSetupState setupState = new LobbyDataSetupState
			{
				totalMaxPlayers = RoR2Application.maxPlayers
			};
			newestLobbyData = new LobbyData(setupState);
			LocalUserManager.onLocalUsersUpdated += UpdatePlayerCount;
			NetworkManagerSystem.onStartServerGlobal += OnStartHostingServer;
			NetworkManagerSystem.onStopServerGlobal += OnStopHostingServer;
			NetworkManagerSystem.onStopClientGlobal += OnStopClient;
			NetworkManagerSystem.onStopClientGlobal += delegate
			{
				SetStartingIfOwner(startingState: false);
			};
			onLobbyOwnershipGained = (Action)Delegate.Combine(onLobbyOwnershipGained, (Action)delegate
			{
				SetStartingIfOwner(startingState: false);
			});
			UserManager.OnDisplayNameMappingComplete += UpdateLobbyNames;
			SetStartingIfOwner(startingState: false);
			SteamworksClientManager.onLoaded += SetSteamLobbyCallbacks;
		}

		public override void Shutdown()
		{
			base.Shutdown();
			lobbyInterface = null;
		}

		private void SetSteamLobbyCallbacks()
		{
			Client steamworksClient = SteamworksClientManager.instance.steamworksClient;
			steamworksClient.Lobby.OnUserInvitedToLobby = OnUserInvitedToSteamLobby;
			steamworksClient.Lobby.OnLobbyJoinRequested = OnSteamLobbyJoinRequested;
		}

		private void OnSteamLobbyJoinRequested(ulong lobbyId)
		{
			UnityEngine.Debug.LogFormat("Request to join lobby {0} received but we're in cross-play, rejecting", lobbyId);
			PCLobbyManager.ShowEnableCrossPlayPopup(isLobbyCrossplay: false);
		}

		private void OnUserInvitedToSteamLobby(ulong lobbyId, ulong senderId)
		{
			UnityEngine.Debug.LogFormat("Received invitation to lobby {0} from sender {1} but we're in cross play, rejecting", lobbyId, senderId);
		}

		private void UpdateLobbyNames()
		{
			onLobbyDataUpdated?.Invoke();
		}

		private void SetupLobbyCallbacks()
		{
			AddNotifyLobbyUpdateReceivedOptions options = default(AddNotifyLobbyUpdateReceivedOptions);
			lobbyInterface.AddNotifyLobbyUpdateReceived(ref options, null, OnLobbyDataUpdateReceived);
			AddNotifyJoinLobbyAcceptedOptions options2 = default(AddNotifyJoinLobbyAcceptedOptions);
			lobbyInterface.AddNotifyJoinLobbyAccepted(ref options2, null, OnJoinLobbyAccepted);
			AddNotifyLobbyInviteReceivedOptions options3 = default(AddNotifyLobbyInviteReceivedOptions);
			lobbyInterface.AddNotifyLobbyInviteReceived(ref options3, null, OnUserInvitedToLobby);
			AddNotifyLobbyInviteAcceptedOptions options4 = default(AddNotifyLobbyInviteAcceptedOptions);
			lobbyInterface.AddNotifyLobbyInviteAccepted(ref options4, null, OnLobbyInviteAccepted);
		}

		public override int GetLobbyMemberPlayerCountByIndex(int memberIndex)
		{
			if (memberIndex >= playerCountsList.Count)
			{
				return 0;
			}
			return playerCountsList[memberIndex];
		}

		public override void CheckIfInitializedAndValid()
		{
		}

		private void UpdateMemberAttribute(string inKey, string inValue)
		{
			if (CurrentLobbyModification != null)
			{
				UnityEngine.Debug.LogFormat("Setting lobby member attribute {0} to value {1} for user {2}", inKey, inValue, EOSLoginManager.loggedInProductId);
				LobbyModificationRemoveMemberAttributeOptions lobbyModificationRemoveMemberAttributeOptions = default(LobbyModificationRemoveMemberAttributeOptions);
				lobbyModificationRemoveMemberAttributeOptions.Key = inKey;
				LobbyModificationRemoveMemberAttributeOptions options = lobbyModificationRemoveMemberAttributeOptions;
				CurrentLobbyModification.RemoveMemberAttribute(ref options);
				LobbyModificationAddMemberAttributeOptions lobbyModificationAddMemberAttributeOptions = default(LobbyModificationAddMemberAttributeOptions);
				lobbyModificationAddMemberAttributeOptions.Attribute = new AttributeData
				{
					Key = inKey,
					Value = inValue
				};
				lobbyModificationAddMemberAttributeOptions.Visibility = LobbyAttributeVisibility.Public;
				LobbyModificationAddMemberAttributeOptions options2 = lobbyModificationAddMemberAttributeOptions;
				CurrentLobbyModification.AddMemberAttribute(ref options2);
				UpdateLobby(CurrentLobbyModification);
			}
		}

		private void UpdatePlayerCount()
		{
			if (currentLobbyDetails != null)
			{
				int count = LocalUserManager.readOnlyLocalUsersList.Count;
				ref MemoizedToString<int, ToStringImplementationInvariant> reference = ref localPlayerCountToString;
				int input = Math.Max(1, count);
				string @string = reference.GetString(in input);
				LobbyDetailsCopyMemberAttributeByKeyOptions lobbyDetailsCopyMemberAttributeByKeyOptions = default(LobbyDetailsCopyMemberAttributeByKeyOptions);
				lobbyDetailsCopyMemberAttributeByKeyOptions.AttrKey = "player_count";
				lobbyDetailsCopyMemberAttributeByKeyOptions.TargetUserId = EOSLoginManager.loggedInProductId;
				LobbyDetailsCopyMemberAttributeByKeyOptions options = lobbyDetailsCopyMemberAttributeByKeyOptions;
				if (CurrentLobbyDetails.CopyMemberAttributeByKey(ref options, out var outAttribute) == Result.Success)
				{
					if ((string)outAttribute.Value.Data.Value.Value.AsUtf8 != @string && CurrentLobbyModification != null)
					{
						UpdateMemberAttribute("player_count", @string);
					}
				}
				else
				{
					UpdateMemberAttribute("player_count", @string);
				}
				playerCountsList.Clear();
				calculatedTotalPlayerCount = 0;
				remoteMachineCount = 0;
				calculatedExtraPlayersCount = 0;
				ProductUserId loggedInProductId = EOSLoginManager.loggedInProductId;
				LobbyDetailsGetMemberCountOptions options2 = default(LobbyDetailsGetMemberCountOptions);
				uint memberCount = currentLobbyDetails.GetMemberCount(ref options2);
				for (uint num = 0u; num < memberCount; num++)
				{
					LobbyDetailsGetMemberByIndexOptions lobbyDetailsGetMemberByIndexOptions = default(LobbyDetailsGetMemberByIndexOptions);
					lobbyDetailsGetMemberByIndexOptions.MemberIndex = num;
					LobbyDetailsGetMemberByIndexOptions options3 = lobbyDetailsGetMemberByIndexOptions;
					ProductUserId memberByIndex = currentLobbyDetails.GetMemberByIndex(ref options3);
					int result = 1;
					LobbyDetailsCopyMemberAttributeByKeyOptions options4 = new LobbyDetailsCopyMemberAttributeByKeyOptions
					{
						AttrKey = "player_count",
						TargetUserId = EOSLoginManager.loggedInProductId
					};
					if (CurrentLobbyDetails.CopyMemberAttributeByKey(ref options4, out var outAttribute2) == Result.Success)
					{
						result = ((!TextSerialization.TryParseInvariant((string)outAttribute2.Value.Data.Value.Value.AsUtf8, out result)) ? 1 : Math.Max(1, result));
					}
					if (memberByIndex == loggedInProductId)
					{
						result = Math.Max(1, count);
					}
					else
					{
						input = remoteMachineCount + 1;
						remoteMachineCount = input;
					}
					playerCountsList.Add(result);
					calculatedTotalPlayerCount += result;
					if (result > 1)
					{
						calculatedExtraPlayersCount += result - 1;
					}
				}
			}
			onPlayerCountUpdated?.Invoke();
		}

		private void OnLobbyChanged()
		{
			OnLobbyDataUpdated();
			onLobbyChanged?.Invoke();
			(PlatformSystems.userManager as UserManagerEOS).QueryForDisplayNames(GetLobbyMembers());
		}

		public override void CreateLobby()
		{
			CreateLobbyOptions createLobbyOptions = default(CreateLobbyOptions);
			createLobbyOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			createLobbyOptions.MaxLobbyMembers = (uint)RoR2Application.maxPlayers;
			createLobbyOptions.PermissionLevel = ((preferredLobbyType != LobbyType.Public) ? LobbyPermissionLevel.Joinviapresence : LobbyPermissionLevel.Publicadvertised);
			createLobbyOptions.BucketId = "gbx_internal";
			createLobbyOptions.PresenceEnabled = true;
			createLobbyOptions.AllowInvites = true;
			CreateLobbyOptions options = createLobbyOptions;
			base.awaitingCreate = true;
			lobbyInterface?.CreateLobby(ref options, null, OnLobbyCreated);
		}

		public override void JoinLobby(PlatformID uid)
		{
			LeaveLobby(delegate
			{
				JoinLobbyOptions joinLobbyOptions = default(JoinLobbyOptions);
				joinLobbyOptions.LocalUserId = EOSLoginManager.loggedInProductId;
				JoinLobbyOptions options = joinLobbyOptions;
				lobbyInterface?.JoinLobby(ref options, null, OnLobbyJoined);
			});
			base.awaitingJoin = true;
		}

		public void JoinLobby(LobbyDetails lobbyID)
		{
			LeaveLobby(delegate
			{
				JoinLobbyOptions joinLobbyOptions = default(JoinLobbyOptions);
				joinLobbyOptions.LocalUserId = EOSLoginManager.loggedInProductId;
				joinLobbyOptions.LobbyDetailsHandle = lobbyID;
				JoinLobbyOptions options = joinLobbyOptions;
				lobbyInterface?.JoinLobby(ref options, null, OnLobbyJoined);
			});
			base.awaitingJoin = true;
		}

		public void FindClipboardLobby(string lobbyId)
		{
			if (joinClipboardLobbySearchHandle != null)
			{
				joinClipboardLobbySearchHandle.Release();
				joinClipboardLobbySearchHandle = null;
			}
			joinClipboardLobbySearchHandle = new LobbySearch();
			CreateLobbySearchOptions createLobbySearchOptions = default(CreateLobbySearchOptions);
			createLobbySearchOptions.MaxResults = 1u;
			CreateLobbySearchOptions options = createLobbySearchOptions;
			if (lobbyInterface?.CreateLobbySearch(ref options, out joinClipboardLobbySearchHandle) == Result.Success)
			{
				LobbySearchSetLobbyIdOptions lobbySearchSetLobbyIdOptions = default(LobbySearchSetLobbyIdOptions);
				lobbySearchSetLobbyIdOptions.LobbyId = lobbyId;
				LobbySearchSetLobbyIdOptions options2 = lobbySearchSetLobbyIdOptions;
				joinClipboardLobbySearchHandle.SetLobbyId(ref options2);
				LobbySearchFindOptions lobbySearchFindOptions = default(LobbySearchFindOptions);
				lobbySearchFindOptions.LocalUserId = EOSLoginManager.loggedInProductId;
				LobbySearchFindOptions options3 = lobbySearchFindOptions;
				joinClipboardLobbySearchHandle.Find(ref options3, "ClipboardJoin", OnLobbySearchComplete);
			}
		}

		public override void LeaveLobby()
		{
			LeaveLobbyOptions leaveLobbyOptions = default(LeaveLobbyOptions);
			leaveLobbyOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			leaveLobbyOptions.LobbyId = currentLobbyId;
			LeaveLobbyOptions options = leaveLobbyOptions;
			lobbyInterface?.LeaveLobby(ref options, null, OnLobbyLeave);
			currentLobbyId = string.Empty;
		}

		private void LeaveLobby(Action callback)
		{
			LeaveLobbyOptions leaveLobbyOptions = default(LeaveLobbyOptions);
			leaveLobbyOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			leaveLobbyOptions.LobbyId = currentLobbyId;
			LeaveLobbyOptions options = leaveLobbyOptions;
			lobbyInterface?.LeaveLobby(ref options, null, delegate(ref LeaveLobbyCallbackInfo data)
			{
				OnLobbyLeave(ref data);
				callback?.Invoke();
			});
			currentLobbyId = string.Empty;
		}

		public override PlatformID[] GetLobbyMembers()
		{
			LobbyDetailsGetMemberCountOptions options = default(LobbyDetailsGetMemberCountOptions);
			uint? num = CurrentLobbyDetails?.GetMemberCount(ref options);
			PlatformID[] array = null;
			if (num.HasValue)
			{
				array = new PlatformID[num.Value];
				for (uint num2 = 0u; num2 < array.Length; num2++)
				{
					LobbyDetailsGetMemberByIndexOptions lobbyDetailsGetMemberByIndexOptions = default(LobbyDetailsGetMemberByIndexOptions);
					lobbyDetailsGetMemberByIndexOptions.MemberIndex = num2;
					LobbyDetailsGetMemberByIndexOptions options2 = lobbyDetailsGetMemberByIndexOptions;
					array[num2] = new PlatformID(CurrentLobbyDetails.GetMemberByIndex(ref options2));
				}
			}
			return array;
		}

		public override bool ShouldShowPromoteButton()
		{
			return false;
		}

		private void Update()
		{
			if (startingFadeSet != (newestLobbyData.starting && !ClientScene.ready))
			{
				if (startingFadeSet)
				{
					FadeToBlackManager.fadeCount--;
				}
				else
				{
					FadeToBlackManager.fadeCount++;
				}
				startingFadeSet = !startingFadeSet;
			}
		}

		private void StaticUpdate()
		{
			UpdateOwnsLobby();
		}

		private PlatformID GetLaunchParamsLobbyId()
		{
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			for (int i = 0; i < commandLineArgs.Length - 1; i++)
			{
				if (string.Equals(commandLineArgs[i], "+connect_lobby", StringComparison.OrdinalIgnoreCase) && PlatformID.TryParse(ArrayUtils.GetSafe(commandLineArgs, i + 1, in string.Empty), out var result))
				{
					return result;
				}
			}
			return PlatformID.nil;
		}

		public void ForceLobbyDataUpdate()
		{
		}

		public void SendLobbyMessage(LobbyMessageType messageType, NetworkWriter writer)
		{
			byte[] array = new byte[1 + writer.Position];
			array[0] = (byte)messageType;
			Array.Copy(writer.AsArray(), 0, array, 1, writer.Position);
		}

		public override void OnCutoffTimerComplete()
		{
		}

		private void OnChatMessageReceived(ulong senderId, byte[] buffer, int byteCount)
		{
			try
			{
				NetworkReader networkReader = new NetworkReader(buffer);
				if (byteCount >= 1)
				{
					LobbyMessageType lobbyMessageType = (LobbyMessageType)networkReader.ReadByte();
					UnityEngine.Debug.LogFormat("Received Steamworks Lobby Message from {0} ({1}B). messageType={2}", senderId, byteCount, lobbyMessageType);
					switch (lobbyMessageType)
					{
					}
				}
				else
				{
					UnityEngine.Debug.LogWarningFormat("Received SteamworksLobbyMessage from {0}, but the message was empty.");
				}
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private void OnLobbyCreated(ref CreateLobbyCallbackInfo data)
		{
			base.awaitingCreate = false;
			if (data.ResultCode == Result.Success)
			{
				currentLobbyId = data.LobbyId;
				TryGetLobbyDetails();
				OnLobbyChanged();
			}
		}

		protected void OnLobbyDataUpdated()
		{
			UpdateNewestLobbyData();
			UpdateOwnsLobby();
			UpdatePlayerCount();
			if (currentLobbyDetails != null && !ownsLobby)
			{
				if (newestLobbyData.serverId.isValid)
				{
					bool num = newestLobbyData.serverId == NetworkManagerSystem.singleton.serverP2PId || NetworkManagerSystem.singleton.IsConnectedToServer(newestLobbyData.serverId);
					bool flag = string.CompareOrdinal(RoR2Application.GetBuildId(), newestLobbyData.buildId) == 0;
					if (!num && flag)
					{
						NetworkManagerSystem.singleton.desiredHost = new HostDescription(newestLobbyData.serverId, HostDescription.HostType.EOS);
						lastHostingLobbyId = currentLobbyId;
					}
				}
				else if (lastHostingLobbyId == currentLobbyId)
				{
					UnityEngine.Debug.LogFormat("Intercepting bad or out-of-order lobby update to server id.");
				}
				else
				{
					NetworkManagerSystem.singleton.desiredHost = HostDescription.none;
				}
			}
			onLobbyDataUpdated?.Invoke();
		}

		private void UpdateNewestLobbyData()
		{
			DateTime value = Util.UnixTimeStampToDateTimeUtc((uint)Util.GetCurrentUnixEpochTimeInSeconds()) + TimeSpan.FromSeconds(30.0);
			if (currentLobbyDetails != null)
			{
				LobbyDataSetupState lobbyDataSetupState = new LobbyDataSetupState
				{
					totalMaxPlayers = RoR2Application.maxPlayers,
					totalPlayerCount = calculatedTotalPlayerCount,
					quickplayQueued = false,
					starting = GetLobbyBoolValue(currentLobbyDetails, "starting"),
					buildId = GetLobbyStringValue(currentLobbyDetails, "build_id"),
					quickplayCutoffTime = value,
					shouldConnect = false,
					joinable = (calculatedTotalPlayerCount < RoR2Application.maxPlayers)
				};
				string lobbyStringValue = GetLobbyStringValue(currentLobbyDetails, "server_id");
				if (lobbyStringValue != string.Empty)
				{
					lobbyDataSetupState.serverId = new PlatformID(lobbyStringValue);
				}
				newestLobbyData = new LobbyData(lobbyDataSetupState);
			}
			else
			{
				newestLobbyData = new LobbyData();
			}
		}

		private void OnLobbyJoined(ref JoinLobbyCallbackInfo data)
		{
			base.awaitingJoin = false;
			bool flag = data.ResultCode == Result.Success;
			if (flag)
			{
				currentLobbyId = data.LobbyId;
				TryGetLobbyDetails();
				if (currentLobbyDetails != null)
				{
					string buildId = RoR2Application.GetBuildId();
					string lobbyStringValue = GetLobbyStringValue(currentLobbyDetails, "build_id");
					if (buildId != lobbyStringValue)
					{
						UnityEngine.Debug.LogFormat("Lobby build_id mismatch, leaving lobby. Ours=\"{0}\" Theirs=\"{1}\"", buildId, lobbyStringValue);
						SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
						simpleDialogBox.AddCancelButton(CommonLanguageTokens.ok);
						simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
						{
							token = "STEAM_LOBBY_VERSION_MISMATCH_DIALOG_TITLE",
							formatParams = Array.Empty<object>()
						};
						SimpleDialogBox.TokenParamsPair descriptionToken = new SimpleDialogBox.TokenParamsPair
						{
							token = "STEAM_LOBBY_VERSION_MISMATCH_DIALOG_DESCRIPTION"
						};
						object[] formatParams = new string[2] { buildId, lobbyStringValue };
						descriptionToken.formatParams = formatParams;
						simpleDialogBox.descriptionToken = descriptionToken;
						return;
					}
				}
				UnityEngine.Debug.LogFormat("lobby join succeeded. Lobby id = {0}", currentLobbyId);
				OnLobbyChanged();
			}
			else
			{
				SimpleDialogBox simpleDialogBox2 = SimpleDialogBox.Create();
				simpleDialogBox2.AddCancelButton(CommonLanguageTokens.ok);
				simpleDialogBox2.headerToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "EOS_CANNOT_JOIN_STEAM_LOBBY_HEADER",
					formatParams = Array.Empty<object>()
				};
				simpleDialogBox2.descriptionToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "KICK_REASON_SERVERFULL",
					formatParams = Array.Empty<object>()
				};
				Console.instance.SubmitCmd(null, "steam_lobby_create_if_none", recordSubmit: true);
			}
			onLobbyJoined?.Invoke(flag);
		}

		private void OnLobbyMemberDataUpdated(PlatformID memberId)
		{
			UpdateOwnsLobby();
			onLobbyMemberDataUpdated?.Invoke(memberId);
		}

		private void OnLobbyKicked(bool kickedDueToDisconnect, ulong lobbyId, ulong adminId)
		{
			UnityEngine.Debug.LogFormat("Kicked from lobby. kickedDueToDisconnect={0} lobbyId={1} adminId={2}", kickedDueToDisconnect, lobbyId, adminId);
			OnLobbyChanged();
		}

		private void OnLobbyLeave(ref LeaveLobbyCallbackInfo data)
		{
			UnityEngine.Debug.LogFormat("Left lobby {0}.", data.LobbyId);
			currentLobbyId = string.Empty;
			if (currentLobbyDetails != null)
			{
				currentLobbyDetails.Release();
				currentLobbyDetails = null;
			}
			if (currentLobbyModificationHandle != null)
			{
				currentLobbyModificationHandle.Release();
				currentLobbyModificationHandle = null;
			}
			OnLobbyChanged();
		}

		private void OnLobbyJoinRequested(ulong lobbyId)
		{
			UnityEngine.Debug.LogFormat("Request to join lobby {0} received. Attempting to join lobby.", lobbyId);
		}

		private void OnUserInvitedToLobby(ref LobbyInviteReceivedCallbackInfo data)
		{
			UnityEngine.Debug.LogFormat("Received invitation to lobby {0} from sender {1}.", data.InviteId, data.TargetUserId);
		}

		private static void OnSendInviteComplete(ref Epic.OnlineServices.Lobby.SendInviteCallbackInfo data)
		{
			_ = data.GetResultCode() == Result.Success;
		}

		private void OnLobbySearchComplete(ref LobbySearchFindCallbackInfo data)
		{
			if (data.GetResultCode() != Result.Success)
			{
				return;
			}
			bool flag = data.ClientData as string == "ClipboardJoin";
			List<LobbyDetails> list = new List<LobbyDetails>();
			LobbySearch lobbySearch = (flag ? joinClipboardLobbySearchHandle : currentSearchHandle);
			if (lobbySearch != null)
			{
				LobbySearchGetSearchResultCountOptions options = default(LobbySearchGetSearchResultCountOptions);
				uint searchResultCount = lobbySearch.GetSearchResultCount(ref options);
				for (uint num = 0u; num < searchResultCount; num++)
				{
					LobbyDetails outLobbyDetailsHandle = new LobbyDetails();
					LobbySearchCopySearchResultByIndexOptions lobbySearchCopySearchResultByIndexOptions = default(LobbySearchCopySearchResultByIndexOptions);
					lobbySearchCopySearchResultByIndexOptions.LobbyIndex = num;
					LobbySearchCopySearchResultByIndexOptions options2 = lobbySearchCopySearchResultByIndexOptions;
					if (lobbySearch.CopySearchResultByIndex(ref options2, out outLobbyDetailsHandle) == Result.Success)
					{
						if (flag)
						{
							JoinLobby(outLobbyDetailsHandle);
							joinClipboardLobbySearchHandle.Release();
							joinClipboardLobbySearchHandle = null;
							return;
						}
						list.Add(outLobbyDetailsHandle);
					}
				}
			}
			(data.ClientData as Action<List<LobbyDetails>>)(list);
		}

		private void OnLobbyDataUpdateReceived(ref LobbyUpdateReceivedCallbackInfo data)
		{
			if (data.LobbyId == (Utf8String)currentLobbyId)
			{
				TryGetLobbyDetails();
				OnLobbyChanged();
			}
		}

		private void OnJoinLobbyAccepted(ref JoinLobbyAcceptedCallbackInfo data)
		{
			UnityEngine.Debug.LogFormat("Attempting to join from ui event {0} from local user {1}.", data.UiEventId, data.LocalUserId);
			LobbyDetails outLobbyDetailsHandle = new LobbyDetails();
			CopyLobbyDetailsHandleByUiEventIdOptions copyLobbyDetailsHandleByUiEventIdOptions = default(CopyLobbyDetailsHandleByUiEventIdOptions);
			copyLobbyDetailsHandleByUiEventIdOptions.UiEventId = data.UiEventId;
			CopyLobbyDetailsHandleByUiEventIdOptions options = copyLobbyDetailsHandleByUiEventIdOptions;
			Result? result = lobbyInterface?.CopyLobbyDetailsHandleByUiEventId(ref options, out outLobbyDetailsHandle);
			if (result == Result.Success)
			{
				JoinLobby(outLobbyDetailsHandle);
			}
			else
			{
				UnityEngine.Debug.LogFormat("failed getting lobby details from join callback, result = " + result.ToString());
			}
		}

		private void OnLobbyInviteAccepted(ref LobbyInviteAcceptedCallbackInfo data)
		{
			UnityEngine.Debug.LogFormat("Accepted invitation to lobby {0} from sender {1}.", data.InviteId, data.TargetUserId);
			LobbyDetails outLobbyDetailsHandle = new LobbyDetails();
			CopyLobbyDetailsHandleByInviteIdOptions copyLobbyDetailsHandleByInviteIdOptions = default(CopyLobbyDetailsHandleByInviteIdOptions);
			copyLobbyDetailsHandleByInviteIdOptions.InviteId = data.InviteId;
			CopyLobbyDetailsHandleByInviteIdOptions options = copyLobbyDetailsHandleByInviteIdOptions;
			Result? result = lobbyInterface?.CopyLobbyDetailsHandleByInviteId(ref options, out outLobbyDetailsHandle);
			if (result == Result.Success)
			{
				JoinLobby(outLobbyDetailsHandle);
			}
			else
			{
				UnityEngine.Debug.LogFormat("failed getting lobby details from invite, result = " + result.ToString());
			}
		}

		private void OnShowFriendsComplete(ref ShowFriendsCallbackInfo data)
		{
			_ = data.GetResultCode() == Result.Success;
		}

		private void OnLobbyUpdated(ref UpdateLobbyCallbackInfo data)
		{
			if (data.GetResultCode() == Result.Success)
			{
				OnLobbyChanged();
			}
		}

		private void TryGetLobbyDetails()
		{
			if (currentLobbyDetails != null)
			{
				currentLobbyDetails.Release();
				currentLobbyDetails = null;
			}
			CopyLobbyDetailsHandleOptions copyLobbyDetailsHandleOptions = default(CopyLobbyDetailsHandleOptions);
			copyLobbyDetailsHandleOptions.LobbyId = currentLobbyId;
			copyLobbyDetailsHandleOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			CopyLobbyDetailsHandleOptions options = copyLobbyDetailsHandleOptions;
			_ = lobbyInterface?.CopyLobbyDetailsHandle(ref options, out currentLobbyDetails) == Result.Success;
			TryGetLobbyModificationHandle();
		}

		private void TryGetLobbyModificationHandle()
		{
			if (currentLobbyModificationHandle != null)
			{
				currentLobbyModificationHandle.Release();
				currentLobbyModificationHandle = null;
			}
			UpdateLobbyModificationOptions updateLobbyModificationOptions = default(UpdateLobbyModificationOptions);
			updateLobbyModificationOptions.LobbyId = currentLobbyId;
			updateLobbyModificationOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			UpdateLobbyModificationOptions options = updateLobbyModificationOptions;
			_ = lobbyInterface?.UpdateLobbyModification(ref options, out currentLobbyModificationHandle) == Result.Success;
		}

		public bool RequestLobbyList(object requester, Filter filter, Action<List<LobbyDetails>> callback)
		{
			if (requester != null)
			{
				foreach (LobbyRefreshRequest lobbyRefreshRequest2 in lobbyRefreshRequests)
				{
					if (requester == lobbyRefreshRequest2.requester)
					{
						return false;
					}
				}
			}
			LobbyRefreshRequest lobbyRefreshRequest = default(LobbyRefreshRequest);
			lobbyRefreshRequest.requester = requester;
			lobbyRefreshRequest.filter = filter;
			lobbyRefreshRequest.callback = callback;
			LobbyRefreshRequest item = lobbyRefreshRequest;
			lobbyRefreshRequests.Enqueue(item);
			UpdateRefreshRequestQueue();
			return true;
		}

		private void UpdateRefreshRequestQueue()
		{
			if (!currentRefreshRequest.HasValue && lobbyRefreshRequests.Count != 0)
			{
				SearchForLobbiesWithRequest(lobbyRefreshRequests.Dequeue());
			}
		}

		private void SearchForLobbiesWithRequest(LobbyRefreshRequest request)
		{
			if (currentSearchHandle != null)
			{
				currentSearchHandle.Release();
				currentSearchHandle = null;
			}
			CreateLobbySearchOptions createLobbySearchOptions = default(CreateLobbySearchOptions);
			createLobbySearchOptions.MaxResults = 50u;
			CreateLobbySearchOptions options = createLobbySearchOptions;
			currentSearchHandle = new LobbySearch();
			Result? result = lobbyInterface?.CreateLobbySearch(ref options, out currentSearchHandle);
			if (result == Result.Success)
			{
				LobbySearchSetParameterOptions lobbySearchSetParameterOptions = default(LobbySearchSetParameterOptions);
				lobbySearchSetParameterOptions.ComparisonOp = ComparisonOp.Equal;
				lobbySearchSetParameterOptions.Parameter = new AttributeData
				{
					Key = "build_id",
					Value = RoR2Application.GetBuildId()
				};
				LobbySearchSetParameterOptions options2 = lobbySearchSetParameterOptions;
				currentSearchHandle.SetParameter(ref options2);
				foreach (AttributeData searchDatum in request.filter.SearchData)
				{
					lobbySearchSetParameterOptions = default(LobbySearchSetParameterOptions);
					lobbySearchSetParameterOptions.ComparisonOp = ComparisonOp.Equal;
					lobbySearchSetParameterOptions.Parameter = searchDatum;
					options2 = lobbySearchSetParameterOptions;
					currentSearchHandle.SetParameter(ref options2);
				}
				LobbySearchFindOptions lobbySearchFindOptions = default(LobbySearchFindOptions);
				lobbySearchFindOptions.LocalUserId = EOSLoginManager.loggedInProductId;
				LobbySearchFindOptions options3 = lobbySearchFindOptions;
				currentSearchHandle.Find(ref options3, request.callback, OnLobbySearchComplete);
			}
			else
			{
				UnityEngine.Debug.LogError("Error Creating Lobby Search Handle! " + result.ToString());
			}
		}

		private void OnStopClient()
		{
			NetworkConnection connection = NetworkManagerSystem.singleton.client.connection;
			bool flag = false;
			bool flag2 = Util.ConnectionIsLocal(connection);
			flag = ((!(connection is EOSNetworkConnection)) ? (connection.address == newestLobbyData.serverAddressPortPair.address) : (((EOSNetworkConnection)connection).RemoteUserID == newestLobbyData.serverId.productUserID));
			if (flag2 && ownsLobby && currentLobbyModificationHandle != null)
			{
				LobbyModificationRemoveAttributeOptions lobbyModificationRemoveAttributeOptions = default(LobbyModificationRemoveAttributeOptions);
				lobbyModificationRemoveAttributeOptions.Key = "server_id";
				LobbyModificationRemoveAttributeOptions options = lobbyModificationRemoveAttributeOptions;
				currentLobbyModificationHandle.RemoveAttribute(ref options);
			}
			if (!flag2 && flag)
			{
				LeaveLobby();
			}
		}

		private void OnStartHostingServer()
		{
			hostingServer = true;
		}

		private void OnStopHostingServer()
		{
			hostingServer = false;
		}

		public void JoinOrStartMigrate(PlatformID newLobbyId)
		{
			if (ownsLobby)
			{
				StartMigrateLobby(newLobbyId.productUserID);
			}
			else
			{
				JoinLobby(newLobbyId);
			}
		}

		public void StartMigrateLobby(ProductUserId newLobbyId)
		{
		}

		private void AttemptToJoinPendingSteamworksLobby()
		{
			_ = LocalUserManager.isAnyUserSignedIn;
		}

		public void SetLobbyQuickPlayQueuedIfOwner(bool quickplayQueuedState)
		{
		}

		public void SetLobbyQuickPlayCutoffTimeIfOwner(uint? timestamp)
		{
		}

		public void SetStartingIfOwner(bool startingState)
		{
		}

		protected void OnLobbyOwnershipGained()
		{
			onLobbyOwnershipGained?.Invoke();
		}

		private void OnLobbyOwnershipLost()
		{
			onLobbyOwnershipLost?.Invoke();
		}

		public override bool IsLobbyOwner(PlatformID user)
		{
			LobbyDetailsGetLobbyOwnerOptions options = default(LobbyDetailsGetLobbyOwnerOptions);
			if (currentLobbyDetails != null)
			{
				return currentLobbyDetails.GetLobbyOwner(ref options) == user.productUserID;
			}
			return false;
		}

		public override void AutoMatchmake()
		{
		}

		public override bool IsLobbyOwner()
		{
			if (isInLobby)
			{
				return _ownsLobby;
			}
			return false;
		}

		public override bool CanInvite()
		{
			return !IsBusy;
		}

		public override void OpenInviteOverlay()
		{
			UIInterface uIInterface = EOSPlatformManager.GetPlatformInterface().GetUIInterface();
			ShowFriendsOptions options = new ShowFriendsOptions
			{
				LocalUserId = EOSLoginManager.loggedInAuthId
			};
			uIInterface?.ShowFriends(ref options, null, OnShowFriendsComplete);
		}

		public override void OnStartPrivateGame()
		{
		}

		public override void ToggleQuickplay()
		{
		}

		public override void CheckIfInvited()
		{
		}

		public override void CheckBusyTimer()
		{
		}

		public override bool ShouldEnableQuickplayButton()
		{
			return false;
		}

		public override bool ShouldEnableStartPrivateGameButton()
		{
			return true;
		}

		public override string GetUserDisplayName(PlatformID user)
		{
			if (user.productUserID != null)
			{
				string userDisplayName = (PlatformSystems.userManager as UserManagerEOS).GetUserDisplayName(user);
				if (userDisplayName != string.Empty)
				{
					return userDisplayName;
				}
			}
			return "";
		}

		public string GetUserDisplayNameFromProductIdString(string productIdString, Action callback = null)
		{
			if (productIdString != string.Empty)
			{
				string userDisplayName = (PlatformSystems.userManager as UserManagerEOS).GetUserDisplayName(new PlatformID(productIdString), callback);
				if (userDisplayName != string.Empty)
				{
					return userDisplayName;
				}
			}
			return "";
		}

		private static LobbyType PermissionLevelToType(LobbyPermissionLevel permissionLevel)
		{
			return permissionLevel switch
			{
				LobbyPermissionLevel.Inviteonly => LobbyType.Private, 
				LobbyPermissionLevel.Publicadvertised => LobbyType.Public, 
				LobbyPermissionLevel.Joinviapresence => LobbyType.FriendsOnly, 
				_ => LobbyType.Error, 
			};
		}

		private static LobbyPermissionLevel LobbyTypeToPermissionLevel(LobbyType type)
		{
			return type switch
			{
				LobbyType.FriendsOnly => LobbyPermissionLevel.Joinviapresence, 
				LobbyType.Private => LobbyPermissionLevel.Joinviapresence, 
				LobbyType.Public => LobbyPermissionLevel.Publicadvertised, 
				_ => LobbyPermissionLevel.Joinviapresence, 
			};
		}

		public override string GetLobbyID()
		{
			return currentLobbyId;
		}

		public override bool CheckLobbyIdValidity(string lobbyID)
		{
			if (lobbyID.IndexOfAny(charactersToCheck) == -1)
			{
				return false;
			}
			return true;
		}

		public override void JoinLobby(ConCommandArgs args)
		{
			CheckIfInitializedAndValid();
			string text = args[0];
			UnityEngine.Debug.LogFormat("Enqueuing join for lobby {0}...", text);
			FindClipboardLobby(text);
		}

		public override void LobbyCreate(ConCommandArgs args)
		{
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			obj.CheckIfInitializedAndValid();
			if (!LocalUserManager.isAnyUserSignedIn)
			{
				throw new ConCommandException("Cannot create a Steamworks lobby without any local users signed in.");
			}
			obj.CreateLobby();
		}

		public override void LobbyCreateIfNone(ConCommandArgs args)
		{
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			obj.CheckIfInitializedAndValid();
			if (!LocalUserManager.isAnyUserSignedIn)
			{
				throw new ConCommandException("Cannot create a Steamworks lobby without any local users signed in.");
			}
			obj.CreateLobby();
		}

		public override void LobbyLeave(ConCommandArgs args)
		{
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			obj.CheckIfInitializedAndValid();
			obj.LeaveLobby();
		}

		public override void LobbyAssignOwner(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as EOSLobbyManager).CheckIfInitializedAndValid();
			UnityEngine.Debug.LogFormat("Promoting {0} to lobby leader...", args[0]);
		}

		public override void LobbyInvite(ConCommandArgs args)
		{
			EOSLobbyManager eOSLobbyManager = PlatformSystems.lobbyManager as EOSLobbyManager;
			eOSLobbyManager.CheckIfInitializedAndValid();
			Epic.OnlineServices.Lobby.SendInviteOptions sendInviteOptions = default(Epic.OnlineServices.Lobby.SendInviteOptions);
			sendInviteOptions.LobbyId = eOSLobbyManager.currentLobbyId;
			sendInviteOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			sendInviteOptions.TargetUserId = ProductUserId.FromString(args.GetArgString(0));
			Epic.OnlineServices.Lobby.SendInviteOptions options = sendInviteOptions;
			eOSLobbyManager.lobbyInterface?.SendInvite(ref options, null, OnSendInviteComplete);
		}

		public override void LobbyOpenInviteOverlay(ConCommandArgs args)
		{
			if (EOSLoginManager.loggedInAuthId == null)
			{
				SteamworksLobbyManager.DoSteamLobbyOpenOverlay();
				return;
			}
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			obj.CheckIfInitializedAndValid();
			obj.OpenInviteOverlay();
		}

		public override void LobbyCopyToClipboard(ConCommandArgs args)
		{
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			obj.CheckIfInitializedAndValid();
			GUIUtility.systemCopyBuffer = obj.currentLobbyId;
			Chat.AddMessage(Language.GetString("STEAM_COPY_LOBBY_TO_CLIPBOARD_MESSAGE"));
		}

		public override void LobbyPrintData(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as EOSLobbyManager).CheckIfInitializedAndValid();
			new List<string>();
		}

		public override void DisplayId(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as EOSLobbyManager).CheckIfInitializedAndValid();
		}

		public override void DisplayLobbyId(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as EOSLobbyManager).CheckIfInitializedAndValid();
		}

		public override void LobbyPrintMembers(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as EOSLobbyManager).CheckIfInitializedAndValid();
		}

		public override void ClearLobbies(ConCommandArgs args)
		{
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			Filter filter = new Filter();
			obj.RequestLobbyList(null, filter, delegate(List<LobbyDetails> lobbies)
			{
				foreach (LobbyDetails lobby in lobbies)
				{
					_ = lobby;
				}
			});
		}

		public override void LobbyUpdatePlayerCount(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as EOSLobbyManager).UpdatePlayerCount();
		}

		public override void LobbyForceUpdateData(ConCommandArgs args)
		{
			EOSLobbyManager obj = PlatformSystems.lobbyManager as EOSLobbyManager;
			obj.CheckIfInitializedAndValid();
			obj.ForceLobbyDataUpdate();
		}

		public override void LobbyPrintList(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as EOSLobbyManager).CheckIfInitializedAndValid();
		}

		public static bool IsLobbyOwner(LobbyDetails lobby)
		{
			LobbyDetailsGetLobbyOwnerOptions options = default(LobbyDetailsGetLobbyOwnerOptions);
			return lobby.GetLobbyOwner(ref options) == EOSLoginManager.loggedInProductId;
		}

		public static string GetLobbyStringValue(LobbyDetails lobby, string key)
		{
			LobbyDetailsCopyAttributeByKeyOptions lobbyDetailsCopyAttributeByKeyOptions = default(LobbyDetailsCopyAttributeByKeyOptions);
			lobbyDetailsCopyAttributeByKeyOptions.AttrKey = key;
			LobbyDetailsCopyAttributeByKeyOptions options = lobbyDetailsCopyAttributeByKeyOptions;
			if (lobby.CopyAttributeByKey(ref options, out var outAttribute) == Result.Success)
			{
				return outAttribute.Value.Data.Value.Value.AsUtf8;
			}
			return string.Empty;
		}

		public static bool GetLobbyBoolValue(LobbyDetails lobbyDetails, string key)
		{
			LobbyDetailsCopyAttributeByKeyOptions lobbyDetailsCopyAttributeByKeyOptions = default(LobbyDetailsCopyAttributeByKeyOptions);
			lobbyDetailsCopyAttributeByKeyOptions.AttrKey = key;
			LobbyDetailsCopyAttributeByKeyOptions options = lobbyDetailsCopyAttributeByKeyOptions;
			if (lobbyDetails.CopyAttributeByKey(ref options, out var outAttribute) == Result.Success)
			{
				if (outAttribute.Value.Data.Value.Value.AsBool.HasValue)
				{
					return outAttribute.Value.Data.Value.Value.AsBool.Value;
				}
				return false;
			}
			return false;
		}

		public static long GetLobbyIntValue(LobbyDetails lobbyDetails, string key)
		{
			LobbyDetailsCopyAttributeByKeyOptions lobbyDetailsCopyAttributeByKeyOptions = default(LobbyDetailsCopyAttributeByKeyOptions);
			lobbyDetailsCopyAttributeByKeyOptions.AttrKey = key;
			LobbyDetailsCopyAttributeByKeyOptions options = lobbyDetailsCopyAttributeByKeyOptions;
			if (lobbyDetails.CopyAttributeByKey(ref options, out var outAttribute) == Result.Success && outAttribute.Value.Data.Value.Value.AsInt64.HasValue)
			{
				return outAttribute.Value.Data.Value.Value.AsInt64.Value;
			}
			return 0L;
		}

		public static double GetLobbyDoubleValue(LobbyDetails lobbyDetails, string key)
		{
			LobbyDetailsCopyAttributeByKeyOptions lobbyDetailsCopyAttributeByKeyOptions = default(LobbyDetailsCopyAttributeByKeyOptions);
			lobbyDetailsCopyAttributeByKeyOptions.AttrKey = key;
			LobbyDetailsCopyAttributeByKeyOptions options = lobbyDetailsCopyAttributeByKeyOptions;
			if (lobbyDetails.CopyAttributeByKey(ref options, out var outAttribute) == Result.Success && outAttribute.Value.Data.Value.Value.AsDouble.HasValue)
			{
				return outAttribute.Value.Data.Value.Value.AsDouble.Value;
			}
			return 0.0;
		}

		public static bool SetLobbyStringValue(LobbyModification lobby, string key, string value)
		{
			if (lobby == null || key == null || value == null || key == string.Empty || value == string.Empty)
			{
				return false;
			}
			LobbyModificationAddAttributeOptions lobbyModificationAddAttributeOptions = default(LobbyModificationAddAttributeOptions);
			lobbyModificationAddAttributeOptions.Attribute = new AttributeData
			{
				Key = key,
				Value = value
			};
			lobbyModificationAddAttributeOptions.Visibility = LobbyAttributeVisibility.Public;
			LobbyModificationAddAttributeOptions options = lobbyModificationAddAttributeOptions;
			return lobby.AddAttribute(ref options) == Result.Success;
		}

		public static void UpdateLobby(LobbyModification lobby)
		{
			EOSLobbyManager eOSLobbyManager = PlatformSystems.lobbyManager as EOSLobbyManager;
			eOSLobbyManager.CheckIfInitializedAndValid();
			UpdateLobbyOptions updateLobbyOptions = default(UpdateLobbyOptions);
			updateLobbyOptions.LobbyModificationHandle = lobby;
			UpdateLobbyOptions options = updateLobbyOptions;
			eOSLobbyManager.lobbyInterface?.UpdateLobby(ref options, null, eOSLobbyManager.OnLobbyUpdated);
		}

		public static bool RemoveLobbyStringValue(LobbyModification lobby, string key)
		{
			if (lobby != null)
			{
				LobbyModificationRemoveAttributeOptions lobbyModificationRemoveAttributeOptions = default(LobbyModificationRemoveAttributeOptions);
				lobbyModificationRemoveAttributeOptions.Key = key;
				LobbyModificationRemoveAttributeOptions options = lobbyModificationRemoveAttributeOptions;
				return lobby.RemoveAttribute(ref options) == Result.Success;
			}
			return false;
		}

		public static uint GetAllCurrentLobbyKVPs(LobbyDetails lobby, ref Dictionary<string, string> KVPs)
		{
			LobbyDetailsGetAttributeCountOptions options = default(LobbyDetailsGetAttributeCountOptions);
			uint attributeCount = lobby.GetAttributeCount(ref options);
			uint num = 0u;
			for (uint num2 = attributeCount; num < num2; num++)
			{
				LobbyDetailsCopyAttributeByIndexOptions lobbyDetailsCopyAttributeByIndexOptions = default(LobbyDetailsCopyAttributeByIndexOptions);
				lobbyDetailsCopyAttributeByIndexOptions.AttrIndex = num;
				LobbyDetailsCopyAttributeByIndexOptions options2 = lobbyDetailsCopyAttributeByIndexOptions;
				if (lobby.CopyAttributeByIndex(ref options2, out var outAttribute) == Result.Success)
				{
					AttributeData value = outAttribute.Value.Data.Value;
					KVPs.Add(value.Key, value.Value.AsUtf8);
				}
			}
			return attributeCount;
		}

		public override void SetLobbyTypeConVarString(string newValue)
		{
			EOSLobbyManager eOSLobbyManager = PlatformSystems.lobbyManager as EOSLobbyManager;
			eOSLobbyManager.CheckIfInitializedAndValid();
			LobbyDetailsCopyInfoOptions options = default(LobbyDetailsCopyInfoOptions);
			if (eOSLobbyManager.CurrentLobbyDetails.CopyInfo(ref options, out var _) != 0 || !eOSLobbyManager.IsLobbyOwner())
			{
				throw new ConCommandException("Lobby type cannot be set while not the owner of a valid lobby.");
			}
			LobbyType dest = LobbyType.Error;
			SteamLobbyTypeConVar.instance.GetEnumValueAbstract(newValue, ref dest);
			if (dest == LobbyType.Error)
			{
				throw new ConCommandException("Lobby type \"Error\" is not allowed.");
			}
			LobbyModificationSetPermissionLevelOptions lobbyModificationSetPermissionLevelOptions = default(LobbyModificationSetPermissionLevelOptions);
			lobbyModificationSetPermissionLevelOptions.PermissionLevel = LobbyTypeToPermissionLevel(dest);
			LobbyModificationSetPermissionLevelOptions options2 = lobbyModificationSetPermissionLevelOptions;
			if (eOSLobbyManager.CurrentLobbyModification.SetPermissionLevel(ref options2) == Result.Success)
			{
				UpdateLobby(eOSLobbyManager.CurrentLobbyModification);
			}
		}

		public override string GetLobbyTypeConVarString()
		{
			EOSLobbyManager eOSLobbyManager = PlatformSystems.lobbyManager as EOSLobbyManager;
			eOSLobbyManager.CheckIfInitializedAndValid();
			if (eOSLobbyManager.currentLobbyDetails != null)
			{
				LobbyDetailsCopyInfoOptions options = default(LobbyDetailsCopyInfoOptions);
				if (eOSLobbyManager.CurrentLobbyDetails.CopyInfo(ref options, out var outLobbyDetailsInfo) == Result.Success)
				{
					return PermissionLevelToType(outLobbyDetailsInfo.Value.PermissionLevel).ToString();
				}
				return string.Empty;
			}
			return string.Empty;
		}

		public override int GetLobbyMemberCount()
		{
			return 0;
		}
	}
	public class EOSLoginManager
	{
		public enum EOSLoginState
		{
			None,
			AttemptingLogin,
			AttemptingLink,
			FailedLogin,
			FailedLink,
			Success
		}

		public static EOSLoginManager instance = null;

		public static readonly BoolConVar cvLinkEOSAccount = new BoolConVar("eos_link_account", ConVarFlags.None, "0", "trigger the account linking process");

		public LoginCredentialType _loginCredentialType = LoginCredentialType.ExchangeCode;

		public string _loginCredentialId;

		public string _loginCredentialToken;

		private bool showCredentialPopup;

		public static EpicAccountId loggedInAuthId = null;

		public static ProductUserId loggedInProductId = null;

		public static PlatformID loggedInUserID;

		private ConnectInterface connectInterface;

		private static string ticket;

		public static EOSLoginState loginState { get; private set; } = EOSLoginState.None;


		public static event Action<EpicAccountId> OnAuthLoggedIn;

		public static event Action<ProductUserId> OnConnectLoggedIn;

		public static bool IsWaitingOnLogin()
		{
			return loginState != EOSLoginState.Success;
		}

		public void TryLogin()
		{
			instance = this;
			RoR2Application.onUpdate += OnUpdate;
			ExternalAuthLogin_Steam();
		}

		private void OnUpdate()
		{
			if (cvLinkEOSAccount.value && !IsWaitingOnLogin())
			{
				StartSteamLoginWithDefaultOptions(attemptAccountLink: true);
			}
		}

		private void OnSteamworksInitialized()
		{
			UpdateSessionAuthTicket();
			SteamworksClientManager.onLoaded -= OnSteamworksInitialized;
		}

		private void UpdateSessionAuthTicket()
		{
			ticket = Client.Instance.Auth.GetAuthSessionTicket().Data.ToHexString();
			StartSteamLoginWithDefaultOptions();
		}

		public void ExternalAuthLogin_Steam()
		{
			if (Client.Instance != null)
			{
				OnSteamworksInitialized();
			}
			else
			{
				SteamworksClientManager.onLoaded += OnSteamworksInitialized;
			}
		}

		public void StartSteamLoginWithDefaultOptions(bool attemptAccountLink = false)
		{
			Epic.OnlineServices.Auth.LoginOptions loginOptions = default(Epic.OnlineServices.Auth.LoginOptions);
			loginOptions.Credentials = new Epic.OnlineServices.Auth.Credentials
			{
				Type = LoginCredentialType.ExternalAuth,
				Token = ticket,
				ExternalType = ExternalCredentialType.SteamSessionTicket
			};
			loginOptions.ScopeFlags = AuthScopeFlags.BasicProfile | AuthScopeFlags.FriendsList | AuthScopeFlags.Presence;
			Epic.OnlineServices.Auth.LoginOptions loginOptions2 = loginOptions;
			StartEGSLogin(loginOptions2, attemptAccountLink);
		}

		private void StartEGSLoginWithDefaultOptions()
		{
			Epic.OnlineServices.Auth.LoginOptions loginOptions = default(Epic.OnlineServices.Auth.LoginOptions);
			loginOptions.Credentials = new Epic.OnlineServices.Auth.Credentials
			{
				Type = _loginCredentialType,
				Id = _loginCredentialId,
				Token = _loginCredentialToken
			};
			loginOptions.ScopeFlags = AuthScopeFlags.BasicProfile | AuthScopeFlags.FriendsList | AuthScopeFlags.Presence;
			Epic.OnlineServices.Auth.LoginOptions loginOptions2 = loginOptions;
			StartEGSLogin(loginOptions2);
		}

		private void StartEGSLogin(Epic.OnlineServices.Auth.LoginOptions loginOptions, bool attemptLink = false)
		{
			loginState = EOSLoginState.AttemptingLogin;
			AuthInterface authInterface = EOSPlatformManager.GetPlatformInterface().GetAuthInterface();
			if (authInterface != null)
			{
				authInterface.Login(ref loginOptions, null, delegate(ref Epic.OnlineServices.Auth.LoginCallbackInfo loginCallbackInfo)
				{
					if (loginCallbackInfo.ResultCode == Result.Success)
					{
						loginState = EOSLoginState.Success;
						cvLinkEOSAccount.SetBool(newValue: false);
						ProcessSuccessfulAuthLogin(loginCallbackInfo.LocalUserId);
					}
					else if (Common.IsOperationComplete(loginCallbackInfo.ResultCode))
					{
						if (loginCallbackInfo.ContinuanceToken != null)
						{
							if (attemptLink)
							{
								loginState = EOSLoginState.AttemptingLink;
								Epic.OnlineServices.Auth.LinkAccountOptions linkAccountOptions = default(Epic.OnlineServices.Auth.LinkAccountOptions);
								linkAccountOptions.ContinuanceToken = loginCallbackInfo.ContinuanceToken;
								linkAccountOptions.LinkAccountFlags = LinkAccountFlags.NoFlags;
								Epic.OnlineServices.Auth.LinkAccountOptions options = linkAccountOptions;
								authInterface.LinkAccount(ref options, null, delegate(ref Epic.OnlineServices.Auth.LinkAccountCallbackInfo linkAccountCallbackInfo)
								{
									if (linkAccountCallbackInfo.ResultCode == Result.Success)
									{
										loginState = EOSLoginState.Success;
										ProcessSuccessfulAuthLogin(linkAccountCallbackInfo.LocalUserId);
									}
									else
									{
										cvLinkEOSAccount.SetBool(newValue: false);
										loginState = EOSLoginState.FailedLink;
									}
								});
							}
							else
							{
								ProcessSteamAppTicketConnectLogin(loginOptions.Credentials.Value.Token);
							}
						}
						else
						{
							loginState = EOSLoginState.FailedLogin;
						}
					}
					else
					{
						loginState = EOSLoginState.FailedLogin;
					}
				});
				return;
			}
			loginState = EOSLoginState.FailedLogin;
			throw new Exception("Failed to get auth interface");
		}

		private void ProcessSuccessfulAuthLogin(EpicAccountId loggedInId)
		{
			loggedInAuthId = loggedInId;
			EOSLoginManager.OnAuthLoggedIn?.Invoke(loggedInAuthId);
			CopyUserAuthTokenOptions options = default(CopyUserAuthTokenOptions);
			if (EOSPlatformManager.GetPlatformInterface().GetAuthInterface().CopyUserAuthToken(ref options, loggedInAuthId, out var outUserAuthToken) == Result.Success)
			{
				Epic.OnlineServices.Connect.LoginOptions loginOptions = default(Epic.OnlineServices.Connect.LoginOptions);
				loginOptions.Credentials = new Epic.OnlineServices.Connect.Credentials
				{
					Token = outUserAuthToken.Value.AccessToken,
					Type = ExternalCredentialType.Epic
				};
				loginOptions.UserLoginInfo = null;
				Epic.OnlineServices.Connect.LoginOptions options2 = loginOptions;
				AttemptConnectLogin(options2);
			}
		}

		private void ProcessSteamAppTicketConnectLogin(string appTicket)
		{
			Epic.OnlineServices.Connect.LoginOptions loginOptions = default(Epic.OnlineServices.Connect.LoginOptions);
			loginOptions.Credentials = new Epic.OnlineServices.Connect.Credentials
			{
				Token = appTicket,
				Type = ExternalCredentialType.SteamSessionTicket
			};
			loginOptions.UserLoginInfo = null;
			Epic.OnlineServices.Connect.LoginOptions options = loginOptions;
			AttemptConnectLogin(options);
		}

		private bool IsConnectInterfaceValid()
		{
			if (connectInterface == null)
			{
				connectInterface = EOSPlatformManager.GetPlatformInterface().GetConnectInterface();
			}
			return connectInterface != null;
		}

		private void AttemptConnectLogin(Epic.OnlineServices.Connect.LoginOptions options)
		{
			if (IsConnectInterfaceValid())
			{
				connectInterface.Login(ref options, null, delegate(ref Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo)
				{
					if (loginCallbackInfo.ResultCode == Result.Success)
					{
						CompleteConnectLogin(loginCallbackInfo.LocalUserId);
					}
					else if (loginCallbackInfo.ResultCode == Result.InvalidUser)
					{
						CreateUserOptions createUserOptions = default(CreateUserOptions);
						createUserOptions.ContinuanceToken = loginCallbackInfo.ContinuanceToken;
						CreateUserOptions options2 = createUserOptions;
						connectInterface.CreateUser(ref options2, null, delegate(ref CreateUserCallbackInfo createUserCallbackInfo)
						{
							if (createUserCallbackInfo.ResultCode == Result.Success)
							{
								CompleteConnectLogin(createUserCallbackInfo.LocalUserId);
							}
							else
							{
								loginState = EOSLoginState.FailedLogin;
							}
						});
					}
					else if (Common.IsOperationComplete(loginCallbackInfo.ResultCode))
					{
						loginState = EOSLoginState.FailedLogin;
					}
				});
				return;
			}
			throw new Exception("Failed to get connect interface");
		}

		private void CompleteConnectLogin(ProductUserId localUserId)
		{
			loggedInProductId = localUserId;
			loggedInUserID = new PlatformID(loggedInProductId);
			EOSLoginManager.OnConnectLoggedIn?.Invoke(loggedInProductId);
			AddNotifyAuthExpirationOptions options = default(AddNotifyAuthExpirationOptions);
			connectInterface.AddNotifyAuthExpiration(ref options, null, OnAuthExpirationCallback);
			loginState = EOSLoginState.Success;
		}

		private void OnAuthExpirationCallback(ref AuthExpirationCallbackInfo data)
		{
			if (loggedInAuthId != null)
			{
				ProcessSuccessfulAuthLogin(loggedInAuthId);
			}
			else
			{
				UpdateSessionAuthTicket();
			}
		}
	}
	public class EOSPlatformManager : PlatformManager
	{
		private static PlatformInterface _platformInterface;

		private string _productName = Application.productName;

		private string _productVersion = Application.version;

		private string _productId = "3bf8fc77540f41b5bb253d9563eec679";

		private string _sandboxId = "0dfcaeede0214b80b597f08fd7d64b1b";

		private string _deploymentId = "f2ca672e660a4792a17b124291408566";

		private string _clientId;

		private string _clientSecret;

		private EOSLibraryManager libManager;

		public EOSPlatformManager()
		{
			libManager = new EOSLibraryManager();
			InitializePlatformInterface();
			SetupLogging();
			CreatePlatformInterface();
		}

		public override void InitializePlatformManager()
		{
			RoR2Application.onShutDown = (Action)Delegate.Combine(RoR2Application.onShutDown, new Action(Shutdown));
			RoR2Application.onUpdate += UpdatePlatformManager;
		}

		public static PlatformInterface GetPlatformInterface()
		{
			if (_platformInterface == null)
			{
				throw new Exception("_platformInterface has not been set. Initialize EOSPlatformManager before attempting to access _platformInterface.");
			}
			return _platformInterface;
		}

		private void InitializePlatformInterface()
		{
			InitializeOptions initializeOptions = default(InitializeOptions);
			initializeOptions.ProductName = _productName;
			initializeOptions.ProductVersion = _productVersion;
			InitializeOptions options = initializeOptions;
			Result result = PlatformInterface.Initialize(ref options);
			if (result != 0 && result != Result.AlreadyConfigured)
			{
				throw new Exception("Failed to initialize platform: " + result);
			}
		}

		private void SetupLogging()
		{
			LoggingInterface.SetLogLevel(LogCategory.AllCategories, LogLevel.VeryVerbose);
			LoggingInterface.SetCallback(delegate(ref LogMessage logMessage)
			{
				System.Console.WriteLine(logMessage.Message);
			});
		}

		private void CreatePlatformInterface()
		{
			Options options = default(Options);
			options.ProductId = _productId;
			options.SandboxId = _sandboxId;
			options.DeploymentId = _deploymentId;
			options.ClientCredentials = new ClientCredentials
			{
				ClientId = "xyza7891fuF5aodDdJ1ITnkYeRbyJbnT",
				ClientSecret = "QMwgx1LJIkRt25iA9YjXldcMD/8aAeQTke7a5FVU3no"
			};
			Options options2 = options;
			_platformInterface = PlatformInterface.Create(ref options2);
			if (_platformInterface == null)
			{
				throw new Exception("Failed to create platform");
			}
		}

		private void Shutdown()
		{
			if (_platformInterface != null)
			{
				_platformInterface.Release();
				_platformInterface = null;
				PlatformInterface.Shutdown();
			}
			libManager.Shutdown();
		}

		protected override void UpdatePlatformManager()
		{
			if (_platformInterface != null)
			{
				_platformInterface.Tick();
			}
		}
	}
	public static class EOSExtensions
	{
		public static ProductUserId ToProductUserId(this EpicAccountId epicAccountId)
		{
			GetExternalAccountMappingsOptions getExternalAccountMappingsOptions = default(GetExternalAccountMappingsOptions);
			getExternalAccountMappingsOptions.AccountIdType = ExternalAccountType.Epic;
			getExternalAccountMappingsOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			getExternalAccountMappingsOptions.TargetExternalUserId = epicAccountId.ToString();
			GetExternalAccountMappingsOptions options = getExternalAccountMappingsOptions;
			return EOSPlatformManager.GetPlatformInterface().GetConnectInterface().GetExternalAccountMapping(ref options);
		}
	}
	internal sealed class EOSServerManager : ServerManagerBase<EOSServerManager>, IDisposable
	{
		private Dictionary<string, string> KeyValue = new Dictionary<string, string>();

		public EOSServerManager()
		{
			Run.onServerRunSetRuleBookGlobal += base.OnServerRunSetRuleBookGlobal;
			PreGameController.onPreGameControllerSetRuleBookServerGlobal += base.OnPreGameControllerSetRuleBookServerGlobal;
			ruleBookKvHelper = new KeyValueSplitter("ruleBook", 2048, 2048, SetKey);
			modListKvHelper = new KeyValueSplitter(NetworkModCompatibilityHelper.steamworksGameserverRulesBaseName, 2048, 2048, SetKey);
			modListKvHelper.SetValue(NetworkModCompatibilityHelper.steamworksGameserverGameRulesValue);
			UpdateServerRuleBook();
		}

		public void SetKey(string Key, string Value)
		{
			KeyValue[Key] = Value;
		}
	}
	public class EOSStatManager
	{
		public static class StatNames
		{
			public const string kFastestWeeklyRun = "FASTESTWEEKLYRUN";
		}

		private static StatsInterface Interface;

		public EOSStatManager()
		{
			Interface = EOSPlatformManager.GetPlatformInterface().GetStatsInterface();
		}

		public static void IngestStat(IngestData[] statsToIngest, object callbackData = null, OnIngestStatCompleteCallback callback = null)
		{
			IngestStatOptions ingestStatOptions = default(IngestStatOptions);
			ingestStatOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			ingestStatOptions.Stats = statsToIngest;
			ingestStatOptions.TargetUserId = EOSLoginManager.loggedInProductId;
			IngestStatOptions options = ingestStatOptions;
			Interface.IngestStat(ref options, callbackData, callback);
		}

		public static void QueryStats(ref QueryStatsOptions queryStatsOptions, object callbackData = null, OnQueryStatsCompleteCallback callback = null)
		{
			Interface.QueryStats(ref queryStatsOptions, callbackData, callback);
		}

		public static Stat GetStat(string statName, ProductUserId targetUserId)
		{
			CopyStatByNameOptions copyStatByNameOptions = default(CopyStatByNameOptions);
			copyStatByNameOptions.Name = statName;
			copyStatByNameOptions.TargetUserId = targetUserId;
			CopyStatByNameOptions options = copyStatByNameOptions;
			Interface.CopyStatByName(ref options, out var outStat);
			return outStat.Value;
		}

		public static uint GetStatsCount(ProductUserId targetUserId)
		{
			GetStatCountOptions getStatCountOptions = default(GetStatCountOptions);
			getStatCountOptions.TargetUserId = targetUserId;
			GetStatCountOptions options = getStatCountOptions;
			return Interface.GetStatsCount(ref options);
		}
	}
	public class SaveSystemEOS : SaveSystemSteam
	{
		public override string GetPlatformUsernameOrDefault(string defaultName)
		{
			return PlatformSystems.userManager.GetUserName();
		}
	}
	public class UserManagerEOS : UserManager
	{
		private string LocalUserName = string.Empty;

		private static Dictionary<ProductUserId, ExternalAccountInfo> UserIDsToAccountInfo = new Dictionary<ProductUserId, ExternalAccountInfo>();

		private static List<ProductUserId> IDQueryList = new List<ProductUserId>();

		public void InitializeUserManager()
		{
			EOSLoginManager.OnAuthLoggedIn += TryGetLogin;
			LocalUserManager.onUserSignIn += OnUserSignIn;
		}

		public void OnUserSignIn(LocalUser localUser)
		{
			LocalUserName = localUser.userProfile.name;
		}

		public override void GetAvatar(PlatformID userID, GameObject requestSender, Texture2D tex, AvatarSize size, Action<Texture2D> onRecieved)
		{
			ulong result = 0uL;
			ProductUserId productUserID = userID.productUserID;
			if (UserIDsToAccountInfo.ContainsKey(productUserID) && ulong.TryParse(UserIDsToAccountInfo[productUserID].AccountId, out result))
			{
				SteamUserManager.GetSteamAvatar(new PlatformID(result), requestSender, tex, size, onRecieved);
			}
		}

		public override string GetUserName()
		{
			LocalUser localUser = LocalUserManager.FindLocalUser(0);
			if (localUser != null)
			{
				return localUser.userProfile.name;
			}
			return LocalUserName;
		}

		public override int GetUserID()
		{
			return -1;
		}

		public void QueryForDisplayNames(PlatformID[] ids, Action callback = null)
		{
			if (ids != null)
			{
				QueryForDisplayNames(ids.Select((PlatformID x) => x.productUserID).ToArray(), callback);
			}
		}

		public void QueryForDisplayNames(ProductUserId productId, Action callback = null)
		{
			QueryForDisplayNames(new ProductUserId[1] { productId }, callback);
		}

		public void QueryForDisplayNames(ProductUserId[] productIds, Action callback = null)
		{
			QueryProductUserIdMappingsOptions queryProductUserIdMappingsOptions = default(QueryProductUserIdMappingsOptions);
			queryProductUserIdMappingsOptions.LocalUserId = EOSLoginManager.loggedInProductId;
			queryProductUserIdMappingsOptions.ProductUserIds = productIds;
			QueryProductUserIdMappingsOptions options = queryProductUserIdMappingsOptions;
			IDQueryList.AddRange(productIds);
			IDQueryList = IDQueryList.Distinct().ToList();
			EOSPlatformManager.GetPlatformInterface().GetConnectInterface().QueryProductUserIdMappings(ref options, productIds, delegate(ref QueryProductUserIdMappingsCallbackInfo data)
			{
				OnQueryProductUserIdMappingsComplete(data);
				callback?.Invoke();
			});
		}

		private bool GetUserNameFromExternalAccountType(ProductUserId id, uint index, out ExternalAccountInfo accountInfo)
		{
			accountInfo = default(ExternalAccountInfo);
			CopyProductUserExternalAccountByIndexOptions copyProductUserExternalAccountByIndexOptions = default(CopyProductUserExternalAccountByIndexOptions);
			copyProductUserExternalAccountByIndexOptions.TargetUserId = id;
			copyProductUserExternalAccountByIndexOptions.ExternalAccountInfoIndex = index;
			CopyProductUserExternalAccountByIndexOptions options = copyProductUserExternalAccountByIndexOptions;
			if (EOSPlatformManager.GetPlatformInterface().GetConnectInterface().CopyProductUserExternalAccountByIndex(ref options, out var outExternalAccountInfo) == Result.Success)
			{
				accountInfo = outExternalAccountInfo.Value;
				return true;
			}
			return false;
		}

		private void OnQueryProductUserIdMappingsComplete(QueryProductUserIdMappingsCallbackInfo data)
		{
			if (data.GetResultCode() != Result.Success)
			{
				return;
			}
			List<ProductUserId> list = new List<ProductUserId>(IDQueryList);
			foreach (ProductUserId iDQuery in IDQueryList)
			{
				if (GetUserNameFromExternalAccountType(iDQuery, 1u, out var accountInfo))
				{
					UserIDsToAccountInfo[iDQuery] = accountInfo;
					list.Remove(iDQuery);
				}
				else if (GetUserNameFromExternalAccountType(iDQuery, 0u, out accountInfo))
				{
					UserIDsToAccountInfo[iDQuery] = accountInfo;
					list.Remove(iDQuery);
				}
			}
			IDQueryList = list;
			if (IDQueryList.Count == 0)
			{
				InvokeDisplayMappingCompleteAction();
			}
		}

		public override string GetUserDisplayName(PlatformID other)
		{
			return GetUserDisplayName(other, null);
		}

		public string GetUserDisplayName(PlatformID other, Action callback)
		{
			if (UserIDsToAccountInfo.ContainsKey(other.productUserID))
			{
				return UserIDsToAccountInfo[other.productUserID].DisplayName;
			}
			if (!string.IsNullOrEmpty(other.productUserID.ToString()))
			{
				QueryForDisplayNames(new PlatformID[1] { other }, callback);
			}
			return string.Empty;
		}

		private void TryGetLogin(EpicAccountId obj)
		{
			UserInfoInterface userInfoInterface = EOSPlatformManager.GetPlatformInterface().GetUserInfoInterface();
			if (userInfoInterface != null && EOSLoginManager.loggedInAuthId != null)
			{
				QueryUserInfoOptions queryUserInfoOptions = default(QueryUserInfoOptions);
				queryUserInfoOptions.LocalUserId = obj;
				queryUserInfoOptions.TargetUserId = obj;
				QueryUserInfoOptions options = queryUserInfoOptions;
				userInfoInterface.QueryUserInfo(ref options, null, OnQueryUserInfo);
			}
		}

		private void OnQueryUserInfo(ref QueryUserInfoCallbackInfo data)
		{
			if (data.ResultCode == Result.Success)
			{
				UserInfoInterface userInfoInterface = EOSPlatformManager.GetPlatformInterface().GetUserInfoInterface();
				if (userInfoInterface != null)
				{
					CopyUserInfoOptions copyUserInfoOptions = default(CopyUserInfoOptions);
					copyUserInfoOptions.LocalUserId = EOSLoginManager.loggedInAuthId;
					copyUserInfoOptions.TargetUserId = EOSLoginManager.loggedInAuthId;
					CopyUserInfoOptions options = copyUserInfoOptions;
					userInfoInterface.CopyUserInfo(ref options, out var outUserInfo);
					LocalUserName = outUserInfo.Value.DisplayName;
				}
			}
		}
	}
	public enum LobbyType
	{
		Private,
		FriendsOnly,
		Public,
		Invisible,
		Error
	}
	[Flags]
	public enum MPFeatures
	{
		None = 0,
		HostGame = 1,
		FindGame = 2,
		Quickplay = 4,
		PrivateGame = 8,
		Invite = 0x10,
		JoinViaID = 0x20,
		EnterGameButton = 0x40,
		AdHoc = 0x80,
		FindFriendSession = 0x100,
		All = -1
	}
	[Flags]
	public enum MPLobbyFeatures
	{
		None = 0,
		CreateLobby = 1,
		SocialIcon = 2,
		HostPromotion = 4,
		Clipboard = 8,
		Invite = 0x10,
		UserIcon = 0x20,
		LeaveLobby = 0x40,
		LobbyDropdownOptions = 0x80,
		Voice = 0x100,
		All = -1
	}
	public abstract class LobbyManager
	{
		public enum State
		{
			Idle,
			Hosting,
			Waiting
		}

		public enum LobbyMessageType : byte
		{
			Chat,
			Password
		}

		public class LobbyDataSetupState
		{
			public int totalMaxPlayers;

			public int totalPlayerCount;

			public bool quickplayQueued;

			public PlatformID lobbyId;

			public PlatformID serverId;

			public AddressPortPair serverAddressPortPair;

			public bool starting;

			public string buildId = "0";

			public DateTime? quickplayCutoffTime;

			public bool shouldConnect;

			public bool joinable;
		}

		public class LobbyData
		{
			public readonly int totalMaxPlayers;

			public readonly int totalPlayerCount;

			public readonly bool quickplayQueued;

			public readonly PlatformID lobbyId = PlatformID.nil;

			public readonly PlatformID serverId = PlatformID.nil;

			public readonly AddressPortPair serverAddressPortPair;

			public readonly bool starting;

			public readonly string buildId = "0";

			public readonly DateTime? quickplayCutoffTime;

			public readonly bool shouldConnect;

			public readonly bool joinable;

			public LobbyData(LobbyDataSetupState setupState)
			{
				totalMaxPlayers = setupState.totalMaxPlayers;
				totalPlayerCount = setupState.totalPlayerCount;
				quickplayQueued = setupState.quickplayQueued;
				lobbyId = setupState.lobbyId;
				serverId = setupState.serverId;
				serverAddressPortPair = setupState.serverAddressPortPair;
				starting = setupState.starting;
				buildId = setupState.buildId;
				quickplayCutoffTime = setupState.quickplayCutoffTime;
				shouldConnect = setupState.shouldConnect;
				joinable = setupState.joinable;
			}

			public LobbyData()
			{
			}

			public static bool TryParseUserID(string str, out PlatformID result)
			{
				if (PlatformID.TryParse(str, out var result2))
				{
					result = result2;
					return true;
				}
				result = PlatformID.nil;
				return false;
			}

			public LobbyData(Lobby lobby)
			{
				PlatformID platformID = new PlatformID(lobby.CurrentLobby);
				Lobby.LobbyData currentLobbyData = lobby.CurrentLobbyData;
				Dictionary<string, string> lobbyDataDictionary = currentLobbyData.GetAllData();
				lobbyId = platformID;
				ReadCSteamID("server_id", ref serverId);
				ReadAddressPortPair("server_address", ref serverAddressPortPair);
				ReadInt("total_max_players", ref totalMaxPlayers);
				ReadInt("player_count", ref totalPlayerCount);
				ReadBool("qp", ref quickplayQueued);
				ReadBool("starting", ref starting);
				ReadString("build_id", ref buildId);
				ReadNullableDate("qp_cutoff_time", out quickplayCutoffTime);
				joinable = true;
				joinable &= totalPlayerCount < totalMaxPlayers;
				joinable &= lobby.LobbyType == Lobby.Type.Public;
				shouldConnect = serverId.isValid || serverAddressPortPair.isValid;
				bool ReadAddressPortPair(string metaDataName, ref AddressPortPair field)
				{
					if (lobbyDataDictionary.TryGetValue(metaDataName, out var value5) && AddressPortPair.TryParse(value5, out var addressPortPair))
					{
						field = addressPortPair;
						return true;
					}
					return false;
				}
				bool ReadBool(string metaDataName, ref bool field)
				{
					if (lobbyDataDictionary.TryGetValue(metaDataName, out var value3) && TextSerialization.TryParseInvariant(value3, out int result2))
					{
						field = result2 != 0;
						return true;
					}
					return false;
				}
				bool ReadCSteamID(string metaDataName, ref PlatformID field)
				{
					if (lobbyDataDictionary.TryGetValue(metaDataName, out var value6) && TryParseUserID(value6, out var result4))
					{
						field = result4;
						return true;
					}
					return false;
				}
				bool ReadInt(string metaDataName, ref int field)
				{
					if (lobbyDataDictionary.TryGetValue(metaDataName, out var value4) && TextSerialization.TryParseInvariant(value4, out int result3))
					{
						field = result3;
						return true;
					}
					return false;
				}
				bool ReadNullableDate(string metaDataName, out DateTime? field)
				{
					if (lobbyDataDictionary.TryGetValue(metaDataName, out var value) && TextSerialization.TryParseInvariant(value, out uint result))
					{
						field = Util.dateZero + TimeSpan.FromSeconds(result);
						return true;
					}
					field = null;
					return false;
				}
				bool ReadString(string metaDataName, ref string field)
				{
					if (lobbyDataDictionary.TryGetValue(metaDataName, out var value2))
					{
						field = value2;
						return true;
					}
					return false;
				}
			}
		}

		public State state;

		public LobbyType preferredLobbyType;

		public Action onPlayerCountUpdated;

		public Action<bool> onLobbyJoined;

		public Action onLobbiesUpdated;

		public Action onLobbyOwnershipGained;

		public Action onLobbyOwnershipLost;

		public Action onLobbyChanged;

		public Action onLobbyDataUpdated;

		public Action<PlatformID> onLobbyLeave;

		public Action<PlatformID> onLobbyMemberDataUpdated;

		public Action onLobbyStateChanged;

		private bool shouldShowGenericSpinner;

		public static readonly IntConVar cvSteamLobbyMaxMembers = new IntConVar("steam_lobby_max_members", ConVarFlags.None, RoR2Application.maxPlayers.ToString(CultureInfo.InvariantCulture), "Sets the maximum number of players allowed in steam lobbies created by this machine.");

		public const float QuickplayWaitTimeInSeconds = 20f;

		public abstract int calculatedTotalPlayerCount { get; protected set; }

		public abstract int calculatedExtraPlayersCount { get; protected set; }

		public abstract bool isInLobby { get; protected set; }

		public abstract bool ownsLobby { get; protected set; }

		public abstract bool IsBusy { get; set; }

		public bool awaitingJoin { get; protected set; }

		public bool awaitingCreate { get; protected set; }

		public bool isFull { get; protected set; }

		public abstract bool hasMinimumPlayerCount { get; }

		public abstract LobbyType currentLobbyType { get; set; }

		public abstract LobbyData newestLobbyData { get; protected set; }

		public abstract MPFeatures GetPlatformMPFeatureFlags();

		public abstract MPLobbyFeatures GetPlatformMPLobbyFeatureFlags();

		public bool HasMPFeatures()
		{
			return GetPlatformMPFeatureFlags() != MPFeatures.None;
		}

		public bool HasMPLobbyUI()
		{
			return GetPlatformMPLobbyFeatureFlags() != MPLobbyFeatures.None;
		}

		public bool HasMPFeature(MPFeatures flags)
		{
			return GetPlatformMPFeatureFlags().HasFlag(flags);
		}

		public bool HasMPLobbyFeature(MPLobbyFeatures flags)
		{
			return GetPlatformMPLobbyFeatureFlags().HasFlag(flags);
		}

		public abstract int GetLobbyMemberPlayerCountByIndex(int memberIndex);

		public abstract void CreateLobby();

		public abstract string GetLobbyID();

		public virtual void SetNetworkType(bool isInternet)
		{
		}

		public virtual bool IsNetworkTypeInternet()
		{
			return true;
		}

		public virtual void Shutdown()
		{
		}

		public abstract void LeaveLobby();

		public abstract void JoinLobby(PlatformID join);

		public abstract void OnStartPrivateGame();

		public virtual void OnMultiplayerMenuEnabled(Action<PlatformID> onLobbyLeave)
		{
			if (!PlatformSystems.lobbyManager.isInLobby)
			{
				PlatformSystems.lobbyManager.CreateLobby();
			}
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyLeave = (Action<PlatformID>)Delegate.Combine(lobbyManager.onLobbyLeave, onLobbyLeave);
		}

		public abstract void AutoMatchmake();

		public abstract void ToggleQuickplay();

		public abstract void OnCutoffTimerComplete();

		public abstract bool ShouldEnableQuickplayButton();

		public virtual bool IsQuickPlaySearching()
		{
			return false;
		}

		public abstract bool IsLobbyOwner(PlatformID user);

		public abstract string GetUserDisplayName(PlatformID user);

		public abstract bool IsLobbyOwner();

		public abstract PlatformID[] GetLobbyMembers();

		public abstract int GetLobbyMemberCount();

		public abstract bool ShouldShowPromoteButton();

		public abstract void CheckIfInitializedAndValid();

		public abstract void CheckIfInvited();

		public abstract bool CanInvite();

		public abstract void CheckBusyTimer();

		public abstract bool ShouldEnableStartPrivateGameButton();

		public virtual void OpenInviteOverlay()
		{
			throw new NotImplementedException();
		}

		public virtual void OpenFriendSessionBrowser()
		{
			throw new NotImplementedException();
		}

		internal virtual bool ShouldEnableEnterGameButton()
		{
			return false;
		}

		internal virtual bool ShouldEnableFindFriendSessionButton()
		{
			return false;
		}

		public virtual bool ShouldShowSpinner()
		{
			return IsQuickPlaySearching();
		}

		public bool ShouldShowGenericSpinner()
		{
			return shouldShowGenericSpinner;
		}

		public void SetShouldShowGenericSpinner(bool shouldShow)
		{
			shouldShowGenericSpinner = shouldShow;
		}

		public virtual bool ShouldEnableInviteButton()
		{
			return CanInvite();
		}

		internal virtual void EnterGameButtonPressed()
		{
		}
	}
	public struct PlatformID : IEquatable<PlatformID>
	{
		public enum EAccountType
		{
			k_EAccountTypeInvalid,
			k_EAccountTypeIndividual,
			k_EAccountTypeMultiseat,
			k_EAccountTypeGameServer,
			k_EAccountTypeAnonGameServer,
			k_EAccountTypePending,
			k_EAccountTypeContentServer,
			k_EAccountTypeClan,
			k_EAccountTypeChat,
			k_EAccountTypeConsoleUser,
			k_EAccountTypeAnonUser,
			k_EAccountTypeMax
		}

		public enum EUniverse
		{
			k_EUniverseInvalid,
			k_EUniversePublic,
			k_EUniverseBeta,
			k_EUniverseInternal,
			k_EUniverseDev,
			k_EUniverseMax
		}

		public ulong ID;

		public ulong ID2;

		public string stringID;

		public static readonly PlatformID nil = new PlatformID(0uL, string.Empty);

		public object value
		{
			get
			{
				if (ID != 0L)
				{
					return ID;
				}
				if (stringID != string.Empty)
				{
					return stringID;
				}
				return null;
			}
		}

		public bool isValid => isSteam ^ isEGS;

		public bool isSteam => ID != 0;

		public bool isEGS => !string.IsNullOrEmpty(stringID);

		public ProductUserId productUserID => ProductUserId.FromString(stringID);

		public uint accountId => GetBitField(0, 32);

		public uint accountInstance => GetBitField(32, 20);

		public EAccountType accountType => (EAccountType)GetBitField(52, 4);

		public EUniverse universe => (EUniverse)GetBitField(56, 8);

		public bool isLobby => accountType == EAccountType.k_EAccountTypeChat;

		public PlatformID(ulong id)
		{
			ID = id;
			ID2 = ID;
			stringID = string.Empty;
		}

		public PlatformID(string stringid)
		{
			ID = 0uL;
			ID2 = ID;
			stringID = stringid;
		}

		public PlatformID(ulong id, string stringid)
		{
			ID = id;
			ID2 = ID;
			stringID = stringid;
		}

		public static explicit operator PlatformID(ulong id)
		{
			return new PlatformID(id);
		}

		public static bool operator ==(PlatformID first, PlatformID second)
		{
			return first.Compare(second);
		}

		public static bool operator !=(PlatformID first, PlatformID second)
		{
			return !first.Compare(second);
		}

		public static bool operator ==(PlatformID first, ulong second)
		{
			return first.ID == second;
		}

		public static bool operator !=(PlatformID first, ulong second)
		{
			return first.ID != second;
		}

		public override string ToString()
		{
			if (value == null)
			{
				return "";
			}
			return value.ToString();
		}

		public bool IsDefault()
		{
			return ID == 0;
		}

		public bool Equals(PlatformID other)
		{
			return Compare(other);
		}

		public bool Compare(PlatformID other)
		{
			if (value is ulong)
			{
				if (other.value is ulong)
				{
					return (ulong)value == (ulong)other.value;
				}
				return false;
			}
			if (value is string)
			{
				if (other.value is string)
				{
					return (string)value == (string)other.value;
				}
				return false;
			}
			if (value == null)
			{
				return other.value == null;
			}
			return false;
		}

		public override int GetHashCode()
		{
			if (value != null)
			{
				return value.GetHashCode();
			}
			return 0;
		}

		public PlatformID(ProductUserId id)
		{
			stringID = id.ToString();
			ID = 0uL;
			ID2 = 0uL;
		}

		public static bool TryParse(string str, out PlatformID result)
		{
			if (!string.IsNullOrEmpty(str))
			{
				return ParseFromString(str, out result);
			}
			result = nil;
			return false;
		}

		private static bool ParseFromString(string str, out PlatformID result)
		{
			if (str[0] <= '9')
			{
				ulong result2;
				bool flag = TextSerialization.TryParseInvariant(str, out result2);
				if (flag)
				{
					result = new PlatformID(flag ? result2 : 0);
					return flag;
				}
			}
			if (PlatformSystems.EgsToggleConVar.value == 1 && str.Length <= 32)
			{
				ProductUserId productUserId = ProductUserId.FromString(str);
				if (productUserId != null)
				{
					result = new PlatformID(productUserId);
					return true;
				}
			}
			result = default(PlatformID);
			return false;
		}

		private uint GetBitField(int bitOffset, int bitCount)
		{
			uint num = uint.MaxValue >> 32 - bitCount;
			return (uint)(int)(ID >> bitOffset) & num;
		}

		public string ToSteamID()
		{
			uint num = accountId;
			return string.Format(CultureInfo.InvariantCulture, "STEAM_{0}:{1}:{2}", (uint)universe, num & 1u, num >> 1);
		}

		public string ToCommunityID()
		{
			char c = 'I';
			switch (accountType)
			{
			case EAccountType.k_EAccountTypeInvalid:
				c = 'I';
				break;
			case EAccountType.k_EAccountTypeIndividual:
				c = 'U';
				break;
			case EAccountType.k_EAccountTypeMultiseat:
				c = 'M';
				break;
			case EAccountType.k_EAccountTypeGameServer:
				c = 'G';
				break;
			case EAccountType.k_EAccountTypeAnonGameServer:
				c = 'A';
				break;
			case EAccountType.k_EAccountTypePending:
				c = 'P';
				break;
			case EAccountType.k_EAccountTypeContentServer:
				c = 'C';
				break;
			case EAccountType.k_EAccountTypeClan:
				c = 'g';
				break;
			case EAccountType.k_EAccountTypeChat:
				c = 'T';
				break;
			case EAccountType.k_EAccountTypeConsoleUser:
				c = 'I';
				break;
			case EAccountType.k_EAccountTypeAnonUser:
				c = 'a';
				break;
			case EAccountType.k_EAccountTypeMax:
				c = 'I';
				break;
			}
			return string.Format(CultureInfo.InvariantCulture, "[{0}:{1}:{2}]", c, 1, accountId);
		}
	}
	public class PlatformManager
	{
		public static Guid DefaultControllerGuid => PlatformSystems.platformManager.GetDefaultControllerGuid();

		public static string DefaultControllerName => PlatformSystems.platformManager.GetDefaultControllerName();

		public static event Action initializeFinished;

		public PlatformManager()
		{
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(InitializePlatformManager));
		}

		public virtual void InitializePlatformManager()
		{
			RoR2Application.onUpdate += UpdatePlatformManager;
		}

		protected virtual void UpdatePlatformManager()
		{
		}

		internal static void OnInitialized()
		{
			PlatformManager.initializeFinished?.Invoke();
		}

		public virtual UnityEngine.Vector3 GetGyroAimDeltaVector()
		{
			return UnityEngine.Vector3.zero;
		}

		public virtual bool IsNetworkAvailable()
		{
			return true;
		}

		[ConCommand(commandName = "PlatformStore_ShowItem", flags = ConVarFlags.None, helpText = "Shows the platform store page for a single Entitlement/DLC")]
		public static void CCPlatformStoreShowItem(ConCommandArgs args)
		{
			int argInt = args.GetArgInt(0);
			if (argInt < EntitlementCatalog.entitlementDefs.Length)
			{
				PlatformSystems.entitlementsSystem.LaunchPlatformShop(EntitlementCatalog.entitlementDefs[argInt]);
			}
		}

		[ConCommand(commandName = "PlatformStore_ShowAll", flags = ConVarFlags.None, helpText = "Shows the platform store page for all purchasable items")]
		public static void CCPlatformStoreShowAll(ConCommandArgs args)
		{
			PlatformSystems.entitlementsSystem.LaunchPlatformShopAllProducts();
		}

		internal virtual Guid GetDefaultControllerGuid()
		{
			return DefaultControllerMaps.gamepadTemplateGuid;
		}

		internal virtual string GetDefaultControllerName()
		{
			return "Default Controller";
		}
	}
	public static class PlatformSystems
	{
		public static SaveSystem saveSystem;

		public static UserManager userManager;

		public static AchievementSystem achievementSystem;

		public static LobbyManager lobbyManager;

		public static TextDataManager textDataManager;

		public static PlatformManager platformManager;

		public static NetworkManagerSystem networkManager;

		public static ActivityManager activityManager;

		public static IUserEntitementsResolverNetworkAndLocal entitlementsSystem;

		public static object statManager;

		public static object friendsManager;

		public static bool crossPlayEnabledOnStartup = false;

		public static bool useNGSS = true;

		public static string[] platformStrings = new string[0];

		public static PlayerPrefsIntConVar EgsToggleConVar = new PlayerPrefsIntConVar("egsToggle", ConVarFlags.Engine, "0", "If EGS is used. If false, use Steam.");

		public const float loadOperationsStartedWeight = 0.25f;

		public const float loadCompleteProgressWeight = 0.75f;

		public static bool ShouldUseEpicOnlineSystems
		{
			get
			{
				return crossPlayEnabledOnStartup;
			}
			set
			{
			}
		}

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
		public static void InitDataAfterAssembliesLoaded()
		{
		}

		public static void Init()
		{
			platformStrings = new string[2] { "steam", "pc" };
			SteamworksClientManager.Init();
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			if (commandLineArgs.Contains("--disableCrossplay"))
			{
				EgsToggleConVar.value = 0;
			}
			else if (commandLineArgs.Contains("--enableCrossplay"))
			{
				EgsToggleConVar.value = 1;
			}
			if (EgsToggleConVar.value == 1)
			{
				try
				{
					crossPlayEnabledOnStartup = true;
					platformManager = new EOSPlatformManager();
					userManager = new UserManagerEOS();
					(userManager as UserManagerEOS).InitializeUserManager();
					textDataManager = new StreamingAssetsTextDataManager();
					lobbyManager = new EOSLobbyManager();
					(lobbyManager as EOSLobbyManager).Init();
					new EOSLoginManager().TryLogin();
				}
				catch
				{
					EgsToggleConVar.value = 0;
					Application.Quit();
				}
			}
			else
			{
				lobbyManager = new SteamworksLobbyManager();
				userManager = new SteamUserManager();
				(userManager as SteamUserManager)?.InitializeUserManager();
				textDataManager = new StreamingAssetsTextDataManager();
			}
			SteamworksRichPresenceManager.Init();
			saveSystem = new SaveSystemSteam();
			achievementSystem = new AchievementSystemSteam();
			entitlementsSystem = new SteamworksEntitlementResolver();
			activityManager = new ActivityManager();
			if (platformManager == null)
			{
				platformManager = new PlatformManager();
			}
			activityManager.Initialize();
			saveSystem.InitializeSaveSystem();
			UserProfile.GenerateSaveFieldFunctions();
			RoR2Application.onUpdate += saveSystem.StaticUpdate;
			if (entitlementsSystem != null)
			{
				EntitlementManager.collectLocalUserEntitlementResolvers += delegate(Action<IUserEntitlementResolver<LocalUser>> add)
				{
					add(entitlementsSystem);
				};
				EntitlementManager.collectNetworkUserEntitlementResolvers += delegate(Action<IUserEntitlementResolver<NetworkUser>> add)
				{
					add(entitlementsSystem);
				};
			}
			RoR2Application.onShutDown = (Action)Delegate.Combine(RoR2Application.onShutDown, new Action(Shutdown));
		}

		private static void Shutdown()
		{
			saveSystem.Shutdown();
			lobbyManager.Shutdown();
		}

		private static T BuildMonoSingleton<T>() where T : MonoBehaviour
		{
			GameObject gameObject = new GameObject("T");
			T result = gameObject.AddComponent<T>();
			UnityEngine.Object.DontDestroyOnLoad(gameObject);
			return result;
		}

		public static void InitNetworkManagerSystem(GameObject networkManagerPrefabObject)
		{
			if (!(networkManagerPrefabObject.GetComponent<NetworkManagerSystem>() != null))
			{
				if (EgsToggleConVar.value == 1)
				{
					networkManager = networkManagerPrefabObject.AddComponent<NetworkManagerSystemEOS>();
				}
				else
				{
					networkManager = networkManagerPrefabObject.AddComponent<NetworkManagerSystemSteam>();
				}
				NetworkManagerConfiguration component = networkManagerPrefabObject.GetComponent<NetworkManagerConfiguration>();
				if (component == null || networkManager == null)
				{
					UnityEngine.Debug.LogError("Missing NetworkManagerConfiguration on NetworkManagerPrefab or platform NetworkManagerSystem not found");
				}
				else
				{
					networkManager.Init(component);
				}
			}
		}

		public static void InitPlatformManagerObject(GameObject platformManagerPrefabObject)
		{
		}

		public static GameObject GetPlatformVoiceManagerObject()
		{
			return null;
		}

		public static void setupRewired(GameObject rewiredObj)
		{
		}

		public static void SetLoadingPriority(UnityEngine.ThreadPriority newPriority)
		{
			Application.backgroundLoadingPriority = newPriority;
		}
	}
	public class FileOutput
	{
		public FileReference fileReference;

		public DateTime requestTime;

		public byte[] contents;
	}
	public struct FileReference : IEquatable<FileReference>
	{
		public IFileSystem fileSystem;

		public UPath path;

		public bool Equals(FileReference other)
		{
			if (fileSystem == other.fileSystem || fileSystem.Equals(other.fileSystem))
			{
				return path.Equals(other.path);
			}
			return false;
		}

		public override bool Equals(object other)
		{
			if (other is FileReference)
			{
				return Equals((FileReference)other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (-990633296 * -1521134295 + EqualityComparer<IFileSystem>.Default.GetHashCode(fileSystem)) * -1521134295 + EqualityComparer<UPath>.Default.GetHashCode(path);
		}
	}
	public struct LoadUserProfileOperationResult
	{
		public string fileName;

		public long fileLength;

		public UserProfile userProfile;

		public Exception exception;

		public string failureContents;
	}
	public abstract class SaveSystemBase
	{
		protected abstract void ProcessFileOutputQueue();

		protected abstract void StartSave(UserProfile userProfile, bool blocking);

		protected abstract LoadUserProfileOperationResult LoadUserProfileFromDisk(IFileSystem fileSystem, UPath path);

		public abstract void LoadUserProfiles();

		public abstract UserProfile LoadPrimaryProfile();

		public abstract string GetPlatformUsernameOrDefault(string defaultName);

		public abstract void LoadInitialData();
	}
	public abstract class SaveSystem : SaveSystemBase
	{
		public bool isXmlReady;

		public bool isInitialLoadFinished;

		public MemoryStream configData;

		public UserProfile userProfile;

		protected readonly Dictionary<FileReference, DateTime> latestWrittenRequestTimesByFile = new Dictionary<FileReference, DateTime>();

		public readonly Dictionary<string, UserProfile> loadedUserProfiles = new Dictionary<string, UserProfile>(StringComparer.OrdinalIgnoreCase);

		public readonly List<LoadUserProfileOperationResult> badFileResults = new List<LoadUserProfileOperationResult>();

		public readonly List<UserProfile> loggedInProfiles = new List<UserProfile>();

		private static float secondAccumulator;

		private const string userProfilesFolder = "/UserProfiles";

		protected readonly Queue<FileOutput> pendingOutputQueue = new Queue<FileOutput>();

		private readonly List<Task> activeTasks = new List<Task>();

		public bool doesInitialDataExist
		{
			get
			{
				if (configData != null)
				{
					return userProfile != null;
				}
				return false;
			}
		}

		public static event Action onAvailableUserProfilesChanged;

		public static void SkipBOM(Stream stream)
		{
			long position = stream.Position;
			if (stream.Length - position < 3)
			{
				return;
			}
			int num = stream.ReadByte();
			int num2 = stream.ReadByte();
			if (num != 255 || num2 != 254)
			{
				int num3 = stream.ReadByte();
				if (num != 239 || num2 != 187 || num3 != 191)
				{
					stream.Position = position;
				}
			}
		}

		public virtual void InitializeSaveSystem()
		{
		}

		public override void LoadInitialData()
		{
		}

		protected bool CanWrite(FileOutput fileOutput)
		{
			if (fileOutput.contents.Length == 0)
			{
				UnityEngine.Debug.LogErrorFormat("Cannot write UserProfile \"{0}\" with zero-length contents. This would erase the file.");
				return false;
			}
			if (latestWrittenRequestTimesByFile.TryGetValue(fileOutput.fileReference, out var value))
			{
				return value < fileOutput.requestTime;
			}
			return true;
		}

		protected UserProfile AttemptToRecoverUserData(string profileXML)
		{
			string value = "<a";
			string value2 = "<c";
			int num = profileXML.IndexOf(value);
			int num2 = profileXML.IndexOf(value2);
			string[] array = null;
			string text = null;
			if (num != -1 && num + 1 < profileXML.Length)
			{
				int num3 = profileXML.IndexOf("<", num + 1);
				int num4 = profileXML.IndexOf(">", num);
				if (num4 != -1)
				{
					num3 = ((num3 != -1) ? (num3 - 1) : (profileXML.Length - 1));
					string text2 = profileXML.Substring(num4 + 1, num3 - num4);
					array = text2.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
					UnityEngine.Debug.LogError("Recovered achievements: " + text2);
				}
			}
			if (num2 != -1 && num2 + 1 < profileXML.Length)
			{
				int num5 = profileXML.IndexOf("<", num2 + 1);
				int num6 = profileXML.IndexOf(">", num2);
				if (num6 != -1)
				{
					num5 = ((num5 != -1) ? (num5 - 1) : (profileXML.Length - 1));
					text = profileXML.Substring(num6 + 1, num5 - num6);
					UnityEngine.Debug.LogError("Recovered coins: " + text);
				}
			}
			UserProfile userProfile = CreateGuestProfile();
			if (array != null && array.Length != 0)
			{
				string[] array2 = array;
				foreach (string achievementName in array2)
				{
					userProfile.AddAchievement(achievementName, isExternal: true);
				}
			}
			else
			{
				UnityEngine.Debug.LogError("XML didn't contain achievements!");
			}
			uint result = 0u;
			if (text != null && uint.TryParse(text, out result))
			{
				userProfile.coins = result;
			}
			else
			{
				UnityEngine.Debug.LogError("XML didn't contain coins!");
			}
			return userProfile;
		}

		protected void AddActiveTask(Task task)
		{
			lock (activeTasks)
			{
				activeTasks.Add(task);
			}
		}

		protected void RemoveActiveTask(Task task)
		{
			lock (activeTasks)
			{
				activeTasks.Remove(task);
			}
		}

		public void StaticUpdate()
		{
			secondAccumulator += Time.unscaledDeltaTime;
			if (secondAccumulator > 1f)
			{
				secondAccumulator -= 1f;
				foreach (UserProfile loggedInProfile in loggedInProfiles)
				{
					loggedInProfile.totalLoginSeconds++;
				}
			}
			foreach (UserProfile loggedInProfile2 in loggedInProfiles)
			{
				if (loggedInProfile2.saveRequestPending && Save(loggedInProfile2, blocking: false))
				{
					loggedInProfile2.saveRequestPending = false;
				}
			}
			ProcessFileOutputQueue();
		}

		public abstract void SaveHistory(byte[] data, string fileName);

		public abstract Dictionary<string, byte[]> LoadHistory();

		public void RequestSave(UserProfile profile, bool immediate = false)
		{
			if (profile.canSave)
			{
				if (immediate)
				{
					Save(profile, blocking: true);
				}
				else
				{
					profile.saveRequestPending = true;
				}
			}
		}

		public bool Save(UserProfile data, bool blocking)
		{
			try
			{
				StartSave(data, blocking);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public virtual void SaveData(byte[] inputData, string fileName)
		{
			UnityEngine.Debug.LogError("Child class method not implemented");
		}

		public void AddLoadedUserProfile(string name, UserProfile profile)
		{
			if (profile != null && !loadedUserProfiles.ContainsKey(name))
			{
				loadedUserProfiles.Add(name, profile);
			}
		}

		public void RemoveLoadedUserProfile(ulong saveId)
		{
			foreach (UserProfile value in loadedUserProfiles.Values)
			{
				if (value.saveID == saveId)
				{
					loadedUserProfiles.Remove(value.name);
					break;
				}
			}
		}

		public List<string> GetAvailableProfileNames()
		{
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, UserProfile> loadedUserProfile in loadedUserProfiles)
			{
				if (!loadedUserProfile.Value.isClaimed)
				{
					list.Add(loadedUserProfile.Key);
				}
			}
			list.Sort();
			return list;
		}

		public UserProfile GetProfile(string profileName)
		{
			profileName = profileName.ToLower(CultureInfo.InvariantCulture);
			if (loadedUserProfiles.TryGetValue(profileName, out var value))
			{
				return value;
			}
			return null;
		}

		public virtual UserProfile CreateProfile(IFileSystem fileSystem, string name, ulong platformUserID = 0uL)
		{
			UserProfile newProfile = UserProfile.FromXml(UserProfile.ToXml(UserProfile.defaultProfile));
			PlatformInitProfile(ref newProfile, fileSystem, name);
			newProfile.saveID = platformUserID;
			newProfile.isInUse = true;
			AddLoadedUserProfile(newProfile.name, newProfile);
			Save(newProfile, blocking: true);
			SaveSystem.onAvailableUserProfilesChanged?.Invoke();
			return newProfile;
		}

		protected virtual void PlatformInitProfile(ref UserProfile newProfile, IFileSystem fileSystem, string name)
		{
			newProfile.fileName = Guid.NewGuid().ToString();
			newProfile.fileSystem = fileSystem;
			newProfile.filePath = "/UserProfiles/" + newProfile.fileName + ".xml";
			newProfile.name = name;
			newProfile.canSave = true;
		}

		public UserProfile CreateGuestProfile()
		{
			UserProfile userProfile = new UserProfile();
			Copy(UserProfile.defaultProfile, userProfile);
			userProfile.name = "Guest";
			return userProfile;
		}

		public override void LoadUserProfiles()
		{
			badFileResults.Clear();
			loadedUserProfiles.Clear();
			UserProfile.LoadDefaultProfile();
			FileSystem cloudStorage = RoR2Application.cloudStorage;
			if (cloudStorage != null)
			{
				if (!cloudStorage.DirectoryExists("/UserProfiles"))
				{
					cloudStorage.CreateDirectory("/UserProfiles");
				}
				foreach (UPath item2 in cloudStorage.EnumeratePaths("/UserProfiles"))
				{
					if (cloudStorage.FileExists(item2) && string.CompareOrdinal(item2.GetExtensionWithDot(), ".xml") == 0)
					{
						LoadUserProfileOperationResult item = LoadUserProfileFromDisk(cloudStorage, item2);
						UserProfile userProfile = item.userProfile;
						if (userProfile != null)
						{
							loadedUserProfiles[userProfile.fileName] = userProfile;
						}
						if (item.exception != null)
						{
							badFileResults.Add(item);
						}
					}
				}
				OutputBadFileResults();
				SaveSystem.onAvailableUserProfilesChanged?.Invoke();
			}
			else
			{
				UnityEngine.Debug.LogError("cloud storage is null");
			}
		}

		private void OutputBadFileResults()
		{
			if (badFileResults.Count == 0)
			{
				return;
			}
			try
			{
				using Stream stream = RoR2Application.fileSystem.CreateFile(new UPath("/bad_profiles.log"));
				using TextWriter textWriter = new StreamWriter(stream);
				foreach (LoadUserProfileOperationResult badFileResult in badFileResults)
				{
					textWriter.WriteLine("Failed to load file \"{0}\" ({1}B)", badFileResult.fileName, badFileResult.fileLength);
					textWriter.WriteLine("Exception: {0}", badFileResult.exception);
					textWriter.Write("Base64 Contents: ");
					textWriter.WriteLine(badFileResult.failureContents ?? string.Empty);
					textWriter.WriteLine(string.Empty);
				}
			}
			catch (Exception ex)
			{
				UnityEngine.Debug.LogFormat("Could not write bad UserProfile load log! Reason: {0}", ex.Message);
			}
		}

		public virtual void Shutdown()
		{
			foreach (UserProfile loggedInProfile in loggedInProfiles)
			{
				RequestSave(loggedInProfile, immediate: true);
			}
		}

		public virtual void SaveLoggedInUserProfiles()
		{
			foreach (UserProfile loggedInProfile in loggedInProfiles)
			{
				RequestSave(loggedInProfile);
			}
		}

		public static void Copy(UserProfile src, UserProfile dest)
		{
			dest.fileSystem = src.fileSystem;
			dest.filePath = src.filePath;
			StatSheet.Copy(src.statSheet, dest.statSheet);
			src.loadout.Copy(dest.loadout);
			dest.tutorialSprint = src.tutorialSprint;
			dest.tutorialDifficulty = src.tutorialDifficulty;
			dest.tutorialEquipment = src.tutorialEquipment;
			SaveFieldAttribute[] saveFields = UserProfile.saveFields;
			for (int i = 0; i < saveFields.Length; i++)
			{
				saveFields[i].copier(src, dest);
			}
			dest.isClaimed = false;
			dest.canSave = false;
			dest.fileName = src.fileName;
			dest.onPickupDiscovered = null;
			dest.onStatsReceived = null;
			dest.loggedIn = false;
		}

		protected void EnqueueFileOutput(FileOutput fileOutput)
		{
			lock (pendingOutputQueue)
			{
				pendingOutputQueue.Enqueue(fileOutput);
			}
		}

		private static bool ProfileNameIsReserved([NotNull] string profileName)
		{
			return string.Equals("default", profileName, StringComparison.OrdinalIgnoreCase);
		}

		[ConCommand(commandName = "user_profile_save", flags = ConVarFlags.None, helpText = "Saves the named profile to disk, if it exists.")]
		private static void CCUserProfileSave(ConCommandArgs args)
		{
			args.CheckArgumentCount(1);
			string text = args[0];
			if (ProfileNameIsReserved(text))
			{
				UnityEngine.Debug.LogFormat("Cannot save profile \"{0}\", it is a reserved profile.", text);
				return;
			}
			UserProfile profile = PlatformSystems.saveSystem.GetProfile(text);
			if (profile == null)
			{
				UnityEngine.Debug.LogFormat("Could not find profile \"{0}\" to save.", text);
			}
			else
			{
				profile.RequestEventualSave();
			}
		}

		[ConCommand(commandName = "user_profile_copy", flags = ConVarFlags.None, helpText = "Copies the profile named by the first argument to a new profile named by the second argument. This does not save the profile.")]
		private static void CCUserProfileCopy(ConCommandArgs args)
		{
			args.CheckArgumentCount(2);
			string text = args[0].ToLower(CultureInfo.InvariantCulture);
			string text2 = args[1].ToLower(CultureInfo.InvariantCulture);
			UserProfile profile = PlatformSystems.saveSystem.GetProfile(text);
			if (profile == null)
			{
				UnityEngine.Debug.LogFormat("Profile {0} does not exist, so it cannot be copied.", text);
				return;
			}
			if (PlatformSystems.saveSystem.GetProfile(text2) != null)
			{
				UnityEngine.Debug.LogFormat("Profile {0} already exists, and cannot be copied to.", text2);
				return;
			}
			UserProfile userProfile = new UserProfile();
			Copy(profile, userProfile);
			userProfile.fileSystem = profile.fileSystem ?? RoR2Application.cloudStorage;
			userProfile.filePath = "/UserProfiles/" + text2 + ".xml";
			userProfile.fileName = text2;
			userProfile.canSave = true;
			PlatformSystems.saveSystem.loadedUserProfiles[text2] = userProfile;
			SaveSystem.onAvailableUserProfilesChanged?.Invoke();
		}

		[ConCommand(commandName = "user_profile_delete", flags = ConVarFlags.None, helpText = "Unloads the named user profile and deletes it from the disk if it exists.")]
		private static void CCUserProfileDelete(ConCommandArgs args)
		{
			args.CheckArgumentCount(1);
			string text = args[0];
			if (ProfileNameIsReserved(text))
			{
				UnityEngine.Debug.LogFormat("Cannot delete profile \"{0}\", it is a reserved profile.", text);
			}
			else
			{
				DeleteUserProfile(text);
			}
		}

		private static void DeleteUserProfile(string fileName)
		{
			fileName = fileName.ToLower(CultureInfo.InvariantCulture);
			UserProfile profile = PlatformSystems.saveSystem.GetProfile(fileName);
			if (PlatformSystems.saveSystem.loadedUserProfiles.ContainsKey(fileName))
			{
				PlatformSystems.saveSystem.loadedUserProfiles.Remove(fileName);
			}
			if (profile != null && profile.fileSystem != null)
			{
				profile.fileSystem.DeleteFile(profile.filePath);
			}
			SaveSystem.onAvailableUserProfilesChanged?.Invoke();
		}

		[ConCommand(commandName = "create_corrupted_profiles", flags = ConVarFlags.None, helpText = "Creates corrupted user profiles.")]
		private static void CCCreateCorruptedProfiles(ConCommandArgs args)
		{
			FileSystem fileSystem = RoR2Application.cloudStorage;
			WriteFile("empty", "");
			WriteFile("truncated", "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<UserProfile>\r\n");
			WriteFile("multiroot", "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<UserProfile>\r\n</UserProfile>\r\n<UserProfile>\r\n</UserProfile>");
			WriteFile("outoforder", "<?xml version=\"1.0\" encodi=\"utf-8\"ng?>\r\n<Userrofile>\r\n<UserProfile>\r\n</UserProfileProfile>\r\n</UserP>");
			void WriteFile(string fileName, string contents)
			{
				using Stream stream = fileSystem.OpenFile("/UserProfiles/" + fileName + ".xml", FileMode.Create, FileAccess.Write);
				using (TextWriter textWriter = new StreamWriter(stream))
				{
					textWriter.Write(contents.ToCharArray());
					textWriter.Flush();
				}
				stream.Flush();
			}
		}

		[ConCommand(commandName = "userprofile_test_buffer_overflow", flags = ConVarFlags.None, helpText = "")]
		private static void CCUserProfileTestBufferOverflow(ConCommandArgs args)
		{
			args.CheckArgumentCount(1);
			int num = 128;
			_ = RoR2Application.cloudStorage;
			RemoteFile remoteFile = Client.Instance.RemoteStorage.OpenFile(args[0]);
			_ = remoteFile.SizeInBytes;
			FieldInfo field = remoteFile.GetType().GetField("_sizeInBytes", BindingFlags.Instance | BindingFlags.NonPublic);
			int num2 = (int)field.GetValue(remoteFile);
			field.SetValue(remoteFile, num2 + num);
			byte[] array = remoteFile.ReadAllBytes();
			byte[] array2 = new byte[num];
			for (int i = 0; i < num; i++)
			{
				array2[i] = array[num2 + i];
			}
			GUIUtility.systemCopyBuffer = Encoding.UTF8.GetString(array2);
			field.SetValue(remoteFile, num2);
		}
	}
	internal class TagManager
	{
		public Action<string> onTagsStringUpdated;

		public string tagsString { get; protected set; } = string.Empty;

	}
	internal class ServerManagerBase<T> : TagManager where T : ServerManagerBase<T>, IDisposable, new()
	{
		protected List<string> tags = new List<string>();

		protected RuleBook currentRuleBook = new RuleBook();

		protected KeyValueSplitter ruleBookKvHelper;

		protected KeyValueSplitter modListKvHelper;

		protected bool disposed;

		protected float playerUpdateTimer;

		protected float playerUpdateInterval = 5f;

		private static string versionGameDataString;

		protected const int k_cbMaxGameServerGameData = 2048;

		public static T instance { get; private set; }

		public event Action<T, List<string>> collectAdditionalTags;

		public static string GetVersionGameDataString()
		{
			return versionGameDataString ?? (versionGameDataString = "gameData=" + RoR2Application.GetBuildId());
		}

		protected void OnPreGameControllerSetRuleBookServerGlobal(PreGameController preGameController, RuleBook ruleBook)
		{
			UpdateServerRuleBook();
		}

		protected void OnServerRunSetRuleBookGlobal(Run run, RuleBook ruleBook)
		{
			UpdateServerRuleBook();
		}

		protected void UpdateServerRuleBook()
		{
			if ((bool)Run.instance)
			{
				SetServerRuleBook(Run.instance.ruleBook);
			}
			else if ((bool)PreGameController.instance)
			{
				SetServerRuleBook(PreGameController.instance.readOnlyRuleBook);
			}
			UpdateTags();
		}

		protected void SetServerRuleBook(RuleBook ruleBook)
		{
			currentRuleBook.Copy(ruleBook);
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			RuleBook.WriteBase64ToStringBuilder(ruleBook, stringBuilder);
			ruleBookKvHelper.SetValue(stringBuilder.ToString());
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}

		protected void UpdateTags()
		{
			tags.Clear();
			if (RoR2Application.isModded)
			{
				tags.Add("mod");
			}
			tags.Add(PreGameController.cvSvAllowRuleVoting.value ? "rv1" : "rv0");
			tags.Add(PreGameController.cvSvAllowMultiplayerPause.value ? "rmp1" : "rmp0");
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			stringBuilder.Append("a=");
			foreach (RuleDef child in RuleCatalog.artifactRuleCategory.children)
			{
				RuleChoiceDef ruleChoice = currentRuleBook.GetRuleChoice(child);
				if (ruleChoice.localName == "On")
				{
					int artifactIndex = (int)((ArtifactDef)ruleChoice.extraData).artifactIndex;
					char value = (char)(48 + artifactIndex);
					stringBuilder.Append(value);
				}
			}
			tags.Add(stringBuilder.ToString());
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			foreach (RuleChoiceDef choice in currentRuleBook.choices)
			{
				if (choice.serverTag != null)
				{
					tags.Add(choice.serverTag);
				}
			}
			this.collectAdditionalTags?.Invoke(instance, tags);
			tags.Add(NetworkManagerSystem.cvSvCustomTags.value);
			string value2 = string.Join(",", tags);
			if (!base.tagsString.Equals(value2, StringComparison.Ordinal))
			{
				base.tagsString = value2;
				TagsStringUpdated();
				onTagsStringUpdated?.Invoke(base.tagsString);
			}
		}

		protected virtual void TagsStringUpdated()
		{
		}

		public virtual void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				RoR2Application.onUpdate -= Update;
				Run.onServerRunSetRuleBookGlobal -= OnServerRunSetRuleBookGlobal;
				PreGameController.onPreGameControllerSetRuleBookServerGlobal -= OnPreGameControllerSetRuleBookServerGlobal;
			}
		}

		protected virtual void Update()
		{
			playerUpdateTimer -= Time.unscaledDeltaTime;
			if (playerUpdateTimer <= 0f)
			{
				playerUpdateTimer = playerUpdateInterval;
			}
		}

		public static void StartServer()
		{
			instance?.Dispose();
			instance = null;
			if (!NetworkServer.dontListen)
			{
				instance = new T();
				if (instance.disposed)
				{
					instance = null;
				}
			}
		}

		public static void StopServer()
		{
			instance?.Dispose();
			instance = null;
		}
	}
	public abstract class PCLobbyManager : LobbyManager
	{
		protected class SteamLobbyTypeConVar : BaseConVar
		{
			public static readonly SteamLobbyTypeConVar instance = new SteamLobbyTypeConVar("steam_lobby_type", ConVarFlags.Engine, null, "The type of the current Steamworks lobby. Cannot be set if not the owner of a lobby.");

			public SteamLobbyTypeConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				(PlatformSystems.lobbyManager as PCLobbyManager).SetLobbyTypeConVarString(newValue);
			}

			public override string GetString()
			{
				return (PlatformSystems.lobbyManager as PCLobbyManager).GetLobbyTypeConVarString();
			}

			public void GetEnumValueAbstract<T>(string str, ref T dest) where T : struct, Enum
			{
				if (Enum.TryParse<T>(str, out var result))
				{
					dest = result;
					return;
				}
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				stringBuilder.Append("Provided value \"").Append(str).Append("\"")
					.Append(" is not a recognized option. Recognized options: { ");
				bool flag = false;
				string[] names = Enum.GetNames(typeof(T));
				foreach (string value in names)
				{
					if (flag)
					{
						stringBuilder.Append(", ");
					}
					else
					{
						flag = true;
					}
					stringBuilder.Append("\"").Append(value).Append("\"");
				}
				stringBuilder.Append(" }");
				string message = stringBuilder.ToString();
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
				throw new ConCommandException(message);
			}
		}

		public abstract void SetLobbyTypeConVarString(string newValue);

		public abstract string GetLobbyTypeConVarString();

		public abstract void JoinLobby(ConCommandArgs lobbyID);

		public abstract void LobbyCreate(ConCommandArgs args);

		public abstract void LobbyCreateIfNone(ConCommandArgs args);

		public abstract void LobbyLeave(ConCommandArgs args);

		public abstract void LobbyAssignOwner(ConCommandArgs args);

		public abstract void LobbyInvite(ConCommandArgs args);

		public abstract void LobbyOpenInviteOverlay(ConCommandArgs args);

		public abstract void LobbyCopyToClipboard(ConCommandArgs args);

		public abstract void LobbyPrintData(ConCommandArgs args);

		public abstract void DisplayId(ConCommandArgs args);

		public abstract void DisplayLobbyId(ConCommandArgs args);

		public abstract void LobbyPrintMembers(ConCommandArgs args);

		public abstract void ClearLobbies(ConCommandArgs args);

		public abstract void LobbyUpdatePlayerCount(ConCommandArgs args);

		public abstract void LobbyForceUpdateData(ConCommandArgs args);

		public abstract void LobbyPrintList(ConCommandArgs args);

		public abstract bool CheckLobbyIdValidity(string lobbyID);

		public static void ShowEnableCrossPlayPopup(bool isLobbyCrossplay)
		{
			SimpleDialogBox dialogBox = SimpleDialogBox.Create();
			Action activateCrossplayAndRestartFunction = delegate
			{
				if ((bool)dialogBox)
				{
					ActivateCrossPlayAndRestart();
				}
			};
			dialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "EOS_CANNOT_JOIN_STEAM_LOBBY_HEADER",
				formatParams = Array.Empty<object>()
			};
			if (isLobbyCrossplay)
			{
				dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "EOS_INVALID_LOBBY_REQUIRES_CROSSPLAY_DESCRIPTION",
					formatParams = Array.Empty<object>()
				};
			}
			else
			{
				dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "EOS_INVALID_LOBBY_NO_CROSSPLAY_DESCRIPTION",
					formatParams = Array.Empty<object>()
				};
			}
			dialogBox.AddActionButton(delegate
			{
				activateCrossplayAndRestartFunction();
			}, "EOS_INVALID_LOBBY_CROSSPLAY_GO_TO_SETTINGS", true);
			dialogBox.AddCancelButton(CommonLanguageTokens.cancel);
			static void ActivateCrossPlayAndRestart()
			{
				MainMenuController.instance.SetDesiredMenuScreen(MainMenuController.instance.settingsMenuScreen);
			}
		}

		[ConCommand(commandName = "steam_lobby_join")]
		private static void CCSteamLobbyJoin(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).JoinLobby(args);
		}

		[ConCommand(commandName = "steam_lobby_create")]
		private static void CCSteamLobbyCreate(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyCreate(args);
		}

		[ConCommand(commandName = "steam_lobby_create_if_none")]
		private static void CCSteamLobbyCreateIfNone(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyCreateIfNone(args);
		}

		[ConCommand(commandName = "steam_lobby_leave")]
		private static void CCSteamLobbyLeave(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyLeave(args);
		}

		[ConCommand(commandName = "steam_lobby_assign_owner")]
		private static void CCSteamLobbyAssignOwner(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyAssignOwner(args);
		}

		[ConCommand(commandName = "steam_lobby_invite", flags = ConVarFlags.None, helpText = "Invites the player with the specified steam id to the current lobby.")]
		private static void CCSteamLobbyInvite(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyInvite(args);
		}

		[ConCommand(commandName = "steam_lobby_open_invite_overlay", flags = ConVarFlags.None, helpText = "Opens the steam overlay to the friend invite dialog.")]
		private static void CCSteamLobbyOpenInviteOverlay(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyOpenInviteOverlay(args);
		}

		[ConCommand(commandName = "lobby_open_invite_overlay", flags = ConVarFlags.None, helpText = "Opens the platform overlay to the friend invite dialog.")]
		private static void CCLobbyOpenInviteOverlay(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyOpenInviteOverlay(args);
		}

		[ConCommand(commandName = "steam_lobby_copy_to_clipboard", flags = ConVarFlags.None, helpText = "Copies the currently active lobby to the clipboard if applicable.")]
		private static void CCSteamLobbyCopyToClipboard(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyCopyToClipboard(args);
		}

		private static void CCSteamLobbyPrintData(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyPrintData(args);
		}

		[ConCommand(commandName = "steam_id", flags = ConVarFlags.None, helpText = "Displays your steam id.")]
		private static void CCSteamId(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).DisplayId(args);
		}

		[ConCommand(commandName = "steam_lobby_id", flags = ConVarFlags.None, helpText = "Displays the steam id of the current lobby.")]
		private static void CCSteamLobbyId(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).DisplayLobbyId(args);
		}

		[ConCommand(commandName = "steam_lobby_print_members", flags = ConVarFlags.None, helpText = "Displays the members current lobby.")]
		private static void CCSteamLobbyPrintMembers(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyPrintMembers(args);
		}

		[ConCommand(commandName = "steam_lobby_print_list", flags = ConVarFlags.None, helpText = "Displays a list of lobbies from the last search.")]
		private static void CCSteamLobbyPrintList(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyPrintList(args);
		}

		[ConCommand(commandName = "steam_lobby_update_player_count", flags = ConVarFlags.None, helpText = "Forces a refresh of the steam lobby player count.")]
		private static void CCSteamLobbyUpdatePlayerCount(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).LobbyUpdatePlayerCount(args);
		}

		[ConCommand(commandName = "dump_lobbies", flags = ConVarFlags.None, helpText = "")]
		private static void DumpLobbies(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as PCLobbyManager).ClearLobbies(args);
		}
	}
	public interface IUserEntitementsResolverNetworkAndLocal : IUserEntitlementResolver<NetworkUser>, IUserEntitlementResolver<LocalUser>, IPlatformShopLauncher
	{
		string[] BuildEntitlements();
	}
	public class AchievementSystemSteam : AchievementSystem
	{
		public override void AddAchievement(string achievementName)
		{
			Client.Instance.Achievements.Trigger(achievementName);
		}
	}
	public class SaveSystemSteam : SaveSystem
	{
		private new readonly Dictionary<FileReference, DateTime> latestWrittenRequestTimesByFile = new Dictionary<FileReference, DateTime>();

		public SaveSystemSteam()
		{
			isInitialLoadFinished = true;
		}

		protected override LoadUserProfileOperationResult LoadUserProfileFromDisk(IFileSystem fileSystem, UPath path)
		{
			UnityEngine.Debug.LogFormat("Attempting to load user profile {0}", path);
			LoadUserProfileOperationResult loadUserProfileOperationResult = default(LoadUserProfileOperationResult);
			loadUserProfileOperationResult.fileName = path.FullName;
			loadUserProfileOperationResult.fileLength = 0L;
			loadUserProfileOperationResult.userProfile = null;
			loadUserProfileOperationResult.exception = null;
			loadUserProfileOperationResult.failureContents = null;
			LoadUserProfileOperationResult result = loadUserProfileOperationResult;
			try
			{
				using Stream stream = fileSystem.OpenFile(path, FileMode.Open, FileAccess.Read, FileShare.Read);
				SaveSystem.SkipBOM(stream);
				result.fileLength = stream.Length;
				using TextReader textReader = new StreamReader(stream, Encoding.UTF8);
				UnityEngine.Debug.LogFormat("stream.Length={0}", stream.Length);
				try
				{
					UserProfile userProfile = XmlUtility.FromXml(XDocument.Load(textReader));
					userProfile.fileName = path.GetNameWithoutExtension();
					userProfile.canSave = true;
					userProfile.fileSystem = fileSystem;
					userProfile.filePath = path;
					result.userProfile = userProfile;
					return result;
				}
				catch (XmlException)
				{
					stream.Position = 0L;
					byte[] array = new byte[stream.Length];
					stream.Read(array, 0, (int)stream.Length);
					result.failureContents = System.Convert.ToBase64String(array);
					UserProfile userProfile2 = CreateGuestProfile();
					userProfile2.fileSystem = fileSystem;
					userProfile2.filePath = path;
					userProfile2.fileName = path.GetNameWithoutExtension();
					userProfile2.name = $"<color=#FF7F7FFF>Corrupted Profile: {userProfile2.fileName}</color>";
					userProfile2.canSave = false;
					userProfile2.isCorrupted = true;
					result.userProfile = userProfile2;
					throw;
				}
			}
			catch (Exception ex2)
			{
				UnityEngine.Debug.LogFormat("Failed to load user profile {0}: {1}\nStack Trace:\n{2}", path, ex2.Message, ex2.StackTrace);
				result.exception = ex2;
				return result;
			}
		}

		protected override void ProcessFileOutputQueue()
		{
			lock (pendingOutputQueue)
			{
				while (pendingOutputQueue.Count > 0)
				{
					FileOutput fileOutput = pendingOutputQueue.Dequeue();
					if (CanWrite(fileOutput))
					{
						WriteToDisk(fileOutput);
					}
				}
			}
		}

		protected override void StartSave(UserProfile userProfile, bool blocking)
		{
			UserProfile tempCopy = new UserProfile();
			SaveSystem.Copy(userProfile, tempCopy);
			FileOutput fileOutput = new FileOutput
			{
				fileReference = new FileReference
				{
					path = tempCopy.filePath,
					fileSystem = tempCopy.fileSystem
				},
				requestTime = DateTime.UtcNow,
				contents = Array.Empty<byte>()
			};
			Task task = null;
			task = new Task(PayloadGeneratorAction);
			AddActiveTask(task);
			task.Start(TaskScheduler.Default);
			if (blocking)
			{
				task.Wait();
				ProcessFileOutputQueue();
			}
			void PayloadGeneratorAction()
			{
				try
				{
					FileIoIndicatorManager.IncrementActiveWriteCount();
					XDocument xDocument = XmlUtility.ToXml(tempCopy);
					using (MemoryStream memoryStream = new MemoryStream())
					{
						using XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
						xDocument.Save(xmlTextWriter);
						xmlTextWriter.Flush();
						fileOutput.contents = new byte[memoryStream.Length];
						memoryStream.Seek(0L, SeekOrigin.Begin);
						memoryStream.Read(fileOutput.contents, 0, fileOutput.contents.Length);
					}
					EnqueueFileOutput(fileOutput);
				}
				catch (Exception)
				{
					RoR2Application.onNextUpdate += delegate
					{
					};
					throw;
				}
				finally
				{
					FileIoIndicatorManager.DecrementActiveWriteCount();
					RemoveActiveTask(task);
				}
			}
		}

		private new bool CanWrite(FileOutput fileOutput)
		{
			if (fileOutput.contents.Length == 0)
			{
				UnityEngine.Debug.LogErrorFormat("Cannot write UserProfile \"{0}\" with zero-length contents. This would erase the file.");
				return false;
			}
			if (latestWrittenRequestTimesByFile.TryGetValue(fileOutput.fileReference, out var value))
			{
				return value < fileOutput.requestTime;
			}
			return true;
		}

		private void WriteToDisk(FileOutput fileOutput)
		{
			FileIoIndicatorManager.IncrementActiveWriteCount();
			try
			{
				using (Stream stream = fileOutput.fileReference.fileSystem.OpenFile(fileOutput.fileReference.path, FileMode.Create, FileAccess.Write))
				{
					stream.Write(fileOutput.contents, 0, fileOutput.contents.Length);
					stream.Flush();
					stream.Close();
					UnityEngine.Debug.LogFormat("Saved file \"{0}\" ({1} bytes)", fileOutput.fileReference.path.GetName(), fileOutput.contents.Length);
				}
				latestWrittenRequestTimesByFile[fileOutput.fileReference] = fileOutput.requestTime;
			}
			catch (Exception)
			{
			}
			finally
			{
				FileIoIndicatorManager.DecrementActiveWriteCount();
			}
		}

		public override UserProfile LoadPrimaryProfile()
		{
			return null;
		}

		public override string GetPlatformUsernameOrDefault(string defaultName)
		{
			string text = Client.Instance?.Username;
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return defaultName;
		}

		public override void SaveHistory(byte[] data, string fileName)
		{
		}

		public override Dictionary<string, byte[]> LoadHistory()
		{
			return new Dictionary<string, byte[]>();
		}
	}
	public class SteamUserManager : UserManager
	{
		private string LocalUserName = string.Empty;

		public void InitializeUserManager()
		{
			LocalUserManager.onUserSignIn += OnUserSignIn;
		}

		public void OnUserSignIn(LocalUser localUser)
		{
			LocalUserName = localUser.userProfile.name;
		}

		public override string GetUserName()
		{
			LocalUser localUser = LocalUserManager.FindLocalUser(0);
			if (localUser != null)
			{
				return localUser.userProfile.name;
			}
			if (Client.Instance != null)
			{
				return Client.Instance.Username;
			}
			return base.GetUserName();
		}

		public override void GetAvatar(PlatformID id, GameObject sender, Texture2D cachedTexture, AvatarSize size, Action<Texture2D> onRecieved)
		{
			GetSteamAvatar(id, sender, cachedTexture, size, onRecieved);
		}

		public static void GetSteamAvatar(PlatformID id, GameObject sender, Texture2D cachedTexture, AvatarSize size, Action<Texture2D> onRecieved)
		{
			ulong iD = id.ID;
			Client instance = Client.Instance;
			Friends.AvatarSize size2 = size switch
			{
				AvatarSize.Small => Friends.AvatarSize.Small, 
				AvatarSize.Medium => Friends.AvatarSize.Medium, 
				_ => Friends.AvatarSize.Large, 
			};
			if (instance == null)
			{
				return;
			}
			Facepunch.Steamworks.Image cachedAvatar = instance.Friends.GetCachedAvatar(size2, iD);
			if (cachedAvatar != null)
			{
				OnSteamAvatarReceived(cachedAvatar, sender, cachedTexture, onRecieved);
				return;
			}
			Action<Facepunch.Steamworks.Image> callback = delegate(Facepunch.Steamworks.Image x)
			{
				OnSteamAvatarReceived(x, sender, cachedTexture, onRecieved);
			};
			instance.Friends.GetAvatar(size2, iD, callback);
		}

		private static void OnSteamAvatarReceived(Facepunch.Steamworks.Image image, GameObject sender, Texture2D tex, Action<Texture2D> onRecieved)
		{
			if (image == null || sender == null)
			{
				return;
			}
			int width = image.Width;
			int height = image.Height;
			tex = UserManager.BuildTexture(tex, width, height);
			byte[] data = image.Data;
			Color32[] array = new Color32[data.Length / 4];
			for (int i = 0; i < height; i++)
			{
				int num = height - 1 - i;
				for (int j = 0; j < width; j++)
				{
					int num2 = (i * width + j) * 4;
					array[num * width + j] = new Color32(data[num2], data[num2 + 1], data[num2 + 2], data[num2 + 3]);
				}
			}
			if ((bool)tex)
			{
				tex.SetPixels32(array);
				tex.Apply();
			}
			onRecieved(tex);
		}
	}
	public class SteamworksLobbyManager : PCLobbyManager
	{
		private struct LobbyRefreshRequest
		{
			public object requester;

			public LobbyList.Filter filter;

			public Action<List<LobbyList.Lobby>> callback;
		}

		public bool isInLobbyDelayed;

		private const MPFeatures PlatformFeatureFlags = MPFeatures.HostGame | MPFeatures.FindGame;

		private const MPLobbyFeatures PlatformLobbyUIFlags = MPLobbyFeatures.CreateLobby | MPLobbyFeatures.SocialIcon | MPLobbyFeatures.HostPromotion | MPLobbyFeatures.Clipboard | MPLobbyFeatures.Invite | MPLobbyFeatures.UserIcon | MPLobbyFeatures.LeaveLobby | MPLobbyFeatures.LobbyDropdownOptions;

		private PlatformID _pendingSteamworksLobbyId;

		private bool _ownsLobby;

		private int minimumPlayerCount = 2;

		public const string mdEdition = "v";

		public const string mdAppId = "appid";

		public const string mdTotalMaxPlayers = "total_max_players";

		public const string mdPlayerCount = "player_count";

		public const string mdQuickplayQueued = "qp";

		public const string mdQuickplayCutoffTime = "qp_cutoff_time";

		public const string mdStarting = "starting";

		public const string mdBuildId = "build_id";

		public const string mdServerId = "server_id";

		public const string mdServerAddress = "server_address";

		public const string mdMap = "_map";

		public const string mdRuleBook = "rulebook";

		public const string mdMigrationId = "migration_id";

		public const string mdHasPassword = "_pw";

		public const string mdIsDedicatedServer = "_ds";

		public const string mdServerName = "_svnm";

		public const string mdServerTags = "_svtags";

		public const string mdServerMaxPlayers = "_svmpl";

		public const string mdServerPlayerCount = "_svplc";

		public const string mdGameModeName = "_svgm";

		public const string mdModHash = "_mh";

		private readonly List<int> playerCountsList = new List<int>();

		private MemoizedToString<int, ToStringImplementationInvariant> localPlayerCountToString = MemoizedToString<int, ToStringImplementationInvariant>.GetNew();

		private bool startingFadeSet;

		private readonly MethodInfo updateLobbyDataMethodInfo = typeof(Lobby).GetMethod("UpdateLobbyData", BindingFlags.Instance | BindingFlags.NonPublic);

		private PlatformID lastHostingLobbyId;

		private Queue<LobbyRefreshRequest> lobbyRefreshRequests = new Queue<LobbyRefreshRequest>();

		private LobbyRefreshRequest? currentRefreshRequest;

		private bool hostingServer;

		private PlatformID currentServerId;

		private MemoizedToString<PlatformID, ToStringDefault<PlatformID>> currentServerIdString = MemoizedToString<PlatformID, ToStringDefault<PlatformID>>.GetNew();

		public PlatformID pendingSteamworksLobbyId
		{
			get
			{
				return _pendingSteamworksLobbyId;
			}
			set
			{
				if (!_pendingSteamworksLobbyId.Equals(value))
				{
					if (_pendingSteamworksLobbyId.value != null)
					{
						RoR2Application.onUpdate -= AttemptToJoinPendingSteamworksLobby;
					}
					_pendingSteamworksLobbyId = value;
					if (_pendingSteamworksLobbyId.value != null)
					{
						RoR2Application.onUpdate += AttemptToJoinPendingSteamworksLobby;
					}
				}
			}
		}

		private Client client => Client.Instance;

		public override bool isInLobby
		{
			get
			{
				if (client == null || client.Lobby == null)
				{
					return false;
				}
				return client.Lobby.IsValid;
			}
			protected set
			{
			}
		}

		public override bool ownsLobby
		{
			get
			{
				return _ownsLobby;
			}
			protected set
			{
				if (value != _ownsLobby)
				{
					_ownsLobby = value;
					if (_ownsLobby)
					{
						OnLobbyOwnershipGained();
						UpdatePlayerCount();
					}
					else
					{
						OnLobbyOwnershipLost();
					}
				}
			}
		}

		public override bool hasMinimumPlayerCount => newestLobbyData.totalPlayerCount >= minimumPlayerCount;

		public int remoteMachineCount { get; private set; }

		public PlatformID serverId => newestLobbyData.serverId;

		public override LobbyData newestLobbyData { get; protected set; }

		public override int calculatedTotalPlayerCount { get; protected set; }

		public override int calculatedExtraPlayersCount { get; protected set; }

		public override LobbyType currentLobbyType
		{
			get
			{
				return (LobbyType)Client.Instance.Lobby.LobbyType;
			}
			set
			{
			}
		}

		public override bool IsBusy { get; set; }

		public override MPFeatures GetPlatformMPFeatureFlags()
		{
			return MPFeatures.HostGame | MPFeatures.FindGame;
		}

		public override MPLobbyFeatures GetPlatformMPLobbyFeatureFlags()
		{
			return MPLobbyFeatures.CreateLobby | MPLobbyFeatures.SocialIcon | MPLobbyFeatures.HostPromotion | MPLobbyFeatures.Clipboard | MPLobbyFeatures.Invite | MPLobbyFeatures.UserIcon | MPLobbyFeatures.LeaveLobby | MPLobbyFeatures.LobbyDropdownOptions;
		}

		public static SteamworksLobbyManager GetFromPlatformSystems()
		{
			return PlatformSystems.lobbyManager as SteamworksLobbyManager;
		}

		private void UpdateOwnsLobby()
		{
			ownsLobby = client.Lobby.IsOwner;
		}

		public void Init()
		{
			Client instance = Client.Instance;
			instance.Lobby.OnChatMessageRecieved = OnChatMessageReceived;
			instance.Lobby.OnLobbyCreated = OnLobbyCreated;
			instance.Lobby.OnLobbyDataUpdated = OnLobbyDataUpdated;
			instance.Lobby.OnLobbyJoined = OnLobbyJoined;
			instance.Lobby.OnLobbyMemberDataUpdated = OnLobbyMemberDataUpdated;
			instance.Lobby.OnLobbyStateChanged = OnLobbyStateChanged;
			instance.Lobby.OnLobbyKicked = OnLobbyKicked;
			instance.Lobby.OnLobbyLeave = OnLobbyLeave;
			instance.Lobby.OnUserInvitedToLobby = OnUserInvitedToLobby;
			instance.Lobby.OnLobbyJoinRequested = OnLobbyJoinRequested;
			instance.LobbyList.OnLobbiesUpdated = OnLobbiesUpdated;
			RoR2Application.onUpdate += StaticUpdate;
			LobbyDataSetupState setupState = new LobbyDataSetupState
			{
				totalMaxPlayers = RoR2Application.maxPlayers
			};
			newestLobbyData = new LobbyData(setupState);
			LocalUserManager.onLocalUsersUpdated += UpdatePlayerCount;
			NetworkManagerSystem.onStartServerGlobal += OnStartHostingServer;
			NetworkManagerSystem.onStopServerGlobal += OnStopHostingServer;
			NetworkManagerSystem.onStopClientGlobal += OnStopClient;
			NetworkManagerSystem.onStopClientGlobal += delegate
			{
				SetStartingIfOwner(startingState: false);
			};
			onLobbyOwnershipGained = (Action)Delegate.Combine(onLobbyOwnershipGained, (Action)delegate
			{
				SetStartingIfOwner(startingState: false);
			});
			SetStartingIfOwner(startingState: false);
			pendingSteamworksLobbyId = GetLaunchParamsLobbyId();
		}

		public override int GetLobbyMemberPlayerCountByIndex(int memberIndex)
		{
			if (memberIndex >= playerCountsList.Count)
			{
				return 0;
			}
			return playerCountsList[memberIndex];
		}

		public override void CheckIfInitializedAndValid()
		{
			if (Client.Instance == null)
			{
				throw new ConCommandException("Steamworks client not available.");
			}
		}

		private void UpdatePlayerCount()
		{
			if (client != null && client.Lobby.IsValid)
			{
				int count = LocalUserManager.readOnlyLocalUsersList.Count;
				string memberData = client.Lobby.GetMemberData(client.SteamId, "player_count");
				ref MemoizedToString<int, ToStringImplementationInvariant> reference = ref localPlayerCountToString;
				int input = Math.Max(1, count);
				string @string = reference.GetString(in input);
				if (memberData != @string)
				{
					client.Lobby.SetMemberData("player_count", @string);
				}
				playerCountsList.Clear();
				calculatedTotalPlayerCount = 0;
				remoteMachineCount = 0;
				calculatedExtraPlayersCount = 0;
				ulong steamId = client.SteamId;
				ulong[] memberIDs = client.Lobby.GetMemberIDs();
				foreach (ulong num in memberIDs)
				{
					int result = ((!TextSerialization.TryParseInvariant(client.Lobby.GetMemberData(num, "player_count"), out result)) ? 1 : Math.Max(1, result));
					if (num == steamId)
					{
						result = Math.Max(1, count);
					}
					else
					{
						int num2 = remoteMachineCount + 1;
						remoteMachineCount = num2;
					}
					playerCountsList.Add(result);
					calculatedTotalPlayerCount += result;
					if (result > 1)
					{
						calculatedExtraPlayersCount += result - 1;
					}
				}
			}
			onPlayerCountUpdated?.Invoke();
		}

		private void OnLobbyChanged()
		{
			isInLobby = client.Lobby.IsValid;
			isInLobbyDelayed = isInLobby;
			UpdateOwnsLobby();
			UpdatePlayerCount();
			onLobbyChanged?.Invoke();
			OnLobbyDataUpdated();
		}

		public override void CreateLobby()
		{
			if (client != null)
			{
				pendingSteamworksLobbyId = default(PlatformID);
				client.Lobby.Leave();
				base.awaitingCreate = true;
				client.Lobby.Create((Lobby.Type)preferredLobbyType, RoR2Application.maxPlayers);
			}
		}

		public override void JoinLobby(PlatformID uid)
		{
			PlatformID platformID = uid;
			if (client != null && LocalUserManager.isAnyUserSignedIn)
			{
				base.awaitingJoin = true;
				LeaveLobby();
				client.Lobby.Join(platformID.ID);
			}
		}

		public override void LeaveLobby()
		{
			client?.Lobby.Leave();
		}

		public override PlatformID[] GetLobbyMembers()
		{
			ulong[] array = Client.Instance?.Lobby?.GetMemberIDs();
			PlatformID[] array2 = null;
			if (array != null)
			{
				array2 = new PlatformID[array.Length];
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i] = new PlatformID(array[i]);
				}
			}
			return array2;
		}

		public override bool ShouldShowPromoteButton()
		{
			return SteamLobbyFinder.running;
		}

		private void Update()
		{
			if (client != null && startingFadeSet != (newestLobbyData.starting && !ClientScene.ready))
			{
				if (startingFadeSet)
				{
					FadeToBlackManager.fadeCount--;
				}
				else
				{
					FadeToBlackManager.fadeCount++;
				}
				startingFadeSet = !startingFadeSet;
			}
		}

		private void StaticUpdate()
		{
			if (client != null)
			{
				UpdateOwnsLobby();
			}
		}

		private PlatformID GetLaunchParamsLobbyId()
		{
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			for (int i = 0; i < commandLineArgs.Length - 1; i++)
			{
				if (string.Equals(commandLineArgs[i], "+connect_lobby", StringComparison.OrdinalIgnoreCase) && PlatformID.TryParse(ArrayUtils.GetSafe(commandLineArgs, i + 1, in string.Empty), out var result))
				{
					return result;
				}
			}
			return PlatformID.nil;
		}

		public void ForceLobbyDataUpdate()
		{
			Lobby lobby = client?.Lobby;
			if (lobby != null)
			{
				updateLobbyDataMethodInfo.Invoke(lobby, Array.Empty<object>());
			}
		}

		public void SendLobbyMessage(LobbyMessageType messageType, NetworkWriter writer)
		{
			byte[] array = new byte[1 + writer.Position];
			array[0] = (byte)messageType;
			Array.Copy(writer.AsArray(), 0, array, 1, writer.Position);
			Client.Instance.Lobby.SendChatMessage(Encoding.UTF8.GetString(array));
		}

		public override void OnCutoffTimerComplete()
		{
		}

		private void OnChatMessageReceived(ulong senderId, byte[] buffer, int byteCount)
		{
			try
			{
				_ = Client.Instance.Lobby.IsOwner;
				bool flag = senderId == Client.Instance.Lobby.Owner;
				bool flag2 = senderId == Client.Instance.SteamId;
				NetworkReader networkReader = new NetworkReader(buffer);
				if (byteCount >= 1)
				{
					LobbyMessageType lobbyMessageType = (LobbyMessageType)networkReader.ReadByte();
					UnityEngine.Debug.LogFormat("Received Steamworks Lobby Message from {0} ({1}B). messageType={2}", senderId, byteCount, lobbyMessageType);
					switch (lobbyMessageType)
					{
					case LobbyMessageType.Chat:
					{
						string arg = networkReader.ReadString();
						Chat.AddMessage(string.Format("{0}: {1}", Client.Instance.Friends.Get(senderId)?.Name ?? "???", arg));
						break;
					}
					case LobbyMessageType.Password:
					{
						string @string = networkReader.ReadString();
						if (!flag2 && flag)
						{
							NetworkManagerSystem.cvClPassword.SetString(@string);
						}
						break;
					}
					}
				}
				else
				{
					UnityEngine.Debug.LogWarningFormat("Received SteamworksLobbyMessage from {0}, but the message was empty.");
				}
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private void OnLobbyCreated(bool success)
		{
			base.awaitingCreate = false;
			if (success)
			{
				UnityEngine.Debug.LogFormat("Steamworks lobby creation succeeded. Lobby id = {0}", client.Lobby.CurrentLobby);
				OnLobbyChanged();
			}
		}

		protected void OnLobbyDataUpdated()
		{
			Lobby lobby = client.Lobby;
			newestLobbyData = (lobby.IsValid ? new LobbyData(lobby) : new LobbyData());
			UpdateOwnsLobby();
			UpdatePlayerCount();
			PlatformID platformID = new PlatformID(lobby.CurrentLobby);
			if (lobby.IsValid && !ownsLobby)
			{
				if (newestLobbyData.serverId.isValid)
				{
					bool num = newestLobbyData.serverId == NetworkManagerSystem.singleton.serverP2PId || NetworkManagerSystem.singleton.IsConnectedToServer(newestLobbyData.serverId);
					bool flag = string.CompareOrdinal(RoR2Application.GetBuildId(), newestLobbyData.buildId) == 0;
					if (!num && flag)
					{
						NetworkManagerSystem.singleton.desiredHost = new HostDescription(newestLobbyData.serverId, HostDescription.HostType.Steam);
						lastHostingLobbyId = platformID;
					}
				}
				else if (lastHostingLobbyId == platformID)
				{
					UnityEngine.Debug.LogFormat("Intercepting bad or out-of-order lobby update to server id.");
				}
				else
				{
					NetworkManagerSystem.singleton.desiredHost = HostDescription.none;
				}
			}
			onLobbyDataUpdated?.Invoke();
		}

		private void OnLobbyJoined(bool success)
		{
			base.awaitingJoin = false;
			if (success)
			{
				if (client.Lobby.CurrentLobbyData != null)
				{
					string buildId = RoR2Application.GetBuildId();
					string data = client.Lobby.CurrentLobbyData.GetData("build_id");
					if (buildId != data)
					{
						UnityEngine.Debug.LogFormat("Lobby build_id mismatch, leaving lobby. Ours=\"{0}\" Theirs=\"{1}\"", buildId, data);
						SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
						simpleDialogBox.AddCancelButton(CommonLanguageTokens.ok);
						simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
						{
							token = "STEAM_LOBBY_VERSION_MISMATCH_DIALOG_TITLE",
							formatParams = Array.Empty<object>()
						};
						SimpleDialogBox.TokenParamsPair descriptionToken = new SimpleDialogBox.TokenParamsPair
						{
							token = "STEAM_LOBBY_VERSION_MISMATCH_DIALOG_DESCRIPTION"
						};
						object[] formatParams = new string[2] { buildId, data };
						descriptionToken.formatParams = formatParams;
						simpleDialogBox.descriptionToken = descriptionToken;
						client.Lobby.Leave();
						return;
					}
				}
				UnityEngine.Debug.LogFormat("Steamworks lobby join succeeded. Lobby id = {0}", client.Lobby.CurrentLobby);
				OnLobbyChanged();
			}
			else
			{
				SimpleDialogBox simpleDialogBox2 = SimpleDialogBox.Create();
				simpleDialogBox2.AddCancelButton(CommonLanguageTokens.ok);
				simpleDialogBox2.headerToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "EOS_CANNOT_JOIN_STEAM_LOBBY_HEADER",
					formatParams = Array.Empty<object>()
				};
				simpleDialogBox2.descriptionToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "KICK_REASON_SERVERFULL",
					formatParams = Array.Empty<object>()
				};
				Console.instance.SubmitCmd(null, "steam_lobby_create_if_none", recordSubmit: true);
			}
			onLobbyJoined?.Invoke(success);
		}

		private void OnLobbyMemberDataUpdated(ulong memberId)
		{
			UpdateOwnsLobby();
			onLobbyMemberDataUpdated?.Invoke(new PlatformID(memberId));
		}

		protected void OnLobbyStateChanged(Lobby.MemberStateChange memberStateChange, ulong initiatorUserId, ulong affectedUserId)
		{
			UnityEngine.Debug.LogFormat("OnLobbyStateChanged memberStateChange={0} initiatorUserId={1} affectedUserId={2}", memberStateChange, initiatorUserId, affectedUserId);
			OnLobbyChanged();
			onLobbyStateChanged?.Invoke();
		}

		private void OnLobbyKicked(bool kickedDueToDisconnect, ulong lobbyId, ulong adminId)
		{
			UnityEngine.Debug.LogFormat("Kicked from lobby. kickedDueToDisconnect={0} lobbyId={1} adminId={2}", kickedDueToDisconnect, lobbyId, adminId);
			OnLobbyChanged();
		}

		private void OnLobbyLeave(ulong lobbyId)
		{
			UnityEngine.Debug.LogFormat("Left lobby {0}.", lobbyId);
			onLobbyLeave?.Invoke(new PlatformID(lobbyId));
			OnLobbyChanged();
		}

		private void OnLobbyJoinRequested(ulong lobbyId)
		{
			UnityEngine.Debug.LogFormat("Request to join lobby {0} received. Attempting to join lobby.", lobbyId);
			pendingSteamworksLobbyId = new PlatformID(lobbyId);
		}

		private void OnUserInvitedToLobby(ulong lobbyId, ulong senderId)
		{
			UnityEngine.Debug.LogFormat("Received invitation to lobby {0} from sender {1}.", lobbyId, senderId);
		}

		public bool RequestLobbyList(object requester, LobbyList.Filter filter, Action<List<LobbyList.Lobby>> callback)
		{
			if (requester != null)
			{
				foreach (LobbyRefreshRequest lobbyRefreshRequest2 in lobbyRefreshRequests)
				{
					if (requester == lobbyRefreshRequest2.requester)
					{
						return false;
					}
				}
			}
			LobbyRefreshRequest lobbyRefreshRequest = default(LobbyRefreshRequest);
			lobbyRefreshRequest.requester = requester;
			lobbyRefreshRequest.filter = filter;
			lobbyRefreshRequest.callback = callback;
			LobbyRefreshRequest item = lobbyRefreshRequest;
			lobbyRefreshRequests.Enqueue(item);
			UpdateRefreshRequestQueue();
			return true;
		}

		private void UpdateRefreshRequestQueue()
		{
			if (!currentRefreshRequest.HasValue && lobbyRefreshRequests.Count != 0)
			{
				currentRefreshRequest = lobbyRefreshRequests.Dequeue();
				client.LobbyList.Refresh(currentRefreshRequest.Value.filter);
			}
		}

		private void OnLobbiesUpdated()
		{
			if (currentRefreshRequest.HasValue)
			{
				LobbyRefreshRequest value = currentRefreshRequest.Value;
				currentRefreshRequest = null;
				List<LobbyList.Lobby> lobbies = client.LobbyList.Lobbies;
				value.callback(lobbies);
			}
			onLobbiesUpdated?.Invoke();
			UpdateRefreshRequestQueue();
		}

		private void OnStopClient()
		{
			if ((bool)NetworkManagerSystem.singleton && NetworkManagerSystem.singleton.client != null && NetworkManagerSystem.singleton.client.connection != null)
			{
				NetworkConnection connection = NetworkManagerSystem.singleton.client.connection;
				bool flag = false;
				bool flag2 = Util.ConnectionIsLocal(connection);
				flag = ((!(connection is SteamNetworkConnection)) ? (connection.address == newestLobbyData.serverAddressPortPair.address) : (((SteamNetworkConnection)connection).steamId == newestLobbyData.serverId));
				if (flag2 && ownsLobby)
				{
					client.Lobby.CurrentLobbyData.RemoveData("server_id");
				}
				if (!flag2 && flag)
				{
					client.Lobby.Leave();
				}
			}
		}

		private void OnStartHostingServer()
		{
			hostingServer = true;
		}

		private void OnStopHostingServer()
		{
			hostingServer = false;
		}

		public void JoinOrStartMigrate(PlatformID newLobbyId)
		{
			if (ownsLobby)
			{
				StartMigrateLobby(newLobbyId);
				return;
			}
			client.Lobby.Leave();
			JoinLobby(newLobbyId);
		}

		public void StartMigrateLobby(PlatformID newLobbyId)
		{
			client.Lobby.Joinable = false;
			client.Lobby.CurrentLobbyData.SetData("migration_id", TextSerialization.ToStringInvariant(newLobbyId.ID));
		}

		private void AttemptToJoinPendingSteamworksLobby()
		{
			if (LocalUserManager.isAnyUserSignedIn && pendingSteamworksLobbyId != default(PlatformID))
			{
				JoinLobby(pendingSteamworksLobbyId);
				pendingSteamworksLobbyId = default(PlatformID);
			}
		}

		public void SetLobbyQuickPlayQueuedIfOwner(bool quickplayQueuedState)
		{
			Lobby lobby = client.Lobby;
			if (lobby?.CurrentLobbyData != null)
			{
				lobby.CurrentLobbyData.SetData("qp", quickplayQueuedState ? "1" : "0");
				if (!quickplayQueuedState)
				{
					lobby.LobbyType = (Lobby.Type)preferredLobbyType;
				}
			}
		}

		public void SetLobbyQuickPlayCutoffTimeIfOwner(uint? timestamp)
		{
			Lobby lobby = client.Lobby;
			if (lobby?.CurrentLobbyData != null)
			{
				if (!timestamp.HasValue)
				{
					lobby.CurrentLobbyData.RemoveData("qp_cutoff_time");
					return;
				}
				string v = TextSerialization.ToStringInvariant(timestamp.Value);
				lobby.CurrentLobbyData.SetData("qp_cutoff_time", v);
			}
		}

		public void SetStartingIfOwner(bool startingState)
		{
			Lobby lobby = client.Lobby;
			if (lobby?.CurrentLobbyData != null)
			{
				lobby.CurrentLobbyData?.SetData("starting", startingState ? "1" : "0");
			}
		}

		protected void OnLobbyOwnershipGained()
		{
			onLobbyOwnershipGained?.Invoke();
		}

		private void OnLobbyOwnershipLost()
		{
			onLobbyOwnershipLost?.Invoke();
		}

		public static void CreateCannotJoinSteamLobbyPopup()
		{
			SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
			simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "EOS_CANNOT_JOIN_STEAM_LOBBY_HEADER",
				formatParams = Array.Empty<object>()
			};
			simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "EOS_CANNOT_JOIN_STEAM_LOBBY_MESSAGE",
				formatParams = Array.Empty<object>()
			};
			simpleDialogBox.AddCancelButton(CommonLanguageTokens.ok);
		}

		public override string GetLobbyID()
		{
			CheckIfInitializedAndValid();
			return TextSerialization.ToStringInvariant(client.Lobby.CurrentLobby);
		}

		public override bool CheckLobbyIdValidity(string lobbyID)
		{
			if (!IsDigitsOnly(lobbyID))
			{
				return false;
			}
			return true;
			static bool IsDigitsOnly(string str)
			{
				foreach (char c in str)
				{
					if (c < '0' || c > '9')
					{
						return false;
					}
				}
				return true;
			}
		}

		public override void JoinLobby(ConCommandArgs args)
		{
			string text = args[0];
			if (PlatformID.TryParse(text, out var result))
			{
				CheckIfInitializedAndValid();
				UnityEngine.Debug.LogFormat("Enqueuing join for lobby {0}...", text);
				pendingSteamworksLobbyId = new PlatformID(result.ID);
			}
			else
			{
				UnityEngine.Debug.LogFormat("Failed parsing lobby ID from {0}...", text);
			}
		}

		public override void LobbyCreate(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			obj.CheckIfInitializedAndValid();
			if (!LocalUserManager.isAnyUserSignedIn)
			{
				throw new ConCommandException("Cannot create a Steamworks lobby without any local users signed in.");
			}
			obj.CreateLobby();
		}

		public override void LobbyCreateIfNone(ConCommandArgs args)
		{
			SteamworksLobbyManager steamworksLobbyManager = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = steamworksLobbyManager.client;
			steamworksLobbyManager.CheckIfInitializedAndValid();
			if (!LocalUserManager.isAnyUserSignedIn)
			{
				throw new ConCommandException("Cannot create a Steamworks lobby without any local users signed in.");
			}
			if (!client.Lobby.IsValid)
			{
				steamworksLobbyManager.CreateLobby();
			}
		}

		public override void LobbyLeave(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			obj.CheckIfInitializedAndValid();
			obj.pendingSteamworksLobbyId = default(PlatformID);
			obj.LeaveLobby();
		}

		public override void LobbyAssignOwner(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			UnityEngine.Debug.LogFormat("Promoting {0} to lobby leader...", args[0]);
			client.Lobby.Owner = args.GetArgPlatformID(0).ID;
		}

		public override void LobbyInvite(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			client.Lobby.InviteUserToLobby(args.GetArgPlatformID(0).ID);
		}

		public static void DoSteamLobbyOpenOverlay()
		{
			Client instance = Client.Instance;
			NetworkManagerSystemSteam.CheckSteamworks();
			instance.Overlay.OpenInviteDialog(instance.Lobby.CurrentLobby);
		}

		public override void LobbyOpenInviteOverlay(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as SteamworksLobbyManager).CheckIfInitializedAndValid();
			DoSteamLobbyOpenOverlay();
		}

		public override void LobbyCopyToClipboard(ConCommandArgs args)
		{
			string lobbyID = GetLobbyID();
			if (!string.IsNullOrWhiteSpace(lobbyID))
			{
				GUIUtility.systemCopyBuffer = lobbyID;
			}
			Chat.AddMessage(Language.GetString("STEAM_COPY_LOBBY_TO_CLIPBOARD_MESSAGE"));
		}

		public override void LobbyPrintData(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			if (!client.Lobby.IsValid)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, string> allDatum in client.Lobby.CurrentLobbyData.GetAllData())
			{
				list.Add($"\"{allDatum.Key}\" = \"{allDatum.Value}\"");
			}
		}

		public override void DisplayId(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			UnityEngine.Debug.LogFormat("Steam id = {0}", client.SteamId);
		}

		public override void DisplayLobbyId(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			UnityEngine.Debug.LogFormat("Lobby id = {0}", client.Lobby.CurrentLobby);
		}

		public override void LobbyPrintMembers(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			ulong[] memberIDs = client.Lobby.GetMemberIDs();
			string[] array = new string[memberIDs.Length];
			for (int i = 0; i < memberIDs.Length; i++)
			{
				array[i] = string.Format("[{0}]{1} id={2} name={3}", i, (client.Lobby.Owner == memberIDs[i]) ? "*" : " ", memberIDs[i], client.Friends.GetName(memberIDs[i]));
			}
		}

		public override void ClearLobbies(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			_ = obj.client;
			obj.RequestLobbyList(null, new LobbyList.Filter
			{
				MaxResults = 50,
				DistanceFilter = LobbyList.Filter.Distance.Worldwide
			}, delegate(List<LobbyList.Lobby> lobbies)
			{
				foreach (LobbyList.Lobby lobby in lobbies)
				{
					_ = lobby;
				}
			});
		}

		public override void LobbyUpdatePlayerCount(ConCommandArgs args)
		{
			(PlatformSystems.lobbyManager as SteamworksLobbyManager).UpdatePlayerCount();
		}

		public override void LobbyForceUpdateData(ConCommandArgs args)
		{
		}

		public override void LobbyPrintList(ConCommandArgs args)
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			List<LobbyList.Lobby> lobbies = client.LobbyList.Lobbies;
			string[] array = new string[lobbies.Count];
			for (int i = 0; i < lobbies.Count; i++)
			{
				array[i] = $"[{i}] id={lobbies[i].LobbyID}\n      players={lobbies[i].NumMembers}/{lobbies[i].MemberLimit},\n      owner=\"{client.Friends.GetName(lobbies[i].Owner)}\"";
			}
		}

		public override bool IsLobbyOwner(PlatformID user)
		{
			if (Client.Instance.Lobby.Owner == user.ID)
			{
				return user != default(PlatformID);
			}
			return false;
		}

		public override void AutoMatchmake()
		{
		}

		public override bool IsLobbyOwner()
		{
			if (isInLobby)
			{
				return _ownsLobby;
			}
			return false;
		}

		public override bool CanInvite()
		{
			return !IsBusy;
		}

		public override void OnStartPrivateGame()
		{
			CreateLobby();
		}

		public override void ToggleQuickplay()
		{
			Console.instance.SubmitCmd(null, SteamLobbyFinder.running ? "steam_quickplay_stop" : "steam_quickplay_start");
		}

		public override void CheckIfInvited()
		{
		}

		public override void CheckBusyTimer()
		{
		}

		public override bool ShouldEnableQuickplayButton()
		{
			return false;
		}

		public override bool ShouldEnableStartPrivateGameButton()
		{
			if (!newestLobbyData.quickplayQueued)
			{
				return ownsLobby;
			}
			return false;
		}

		public override string GetUserDisplayName(PlatformID user)
		{
			Client instance = Client.Instance;
			string result = "none";
			if (instance != null)
			{
				result = instance.Friends.GetName(user.ID);
			}
			return result;
		}

		public override void OpenInviteOverlay()
		{
			SteamworksLobbyManager obj = PlatformSystems.lobbyManager as SteamworksLobbyManager;
			Client client = obj.client;
			obj.CheckIfInitializedAndValid();
			NetworkManagerSystemSteam.CheckSteamworks();
			client.Overlay.OpenInviteDialog(client.Lobby.CurrentLobby);
		}

		public override void SetLobbyTypeConVarString(string newValue)
		{
			(PlatformSystems.lobbyManager as SteamworksLobbyManager).CheckIfInitializedAndValid();
			if (Client.Instance.Lobby.LobbyType == Lobby.Type.Error || !Client.Instance.Lobby.IsOwner)
			{
				throw new ConCommandException("Lobby type cannot be set while not the owner of a valid lobby.");
			}
			Lobby.Type dest = Lobby.Type.Error;
			SteamLobbyTypeConVar.instance.GetEnumValueAbstract(newValue, ref dest);
			if (dest == Lobby.Type.Error)
			{
				throw new ConCommandException("Lobby type \"Error\" is not allowed.");
			}
			Client.Instance.Lobby.LobbyType = dest;
		}

		public override string GetLobbyTypeConVarString()
		{
			return Client.Instance?.Lobby.LobbyType.ToString() ?? string.Empty;
		}

		public override int GetLobbyMemberCount()
		{
			return (Client.Instance?.Lobby)?.NumMembers ?? 0;
		}
	}
	internal static class SteamworksRichPresenceManager
	{
		private abstract class BaseRichPresenceField
		{
			private static readonly Queue<BaseRichPresenceField> dirtyFields = new Queue<BaseRichPresenceField>();

			private bool isDirty;

			[CanBeNull]
			private string currentValue;

			private bool installed;

			protected abstract string key { get; }

			public static void ProcessDirtyFields()
			{
				while (dirtyFields.Count > 0)
				{
					dirtyFields.Dequeue().UpdateIfNecessary();
				}
			}

			[CanBeNull]
			protected abstract string RebuildValue();

			protected virtual void OnChanged()
			{
			}

			public void SetDirty()
			{
				if (!isDirty)
				{
					isDirty = true;
					dirtyFields.Enqueue(this);
				}
			}

			private void UpdateIfNecessary()
			{
				if (installed)
				{
					isDirty = false;
					string text = RebuildValue();
					if (text != currentValue)
					{
						currentValue = text;
						SetKeyValue(key, currentValue);
						OnChanged();
					}
				}
			}

			protected virtual void OnInstall()
			{
			}

			protected virtual void OnUninstall()
			{
			}

			public void Install()
			{
				if (!installed)
				{
					OnInstall();
					SetDirty();
					installed = true;
				}
			}

			public void Uninstall()
			{
				if (installed)
				{
					OnUninstall();
					installed = false;
					SetKeyValue(key, null);
				}
			}

			protected void SetDirtyableValue<T>(ref T field, T value) where T : struct, IEquatable<T>
			{
				if (!field.Equals(value))
				{
					field = value;
					SetDirty();
				}
			}

			protected void SetDirtyableReference<T>(ref T field, T value) where T : class
			{
				if (field != value)
				{
					field = value;
					SetDirty();
				}
			}
		}

		private sealed class DifficultyField : BaseRichPresenceField
		{
			protected override string key => "difficulty";

			protected override string RebuildValue()
			{
				if (!Run.instance)
				{
					return null;
				}
				if (DifficultyCatalog.GetDifficultyDef(Run.instance.selectedDifficulty).countsAsHardMode)
				{
					return "Hard";
				}
				return Run.instance.selectedDifficulty switch
				{
					DifficultyIndex.Easy => "Easy", 
					DifficultyIndex.Normal => "Normal", 
					DifficultyIndex.Hard => "Hard", 
					_ => null, 
				};
			}

			private void SetDirty(Run run)
			{
				SetDirty();
			}

			protected override void OnInstall()
			{
				base.OnInstall();
				Run.onRunStartGlobal += SetDirty;
				Run.onRunDestroyGlobal += SetDirty;
			}

			protected override void OnUninstall()
			{
				Run.onRunStartGlobal -= SetDirty;
				Run.onRunDestroyGlobal -= SetDirty;
				base.OnUninstall();
			}
		}

		private sealed class GameModeField : BaseRichPresenceField
		{
			protected override string key => "gamemode";

			protected override string RebuildValue()
			{
				if (!Run.instance)
				{
					return null;
				}
				return GameModeCatalog.FindGameModePrefabComponent(Run.instance.name)?.name;
			}

			private void SetDirty(Run run)
			{
				SetDirty();
			}

			protected override void OnInstall()
			{
				base.OnInstall();
				Run.onRunStartGlobal += SetDirty;
				Run.onRunDestroyGlobal += SetDirty;
			}

			protected override void OnUninstall()
			{
				Run.onRunStartGlobal -= SetDirty;
				Run.onRunDestroyGlobal -= SetDirty;
				base.OnUninstall();
			}
		}

		private sealed class ParticipationField : BaseRichPresenceField
		{
			private enum ParticipationType
			{
				None,
				Alive,
				Dead,
				Spectator
			}

			private ParticipationType participationType;

			private LocalUser trackedUser;

			private CharacterMaster currentMaster;

			protected override string key => "participation_type";

			private void SetParticipationType(ParticipationType newParticipationType)
			{
				if (participationType != newParticipationType)
				{
					participationType = newParticipationType;
					SetDirty();
				}
			}

			protected override string RebuildValue()
			{
				return participationType switch
				{
					ParticipationType.Alive => "Alive", 
					ParticipationType.Dead => "Dead", 
					ParticipationType.Spectator => "Spectator", 
					_ => null, 
				};
			}

			protected override void OnInstall()
			{
				base.OnInstall();
				LocalUserManager.onUserSignIn += OnLocalUserDiscovered;
				LocalUserManager.onUserSignOut += OnLocalUserLost;
				Run.onRunStartGlobal += OnRunStart;
				Run.onRunDestroyGlobal += OnRunDestroy;
			}

			protected override void OnUninstall()
			{
				LocalUserManager.onUserSignIn -= OnLocalUserDiscovered;
				LocalUserManager.onUserSignOut -= OnLocalUserLost;
				Run.onRunStartGlobal -= OnRunStart;
				Run.onRunDestroyGlobal -= OnRunDestroy;
				SetCurrentMaster(null);
			}

			private void SetTrackedUser(LocalUser newTrackedUser)
			{
				if (trackedUser != null)
				{
					trackedUser.onMasterChanged -= OnMasterChanged;
				}
				trackedUser = newTrackedUser;
				if (trackedUser != null)
				{
					trackedUser.onMasterChanged += OnMasterChanged;
				}
			}

			private void OnLocalUserDiscovered(LocalUser localUser)
			{
				if (trackedUser == null)
				{
					SetTrackedUser(localUser);
				}
			}

			private void OnLocalUserLost(LocalUser localUser)
			{
				if (trackedUser == localUser)
				{
					SetTrackedUser(null);
				}
			}

			private void OnRunStart(Run run)
			{
				if (trackedUser != null && !trackedUser.cachedMasterObject)
				{
					SetParticipationType(ParticipationType.Spectator);
				}
			}

			private void OnRunDestroy(Run run)
			{
				if (trackedUser != null)
				{
					SetParticipationType(ParticipationType.None);
				}
			}

			private void OnMasterChanged()
			{
				PlayerCharacterMasterController cachedMasterController = trackedUser.cachedMasterController;
				SetCurrentMaster(cachedMasterController ? cachedMasterController.master : null);
			}

			private void SetCurrentMaster(CharacterMaster newMaster)
			{
				if ((object)currentMaster != null)
				{
					currentMaster.onBodyDeath.RemoveListener(OnBodyDeath);
					currentMaster.onBodyStart -= OnBodyStart;
				}
				currentMaster = newMaster;
				if ((object)currentMaster != null)
				{
					currentMaster.onBodyDeath.AddListener(OnBodyDeath);
					currentMaster.onBodyStart += OnBodyStart;
				}
			}

			private void OnBodyDeath()
			{
				SetParticipationType(ParticipationType.Dead);
			}

			private void OnBodyStart(CharacterBody body)
			{
				SetParticipationType(ParticipationType.Alive);
			}
		}

		private sealed class MinutesField : BaseRichPresenceField
		{
			private uint minutes;

			protected override string key => "minutes";

			protected override string RebuildValue()
			{
				return TextSerialization.ToStringInvariant(minutes);
			}

			private void FixedUpdate()
			{
				uint value = 0u;
				if ((bool)Run.instance)
				{
					value = (uint)Mathf.FloorToInt(Run.instance.GetRunStopwatch() / 60f);
				}
				SetDirtyableValue(ref minutes, value);
			}

			protected override void OnInstall()
			{
				base.OnInstall();
				RoR2Application.onFixedUpdate += FixedUpdate;
			}

			protected override void OnUninstall()
			{
				RoR2Application.onFixedUpdate -= FixedUpdate;
				base.OnUninstall();
			}
		}

		private sealed class SteamPlayerGroupField : BaseRichPresenceField
		{
			private PlatformID lobbyId = PlatformID.nil;

			private PlatformID hostId = PlatformID.nil;

			private PlatformID groupId = PlatformID.nil;

			private SteamPlayerGroupSizeField groupSizeField;

			protected override string key => "steam_player_group";

			private void SetLobbyId(PlatformID newLobbyId)
			{
				if (lobbyId != newLobbyId)
				{
					lobbyId = newLobbyId;
					UpdateGroupID();
				}
			}

			private void SetHostId(PlatformID newHostId)
			{
				if (hostId != newHostId)
				{
					hostId = newHostId;
					UpdateGroupID();
				}
			}

			private void SetGroupId(PlatformID newGroupId)
			{
				if (groupId != newGroupId)
				{
					groupId = newGroupId;
					SetDirty();
				}
			}

			private void UpdateGroupID()
			{
				if (hostId != PlatformID.nil)
				{
					SetGroupId(hostId);
					if (!(groupSizeField is SteamPlayerGroupSizeFieldGame))
					{
						groupSizeField?.Uninstall();
						groupSizeField = new SteamPlayerGroupSizeFieldGame();
						groupSizeField.Install();
					}
				}
				else
				{
					SetGroupId(lobbyId);
					if (!(groupSizeField is SteamPlayerGroupSizeFieldLobby))
					{
						groupSizeField?.Uninstall();
						groupSizeField = new SteamPlayerGroupSizeFieldLobby();
						groupSizeField.Install();
					}
				}
			}

			protected override void OnInstall()
			{
				base.OnInstall();
				NetworkManagerSystem.onClientConnectGlobal += OnClientConnectGlobal;
				NetworkManagerSystem.onClientDisconnectGlobal += OnClientDisconnectGlobal;
				NetworkManagerSystem.onStartServerGlobal += OnStartServerGlobal;
				NetworkManagerSystem.onStopServerGlobal += OnStopServerGlobal;
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onLobbyChanged = (Action)Delegate.Combine(lobbyManager.onLobbyChanged, new Action(OnLobbyChanged));
			}

			protected override void OnUninstall()
			{
				NetworkManagerSystem.onClientConnectGlobal -= OnClientConnectGlobal;
				NetworkManagerSystem.onClientDisconnectGlobal -= OnClientDisconnectGlobal;
				NetworkManagerSystem.onStartServerGlobal -= OnStartServerGlobal;
				NetworkManagerSystem.onStopServerGlobal -= OnStopServerGlobal;
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onLobbyChanged = (Action)Delegate.Remove(lobbyManager.onLobbyChanged, new Action(OnLobbyChanged));
				groupSizeField?.Uninstall();
				groupSizeField = null;
				base.OnUninstall();
			}

			protected override string RebuildValue()
			{
				if (groupId == PlatformID.nil)
				{
					return null;
				}
				return TextSerialization.ToStringInvariant(groupId.ID);
			}

			private void OnClientConnectGlobal(NetworkConnection conn)
			{
				if (conn is SteamNetworkConnection steamNetworkConnection)
				{
					hostId = steamNetworkConnection.steamId;
				}
			}

			private void OnClientDisconnectGlobal(NetworkConnection conn)
			{
				hostId = PlatformID.nil;
			}

			private void OnStartServerGlobal()
			{
				hostId = NetworkManagerSystem.singleton.serverP2PId;
			}

			private void OnStopServerGlobal()
			{
				hostId = PlatformID.nil;
			}

			private void OnLobbyChanged()
			{
				SetLobbyId(new PlatformID(Client.Instance.Lobby.CurrentLobby));
			}
		}

		private abstract class SteamPlayerGroupSizeField : BaseRichPresenceField
		{
			protected int groupSize;

			protected override string key => "steam_player_group_size";

			protected override string RebuildValue()
			{
				return TextSerialization.ToStringInvariant(groupSize);
			}
		}

		private sealed class SteamPlayerGroupSizeFieldLobby : SteamPlayerGroupSizeField
		{
			protected override void OnInstall()
			{
				base.OnInstall();
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onPlayerCountUpdated = (Action)Delegate.Combine(lobbyManager.onPlayerCountUpdated, new Action(UpdateGroupSize));
				UpdateGroupSize();
			}

			protected override void OnUninstall()
			{
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onPlayerCountUpdated = (Action)Delegate.Remove(lobbyManager.onPlayerCountUpdated, new Action(UpdateGroupSize));
				base.OnUninstall();
			}

			private void UpdateGroupSize()
			{
				SetDirtyableValue(ref groupSize, PlatformSystems.lobbyManager.calculatedTotalPlayerCount);
			}
		}

		private sealed class SteamPlayerGroupSizeFieldGame : SteamPlayerGroupSizeField
		{
			protected override void OnInstall()
			{
				base.OnInstall();
				NetworkUser.onNetworkUserDiscovered += OnNetworkUserDiscovered;
				NetworkUser.onNetworkUserLost += OnNetworkUserLost;
				UpdateGroupSize();
			}

			protected override void OnUninstall()
			{
				NetworkUser.onNetworkUserDiscovered -= OnNetworkUserDiscovered;
				NetworkUser.onNetworkUserLost -= OnNetworkUserLost;
				base.OnUninstall();
			}

			private void UpdateGroupSize()
			{
				SetDirtyableValue(ref groupSize, NetworkUser.readOnlyInstancesList.Count);
			}

			private void OnNetworkUserLost(NetworkUser networkuser)
			{
				UpdateGroupSize();
			}

			private void OnNetworkUserDiscovered(NetworkUser networkUser)
			{
				UpdateGroupSize();
			}
		}

		private sealed class SteamDisplayField : BaseRichPresenceField
		{
			protected override string key => "steam_display";

			protected override string RebuildValue()
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if ((bool)Run.instance)
				{
					if ((bool)GameOverController.instance)
					{
						return "#Display_GameOver";
					}
					return "#Display_InGame";
				}
				if ((bool)NetworkSession.instance)
				{
					return "#Display_PreGame";
				}
				if (SteamLobbyFinder.running)
				{
					return "#Display_Quickplay";
				}
				if (PlatformSystems.lobbyManager.isInLobby)
				{
					return "#Display_InLobby";
				}
				if (activeScene.name == "logbook")
				{
					return "#Display_Logbook";
				}
				return "#Display_MainMenu";
			}

			protected override void OnInstall()
			{
				base.OnInstall();
				RoR2Application.onUpdate += base.SetDirty;
			}

			protected override void OnUninstall()
			{
				RoR2Application.onUpdate -= base.SetDirty;
				base.OnUninstall();
			}
		}

		private const string rpDifficulty = "difficulty";

		private const string rpGameMode = "gamemode";

		private const string rpParticipationType = "participation_type";

		private const string rpMinutes = "minutes";

		private const string rpSteamPlayerGroupSize = "steam_player_group_size";

		private const string rpSteamPlayerGroup = "steam_player_group";

		private const string rpSteamDisplay = "steam_display";

		private static void SetKeyValue([NotNull] string key, [CanBeNull] string value)
		{
			if (Client.Instance != null && Client.Instance.User != null)
			{
				Client.Instance.User.SetRichPresence(key, value);
			}
		}

		public static void Init()
		{
			new DifficultyField().Install();
			new GameModeField().Install();
			new ParticipationField().Install();
			new MinutesField().Install();
			new SteamPlayerGroupField().Install();
			new SteamDisplayField().Install();
			RoR2Application.onUpdate += BaseRichPresenceField.ProcessDirtyFields;
		}
	}
	public class StreamingAssetsTextDataManager : TextDataManager
	{
		private readonly string configFolder;

		public override bool InitializedConfigFiles => true;

		public override bool InitializedLocFiles => true;

		public StreamingAssetsTextDataManager()
		{
			configFolder = System.IO.Path.Combine(Application.dataPath, "Config");
		}

		public override string GetConfFile(string fileName, string path)
		{
			if (RoR2Application.fileSystem != null)
			{
				using Stream stream = RoR2Application.fileSystem.OpenFile(path, FileMode.Open, FileAccess.Read);
				if (stream != null)
				{
					using (TextReader textReader = new StreamReader(stream))
					{
						return textReader.ReadToEnd();
					}
				}
			}
			return "";
		}

		public override void GetLocFiles(string folderPath, Action<string[]> callback)
		{
			List<string> list = new List<string>();
			foreach (string item in Directory.EnumerateFiles(folderPath))
			{
				if (string.Compare(System.IO.Path.GetFileName(item), "language.json", StringComparison.OrdinalIgnoreCase) != 0)
				{
					string extension = System.IO.Path.GetExtension(item);
					if (MatchesExtension(extension, ".txt") || MatchesExtension(extension, ".json"))
					{
						list.Add(item);
					}
				}
			}
			callback?.Invoke(list.ConvertAll((string x) => File.ReadAllText(x)).ToArray());
			static bool MatchesExtension(string fileExtension, string testExtension)
			{
				return string.Compare(fileExtension, testExtension, StringComparison.OrdinalIgnoreCase) == 0;
			}
		}
	}
	public abstract class TextDataManager
	{
		public abstract bool InitializedConfigFiles { get; }

		public abstract bool InitializedLocFiles { get; }

		public abstract string GetConfFile(string fileName, string path);

		public abstract void GetLocFiles(string folderPath, Action<string[]> callback);
	}
	public abstract class UserManager
	{
		public enum AvatarSize
		{
			Small,
			Medium,
			Large
		}

		public enum PlatformRestriction
		{
			VoiceChat,
			TextChat,
			Multiplayer,
			Age
		}

		public static BoolConVar P_UseSocialIcon = new BoolConVar("UseSocialIconFlag", ConVarFlags.Archive, "1", "A per-platform flag that indicates whether we display user icons or not.");

		public static event Action<int, Player> OnControllerAssigned;

		public static event Action<int, Player> OnControllerUnassigned;

		public static event Action OnUserStateChanged;

		public static event Action OnDisplayNameMappingComplete;

		internal void InvokeDisplayMappingCompleteAction()
		{
			UserManager.OnDisplayNameMappingComplete?.Invoke();
		}

		public abstract void GetAvatar(PlatformID userID, GameObject requestSender, Texture2D tex, AvatarSize size, Action<Texture2D> onRecieved);

		public virtual bool GetRestricted(PlatformID userID)
		{
			return false;
		}

		protected static Texture2D BuildTexture(Texture2D generatedTexture, int width, int height)
		{
			if ((bool)generatedTexture && (generatedTexture.width != width || generatedTexture.height != height))
			{
				generatedTexture.Reinitialize(width, height);
			}
			if (generatedTexture == null)
			{
				generatedTexture = new Texture2D(width, height);
			}
			return generatedTexture;
		}

		public virtual string GetUserDisplayName(PlatformID other)
		{
			return string.Empty;
		}

		public virtual bool ShouldHideOtherDisplayNames()
		{
			return false;
		}

		public virtual bool ShouldAlwaysUseCurrentDisplayName()
		{
			return false;
		}

		public virtual int GetUserID()
		{
			return 0;
		}

		public virtual string GetUserName()
		{
			return "";
		}

		public virtual string GetUserName(PlatformID id)
		{
			return "";
		}

		protected void NotifyUserStateChanged()
		{
			UserManager.OnUserStateChanged?.Invoke();
		}

		public static void NotifyControllerAssigned(int slot, Player player)
		{
			UserManager.OnControllerAssigned?.Invoke(slot, player);
		}

		public static void NotifyControllerUnassigned(int slot, Player player)
		{
			UserManager.OnControllerUnassigned?.Invoke(slot, player);
		}

		public virtual void EnableUserControllerHandling()
		{
		}

		public virtual bool CurrentUserHasRestriction(PlatformRestriction restriction, Action callback = null)
		{
			return false;
		}

		public virtual bool CurrentUserHasAgeRestriction()
		{
			return false;
		}

		public virtual void DisplayRestrictionMessage()
		{
		}
	}
	public class UserManagerDummy : UserManager
	{
		public override void GetAvatar(PlatformID userID, GameObject requestSender, Texture2D tex, AvatarSize size, Action<Texture2D> onRecieved)
		{
			onRecieved?.Invoke(null);
		}
	}
	public class UserProfile
	{
		public struct TutorialProgression
		{
			public uint showCount;

			public bool shouldShow;
		}

		public bool isClaimed;

		public bool canSave;

		public string fileName;

		public ulong saveID;

		public bool isInUse;

		public IFileSystem fileSystem;

		public UPath filePath = UPath.Empty;

		[SaveField]
		public string name;

		[SaveField]
		public uint coins;

		[SaveField]
		public uint totalCollectedCoins;

		[SaveField]
		public string version = "2";

		[SaveField]
		public float screenShakeScale = 1f;

		[SaveField]
		public float directionalDamageIndicatorScale;

		[SaveField]
		public bool increasedDifficultyBarFX;

		[SaveField]
		public bool useInspectFeature;

		[SaveField]
		public bool useInspectAutopause;

		[SaveField]
		public bool useToggleScoreboard;

		[SaveField]
		public bool useTeleporterParticleScaling;

		[SaveField]
		public bool useTeleporterDiscoveryIndicator;

		[SaveField(explicitSetupMethod = "SetupKeyboardMap")]
		public KeyboardMap keyboardMap = new KeyboardMap(DefaultControllerMaps.defaultKeyboardMap);

		[SaveField(explicitSetupMethod = "SetupMouseMap")]
		public MouseMap mouseMap = new MouseMap(DefaultControllerMaps.defaultMouseMap);

		[SaveField(explicitSetupMethod = "SetupJoystickMap")]
		public JoystickMap joystickMap = new JoystickMap(DefaultControllerMaps.DefaultJoystickMap);

		[SaveField(explicitSetupMethod = "SetupJoystickHardwareMap")]
		public Dictionary<Guid, JoystickMap> HardwareJoystickMaps2 = new Dictionary<Guid, JoystickMap>();

		[SaveField]
		public float mouseLookSensitivity = 0.25f;

		[SaveField]
		public float mouseLookScaleX = 1f;

		[SaveField]
		public float mouseLookScaleY = 1f;

		[SaveField]
		public bool mouseLookInvertX;

		[SaveField]
		public bool mouseLookInvertY;

		[SaveField]
		public float stickLookSensitivity = 4f;

		[SaveField]
		public float stickLookScaleX = 1f;

		[SaveField]
		public float stickLookScaleY = 1f;

		[SaveField]
		public int hudSizeMode;

		[SaveField]
		public bool gyroEnabled;

		[SaveField]
		public float gyroLookSensitivity = 1f;

		[SaveField]
		public float gyroLookScaleX = 1f;

		[SaveField]
		public float gyroLookScaleY = 0.65f;

		[SaveField]
		public bool gyroLookInvertX;

		[SaveField]
		public bool gyroLookInvertY;

		[SaveField]
		public bool gyroDisabledDuringSprint = true;

		[SaveField]
		public bool gyroDisabledDuringSprint_Huntress;

		[SaveField]
		public bool gyroDisabledDuringSprint_Melee;

		[SaveField]
		public bool toggleArtificerHover = true;

		[SaveField]
		public bool toggleSeekerSojourn = true;

		[SaveField]
		public bool stickLookInvertX;

		[SaveField]
		public bool stickLookInvertY;

		[SaveField]
		public float gamepadVibrationScale = 1f;

		[SaveField]
		public bool aimAssistEnabled = true;

		[SaveField]
		public float aimAssistSensitivity = 6f;

		[SaveField]
		public bool disableItemDisplays;

		[SaveField]
		public float inputAimAssistSensitivity = 4f;

		[SaveField]
		public float mouseTrajectoryAimAssistSensitivity;

		[SaveField]
		public float gamePadTrajectoryAimAssistSensitivity = 4f;

		public bool saveRequestPending;

		private static string[] saveFieldNames;

		public static SaveFieldAttribute[] saveFields;

		private static readonly Dictionary<string, SaveFieldAttribute> nameToSaveFieldMap = new Dictionary<string, SaveFieldAttribute>();

		public static UserProfile defaultProfile;

		[SaveField(explicitSetupMethod = "SetupTokenList")]
		public List<string> viewedUnlockablesList = new List<string>();

		[SaveField(explicitSetupMethod = "SetupPickupsSet")]
		private readonly bool[] discoveredPickups = PickupCatalog.GetPerPickupBuffer<bool>();

		public Action<PickupIndex> onPickupDiscovered;

		public Action onStatsReceived;

		[SaveField(explicitSetupMethod = "SetupTokenList")]
		private List<string> achievementsList = new List<string>();

		[SaveField(explicitSetupMethod = "SetupTokenList")]
		private List<string> unviewedAchievementsList = new List<string>();

		public StatSheet statSheet = StatSheet.New();

		private const uint maxShowCount = 3u;

		public TutorialProgression tutorialDifficulty;

		public TutorialProgression tutorialSprint;

		public TutorialProgression tutorialEquipment;

		[SaveField]
		private SurvivorDef survivorPreference = SurvivorCatalog.defaultSurvivor;

		public readonly Loadout loadout = new Loadout();

		[SaveField]
		public uint totalLoginSeconds;

		[SaveField]
		public uint totalRunSeconds;

		[SaveField]
		public uint totalAliveSeconds;

		[SaveField]
		public uint totalRunCount;

		private bool ownsPortrait;

		[SaveField]
		public bool chefAchievementIngredient1;

		[SaveField]
		public bool chefAchievementIngredient2;

		[SaveField]
		public bool chefAchievementIngredient3;

		[SaveField]
		public string RebirthItem;

		private const string defaultProfileContents = "<UserProfile>\r\n  <name>Survivor</name>\r\n  <mouseLookSensitivity>0.2</mouseLookSensitivity>\r\n  <mouseLookScaleX>1</mouseLookScaleX>\r\n  <mouseLookScaleY>1</mouseLookScaleY>\r\n  <stickLookSensitivity>5</stickLookSensitivity>\r\n  <stickLookScaleX>1</stickLookScaleX>\r\n  <stickLookScaleY>1</stickLookScaleY>\r\n <inputAimAssistSensitivity>4</inputAimAssistSensitivity>\r\n <mouseTrajectoryAimAssistSensitivity>0</mouseTrajectoryAimAssistSensitivity>\r\n <gamePadTrajectoryAimAssistSensitivity>4</gamePadTrajectoryAimAssistSensitivity>\r\n</UserProfile>";

		[SaveField(defaultValue = "", explicitSetupMethod = "SetupTokenList", fieldName = "viewedViewables")]
		private readonly List<string> viewedViewables = new List<string>();

		public bool isCorrupted { get; set; }

		public bool hasUnviewedAchievement => unviewedAchievementsList.Count > 0;

		public bool loggedIn { get; set; }

		public Texture portraitTexture { get; private set; }

		public event Action onSurvivorPreferenceChanged;

		public static event Action<UserProfile> onSurvivorPreferenceChangedGlobal;

		public event Action onLoadoutChanged;

		public static event Action<UserProfile> onLoadoutChangedGlobal;

		public static event Action<UserProfile, UnlockableDef> onUnlockableGranted;

		public static event Action<UserProfile> onUserProfileViewedViewablesChanged;

		public void FillDefaultJoystickMaps()
		{
			Dictionary<Guid, JoystickMap> defaultJoystickMaps = DefaultControllerMaps.GetDefaultJoystickMaps();
			if (defaultJoystickMaps == null)
			{
				return;
			}
			foreach (KeyValuePair<Guid, JoystickMap> item in defaultJoystickMaps)
			{
				DefaultControllerMaps.RewiredDebugLog($"FillDefaultJoystickMaps> Guid {item.Key} --- {item.Value.ToXmlString()}");
				HardwareJoystickMaps2.Add(item.Key, item.Value);
				LocalUser.DumpControllerMap(item.Value);
			}
		}

		public JoystickMap GetJoystickMap(Guid inControllerGuid)
		{
			if (HardwareJoystickMaps2.Count == 0)
			{
				FillDefaultJoystickMaps();
			}
			if (HardwareJoystickMaps2.ContainsKey(inControllerGuid))
			{
				DefaultControllerMaps.RewiredDebugLog($"***** GetJoystickMap: return controller for guid {inControllerGuid}");
				return new JoystickMap(HardwareJoystickMaps2[inControllerGuid]);
			}
			if (inControllerGuid == DefaultControllerMaps.xboneControllerGuid && HardwareJoystickMaps2.ContainsKey(DefaultControllerMaps.xbox360ControllerGuid))
			{
				DefaultControllerMaps.RewiredDebugWarn("***** GetJoystickMap: Failed to find guid {0}... returning Xbox360 mapping (XInput detected)", inControllerGuid);
				return new JoystickMap(HardwareJoystickMaps2[DefaultControllerMaps.xbox360ControllerGuid]);
			}
			if (inControllerGuid == DefaultControllerMaps.xbox360ControllerGuid && HardwareJoystickMaps2.ContainsKey(DefaultControllerMaps.xboneControllerGuid))
			{
				DefaultControllerMaps.RewiredDebugWarn("***** GetJoystickMap: Failed to find guid {0}... returning Xbone mapping (XInput detected)", inControllerGuid);
				return new JoystickMap(HardwareJoystickMaps2[DefaultControllerMaps.xboneControllerGuid]);
			}
			if (HardwareJoystickMaps2.ContainsKey(PlatformManager.DefaultControllerGuid))
			{
				DefaultControllerMaps.RewiredDebugWarn("***** GetJoystickMap: Failed to find guid {0}... returning default", inControllerGuid);
				return new JoystickMap(HardwareJoystickMaps2[PlatformManager.DefaultControllerGuid]);
			}
			return null;
		}

		public void SwitchJoystickMap(Guid inNewControllerGuid)
		{
			DefaultControllerMaps.RewiredDebugLog($"***** SwitchJoystickMap: From {this.joystickMap.hardwareGuid} to {inNewControllerGuid}");
			JoystickMap joystickMap = GetJoystickMap(inNewControllerGuid);
			if (joystickMap != null)
			{
				this.joystickMap = joystickMap;
			}
		}

		public void UpdateJoystickMap(Guid inControllerGuid, JoystickMap inJoystickMap)
		{
			if (!HardwareJoystickMaps2.ContainsKey(inControllerGuid))
			{
				DefaultControllerMaps.RewiredDebugWarn($"***** UpdateJoystickMap: {inControllerGuid} not found!");
				return;
			}
			HardwareJoystickMaps2[inControllerGuid] = inJoystickMap;
			if (inControllerGuid == joystickMap.hardwareGuid)
			{
				SwitchJoystickMap(inControllerGuid);
			}
		}

		public void UpdateKeyboardMap(KeyboardMap inKeyboardMap)
		{
			keyboardMap = inKeyboardMap;
		}

		public void UpdateMouseMap(MouseMap inMouseMap)
		{
			mouseMap = inMouseMap;
		}

		public static void GenerateSaveFieldFunctions()
		{
			nameToSaveFieldMap.Clear();
			FieldInfo[] fields = typeof(UserProfile).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				SaveFieldAttribute customAttribute = CustomAttributeExtensions.GetCustomAttribute<SaveFieldAttribute>(fieldInfo);
				if (customAttribute != null)
				{
					customAttribute.Setup(fieldInfo);
					nameToSaveFieldMap[fieldInfo.Name] = customAttribute;
				}
			}
			saveFieldNames = nameToSaveFieldMap.Keys.ToArray();
			Array.Sort(saveFieldNames);
			saveFields = saveFieldNames.Select((string name) => nameToSaveFieldMap[name]).ToArray();
		}

		public void SetSaveFieldString([NotNull] string fieldName, [NotNull] string value)
		{
			if (nameToSaveFieldMap.TryGetValue(fieldName, out var value2))
			{
				value2.setter(this, value);
				return;
			}
			UnityEngine.Debug.LogErrorFormat("Save field {0} is not defined.", fieldName);
		}

		public string GetSaveFieldString([NotNull] string fieldName)
		{
			if (nameToSaveFieldMap.TryGetValue(fieldName, out var value))
			{
				return value.getter(this);
			}
			UnityEngine.Debug.LogErrorFormat("Save field {0} is not defined.", fieldName);
			return string.Empty;
		}

		public static XDocument ToXml(UserProfile userProfile)
		{
			return XmlUtility.ToXml(userProfile);
		}

		public static UserProfile FromXml(XDocument doc)
		{
			return XmlUtility.FromXml(doc);
		}

		public bool HasUnlockable([NotNull] string unlockableToken)
		{
			UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(unlockableToken);
			if (!(unlockableDef == null))
			{
				return HasUnlockable(unlockableDef);
			}
			return true;
		}

		public bool HasUnlockable([CanBeNull] UnlockableDef unlockableDef)
		{
			return statSheet.HasUnlockable(unlockableDef);
		}

		public void AddUnlockToken(string unlockableToken)
		{
			UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(unlockableToken);
			if (unlockableDef != null)
			{
				GrantUnlockable(unlockableDef);
			}
		}

		public void GrantUnlockable(UnlockableDef unlockableDef)
		{
			if (!statSheet.HasUnlockable(unlockableDef))
			{
				statSheet.AddUnlockable(unlockableDef);
				UnityEngine.Debug.LogFormat("{0} unlocked {1}", name, unlockableDef.nameToken);
				RequestEventualSave();
				UserProfile.onUnlockableGranted?.Invoke(this, unlockableDef);
			}
		}

		public void RequestEventualSave()
		{
			if (canSave)
			{
				saveRequestPending = true;
			}
		}

		public void RevokeUnlockable(UnlockableDef unlockableDef)
		{
			if (statSheet.HasUnlockable(unlockableDef))
			{
				statSheet.RemoveUnlockable(unlockableDef.index);
				UnityEngine.Debug.LogFormat("{0} had {1} revoked", name, unlockableDef.nameToken);
				RequestEventualSave();
			}
		}

		public bool HasSurvivorUnlocked(SurvivorIndex survivorIndex)
		{
			SurvivorDef survivorDef = SurvivorCatalog.GetSurvivorDef(survivorIndex);
			if (survivorDef == null)
			{
				return false;
			}
			if (!survivorDef.unlockableDef)
			{
				return true;
			}
			return HasUnlockable(survivorDef.unlockableDef);
		}

		public bool HasDiscoveredPickup(PickupIndex pickupIndex)
		{
			if (pickupIndex.isValid)
			{
				return discoveredPickups[pickupIndex.value];
			}
			return false;
		}

		public void DiscoverPickup(PickupIndex pickupIndex)
		{
			SetPickupDiscovered(pickupIndex, newDiscovered: true);
		}

		private void SetPickupDiscovered(PickupIndex pickupIndex, bool newDiscovered)
		{
			if (!pickupIndex.isValid)
			{
				return;
			}
			ref bool reference = ref discoveredPickups[pickupIndex.value];
			if (reference != newDiscovered)
			{
				reference = newDiscovered;
				if (newDiscovered)
				{
					onPickupDiscovered?.Invoke(pickupIndex);
					RequestEventualSave();
				}
			}
		}

		[ConCommand(commandName = "user_profile_set_pickup_discovered", flags = ConVarFlags.Cheat, helpText = "Sets the pickup discovery state for the sender's profile.")]
		private static void CCUserProfileSetPickupDiscovered(ConCommandArgs args)
		{
			UserProfile userProfile = args.GetSenderLocalUser().userProfile;
			IEnumerable<PickupIndex> enumerable = null;
			enumerable = (IEnumerable<PickupIndex>)((!(args.TryGetArgString(0) == "all")) ? new PickupIndex[1] { args.GetArgPickupIndex(0) } : ((object)PickupCatalog.allPickupIndices));
			bool argBool = args.GetArgBool(1);
			foreach (PickupIndex item in enumerable)
			{
				userProfile.SetPickupDiscovered(item, argBool);
			}
		}

		public bool HasAchievement(string achievementName)
		{
			return achievementsList.Contains(achievementName);
		}

		public bool CanSeeAchievement(string achievementName)
		{
			if (HasAchievement(achievementName))
			{
				return true;
			}
			AchievementDef achievementDef = AchievementManager.GetAchievementDef(achievementName);
			if (achievementDef != null)
			{
				if (string.IsNullOrEmpty(achievementDef.prerequisiteAchievementIdentifier))
				{
					return true;
				}
				return HasAchievement(achievementDef.prerequisiteAchievementIdentifier);
			}
			return false;
		}

		public void AddAchievement(string achievementName, bool isExternal)
		{
			achievementsList.Add(achievementName);
			unviewedAchievementsList.Add(achievementName);
			if (isExternal)
			{
				PlatformSystems.achievementSystem.AddAchievement(achievementName);
			}
			RequestEventualSave();
		}

		public void RevokeAchievement(string achievementName)
		{
			achievementsList.Remove(achievementName);
			unviewedAchievementsList.Remove(achievementName);
			RequestEventualSave();
		}

		public string PopNextUnviewedAchievementName()
		{
			if (unviewedAchievementsList.Count == 0)
			{
				return null;
			}
			string result = unviewedAchievementsList[0];
			unviewedAchievementsList.RemoveAt(0);
			return result;
		}

		public void ClearAllAchievementNotifications()
		{
			unviewedAchievementsList.Clear();
		}

		public void ApplyDeltaStatSheet(StatSheet deltaStatSheet)
		{
			int i = 0;
			for (int unlockableCount = deltaStatSheet.GetUnlockableCount(); i < unlockableCount; i++)
			{
				GrantUnlockable(deltaStatSheet.GetUnlockable(i));
			}
			for (int j = 0; j < deltaStatSheet.fields.Length; j++)
			{
				if (deltaStatSheet.fields[j].hasChanged)
				{
					deltaStatSheet.fields[j].statDef.onChangeCallback?.Invoke();
				}
			}
			statSheet.ApplyDelta(deltaStatSheet);
			onStatsReceived?.Invoke();
		}

		[ConCommand(commandName = "user_profile_stats_stress_test", flags = ConVarFlags.Cheat, helpText = "Sets the stats of the sender's user profile to the maximum their datatypes support for stress-testing purposes.")]
		private static void CCUserProfileStatsStressTest(ConCommandArgs args)
		{
			LocalUser senderLocalUser = args.GetSenderLocalUser();
			senderLocalUser.userProfile.statSheet.SetAllFieldsToMaxValue();
			PlatformSystems.saveSystem.Save(senderLocalUser.userProfile, blocking: true);
		}

		private void ResetShouldShowTutorial(ref TutorialProgression tutorialProgression)
		{
			tutorialProgression.shouldShow = tutorialProgression.showCount < 3;
		}

		private void RebuildTutorialProgressions()
		{
			ResetShouldShowTutorial(ref tutorialDifficulty);
			ResetShouldShowTutorial(ref tutorialSprint);
			ResetShouldShowTutorial(ref tutorialEquipment);
		}

		[NotNull]
		public SurvivorDef GetSurvivorPreference()
		{
			return survivorPreference;
		}

		public void SetSurvivorPreference([NotNull] SurvivorDef newSurvivorPreference)
		{
			if (!newSurvivorPreference)
			{
				throw new ArgumentException("Provided object is null or invalid", "newSurvivorPreference");
			}
			if ((object)survivorPreference != newSurvivorPreference)
			{
				survivorPreference = newSurvivorPreference;
				this.onSurvivorPreferenceChanged?.Invoke();
				UserProfile.onSurvivorPreferenceChangedGlobal?.Invoke(this);
			}
		}

		public void OnLoadoutChanged()
		{
			this.onLoadoutChanged?.Invoke();
			UserProfile.onLoadoutChangedGlobal?.Invoke(this);
			RequestEventualSave();
		}

		public void CopyLoadout(Loadout dest)
		{
			loadout.Copy(dest);
		}

		public void SetLoadout(Loadout newLoadout)
		{
			if (!loadout.ValueEquals(newLoadout))
			{
				newLoadout.Copy(loadout);
				OnLoadoutChanged();
			}
		}

		[ConCommand(commandName = "loadout_set_skill_variant", flags = (ConVarFlags.ExecuteOnServer | ConVarFlags.Cheat), helpText = "loadout_set_skill_variant [body_name] [skill_slot_index] [skill_variant_index]\nSets the skill variant for the sender's user profile.")]
		private static void CCLoadoutSetSkillVariant(ConCommandArgs args)
		{
			BodyIndex argBodyIndex = args.GetArgBodyIndex(0);
			int argInt = args.GetArgInt(1);
			int argInt2 = args.GetArgInt(2);
			UserProfile userProfile = args.GetSenderLocalUser().userProfile;
			Loadout loadout = new Loadout();
			userProfile.loadout.Copy(loadout);
			loadout.bodyLoadoutManager.SetSkillVariant(argBodyIndex, argInt, (uint)argInt2);
			userProfile.SetLoadout(loadout);
			if ((bool)args.senderMaster)
			{
				args.senderMaster.SetLoadoutServer(loadout);
			}
			if ((bool)args.senderBody)
			{
				args.senderBody.SetLoadoutServer(loadout);
			}
		}

		public void OnLogin()
		{
			if (loggedIn)
			{
				UnityEngine.Debug.LogErrorFormat("Profile {0} is already logged in!", fileName);
				return;
			}
			loggedIn = true;
			PlatformSystems.saveSystem.loggedInProfiles.Add(this);
			RebuildTutorialProgressions();
			foreach (string achievements in achievementsList)
			{
				PlatformSystems.achievementSystem.AddAchievement(achievements);
				UserProfile userProfile = LocalUserManager.GetFirstLocalUser().userProfile;
				if (userProfile != null && userProfile == this)
				{
					BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
					baseActivitySelector.activityAchievementID = achievements;
					PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
				}
			}
			LoadPortrait();
		}

		public void OnLogout()
		{
			if (!loggedIn)
			{
				UnityEngine.Debug.LogErrorFormat("Profile {0} is already logged out!", fileName);
				return;
			}
			UnloadPortrait();
			loggedIn = false;
			if (canSave)
			{
				PlatformSystems.saveSystem.Save(this, blocking: true);
			}
			PlatformSystems.saveSystem.loggedInProfiles.Remove(this);
		}

		private void LoadPortrait()
		{
			Texture2D newPortraitTexture = new Texture2D(184, 184, TextureFormat.ARGB32, mipChain: false, linear: false);
			portraitTexture = newPortraitTexture;
			ownsPortrait = true;
			Client.Instance.Friends.GetAvatar(Friends.AvatarSize.Large, Client.Instance.SteamId, LoadSteamImage);
			void LoadSteamImage(Facepunch.Steamworks.Image image)
			{
				if (image?.Data != null && (bool)newPortraitTexture && !(newPortraitTexture != portraitTexture))
				{
					byte[] data = image.Data;
					Color32[] array = new Color32[data.Length / 4];
					int width = image.Width;
					int height = image.Height;
					newPortraitTexture.Reinitialize(width, height);
					for (int i = 0; i < height; i++)
					{
						int num = height - 1 - i;
						for (int j = 0; j < width; j++)
						{
							int num2 = (i * width + j) * 4;
							array[num * width + j] = new Color32(data[num2], data[num2 + 1], data[num2 + 2], data[num2 + 3]);
						}
					}
					newPortraitTexture.SetPixels32(array);
					newPortraitTexture.Apply();
				}
			}
		}

		public void ReloadPortrait()
		{
			RoR2Application.onUpdate -= ReloadPortrait;
			if (loggedIn)
			{
				LoadPortrait();
			}
		}

		private void UnloadPortrait()
		{
			if (ownsPortrait)
			{
				UnityEngine.Object.Destroy(portraitTexture);
				portraitTexture = null;
				ownsPortrait = false;
			}
		}

		[ConCommand(commandName = "revert_chef_achievement_tracking_bools", flags = ConVarFlags.Cheat, helpText = "Reverts the bools associated with the chef achievement ingredient tracking.")]
		private static void CCRevertChefAchievementTrackingBools(ConCommandArgs args)
		{
			LocalUser senderLocalUser = args.GetSenderLocalUser();
			senderLocalUser.userProfile.chefAchievementIngredient1 = false;
			senderLocalUser.userProfile.chefAchievementIngredient2 = false;
			senderLocalUser.userProfile.chefAchievementIngredient3 = false;
		}

		[ConCommand(commandName = "empty_rebirth_items", flags = ConVarFlags.Cheat, helpText = "Empties rebirth items stored in user's profile.")]
		private static void CCEmptyRebirthItems(ConCommandArgs args)
		{
			args.GetSenderLocalUser().userProfile.RebirthItem = null;
		}

		[ConCommand(commandName = "give_rebirth_reward", flags = ConVarFlags.Cheat, helpText = "gives rebirth items")]
		private static void CCGiveRebirth(ConCommandArgs args)
		{
			LocalUser senderLocalUser = args.GetSenderLocalUser();
			if (args.userArgs.Count > 0)
			{
				PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(args.GetArgItemIndex(0));
				if (!(pickupIndex != PickupIndex.none))
				{
					return;
				}
				senderLocalUser.userProfile.RebirthItem = PickupCatalog.GetPickupDef(pickupIndex).internalName;
			}
			else
			{
				senderLocalUser.userProfile.RebirthItem = PickupCatalog.GetPickupDef(new PickupIndex(UnityEngine.Random.Range(0, ItemCatalog.itemCount))).internalName;
			}
			senderLocalUser.userProfile.AddUnlockToken("Artifacts.Rebirth");
		}

		public static void LoadDefaultProfile()
		{
			defaultProfile = XmlUtility.FromXml(XDocument.Parse("<UserProfile>\r\n  <name>Survivor</name>\r\n  <mouseLookSensitivity>0.2</mouseLookSensitivity>\r\n  <mouseLookScaleX>1</mouseLookScaleX>\r\n  <mouseLookScaleY>1</mouseLookScaleY>\r\n  <stickLookSensitivity>5</stickLookSensitivity>\r\n  <stickLookScaleX>1</stickLookScaleX>\r\n  <stickLookScaleY>1</stickLookScaleY>\r\n <inputAimAssistSensitivity>4</inputAimAssistSensitivity>\r\n <mouseTrajectoryAimAssistSensitivity>0</mouseTrajectoryAimAssistSensitivity>\r\n <gamePadTrajectoryAimAssistSensitivity>4</gamePadTrajectoryAimAssistSensitivity>\r\n</UserProfile>"));
			defaultProfile.canSave = false;
		}

		public bool HasViewedViewable(string viewableName)
		{
			return viewedViewables.Contains(viewableName);
		}

		public void MarkViewableAsViewed(string viewableName)
		{
			if (!HasViewedViewable(viewableName))
			{
				viewedViewables.Add(viewableName);
				UserProfile.onUserProfileViewedViewablesChanged?.Invoke(this);
				RequestEventualSave();
			}
		}

		public void ClearAllViewablesAsViewed()
		{
			viewedViewables.Clear();
			UserProfile.onUserProfileViewedViewablesChanged?.Invoke(this);
			RequestEventualSave();
		}
	}
	public abstract class VoiceChatManager
	{
		public abstract bool IsVoiceChatEnabled { get; }

		public abstract PlatformID LocalUser { get; }

		public abstract bool IsPlayerLocalMuted(PlatformID id);

		public abstract bool IsPlayerMicAccessAvailable(PlatformID id);

		public abstract bool IsPlayerSpeaking(PlatformID id);

		public abstract bool IsPlayerBlocked(PlatformID id);

		public abstract void ToggleMutePlayer(PlatformID id);

		public virtual void SetMuteForPlayer(PlatformID id, bool muted)
		{
		}
	}
	public static class XmlUtility
	{
		private static XElement CreateStringField(string name, string value)
		{
			return new XElement(name, value);
		}

		private static XElement CreateUintField(string name, uint value)
		{
			return new XElement(name, TextSerialization.ToStringInvariant(value));
		}

		private static XElement CreateStatsField(string name, StatSheet statSheet)
		{
			XElement xElement = new XElement(name);
			for (int i = 0; i < statSheet.fields.Length; i++)
			{
				XElement xElement2 = new XElement("stat", new XText(statSheet.fields[i].ToString()));
				xElement2.SetAttributeValue("name", statSheet.fields[i].name);
				xElement.Add(xElement2);
			}
			int unlockableCount = statSheet.GetUnlockableCount();
			for (int j = 0; j < unlockableCount; j++)
			{
				UnlockableDef unlockable = statSheet.GetUnlockable(j);
				XElement content = new XElement("unlock", new XText(unlockable.cachedName));
				xElement.Add(content);
			}
			return xElement;
		}

		private static XElement CreateLoadoutField(string name, Loadout loadout)
		{
			return loadout.ToXml(name);
		}

		private static uint GetUintField(XElement container, string fieldName, uint defaultValue)
		{
			XElement xElement = container.Element(fieldName);
			if (xElement != null)
			{
				XNode firstNode = xElement.FirstNode;
				if (firstNode != null && firstNode.NodeType == XmlNodeType.Text)
				{
					if (!TextSerialization.TryParseInvariant(((XText)firstNode).Value, out uint result))
					{
						return defaultValue;
					}
					return result;
				}
			}
			return defaultValue;
		}

		private static string GetStringField(XElement container, string fieldName, string defaultValue)
		{
			XElement xElement = container.Element(fieldName);
			if (xElement != null)
			{
				XNode firstNode = xElement.FirstNode;
				if (firstNode != null && firstNode.NodeType == XmlNodeType.Text)
				{
					return ((XText)firstNode).Value;
				}
			}
			return defaultValue;
		}

		private static void GetStatsField(XElement container, string fieldName, StatSheet dest)
		{
			XElement xElement = container.Element(fieldName);
			if (xElement == null)
			{
				return;
			}
			foreach (XElement item in from element in xElement.Elements()
				where element.Name == "stat"
				select element)
			{
				string statName = item.Attributes().FirstOrDefault((XAttribute attribute) => attribute.Name == "name")?.Value;
				string value = (item.Nodes().FirstOrDefault((XNode node) => node.NodeType == XmlNodeType.Text) as XText)?.Value;
				dest.SetStatValueFromString(StatDef.Find(statName), value);
			}
			foreach (XElement item2 in from element in xElement.Elements()
				where element.Name == "unlock"
				select element)
			{
				UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef((item2.Nodes().FirstOrDefault((XNode node) => node.NodeType == XmlNodeType.Text) as XText)?.Value);
				if (unlockableDef != null)
				{
					dest.AddUnlockable(unlockableDef);
				}
			}
		}

		private static void GetLoadoutField(XElement container, string fieldName, Loadout dest)
		{
			XElement xElement = container.Element(fieldName);
			if (xElement != null)
			{
				Loadout loadout = new Loadout();
				if (loadout.FromXml(xElement))
				{
					loadout.Copy(dest);
				}
			}
		}

		public static XDocument ToXml(UserProfile userProfile)
		{
			object[] array = new object[UserProfile.saveFields.Length];
			for (int i = 0; i < UserProfile.saveFields.Length; i++)
			{
				SaveFieldAttribute saveFieldAttribute = UserProfile.saveFields[i];
				array[i] = CreateStringField(saveFieldAttribute.fieldName, saveFieldAttribute.getter(userProfile));
			}
			object[] element = new object[5]
			{
				CreateStatsField("stats", userProfile.statSheet),
				CreateUintField("tutorialDifficulty", userProfile.tutorialDifficulty.showCount),
				CreateUintField("tutorialEquipment", userProfile.tutorialEquipment.showCount),
				CreateUintField("tutorialSprint", userProfile.tutorialSprint.showCount),
				CreateLoadoutField("loadout", userProfile.loadout)
			};
			return new XDocument(new XElement("UserProfile", array.Append(element).ToArray()));
		}

		public static UserProfile FromXml(XDocument doc)
		{
			UserProfile userProfile = new UserProfile();
			XElement root = doc.Root;
			SaveFieldAttribute[] saveFields = UserProfile.saveFields;
			foreach (SaveFieldAttribute saveFieldAttribute in saveFields)
			{
				string stringField = GetStringField(root, saveFieldAttribute.fieldName, null);
				if (stringField != null)
				{
					saveFieldAttribute.setter(userProfile, stringField);
				}
			}
			GetStatsField(root, "stats", userProfile.statSheet);
			GetLoadoutField(root, "loadout", userProfile.loadout);
			userProfile.tutorialDifficulty.showCount = GetUintField(root, "tutorialDifficulty", userProfile.tutorialDifficulty.showCount);
			userProfile.tutorialEquipment.showCount = GetUintField(root, "tutorialEquipment", userProfile.tutorialEquipment.showCount);
			userProfile.tutorialSprint.showCount = GetUintField(root, "tutorialSprint", userProfile.tutorialSprint.showCount);
			return userProfile;
		}
	}
	public class PortalDialerButtonController : NetworkBehaviour
	{
		[SyncVar(hook = "OnSyncDigitIndex")]
		public byte currentDigitIndex = 1;

		public GameObject holderObject;

		public GameObject swapEffect;

		public ArtifactCompoundDef[] digitDefs;

		private GameObject modelInstance;

		public ArtifactCompoundDef currentDigitDef => digitDefs[currentDigitIndex];

		public byte NetworkcurrentDigitIndex
		{
			get
			{
				return currentDigitIndex;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncDigitIndex(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref currentDigitIndex, 1u);
			}
		}

		private void OnSyncDigitIndex(byte newDigitIndex)
		{
			NetworkcurrentDigitIndex = newDigitIndex;
			if ((bool)modelInstance)
			{
				UnityEngine.Object.Destroy(modelInstance);
			}
			if ((bool)swapEffect)
			{
				swapEffect.SetActive(value: false);
				swapEffect.SetActive(value: true);
			}
			if ((bool)currentDigitDef.modelPrefab)
			{
				modelInstance = UnityEngine.Object.Instantiate(currentDigitDef.modelPrefab, holderObject.transform);
			}
		}

		public override void OnStartClient()
		{
			base.OnStartClient();
			OnSyncDigitIndex(currentDigitIndex);
		}

		[Server]
		public void CycleDigitServer()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.PortalDialerButtonController::CycleDigitServer()' called on client");
				return;
			}
			byte b = (byte)(currentDigitIndex + 1);
			if (b >= digitDefs.Length)
			{
				b = 1;
			}
			NetworkcurrentDigitIndex = b;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32(currentDigitIndex);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(currentDigitIndex);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				currentDigitIndex = (byte)reader.ReadPackedUInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncDigitIndex((byte)reader.ReadPackedUInt32());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	public class PrefabReferenceAttribute : PropertyAttribute
	{
	}
	public enum ProcType : uint
	{
		Behemoth,
		Missile,
		AACannon,
		ChainLightning,
		PlasmaCore,
		BleedOnHit,
		HealOnHit,
		BounceNearby,
		HealOnCrit,
		CritHeal,
		HealNova,
		LunarPotionActivation,
		Rings,
		RepeatHeal,
		LoaderLightning,
		Thorns,
		Meatball,
		Backstab,
		LightningStrikeOnHit,
		FractureOnHit,
		MicroMissile,
		VoidSurvivorCrush,
		MeteorAttackOnHighDamage,
		StunAndPierceDamage,
		Count
	}
	[Serializable]
	public struct ProcChainMask : IEquatable<ProcChainMask>
	{
		[SerializeField]
		public uint mask;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		public void AddProc(ProcType procType)
		{
			mask |= (uint)(1 << (int)procType);
		}

		public void RemoveProc(ProcType procType)
		{
			mask &= (uint)(~(1 << (int)procType));
		}

		public bool HasProc(ProcType procType)
		{
			return (mask & (1 << (int)procType)) != 0;
		}

		private static bool StaticCheck()
		{
			return true;
		}

		public bool Equals(ProcChainMask other)
		{
			return mask == other.mask;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is ProcChainMask)
			{
				return Equals((ProcChainMask)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return mask.GetHashCode();
		}

		public override string ToString()
		{
			AppendToStringBuilder(sharedStringBuilder);
			string result = sharedStringBuilder.ToString();
			sharedStringBuilder.Clear();
			return result;
		}

		public void AppendToStringBuilder(StringBuilder stringBuilder)
		{
			stringBuilder.Append("(");
			bool flag = false;
			for (ProcType procType = ProcType.Behemoth; procType < ProcType.Count; procType++)
			{
				if (HasProc(procType))
				{
					if (flag)
					{
						stringBuilder.Append("|");
					}
					stringBuilder.Append(procType.ToString());
					flag = true;
				}
			}
			stringBuilder.Append(")");
		}
	}
	public static class ProjectileCatalog
	{
		private static GameObject[] projectilePrefabs = Array.Empty<GameObject>();

		private static ProjectileController[] projectilePrefabProjectileControllerComponents = Array.Empty<ProjectileController>();

		private static string[] projectileNames = Array.Empty<string>();

		public static int projectilePrefabCount => projectilePrefabs.Length;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<GameObject>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.ProjectileCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.projectilePrefabs);
			}
			remove
			{
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetProjectilePrefabs(ContentManager.projectilePrefabs);
		}

		private static void SetProjectilePrefabs(GameObject[] newProjectilePrefabs)
		{
			ProjectileController[] array = projectilePrefabProjectileControllerComponents;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].catalogIndex = -1;
			}
			ArrayUtils.CloneTo(newProjectilePrefabs, ref projectilePrefabs);
			Array.Sort(projectilePrefabs, (GameObject a, GameObject b) => string.CompareOrdinal(a.name, b.name));
			int num = 256;
			if (projectilePrefabs.Length > num)
			{
				UnityEngine.Debug.LogErrorFormat("Cannot have more than {0} projectile prefabs defined, which is over the limit for {1}. Check comments at error source for details.", num, typeof(byte).Name);
				for (int j = num; j < projectilePrefabs.Length; j++)
				{
					UnityEngine.Debug.LogErrorFormat("Could not register projectile [{0}/{1}]=\"{2}\"", j, num - 1, projectilePrefabs[j].name);
				}
			}
			Array.Resize(ref projectilePrefabProjectileControllerComponents, projectilePrefabs.Length);
			Array.Resize(ref projectileNames, projectilePrefabs.Length);
			for (int k = 0; k < projectilePrefabs.Length; k++)
			{
				GameObject gameObject = projectilePrefabs[k];
				ProjectileController component = gameObject.GetComponent<ProjectileController>();
				component.catalogIndex = k;
				projectilePrefabProjectileControllerComponents[k] = component;
				projectileNames[k] = gameObject.name;
			}
		}

		public static int GetProjectileIndex(GameObject projectileObject)
		{
			if ((bool)projectileObject)
			{
				return GetProjectileIndex(projectileObject.GetComponent<ProjectileController>());
			}
			return -1;
		}

		public static int GetProjectileIndex(ProjectileController projectileController)
		{
			if (!projectileController)
			{
				return -1;
			}
			return projectileController.catalogIndex;
		}

		public static GameObject GetProjectilePrefab(int projectileIndex)
		{
			return ArrayUtils.GetSafe(projectilePrefabs, projectileIndex);
		}

		public static ProjectileController GetProjectilePrefabProjectileControllerComponent(int projectileIndex)
		{
			return ArrayUtils.GetSafe(projectilePrefabProjectileControllerComponents, projectileIndex);
		}

		public static int FindProjectileIndex(string projectileName)
		{
			return Array.IndexOf(projectileNames, projectileName);
		}

		[ConCommand(commandName = "dump_projectile_map", flags = ConVarFlags.None, helpText = "Dumps the map between indices and projectile prefabs.")]
		private static void DumpProjectileMap(ConCommandArgs args)
		{
			string[] array = new string[projectilePrefabs.Length];
			for (int i = 0; i < projectilePrefabs.Length; i++)
			{
				array[i] = $"[{i}] = {projectilePrefabs[i].name}";
			}
		}
	}
	public static class ProjectileGhostReplacementManager
	{
		private struct SkinGhostPair
		{
			public SkinDef skinDef;

			public GameObject projectileGhost;
		}

		private static SkinGhostPair[][] projectileToSkinGhostPairs = Array.Empty<SkinGhostPair[]>();

		public static GameObject FindProjectileGhostPrefab(ProjectileController projectileController)
		{
			SkinGhostPair[] safe = ArrayUtils.GetSafe(projectileToSkinGhostPairs, projectileController.catalogIndex);
			if (safe != null && (bool)projectileController.owner)
			{
				CharacterBody component = projectileController.owner.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					SkinDef bodySkinDef = SkinCatalog.GetBodySkinDef(component.bodyIndex, (int)component.skinIndex);
					if ((bool)bodySkinDef)
					{
						for (int i = 0; i < safe.Length; i++)
						{
							if ((object)safe[i].skinDef == bodySkinDef)
							{
								return safe[i].projectileGhost;
							}
						}
					}
				}
			}
			return projectileController.ghostPrefab;
		}

		[SystemInitializer(new Type[]
		{
			typeof(SkinCatalog),
			typeof(ProjectileCatalog)
		})]
		private static void Init()
		{
			BuildTable();
		}

		private static void BuildTable()
		{
			List<SkinDef> list = new List<SkinDef>();
			SkinIndex skinIndex = (SkinIndex)0;
			for (SkinIndex skinCount = (SkinIndex)SkinCatalog.skinCount; skinIndex < skinCount; skinIndex++)
			{
				SkinDef skinDef = SkinCatalog.GetSkinDef(skinIndex);
				if (skinDef.projectileGhostReplacements.Length != 0)
				{
					list.Add(skinDef);
				}
			}
			projectileToSkinGhostPairs = new SkinGhostPair[ProjectileCatalog.projectilePrefabCount][];
			foreach (SkinDef item in list)
			{
				SkinDef.ProjectileGhostReplacement[] projectileGhostReplacements = item.projectileGhostReplacements;
				for (int i = 0; i < item.projectileGhostReplacements.Length; i++)
				{
					SkinDef.ProjectileGhostReplacement projectileGhostReplacement = projectileGhostReplacements[i];
					int catalogIndex = projectileGhostReplacement.projectilePrefab.GetComponent<ProjectileController>().catalogIndex;
					if (projectileToSkinGhostPairs[catalogIndex] == null)
					{
						projectileToSkinGhostPairs[catalogIndex] = Array.Empty<SkinGhostPair>();
					}
					SkinGhostPair skinGhostPair = default(SkinGhostPair);
					skinGhostPair.projectileGhost = projectileGhostReplacement.projectileGhostReplacementPrefab;
					skinGhostPair.skinDef = item;
					SkinGhostPair value = skinGhostPair;
					ArrayUtils.ArrayAppend(ref projectileToSkinGhostPairs[catalogIndex], in value);
				}
			}
		}
	}
	[MeansImplicitUse]
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
	public class AssetCheckAttribute : System.Attribute
	{
		public Type assetType;

		public AssetCheckAttribute(Type assetType)
		{
			this.assetType = assetType;
		}
	}
	public class AssetCheckArgs
	{
		[NotNull]
		public ProjectIssueChecker projectIssueChecker;

		[NotNull]
		public UnityEngine.Object asset;

		[CanBeNull]
		public Component assetComponent => asset as Component;

		[CanBeNull]
		public GameObject gameObject => assetComponent?.gameObject;

		[CanBeNull]
		public GameObject gameObjectRoot => gameObject?.transform.root?.gameObject;

		public bool isPrefab => GameObjectIsPrefab(gameObjectRoot);

		public bool isPrefabVariant => GameObjectIsPrefabVariant(gameObjectRoot);

		[CanBeNull]
		public GameObject prefabRoot
		{
			get
			{
				GameObject result = gameObjectRoot;
				if (GameObjectIsPrefab(result))
				{
					return result;
				}
				return null;
			}
		}

		private static bool GameObjectIsPrefab(GameObject gameObject)
		{
			return false;
		}

		private static bool GameObjectIsPrefabVariant(GameObject gameObject)
		{
			return false;
		}

		public void UpdatePrefab()
		{
			_ = (bool)prefabRoot;
		}

		public void Log(string str, UnityEngine.Object context = null)
		{
			projectIssueChecker.Log(str, context);
		}

		public void LogError(string str, UnityEngine.Object context = null)
		{
			projectIssueChecker.LogError(str, context);
		}

		public void LogFormat(UnityEngine.Object context, string format, params object[] formatArgs)
		{
			projectIssueChecker.LogFormat(context, format, formatArgs);
		}

		public void LogErrorFormat(UnityEngine.Object context, string format, params object[] formatArgs)
		{
			projectIssueChecker.LogErrorFormat(context, format, formatArgs);
		}

		public void EnsurePath(string path)
		{
			Directory.Exists(path);
		}

		public T LoadAsset<T>(string fullFilePath) where T : UnityEngine.Object
		{
			File.Exists(fullFilePath);
			return null;
		}

		public static void CreateAsset<T>(string path)
		{
		}
	}
	public class ProjectIssueChecker
	{
		private struct LogMessage
		{
			public bool error;

			public string message;

			public UnityEngine.Object context;

			public string assetPath;
		}

		private Dictionary<Type, List<MethodInfo>> assetCheckMethods;

		private List<MethodInfo> allChecks;

		private Dictionary<MethodInfo, bool> enabledChecks;

		private bool checkScenes = true;

		private List<string> scenesToCheck = new List<string>();

		private string currentAssetPath = "";

		private readonly Stack<UnityEngine.Object> assetStack = new Stack<UnityEngine.Object>();

		private UnityEngine.Object currentAsset;

		private List<LogMessage> log = new List<LogMessage>();

		private string currentSceneName = "";

		private static IEnumerable<Assembly> GetAssemblies()
		{
			List<string> list = new List<string>();
			Stack<Assembly> stack = new Stack<Assembly>();
			stack.Push(Assembly.GetEntryAssembly());
			do
			{
				Assembly asm = stack.Pop();
				yield return asm;
				AssemblyName[] referencedAssemblies = asm.GetReferencedAssemblies();
				foreach (AssemblyName assemblyName in referencedAssemblies)
				{
					if (!list.Contains(assemblyName.FullName))
					{
						stack.Push(Assembly.Load(assemblyName));
						list.Add(assemblyName.FullName);
					}
				}
			}
			while (stack.Count > 0);
		}

		private ProjectIssueChecker()
		{
			assetCheckMethods = new Dictionary<Type, List<MethodInfo>>();
			allChecks = new List<MethodInfo>();
			enabledChecks = new Dictionary<MethodInfo, bool>();
			Assembly[] source = new Assembly[4]
			{
				typeof(GameObject).Assembly,
				typeof(Canvas).Assembly,
				typeof(RoR2Application).Assembly,
				typeof(TMP_Text).Assembly
			};
			Type[] types = source.SelectMany((Assembly a) => a.GetTypes()).ToArray();
			Type[] array = types;
			for (int i = 0; i < array.Length; i++)
			{
				MethodInfo[] methods = array[i].GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo2 in methods)
				{
					foreach (AssetCheckAttribute customAttribute in CustomAttributeExtensions.GetCustomAttributes<AssetCheckAttribute>(methodInfo2))
					{
						Type assetType = customAttribute.assetType;
						AddMethodForTypeDescending(assetType, methodInfo2);
						if (!allChecks.Contains(methodInfo2))
						{
							allChecks.Add(methodInfo2);
							enabledChecks.Add(methodInfo2, value: true);
						}
					}
				}
			}
			void AddMethodForTypeDescending(Type t, MethodInfo methodInfo)
			{
				foreach (Type item in types.Where(t.IsAssignableFrom))
				{
					AddMethodForType(item, methodInfo);
					void AddMethodForType(Type t, MethodInfo methodInfo)
					{
						List<MethodInfo> value = null;
						assetCheckMethods.TryGetValue(t, out value);
						if (value == null)
						{
							value = new List<MethodInfo>();
							assetCheckMethods[t] = value;
						}
						value.Add(methodInfo);
					}
				}
			}
		}

		private string GetCurrentAssetFullPath()
		{
			GameObject gameObject = null;
			string arg = "";
			if (currentAsset is GameObject)
			{
				gameObject = (GameObject)currentAsset;
			}
			else if (currentAsset is Component)
			{
				gameObject = ((Component)currentAsset).gameObject;
			}
			string arg2 = (currentAsset ? currentAsset.name : "NULL ASSET");
			if ((bool)gameObject)
			{
				arg2 = Util.GetGameObjectHierarchyName(gameObject);
			}
			string arg3 = (currentAsset ? currentAsset.GetType().Name : "VOID");
			return $"{arg}:{arg2}({arg3})";
		}

		public void Log(string message, UnityEngine.Object context = null)
		{
			log.Add(new LogMessage
			{
				error = false,
				message = message,
				assetPath = GetCurrentAssetFullPath(),
				context = context
			});
		}

		public void LogError(string message, UnityEngine.Object context = null)
		{
			log.Add(new LogMessage
			{
				error = true,
				message = message,
				assetPath = GetCurrentAssetFullPath(),
				context = context
			});
		}

		public void LogFormat(UnityEngine.Object context, string format, params object[] args)
		{
			log.Add(new LogMessage
			{
				error = false,
				message = string.Format(format, args),
				assetPath = GetCurrentAssetFullPath(),
				context = context
			});
		}

		public void LogErrorFormat(UnityEngine.Object context, string format, params object[] args)
		{
			log.Add(new LogMessage
			{
				error = true,
				message = string.Format(format, args),
				assetPath = GetCurrentAssetFullPath(),
				context = context
			});
		}

		private void FlushLog()
		{
			bool flag = false;
			for (int i = 0; i < log.Count; i++)
			{
				if (log[i].error)
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				foreach (LogMessage item in log)
				{
					if (item.error)
					{
						UnityEngine.Debug.LogErrorFormat(item.context, "[\"{0}\"] {1}", item.assetPath, item.message);
					}
					else
					{
						UnityEngine.Debug.LogFormat(item.context, "[\"{0}\"] {1}", item.assetPath, item.message);
					}
				}
			}
			log.Clear();
		}
	}
	public static class QuitConfirmationHelper
	{
		private enum NetworkStatus
		{
			None,
			SinglePlayer,
			Client,
			Host
		}

		private static bool IsQuitConfirmationRequired()
		{
			if ((bool)Run.instance && !GameOverController.instance)
			{
				return true;
			}
			return false;
		}

		public static void IssueQuitCommand(NetworkUser sender, string consoleCmd)
		{
			IssueQuitCommand(RunCmd);
			void RunCmd()
			{
				Console.instance.SubmitCmd(sender, consoleCmd);
			}
		}

		public static void IssueQuitCommand(Action action)
		{
			if (!IsQuitConfirmationRequired())
			{
				action();
				return;
			}
			NetworkStatus networkStatus = ((NetworkUser.readOnlyInstancesList.Count <= NetworkUser.readOnlyLocalPlayersList.Count) ? NetworkStatus.SinglePlayer : ((!NetworkServer.active) ? NetworkStatus.Client : NetworkStatus.Host));
			string text = "";
			text = networkStatus switch
			{
				NetworkStatus.None => "", 
				NetworkStatus.SinglePlayer => "QUIT_RUN_CONFIRM_DIALOG_BODY_SINGLEPLAYER", 
				NetworkStatus.Client => "QUIT_RUN_CONFIRM_DIALOG_BODY_CLIENT", 
				NetworkStatus.Host => "QUIT_RUN_CONFIRM_DIALOG_BODY_HOST", 
				_ => throw new ArgumentOutOfRangeException(), 
			};
			MPEventSystem owner = null;
			foreach (MPEventSystem readOnlyInstances in MPEventSystem.readOnlyInstancesList)
			{
				if (readOnlyInstances.player.id == PauseManager.PausingPlayerID)
				{
					owner = readOnlyInstances;
					break;
				}
			}
			SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create(owner);
			simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair("QUIT_RUN_CONFIRM_DIALOG_TITLE");
			simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair(text);
			simpleDialogBox.AddActionButton(action.Invoke, "DIALOG_OPTION_YES", true);
			simpleDialogBox.AddCancelButton("CANCEL");
		}

		[ConCommand(commandName = "quit_confirmed_command", flags = ConVarFlags.None, helpText = "Runs the command provided in the argument only if the user confirms they want to quit the current game via dialog UI.")]
		private static void CCQuitConfirmedCommand(ConCommandArgs args)
		{
			NetworkUser sender = args.sender;
			string consoleCmd = args[0];
			IssueQuitCommand(RunCmd);
			void RunCmd()
			{
				Console.instance.SubmitCmd(sender, consoleCmd);
			}
		}
	}
	[Serializable]
	public struct RangeFloat
	{
		public float min;

		public float max;
	}
	[RequireComponent(typeof(RectTransform))]
	public class RemoteGameDetailsPanelController : MonoBehaviour
	{
		[Header("Main Info")]
		public TextMeshProUGUI nameLabel;

		public TextMeshProUGUI typeLabel;

		public TextMeshProUGUI lobbyPlayerCountLabel;

		public TextMeshProUGUI serverPlayerCountLabel;

		public TextMeshProUGUI pingLabel;

		public TextMeshProUGUI tagsLabel;

		public TextMeshProUGUI gameModeLabel;

		public TextMeshProUGUI mapLabel;

		public TextMeshProUGUI statusLabel;

		[Header("Password")]
		public RectTransform passwordPanel;

		public TMP_InputField passwordTextBox;

		[Header("Rules")]
		public RectTransform rulesPanel;

		public RectTransform rulesContainer;

		public GameObject ruleIconPrefab;

		[Header("Players")]
		public RectTransform playersPanel;

		public RectTransform playersContainer;

		public GameObject playerStripPrefab;

		[Header("Favorite/Blacklist")]
		public MPToggle favoriteToggle;

		public MPToggle blacklistToggle;

		[Header("Buttons")]
		public MPButton refreshButton;

		public MPButton joinLobbyButton;

		public MPButton joinServerButton;

		[Header("Warning Panels")]
		public GameObject highCapacityWarningPanel;

		public GameObject versionMismatchWarningPanel;

		public GameObject modMismatchWarningPanel;

		private UIElementAllocator<ChildLocator> playerStripAllocator;

		private UIElementAllocator<RuleChoiceController> ruleIconAllocator;

		private RuleBook ruleBook;

		private RectTransform rectTransform;

		private RemoteGameInfo currentGameInfo;

		private int cookie;

		private void Awake()
		{
			rectTransform = (RectTransform)base.transform;
			playerStripAllocator = new UIElementAllocator<ChildLocator>(playersContainer, playerStripPrefab);
			ruleIconAllocator = new UIElementAllocator<RuleChoiceController>(rulesContainer, ruleIconPrefab);
			ruleBook = new RuleBook();
			passwordTextBox.onValueChanged.AddListener(NetworkManagerSystem.cvClPassword.SetString);
		}

		private void OnEnable()
		{
			passwordTextBox.SetTextWithoutNotify(NetworkManagerSystem.cvClPassword.value);
		}

		private void Update()
		{
			int num = LocalUserManager.readOnlyLocalUsersList.Count;
			if (PlatformSystems.lobbyManager.isInLobby)
			{
				num = PlatformSystems.lobbyManager.calculatedTotalPlayerCount;
			}
			joinLobbyButton.interactable = currentGameInfo.availableLobbySlots >= num;
			joinServerButton.interactable = currentGameInfo.availableServerSlots >= num;
		}

		public void SetGameInfo(RemoteGameInfo newGameInfo)
		{
			SetGameInfoInternal(in newGameInfo);
			RequestRefresh();
		}

		private void SetGameInfoInternal(in RemoteGameInfo newGameInfo)
		{
			currentGameInfo = newGameInfo;
			SceneDef sceneDef = SceneCatalog.GetSceneDef(newGameInfo.currentSceneIndex ?? SceneIndex.Invalid);
			string value = null;
			if (newGameInfo.didRespond.HasValue)
			{
				value = Language.GetString(newGameInfo.didRespond.Value ? "REMOTE_GAME_STATUS_RESPONSIVE" : "REMOTE_GAME_STATUS_UNRESPONSIVE");
			}
			GameModeIndex gameModeIndex = GameModeIndex.Invalid;
			string text = null;
			if (currentGameInfo.gameModeName != null)
			{
				gameModeIndex = GameModeCatalog.FindGameModeIndex(currentGameInfo.gameModeName);
			}
			if (gameModeIndex != GameModeIndex.Invalid)
			{
				text = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex).nameToken;
			}
			if (PlatformSystems.ShouldUseEpicOnlineSystems)
			{
				SetLabelInfo(nameLabel, "REMOTE_GAME_DETAILS_NAME", currentGameInfo.serverName);
			}
			else
			{
				SetLabelInfo(nameLabel, "REMOTE_GAME_DETAILS_NAME", currentGameInfo.name);
			}
			SetLabelInfo(pingLabel, "REMOTE_GAME_DETAILS_PING", currentGameInfo.ping);
			SetLabelInfo(tagsLabel, "REMOTE_GAME_DETAILS_TAGS", (currentGameInfo.tags != null) ? string.Join(",", currentGameInfo.tags) : null);
			SetLabelInfo(gameModeLabel, "REMOTE_GAME_DETAILS_GAMEMODE", (text != null) ? Language.GetString(text) : null);
			SetLabelInfo(mapLabel, "REMOTE_GAME_DETAILS_MAP", sceneDef ? Language.GetString(sceneDef.nameToken) : null);
			SetLabelInfo(statusLabel, "REMOTE_GAME_DETAILS_STATUS", value);
			SetLabelInfo(lobbyPlayerCountLabel, "REMOTE_GAME_DETAILS_LOBBY_PLAYER_COUNT", currentGameInfo.lobbyPlayerCount, currentGameInfo.lobbyMaxPlayers);
			SetLabelInfo(serverPlayerCountLabel, "REMOTE_GAME_DETAILS_SERVER_PLAYER_COUNT", currentGameInfo.serverPlayerCount, currentGameInfo.serverMaxPlayers);
			List<RemotePlayerInfo> list = new List<RemotePlayerInfo>();
			newGameInfo.GetPlayers(list);
			playerStripAllocator.AllocateElements(list.Count);
			ReadOnlyCollection<ChildLocator> elements = playerStripAllocator.elements;
			for (int i = 0; i < playerStripAllocator.elements.Count; i++)
			{
				ChildLocator childLocator = elements[i];
				RemotePlayerInfo remotePlayerInfo = list[i];
				childLocator.FindChild("NameLabel").GetComponent<TextMeshProUGUI>().SetText(remotePlayerInfo.name);
			}
			if (newGameInfo.GetRuleBook(ruleBook))
			{
				List<RuleChoiceDef> list2 = new List<RuleChoiceDef>();
				foreach (RuleChoiceDef choice in ruleBook.choices)
				{
					if (!choice.onlyShowInGameBrowserIfNonDefault || !choice.isDefaultChoice)
					{
						list2.Add(choice);
					}
				}
				ruleIconAllocator.AllocateElements(list2.Count);
				ReadOnlyCollection<RuleChoiceController> elements2 = ruleIconAllocator.elements;
				for (int j = 0; j < list2.Count; j++)
				{
					elements2[j].SetChoice(list2[j]);
				}
			}
			else
			{
				ruleIconAllocator.AllocateElements(0);
			}
			SetWarningEnabled(highCapacityWarningPanel, currentGameInfo.greaterMaxPlayers > 4);
			SetWarningEnabled(versionMismatchWarningPanel, newGameInfo.buildId != null && !string.Equals(newGameInfo.buildId, RoR2Application.GetBuildId(), StringComparison.OrdinalIgnoreCase));
			SetWarningEnabled(modMismatchWarningPanel, newGameInfo.modHash != null && !string.Equals(newGameInfo.modHash, NetworkModCompatibilityHelper.networkModHash, StringComparison.OrdinalIgnoreCase));
			bool flag = newGameInfo.IsLobbyIdValid();
			bool flag2 = newGameInfo.IsServerIdValid() || newGameInfo.serverAddress.HasValue;
			if (flag && flag2)
			{
				flag2 = false;
			}
			joinLobbyButton.gameObject.SetActive(flag);
			joinServerButton.gameObject.SetActive(flag2);
			passwordPanel.gameObject.SetActive(currentGameInfo.hasPassword.GetValueOrDefault());
		}

		private void SetLabelInfo<T>(TextMeshProUGUI label, string formatToken, T? value, GameObject explicitContainer = null) where T : struct
		{
			if ((object)explicitContainer == null)
			{
				explicitContainer = label.gameObject;
			}
			bool hasValue = value.HasValue;
			explicitContainer.SetActive(hasValue);
			if (hasValue)
			{
				label.SetText(Language.GetStringFormatted(formatToken, value.Value));
			}
		}

		private void SetLabelInfo(TextMeshProUGUI label, string formatToken, string value, GameObject explicitContainer = null)
		{
			if ((object)explicitContainer == null)
			{
				explicitContainer = label.gameObject;
			}
			bool flag = !string.IsNullOrEmpty(value);
			explicitContainer.SetActive(flag);
			if (flag)
			{
				label.SetText(Language.GetStringFormatted(formatToken, value));
			}
		}

		private void SetLabelInfo(TextMeshProUGUI label, string formatToken, int? value1, int? value2, GameObject explicitContainer = null)
		{
			if ((object)explicitContainer == null)
			{
				explicitContainer = label.gameObject;
			}
			bool flag = value1.HasValue && value2.HasValue;
			explicitContainer.SetActive(flag);
			if (flag)
			{
				label.SetText(Language.GetStringFormatted(formatToken, value1.Value, value2.Value));
			}
		}

		private void SetWarningEnabled(GameObject labelObject, bool shouldEnable)
		{
			if ((bool)labelObject)
			{
				labelObject.SetActive(shouldEnable);
			}
		}

		public void JoinCurrentLobby()
		{
			if (currentGameInfo.IsLobbyIdValid())
			{
				string text = null;
				text = ((!PlatformSystems.ShouldUseEpicOnlineSystems) ? currentGameInfo.lobbyId.ToString() : currentGameInfo.lobbyIdStr);
				Console.instance.SubmitCmd(null, "steam_lobby_join " + text);
			}
		}

		public void JoinCurrentServer()
		{
			if (currentGameInfo.serverAddress.HasValue)
			{
				Console.instance.SubmitCmd(null, "connect " + currentGameInfo.serverAddress.Value.ToString());
			}
			else if (currentGameInfo.IsServerIdValid())
			{
				Console.instance.SubmitCmd(null, "connect_steamworks_p2p " + currentGameInfo.serverId);
			}
		}

		public void RequestRefresh()
		{
			int capturedCookie = ++cookie;
			currentGameInfo.RequestRefresh(delegate(in RemoteGameInfo refreshedGameInfo)
			{
				if ((bool)this && capturedCookie == cookie)
				{
					RemoteGameInfo newGameInfo = refreshedGameInfo;
					newGameInfo.didRespond = true;
					SetGameInfoInternal(in newGameInfo);
				}
			}, delegate
			{
				currentGameInfo.didRespond = false;
				SetGameInfoInternal(in currentGameInfo);
			}, fetchDetails: true);
		}
	}
	public static class RewiredIntegrationManager
	{
		public static List<Controller> blockedControllers = new List<Controller>();

		public static List<ulong> usersToReconnect = new List<ulong>();

		public static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Rewired Input Manager");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				if (x.Result != null)
				{
					FinishInit(x.Result);
				}
			};
		}

		public static void FinishInit(GameObject result)
		{
			UnityEngine.Object.Instantiate(result);
			ReInput.ControllerConnectedEvent += AssignNewController;
			ReInput.ControllerPreDisconnectEvent += UnassignController;
			ReInput.ControllerDisconnectedEvent += OnControllerDisconnected;
			ControllerType[] array = new ControllerType[3]
			{
				ControllerType.Keyboard,
				ControllerType.Mouse,
				ControllerType.Joystick
			};
			foreach (ControllerType controllerType in array)
			{
				Controller[] controllers = ReInput.controllers.GetControllers(controllerType);
				if (controllers != null)
				{
					for (int j = 0; j < controllers.Length; j++)
					{
						AssignNewController(controllers[j]);
					}
				}
			}
			LocalUser.LoadInitialUIMap();
		}

		private static void AssignJoystickToAvailablePlayer(Controller controller)
		{
			IList<Player> players = ReInput.players.Players;
			for (int i = 0; i < players.Count; i++)
			{
				Player player = players[i];
				if (player.name != "PlayerMain" && ((player.controllers.joystickCount == 0 && !player.controllers.hasKeyboard && !player.controllers.hasMouse) || ReInput.controllers.IsControllerAssignedToPlayer(controller.type, controller.id, player.id)))
				{
					player.controllers.AddController(controller, removeFromOtherPlayers: true);
					UserManager.NotifyControllerAssigned(controller.id, player);
					break;
				}
			}
		}

		private static void AssignNewController(ControllerStatusChangedEventArgs args)
		{
			AssignNewController(ReInput.controllers.GetController(args.controllerType, args.controllerId));
		}

		private static void AssignNewController(Controller controller)
		{
			if (!ReInput.controllers.IsControllerAssigned(controller.type, controller))
			{
				ReInput.players.GetPlayer("PlayerMain").controllers.AddController(controller, removeFromOtherPlayers: true);
				UserManager.NotifyControllerAssigned(controller.id, ReInput.players.GetPlayer("PlayerMain"));
			}
		}

		private static void UnassignController(ControllerStatusChangedEventArgs args)
		{
			Controller controller = ReInput.controllers.GetController(args.controllerType, args.controllerId);
			foreach (Player allPlayer in ReInput.players.AllPlayers)
			{
				if (ReInput.controllers.IsControllerAssignedToPlayer(args.controllerType, args.controllerId, allPlayer.id))
				{
					UserManager.NotifyControllerUnassigned(controller.id, allPlayer);
					break;
				}
			}
			ReInput.controllers.RemoveControllerFromAllPlayers(controller);
			if (blockedControllers.Contains(controller))
			{
				blockedControllers.Remove(controller);
			}
		}

		private static void OnControllerDisconnected(ControllerStatusChangedEventArgs args)
		{
			RefreshJoystickAssignment();
		}

		public static void RefreshJoystickAssignment()
		{
			Controller[] controllers = ReInput.controllers.GetControllers(ControllerType.Joystick);
			if (controllers == null)
			{
				return;
			}
			Controller[] array = controllers;
			foreach (Controller controller in array)
			{
				if (!blockedControllers.Contains(controller) && !ReInput.controllers.IsControllerAssigned(ControllerType.Joystick, controller))
				{
					AssignJoystickToAvailablePlayer(controller);
				}
			}
		}

		public static void RefreshAfterRunFinish()
		{
			usersToReconnect.Clear();
			blockedControllers.Clear();
			RefreshJoystickAssignment();
		}

		public static Player GetPlayerUsingJoystickId(int slot)
		{
			foreach (Player player in ReInput.players.Players)
			{
				if (ReInput.controllers.IsJoystickAssignedToPlayer(slot, player.id))
				{
					return player;
				}
			}
			return null;
		}
	}
	public class RoR2Content : IContentPackProvider
	{
		public static class Artifacts
		{
			public static ArtifactDef Glass;

			public static ArtifactDef Bomb;

			public static ArtifactDef Sacrifice;

			public static ArtifactDef Enigma;

			public static ArtifactDef EliteOnly;

			public static ArtifactDef RandomSurvivorOnRespawn;

			public static ArtifactDef WeakAssKnees;

			public static ArtifactDef WispOnDeath;

			public static ArtifactDef SingleMonsterType;

			public static ArtifactDef MixEnemy;

			public static ArtifactDef ShadowClone;

			public static ArtifactDef TeamDeath;

			public static ArtifactDef Swarms;

			public static ArtifactDef Command;

			public static ArtifactDef MonsterTeamGainsItems;

			public static ArtifactDef FriendlyFire;

			public static ArtifactDef glassArtifactDef => Glass;

			public static ArtifactDef bombArtifactDef => Bomb;

			public static ArtifactDef sacrificeArtifactDef => Sacrifice;

			public static ArtifactDef enigmaArtifactDef => Enigma;

			public static ArtifactDef eliteOnlyArtifactDef => EliteOnly;

			public static ArtifactDef randomSurvivorOnRespawnArtifactDef => RandomSurvivorOnRespawn;

			public static ArtifactDef weakAssKneesArtifactDef => WeakAssKnees;

			public static ArtifactDef wispOnDeath => WispOnDeath;

			public static ArtifactDef singleMonsterTypeArtifactDef => SingleMonsterType;

			public static ArtifactDef mixEnemyArtifactDef => MixEnemy;

			public static ArtifactDef shadowCloneArtifactDef => ShadowClone;

			public static ArtifactDef teamDeathArtifactDef => TeamDeath;

			public static ArtifactDef swarmsArtifactDef => Swarms;

			public static ArtifactDef commandArtifactDef => Command;

			public static ArtifactDef monsterTeamGainsItemsArtifactDef => MonsterTeamGainsItems;

			public static ArtifactDef friendlyFireArtifactDef => FriendlyFire;
		}

		public static class Items
		{
			public static ItemDef Syringe;

			public static ItemDef Bear;

			public static ItemDef Behemoth;

			public static ItemDef Missile;

			public static ItemDef ExplodeOnDeath;

			public static ItemDef Dagger;

			public static ItemDef Tooth;

			public static ItemDef CritGlasses;

			public static ItemDef Hoof;

			public static ItemDef Feather;

			public static ItemDef ChainLightning;

			public static ItemDef Seed;

			public static ItemDef Icicle;

			public static ItemDef GhostOnKill;

			public static ItemDef Mushroom;

			public static ItemDef Crowbar;

			public static ItemDef LevelBonus;

			public static ItemDef AttackSpeedOnCrit;

			public static ItemDef BleedOnHit;

			public static ItemDef SprintOutOfCombat;

			public static ItemDef FallBoots;

			public static ItemDef WardOnLevel;

			public static ItemDef Phasing;

			public static ItemDef HealOnCrit;

			public static ItemDef HealWhileSafe;

			public static ItemDef PersonalShield;

			public static ItemDef EquipmentMagazine;

			public static ItemDef NovaOnHeal;

			public static ItemDef ShockNearby;

			public static ItemDef Infusion;

			public static ItemDef Clover;

			public static ItemDef Medkit;

			public static ItemDef Bandolier;

			public static ItemDef BounceNearby;

			public static ItemDef IgniteOnKill;

			public static ItemDef StunChanceOnHit;

			public static ItemDef Firework;

			public static ItemDef LunarDagger;

			public static ItemDef GoldOnHit;

			public static ItemDef WarCryOnMultiKill;

			public static ItemDef BoostHp;

			public static ItemDef BoostDamage;

			public static ItemDef ShieldOnly;

			public static ItemDef AlienHead;

			public static ItemDef Talisman;

			public static ItemDef Knurl;

			public static ItemDef BeetleGland;

			public static ItemDef CrippleWardOnLevel;

			public static ItemDef SprintBonus;

			public static ItemDef SecondarySkillMagazine;

			public static ItemDef StickyBomb;

			public static ItemDef TreasureCache;

			public static ItemDef BossDamageBonus;

			public static ItemDef SprintArmor;

			public static ItemDef IceRing;

			public static ItemDef FireRing;

			public static ItemDef SlowOnHit;

			public static ItemDef ExtraLife;

			public static ItemDef ExtraLifeConsumed;

			public static ItemDef UtilitySkillMagazine;

			public static ItemDef HeadHunter;

			public static ItemDef KillEliteFrenzy;

			public static ItemDef RepeatHeal;

			public static ItemDef Ghost;

			public static ItemDef HealthDecay;

			public static ItemDef AutoCastEquipment;

			public static ItemDef IncreaseHealing;

			public static ItemDef JumpBoost;

			public static ItemDef DrizzlePlayerHelper;

			public static ItemDef ExecuteLowHealthElite;

			public static ItemDef EnergizedOnEquipmentUse;

			public static ItemDef BarrierOnOverHeal;

			public static ItemDef TonicAffliction;

			public static ItemDef TitanGoldDuringTP;

			public static ItemDef SprintWisp;

			public static ItemDef BarrierOnKill;

			public static ItemDef ArmorReductionOnHit;

			public static ItemDef TPHealingNova;

			public static ItemDef NearbyDamageBonus;

			public static ItemDef LunarUtilityReplacement;

			public static ItemDef MonsoonPlayerHelper;

			public static ItemDef Thorns;

			public static ItemDef FlatHealth;

			public static ItemDef Pearl;

			public static ItemDef ShinyPearl;

			public static ItemDef BonusGoldPackOnKill;

			public static ItemDef LaserTurbine;

			public static ItemDef LunarPrimaryReplacement;

			public static ItemDef NovaOnLowHealth;

			public static ItemDef LunarTrinket;

			public static ItemDef InvadingDoppelganger;

			public static ItemDef CutHp;

			public static ItemDef ArtifactKey;

			public static ItemDef ArmorPlate;

			public static ItemDef Squid;

			public static ItemDef DeathMark;

			public static ItemDef Plant;

			public static ItemDef FocusConvergence;

			public static ItemDef BoostAttackSpeed;

			public static ItemDef AdaptiveArmor;

			public static ItemDef CaptainDefenseMatrix;

			public static ItemDef FireballsOnHit;

			public static ItemDef LightningStrikeOnHit;

			public static ItemDef BleedOnHitAndExplode;

			public static ItemDef SiphonOnLowHealth;

			public static ItemDef MonstersOnShrineUse;

			public static ItemDef RandomDamageZone;

			public static ItemDef ScrapWhite;

			public static ItemDef ScrapGreen;

			public static ItemDef ScrapRed;

			public static ItemDef ScrapYellow;

			public static ItemDef LunarBadLuck;

			public static ItemDef BoostEquipmentRecharge;

			public static ItemDef LunarSecondaryReplacement;

			public static ItemDef LunarSpecialReplacement;

			public static ItemDef TeamSizeDamageBonus;

			public static ItemDef RoboBallBuddy;

			public static ItemDef ParentEgg;

			public static ItemDef SummonedEcho;

			public static ItemDef MinionLeash;

			public static ItemDef UseAmbientLevel;

			public static ItemDef TeleportWhenOob;

			public static ItemDef MinHealthPercentage;
		}

		public static class Equipment
		{
			public static EquipmentDef CommandMissile;

			public static EquipmentDef Fruit;

			public static EquipmentDef Meteor;

			[TargetAssetName("EliteFireEquipment")]
			public static EquipmentDef AffixRed;

			[TargetAssetName("EliteLightningEquipment")]
			public static EquipmentDef AffixBlue;

			[TargetAssetName("EliteIceEquipment")]
			public static EquipmentDef AffixWhite;

			[TargetAssetName("ElitePoisonEquipment")]
			public static EquipmentDef AffixPoison;

			public static EquipmentDef Blackhole;

			public static EquipmentDef CritOnUse;

			public static EquipmentDef DroneBackup;

			public static EquipmentDef BFG;

			public static EquipmentDef Jetpack;

			public static EquipmentDef Lightning;

			public static EquipmentDef GoldGat;

			public static EquipmentDef PassiveHealing;

			public static EquipmentDef LunarPotion;

			public static EquipmentDef BurnNearby;

			public static EquipmentDef Scanner;

			public static EquipmentDef CrippleWard;

			public static EquipmentDef Gateway;

			public static EquipmentDef Tonic;

			public static EquipmentDef QuestVolatileBattery;

			public static EquipmentDef Cleanse;

			public static EquipmentDef FireBallDash;

			[TargetAssetName("EliteHauntedEquipment")]
			public static EquipmentDef AffixHaunted;

			public static EquipmentDef GainArmor;

			public static EquipmentDef Saw;

			public static EquipmentDef Recycle;

			public static EquipmentDef LifestealOnHit;

			public static EquipmentDef TeamWarCry;

			public static EquipmentDef DeathProjectile;

			[TargetAssetName("EliteEchoEquipment")]
			public static EquipmentDef AffixEcho;

			[TargetAssetName("EliteLunarEquipment")]
			public static EquipmentDef AffixLunar;
		}

		public static class Buffs
		{
			public static BuffDef Slow50;

			public static BuffDef ArmorBoost;

			public static BuffDef AttackSpeedOnCrit;

			public static BuffDef HiddenInvincibility;

			public static BuffDef OnFire;

			public static BuffDef Warbanner;

			public static BuffDef Cloak;

			public static BuffDef CloakSpeed;

			public static BuffDef FullCrit;

			[TargetAssetName("bdElitePoison")]
			public static BuffDef AffixPoison;

			public static BuffDef EngiShield;

			public static BuffDef TeslaField;

			public static BuffDef WarCryBuff;

			public static BuffDef Energized;

			public static BuffDef BeetleJuice;

			public static BuffDef BugWings;

			public static BuffDef MedkitHeal;

			public static BuffDef ClayGoo;

			public static BuffDef Immune;

			public static BuffDef Cripple;

			public static BuffDef Slow80;

			public static BuffDef Slow60;

			[TargetAssetName("bdEliteFire")]
			public static BuffDef AffixRed;

			[TargetAssetName("bdEliteLightning")]
			public static BuffDef AffixBlue;

			public static BuffDef NoCooldowns;

			[TargetAssetName("bdEliteIce")]
			public static BuffDef AffixWhite;

			public static BuffDef TonicBuff;

			public static BuffDef HealingDisabled;

			public static BuffDef Weak;

			public static BuffDef Entangle;

			[TargetAssetName("bdEliteHaunted")]
			public static BuffDef AffixHaunted;

			public static BuffDef Pulverized;

			public static BuffDef PulverizeBuildup;

			[TargetAssetName("bdEliteHauntedRecipient")]
			public static BuffDef AffixHauntedRecipient;

			public static BuffDef Intangible;

			public static BuffDef ElephantArmorBoost;

			public static BuffDef NullifyStack;

			public static BuffDef Nullified;

			public static BuffDef Bleeding;

			public static BuffDef SuperBleed;

			public static BuffDef Poisoned;

			public static BuffDef WhipBoost;

			public static BuffDef Blight;

			public static BuffDef DeathMark;

			public static BuffDef CrocoRegen;

			public static BuffDef MercExpose;

			public static BuffDef LifeSteal;

			public static BuffDef PowerBuff;

			public static BuffDef LunarShell;

			public static BuffDef TeamWarCry;

			public static BuffDef PermanentCurse;

			public static BuffDef ElementalRingsReady;

			public static BuffDef ElementalRingsCooldown;

			public static BuffDef LunarSecondaryRoot;

			public static BuffDef LunarDetonationCharge;

			public static BuffDef Overheat;

			public static BuffDef Fruiting;

			public static BuffDef BanditSkull;

			[TargetAssetName("bdEliteEcho")]
			public static BuffDef AffixEcho;

			public static BuffDef LaserTurbineKillCharge;

			[TargetAssetName("bdEliteLunar")]
			public static BuffDef AffixLunar;

			public static BuffDef SmallArmorBoost;

			public static BuffDef VoidFogMild;

			public static BuffDef VoidFogStrong;
		}

		public static class Elites
		{
			public static EliteDef Fire;

			public static EliteDef FireHonor;

			public static EliteDef Lightning;

			public static EliteDef LightningHonor;

			public static EliteDef Ice;

			public static EliteDef IceHonor;

			public static EliteDef Poison;

			public static EliteDef Haunted;

			public static EliteDef Echo;

			public static EliteDef Lunar;
		}

		public static class GameEndings
		{
			public static GameEndingDef StandardLoss;

			public static GameEndingDef ObliterationEnding;

			public static GameEndingDef LimboEnding;

			public static GameEndingDef MainEnding;

			public static GameEndingDef PrismaticTrialEnding;
		}

		public static class Survivors
		{
			public static SurvivorDef Commando;

			public static SurvivorDef Engi;

			public static SurvivorDef Huntress;

			public static SurvivorDef Mage;

			public static SurvivorDef Merc;

			public static SurvivorDef Toolbot;

			public static SurvivorDef Treebot;

			public static SurvivorDef Loader;

			public static SurvivorDef Croco;

			public static SurvivorDef Captain;

			public static SurvivorDef Bandit2;
		}

		public static class MiscPickups
		{
			public static MiscPickupDef LunarCoin;
		}

		public static DirectorCardCategorySelection mixEnemyMonsterCards;

		public static bool initialized;

		public static AsyncOperationHandle<DirectorCardCategorySelection> loadOperationHandle;

		private ContentPack contentPack = new ContentPack();

		private Dictionary<SurvivorDef, UnlockableDef[]> eclipseUnlockableCache = new Dictionary<SurvivorDef, UnlockableDef[]>();

		public string identifier => "RoR2.BaseContent";

		public static void Init()
		{
			RoR2Application.Print("RoR2Content init, time = " + RoR2Application.stopwatch.ElapsedMilliseconds + "msec. ");
			AsyncOperationHandle<DirectorCardCategorySelection> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<DirectorCardCategorySelection>("DirectorCardCategorySelections/dccsMixEnemy");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<DirectorCardCategorySelection> x)
			{
				mixEnemyMonsterCards = x.Result;
			};
			initialized = true;
			RoR2Application.Print("RoR2Content init end, time = " + RoR2Application.stopwatch.ElapsedMilliseconds + "msec. ");
		}

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			contentPack.identifier = identifier;
			AddressablesLoadHelper loadHelper = AddressablesLoadHelper.CreateUsingDefaultResourceLocator("ContentPack:RoR2.BaseContent");
			yield return loadHelper.AddContentPackLoadOperationWithYields(contentPack);
			loadHelper.AddGenericOperation(delegate
			{
				ContentLoadHelper.PopulateTypeFields(typeof(Artifacts), contentPack.artifactDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Items), contentPack.itemDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Equipment), contentPack.equipmentDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Buffs), contentPack.buffDefs, (string fieldName) => "bd" + fieldName);
				ContentLoadHelper.PopulateTypeFields(typeof(Elites), contentPack.eliteDefs, (string fieldName) => "ed" + fieldName);
				ContentLoadHelper.PopulateTypeFields(typeof(GameEndings), contentPack.gameEndingDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(Survivors), contentPack.survivorDefs);
				ContentLoadHelper.PopulateTypeFields(typeof(MiscPickups), contentPack.miscPickupDefs);
			}, 0.04f);
			loadHelper.AddGenericOperation(delegate
			{
				contentPack.effectDefs.Find("CoinEmitter").cullMethod = (EffectData effectData) => SettingsConVars.cvExpAndMoneyEffects.value;
			}, 0.01f);
			while (loadHelper.coroutine.MoveNext())
			{
				args.ReportProgress(loadHelper.progress.value);
				yield return loadHelper.coroutine.Current;
			}
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			ContentPack.Copy(contentPack, args.output);
			int minEclipseLevel = 1;
			int maxEclipseLevel = 8;
			List<UnlockableDef> list = new List<UnlockableDef>();
			foreach (ContentPackLoadInfo peerLoadInfo in args.peerLoadInfos)
			{
				ReadOnlyNamedAssetCollection<SurvivorDef> survivorDefs = peerLoadInfo.previousContentPack.survivorDefs;
				_ = args.output.unlockableDefs.Length;
				foreach (SurvivorDef item2 in survivorDefs)
				{
					if (!eclipseUnlockableCache.TryGetValue(item2, out var value))
					{
						value = CreateEclipseUnlockablesForSurvivor(item2, minEclipseLevel, maxEclipseLevel);
						eclipseUnlockableCache[item2] = value;
					}
					UnlockableDef[] array = value;
					foreach (UnlockableDef item in array)
					{
						list.Add(item);
					}
				}
			}
			args.output.unlockableDefs.Add(list.ToArray());
			args.ReportProgress(1f);
			yield break;
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			eclipseUnlockableCache.Clear();
			args.ReportProgress(1f);
			yield break;
		}

		private static UnlockableDef[] CreateEclipseUnlockablesForSurvivor(SurvivorDef survivorDef, int minEclipseLevel, int maxEclipseLevel)
		{
			UnlockableDef[] array = new UnlockableDef[maxEclipseLevel - minEclipseLevel + 1];
			for (int i = minEclipseLevel + 1; i <= maxEclipseLevel + 1; i++)
			{
				array[i - (minEclipseLevel + 1)] = CreateEclipseUnlockableForSurvivor(survivorDef, i);
			}
			return array;
		}

		private static UnlockableDef CreateEclipseUnlockableForSurvivor(SurvivorDef survivorDef, int eclipseLevel)
		{
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			string cachedName = stringBuilder.Clear().Append("Eclipse.").Append(survivorDef.cachedName)
				.Append(".")
				.AppendInt(eclipseLevel)
				.ToString();
			UnlockableDef unlockableDef = ScriptableObject.CreateInstance<UnlockableDef>();
			unlockableDef.cachedName = cachedName;
			unlockableDef.hidden = true;
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			return unlockableDef;
		}
	}
	public static class RoR2ServerTags
	{
		public const string mod = "mod";

		public const string difficultyEasy = "dz";

		public const string difficultyNormal = "rs";

		public const string difficultyHard = "mn";

		public const string ruleVoteEnabled = "rv1";

		public const string ruleVoteDisabled = "rv0";

		public const string ruleMultiplayerPauseEnabled = "rmp1";

		public const string ruleMultiplayerPauseDisabled = "rmp0";
	}
	public class RuleBook : IEquatable<RuleBook>
	{
		public struct ChoicesEnumerable : IEnumerable<RuleChoiceDef>, IEnumerable
		{
			public struct Enumerator : IEnumerator<RuleChoiceDef>, IEnumerator, IDisposable
			{
				private int ruleIndex;

				private readonly byte[] localChoiceIndicesArray;

				public RuleChoiceDef Current => RuleCatalog.GetRuleDef(ruleIndex)?.choices[localChoiceIndicesArray[ruleIndex]];

				object IEnumerator.Current => Current;

				public Enumerator(byte[] localChoiceIndicesArray)
				{
					ruleIndex = -1;
					this.localChoiceIndicesArray = localChoiceIndicesArray;
				}

				public bool MoveNext()
				{
					ruleIndex++;
					return ruleIndex < localChoiceIndicesArray.Length;
				}

				public void Reset()
				{
					ruleIndex = -1;
				}

				public void Dispose()
				{
				}
			}

			public readonly RuleBook target;

			public ChoicesEnumerable(RuleBook target)
			{
				this.target = target;
			}

			public Enumerator GetEnumerator()
			{
				return new Enumerator(target.ruleValues);
			}

			IEnumerator<RuleChoiceDef> IEnumerable<RuleChoiceDef>.GetEnumerator()
			{
				return GetEnumerator();
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}
		}

		private readonly byte[] ruleValues = new byte[RuleCatalog.ruleCount];

		protected static readonly RuleDef startingMoneyRule = RuleCatalog.FindRuleDef("Misc.StartingMoney");

		protected static readonly RuleDef stageOrderRule = RuleCatalog.FindRuleDef("Misc.StageOrder");

		protected static readonly RuleDef keepMoneyBetweenStagesRule = RuleCatalog.FindRuleDef("Misc.KeepMoneyBetweenStages");

		private static byte[] defaultValues;

		public uint startingMoney => (uint)GetRuleChoice(startingMoneyRule).extraData;

		public StageOrder stageOrder => (StageOrder)GetRuleChoice(stageOrderRule).extraData;

		public bool keepMoneyBetweenStages => (bool)GetRuleChoice(keepMoneyBetweenStagesRule).extraData;

		public ChoicesEnumerable choices => new ChoicesEnumerable(this);

		[SystemInitializer(new Type[] { typeof(RuleCatalog) })]
		private static void Init()
		{
			defaultValues = new byte[RuleCatalog.ruleCount];
			for (int i = 0; i < RuleCatalog.ruleCount; i++)
			{
				defaultValues[i] = (byte)RuleCatalog.GetRuleDef(i).defaultChoiceIndex;
			}
			HGXml.Register<RuleBook>(ToXml, FromXml);
		}

		public RuleBook()
		{
			SetToDefaults();
		}

		public void SetToDefaults()
		{
			Array.Copy(defaultValues, 0, ruleValues, 0, ruleValues.Length);
		}

		public void ApplyChoice(RuleChoiceDef choiceDef)
		{
			ruleValues[choiceDef.ruleDef.globalIndex] = (byte)choiceDef.localIndex;
		}

		public bool IsChoiceActive(RuleChoiceDef choiceDef)
		{
			return ruleValues[choiceDef.ruleDef.globalIndex] == choiceDef.localIndex;
		}

		public int GetRuleChoiceIndex(int ruleIndex)
		{
			return ruleValues[ruleIndex];
		}

		public int GetRuleChoiceIndex(RuleDef ruleDef)
		{
			return ruleValues[ruleDef.globalIndex];
		}

		public RuleChoiceDef GetRuleChoice(int ruleIndex)
		{
			return RuleCatalog.GetRuleDef(ruleIndex).choices[ruleValues[ruleIndex]];
		}

		public RuleChoiceDef GetRuleChoice(RuleDef ruleDef)
		{
			return ruleDef.choices[ruleValues[ruleDef.globalIndex]];
		}

		public void Serialize(NetworkWriter writer)
		{
			for (int i = 0; i < ruleValues.Length; i++)
			{
				writer.Write(ruleValues[i]);
			}
		}

		public void Deserialize(NetworkReader reader)
		{
			for (int i = 0; i < ruleValues.Length; i++)
			{
				ruleValues[i] = reader.ReadByte();
			}
		}

		public bool Equals(RuleBook other)
		{
			if (other == null)
			{
				return false;
			}
			return ArrayUtils.SequenceEquals(ruleValues, other.ruleValues);
		}

		public override bool Equals(object obj)
		{
			return Equals(obj as RuleBook);
		}

		public override int GetHashCode()
		{
			int num = 0;
			for (int i = 0; i < ruleValues.Length; i++)
			{
				num += ruleValues[i];
			}
			return num;
		}

		public void Copy([NotNull] RuleBook src)
		{
			if (src == null)
			{
				throw new ArgumentException("Argument cannot be null.", "src");
			}
			Array.Copy(src.ruleValues, ruleValues, ruleValues.Length);
		}

		public DifficultyIndex FindDifficulty()
		{
			for (int i = 0; i < ruleValues.Length; i++)
			{
				RuleChoiceDef ruleChoiceDef = RuleCatalog.GetRuleDef(i).choices[ruleValues[i]];
				if (ruleChoiceDef.difficultyIndex != DifficultyIndex.Invalid)
				{
					return ruleChoiceDef.difficultyIndex;
				}
			}
			return DifficultyIndex.Invalid;
		}

		public ArtifactMask GenerateArtifactMask()
		{
			ArtifactMask result = default(ArtifactMask);
			for (int i = 0; i < ruleValues.Length; i++)
			{
				RuleChoiceDef ruleChoiceDef = RuleCatalog.GetRuleDef(i).choices[ruleValues[i]];
				if (ruleChoiceDef.artifactIndex != ArtifactIndex.None)
				{
					result.AddArtifact(ruleChoiceDef.artifactIndex);
				}
			}
			return result;
		}

		public void GenerateItemMask([NotNull] ItemMask dest)
		{
			dest.Clear();
			for (int i = 0; i < ruleValues.Length; i++)
			{
				RuleChoiceDef ruleChoiceDef = RuleCatalog.GetRuleDef(i).choices[ruleValues[i]];
				if (ruleChoiceDef.itemIndex != ItemIndex.None)
				{
					dest.Add(ruleChoiceDef.itemIndex);
				}
			}
		}

		public void GenerateEquipmentMask([NotNull] EquipmentMask dest)
		{
			dest.Clear();
			for (int i = 0; i < ruleValues.Length; i++)
			{
				RuleChoiceDef ruleChoiceDef = RuleCatalog.GetRuleDef(i).choices[ruleValues[i]];
				if (ruleChoiceDef.equipmentIndex != EquipmentIndex.None)
				{
					dest.Add(ruleChoiceDef.equipmentIndex);
				}
			}
		}

		public static void ToXml(XElement element, RuleBook src)
		{
			byte[] array = src.ruleValues;
			string[] choiceNamesBuffer = new string[array.Length];
			int choiceNamesCount = 0;
			for (int i = 0; i < array.Length; i++)
			{
				RuleDef ruleDef = RuleCatalog.GetRuleDef(i);
				byte b = array[i];
				if ((long)b < (long)ruleDef.choices.Count)
				{
					AddChoice(ruleDef.choices[b].globalName);
				}
			}
			element.Value = string.Join(" ", choiceNamesBuffer, 0, choiceNamesCount);
			void AddChoice(string globalChoiceName)
			{
				choiceNamesBuffer[choiceNamesCount++] = globalChoiceName;
			}
		}

		public static bool FromXml(XElement element, ref RuleBook dest)
		{
			dest.SetToDefaults();
			string[] array = element.Value.Split(' ');
			for (int i = 0; i < array.Length; i++)
			{
				RuleChoiceDef ruleChoiceDef = RuleCatalog.FindChoiceDef(array[i]);
				if (ruleChoiceDef != null)
				{
					dest.ApplyChoice(ruleChoiceDef);
				}
			}
			return true;
		}

		public static void WriteBase64ToStringBuilder(RuleBook src, StringBuilder dest)
		{
			byte[] array = src.ruleValues;
			int inputWriteIndex = 0;
			byte[] inputBytes = new byte[3];
			char[] outputChars = new char[4];
			int bytesPerRuleChoiceGlobalIndex = 1;
			if (RuleCatalog.choiceCount > 256)
			{
				bytesPerRuleChoiceGlobalIndex = 2;
				if (RuleCatalog.choiceCount > 65536)
				{
					bytesPerRuleChoiceGlobalIndex = 3;
					if (RuleCatalog.choiceCount > 16777216)
					{
						bytesPerRuleChoiceGlobalIndex = 4;
					}
				}
			}
			PushByte((byte)bytesPerRuleChoiceGlobalIndex);
			for (int i = 0; i < array.Length; i++)
			{
				byte index = array[i];
				RuleChoiceDef ruleChoiceDef = RuleCatalog.GetRuleDef(i).choices[index];
				if (!ruleChoiceDef.isDefaultChoice)
				{
					PushRuleChoiceGlobalIndex((ushort)ruleChoiceDef.globalIndex);
				}
			}
			PushCurrentInputToDest();
			void PushByte(byte value)
			{
				inputBytes[inputWriteIndex++] = value;
				if (inputWriteIndex == 3)
				{
					PushCurrentInputToDest();
				}
			}
			void PushCurrentInputToDest()
			{
				if (inputWriteIndex != 0)
				{
					System.Convert.ToBase64CharArray(inputBytes, 0, inputWriteIndex, outputChars, 0);
					dest.Append(outputChars);
					inputWriteIndex = 0;
				}
			}
			void PushRuleChoiceGlobalIndex(int id)
			{
				for (int j = 0; j < bytesPerRuleChoiceGlobalIndex; j++)
				{
					int num = (bytesPerRuleChoiceGlobalIndex - 1 - j) * 8;
					PushByte((byte)(id >> num));
				}
			}
		}

		public static void ReadBase64(string src, RuleBook dest)
		{
			dest.SetToDefaults();
			byte[] array = System.Convert.FromBase64String(src);
			if (array.Length == 0)
			{
				return;
			}
			int num = array[0];
			if (num > 4)
			{
				return;
			}
			for (int i = 1; i < array.Length; i += num)
			{
				int num2 = 0;
				for (int j = 0; j < num; j++)
				{
					num2 <<= 8;
					num2 |= array[i + j];
				}
				RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(num2);
				if (choiceDef != null)
				{
					dest.ApplyChoice(choiceDef);
				}
			}
		}
	}
	public class RuleMask : SerializableBitArray
	{
		public RuleMask()
			: base(RuleCatalog.ruleCount)
		{
		}

		public void Serialize(NetworkWriter writer)
		{
			for (int i = 0; i < bytes.Length; i++)
			{
				writer.Write(bytes[i]);
			}
		}

		public void Deserialize(NetworkReader reader)
		{
			for (int i = 0; i < bytes.Length; i++)
			{
				bytes[i] = reader.ReadByte();
			}
		}

		public override bool Equals(object obj)
		{
			if (obj is RuleMask ruleMask)
			{
				for (int i = 0; i < bytes.Length; i++)
				{
					if (bytes[i] != ruleMask.bytes[i])
					{
						return false;
					}
				}
			}
			return true;
		}

		public override int GetHashCode()
		{
			int num = 0;
			for (int i = 0; i < bytes.Length; i++)
			{
				num += bytes[i];
			}
			return num;
		}

		public void Copy([NotNull] RuleMask src)
		{
			byte[] array = src.bytes;
			byte[] array2 = bytes;
			int i = 0;
			for (int num = array2.Length; i < num; i++)
			{
				array2[i] = array[i];
			}
		}
	}
	public class RuleChoiceMask : SerializableBitArray
	{
		public bool this[RuleChoiceDef choiceDef]
		{
			get
			{
				return base[choiceDef.globalIndex];
			}
			set
			{
				base[choiceDef.globalIndex] = value;
			}
		}

		public RuleChoiceMask()
			: base(RuleCatalog.choiceCount)
		{
		}

		public void Serialize(NetworkWriter writer)
		{
			for (int i = 0; i < bytes.Length; i++)
			{
				writer.Write(bytes[i]);
			}
		}

		public void Deserialize(NetworkReader reader)
		{
			for (int i = 0; i < bytes.Length; i++)
			{
				bytes[i] = reader.ReadByte();
			}
		}

		public override bool Equals(object obj)
		{
			if (obj is RuleChoiceMask ruleChoiceMask)
			{
				for (int i = 0; i < bytes.Length; i++)
				{
					if (bytes[i] != ruleChoiceMask.bytes[i])
					{
						return false;
					}
				}
			}
			return true;
		}

		public override int GetHashCode()
		{
			int num = 0;
			for (int i = 0; i < bytes.Length; i++)
			{
				num += bytes[i];
			}
			return num;
		}

		public void Copy([NotNull] RuleChoiceMask src)
		{
			byte[] array = src.bytes;
			byte[] array2 = bytes;
			int i = 0;
			for (int num = array2.Length; i < num; i++)
			{
				array2[i] = array[i];
			}
		}
	}
	public static class RuleCatalog
	{
		public enum RuleCategoryType
		{
			StripVote,
			VoteResultGrid
		}

		private static readonly List<RuleDef> allRuleDefs = new List<RuleDef>();

		private static readonly List<RuleChoiceDef> allChoicesDefs = new List<RuleChoiceDef>();

		public static readonly List<RuleCategoryDef> allCategoryDefs = new List<RuleCategoryDef>();

		public static RuleCategoryDef artifactRuleCategory;

		private static RuleChoiceDef[] _allChoiceDefsWithUnlocks = Array.Empty<RuleChoiceDef>();

		private static readonly Dictionary<string, RuleDef> ruleDefsByGlobalName = new Dictionary<string, RuleDef>();

		private static readonly Dictionary<string, RuleChoiceDef> ruleChoiceDefsByGlobalName = new Dictionary<string, RuleChoiceDef>();

		public static ResourceAvailability availability;

		private static readonly BoolConVar ruleShowItems = new BoolConVar("rule_show_items", ConVarFlags.Cheat, "0", "Whether or not to allow voting on items in the pregame rules.");

		public static IEnumerable<RuleChoiceDef> allChoiceDefsWithUnlocks => _allChoiceDefsWithUnlocks;

		public static int ruleCount => allRuleDefs.Count;

		public static int choiceCount => allChoicesDefs.Count;

		public static int categoryCount => allCategoryDefs.Count;

		public static int highestLocalChoiceCount { get; private set; }

		public static RuleDef GetRuleDef(int ruleDefIndex)
		{
			return allRuleDefs[ruleDefIndex];
		}

		public static RuleDef FindRuleDef(string ruleDefGlobalName)
		{
			ruleDefsByGlobalName.TryGetValue(ruleDefGlobalName, out var value);
			return value;
		}

		public static RuleChoiceDef FindChoiceDef(string ruleChoiceDefGlobalName)
		{
			ruleChoiceDefsByGlobalName.TryGetValue(ruleChoiceDefGlobalName, out var value);
			return value;
		}

		public static RuleChoiceDef GetChoiceDef(int ruleChoiceDefIndex)
		{
			return allChoicesDefs[ruleChoiceDefIndex];
		}

		public static RuleCategoryDef GetCategoryDef(int ruleCategoryDefIndex)
		{
			return allCategoryDefs[ruleCategoryDefIndex];
		}

		private static bool HiddenTestTrue()
		{
			return true;
		}

		private static bool HiddenTestFalse()
		{
			return false;
		}

		private static bool HiddenTestItemsConvar()
		{
			return !ruleShowItems.value;
		}

		private static RuleCategoryDef AddCategory(string displayToken, string subtitleToken, UnityEngine.Color color)
		{
			return AddCategory(displayToken, subtitleToken, color, "", null, HiddenTestFalse, RuleCategoryType.StripVote);
		}

		private static RuleCategoryDef AddCategory(string displayToken, string subtitleToken, UnityEngine.Color color, string emptyTipToken, string editToken, Func<bool> hiddenTest, RuleCategoryType ruleCategoryType)
		{
			RuleCategoryDef ruleCategoryDef = new RuleCategoryDef
			{
				position = allRuleDefs.Count,
				displayToken = displayToken,
				subtitleToken = subtitleToken,
				color = color,
				emptyTipToken = emptyTipToken,
				editToken = editToken,
				hiddenTest = hiddenTest,
				ruleCategoryType = ruleCategoryType
			};
			allCategoryDefs.Add(ruleCategoryDef);
			return ruleCategoryDef;
		}

		private static void AddRule(RuleDef ruleDef)
		{
			if (allCategoryDefs.Count > 0)
			{
				ruleDef.category = allCategoryDefs[allCategoryDefs.Count - 1];
				allCategoryDefs[allCategoryDefs.Count - 1].children.Add(ruleDef);
			}
			allRuleDefs.Add(ruleDef);
			if (highestLocalChoiceCount < ruleDef.choices.Count)
			{
				highestLocalChoiceCount = ruleDef.choices.Count;
			}
			ruleDefsByGlobalName[ruleDef.globalName] = ruleDef;
			foreach (RuleChoiceDef choice in ruleDef.choices)
			{
				ruleChoiceDefsByGlobalName[choice.globalName] = choice;
			}
		}

		[SystemInitializer(new Type[]
		{
			typeof(ItemCatalog),
			typeof(EquipmentCatalog),
			typeof(ArtifactCatalog),
			typeof(EntitlementCatalog)
		})]
		private static void Init()
		{
			AddCategory("RULE_HEADER_DIFFICULTY", "", new Color32(43, 124, 181, byte.MaxValue));
			AddRule(RuleDef.FromDifficulty());
			AddCategory("RULE_HEADER_EXPANSIONS", "RULE_HEADER_EXPANSIONS_SUBTITLE", new Color32(219, 114, 114, byte.MaxValue), null, "RULE_HEADER_EXPANSIONS_EDIT", HiddenTestFalse, RuleCategoryType.VoteResultGrid);
			foreach (ExpansionDef expansionDef in ExpansionCatalog.expansionDefs)
			{
				AddRule(RuleDef.FromExpansion(expansionDef));
			}
			int num = 0;
			artifactRuleCategory = AddCategory("RULE_HEADER_ARTIFACTS", "RULE_HEADER_ARTIFACTS_SUBTITLE", ColorCatalog.GetColor(ColorCatalog.ColorIndex.Artifact), "RULE_ARTIFACTS_EMPTY_TIP", "RULE_HEADER_ARTIFACTS_EDIT", HiddenTestFalse, RuleCategoryType.VoteResultGrid);
			num = ArtifactCatalog.artifactCount;
			for (ArtifactIndex artifactIndex = (ArtifactIndex)0; (int)artifactIndex < num; artifactIndex++)
			{
				AddRule(RuleDef.FromArtifact(artifactIndex));
			}
			num = ItemCatalog.itemCount;
			AddCategory("RULE_HEADER_ITEMS", "RULE_HEADER_ITEMSANDEQUIPMENT_SUBTITLE", new Color32(147, 225, 128, byte.MaxValue), null, "RULE_HEADER_ITEMSANDEQUIPMENT_EDIT", HiddenTestItemsConvar, RuleCategoryType.VoteResultGrid);
			ItemIndex[] array = new ItemIndex[num];
			ItemTier[] array2 = new ItemTier[num];
			Array values = Enum.GetValues(typeof(ItemTier));
			bool[] array3 = new bool[values.Length];
			foreach (ItemTier item in values)
			{
				ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(item);
				if (!(itemTierDef == null))
				{
					array3[(int)item] = itemTierDef.isDroppable;
				}
			}
			int i = 0;
			for (int num2 = num; i < num2; i++)
			{
				array2[i] = ItemCatalog.GetItemDef(array[i] = (ItemIndex)i).tier;
			}
			foreach (ItemTier item2 in values)
			{
				int num3 = (int)item2;
				if (!array3[num3])
				{
					continue;
				}
				for (int j = 0; j < num; j++)
				{
					if (array2[j] == item2)
					{
						AddRule(RuleDef.FromItem(array[j]));
					}
				}
			}
			AddCategory("RULE_HEADER_EQUIPMENT", "RULE_HEADER_ITEMSANDEQUIPMENT_SUBTITLE", new Color32(byte.MaxValue, 128, 0, byte.MaxValue), null, "RULE_HEADER_ITEMSANDEQUIPMENT_EDIT", HiddenTestItemsConvar, RuleCategoryType.VoteResultGrid);
			EquipmentIndex equipmentIndex = (EquipmentIndex)0;
			for (EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; equipmentIndex < equipmentCount; equipmentIndex++)
			{
				if (EquipmentCatalog.GetEquipmentDef(equipmentIndex).canDrop)
				{
					AddRule(RuleDef.FromEquipment(equipmentIndex));
				}
			}
			AddCategory("RULE_HEADER_MISC", "", new Color32(192, 192, 192, byte.MaxValue), null, "", HiddenTestFalse, RuleCategoryType.VoteResultGrid);
			RuleDef ruleDef = new RuleDef("Misc.StartingMoney", "RULE_MISC_STARTING_MONEY");
			RuleChoiceDef ruleChoiceDef = ruleDef.AddChoice("0", 0u, excludeByDefault: true);
			ruleChoiceDef.tooltipNameToken = "RULE_STARTINGMONEY_CHOICE_0_NAME";
			ruleChoiceDef.tooltipBodyToken = "RULE_STARTINGMONEY_CHOICE_0_DESC";
			ruleChoiceDef.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.LunarCoin);
			ruleChoiceDef.onlyShowInGameBrowserIfNonDefault = true;
			RuleChoiceDef ruleChoiceDef2 = ruleDef.AddChoice("15", 15u, excludeByDefault: true);
			ruleChoiceDef2.tooltipNameToken = "RULE_STARTINGMONEY_CHOICE_15_NAME";
			ruleChoiceDef2.tooltipBodyToken = "RULE_STARTINGMONEY_CHOICE_15_DESC";
			ruleChoiceDef2.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.LunarCoin);
			ruleChoiceDef2.onlyShowInGameBrowserIfNonDefault = true;
			ruleDef.MakeNewestChoiceDefault();
			RuleChoiceDef ruleChoiceDef3 = ruleDef.AddChoice("50", 50u, excludeByDefault: true);
			ruleChoiceDef3.tooltipNameToken = "RULE_STARTINGMONEY_CHOICE_50_NAME";
			ruleChoiceDef3.tooltipBodyToken = "RULE_STARTINGMONEY_CHOICE_50_DESC";
			ruleChoiceDef3.spritePath = "Textures/MiscIcons/texRuleBonusStartingMoney";
			ruleChoiceDef3.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.LunarCoin);
			ruleChoiceDef3.onlyShowInGameBrowserIfNonDefault = true;
			AddRule(ruleDef);
			RuleDef ruleDef2 = new RuleDef("Misc.StageOrder", "RULE_MISC_STAGE_ORDER");
			RuleChoiceDef ruleChoiceDef4 = ruleDef2.AddChoice("Normal", StageOrder.Normal, excludeByDefault: true);
			ruleChoiceDef4.tooltipNameToken = "RULE_STAGEORDER_CHOICE_NORMAL_NAME";
			ruleChoiceDef4.tooltipBodyToken = "RULE_STAGEORDER_CHOICE_NORMAL_DESC";
			ruleChoiceDef4.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.LunarCoin);
			ruleChoiceDef4.onlyShowInGameBrowserIfNonDefault = true;
			ruleDef2.MakeNewestChoiceDefault();
			RuleChoiceDef ruleChoiceDef5 = ruleDef2.AddChoice("Random", StageOrder.Random, excludeByDefault: true);
			ruleChoiceDef5.tooltipNameToken = "RULE_STAGEORDER_CHOICE_RANDOM_NAME";
			ruleChoiceDef5.tooltipBodyToken = "RULE_STAGEORDER_CHOICE_RANDOM_DESC";
			ruleChoiceDef5.spritePath = "Textures/MiscIcons/texRuleMapIsRandom";
			ruleChoiceDef5.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.LunarCoin);
			ruleChoiceDef5.onlyShowInGameBrowserIfNonDefault = true;
			AddRule(ruleDef2);
			RuleDef ruleDef3 = new RuleDef("Misc.KeepMoneyBetweenStages", "RULE_MISC_KEEP_MONEY_BETWEEN_STAGES");
			RuleChoiceDef ruleChoiceDef6 = ruleDef3.AddChoice("On", true, excludeByDefault: true);
			ruleChoiceDef6.tooltipNameToken = "";
			ruleChoiceDef6.tooltipBodyToken = "RULE_KEEPMONEYBETWEENSTAGES_CHOICE_ON_DESC";
			ruleChoiceDef6.onlyShowInGameBrowserIfNonDefault = true;
			RuleChoiceDef ruleChoiceDef7 = ruleDef3.AddChoice("Off", false, excludeByDefault: true);
			ruleChoiceDef7.tooltipNameToken = "";
			ruleChoiceDef7.tooltipBodyToken = "RULE_KEEPMONEYBETWEENSTAGES_CHOICE_OFF_DESC";
			ruleChoiceDef7.onlyShowInGameBrowserIfNonDefault = true;
			ruleDef3.MakeNewestChoiceDefault();
			AddRule(ruleDef3);
			RuleDef ruleDef4 = new RuleDef("Misc.AllowDropIn", "RULE_MISC_ALLOW_DROP_IN");
			RuleChoiceDef ruleChoiceDef8 = ruleDef4.AddChoice("On", true, excludeByDefault: true);
			ruleChoiceDef8.tooltipNameToken = "";
			ruleChoiceDef8.tooltipBodyToken = "RULE_ALLOWDROPIN_CHOICE_ON_DESC";
			ruleChoiceDef8.onlyShowInGameBrowserIfNonDefault = true;
			RuleChoiceDef ruleChoiceDef9 = ruleDef4.AddChoice("Off", false, excludeByDefault: true);
			ruleChoiceDef9.tooltipNameToken = "";
			ruleChoiceDef9.tooltipBodyToken = "RULE_ALLOWDROPIN_CHOICE_OFF_DESC";
			ruleChoiceDef9.onlyShowInGameBrowserIfNonDefault = true;
			ruleDef4.MakeNewestChoiceDefault();
			AddRule(ruleDef4);
			int num4 = 0;
			for (int k = 0; k < allRuleDefs.Count; k++)
			{
				RuleDef ruleDef5 = allRuleDefs[k];
				ruleDef5.globalIndex = k;
				for (int l = 0; l < ruleDef5.choices.Count; l++)
				{
					RuleChoiceDef ruleChoiceDef10 = ruleDef5.choices[l];
					ruleChoiceDef10.localIndex = l;
					ruleChoiceDef10.globalIndex = allChoicesDefs.Count;
					if ((bool)ruleChoiceDef10.unlockable)
					{
						num4++;
					}
					allChoicesDefs.Add(ruleChoiceDef10);
				}
			}
			_allChoiceDefsWithUnlocks = new RuleChoiceDef[num4];
			int num5 = 0;
			foreach (RuleChoiceDef allChoicesDef in allChoicesDefs)
			{
				if ((bool)allChoicesDef.unlockable)
				{
					_allChoiceDefsWithUnlocks[num5++] = allChoicesDef;
				}
			}
			availability.MakeAvailable();
		}

		[ConCommand(commandName = "rules_dump", flags = ConVarFlags.None, helpText = "Dump information about the rules system.")]
		private static void CCRulesDump(ConCommandArgs args)
		{
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			for (int i = 0; i < ruleCount; i++)
			{
				RuleDef ruleDef = GetRuleDef(i);
				for (int j = 0; j < ruleDef.choices.Count; j++)
				{
					RuleChoiceDef ruleChoiceDef = ruleDef.choices[j];
					string item = $"  {{localChoiceIndex={ruleChoiceDef.localIndex} globalChoiceIndex={ruleChoiceDef.globalIndex} localName={ruleChoiceDef.localName}}}";
					list2.Add(item);
				}
				string text = string.Join("\n", list2);
				list2.Clear();
				string text2 = $"[{i}] {ruleDef.globalName} defaultChoiceIndex={ruleDef.defaultChoiceIndex}\n";
				list.Add(text2 + text);
			}
		}

		[ConCommand(commandName = "rules_list_choices", flags = ConVarFlags.None, helpText = "Lists all rule choices.")]
		private static void CCRulesListChoices(ConCommandArgs args)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("* = default choice.");
			stringBuilder.AppendLine();
			foreach (RuleChoiceDef allChoicesDef in allChoicesDefs)
			{
				stringBuilder.Append(allChoicesDef.globalName);
				if (allChoicesDef.isDefaultChoice)
				{
					stringBuilder.Append("*");
				}
				stringBuilder.AppendLine();
			}
		}
	}
	public class RuleCategoryDef
	{
		public int position;

		public string displayToken;

		public string subtitleToken;

		public string emptyTipToken;

		public string editToken;

		public UnityEngine.Color color;

		public List<RuleDef> children = new List<RuleDef>();

		public RuleCatalog.RuleCategoryType ruleCategoryType;

		public Func<bool> hiddenTest;

		public bool isHidden => hiddenTest?.Invoke() ?? false;
	}
	public class RuleChoiceDef
	{
		public RuleDef ruleDef;

		public Sprite sprite;

		[NotNull]
		public string tooltipNameToken;

		public Func<RuleChoiceDef, string> getTooltipName = GetNormalTooltipNameFromToken;

		public UnityEngine.Color tooltipNameColor = UnityEngine.Color.white;

		[NotNull]
		public string tooltipBodyToken;

		public UnityEngine.Color tooltipBodyColor = UnityEngine.Color.white;

		public string localName;

		public string globalName;

		public int localIndex;

		public int globalIndex;

		public UnlockableDef requiredUnlockable;

		public RuleChoiceDef requiredChoiceDef;

		public EntitlementDef requiredEntitlementDef;

		public ExpansionDef requiredExpansionDef;

		public bool availableInSinglePlayer = true;

		public bool availableInMultiPlayer = true;

		public DifficultyIndex difficultyIndex = DifficultyIndex.Invalid;

		public ArtifactIndex artifactIndex = ArtifactIndex.None;

		public ItemIndex itemIndex = ItemIndex.None;

		public EquipmentIndex equipmentIndex = EquipmentIndex.None;

		public object extraData;

		public bool excludeByDefault;

		public string selectionUISound;

		[CanBeNull]
		public string serverTag;

		public bool onlyShowInGameBrowserIfNonDefault;

		public string spritePath
		{
			set
			{
				AsyncOperationHandle<Sprite> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<Sprite>(value);
				asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Sprite> x)
				{
					sprite = x.Result;
				};
			}
		}

		[Obsolete("Use 'requiredUnlockable' instead.", false)]
		public ref UnlockableDef unlockable => ref requiredUnlockable;

		public bool isDefaultChoice => ruleDef.defaultChoiceIndex == localIndex;

		public static string GetNormalTooltipNameFromToken(RuleChoiceDef ruleChoiceDef)
		{
			return Language.GetString(ruleChoiceDef.tooltipNameToken);
		}

		public static string GetOffTooltipNameFromToken(RuleChoiceDef ruleChoiceDef)
		{
			return Language.GetStringFormatted("RULE_OFF_FORMAT", Language.GetString(ruleChoiceDef.tooltipNameToken));
		}
	}
	public class RuleDef
	{
		public readonly string globalName;

		public int globalIndex;

		public readonly string displayToken;

		public readonly List<RuleChoiceDef> choices = new List<RuleChoiceDef>();

		public int defaultChoiceIndex;

		public RuleCategoryDef category;

		public bool forceLobbyDisplay;

		private const string pathToOffChoiceMaterial = "Materials/UI/matRuleChoiceOff";

		public RuleChoiceDef AddChoice(string choiceName, object extraData = null, bool excludeByDefault = false)
		{
			RuleChoiceDef ruleChoiceDef = new RuleChoiceDef();
			ruleChoiceDef.ruleDef = this;
			ruleChoiceDef.localName = choiceName;
			ruleChoiceDef.globalName = globalName + "." + choiceName;
			ruleChoiceDef.localIndex = choices.Count;
			ruleChoiceDef.extraData = extraData;
			ruleChoiceDef.excludeByDefault = excludeByDefault;
			choices.Add(ruleChoiceDef);
			return ruleChoiceDef;
		}

		public int AvailableChoiceCount(RuleChoiceMask availability)
		{
			int num = 0;
			for (int i = 0; i < choices.Count; i++)
			{
				if (availability[choices[i].globalIndex])
				{
					num++;
				}
			}
			return num;
		}

		public RuleChoiceDef FindChoice(string choiceLocalName)
		{
			int i = 0;
			for (int count = choices.Count; i < count; i++)
			{
				if (choices[i].localName == choiceLocalName)
				{
					return choices[i];
				}
			}
			return null;
		}

		public void MakeNewestChoiceDefault()
		{
			defaultChoiceIndex = choices.Count - 1;
		}

		public RuleDef(string globalName, string displayToken)
		{
			this.globalName = globalName;
			this.displayToken = displayToken;
		}

		public static RuleDef FromDifficulty()
		{
			RuleDef ruleDef = new RuleDef("Difficulty", "RULE_NAME_DIFFICULTY");
			for (DifficultyIndex difficultyIndex = DifficultyIndex.Easy; difficultyIndex < DifficultyIndex.Count; difficultyIndex++)
			{
				DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(difficultyIndex);
				RuleChoiceDef ruleChoiceDef = ruleDef.AddChoice(difficultyIndex.ToString());
				ruleChoiceDef.spritePath = difficultyDef.iconPath;
				ruleChoiceDef.tooltipNameToken = difficultyDef.nameToken;
				ruleChoiceDef.tooltipNameColor = difficultyDef.color;
				ruleChoiceDef.tooltipBodyToken = difficultyDef.descriptionToken;
				ruleChoiceDef.difficultyIndex = difficultyIndex;
				ruleChoiceDef.serverTag = difficultyDef.serverTag;
				ruleChoiceDef.excludeByDefault = (int)difficultyIndex >= DifficultyCatalog.standardDifficultyCount;
			}
			ruleDef.defaultChoiceIndex = 1;
			return ruleDef;
		}

		public static RuleDef FromArtifact(ArtifactIndex artifactIndex)
		{
			ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(artifactIndex);
			RuleDef ruleDef = new RuleDef("Artifacts." + artifactDef.cachedName, artifactDef.nameToken);
			RuleChoiceDef ruleChoiceDef = ruleDef.AddChoice("On");
			ruleChoiceDef.sprite = artifactDef.smallIconSelectedSprite;
			ruleChoiceDef.tooltipNameToken = artifactDef.nameToken;
			ruleChoiceDef.tooltipBodyToken = artifactDef.descriptionToken;
			ruleChoiceDef.unlockable = artifactDef.unlockableDef;
			ruleChoiceDef.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Artifact);
			ruleChoiceDef.artifactIndex = artifactIndex;
			ruleChoiceDef.selectionUISound = "Play_UI_artifactSelect";
			ruleChoiceDef.requiredExpansionDef = artifactDef.requiredExpansion;
			ruleChoiceDef.extraData = artifactDef;
			RuleChoiceDef ruleChoiceDef2 = ruleDef.AddChoice("Off");
			ruleChoiceDef2.sprite = artifactDef.smallIconDeselectedSprite;
			ruleChoiceDef2.tooltipNameToken = artifactDef.nameToken;
			ruleChoiceDef2.getTooltipName = RuleChoiceDef.GetOffTooltipNameFromToken;
			ruleChoiceDef2.tooltipBodyToken = artifactDef.descriptionToken;
			ruleChoiceDef2.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unaffordable);
			ruleChoiceDef2.selectionUISound = "Play_UI_artifactDeselect";
			ruleChoiceDef2.extraData = artifactDef;
			ruleDef.MakeNewestChoiceDefault();
			return ruleDef;
		}

		public static RuleDef FromItem(ItemIndex itemIndex)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			RuleDef ruleDef = new RuleDef("Items." + itemDef.name, itemDef.nameToken);
			RuleChoiceDef ruleChoiceDef = ruleDef.AddChoice("On");
			ruleChoiceDef.sprite = itemDef.pickupIconSprite;
			ruleChoiceDef.tooltipNameToken = itemDef.nameToken;
			ruleChoiceDef.tooltipBodyToken = "RULE_ITEM_ON_DESCRIPTION";
			ruleChoiceDef.unlockable = itemDef.unlockableDef;
			ruleChoiceDef.itemIndex = itemIndex;
			ruleChoiceDef.onlyShowInGameBrowserIfNonDefault = true;
			ruleChoiceDef.requiredExpansionDef = itemDef.requiredExpansion;
			ruleDef.MakeNewestChoiceDefault();
			RuleChoiceDef ruleChoiceDef2 = ruleDef.AddChoice("Off");
			ruleChoiceDef2.spritePath = "Textures/MiscIcons/texUnlockIcon";
			ruleChoiceDef2.tooltipNameToken = itemDef.nameToken;
			ruleChoiceDef2.getTooltipName = RuleChoiceDef.GetOffTooltipNameFromToken;
			ruleChoiceDef2.tooltipBodyToken = "RULE_ITEM_OFF_DESCRIPTION";
			ruleChoiceDef2.onlyShowInGameBrowserIfNonDefault = true;
			return ruleDef;
		}

		public static RuleDef FromEquipment(EquipmentIndex equipmentIndex)
		{
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
			RuleDef ruleDef = new RuleDef("Equipment." + equipmentDef.name, equipmentDef.nameToken);
			RuleChoiceDef ruleChoiceDef = ruleDef.AddChoice("On");
			ruleChoiceDef.sprite = equipmentDef.pickupIconSprite;
			ruleChoiceDef.tooltipNameToken = equipmentDef.nameToken;
			ruleChoiceDef.tooltipBodyToken = "RULE_ITEM_ON_DESCRIPTION";
			ruleChoiceDef.unlockable = equipmentDef.unlockableDef;
			ruleChoiceDef.equipmentIndex = equipmentIndex;
			ruleChoiceDef.availableInMultiPlayer = equipmentDef.appearsInMultiPlayer;
			ruleChoiceDef.availableInSinglePlayer = equipmentDef.appearsInSinglePlayer;
			ruleChoiceDef.onlyShowInGameBrowserIfNonDefault = true;
			ruleChoiceDef.requiredExpansionDef = equipmentDef.requiredExpansion;
			ruleDef.MakeNewestChoiceDefault();
			RuleChoiceDef ruleChoiceDef2 = ruleDef.AddChoice("Off");
			ruleChoiceDef2.sprite = equipmentDef.pickupIconSprite;
			ruleChoiceDef2.tooltipNameToken = equipmentDef.nameToken;
			ruleChoiceDef2.getTooltipName = RuleChoiceDef.GetOffTooltipNameFromToken;
			ruleChoiceDef2.tooltipBodyToken = "RULE_ITEM_OFF_DESCRIPTION";
			ruleChoiceDef2.onlyShowInGameBrowserIfNonDefault = true;
			return ruleDef;
		}

		public static RuleDef FromExpansion(ExpansionDef expansionDef)
		{
			RuleDef obj = new RuleDef("Expansions." + expansionDef.name, expansionDef.nameToken)
			{
				forceLobbyDisplay = true
			};
			RuleChoiceDef ruleChoiceDef = obj.AddChoice("On", expansionDef);
			ruleChoiceDef.sprite = expansionDef.iconSprite;
			ruleChoiceDef.tooltipNameToken = expansionDef.nameToken;
			ruleChoiceDef.tooltipNameColor = new Color32(219, 114, 114, byte.MaxValue);
			ruleChoiceDef.tooltipBodyToken = expansionDef.descriptionToken;
			ruleChoiceDef.requiredEntitlementDef = expansionDef.requiredEntitlement;
			obj.MakeNewestChoiceDefault();
			expansionDef.enabledChoice = ruleChoiceDef;
			RuleChoiceDef ruleChoiceDef2 = obj.AddChoice("Off");
			ruleChoiceDef2.sprite = expansionDef.disabledIconSprite;
			ruleChoiceDef2.tooltipNameToken = expansionDef.nameToken;
			ruleChoiceDef2.tooltipNameColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unaffordable);
			ruleChoiceDef2.getTooltipName = RuleChoiceDef.GetOffTooltipNameFromToken;
			ruleChoiceDef2.tooltipBodyToken = expansionDef.descriptionToken;
			return obj;
		}
	}
	public class RunReport
	{
		public class PlayerInfo
		{
			[CanBeNull]
			public NetworkUser networkUser;

			[CanBeNull]
			public CharacterMaster master;

			public int localPlayerIndex = -1;

			public string name = string.Empty;

			public BodyIndex bodyIndex = BodyIndex.None;

			public BodyIndex killerBodyIndex = BodyIndex.None;

			public bool isDead;

			public StatSheet statSheet = StatSheet.New();

			public ItemIndex[] itemAcquisitionOrder = Array.Empty<ItemIndex>();

			public int[] itemStacks = ItemCatalog.RequestItemStackArray();

			public EquipmentIndex[] equipment = Array.Empty<EquipmentIndex>();

			public string finalMessageToken = string.Empty;

			public string userProfileFileName = string.Empty;

			private static readonly HGXml.SerializationRules<int[]> itemStacksRules = new HGXml.SerializationRules<int[]>
			{
				serializer = delegate(XElement element, int[] value)
				{
					element.RemoveAll();
					element.Add(from itemIndex in ItemCatalog.allItems
						where value[(int)itemIndex] > 0
						select new XElement(ItemCatalog.GetItemDef(itemIndex).name, value[(int)itemIndex]));
				},
				deserializer = delegate(XElement element, ref int[] value)
				{
					Array.Resize(ref value, ItemCatalog.itemCount);
					for (ItemIndex itemIndex2 = ItemIndex.Count; (int)itemIndex2 < ItemCatalog.itemCount; itemIndex2++)
					{
						value[(int)itemIndex2] = 0;
					}
					foreach (XElement item in element.Elements())
					{
						ItemIndex itemIndex3 = ItemCatalog.FindItemIndex(item.Name.LocalName);
						if (ItemCatalog.IsIndexValid(in itemIndex3))
						{
							HGXml.FromXml(item, ref value[(int)itemIndex3]);
						}
					}
					return true;
				}
			};

			private static readonly HGXml.SerializationRules<EquipmentIndex[]> equipmentRules = new HGXml.SerializationRules<EquipmentIndex[]>
			{
				serializer = delegate(XElement element, EquipmentIndex[] value)
				{
					element.Value = string.Join(" ", value.Select((EquipmentIndex equipmentIndex) => EquipmentCatalog.GetEquipmentDef(equipmentIndex)?.name ?? "None"));
				},
				deserializer = delegate(XElement element, ref EquipmentIndex[] value)
				{
					value = element.Value.Split(' ').Select(EquipmentCatalog.FindEquipmentIndex).ToArray();
					return true;
				}
			};

			[CanBeNull]
			public LocalUser localUser
			{
				get
				{
					if (!networkUser)
					{
						return null;
					}
					return networkUser.localUser;
				}
			}

			public bool isLocalPlayer => localPlayerIndex >= 0;

			public string bodyName
			{
				get
				{
					return BodyCatalog.GetBodyPrefab(bodyIndex)?.gameObject.name ?? "InvalidBody";
				}
				set
				{
					bodyIndex = BodyCatalog.FindBodyIndex(value);
				}
			}

			public string killerBodyName
			{
				get
				{
					return BodyCatalog.GetBodyPrefab(killerBodyIndex)?.gameObject.name ?? "InvalidBody";
				}
				set
				{
					killerBodyIndex = BodyCatalog.FindBodyIndex(value);
				}
			}

			public void Write(NetworkWriter writer)
			{
				writer.WriteBodyIndex(bodyIndex);
				writer.WriteBodyIndex(killerBodyIndex);
				writer.Write(isDead);
				writer.Write(master ? master.gameObject : null);
				statSheet.Write(writer);
				writer.WritePackedUInt32((uint)itemAcquisitionOrder.Length);
				for (int i = 0; i < itemAcquisitionOrder.Length; i++)
				{
					writer.Write(itemAcquisitionOrder[i]);
				}
				writer.WriteItemStacks(itemStacks);
				writer.WritePackedUInt32((uint)equipment.Length);
				for (int j = 0; j < equipment.Length; j++)
				{
					writer.Write(equipment[j]);
				}
				writer.Write(finalMessageToken);
			}

			public void Read(NetworkReader reader)
			{
				bodyIndex = reader.ReadBodyIndex();
				killerBodyIndex = reader.ReadBodyIndex();
				isDead = reader.ReadBoolean();
				GameObject gameObject = reader.ReadGameObject();
				master = (gameObject ? gameObject.GetComponent<CharacterMaster>() : null);
				statSheet.ReadOrSetDefault(reader);
				int newSize = (int)reader.ReadPackedUInt32();
				Array.Resize(ref itemAcquisitionOrder, newSize);
				for (int i = 0; i < itemAcquisitionOrder.Length; i++)
				{
					ItemIndex itemIndex = reader.ReadItemIndex();
					itemAcquisitionOrder[i] = itemIndex;
				}
				reader.ReadItemStacks(itemStacks);
				int newSize2 = (int)reader.ReadPackedUInt32();
				Array.Resize(ref equipment, newSize2);
				for (int j = 0; j < equipment.Length; j++)
				{
					EquipmentIndex equipmentIndex = reader.ReadEquipmentIndex();
					equipment[j] = equipmentIndex;
				}
				finalMessageToken = reader.ReadString();
				ResolveLocalInformation();
			}

			public void ResolveLocalInformation()
			{
				name = Util.GetBestMasterName(master);
				PlayerCharacterMasterController playerCharacterMasterController = null;
				if ((bool)master)
				{
					playerCharacterMasterController = master.GetComponent<PlayerCharacterMasterController>();
				}
				networkUser = null;
				if ((bool)playerCharacterMasterController)
				{
					networkUser = playerCharacterMasterController.networkUser;
				}
				localPlayerIndex = -1;
				userProfileFileName = string.Empty;
				if ((bool)networkUser && networkUser.localUser != null)
				{
					localPlayerIndex = networkUser.localUser.id;
					userProfileFileName = networkUser.localUser.userProfile.fileName;
				}
			}

			public static PlayerInfo Generate(PlayerCharacterMasterController playerCharacterMasterController, GameEndingDef gameEnding)
			{
				CharacterMaster characterMaster = playerCharacterMasterController.master;
				Inventory inventory = characterMaster.inventory;
				PlayerStatsComponent component = playerCharacterMasterController.GetComponent<PlayerStatsComponent>();
				PlayerInfo playerInfo = new PlayerInfo
				{
					networkUser = playerCharacterMasterController.networkUser,
					master = characterMaster,
					bodyIndex = BodyCatalog.FindBodyIndex(characterMaster.bodyPrefab),
					killerBodyIndex = characterMaster.GetKillerBodyIndex(),
					isDead = characterMaster.lostBodyToDeath
				};
				if (playerInfo.killerBodyIndex == BodyIndex.None && (bool)gameEnding && (bool)gameEnding.defaultKillerOverride)
				{
					playerInfo.killerBodyIndex = BodyCatalog.FindBodyIndex(gameEnding.defaultKillerOverride);
				}
				StatSheet.Copy(component.currentStats, playerInfo.statSheet);
				playerInfo.itemAcquisitionOrder = inventory.itemAcquisitionOrder.ToArray();
				ItemIndex itemIndex = ItemIndex.Count;
				for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
				{
					playerInfo.itemStacks[(int)itemIndex] = inventory.GetItemCount(itemIndex);
				}
				playerInfo.equipment = new EquipmentIndex[inventory.GetEquipmentSlotCount()];
				for (uint num = 0u; num < playerInfo.equipment.Length; num++)
				{
					playerInfo.equipment[num] = inventory.GetEquipment(num).equipmentIndex;
				}
				playerInfo.finalMessageToken = playerCharacterMasterController.finalMessageTokenServer;
				return playerInfo;
			}

			public static void ToXml(XElement element, PlayerInfo playerInfo)
			{
				element.RemoveAll();
				element.Add(HGXml.ToXml("name", playerInfo.name));
				element.Add(HGXml.ToXml("bodyName", playerInfo.bodyName));
				element.Add(HGXml.ToXml("killerBodyName", playerInfo.killerBodyName));
				element.Add(HGXml.ToXml("isDead", playerInfo.isDead));
				element.Add(HGXml.ToXml("statSheet", playerInfo.statSheet));
				element.Add(HGXml.ToXml("itemAcquisitionOrder", playerInfo.itemAcquisitionOrder));
				element.Add(HGXml.ToXml("itemStacks", playerInfo.itemStacks, itemStacksRules));
				element.Add(HGXml.ToXml("equipment", playerInfo.equipment, equipmentRules));
				element.Add(HGXml.ToXml("finalMessageToken", playerInfo.finalMessageToken));
				element.Add(HGXml.ToXml("localPlayerIndex", playerInfo.localPlayerIndex));
				element.Add(HGXml.ToXml("userProfileFileName", playerInfo.userProfileFileName));
			}

			public static bool FromXml(XElement element, ref PlayerInfo playerInfo)
			{
				playerInfo = new PlayerInfo();
				element.Element("name")?.Deserialize(ref playerInfo.name);
				string dest = playerInfo.bodyName;
				element.Element("bodyName")?.Deserialize(ref dest);
				playerInfo.bodyName = dest;
				string dest2 = playerInfo.killerBodyName;
				element.Element("killerBodyName")?.Deserialize(ref dest2);
				playerInfo.killerBodyName = dest2;
				element.Element("isDead")?.Deserialize(ref playerInfo.isDead);
				element.Element("statSheet")?.Deserialize(ref playerInfo.statSheet);
				element.Element("itemAcquisitionOrder")?.Deserialize(ref playerInfo.itemAcquisitionOrder);
				element.Element("itemStacks")?.Deserialize(ref playerInfo.itemStacks, itemStacksRules);
				element.Element("equipment")?.Deserialize(ref playerInfo.equipment, equipmentRules);
				element.Element("finalMessageToken")?.Deserialize(ref playerInfo.finalMessageToken);
				element.Element("localPlayerIndex")?.Deserialize(ref playerInfo.localPlayerIndex);
				element.Element("userProfileFileName")?.Deserialize(ref playerInfo.userProfileFileName);
				return true;
			}

			public static void ArrayToXml(XElement element, PlayerInfo[] playerInfos)
			{
				element.RemoveAll();
				for (int i = 0; i < playerInfos.Length; i++)
				{
					element.Add(HGXml.ToXml("PlayerInfo", playerInfos[i]));
				}
			}

			public static bool ArrayFromXml(XElement element, ref PlayerInfo[] playerInfos)
			{
				playerInfos = (from e in element.Elements()
					where e.Name == "PlayerInfo"
					select e).Select(delegate(XElement e)
				{
					PlayerInfo value = null;
					HGXml.FromXml(e, ref value);
					return value;
				}).ToArray();
				return true;
			}
		}

		private const string currentXmlVersion = "2";

		public Guid runGuid;

		private GameModeIndex gameModeIndex = GameModeIndex.Invalid;

		public GameEndingDef gameEnding;

		public ulong seed;

		public DateTime runStartTimeUtc;

		public DateTime snapshotTimeUtc;

		public Run.FixedTimeStamp snapshotRunTime;

		public float runStopwatchValue;

		public RuleBook ruleBook = new RuleBook();

		private PlayerInfo[] playerInfos = Array.Empty<PlayerInfo>();

		private static string runReportsFolder;

		public string gameModeName
		{
			get
			{
				return gameMode?.name ?? "InvalidGameMode";
			}
			set
			{
				gameMode = GameModeCatalog.FindGameModePrefabComponent(value);
			}
		}

		public Run gameMode
		{
			get
			{
				return GameModeCatalog.GetGameModePrefabComponent(gameModeIndex);
			}
			set
			{
				gameModeIndex = value?.gameModeIndex ?? GameModeIndex.Invalid;
			}
		}

		public int playerInfoCount => playerInfos.Length;

		public static RunReport GetLocalUserRunReport(RunReport oldReport, LocalUser localUser)
		{
			if (localUser.id == 0 || oldReport.playerInfoCount == 1)
			{
				return oldReport;
			}
			PlayerInfo playerInfo = null;
			int num = -1;
			PlayerInfo playerInfo2 = null;
			int num2 = -1;
			for (int i = 0; i < oldReport.playerInfoCount; i++)
			{
				PlayerInfo playerInfo3 = oldReport.GetPlayerInfo(i);
				if (playerInfo3.localPlayerIndex == 0)
				{
					playerInfo = playerInfo3;
					num = i;
				}
				else if (playerInfo3.localPlayerIndex == localUser.id)
				{
					playerInfo2 = playerInfo3;
					num2 = i;
				}
			}
			oldReport.playerInfos[num] = playerInfo2;
			oldReport.playerInfos[num2] = playerInfo;
			return oldReport;
		}

		[NotNull]
		public PlayerInfo GetPlayerInfo(int i)
		{
			return playerInfos[i];
		}

		[CanBeNull]
		public PlayerInfo GetPlayerInfoSafe(int i)
		{
			return ArrayUtils.GetSafe(playerInfos, i);
		}

		public int FindPlayerIndex(LocalUser localUser)
		{
			if (localUser != null)
			{
				for (int i = 0; i < playerInfos.Length; i++)
				{
					if (playerInfos[i].localUser == localUser)
					{
						return i;
					}
				}
			}
			return -1;
		}

		public int FindPlayerIndex([CanBeNull] UserProfile userProfile)
		{
			if (userProfile != null)
			{
				for (int i = 0; i < playerInfos.Length; i++)
				{
					if (string.Equals(userProfile.fileName, playerInfos[i].userProfileFileName, StringComparison.OrdinalIgnoreCase))
					{
						return i;
					}
				}
			}
			return -1;
		}

		public bool HasUserParticipated([CanBeNull] LocalUser localUser)
		{
			if (localUser != null)
			{
				for (int i = 0; i < playerInfos.Length; i++)
				{
					if (playerInfos[i].localPlayerIndex == localUser.id)
					{
						return true;
					}
				}
			}
			return false;
		}

		[CanBeNull]
		public PlayerInfo FindPlayerInfo(LocalUser localUser)
		{
			return ArrayUtils.GetSafe(playerInfos, FindPlayerIndex(localUser));
		}

		[CanBeNull]
		public PlayerInfo FindPlayerInfo([CanBeNull] UserProfile userProfile)
		{
			return ArrayUtils.GetSafe(playerInfos, FindPlayerIndex(userProfile));
		}

		[CanBeNull]
		public PlayerInfo FindFirstPlayerInfo()
		{
			if (playerInfoCount <= 0)
			{
				return null;
			}
			return playerInfos[0];
		}

		public static RunReport Generate([NotNull] Run run, GameEndingDef gameEnding)
		{
			RunReport runReport = new RunReport();
			runReport.runGuid = run.GetUniqueId();
			runReport.gameModeIndex = GameModeCatalog.FindGameModeIndex(run.gameObject.name);
			runReport.seed = run.seed;
			runReport.runStartTimeUtc = run.GetStartTimeUtc();
			runReport.snapshotTimeUtc = DateTime.UtcNow;
			runReport.snapshotRunTime = Run.FixedTimeStamp.now;
			runReport.runStopwatchValue = run.GetRunStopwatch();
			runReport.gameEnding = gameEnding;
			runReport.ruleBook.Copy(run.ruleBook);
			runReport.playerInfos = new PlayerInfo[PlayerCharacterMasterController.instances.Count];
			for (int i = 0; i < runReport.playerInfos.Length; i++)
			{
				runReport.playerInfos[i] = PlayerInfo.Generate(PlayerCharacterMasterController.instances[i], gameEnding);
			}
			runReport.ResolveLocalInformation();
			return runReport;
		}

		private void ResolveLocalInformation()
		{
			PlayerInfo[] array = playerInfos;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].ResolveLocalInformation();
			}
		}

		public void Write(NetworkWriter writer)
		{
			writer.WriteGuid(in runGuid);
			writer.WritePackedIndex32((int)GameEndingCatalog.GetGameEndingIndex(gameEnding));
			writer.WritePackedIndex32((int)gameModeIndex);
			writer.Write(seed);
			NetworkDateTime networkDateTime = (NetworkDateTime)runStartTimeUtc;
			writer.Write(in networkDateTime);
			networkDateTime = (NetworkDateTime)snapshotTimeUtc;
			writer.Write(in networkDateTime);
			writer.Write(snapshotRunTime);
			writer.Write(runStopwatchValue);
			writer.Write(ruleBook);
			writer.Write((byte)playerInfos.Length);
			for (int i = 0; i < playerInfos.Length; i++)
			{
				playerInfos[i].Write(writer);
			}
		}

		public void Read(NetworkReader reader)
		{
			runGuid = reader.ReadGuid();
			gameEnding = GameEndingCatalog.GetGameEndingDef((GameEndingIndex)reader.ReadPackedIndex32());
			gameModeIndex = (GameModeIndex)reader.ReadPackedIndex32();
			seed = reader.ReadUInt64();
			runStartTimeUtc = (DateTime)reader.ReadNetworkDateTime();
			snapshotTimeUtc = (DateTime)reader.ReadNetworkDateTime();
			snapshotRunTime = reader.ReadFixedTimeStamp();
			runStopwatchValue = reader.ReadSingle();
			reader.ReadRuleBook(ruleBook);
			int newSize = reader.ReadByte();
			Array.Resize(ref playerInfos, newSize);
			for (int i = 0; i < playerInfos.Length; i++)
			{
				if (playerInfos[i] == null)
				{
					playerInfos[i] = new PlayerInfo();
				}
				playerInfos[i].Read(reader);
			}
			SortByLocalPlayers();
		}

		public void SortByLocalPlayers()
		{
			Array.Sort(playerInfos, delegate(PlayerInfo a, PlayerInfo b)
			{
				if (a.isLocalPlayer == b.isLocalPlayer)
				{
					if (a.isLocalPlayer)
					{
						return a.localPlayerIndex - b.localPlayerIndex;
					}
					return 0;
				}
				return (!a.isLocalPlayer) ? 1 : (-1);
			});
		}

		public static void ToXml(XElement element, RunReport runReport)
		{
			element.RemoveAll();
			element.Add(HGXml.ToXml("version", "2"));
			element.Add(HGXml.ToXml("runGuid", runReport.runGuid));
			element.Add(HGXml.ToXml("gameModeName", runReport.gameModeName));
			element.Add(HGXml.ToXml("gameEnding", runReport.gameEnding));
			element.Add(HGXml.ToXml("seed", runReport.seed));
			element.Add(HGXml.ToXml("runStartTimeUtc", runReport.runStartTimeUtc));
			element.Add(HGXml.ToXml("snapshotTimeUtc", runReport.snapshotTimeUtc));
			element.Add(HGXml.ToXml("snapshotRunTime", runReport.snapshotRunTime));
			element.Add(HGXml.ToXml("runStopwatchValue", runReport.runStopwatchValue));
			element.Add(HGXml.ToXml("ruleBook", runReport.ruleBook));
			element.Add(HGXml.ToXml("playerInfos", runReport.playerInfos));
		}

		public static bool FromXml(XElement element, ref RunReport runReport)
		{
			string dest = "NO_VERSION";
			element.Element("version")?.Deserialize(ref dest);
			if (dest != "2" && !(dest == "1"))
			{
				UnityEngine.Debug.LogFormat("Could not load RunReport with non-upgradeable version \"{0}\".", dest);
				runReport = null;
				return false;
			}
			element.Element("runGuid")?.Deserialize(ref runReport.runGuid);
			string dest2 = runReport.gameModeName;
			element.Element("gameModeName")?.Deserialize(ref dest2);
			runReport.gameModeName = dest2;
			element.Element("gameEnding")?.Deserialize(ref runReport.gameEnding);
			element.Element("seed")?.Deserialize(ref runReport.seed);
			element.Element("runStartTimeUtc")?.Deserialize(ref runReport.runStartTimeUtc);
			element.Element("snapshotTimeUtc")?.Deserialize(ref runReport.snapshotTimeUtc);
			element.Element("snapshotRunTime")?.Deserialize(ref runReport.snapshotRunTime);
			element.Element("runStopwatchValue")?.Deserialize(ref runReport.runStopwatchValue);
			element.Element("ruleBook")?.Deserialize(ref runReport.ruleBook);
			element.Element("playerInfos")?.Deserialize(ref runReport.playerInfos);
			return true;
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			runReportsFolder = Application.dataPath + "/RunReports/";
			HGXml.Register<RunReport>(ToXml, FromXml);
			HGXml.Register<PlayerInfo>(PlayerInfo.ToXml, PlayerInfo.FromXml);
			HGXml.Register<PlayerInfo[]>(PlayerInfo.ArrayToXml, PlayerInfo.ArrayFromXml);
		}

		[NotNull]
		private static string FileNameToPath([NotNull] string fileName)
		{
			return string.Format(CultureInfo.InvariantCulture, "{0}{1}.xml", runReportsFolder, fileName);
		}

		[CanBeNull]
		public static RunReport Load([NotNull] string fileName)
		{
			string text = FileNameToPath(fileName);
			try
			{
				XElement xElement = XDocument.Load(text).Element("RunReport");
				if (xElement == null)
				{
					UnityEngine.Debug.LogFormat("Could not load RunReport {0}: {1}", text, "File is malformed.");
					return null;
				}
				RunReport runReport = new RunReport();
				FromXml(xElement, ref runReport);
				return runReport;
			}
			catch (Exception ex)
			{
				UnityEngine.Debug.LogFormat("Could not load RunReport {0}: {1}", text, ex.Message);
				return null;
			}
		}

		public static bool Save([NotNull] RunReport runReport, [NotNull] string fileName)
		{
			string text = FileNameToPath(fileName);
			try
			{
				if (!Directory.Exists(runReportsFolder))
				{
					Directory.CreateDirectory(runReportsFolder);
				}
				XDocument xDocument = new XDocument();
				xDocument.Add(HGXml.ToXml("RunReport", runReport));
				xDocument.Save(text);
				return true;
			}
			catch (Exception ex)
			{
				UnityEngine.Debug.LogFormat("Could not save RunReport {0}: {1}", text, ex.Message);
				return false;
			}
		}

		public static void TestSerialization(RunReport runReport)
		{
			NetworkWriter networkWriter = new NetworkWriter();
			runReport.Write(networkWriter);
			NetworkReader reader = new NetworkReader(networkWriter.AsArray());
			new RunReport().Read(reader);
		}
	}
	public class SaveFieldAttribute : System.Attribute
	{
		[Serializable]
		public struct HardwareMapEntry
		{
			public string HWGuid;

			public string XMLMap;
		}

		[Serializable]
		public struct HardwareMapWrapper
		{
			public HardwareMapEntry[] Entries;
		}

		public Action<UserProfile, string> setter;

		public Func<UserProfile, string> getter;

		public Action<UserProfile, UserProfile> copier;

		public string defaultValue = string.Empty;

		public string fieldName;

		public string explicitSetupMethod;

		private FieldInfo fieldInfo;

		public void Setup(FieldInfo fieldInfo)
		{
			this.fieldInfo = fieldInfo;
			Type fieldType = fieldInfo.FieldType;
			fieldName = fieldInfo.Name;
			if (explicitSetupMethod != null)
			{
				MethodInfo method = typeof(SaveFieldAttribute).GetMethod(explicitSetupMethod, BindingFlags.Instance | BindingFlags.Public);
				if (method == null)
				{
					UnityEngine.Debug.LogErrorFormat("Explicit setup {0} specified by field {1} could not be found. Use the nameof() operator to ensure the method exists.");
				}
				else if (method.GetParameters().Length > 1)
				{
					UnityEngine.Debug.LogErrorFormat("Explicit setup method {0} for field {1} must have one parameter.", explicitSetupMethod, fieldInfo.Name);
				}
				else
				{
					method.Invoke(this, new object[1] { fieldInfo });
				}
			}
			else if (fieldType == typeof(string))
			{
				SetupString(fieldInfo);
			}
			else if (fieldType == typeof(int))
			{
				SetupInt(fieldInfo);
			}
			else if (fieldType == typeof(uint))
			{
				SetupUint(fieldInfo);
			}
			else if (fieldType == typeof(float))
			{
				SetupFloat(fieldInfo);
			}
			else if (fieldType == typeof(bool))
			{
				SetupBool(fieldInfo);
			}
			else if (fieldType == typeof(SurvivorDef))
			{
				SetupSurvivorDef(fieldInfo);
			}
			else
			{
				UnityEngine.Debug.LogErrorFormat("No explicit setup method or supported type for save field {0}", fieldInfo.Name);
			}
		}

		public void SetupString(FieldInfo fieldInfo)
		{
			getter = (UserProfile userProfile) => (string)fieldInfo.GetValue(userProfile);
			setter = delegate(UserProfile userProfile, string valueString)
			{
				fieldInfo.SetValue(userProfile, valueString);
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				fieldInfo.SetValue(destProfile, fieldInfo.GetValue(srcProfile));
			};
		}

		public void SetupFloat(FieldInfo fieldInfo)
		{
			getter = (UserProfile userProfile) => TextSerialization.ToStringInvariant((float)fieldInfo.GetValue(userProfile));
			setter = delegate(UserProfile userProfile, string valueString)
			{
				if (TextSerialization.TryParseInvariant(valueString, out float result))
				{
					fieldInfo.SetValue(userProfile, result);
				}
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				fieldInfo.SetValue(destProfile, fieldInfo.GetValue(srcProfile));
			};
		}

		public void SetupInt(FieldInfo fieldInfo)
		{
			getter = (UserProfile userProfile) => TextSerialization.ToStringInvariant((int)fieldInfo.GetValue(userProfile));
			setter = delegate(UserProfile userProfile, string valueString)
			{
				if (TextSerialization.TryParseInvariant(valueString, out int result))
				{
					fieldInfo.SetValue(userProfile, result);
				}
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				fieldInfo.SetValue(destProfile, fieldInfo.GetValue(srcProfile));
			};
		}

		public void SetupUint(FieldInfo fieldInfo)
		{
			getter = (UserProfile userProfile) => TextSerialization.ToStringInvariant((uint)fieldInfo.GetValue(userProfile));
			setter = delegate(UserProfile userProfile, string valueString)
			{
				if (TextSerialization.TryParseInvariant(valueString, out uint result))
				{
					fieldInfo.SetValue(userProfile, result);
				}
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				fieldInfo.SetValue(destProfile, fieldInfo.GetValue(srcProfile));
			};
		}

		public void SetupBool(FieldInfo fieldInfo)
		{
			getter = (UserProfile userProfile) => (!(bool)fieldInfo.GetValue(userProfile)) ? "0" : "1";
			setter = delegate(UserProfile userProfile, string valueString)
			{
				if (TextSerialization.TryParseInvariant(valueString, out int result))
				{
					fieldInfo.SetValue(userProfile, result > 0);
				}
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				fieldInfo.SetValue(destProfile, fieldInfo.GetValue(srcProfile));
			};
		}

		public void SetupTokenList(FieldInfo fieldInfo)
		{
			getter = (UserProfile userProfile) => string.Join(" ", (List<string>)fieldInfo.GetValue(userProfile));
			setter = delegate(UserProfile userProfile, string valueString)
			{
				List<string> list = (List<string>)fieldInfo.GetValue(userProfile);
				list.Clear();
				string[] array = valueString.Split(' ');
				foreach (string item in array)
				{
					list.Add(item);
				}
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				List<string> src = (List<string>)fieldInfo.GetValue(srcProfile);
				List<string> dest = (List<string>)fieldInfo.GetValue(destProfile);
				Util.CopyList(src, dest);
			};
		}

		public void SetupPickupsSet(FieldInfo fieldInfo)
		{
			getter = delegate(UserProfile userProfile)
			{
				bool[] pickupsSet = (bool[])fieldInfo.GetValue(userProfile);
				return string.Join(" ", from pickupDef in PickupCatalog.allPickups
					where pickupsSet[pickupDef.pickupIndex.value]
					select pickupDef.internalName);
			};
			setter = delegate(UserProfile userProfile, string valueString)
			{
				bool[] array2 = (bool[])fieldInfo.GetValue(userProfile);
				Array.Clear(array2, 0, 0);
				string[] array3 = valueString.Split(' ');
				for (int i = 0; i < array3.Length; i++)
				{
					PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(array3[i]);
					if (pickupIndex.isValid)
					{
						array2[pickupIndex.value] = true;
					}
				}
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				bool[] sourceArray = (bool[])fieldInfo.GetValue(srcProfile);
				bool[] array = (bool[])fieldInfo.GetValue(destProfile);
				Array.Copy(sourceArray, array, array.Length);
			};
		}

		public void SetupSurvivorDef(FieldInfo fieldInfo)
		{
			getter = delegate(UserProfile userProfile)
			{
				SurvivorDef survivorDef = (SurvivorDef)fieldInfo.GetValue(userProfile);
				return (!survivorDef) ? SurvivorCatalog.defaultSurvivor.cachedName : survivorDef.cachedName;
			};
			setter = delegate(UserProfile userProfile, string valueString)
			{
				SurvivorDef value = SurvivorCatalog.FindSurvivorDef(valueString);
				fieldInfo.SetValue(userProfile, value);
			};
			copier = DefaultCopier;
		}

		public void SetupKeyboardMap(FieldInfo fieldInfo)
		{
			SetupControllerMap(fieldInfo, ControllerType.Keyboard);
		}

		public void SetupMouseMap(FieldInfo fieldInfo)
		{
			SetupControllerMap(fieldInfo, ControllerType.Mouse);
		}

		public void SetupJoystickMap(FieldInfo fieldInfo)
		{
			SetupControllerMap(fieldInfo, ControllerType.Joystick);
		}

		private void SetupControllerMap(FieldInfo fieldInfo, ControllerType controllerType)
		{
			getter = (UserProfile userProfile) => ((ControllerMap)fieldInfo.GetValue(userProfile))?.ToXmlString() ?? string.Empty;
			setter = delegate(UserProfile userProfile, string valueString)
			{
				fieldInfo.SetValue(userProfile, ControllerMap.CreateFromXml(controllerType, valueString));
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				switch (controllerType)
				{
				case ControllerType.Joystick:
					fieldInfo.SetValue(destProfile, new JoystickMap((JoystickMap)fieldInfo.GetValue(srcProfile)));
					break;
				case ControllerType.Keyboard:
					fieldInfo.SetValue(destProfile, new KeyboardMap((KeyboardMap)fieldInfo.GetValue(srcProfile)));
					break;
				case ControllerType.Mouse:
					fieldInfo.SetValue(destProfile, new MouseMap((MouseMap)fieldInfo.GetValue(srcProfile)));
					break;
				default:
					throw new NotImplementedException();
				}
			};
		}

		public void SetupJoystickHardwareMap(FieldInfo fieldInfo)
		{
			getter = delegate(UserProfile userProfile)
			{
				DefaultControllerMaps.RewiredDebugLog("SetupJoystickHardwareMap.getter");
				Dictionary<Guid, JoystickMap> dictionary2 = (Dictionary<Guid, JoystickMap>)fieldInfo.GetValue(userProfile);
				if (dictionary2 != null)
				{
					List<HardwareMapEntry> list = new List<HardwareMapEntry>();
					foreach (KeyValuePair<Guid, JoystickMap> item2 in dictionary2)
					{
						HardwareMapEntry item = default(HardwareMapEntry);
						item.HWGuid = item2.Key.ToString();
						item.XMLMap = ((item2.Value != null) ? item2.Value.ToXmlString() : "");
						list.Add(item);
					}
					HardwareMapWrapper hardwareMapWrapper2 = default(HardwareMapWrapper);
					hardwareMapWrapper2.Entries = list.ToArray();
					string text = JsonUtility.ToJson(hardwareMapWrapper2);
					DefaultControllerMaps.RewiredDebugLog("\tReturning '{0}'", text);
					return text;
				}
				return string.Empty;
			};
			setter = delegate(UserProfile userProfile, string valueString)
			{
				DefaultControllerMaps.RewiredDebugLog("SetupJoystickHardwareMap.setter> {0}", valueString);
				HardwareMapWrapper hardwareMapWrapper = JsonUtility.FromJson<HardwareMapWrapper>(valueString);
				Dictionary<Guid, JoystickMap> dictionary = new Dictionary<Guid, JoystickMap>();
				HardwareMapEntry[] entries = hardwareMapWrapper.Entries;
				for (int i = 0; i < entries.Length; i++)
				{
					HardwareMapEntry hardwareMapEntry = entries[i];
					Guid key = Guid.Parse(hardwareMapEntry.HWGuid);
					string xMLMap = hardwareMapEntry.XMLMap;
					if (ControllerMap.CreateFromXml(ControllerType.Joystick, xMLMap) is JoystickMap joystickMap)
					{
						DefaultControllerMaps.RewiredDebugLog("Serialized Joystick Map for {0}", key.ToString());
						LocalUser.DumpControllerMap(joystickMap);
						dictionary.Add(key, joystickMap);
					}
				}
				fieldInfo.SetValue(userProfile, dictionary);
			};
			copier = delegate(UserProfile srcProfile, UserProfile destProfile)
			{
				DefaultControllerMaps.RewiredDebugLog("SetupJoystickHardwareMap.copier");
				fieldInfo.SetValue(destProfile, new Dictionary<Guid, JoystickMap>((Dictionary<Guid, JoystickMap>)fieldInfo.GetValue(srcProfile)));
			};
		}

		private void DefaultCopier(UserProfile srcProfile, UserProfile destProfile)
		{
			fieldInfo.SetValue(destProfile, fieldInfo.GetValue(srcProfile));
		}
	}
	public enum SceneIndex
	{
		Invalid = -1
	}
	public static class SceneCatalog
	{
		private static SceneDef[] indexToSceneDef = Array.Empty<SceneDef>();

		private static SceneDef[] _stageSceneDefs = Array.Empty<SceneDef>();

		private static string[] _baseSceneNames = Array.Empty<string>();

		private static readonly Dictionary<string, SceneIndex> nameToIndex = new Dictionary<string, SceneIndex>(StringComparer.OrdinalIgnoreCase);

		private static SceneDef currentSceneDef;

		public static ResourceAvailability availability;

		public static int sceneDefCount => indexToSceneDef.Length;

		public static ReadOnlyArray<SceneDef> allSceneDefs => indexToSceneDef;

		public static ReadOnlyArray<SceneDef> allStageSceneDefs => _stageSceneDefs;

		public static ReadOnlyArray<string> allBaseSceneNames => _baseSceneNames;

		[NotNull]
		public static SceneDef mostRecentSceneDef { get; private set; }

		public static event Action<SceneDef> onMostRecentSceneDefChanged;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<SceneDef>> getAdditionalEntries
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.SceneCatalog.getAdditionalEntries", value, LegacyModContentPackProvider.instance.registrationContentPack.sceneDefs);
			}
			remove
			{
			}
		}

		public static IEnumerator Init()
		{
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
			yield return SetSceneDefs(ContentManager.sceneDefs);
			availability.MakeAvailable();
		}

		private static IEnumerator SetSceneDefs([NotNull] SceneDef[] newSceneDefs)
		{
			SceneDef[] array = indexToSceneDef;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].sceneDefIndex = SceneIndex.Invalid;
			}
			ArrayUtils.CloneTo(newSceneDefs, ref indexToSceneDef);
			Array.Sort(indexToSceneDef, (SceneDef a, SceneDef b) => string.CompareOrdinal(a.cachedName, b.cachedName));
			for (int j = 0; j < indexToSceneDef.Length; j++)
			{
				indexToSceneDef[j].sceneDefIndex = (SceneIndex)j;
			}
			yield return null;
			nameToIndex.Clear();
			for (int k = 0; k < indexToSceneDef.Length; k++)
			{
				SceneDef sceneDef = indexToSceneDef[k];
				nameToIndex[sceneDef.cachedName] = (SceneIndex)k;
			}
			List<string> list = new List<string>();
			List<SceneDef> list2 = new List<SceneDef>();
			array = indexToSceneDef;
			foreach (SceneDef sceneDef2 in array)
			{
				if (!list.Contains(sceneDef2.baseSceneName))
				{
					list.Add(sceneDef2.baseSceneName);
				}
				if (sceneDef2.sceneType == SceneType.Stage)
				{
					list2.Add(sceneDef2);
				}
			}
			int num = 0;
			_stageSceneDefs = new SceneDef[list2.Count];
			foreach (SceneDef item in list2)
			{
				_stageSceneDefs[num++] = item;
			}
			num = 0;
			_baseSceneNames = new string[list.Count];
			foreach (string item2 in list)
			{
				_baseSceneNames[num++] = item2;
			}
			currentSceneDef = GetSceneDefFromSceneName(SceneManager.GetActiveScene().name);
			mostRecentSceneDef = currentSceneDef;
			yield return null;
		}

		private static void OnActiveSceneChanged(Scene oldScene, Scene newScene)
		{
			currentSceneDef = GetSceneDefFromSceneName(newScene.name);
			if ((object)currentSceneDef != null)
			{
				mostRecentSceneDef = currentSceneDef;
				SceneCatalog.onMostRecentSceneDefChanged?.Invoke(mostRecentSceneDef);
			}
		}

		[NotNull]
		public static UnlockableDef GetUnlockableLogFromBaseSceneName([NotNull] string baseSceneName)
		{
			return UnlockableCatalog.GetUnlockableDef(string.Format(CultureInfo.InvariantCulture, "Logs.Stages.{0}", baseSceneName));
		}

		[CanBeNull]
		public static SceneDef GetSceneDefForCurrentScene()
		{
			return GetSceneDefFromScene(SceneManager.GetActiveScene());
		}

		[CanBeNull]
		public static SceneDef GetSceneDef(SceneIndex sceneIndex)
		{
			return ArrayUtils.GetSafe(indexToSceneDef, (int)sceneIndex);
		}

		[CanBeNull]
		public static SceneDef GetSceneDefFromSceneName([NotNull] string sceneName)
		{
			SceneDef sceneDef = FindSceneDef(sceneName);
			if ((object)sceneDef != null)
			{
				return sceneDef;
			}
			UnityEngine.Debug.LogWarningFormat("Could not find scene with name \"{0}\".", sceneName);
			return null;
		}

		[CanBeNull]
		public static SceneDef GetSceneDefFromScene(Scene scene)
		{
			return GetSceneDefFromSceneName(scene.name);
		}

		public static SceneIndex FindSceneIndex([NotNull] string sceneName)
		{
			if (nameToIndex.TryGetValue(sceneName, out var value))
			{
				return value;
			}
			return SceneIndex.Invalid;
		}

		public static SceneDef FindSceneDef([NotNull] string sceneName)
		{
			return ArrayUtils.GetSafe(indexToSceneDef, (int)FindSceneIndex(sceneName));
		}
	}
	[MeansImplicitUse]
	public abstract class SearchableAttribute : System.Attribute
	{
		private static readonly Dictionary<Type, List<SearchableAttribute>> instancesListsByType;

		private static HashSet<string> assemblyBlacklist;

		public object target { get; private set; }

		public static List<SearchableAttribute> GetInstances<T>() where T : SearchableAttribute
		{
			if (instancesListsByType.TryGetValue(typeof(T), out var value))
			{
				return value;
			}
			return null;
		}

		public static void GetInstances<T>(List<T> dest) where T : SearchableAttribute
		{
			List<SearchableAttribute> instances = GetInstances<T>();
			if (instances == null)
			{
				return;
			}
			foreach (SearchableAttribute item in instances)
			{
				dest.Add((T)item);
			}
		}

		private static IEnumerable<Assembly> GetScannableAssemblies()
		{
			return from a in AppDomain.CurrentDomain.GetAssemblies()
				where !assemblyBlacklist.Contains(a.GetName().Name)
				select a;
		}

		private static void Scan()
		{
			IEnumerable<Type> enumerable = GetScannableAssemblies().SelectMany((Assembly a) => a.GetTypes());
			List<SearchableAttribute> allInstancesList = new List<SearchableAttribute>();
			Type memoizedInput = null;
			List<SearchableAttribute> memoizedOutput = null;
			foreach (Type item in enumerable)
			{
				foreach (SearchableAttribute customAttribute in CustomAttributeExtensions.GetCustomAttributes<SearchableAttribute>(item, inherit: false))
				{
					Register(customAttribute, item);
				}
				MemberInfo[] members = item.GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MemberInfo element in members)
				{
					foreach (SearchableAttribute customAttribute2 in CustomAttributeExtensions.GetCustomAttributes<SearchableAttribute>(element, inherit: false))
					{
						Register(customAttribute2, element);
					}
				}
			}
			List<SearchableAttribute> GetInstancesListForType(Type attributeType)
			{
				if (attributeType.Equals(memoizedInput))
				{
					return memoizedOutput;
				}
				if (!instancesListsByType.TryGetValue(attributeType, out var value))
				{
					value = new List<SearchableAttribute>();
					instancesListsByType.Add(attributeType, value);
				}
				memoizedInput = attributeType;
				memoizedOutput = value;
				return value;
			}
			void Register(SearchableAttribute attribute, object target)
			{
				attribute.target = target;
				allInstancesList.Add(attribute);
				GetInstancesListForType(attribute.GetType()).Add(attribute);
			}
		}

		static SearchableAttribute()
		{
			instancesListsByType = new Dictionary<Type, List<SearchableAttribute>>();
			assemblyBlacklist = new HashSet<string>
			{
				"mscorlib", "UnityEngine", "UnityEngine.AIModule", "UnityEngine.ARModule", "UnityEngine.AccessibilityModule", "UnityEngine.AnimationModule", "UnityEngine.AssetBundleModule", "UnityEngine.AudioModule", "UnityEngine.BaselibModule", "UnityEngine.ClothModule",
				"UnityEngine.ClusterInputModule", "UnityEngine.ClusterRendererModule", "UnityEngine.CoreModule", "UnityEngine.CrashReportingModule", "UnityEngine.DirectorModule", "UnityEngine.FileSystemHttpModule", "UnityEngine.GameCenterModule", "UnityEngine.GridModule", "UnityEngine.HotReloadModule", "UnityEngine.IMGUIModule",
				"UnityEngine.ImageConversionModule", "UnityEngine.InputModule", "UnityEngine.JSONSerializeModule", "UnityEngine.LocalizationModule", "UnityEngine.ParticleSystemModule", "UnityEngine.PerformanceReportingModule", "UnityEngine.PhysicsModule", "UnityEngine.Physics2DModule", "UnityEngine.ProfilerModule", "UnityEngine.ScreenCaptureModule",
				"UnityEngine.SharedInternalsModule", "UnityEngine.SpatialTrackingModule", "UnityEngine.SpriteMaskModule", "UnityEngine.SpriteShapeModule", "UnityEngine.StreamingModule", "UnityEngine.StyleSheetsModule", "UnityEngine.SubstanceModule", "UnityEngine.TLSModule", "UnityEngine.TerrainModule", "UnityEngine.TerrainPhysicsModule",
				"UnityEngine.TextCoreModule", "UnityEngine.TextRenderingModule", "UnityEngine.TilemapModule", "UnityEngine.TimelineModule", "UnityEngine.UIModule", "UnityEngine.UIElementsModule", "UnityEngine.UNETModule", "UnityEngine.UmbraModule", "UnityEngine.UnityAnalyticsModule", "UnityEngine.UnityConnectModule",
				"UnityEngine.UnityTestProtocolModule", "UnityEngine.UnityWebRequestModule", "UnityEngine.UnityWebRequestAssetBundleModule", "UnityEngine.UnityWebRequestAudioModule", "UnityEngine.UnityWebRequestTextureModule", "UnityEngine.UnityWebRequestWWWModule", "UnityEngine.VFXModule", "UnityEngine.VRModule", "UnityEngine.VehiclesModule", "UnityEngine.VideoModule",
				"UnityEngine.WindModule", "UnityEngine.XRModule", "UnityEditor", "Unity.Locator", "System.Core", "System", "Mono.Security", "System.Configuration", "System.Xml", "Unity.DataContract",
				"Unity.PackageManager", "UnityEngine.UI", "UnityEditor.UI", "UnityEditor.TestRunner", "UnityEngine.TestRunner", "nunit.framework", "UnityEngine.Timeline", "UnityEditor.Timeline", "UnityEngine.Networking", "UnityEditor.Networking",
				"UnityEditor.GoogleAudioSpatializer", "UnityEngine.GoogleAudioSpatializer", "UnityEditor.SpatialTracking", "UnityEngine.SpatialTracking", "UnityEditor.VR", "UnityEditor.Graphs", "UnityEditor.WindowsStandalone.Extensions", "SyntaxTree.VisualStudio.Unity.Bridge", "Rewired_ControlMapper_CSharp_Editor", "Rewired_CSharp_Editor",
				"Unity.ProBuilder.AddOns.Editor", "Wwise-Editor", "Unity.RenderPipelines.Core.Editor", "Unity.RenderPipelines.Core.Runtime", "Unity.TextMeshPro.Editor", "Unity.PackageManagerUI.Editor", "Rewired_NintendoSwitch_CSharp", "Unity.Postprocessing.Editor", "Rewired_CSharp", "Unity.Postprocessing.Runtime",
				"Rewired_NintendoSwitch_CSharp_Editor", "Wwise", "Unity.RenderPipelines.Core.ShaderLibrary", "Unity.TextMeshPro", "Rewired_UnityUI_CSharp_Editor", "Facepunch.Steamworks", "Rewired_Editor", "Rewired_Core", "Rewired_Windows_Lib", "Rewired_NintendoSwitch_Editor",
				"Rewired_NintendoSwitch_EditorRuntime", "Zio", "AssetIdRemapUtility", "ProBuilderCore", "ProBuilderMeshOps", "KdTreeLib", "pb_Stl", "Poly2Tri", "ProBuilderEditor", "netstandard",
				"System.Xml.Linq", "Unity.Cecil", "Unity.SerializationLogic", "Unity.Legacy.NRefactory", "ExCSS.Unity", "Unity.IvyParser", "UnityEditor.iOS.Extensions.Xcode", "SyntaxTree.VisualStudio.Unity.Messaging", "Microsoft.GeneratedCode", "Anonymously",
				"Hosted", "DynamicMethods", "Assembly", "UnityEditor.Switch.Extensions"
			};
			try
			{
				Scan();
			}
			catch (Exception ex)
			{
				System.Console.WriteLine(ex.Message);
			}
		}
	}
	[Serializable]
	public class SerializableLoadout
	{
		[Serializable]
		public struct BodyLoadout
		{
			[Serializable]
			public struct SkillChoice
			{
				public SkillFamily skillFamily;

				public SkillDef variant;
			}

			public CharacterBody body;

			public SkillChoice[] skillChoices;

			public SkinDef skinChoice;
		}

		private class LoadoutBuilder
		{
			private struct SkillSetter
			{
				public readonly BodyIndex bodyIndex;

				public readonly int skillSlotIndex;

				public readonly uint skillVariantIndex;

				public SkillSetter(BodyIndex bodyIndex, int skillSlotIndex, uint skillVariantIndex)
				{
					this.bodyIndex = bodyIndex;
					this.skillSlotIndex = skillSlotIndex;
					this.skillVariantIndex = skillVariantIndex;
				}
			}

			private struct SkinSetter
			{
				public readonly BodyIndex bodyIndex;

				public readonly uint skinIndex;

				public SkinSetter(BodyIndex bodyIndex, uint skinIndex)
				{
					this.bodyIndex = bodyIndex;
					this.skinIndex = skinIndex;
				}
			}

			private readonly SkillSetter[] skillSetters;

			private readonly SkinSetter[] skinSetters;

			public LoadoutBuilder(SerializableLoadout serializedLoadout)
			{
				BodyLoadout[] bodyLoadouts = serializedLoadout.bodyLoadouts;
				List<SkillSetter> list = new List<SkillSetter>(8);
				List<SkinSetter> list2 = new List<SkinSetter>(bodyLoadouts.Length);
				for (int i = 0; i < bodyLoadouts.Length; i++)
				{
					ref BodyLoadout reference = ref bodyLoadouts[i];
					CharacterBody body = reference.body;
					if (!body)
					{
						continue;
					}
					BodyIndex bodyIndex = body.bodyIndex;
					GenericSkill[] bodyPrefabSkillSlots = BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex);
					BodyLoadout.SkillChoice[] skillChoices = reference.skillChoices;
					for (int j = 0; j < skillChoices.Length; j++)
					{
						ref BodyLoadout.SkillChoice reference2 = ref skillChoices[j];
						int num = FindSkillSlotIndex(bodyPrefabSkillSlots, reference2.skillFamily);
						int num2 = FindSkillVariantIndex(reference2.skillFamily, reference2.variant);
						if (num != -1 && num2 != -1)
						{
							list.Add(new SkillSetter(bodyIndex, num, (uint)num2));
						}
					}
					int num3 = Array.IndexOf(BodyCatalog.GetBodySkins(bodyIndex), reference.skinChoice);
					if (num3 != -1)
					{
						list2.Add(new SkinSetter(bodyIndex, (uint)num3));
					}
				}
				skillSetters = list.ToArray();
				skinSetters = list2.ToArray();
			}

			public void Apply(Loadout loadout)
			{
				for (int i = 0; i < skillSetters.Length; i++)
				{
					ref SkillSetter reference = ref skillSetters[i];
					loadout.bodyLoadoutManager.SetSkillVariant(reference.bodyIndex, reference.skillSlotIndex, reference.skillVariantIndex);
				}
				for (int j = 0; j < skinSetters.Length; j++)
				{
					ref SkinSetter reference2 = ref skinSetters[j];
					loadout.bodyLoadoutManager.SetSkinIndex(reference2.bodyIndex, reference2.skinIndex);
				}
			}

			private static int FindSkillSlotIndex(GenericSkill[] skillSlots, SkillFamily skillFamily)
			{
				for (int i = 0; i < skillSlots.Length; i++)
				{
					if ((object)skillSlots[i].skillFamily == skillFamily)
					{
						return i;
					}
				}
				return -1;
			}

			private static int FindSkillVariantIndex(SkillFamily skillFamily, SkillDef skillDef)
			{
				if ((bool)skillFamily)
				{
					if (skillFamily.variants != null)
					{
						for (int i = 0; i < skillFamily.variants.Length; i++)
						{
							if ((object)skillFamily.variants[i].skillDef == skillDef)
							{
								return i;
							}
						}
					}
					else
					{
						UnityEngine.Debug.LogError("SkillFamily " + ((UnityEngine.Object)skillFamily).name + " has null skill variants");
					}
				}
				else
				{
					UnityEngine.Debug.LogError("FindSkillVariantIndex: SkillFamily is null");
				}
				return -1;
			}
		}

		public BodyLoadout[] bodyLoadouts = Array.Empty<BodyLoadout>();

		private LoadoutBuilder loadoutBuilder;

		private static bool loadoutSystemReady;

		public bool isEmpty => bodyLoadouts.Length == 0;

		public void Apply(Loadout loadout)
		{
			if (!loadoutSystemReady)
			{
				throw new InvalidOperationException("Loadout system is not yet initialized.");
			}
			if (loadoutBuilder == null)
			{
				loadoutBuilder = new LoadoutBuilder(this);
			}
			loadoutBuilder.Apply(loadout);
		}

		[SystemInitializer(new Type[] { typeof(Loadout) })]
		private static void Init()
		{
			loadoutSystemReady = true;
		}
	}
	public static class SettingsConVars
	{
		private class VSyncCountConVar : BaseConVar
		{
			private static VSyncCountConVar instance = new VSyncCountConVar("vsync_count", ConVarFlags.Archive | ConVarFlags.Engine, null, "Vsync count.");

			private VSyncCountConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					QualitySettings.vSyncCount = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(QualitySettings.vSyncCount);
			}
		}

		private class WindowModeConVar : BaseConVar
		{
			private enum WindowMode
			{
				Fullscreen,
				Window,
				FullscreenExclusive
			}

			private static WindowModeConVar instance = new WindowModeConVar("window_mode", ConVarFlags.Archive | ConVarFlags.Engine, null, "The window mode. Choices are Fullscreen and Window.");

			private WindowModeConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				try
				{
					FullScreenMode fullScreenMode = FullScreenMode.ExclusiveFullScreen;
					switch ((WindowMode)Enum.Parse(typeof(WindowMode), newValue, ignoreCase: true))
					{
					case WindowMode.Fullscreen:
						fullScreenMode = FullScreenMode.FullScreenWindow;
						break;
					case WindowMode.Window:
						fullScreenMode = FullScreenMode.Windowed;
						break;
					case WindowMode.FullscreenExclusive:
						fullScreenMode = FullScreenMode.ExclusiveFullScreen;
						break;
					}
					Screen.fullScreenMode = fullScreenMode;
				}
				catch (ArgumentException)
				{
					Console.ShowHelpText(name);
				}
			}

			public override string GetString()
			{
				return (Screen.fullScreenMode switch
				{
					FullScreenMode.ExclusiveFullScreen => WindowMode.FullscreenExclusive, 
					FullScreenMode.FullScreenWindow => WindowMode.Fullscreen, 
					FullScreenMode.MaximizedWindow => WindowMode.Window, 
					FullScreenMode.Windowed => WindowMode.Window, 
					_ => WindowMode.Fullscreen, 
				}).ToString();
			}
		}

		private class ResolutionConVar : BaseConVar
		{
			private static ResolutionConVar instance = new ResolutionConVar("resolution", ConVarFlags.Archive | ConVarFlags.Engine, null, "The resolution of the game window. Format example: 1920x1080x60");

			private ResolutionConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				string[] array = newValue.Split('x');
				if (array.Length < 1 || !TextSerialization.TryParseInvariant(array[0], out int result))
				{
					throw new ConCommandException("Invalid resolution format. No width integer. Example: \"1920x1080x60\".");
				}
				if (array.Length < 2 || !TextSerialization.TryParseInvariant(array[1], out int result2))
				{
					throw new ConCommandException("Invalid resolution format. No height integer. Example: \"1920x1080x60\".");
				}
				if (array.Length < 3 || !TextSerialization.TryParseInvariant(array[2], out int result3))
				{
					throw new ConCommandException("Invalid resolution format. No refresh rate integer. Example: \"1920x1080x60\".");
				}
				Screen.SetResolution(result, result2, Screen.fullScreenMode, result3);
			}

			public override string GetString()
			{
				Resolution currentResolution = Screen.currentResolution;
				return string.Format(CultureInfo.InvariantCulture, "{0}x{1}x{2}", Screen.width, Screen.height, currentResolution.refreshRate);
			}

			[ConCommand(commandName = "resolution_list", flags = ConVarFlags.None, helpText = "Prints a list of all possible resolutions for the current display.")]
			private static void CCResolutionList(ConCommandArgs args)
			{
				Resolution[] resolutions = Screen.resolutions;
				string[] array = new string[resolutions.Length];
				for (int i = 0; i < resolutions.Length; i++)
				{
					Resolution resolution = resolutions[i];
					array[i] = $"{resolution.width}x{resolution.height}x{resolution.refreshRate}";
				}
			}
		}

		private class FpsMaxConVar : BaseConVar
		{
			private static FpsMaxConVar instance = new FpsMaxConVar("fps_max", ConVarFlags.Archive, "60", "Maximum FPS. -1 is unlimited.");

			private FpsMaxConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					Application.targetFrameRate = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(Application.targetFrameRate);
			}
		}

		private class ShadowsConVar : BaseConVar
		{
			private static ShadowsConVar instance = new ShadowsConVar("r_shadows", ConVarFlags.Archive | ConVarFlags.Engine, null, "Shadow quality. Can be \"All\" \"HardOnly\" or \"Disable\"");

			private ShadowsConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				try
				{
					QualitySettings.shadows = (ShadowQuality)Enum.Parse(typeof(ShadowQuality), newValue, ignoreCase: true);
				}
				catch (ArgumentException)
				{
					Console.ShowHelpText(name);
				}
			}

			public override string GetString()
			{
				return QualitySettings.shadows.ToString();
			}
		}

		private class SoftParticlesConVar : BaseConVar
		{
			private static SoftParticlesConVar instance = new SoftParticlesConVar("r_softparticles", ConVarFlags.Archive | ConVarFlags.Engine, null, "Whether or not soft particles are enabled.");

			private SoftParticlesConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					QualitySettings.softParticles = result != 0;
				}
			}

			public override string GetString()
			{
				if (!QualitySettings.softParticles)
				{
					return "0";
				}
				return "1";
			}
		}

		private class FoliageWindConVar : BaseConVar
		{
			private static FoliageWindConVar instance = new FoliageWindConVar("r_foliagewind", ConVarFlags.Archive, "1", "Whether or not foliage has wind.");

			private FoliageWindConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					if (result >= 1)
					{
						Shader.EnableKeyword("ENABLE_WIND");
					}
					else
					{
						Shader.DisableKeyword("ENABLE_WIND");
					}
				}
			}

			public override string GetString()
			{
				if (!Shader.IsKeywordEnabled("ENABLE_WIND"))
				{
					return "0";
				}
				return "1";
			}
		}

		private class LodBiasConVar : BaseConVar
		{
			private static LodBiasConVar instance = new LodBiasConVar("r_lod_bias", ConVarFlags.Archive | ConVarFlags.Engine, null, "LOD bias.");

			private LodBiasConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out float result))
				{
					QualitySettings.lodBias = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(QualitySettings.lodBias);
			}
		}

		private class MaximumLodConVar : BaseConVar
		{
			private static MaximumLodConVar instance = new MaximumLodConVar("r_lod_max", ConVarFlags.Archive | ConVarFlags.Engine, null, "The maximum allowed LOD level.");

			private MaximumLodConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					QualitySettings.maximumLODLevel = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(QualitySettings.maximumLODLevel);
			}
		}

		private class MasterTextureLimitConVar : BaseConVar
		{
			private static MasterTextureLimitConVar instance = new MasterTextureLimitConVar("master_texture_limit", ConVarFlags.Archive | ConVarFlags.Engine, null, "Reduction in texture quality. 0 is highest quality textures, 1 is half, 2 is quarter, etc.");

			private MasterTextureLimitConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					QualitySettings.masterTextureLimit = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(QualitySettings.masterTextureLimit);
			}
		}

		private class AnisotropicFilteringConVar : BaseConVar
		{
			private static AnisotropicFilteringConVar instance = new AnisotropicFilteringConVar("anisotropic_filtering", ConVarFlags.Archive, "Disable", "The anisotropic filtering mode. Can be \"Disable\", \"Enable\" or \"ForceEnable\".");

			private AnisotropicFilteringConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				try
				{
					QualitySettings.anisotropicFiltering = (AnisotropicFiltering)Enum.Parse(typeof(AnisotropicFiltering), newValue, ignoreCase: true);
				}
				catch (ArgumentException)
				{
					Console.ShowHelpText(name);
				}
			}

			public override string GetString()
			{
				return QualitySettings.anisotropicFiltering.ToString();
			}
		}

		private class ShadowResolutionConVar : BaseConVar
		{
			private static ShadowResolutionConVar instance = new ShadowResolutionConVar("shadow_resolution", ConVarFlags.Archive | ConVarFlags.Engine, "Medium", "Default shadow resolution. Can be \"Low\", \"Medium\", \"High\" or \"VeryHigh\".");

			private ShadowResolutionConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				try
				{
					QualitySettings.shadowResolution = (ShadowResolution)Enum.Parse(typeof(ShadowResolution), newValue, ignoreCase: true);
				}
				catch (ArgumentException)
				{
					Console.ShowHelpText(name);
				}
			}

			public override string GetString()
			{
				return QualitySettings.shadowResolution.ToString();
			}
		}

		private class ShadowCascadesConVar : BaseConVar
		{
			private static ShadowCascadesConVar instance = new ShadowCascadesConVar("shadow_cascades", ConVarFlags.Archive | ConVarFlags.Engine, null, "The number of cascades to use for directional light shadows. low=0 high=4");

			private ShadowCascadesConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					QualitySettings.shadowCascades = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(QualitySettings.shadowCascades);
			}
		}

		private class ShadowDistanceConvar : BaseConVar
		{
			private static ShadowDistanceConvar instance = new ShadowDistanceConvar("shadow_distance", ConVarFlags.Archive, "200", "The distance in meters to draw shadows.");

			private ShadowDistanceConvar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out float result))
				{
					QualitySettings.shadowDistance = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(QualitySettings.shadowDistance);
			}
		}

		private class MSAAConvar : BaseConVar
		{
			private static MSAAConvar instance = new MSAAConvar("r_ui_msaa", ConVarFlags.Archive, "0", "Whether or not MSAA for the UI is enabled.");

			private MSAAConvar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					QualitySettings.antiAliasing = result;
				}
			}

			public override string GetString()
			{
				return QualitySettings.antiAliasing.ToString();
			}
		}

		private class PpMotionBlurConVar : BaseConVar
		{
			private static MotionBlur settings;

			private static PpMotionBlurConVar instance = new PpMotionBlurConVar("pp_motionblur", ConVarFlags.Archive, "0", "Motion blur. 0 = disabled 1 = enabled");

			private PpMotionBlurConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				RoR2Application.instance.postProcessSettingsController.sharedProfile.TryGetSettings<MotionBlur>(out settings);
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result) && (bool)settings)
				{
					settings.active = result == 0;
				}
			}

			public override string GetString()
			{
				if (!settings)
				{
					return "1";
				}
				if (!settings.active)
				{
					return "1";
				}
				return "0";
			}
		}

		private class PpSobelOutlineConVar : BaseConVar
		{
			private static SobelOutline sobelOutlineSettings;

			private static PpSobelOutlineConVar instance = new PpSobelOutlineConVar("pp_sobel_outline", ConVarFlags.Archive, "1", "Whether or not to use the sobel rim light effect.");

			private PpSobelOutlineConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				RoR2Application.instance.postProcessSettingsController.sharedProfile.TryGetSettings<SobelOutline>(out sobelOutlineSettings);
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result) && (bool)sobelOutlineSettings)
				{
					sobelOutlineSettings.active = result == 0;
				}
			}

			public override string GetString()
			{
				if (!sobelOutlineSettings)
				{
					return "1";
				}
				if (!sobelOutlineSettings.active)
				{
					return "1";
				}
				return "0";
			}
		}

		private class PpBloomConVar : BaseConVar
		{
			private static Bloom settings;

			private static PpBloomConVar instance = new PpBloomConVar("pp_bloom", ConVarFlags.Archive | ConVarFlags.Engine, null, "Bloom postprocessing. 0 = disabled 1 = enabled");

			private PpBloomConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				RoR2Application.instance.postProcessSettingsController.sharedProfile.TryGetSettings<Bloom>(out settings);
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result) && (bool)settings)
				{
					settings.active = result == 0;
				}
			}

			public override string GetString()
			{
				if (!settings)
				{
					return "1";
				}
				if (!settings.active)
				{
					return "1";
				}
				return "0";
			}
		}

		private class PpAOConVar : BaseConVar
		{
			private static AmbientOcclusion settings;

			private static PpAOConVar instance = new PpAOConVar("pp_ao", ConVarFlags.Archive | ConVarFlags.Engine, null, "SSAO postprocessing. 0 = disabled 1 = enabled");

			private PpAOConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				RoR2Application.instance.postProcessSettingsController.sharedProfile.TryGetSettings<AmbientOcclusion>(out settings);
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result) && (bool)settings)
				{
					settings.active = result == 0;
				}
			}

			public override string GetString()
			{
				if (!settings)
				{
					return "1";
				}
				if (!settings.active)
				{
					return "1";
				}
				return "0";
			}
		}

		private class PpScreenDistortionConVar : BaseConVar
		{
			private static LensDistortion settings;

			private static PpScreenDistortionConVar instance = new PpScreenDistortionConVar("pp_screendistortion", ConVarFlags.Archive | ConVarFlags.Engine, null, "Screen distortion, like from Spinel Tonic. 0 = disabled 1 = enabled");

			private PpScreenDistortionConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				RoR2Application.instance.postProcessSettingsController.sharedProfile.TryGetSettings<LensDistortion>(out settings);
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result) && (bool)settings)
				{
					settings.active = result == 0;
				}
			}

			public override string GetString()
			{
				if (!settings)
				{
					return "1";
				}
				if (!settings.active)
				{
					return "1";
				}
				return "0";
			}
		}

		private class PpGammaConVar : BaseConVar
		{
			private static ColorGrading colorGradingSettings;

			private static PpGammaConVar instance = new PpGammaConVar("gamma", ConVarFlags.Archive, "0", "Gamma boost, from -inf to inf.");

			private PpGammaConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
				RoR2Application.instance.postProcessSettingsController.sharedProfile.TryGetSettings<ColorGrading>(out colorGradingSettings);
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out float result) && (bool)colorGradingSettings)
				{
					colorGradingSettings.gamma.value.w = result;
				}
			}

			public override string GetString()
			{
				if (!colorGradingSettings)
				{
					return "0";
				}
				return TextSerialization.ToStringInvariant(colorGradingSettings.gamma.value.w);
			}
		}

		public static readonly BoolConVar cvExpAndMoneyEffects = new BoolConVar("exp_and_money_effects", ConVarFlags.Archive, "1", "Whether or not to create effects for experience and money from defeating monsters.");

		public static BoolConVar enableDamageNumbers = new BoolConVar("enable_damage_numbers", ConVarFlags.Archive, "1", "Whether or not damage and healing numbers spawn.");

		public static BoolConVar enableScreenDistortion = new BoolConVar("enable_screen_distortion", ConVarFlags.Archive, "1", "Screen distortion, like from Spinel Tonic. 0 = disabled 1 = enabled");
	}
	[Serializable]
	[StructLayout(LayoutKind.Sequential, Pack = 8)]
	public struct Sha256Hash : IEquatable<Sha256Hash>
	{
		[SerializeField]
		private ulong _00_07;

		[SerializeField]
		private ulong _08_15;

		[SerializeField]
		private ulong _16_23;

		[SerializeField]
		private ulong _24_31;

		private static readonly byte[] ulongToByteBuffer = new byte[8];

		public static Sha256Hash FromHexString(string hexString, int startIndex = 0)
		{
			if (startIndex + hexString.Length < 64)
			{
				throw new ArgumentException("Not enough characters in string.");
			}
			int readPos = startIndex;
			ulong num = ReadULong();
			ulong num2 = ReadULong();
			ulong num3 = ReadULong();
			ulong num4 = ReadULong();
			return FromULong4(num, num2, num3, num4);
			byte ReadByte()
			{
				byte num5 = ReadNibble();
				byte b = ReadNibble();
				return (byte)((num5 << 4) | b);
			}
			byte ReadNibble()
			{
				char c = hexString[readPos++];
				if (c >= '0' && c <= '9')
				{
					return (byte)(c - 48);
				}
				if (c >= 'a' && c <= 'f')
				{
					return (byte)(10 + (c - 97));
				}
				if (c >= 'A' && c <= 'F')
				{
					return (byte)(10 + (c - 65));
				}
				return 0;
			}
			ulong ReadULong()
			{
				ulongToByteBuffer[0] = ReadByte();
				ulongToByteBuffer[1] = ReadByte();
				ulongToByteBuffer[2] = ReadByte();
				ulongToByteBuffer[3] = ReadByte();
				ulongToByteBuffer[4] = ReadByte();
				ulongToByteBuffer[5] = ReadByte();
				ulongToByteBuffer[6] = ReadByte();
				ulongToByteBuffer[7] = ReadByte();
				return BitConverter.ToUInt64(ulongToByteBuffer, 0);
			}
		}

		public static Sha256Hash FromULong4(ulong _00_07, ulong _08_15, ulong _16_23, ulong _24_31)
		{
			Sha256Hash result = default(Sha256Hash);
			result._00_07 = _00_07;
			result._08_15 = _08_15;
			result._16_23 = _16_23;
			result._24_31 = _24_31;
			return result;
		}

		public void ToULong4(out ulong _00_07, out ulong _08_15, out ulong _16_23, out ulong _24_31)
		{
			_00_07 = this._00_07;
			_08_15 = this._08_15;
			_16_23 = this._16_23;
			_24_31 = this._24_31;
		}

		public static Sha256Hash FromBytes(byte[] bytes, int startIndex = 0)
		{
			if (startIndex + bytes.Length < 32)
			{
				throw new ArgumentException("Not enough bytes in buffer.");
			}
			Sha256Hash result = default(Sha256Hash);
			result._00_07 = BitConverter.ToUInt64(bytes, startIndex);
			result._08_15 = BitConverter.ToUInt64(bytes, startIndex + 8);
			result._16_23 = BitConverter.ToUInt64(bytes, startIndex + 16);
			result._24_31 = BitConverter.ToUInt64(bytes, startIndex + 24);
			return result;
		}

		public bool Equals(Sha256Hash other)
		{
			if (_00_07 == other._00_07 && _08_15 == other._08_15 && _16_23 == other._16_23)
			{
				return _24_31 == other._24_31;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is Sha256Hash other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((((_00_07.GetHashCode() * 397) ^ _08_15.GetHashCode()) * 397) ^ _16_23.GetHashCode()) * 397) ^ _24_31.GetHashCode();
		}

		public static StringBuilder AppendSha256HashHex(StringBuilder stringBuilder, in Sha256Hash hash)
		{
			stringBuilder.EnsureCapacity(stringBuilder.Length + 64);
			AppendULong(hash._00_07);
			AppendULong(hash._08_15);
			AppendULong(hash._16_23);
			AppendULong(hash._24_31);
			return stringBuilder;
			void AppendULong(ulong value)
			{
				stringBuilder.AppendByteHexValue((byte)(value & 0xFF));
				stringBuilder.AppendByteHexValue((byte)((value >> 8) & 0xFF));
				stringBuilder.AppendByteHexValue((byte)((value >> 16) & 0xFF));
				stringBuilder.AppendByteHexValue((byte)((value >> 24) & 0xFF));
				stringBuilder.AppendByteHexValue((byte)((value >> 32) & 0xFF));
				stringBuilder.AppendByteHexValue((byte)((value >> 40) & 0xFF));
				stringBuilder.AppendByteHexValue((byte)((value >> 48) & 0xFF));
				stringBuilder.AppendByteHexValue((byte)((value >> 56) & 0xFF));
			}
		}

		public override string ToString()
		{
			return AppendSha256HashHex(new StringBuilder(64), in this).ToString();
		}
	}
	public class ShrineRebirthController : NetworkBehaviour, IDisplayNameProvider
	{
		[Serializable]
		public class InteractorUnityEvent : UnityEvent
		{
		}

		private Interactor rebirthCandidate;

		private CharacterBody rebirthBody;

		[SerializeField]
		private int maxItemsTogive = 4;

		public EntityStateMachine stateMachine;

		public InteractorUnityEvent onRebirthChoiceFinished;

		private int itemsGiven;

		[SerializeField]
		private NetworkUIPromptController networkUIPromptController;

		private bool RebirthItemGiven;

		[SyncVar]
		public GameObject portalObject;

		public PurchaseInteraction purchaseInteraction;

		public ChildLocator childLocator;

		public bool isForTesting;

		public GameObject onShrineRevealObjectiveTextObject;

		public GameObject onRebirthOrContinueTextObject;

		[SerializeField]
		public InteractableSpawnCard helminthPortalISC;

		private ItemIndex rebirthIndex = ItemIndex.None;

		private PickupPickerController _pickupPickerController;

		private NetworkUIPromptController _netUIPromptController;

		private NetworkInstanceId ___portalObjectNetId;

		private static int kRpcRpcChangeInteractScript;

		public GameObject NetworkportalObject
		{
			get
			{
				return portalObject;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref portalObject, 1u, ref ___portalObjectNetId);
			}
		}

		private NetworkUser GetNetworkUserFromCandidate()
		{
			if ((bool)rebirthBody)
			{
				CharacterMaster master = rebirthBody.master;
				if ((bool)master)
				{
					PlayerCharacterMasterController playerCharacterMasterController = master.playerCharacterMasterController;
					if ((bool)playerCharacterMasterController)
					{
						NetworkUser networkUser = playerCharacterMasterController.networkUser;
						if ((bool)networkUser)
						{
							return networkUser;
						}
					}
				}
			}
			return null;
		}

		[Server]
		public void StoreRebirthItemChoice(int itemChoice)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.ShrineRebirthController::StoreRebirthItemChoice(System.Int32)' called on client");
				return;
			}
			PickupDef pickupDef = PickupCatalog.GetPickupDef(new PickupIndex(itemChoice));
			_ = rebirthCandidate == null;
			if (pickupDef == null || !rebirthCandidate || !rebirthBody || !rebirthBody.inventory)
			{
				return;
			}
			rebirthBody.inventory.RemoveItem(pickupDef.itemIndex);
			itemsGiven++;
			StoreRebirthItem(pickupDef);
			if (!MaxRebirthItemsGiven())
			{
				return;
			}
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				readOnlyInstances.CallCmdStoreRebirthItems(rebirthIndex);
			}
			onRebirthChoiceFinished?.Invoke();
			stateMachine.SetNextState(new RebirthChoice());
		}

		private bool MaxRebirthItemsGiven()
		{
			bool result = false;
			if (itemsGiven >= maxItemsTogive)
			{
				result = true;
			}
			return result;
		}

		private void StoreRebirthItem(PickupDef pickupDef)
		{
			if ((bool)GetNetworkUserFromCandidate())
			{
				if (!RebirthItemGiven)
				{
					RebirthItemGiven = true;
					rebirthIndex = pickupDef.itemIndex;
				}
				if ((bool)rebirthCandidate)
				{
					Run.instance.GrantUnlockToAllParticipatingPlayers(UnlockableCatalog.GetUnlockableDef("Artifacts.Rebirth"));
				}
			}
		}

		public void AssignPotentialInteractor(Interactor potentialInteractor)
		{
			if (!rebirthCandidate)
			{
				rebirthCandidate = potentialInteractor;
				rebirthBody = rebirthCandidate.GetComponent<CharacterBody>();
			}
		}

		private void Start()
		{
			_pickupPickerController = base.gameObject.GetComponent<PickupPickerController>();
			_netUIPromptController = GetComponent<NetworkUIPromptController>();
			_netUIPromptController.enabled = false;
			_pickupPickerController.enabled = false;
		}

		[ClientRpc]
		public void RpcChangeInteractScript()
		{
			UnityEngine.Object.Destroy(base.gameObject.GetComponent<PurchaseInteraction>());
			_netUIPromptController.enabled = true;
			_pickupPickerController.enabled = true;
			_pickupPickerController.SetAvailable(newAvailable: true);
			portalObject.SetActive(value: true);
		}

		public void SetEntityStateMachineToRebirthOrPortal()
		{
			stateMachine.SetNextState(new RebirthOrPortalChoice());
		}

		public string GetDisplayName()
		{
			return Language.GetString("SHRINE_REBIRTH_NAME");
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeRpcRpcChangeInteractScript(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcChangeInteractScript called on server.");
			}
			else
			{
				((ShrineRebirthController)obj).RpcChangeInteractScript();
			}
		}

		public void CallRpcChangeInteractScript()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcChangeInteractScript called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcChangeInteractScript);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcChangeInteractScript");
		}

		static ShrineRebirthController()
		{
			kRpcRpcChangeInteractScript = 1007694444;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ShrineRebirthController), kRpcRpcChangeInteractScript, InvokeRpcRpcChangeInteractScript);
			NetworkCRC.RegisterBehaviour("ShrineRebirthController", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(portalObject);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(portalObject);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___portalObjectNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				portalObject = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___portalObjectNetId.IsEmpty())
			{
				NetworkportalObject = ClientScene.FindLocalObject(___portalObjectNetId);
			}
		}
	}
	public enum SkillSlot : sbyte
	{
		None = -1,
		Primary,
		Secondary,
		Utility,
		Special
	}
	public enum SkinIndex
	{
		None = -1
	}
	public static class SkinCatalog
	{
		private static SkinDef[] allSkinDefs = Array.Empty<SkinDef>();

		private static SkinDef[][] skinsByBody = Array.Empty<SkinDef[]>();

		public static int skinCount => allSkinDefs.Length;

		[SystemInitializer(new Type[] { typeof(BodyCatalog) })]
		private static void Init()
		{
			List<SkinDef> list = new List<SkinDef>();
			skinsByBody = new SkinDef[BodyCatalog.bodyCount][];
			for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < BodyCatalog.bodyCount; bodyIndex++)
			{
				SkinDef[] array = ArrayUtils.Clone(FindSkinsForBody(bodyIndex));
				skinsByBody[(int)bodyIndex] = array;
				list.AddRange(array);
			}
			allSkinDefs = list.ToArray();
			for (int i = 0; i < allSkinDefs.Length; i++)
			{
				allSkinDefs[i].skinIndex = (SkinIndex)i;
			}
		}

		[CanBeNull]
		public static SkinDef FindCurrentSkinDefForBodyInstance(GameObject bodyObject)
		{
			ModelLocator component = bodyObject.GetComponent<ModelLocator>();
			if (!component || !component.modelTransform)
			{
				return null;
			}
			ModelSkinController component2 = component.modelTransform.GetComponent<ModelSkinController>();
			if (!component2)
			{
				return null;
			}
			return ArrayUtils.GetSafe(component2.skins, component2.currentSkinIndex);
		}

		[NotNull]
		private static SkinDef[] FindSkinsForBody(BodyIndex bodyIndex)
		{
			ModelLocator component = BodyCatalog.GetBodyPrefab(bodyIndex).GetComponent<ModelLocator>();
			if (!component || !component.modelTransform)
			{
				return Array.Empty<SkinDef>();
			}
			ModelSkinController component2 = component.modelTransform.GetComponent<ModelSkinController>();
			if (!component2)
			{
				return Array.Empty<SkinDef>();
			}
			return component2.skins;
		}

		[CanBeNull]
		public static SkinDef GetSkinDef(SkinIndex skinIndex)
		{
			return ArrayUtils.GetSafe(allSkinDefs, (int)skinIndex);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[NotNull]
		private static SkinDef[] GetBodySkinDefs(BodyIndex bodyIndex)
		{
			SkinDef[][] array = skinsByBody;
			SkinDef[] defaultValue = Array.Empty<SkinDef>();
			return ArrayUtils.GetSafe(array, (int)bodyIndex, in defaultValue);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int GetBodySkinCount(BodyIndex bodyIndex)
		{
			return GetBodySkinDefs(bodyIndex).Length;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static SkinDef GetBodySkinDef(BodyIndex bodyIndex, int skinIndex)
		{
			return ArrayUtils.GetSafe(GetBodySkinDefs(bodyIndex), skinIndex);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int FindLocalSkinIndexForBody(BodyIndex bodyIndex, [CanBeNull] SkinDef skinDef)
		{
			return Array.IndexOf(GetBodySkinDefs(bodyIndex), skinDef);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkinDef")]
	public class SkinDef : ScriptableObject
	{
		[Serializable]
		public struct GameObjectActivation
		{
			[PrefabReference]
			public GameObject gameObject;

			public bool shouldActivate;
		}

		[Serializable]
		public struct MeshReplacement
		{
			[PrefabReference]
			public Renderer renderer;

			public Mesh mesh;
		}

		[Serializable]
		public struct ProjectileGhostReplacement
		{
			public GameObject projectilePrefab;

			public GameObject projectileGhostReplacementPrefab;
		}

		[Serializable]
		public struct MinionSkinReplacement
		{
			public GameObject minionBodyPrefab;

			public SkinDef minionSkin;
		}

		private struct RendererInfoTemplate
		{
			public string path;

			public CharacterModel.RendererInfo data;
		}

		private struct GameObjectActivationTemplate
		{
			public string path;

			public bool shouldActivate;
		}

		private struct MeshReplacementTemplate
		{
			public string path;

			public Mesh mesh;
		}

		private class RuntimeSkin
		{
			public RendererInfoTemplate[] rendererInfoTemplates;

			public GameObjectActivationTemplate[] gameObjectActivationTemplates;

			public MeshReplacementTemplate[] meshReplacementTemplates;

			private static readonly List<CharacterModel.RendererInfo> rendererInfoBuffer = new List<CharacterModel.RendererInfo>();

			public void Apply(GameObject modelObject)
			{
				Transform transform = modelObject.transform;
				for (int i = 0; i < rendererInfoTemplates.Length; i++)
				{
					ref RendererInfoTemplate reference = ref rendererInfoTemplates[i];
					CharacterModel.RendererInfo data = reference.data;
					Transform transform2 = transform.Find(reference.path);
					if ((bool)transform2)
					{
						Renderer component = transform2.GetComponent<Renderer>();
						if ((bool)component)
						{
							data.renderer = component;
							rendererInfoBuffer.Add(data);
						}
						else
						{
							UnityEngine.Debug.LogWarningFormat("No renderer at {0}/{1}", transform.name, reference.path);
						}
					}
					else
					{
						UnityEngine.Debug.LogWarningFormat("Could not find transform \"{0}\" relative to \"{1}\".", reference.path, transform.name);
					}
				}
				CharacterModel component2 = modelObject.GetComponent<CharacterModel>();
				component2.baseRendererInfos = rendererInfoBuffer.ToArray();
				component2.forceUpdate = true;
				rendererInfoBuffer.Clear();
				foreach (Transform gameObjectActivationTransform in component2.gameObjectActivationTransforms)
				{
					if ((bool)gameObjectActivationTransform.gameObject)
					{
						gameObjectActivationTransform.gameObject.SetActive(value: false);
					}
				}
				component2.gameObjectActivationTransforms.Clear();
				for (int j = 0; j < gameObjectActivationTemplates.Length; j++)
				{
					ref GameObjectActivationTemplate reference2 = ref gameObjectActivationTemplates[j];
					bool shouldActivate = reference2.shouldActivate;
					Transform transform3 = transform.Find(reference2.path);
					transform3.gameObject.SetActive(shouldActivate);
					component2.gameObjectActivationTransforms.Add(transform3);
				}
				for (int k = 0; k < meshReplacementTemplates.Length; k++)
				{
					ref MeshReplacementTemplate reference3 = ref meshReplacementTemplates[k];
					Mesh mesh = reference3.mesh;
					Renderer component3 = transform.Find(reference3.path).GetComponent<Renderer>();
					if (component3 is MeshRenderer)
					{
						component3.GetComponent<MeshFilter>().sharedMesh = mesh;
					}
					else if (component3 is SkinnedMeshRenderer skinnedMeshRenderer)
					{
						skinnedMeshRenderer.sharedMesh = mesh;
					}
				}
			}
		}

		[Tooltip("The skins which will be applied before this one.")]
		public SkinDef[] baseSkins;

		[ShowThumbnail]
		public Sprite icon;

		public string nameToken;

		[Obsolete("Use 'unlockableDef' instead.")]
		public string unlockableName;

		public UnlockableDef unlockableDef;

		[PrefabReference]
		public GameObject rootObject;

		public CharacterModel.RendererInfo[] rendererInfos = Array.Empty<CharacterModel.RendererInfo>();

		public GameObjectActivation[] gameObjectActivations = Array.Empty<GameObjectActivation>();

		public MeshReplacement[] meshReplacements = Array.Empty<MeshReplacement>();

		public ProjectileGhostReplacement[] projectileGhostReplacements = Array.Empty<ProjectileGhostReplacement>();

		public MinionSkinReplacement[] minionSkinReplacements = Array.Empty<MinionSkinReplacement>();

		private RuntimeSkin runtimeSkin;

		public SkinIndex skinIndex { get; set; } = SkinIndex.None;


		private void Bake()
		{
			if (runtimeSkin != null)
			{
				return;
			}
			runtimeSkin = new RuntimeSkin();
			List<RendererInfoTemplate> rendererInfoTemplates = new List<RendererInfoTemplate>();
			List<GameObjectActivationTemplate> gameObjectActivationTemplates = new List<GameObjectActivationTemplate>();
			List<MeshReplacementTemplate> meshReplacementTemplates = new List<MeshReplacementTemplate>();
			SkinDef[] array = baseSkins;
			foreach (SkinDef skinDef in array)
			{
				if (!skinDef)
				{
					continue;
				}
				skinDef.Bake();
				if (skinDef.runtimeSkin == null)
				{
					continue;
				}
				if (skinDef.runtimeSkin.rendererInfoTemplates != null)
				{
					RendererInfoTemplate[] rendererInfoTemplates2 = skinDef.runtimeSkin.rendererInfoTemplates;
					for (int j = 0; j < rendererInfoTemplates2.Length; j++)
					{
						AddRendererInfoTemplate(rendererInfoTemplates2[j]);
					}
				}
				if (skinDef.runtimeSkin.gameObjectActivationTemplates != null)
				{
					GameObjectActivationTemplate[] gameObjectActivationTemplates2 = skinDef.runtimeSkin.gameObjectActivationTemplates;
					for (int j = 0; j < gameObjectActivationTemplates2.Length; j++)
					{
						AddGameObjectActivationTemplate(gameObjectActivationTemplates2[j]);
					}
				}
				if (skinDef.runtimeSkin.meshReplacementTemplates != null)
				{
					MeshReplacementTemplate[] meshReplacementTemplates2 = skinDef.runtimeSkin.meshReplacementTemplates;
					for (int j = 0; j < meshReplacementTemplates2.Length; j++)
					{
						AddMeshReplacementTemplate(meshReplacementTemplates2[j]);
					}
				}
			}
			for (int k = 0; k < rendererInfos.Length; k++)
			{
				ref CharacterModel.RendererInfo reference = ref rendererInfos[k];
				if (!reference.renderer)
				{
					UnityEngine.Debug.LogErrorFormat("Skin {0} has an empty renderer field in its rendererInfos at index {1}.", this, k);
				}
				else
				{
					RendererInfoTemplate rendererInfoTemplate2 = default(RendererInfoTemplate);
					rendererInfoTemplate2.data = reference;
					rendererInfoTemplate2.path = Util.BuildPrefabTransformPath(rootObject.transform, reference.renderer.transform);
					AddRendererInfoTemplate(rendererInfoTemplate2);
				}
			}
			runtimeSkin.rendererInfoTemplates = rendererInfoTemplates.ToArray();
			for (int l = 0; l < gameObjectActivations.Length; l++)
			{
				ref GameObjectActivation reference2 = ref gameObjectActivations[l];
				if (!reference2.gameObject)
				{
					UnityEngine.Debug.LogErrorFormat("Skin {0} has an empty gameObject field in its gameObjectActivations at index {1}.", this, l);
				}
				else
				{
					GameObjectActivationTemplate gameObjectActivationTemplate2 = default(GameObjectActivationTemplate);
					gameObjectActivationTemplate2.shouldActivate = reference2.shouldActivate;
					gameObjectActivationTemplate2.path = Util.BuildPrefabTransformPath(rootObject.transform, reference2.gameObject.transform);
					AddGameObjectActivationTemplate(gameObjectActivationTemplate2);
				}
			}
			runtimeSkin.gameObjectActivationTemplates = gameObjectActivationTemplates.ToArray();
			for (int m = 0; m < meshReplacements.Length; m++)
			{
				ref MeshReplacement reference3 = ref meshReplacements[m];
				if (!reference3.renderer)
				{
					UnityEngine.Debug.LogErrorFormat("Skin {0} has an empty renderer field in its meshReplacements at index {1}.", this, m);
				}
				else
				{
					MeshReplacementTemplate meshReplacementTemplate2 = default(MeshReplacementTemplate);
					meshReplacementTemplate2.mesh = reference3.mesh;
					meshReplacementTemplate2.path = Util.BuildPrefabTransformPath(rootObject.transform, reference3.renderer.transform);
					AddMeshReplacementTemplate(meshReplacementTemplate2);
				}
			}
			runtimeSkin.meshReplacementTemplates = meshReplacementTemplates.ToArray();
			void AddGameObjectActivationTemplate(GameObjectActivationTemplate gameObjectActivationTemplate)
			{
				int num = 0;
				for (int count2 = gameObjectActivationTemplates.Count; num < count2; num++)
				{
					if (gameObjectActivationTemplates[num].path == gameObjectActivationTemplate.path)
					{
						gameObjectActivationTemplates[num] = gameObjectActivationTemplate;
						return;
					}
				}
				gameObjectActivationTemplates.Add(gameObjectActivationTemplate);
			}
			void AddMeshReplacementTemplate(MeshReplacementTemplate meshReplacementTemplate)
			{
				int n = 0;
				for (int count = meshReplacementTemplates.Count; n < count; n++)
				{
					if (meshReplacementTemplates[n].path == meshReplacementTemplate.path)
					{
						meshReplacementTemplates[n] = meshReplacementTemplate;
						return;
					}
				}
				meshReplacementTemplates.Add(meshReplacementTemplate);
			}
			void AddRendererInfoTemplate(RendererInfoTemplate rendererInfoTemplate)
			{
				int num2 = 0;
				for (int count3 = rendererInfoTemplates.Count; num2 < count3; num2++)
				{
					if (rendererInfoTemplates[num2].path == rendererInfoTemplate.path)
					{
						rendererInfoTemplates[num2] = rendererInfoTemplate;
						return;
					}
				}
				rendererInfoTemplates.Add(rendererInfoTemplate);
			}
		}

		public void Apply(GameObject modelObject)
		{
			Bake();
			runtimeSkin.Apply(modelObject);
		}

		private void Awake()
		{
			if (Application.IsPlaying(this))
			{
				Bake();
			}
		}

		[ContextMenu("Upgrade unlockableName to unlockableDef")]
		public void UpgradeUnlockableNameToUnlockableDef()
		{
			if (!string.IsNullOrEmpty(unlockableName) && !this.unlockableDef)
			{
				UnlockableDef unlockableDef = LegacyResourcesAPI.Load<UnlockableDef>("UnlockableDefs/" + unlockableName);
				if ((bool)unlockableDef)
				{
					this.unlockableDef = unlockableDef;
					unlockableName = null;
				}
			}
			EditorUtil.SetDirty(this);
		}
	}
	public class SpectatorCameraCommands : NetworkBehaviour
	{
		private void Start()
		{
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class SphereSearch
	{
		private struct Candidate
		{
			public Collider collider;

			public HurtBox hurtBox;

			public UnityEngine.Vector3 position;

			public UnityEngine.Vector3 difference;

			public float distanceSqr;

			public Transform root;

			public ProjectileController projectileController;

			public EntityLocator entityLocator;

			public static bool HurtBoxHealthComponentIsValid(Candidate candidate)
			{
				return candidate.hurtBox.healthComponent;
			}
		}

		private struct SearchData
		{
			private Candidate[] candidatesBuffer;

			private int[] candidatesMapping;

			private int candidatesCount;

			private bool hurtBoxesLoaded;

			private bool rootsLoaded;

			private bool projectileControllersLoaded;

			private bool entityLocatorsLoaded;

			private bool filteredByHurtBoxes;

			private bool filteredByHurtBoxHealthComponents;

			private bool filteredByProjectileControllers;

			private bool filteredByEntityLocators;

			public static readonly SearchData empty = new SearchData
			{
				candidatesBuffer = Array.Empty<Candidate>(),
				candidatesMapping = Array.Empty<int>(),
				candidatesCount = 0,
				hurtBoxesLoaded = false
			};

			public SearchData(Candidate[] candidatesBuffer)
			{
				this.candidatesBuffer = candidatesBuffer;
				candidatesMapping = new int[candidatesBuffer.Length];
				candidatesCount = candidatesBuffer.Length;
				for (int i = 0; i < candidatesBuffer.Length; i++)
				{
					candidatesMapping[i] = i;
				}
				hurtBoxesLoaded = false;
				rootsLoaded = false;
				projectileControllersLoaded = false;
				entityLocatorsLoaded = false;
				filteredByHurtBoxes = false;
				filteredByHurtBoxHealthComponents = false;
				filteredByProjectileControllers = false;
				filteredByEntityLocators = false;
			}

			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			private ref Candidate GetCandidate(int i)
			{
				return ref candidatesBuffer[candidatesMapping[i]];
			}

			private void RemoveCandidate(int i)
			{
				ArrayUtils.ArrayRemoveAt(candidatesMapping, ref candidatesCount, i);
			}

			public void LoadHurtBoxes()
			{
				if (!hurtBoxesLoaded)
				{
					for (int i = 0; i < candidatesCount; i++)
					{
						ref Candidate candidate = ref GetCandidate(i);
						candidate.hurtBox = candidate.collider.GetComponent<HurtBox>();
					}
					hurtBoxesLoaded = true;
				}
			}

			public void LoadRoots()
			{
				if (!rootsLoaded)
				{
					for (int i = 0; i < candidatesCount; i++)
					{
						ref Candidate candidate = ref GetCandidate(i);
						candidate.root = candidate.collider.transform.root;
					}
					rootsLoaded = true;
				}
			}

			public void LoadProjectileControllers()
			{
				if (!projectileControllersLoaded)
				{
					LoadRoots();
					for (int i = 0; i < candidatesCount; i++)
					{
						ref Candidate candidate = ref GetCandidate(i);
						candidate.projectileController = (candidate.root ? candidate.root.GetComponent<ProjectileController>() : null);
					}
					projectileControllersLoaded = true;
				}
			}

			public void LoadColliderEntityLocators()
			{
				if (!entityLocatorsLoaded)
				{
					for (int i = 0; i < candidatesCount; i++)
					{
						ref Candidate candidate = ref GetCandidate(i);
						candidate.entityLocator = candidate.collider.GetComponent<EntityLocator>();
					}
					entityLocatorsLoaded = true;
				}
			}

			public void FilterByProjectileControllers()
			{
				if (filteredByProjectileControllers)
				{
					return;
				}
				LoadProjectileControllers();
				for (int num = candidatesCount - 1; num >= 0; num--)
				{
					if (!GetCandidate(num).projectileController)
					{
						RemoveCandidate(num);
					}
				}
				filteredByProjectileControllers = true;
			}

			public void FilterByHurtBoxes()
			{
				if (filteredByHurtBoxes)
				{
					return;
				}
				LoadHurtBoxes();
				for (int num = candidatesCount - 1; num >= 0; num--)
				{
					if (!GetCandidate(num).hurtBox)
					{
						RemoveCandidate(num);
					}
				}
				filteredByHurtBoxes = true;
			}

			public void FilterByHurtBoxHealthComponents()
			{
				if (filteredByHurtBoxHealthComponents)
				{
					return;
				}
				FilterByHurtBoxes();
				for (int num = candidatesCount - 1; num >= 0; num--)
				{
					if (!GetCandidate(num).hurtBox.healthComponent)
					{
						RemoveCandidate(num);
					}
				}
				filteredByHurtBoxHealthComponents = true;
			}

			public void FilterByHurtBoxTeam(TeamMask teamMask)
			{
				FilterByHurtBoxes();
				for (int num = candidatesCount - 1; num >= 0; num--)
				{
					if (!teamMask.HasTeam(GetCandidate(num).hurtBox.teamIndex))
					{
						RemoveCandidate(num);
					}
				}
			}

			public void FilterByHurtBoxEntitiesDistinct()
			{
				FilterByHurtBoxHealthComponents();
				for (int num = candidatesCount - 1; num >= 0; num--)
				{
					ref Candidate candidate = ref GetCandidate(num);
					for (int num2 = num - 1; num2 >= 0; num2--)
					{
						ref Candidate candidate2 = ref GetCandidate(num2);
						if ((object)candidate.hurtBox.healthComponent == candidate2.hurtBox.healthComponent)
						{
							RemoveCandidate(num);
							break;
						}
					}
				}
			}

			public void FilterByColliderEntities()
			{
				if (filteredByEntityLocators)
				{
					return;
				}
				LoadColliderEntityLocators();
				for (int num = candidatesCount - 1; num >= 0; num--)
				{
					ref Candidate candidate = ref GetCandidate(num);
					if (!candidate.entityLocator || !candidate.entityLocator.entity)
					{
						RemoveCandidate(num);
					}
				}
				filteredByEntityLocators = true;
			}

			public void FilterByColliderEntitiesDistinct()
			{
				FilterByColliderEntities();
				for (int num = candidatesCount - 1; num >= 0; num--)
				{
					ref Candidate candidate = ref GetCandidate(num);
					for (int num2 = num - 1; num2 >= 0; num2--)
					{
						ref Candidate candidate2 = ref GetCandidate(num2);
						if ((object)candidate.entityLocator.entity == candidate2.entityLocator.entity)
						{
							RemoveCandidate(num);
							break;
						}
					}
				}
			}

			public void OrderByDistance()
			{
				if (candidatesCount == 0)
				{
					return;
				}
				bool flag = true;
				while (flag)
				{
					flag = false;
					ref Candidate reference = ref GetCandidate(0);
					int i = 1;
					for (int num = candidatesCount - 1; i < num; i++)
					{
						ref Candidate candidate = ref GetCandidate(i);
						if (reference.distanceSqr > candidate.distanceSqr)
						{
							Util.Swap(ref candidatesMapping[i - 1], ref candidatesMapping[i]);
							flag = true;
						}
						else
						{
							reference = ref candidate;
						}
					}
				}
			}

			public HurtBox[] GetHurtBoxes()
			{
				FilterByHurtBoxes();
				HurtBox[] array = new HurtBox[candidatesCount];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = GetCandidate(i).hurtBox;
				}
				return array;
			}

			public void GetHurtBoxes(List<HurtBox> dest)
			{
				int num = dest.Count + candidatesCount;
				if (dest.Capacity < num)
				{
					dest.Capacity = num;
				}
				for (int i = 0; i < candidatesCount; i++)
				{
					dest.Add(GetCandidate(i).hurtBox);
				}
			}

			public void GetProjectileControllers(List<ProjectileController> dest)
			{
				int num = dest.Count + candidatesCount;
				if (dest.Capacity < num)
				{
					dest.Capacity = num;
				}
				for (int i = 0; i < candidatesCount; i++)
				{
					dest.Add(GetCandidate(i).projectileController);
				}
			}

			public void GetColliders(List<Collider> dest)
			{
				int num = dest.Count + candidatesCount;
				if (dest.Capacity < num)
				{
					dest.Capacity = num;
				}
				for (int i = 0; i < candidatesCount; i++)
				{
					dest.Add(GetCandidate(i).collider);
				}
			}
		}

		public float radius;

		public UnityEngine.Vector3 origin;

		public LayerMask mask;

		public QueryTriggerInteraction queryTriggerInteraction;

		private SearchData searchData = SearchData.empty;

		public SphereSearch ClearCandidates()
		{
			searchData = SearchData.empty;
			return this;
		}

		public SphereSearch RefreshCandidates()
		{
			Collider[] colliders;
			int num = HGPhysics.OverlapSphere(out colliders, origin, radius, mask, queryTriggerInteraction);
			Candidate[] array = new Candidate[num];
			for (int i = 0; i < num; i++)
			{
				Collider collider = colliders[i];
				ref Candidate reference = ref array[i];
				reference.collider = collider;
				if (collider is MeshCollider { convex: false })
				{
					reference.position = collider.ClosestPointOnBounds(origin);
				}
				else
				{
					reference.position = collider.ClosestPoint(origin);
				}
				reference.difference = reference.position - origin;
				reference.distanceSqr = reference.difference.sqrMagnitude;
			}
			HGPhysics.ReturnResults(colliders);
			searchData = new SearchData(array);
			return this;
		}

		public SphereSearch OrderCandidatesByDistance()
		{
			searchData.OrderByDistance();
			return this;
		}

		public SphereSearch FilterCandidatesByHurtBoxTeam(TeamMask mask)
		{
			searchData.FilterByHurtBoxTeam(mask);
			return this;
		}

		public SphereSearch FilterCandidatesByColliderEntities()
		{
			searchData.FilterByColliderEntities();
			return this;
		}

		public SphereSearch FilterCandidatesByDistinctColliderEntities()
		{
			searchData.FilterByColliderEntitiesDistinct();
			return this;
		}

		public SphereSearch FilterCandidatesByDistinctHurtBoxEntities()
		{
			searchData.FilterByHurtBoxEntitiesDistinct();
			return this;
		}

		public SphereSearch FilterCandidatesByProjectileControllers()
		{
			searchData.FilterByProjectileControllers();
			return this;
		}

		public HurtBox[] GetHurtBoxes()
		{
			return searchData.GetHurtBoxes();
		}

		public void GetHurtBoxes(List<HurtBox> dest)
		{
			searchData.GetHurtBoxes(dest);
		}

		public void GetProjectileControllers(List<ProjectileController> dest)
		{
			searchData.GetProjectileControllers(dest);
		}

		public void GetColliders(List<Collider> dest)
		{
			searchData.GetColliders(dest);
		}
	}
	public enum StageOrder
	{
		Normal,
		Random,
		Count
	}
	public sealed class SteamworksClientManager : IDisposable
	{
		private bool disposed;

		public static SteamworksClientManager instance { get; private set; }

		public Client steamworksClient { get; private set; }

		private static event Action _onLoaded;

		public static event Action onLoaded
		{
			add
			{
				if (instance == null)
				{
					_onLoaded += value;
				}
				else if (!instance.disposed)
				{
					value();
				}
			}
			remove
			{
				_onLoaded -= value;
			}
		}

		private SteamworksClientManager()
		{
			if (!Application.isEditor && File.Exists("steam_appid.txt"))
			{
				try
				{
					File.Delete("steam_appid.txt");
				}
				catch (Exception)
				{
				}
				if (File.Exists("steam_appid.txt"))
				{
					Dispose();
					return;
				}
			}
			Facepunch.Steamworks.Config.ForUnity(Application.platform.ToString());
			steamworksClient = new Client(632360u);
			if (!steamworksClient.IsValid)
			{
				RoR2Application.HardStopPlayInEditor("Steam Init Failed", "Steam Init failed. Steam is likely not running.");
				Dispose();
				return;
			}
			if (!Application.isEditor)
			{
				if (Client.RestartIfNecessary(632360u) || !steamworksClient.IsValid || !SteamApiValidator.IsValidSteamApiDll())
				{
					Dispose();
					return;
				}
				if (!steamworksClient.App.IsSubscribed(632360u))
				{
					Dispose();
					return;
				}
			}
			RoR2Application.steamBuildId = TextSerialization.ToStringInvariant(steamworksClient.BuildId);
			RoR2Application.onUpdate += Update;
			RoR2Application.cloudStorage = new SteamworksRemoteStorageFileSystem();
			(PlatformSystems.lobbyManager as SteamworksLobbyManager)?.Init();
		}

		private void Update()
		{
			steamworksClient.Update();
		}

		public void Dispose()
		{
			if (disposed)
			{
				return;
			}
			disposed = true;
			RoR2Application.onUpdate -= Update;
			if (steamworksClient != null)
			{
				if ((bool)NetworkManagerSystem.singleton)
				{
					NetworkManagerSystem.singleton.ForceCloseAllConnections();
				}
				steamworksClient.Lobby.Leave();
				if (Server.Instance != null)
				{
					Server.Instance.Dispose();
				}
				steamworksClient.Update();
				steamworksClient.Dispose();
				steamworksClient = null;
			}
		}

		public static void Init()
		{
			RoR2Application.loadSteamworksClient = delegate
			{
				instance = new SteamworksClientManager();
				if (!instance.disposed)
				{
					SteamworksClientManager._onLoaded?.Invoke();
					SteamworksClientManager._onLoaded = null;
					return true;
				}
				return false;
			};
			RoR2Application.unloadSteamworksClient = delegate
			{
				instance?.Dispose();
				instance = null;
			};
		}

		[ConCommand(commandName = "steamworks_client_print_p2p_connection_status", flags = ConVarFlags.None, helpText = "Prints debug information for any established P2P connection to the specified Steam ID.")]
		private static void CCSteamworksClientPrintP2PConnectionStatus(ConCommandArgs args)
		{
			Facepunch.Steamworks.Networking.P2PSessionState sessionState = default(Facepunch.Steamworks.Networking.P2PSessionState);
			if (Client.Instance.Networking.GetP2PSessionState(args.GetArgPlatformID(0).ID, ref sessionState))
			{
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				stringBuilder.Append("BytesQueuedForSend").Append("=").Append(sessionState.BytesQueuedForSend)
					.AppendLine();
				stringBuilder.Append("Connecting").Append("=").Append(sessionState.Connecting)
					.AppendLine();
				stringBuilder.Append("ConnectionActive").Append("=").Append(sessionState.ConnectionActive)
					.AppendLine();
				stringBuilder.Append("PacketsQueuedForSend").Append("=").Append(sessionState.PacketsQueuedForSend)
					.AppendLine();
				stringBuilder.Append("P2PSessionError").Append("=").Append(sessionState.P2PSessionError)
					.AppendLine();
				stringBuilder.Append("UsingRelay").Append("=").Append(sessionState.UsingRelay)
					.AppendLine();
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			}
		}
	}
	internal static class SteamworksInviteManager
	{
		private const string rpConnect = "connect";

		private const string rpStatus = "status";

		private static void SetKeyValue([NotNull] string key, [CanBeNull] string value)
		{
			Client.Instance.User.SetRichPresence(key, value);
		}

		private static void OnNetworkStart()
		{
			string text = null;
			PlatformID platformID = PlatformID.nil;
			PlatformID platformID2 = PlatformID.nil;
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			for (int i = 0; i < commandLineArgs.Length - 1; i++)
			{
				switch (commandLineArgs[i].ToLower(CultureInfo.InvariantCulture))
				{
				case "+connect":
				{
					if (AddressPortPair.TryParse(commandLineArgs[i + 1], out var addressPortPair))
					{
						text = addressPortPair.address + ":" + addressPortPair.port;
					}
					break;
				}
				case "+connect_steamworks_p2p":
				{
					if (PlatformID.TryParse(commandLineArgs[i + 1], out var result2))
					{
						platformID = result2;
					}
					break;
				}
				case "+steam_lobby_join":
				{
					if (PlatformID.TryParse(commandLineArgs[i + 1], out var result))
					{
						platformID2 = result;
					}
					break;
				}
				}
			}
			if (platformID2 != PlatformID.nil)
			{
				Console.instance.SubmitCmd(null, "steam_lobby_join " + platformID2.value);
			}
			else if (platformID != PlatformID.nil)
			{
				Console.instance.SubmitCmd(null, "connect_steamworks_p2p " + platformID.value);
			}
			else if (text != null)
			{
				Console.instance.SubmitCmd(null, "connect " + text);
			}
		}

		private static void OnLobbyChanged()
		{
			if (PlatformSystems.lobbyManager.isInLobby)
			{
				SetKeyValue("connect", "+steam_lobby_join " + PlatformSystems.lobbyManager.GetLobbyID());
			}
			else
			{
				SetKeyValue("connect", null);
			}
		}

		private static void OnInvitedToGame(SteamFriend steamFriend, string connectString)
		{
			UnityEngine.Debug.LogFormat("OnGameRichPresenceJoinRequested connectString=\"{0}\" steamFriend=\"{1}\"", connectString, steamFriend.Name);
			string[] array = connectString.Split(' ');
			if (array.Length < 2)
			{
				return;
			}
			if (array[0] == "+connect_steamworks_p2p" && PlatformID.TryParse(array[1], out var result))
			{
				if (!PlatformSystems.lobbyManager.ownsLobby)
				{
					PlatformSystems.lobbyManager.LeaveLobby();
				}
				QuitConfirmationHelper.IssueQuitCommand(null, "connect_steamworks_p2p " + result.value);
			}
			if (!(array[0] == "+steam_lobby_join"))
			{
				return;
			}
			if (!(PlatformSystems.lobbyManager as PCLobbyManager).CheckLobbyIdValidity(array[1]))
			{
				if (PlatformSystems.ShouldUseEpicOnlineSystems)
				{
					PCLobbyManager.ShowEnableCrossPlayPopup(isLobbyCrossplay: false);
				}
				else
				{
					PCLobbyManager.ShowEnableCrossPlayPopup(isLobbyCrossplay: true);
				}
				return;
			}
			bool shouldUseEpicOnlineSystems = PlatformSystems.ShouldUseEpicOnlineSystems;
			if (PlatformID.TryParse(array[1], out var result2) || shouldUseEpicOnlineSystems)
			{
				if (!PlatformSystems.lobbyManager.ownsLobby)
				{
					PlatformSystems.lobbyManager.LeaveLobby();
				}
				string text = (shouldUseEpicOnlineSystems ? array[1] : result2.value.ToString());
				QuitConfirmationHelper.IssueQuitCommand(null, "steam_lobby_join " + text);
			}
		}

		private static void OnGameServerChangeRequested(string address, string password)
		{
			UnityEngine.Debug.LogFormat("OnGameServerChangeRequested address=\"{0}\"", address);
			if (!PlatformSystems.lobbyManager.ownsLobby)
			{
				PlatformSystems.lobbyManager.LeaveLobby();
			}
			string consoleCmd = $"cl_password \"{Util.EscapeQuotes(password)}\"; connect \"{Util.EscapeQuotes(address)}\"";
			QuitConfirmationHelper.IssueQuitCommand(null, consoleCmd);
		}

		private static void SetupCallbacks()
		{
			NetworkManagerSystem.onStartGlobal += OnNetworkStart;
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyChanged = (Action)Delegate.Combine(lobbyManager.onLobbyChanged, new Action(OnLobbyChanged));
			if (Client.Instance != null)
			{
				Client.Instance.Friends.OnInvitedToGame += OnInvitedToGame;
				Client.Instance.Friends.OnGameServerChangeRequested = OnGameServerChangeRequested;
			}
		}

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
		private static void Init()
		{
			SteamworksClientManager.onLoaded += SetupCallbacks;
		}
	}
	public static class SteamworksLobbyDataGenerator
	{
		private static class ToStringCache
		{
			public static MemoizedToString<PlatformID, ToStringDefault<PlatformID>> serverId;

			public static MemoizedToString<AddressPortPair, ToStringDefault<AddressPortPair>> serverAddress;

			public static MemoizedToString<int, ToStringImplementationInvariant> playerCount;

			public static MemoizedToString<int, ToStringImplementationInvariant> edition;

			public static MemoizedToString<int, ToStringImplementationInvariant> serverMaxPlayers;

			public static MemoizedToString<int, ToStringImplementationInvariant> serverPlayerCount;
		}

		private const int k_cubChatMetadataMax = 8192;

		private const int k_nMaxLobbyKeyLength = 255;

		private static PlatformID lobbyId;

		private static int edition;

		private static RuleBook cachedRuleBook;

		private static bool dirty = false;

		private static readonly string[] specialKeys = new string[9] { "joinable", "name", "appid", "lobbytype", "total_max_players", "v", "qp_cutoff_time", "qp", "starting" };

		private static readonly List<KeyValuePair<string, string>> ruleBookKeyValues = new List<KeyValuePair<string, string>>(1);

		private static readonly KeyValueSplitter ruleBookKeyValueSplitter = new KeyValueSplitter("rulebook", 255, 8192, SetRuleBookKeyValue);

		public static event Action<List<KeyValuePair<string, string>>> getAdditionalKeyValues;

		[SystemInitializer(new Type[] { typeof(RuleBook) })]
		private static void Init()
		{
			cachedRuleBook = new RuleBook();
			if (PlatformSystems.EgsToggleConVar.value != 1)
			{
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onLobbyOwnershipGained = (Action)Delegate.Combine(lobbyManager.onLobbyOwnershipGained, new Action(OnLobbyOwnershipGained));
				LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
				lobbyManager2.onLobbyOwnershipLost = (Action)Delegate.Combine(lobbyManager2.onLobbyOwnershipLost, new Action(OnLobbyOwnershipLost));
			}
		}

		private static void OnLobbyOwnershipGained()
		{
			lobbyId = new PlatformID(Client.Instance.Lobby.CurrentLobby);
			string data = Client.Instance.Lobby.CurrentLobbyData.GetData("v");
			edition = 0;
			if (!string.IsNullOrEmpty(data))
			{
				int.TryParse(data, out edition);
			}
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyMemberDataUpdated = (Action<PlatformID>)Delegate.Combine(lobbyManager.onLobbyMemberDataUpdated, new Action<PlatformID>(SteamworksLobbyManagerOnOnLobbyMemberDataUpdated));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyStateChanged = (Action)Delegate.Combine(lobbyManager2.onLobbyStateChanged, new Action(SteamworksLobbyManagerOnOnLobbyStateChanged));
			NetworkManagerSystem.onStartClientGlobal += NetworkManagerSystemOnOnStartClientGlobal;
			NetworkManagerSystem.onStopClientGlobal += NetworkManagerSystemOnOnStopClientGlobal;
			SceneCatalog.onMostRecentSceneDefChanged += SceneCatalogOnOnMostRecentSceneDefChanged;
			NetworkUser.onNetworkUserDiscovered += NetworkUserOnOnNetworkUserDiscovered;
			NetworkUser.onNetworkUserLost += NetworkUserOnOnNetworkUserLost;
			PreGameController.onPreGameControllerSetRuleBookGlobal += OnPreGameControllerSetRuleBook;
			Run.onRunSetRuleBookGlobal += OnRunSetRuleBook;
			Client.Instance.Lobby.Name = Language.GetStringFormatted("LOBBY_DEFAULT_NAME_FORMAT", Client.Instance.Username);
			UpdateRuleBook();
			RebuildLobbyData();
		}

		private static void OnLobbyOwnershipLost()
		{
			lobbyId = PlatformID.nil;
			edition = 0;
			Run.onRunSetRuleBookGlobal -= OnRunSetRuleBook;
			PreGameController.onPreGameControllerSetRuleBookGlobal -= OnPreGameControllerSetRuleBook;
			NetworkUser.onNetworkUserLost -= NetworkUserOnOnNetworkUserLost;
			NetworkUser.onNetworkUserDiscovered -= NetworkUserOnOnNetworkUserDiscovered;
			SceneCatalog.onMostRecentSceneDefChanged -= SceneCatalogOnOnMostRecentSceneDefChanged;
			NetworkManagerSystem.onStopClientGlobal -= NetworkManagerSystemOnOnStopClientGlobal;
			NetworkManagerSystem.onStartClientGlobal -= NetworkManagerSystemOnOnStartClientGlobal;
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyMemberDataUpdated = (Action<PlatformID>)Delegate.Remove(lobbyManager.onLobbyMemberDataUpdated, new Action<PlatformID>(SteamworksLobbyManagerOnOnLobbyMemberDataUpdated));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyStateChanged = (Action)Delegate.Remove(lobbyManager2.onLobbyStateChanged, new Action(SteamworksLobbyManagerOnOnLobbyStateChanged));
		}

		private static void OnPreGameControllerSetRuleBook(PreGameController run, RuleBook ruleBook)
		{
			UpdateRuleBook();
		}

		private static void OnRunSetRuleBook(Run run, RuleBook ruleBook)
		{
			UpdateRuleBook();
		}

		private static void SteamworksLobbyManagerOnOnLobbyMemberDataUpdated(PlatformID memberId)
		{
			SetDirty();
		}

		private static void SteamworksLobbyManagerOnOnLobbyStateChanged()
		{
			SetDirty();
		}

		private static void NetworkManagerSystemOnOnStartClientGlobal(NetworkClient networkClient)
		{
			SetDirty();
		}

		private static void NetworkManagerSystemOnOnStopClientGlobal()
		{
			SetDirty();
		}

		private static void SceneCatalogOnOnMostRecentSceneDefChanged(SceneDef sceneDef)
		{
			SetDirty();
		}

		private static void NetworkUserOnOnNetworkUserDiscovered(NetworkUser networkUser)
		{
			SetDirty();
		}

		private static void NetworkUserOnOnNetworkUserLost(NetworkUser networkUser)
		{
			SetDirty();
		}

		public static void SetDirty()
		{
			if (!dirty)
			{
				dirty = true;
				RoR2Application.onNextUpdate += RebuildLobbyData;
			}
		}

		public static void RebuildLobbyData()
		{
			try
			{
				dirty = false;
				Lobby lobby = Client.Instance?.Lobby;
				if (lobby == null)
				{
					return;
				}
				Lobby.LobbyData currentLobbyData = lobby.CurrentLobbyData;
				Dictionary<string, string> dictionary = currentLobbyData?.GetAllData();
				if (!lobby.IsOwner || dictionary == null || currentLobbyData == null)
				{
					return;
				}
				string value2 = null;
				dictionary.TryGetValue("total_max_players", out value2);
				if (value2 == null || !int.TryParse(value2, out var result))
				{
					result = LobbyManager.cvSteamLobbyMaxMembers.value;
					currentLobbyData.SetData("total_max_players", result.ToString());
				}
				int num = result - PlatformSystems.lobbyManager.calculatedExtraPlayersCount;
				if (lobby.MaxMembers != num)
				{
					lobby.MaxMembers = num;
				}
				Dictionary<string, string> newData = CollectionPool<KeyValuePair<string, string>, Dictionary<string, string>>.RentCollection();
				List<KeyValuePair<string, string>> list = CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.RentCollection();
				SteamworksLobbyDataGenerator.getAdditionalKeyValues?.Invoke(list);
				for (int i = 0; i < list.Count; i++)
				{
					KeyValuePair<string, string> keyValuePair = list[i];
					AddData(keyValuePair.Key, keyValuePair.Value);
				}
				CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.ReturnCollection(list);
				AddData("build_id", RoR2Application.GetBuildId());
				AddData("_mh", NetworkModCompatibilityHelper.networkModHash);
				int input = PlatformSystems.lobbyManager.calculatedTotalPlayerCount;
				AddData("player_count", ToStringCache.playerCount.GetString(in input));
				string value3 = SceneCatalog.GetSceneDefForCurrentScene()?.baseSceneName;
				if (!string.IsNullOrEmpty(value3))
				{
					AddData("_map", value3);
				}
				GetServerInfo(out var serverId, out var serverAddress, out var isSelf);
				bool flag = false;
				bool num2 = dictionary?.ContainsKey("server_id") ?? false;
				bool flag2 = dictionary?.ContainsKey("server_address") ?? false;
				bool flag3 = num2 || flag2;
				bool flag4 = false;
				if ((bool)NetworkSession.instance)
				{
					flag = NetworkSession.instance.HasFlag(NetworkSession.Flags.HasPassword);
					AddData("_ds", NetworkSession.instance.HasFlag(NetworkSession.Flags.IsDedicatedServer) ? "1" : "0");
					AddData("_pw", flag ? "1" : "0");
					AddData("_svtags", NetworkSession.instance.tagsString);
					input = (int)NetworkSession.instance.maxPlayers;
					AddData("_svmpl", ToStringCache.serverMaxPlayers.GetString(in input));
					input = NetworkUser.readOnlyInstancesList.Count;
					AddData("_svplc", ToStringCache.serverPlayerCount.GetString(in input));
					AddData("_svnm", NetworkSession.instance.serverName);
					if (serverId != PlatformID.nil)
					{
						AddData("server_id", ToStringCache.serverId.GetString(in serverId));
						flag4 = true;
					}
					if (serverAddress.isValid)
					{
						AddData("server_address", ToStringCache.serverAddress.GetString(in serverAddress));
						flag4 = true;
					}
				}
				GameModeIndex gameModeIndex = GameModeIndex.Invalid;
				if ((bool)Run.instance)
				{
					gameModeIndex = Run.instance.gameModeIndex;
				}
				else if ((bool)PreGameController.instance)
				{
					gameModeIndex = PreGameController.instance.gameModeIndex;
				}
				if (gameModeIndex != GameModeIndex.Invalid)
				{
					string gameModeName = GameModeCatalog.GetGameModeName(gameModeIndex);
					AddData("_svgm", gameModeName);
				}
				if (flag4 && !flag3 && flag)
				{
					string value4 = (isSelf ? NetworkManagerSystem.SvPasswordConVar.instance.value : NetworkManagerSystem.cvClPassword.value);
					NetworkWriter networkWriter = new NetworkWriter();
					networkWriter.Write(value4);
					(PlatformSystems.lobbyManager as SteamworksLobbyManager).SendLobbyMessage(LobbyManager.LobbyMessageType.Password, networkWriter);
				}
				for (int j = 0; j < ruleBookKeyValues.Count; j++)
				{
					KeyValuePair<string, string> keyValuePair2 = ruleBookKeyValues[j];
					AddData(keyValuePair2.Key, keyValuePair2.Value);
				}
				for (int k = 0; k < specialKeys.Length; k++)
				{
					dictionary.Remove(specialKeys[k]);
				}
				bool flag5 = false;
				List<string> list2 = CollectionPool<string, List<string>>.RentCollection();
				if (dictionary != null)
				{
					foreach (KeyValuePair<string, string> item in dictionary)
					{
						if (!newData.ContainsKey(item.Key))
						{
							list2.Add(item.Key);
						}
					}
				}
				for (int l = 0; l < list2.Count; l++)
				{
					currentLobbyData.RemoveData(list2[l]);
				}
				if (list2.Count > 0)
				{
					flag5 = true;
				}
				CollectionPool<string, List<string>>.ReturnCollection(list2);
				foreach (KeyValuePair<string, string> item2 in newData)
				{
					string value5 = null;
					if (dictionary == null || !dictionary.TryGetValue(item2.Key, out value5) || !item2.Value.Equals(value5, StringComparison.Ordinal))
					{
						currentLobbyData.SetData(item2.Key, item2.Value);
						flag5 = true;
					}
				}
				if (flag5)
				{
					edition++;
				}
				currentLobbyData.SetData("v", ToStringCache.edition.GetString(in edition));
				CollectionPool<KeyValuePair<string, string>, Dictionary<string, string>>.ReturnCollection(newData);
				void AddData(string key, string value)
				{
					newData.Add(key, value);
				}
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
		}

		private static void GetServerInfo(out PlatformID serverId, out AddressPortPair serverAddress, out bool isSelf)
		{
			serverId = PlatformID.nil;
			serverAddress = default(AddressPortPair);
			isSelf = false;
			HostDescription desiredHost = NetworkManagerSystem.singleton.desiredHost;
			if (desiredHost.hostType == HostDescription.HostType.None)
			{
				return;
			}
			if (desiredHost.hostType == HostDescription.HostType.Self)
			{
				if (NetworkServer.active)
				{
					serverId = NetworkManagerSystem.singleton.serverP2PId;
					isSelf = true;
				}
			}
			else if (desiredHost.hostType == HostDescription.HostType.Steam)
			{
				serverId = desiredHost.userID;
			}
			else if (desiredHost.hostType == HostDescription.HostType.IPv4)
			{
				serverAddress = desiredHost.addressPortPair;
			}
		}

		private static void UpdateRuleBook()
		{
			RuleBook ruleBook = null;
			if ((bool)Run.instance)
			{
				ruleBook = Run.instance.ruleBook;
			}
			else if ((bool)PreGameController.instance)
			{
				ruleBook = PreGameController.instance.readOnlyRuleBook;
			}
			if (ruleBook != null && !ruleBook.Equals(cachedRuleBook))
			{
				cachedRuleBook.Copy(ruleBook);
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				RuleBook.WriteBase64ToStringBuilder(cachedRuleBook, stringBuilder);
				ruleBookKeyValueSplitter.SetValue(stringBuilder);
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			}
			else
			{
				cachedRuleBook.SetToDefaults();
			}
		}

		private static void SetRuleBookKeyValue(string key, string value)
		{
			int num = -1;
			for (int i = 0; i < ruleBookKeyValues.Count; i++)
			{
				if (ruleBookKeyValues[i].Key.Equals(key, StringComparison.Ordinal))
				{
					if (ruleBookKeyValues[i].Value.Equals(value, StringComparison.Ordinal))
					{
						return;
					}
					num = i;
					break;
				}
			}
			if (value == null)
			{
				if (num != -1)
				{
					ruleBookKeyValues.RemoveAt(num);
				}
			}
			else
			{
				KeyValuePair<string, string> keyValuePair = new KeyValuePair<string, string>(key, value);
				if (num != -1)
				{
					ruleBookKeyValues[num] = keyValuePair;
				}
				else
				{
					ruleBookKeyValues.Add(keyValuePair);
				}
			}
			SetDirty();
		}

		[ConCommand(commandName = "steam_lobby_data_regenerate", flags = ConVarFlags.None, helpText = "Forces the current Steamworks lobby data to be regenerated.")]
		public static void CCSteamLobbyRegenerateData(ConCommandArgs args)
		{
			SetDirty();
		}
	}
	public class SteamworksRemoteStorageFileSystem : FileSystem
	{
		private struct SteamworksRemoteStoragePath : IEquatable<SteamworksRemoteStoragePath>
		{
			public readonly string str;

			public SteamworksRemoteStoragePath(string path)
			{
				str = path;
			}

			public static implicit operator SteamworksRemoteStoragePath(string str)
			{
				return new SteamworksRemoteStoragePath(str);
			}

			public bool Equals(SteamworksRemoteStoragePath other)
			{
				return string.Equals(str, other.str);
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is SteamworksRemoteStoragePath other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				if (str == null)
				{
					return 0;
				}
				return str.GetHashCode();
			}
		}

		private class Node
		{
			public readonly UPath path;

			public Node parent;

			public Node(UPath path)
			{
				this.path = path.ToAbsolute();
			}
		}

		private class FileNode : Node
		{
			public readonly SteamworksRemoteStoragePath steamworksRemoteStoragePath;

			private RemoteFile file => remoteStorage.OpenFile(steamworksRemoteStoragePath.str);

			public FileNode(SteamworksRemoteStoragePath steamworksRemoteStoragePath)
				: base(steamworksRemoteStoragePath.str)
			{
				this.steamworksRemoteStoragePath = steamworksRemoteStoragePath;
			}

			public int GetLength()
			{
				return file.SizeInBytes;
			}

			public Stream OpenWrite()
			{
				return file.OpenWrite();
			}

			public Stream OpenRead()
			{
				return file.OpenRead();
			}

			public void Delete()
			{
				file.Delete();
			}
		}

		private class DirectoryNode : Node
		{
			private Node[] childNodes = Array.Empty<Node>();

			public int childCount { get; private set; }

			public Node GetChild(int i)
			{
				return childNodes[i];
			}

			public void AddChild(Node node)
			{
				int num = childCount + 1;
				childCount = num;
				if (childCount > childNodes.Length)
				{
					Array.Resize(ref childNodes, childCount);
				}
				childNodes[childCount - 1] = node;
				node.parent = this;
			}

			public void RemoveChildAt(int i)
			{
				if (childCount > 0)
				{
					childNodes[i].parent = null;
				}
				int num = childCount - 1;
				while (i < num)
				{
					childNodes[i] = childNodes[i + 1];
					i++;
				}
				if (childCount > 0)
				{
					childNodes[childCount - 1] = null;
				}
				int num2 = childCount - 1;
				childCount = num2;
			}

			public void RemoveChild(Node node)
			{
				int num = Array.IndexOf(childNodes, node);
				if (num >= 0)
				{
					RemoveChildAt(num);
				}
			}

			public void RemoveAllChildren()
			{
				for (int i = 0; i < childCount; i++)
				{
					childNodes[i].parent = null;
					childNodes[i] = null;
				}
				childCount = 0;
			}

			public DirectoryNode(UPath path)
				: base(path)
			{
			}
		}

		private static readonly object globalLock = new object();

		private string[] allFilePaths = Array.Empty<string>();

		private readonly DirectoryNode rootNode = new DirectoryNode(UPath.Root);

		private readonly Dictionary<UPath, Node> pathToNodeMap = new Dictionary<UPath, Node>();

		private bool treeIsDirty = true;

		private static Client steamworksClient => Client.Instance;

		private static RemoteStorage remoteStorage => steamworksClient.RemoteStorage;

		public SteamworksRemoteStorageFileSystem()
		{
			pathToNodeMap[UPath.Root] = rootNode;
		}

		protected override void CreateDirectoryImpl(UPath path)
		{
		}

		protected override bool DirectoryExistsImpl(UPath path)
		{
			return true;
		}

		protected override void MoveDirectoryImpl(UPath srcPath, UPath destPath)
		{
			treeIsDirty = true;
			throw new NotImplementedException();
		}

		protected override void DeleteDirectoryImpl(UPath path, bool isRecursive)
		{
			throw new NotImplementedException();
		}

		protected override void CopyFileImpl(UPath srcPath, UPath destPath, bool overwrite)
		{
			treeIsDirty = true;
			throw new NotImplementedException();
		}

		protected override void ReplaceFileImpl(UPath srcPath, UPath destPath, UPath destBackupPath, bool ignoreMetadataErrors)
		{
			throw new NotImplementedException();
		}

		protected override long GetFileLengthImpl(UPath path)
		{
			int num = 0;
			EnterFileSystemShared();
			try
			{
				UpdateDirectories();
				num = GetFileNode(path)?.GetLength() ?? 0;
			}
			finally
			{
				ExitFileSystemShared();
			}
			return num;
		}

		protected override bool FileExistsImpl(UPath path)
		{
			UpdateDirectories();
			return GetFileNode(path) != null;
		}

		protected override void MoveFileImpl(UPath srcPath, UPath destPath)
		{
			treeIsDirty = true;
			throw new NotImplementedException();
		}

		protected override void DeleteFileImpl(UPath path)
		{
			EnterFileSystemShared();
			try
			{
				treeIsDirty = true;
				GetFileNode(path)?.Delete();
			}
			finally
			{
				ExitFileSystemShared();
			}
		}

		protected override Stream OpenFileImpl(UPath path, FileMode mode, FileAccess access, FileShare share)
		{
			EnterFileSystemShared();
			if (!path.IsAbsolute)
			{
				throw new ArgumentException(string.Format("'{0}' must be absolute. {0} = {1}", "path", path));
			}
			try
			{
				bool flag = false;
				switch (mode)
				{
				case FileMode.Append:
					throw new NotImplementedException();
				case FileMode.Create:
					flag = true;
					break;
				case FileMode.CreateNew:
					flag = true;
					break;
				}
				if (flag && access == FileAccess.Write)
				{
					treeIsDirty = true;
					return remoteStorage.CreateFile(path.ToRelative().FullName).OpenWrite();
				}
				return access switch
				{
					FileAccess.Read => GetFileNode(path)?.OpenRead(), 
					FileAccess.Write => GetFileNode(path)?.OpenWrite(), 
					_ => throw new NotImplementedException(), 
				};
			}
			finally
			{
				ExitFileSystemShared();
			}
		}

		protected override FileAttributes GetAttributesImpl(UPath path)
		{
			throw new NotImplementedException();
		}

		protected override void SetAttributesImpl(UPath path, FileAttributes attributes)
		{
		}

		protected override DateTime GetCreationTimeImpl(UPath path)
		{
			throw new NotImplementedException();
		}

		protected override void SetCreationTimeImpl(UPath path, DateTime time)
		{
		}

		protected override DateTime GetLastAccessTimeImpl(UPath path)
		{
			throw new NotImplementedException();
		}

		protected override void SetLastAccessTimeImpl(UPath path, DateTime time)
		{
		}

		protected override DateTime GetLastWriteTimeImpl(UPath path)
		{
			return DateTime.FromFileTimeUtc(remoteStorage.OpenFile(path.ToRelative().FullName).FileTimestamp);
		}

		protected override void SetLastWriteTimeImpl(UPath path, DateTime time)
		{
		}

		private FileNode AddFileToTree(string path)
		{
			FileNode fileNode = new FileNode(path);
			AddNodeToTree(fileNode);
			return fileNode;
		}

		private DirectoryNode AddDirectoryToTree(UPath path)
		{
			DirectoryNode directoryNode = new DirectoryNode(path);
			AddNodeToTree(directoryNode);
			return directoryNode;
		}

		private void AddNodeToTree(Node newNode)
		{
			UPath directory = newNode.path.GetDirectory();
			GetDirectoryNode(directory).AddChild(newNode);
			pathToNodeMap[newNode.path] = newNode;
		}

		[CanBeNull]
		private DirectoryNode GetDirectoryNode(UPath directoryPath)
		{
			if (pathToNodeMap.TryGetValue(directoryPath, out var value))
			{
				return value as DirectoryNode;
			}
			return AddDirectoryToTree(directoryPath);
		}

		[CanBeNull]
		private FileNode GetFileNode(UPath filePath)
		{
			if (pathToNodeMap.TryGetValue(filePath, out var value))
			{
				return value as FileNode;
			}
			return null;
		}

		private void UpdateDirectories()
		{
			EnterFileSystemShared();
			try
			{
				if (!treeIsDirty)
				{
					return;
				}
				treeIsDirty = false;
				IEnumerable<string> enumerable = remoteStorage.Files.Select((RemoteFile file) => file.FileName);
				if (!enumerable.SequenceEqual(allFilePaths))
				{
					allFilePaths = enumerable.ToArray();
					pathToNodeMap.Clear();
					pathToNodeMap[UPath.Root] = rootNode;
					rootNode.RemoveAllChildren();
					string[] array = allFilePaths;
					foreach (string path in array)
					{
						AddFileToTree(path);
					}
				}
			}
			finally
			{
				ExitFileSystemShared();
			}
		}

		private void AssertDirectory(Node node, UPath srcPath)
		{
			if (node is FileNode)
			{
				throw new IOException($"The source directory `{srcPath}` is a file");
			}
		}

		protected override IEnumerable<UPath> EnumeratePathsImpl(UPath path, string searchPattern, SearchOption searchOption, SearchTarget searchTarget)
		{
			UpdateDirectories();
			SearchPattern search = SearchPattern.Parse(ref path, ref searchPattern);
			List<UPath> foldersToProcess = new List<UPath> { path };
			SortedSet<UPath> entries = new SortedSet<UPath>(UPath.DefaultComparerIgnoreCase);
			while (foldersToProcess.Count > 0)
			{
				UPath uPath = foldersToProcess[0];
				foldersToProcess.RemoveAt(0);
				int num = 0;
				entries.Clear();
				EnterFileSystemShared();
				try
				{
					Node directoryNode = GetDirectoryNode(uPath);
					if (uPath == path)
					{
						AssertDirectory(directoryNode, uPath);
						goto IL_00cb;
					}
					if (directoryNode is DirectoryNode)
					{
						goto IL_00cb;
					}
					goto end_IL_009b;
					IL_00cb:
					DirectoryNode directoryNode2 = (DirectoryNode)directoryNode;
					for (int i = 0; i < directoryNode2.childCount; i++)
					{
						Node child = directoryNode2.GetChild(i);
						if (!(child is FileNode) || searchTarget != SearchTarget.Directory)
						{
							bool flag = search.Match(child.path);
							bool num2 = searchOption == SearchOption.AllDirectories && child is DirectoryNode;
							bool flag2 = (child is FileNode && searchTarget != SearchTarget.Directory && flag) || (child is DirectoryNode && searchTarget != SearchTarget.File && flag);
							UPath item = uPath / child.path;
							if (num2)
							{
								foldersToProcess.Insert(num++, item);
							}
							if (flag2)
							{
								entries.Add(item);
							}
						}
					}
					goto IL_01b6;
					end_IL_009b:;
				}
				finally
				{
					ExitFileSystemShared();
				}
				continue;
				IL_01b6:
				foreach (UPath item2 in entries)
				{
					yield return item2;
				}
			}
		}

		private static void EnterFileSystemShared()
		{
			System.Threading.Monitor.Enter(globalLock);
		}

		private static void ExitFileSystemShared()
		{
			System.Threading.Monitor.Exit(globalLock);
		}

		protected override IFileSystemWatcher WatchImpl(UPath path)
		{
			throw new NotImplementedException();
		}

		protected override string ConvertPathToInternalImpl(UPath path)
		{
			return path.FullName;
		}

		protected override UPath ConvertPathFromInternalImpl(string innerPath)
		{
			return new UPath(innerPath);
		}

		[ConCommand(commandName = "steam_remote_storage_list_files", flags = ConVarFlags.None, helpText = "Lists the files currently being managed by Steamworks remote storage.")]
		private static void CCSteamRemoteStorageListFiles(ConCommandArgs args)
		{
		}
	}
	internal sealed class SteamworksServerManager : ServerManagerBase<SteamworksServerManager>, IDisposable
	{
		private sealed class SteamServerHeartbeatEnabledConVar : BaseConVar
		{
			public static readonly SteamServerHeartbeatEnabledConVar instance = new SteamServerHeartbeatEnabledConVar("steam_server_heartbeat_enabled", ConVarFlags.Engine, null, "Whether or not this server issues any heartbeats to the Steam master server and effectively advertises it in the master server list. Default is 1 for dedicated servers, 0 for client builds.");

			public bool value { get; private set; }

			public SteamServerHeartbeatEnabledConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValueString)
			{
				if (!TextSerialization.TryParseInvariant(newValueString, out int result))
				{
					return;
				}
				bool flag = result != 0;
				if (flag != value)
				{
					value = flag;
					if (ServerManagerBase<SteamworksServerManager>.instance != null)
					{
						ServerManagerBase<SteamworksServerManager>.instance.steamworksServer.AutomaticHeartbeats = value;
					}
				}
			}

			public override string GetString()
			{
				if (!value)
				{
					return "0";
				}
				return "1";
			}
		}

		public class SteamServerPortConVar : BaseConVar
		{
			public ushort value { get; private set; }

			public SteamServerPortConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValueString)
			{
				if (NetworkServer.active)
				{
					throw new ConCommandException("Cannot change this convar while the server is running.");
				}
				if (TextSerialization.TryParseInvariant(newValueString, out ushort result))
				{
					value = result;
				}
			}

			public override string GetString()
			{
				return value.ToString();
			}
		}

		private Server steamworksServer;

		private IPAddress address;

		private static readonly SteamServerPortConVar cvSteamServerQueryPort = new SteamServerPortConVar("steam_server_query_port", ConVarFlags.Engine, "27016", "The port for queries.");

		private static readonly SteamServerPortConVar cvSteamServerSteamPort = new SteamServerPortConVar("steam_server_steam_port", ConVarFlags.Engine, "0", "The port for steam. 0 for a random port in the range 10000-60000.");

		public SteamworksServerManager()
		{
			string gameDesc = "Risk of Rain 2";
			steamworksServer = new Server(632360u, new ServerInit("Risk of Rain 2", gameDesc)
			{
				IpAddress = IPAddress.Any,
				Secure = true,
				VersionString = RoR2Application.GetBuildId(),
				GamePort = NetworkManagerSystem.SvPortConVar.instance.value,
				QueryPort = cvSteamServerQueryPort.value,
				SteamPort = cvSteamServerSteamPort.value,
				GameData = ServerManagerBase<SteamworksServerManager>.GetVersionGameDataString() + "," + NetworkModCompatibilityHelper.steamworksGameserverGameDataValue
			});
			UnityEngine.Debug.LogFormat("steamworksServer.IsValid={0}", steamworksServer.IsValid);
			if (!steamworksServer.IsValid)
			{
				Dispose();
				return;
			}
			steamworksServer.Auth.OnAuthChange = OnAuthChange;
			steamworksServer.MaxPlayers = GetMaxPlayers();
			UpdateHostName(NetworkManagerSystem.SvHostNameConVar.instance.GetString());
			NetworkManagerSystem.SvHostNameConVar.instance.onValueChanged += UpdateHostName;
			UpdateMapName(SceneManager.GetActiveScene().name);
			NetworkManagerSystem.onServerSceneChangedGlobal += UpdateMapName;
			UpdatePassword(NetworkManagerSystem.SvPasswordConVar.instance.value);
			NetworkManagerSystem.SvPasswordConVar.instance.onValueChanged += UpdatePassword;
			steamworksServer.DedicatedServer = false;
			steamworksServer.AutomaticHeartbeats = SteamServerHeartbeatEnabledConVar.instance.value;
			steamworksServer.LogOnAnonymous();
			UnityEngine.Debug.LogFormat("steamworksServer.LoggedOn={0}", steamworksServer.LoggedOn);
			RoR2Application.onUpdate += Update;
			NetworkManagerSystem.onServerConnectGlobal += OnServerConnectClient;
			NetworkManagerSystem.onServerDisconnectGlobal += OnServerDisconnectClient;
			ServerAuthManager.onAuthDataReceivedFromClient += OnAuthDataReceivedFromClient;
			ServerAuthManager.onAuthExpired += OnAuthExpired;
			Run.onServerRunSetRuleBookGlobal += base.OnServerRunSetRuleBookGlobal;
			PreGameController.onPreGameControllerSetRuleBookServerGlobal += base.OnPreGameControllerSetRuleBookServerGlobal;
			NetworkUser.onNetworkUserDiscovered += OnNetworkUserDiscovered;
			NetworkUser.onNetworkUserLost += OnNetworkUserLost;
			steamworksServer.SetKey("Test", "Value");
			steamworksServer.SetKey("gameMode", PreGameController.GameModeConVar.instance.GetString());
			steamworksServer.SetKey("buildId", RoR2Application.GetBuildId());
			steamworksServer.SetKey("modHash", NetworkModCompatibilityHelper.networkModHash);
			ruleBookKvHelper = new KeyValueSplitter("ruleBook", 2048, 2048, steamworksServer.SetKey);
			modListKvHelper = new KeyValueSplitter(NetworkModCompatibilityHelper.steamworksGameserverRulesBaseName, 2048, 2048, steamworksServer.SetKey);
			modListKvHelper.SetValue(NetworkModCompatibilityHelper.steamworksGameserverGameRulesValue);
			steamworksServer.ForceHeartbeat();
			UpdateServerRuleBook();
		}

		protected override void TagsStringUpdated()
		{
			base.TagsStringUpdated();
			steamworksServer.GameTags = base.tagsString;
		}

		private void OnAuthExpired(NetworkConnection conn, ClientAuthData authData)
		{
			SteamNetworkConnection obj = conn as SteamNetworkConnection;
			PlatformID? platformID = ((obj != null) ? new PlatformID?(obj.steamId) : authData?.platformId);
			if (platformID.HasValue)
			{
				steamworksServer.Auth.EndSession(platformID.Value.ID);
			}
		}

		private void OnAuthDataReceivedFromClient(NetworkConnection conn, ClientAuthData authData)
		{
			PlatformID platformID = authData.platformId;
			if (conn is SteamNetworkConnection steamNetworkConnection)
			{
				platformID = steamNetworkConnection.steamId;
			}
			steamworksServer.Auth.StartSession(authData.authTicket, platformID.ID);
		}

		private void OnServerConnectClient(NetworkConnection conn)
		{
		}

		private void OnServerDisconnectClient(NetworkConnection conn)
		{
		}

		public override void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				steamworksServer?.Dispose();
				steamworksServer = null;
				RoR2Application.onUpdate -= Update;
				NetworkManagerSystem.SvHostNameConVar.instance.onValueChanged -= UpdateHostName;
				NetworkManagerSystem.SvPasswordConVar.instance.onValueChanged -= UpdatePassword;
				NetworkManagerSystem.onServerSceneChangedGlobal -= UpdateMapName;
				NetworkManagerSystem.onServerConnectGlobal -= OnServerConnectClient;
				NetworkManagerSystem.onServerDisconnectGlobal -= OnServerDisconnectClient;
				ServerAuthManager.onAuthDataReceivedFromClient -= OnAuthDataReceivedFromClient;
				ServerAuthManager.onAuthExpired -= OnAuthExpired;
				Run.onServerRunSetRuleBookGlobal -= base.OnServerRunSetRuleBookGlobal;
				PreGameController.onPreGameControllerSetRuleBookServerGlobal -= base.OnPreGameControllerSetRuleBookServerGlobal;
				NetworkUser.onNetworkUserDiscovered -= OnNetworkUserDiscovered;
				NetworkUser.onNetworkUserLost -= OnNetworkUserLost;
			}
		}

		private int GetMaxPlayers()
		{
			return NetworkManagerSystem.singleton.maxConnections;
		}

		private void OnNetworkUserLost(NetworkUser networkUser)
		{
			UpdateBotPlayerCount();
		}

		private void OnNetworkUserDiscovered(NetworkUser networkUser)
		{
			UpdateBotPlayerCount();
		}

		private void UpdateBotPlayerCount()
		{
			int num = 0;
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				if (readOnlyInstances.isSplitScreenExtraPlayer)
				{
					num++;
				}
			}
			steamworksServer.BotCount = num;
		}

		private void UpdateHostName(string newHostName)
		{
			steamworksServer.ServerName = newHostName;
		}

		private void UpdateMapName(string sceneName)
		{
			steamworksServer.MapName = sceneName;
		}

		private void UpdatePassword(string newPassword)
		{
			steamworksServer.Passworded = newPassword.Length > 0;
		}

		private void OnAddressDiscovered()
		{
		}

		private void RefreshSteamServerPlayers()
		{
			foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
			{
				ClientAuthData clientAuthData = ServerAuthManager.FindAuthData(readOnlyInstances.connectionToClient);
				if (clientAuthData != null)
				{
					steamworksServer.UpdatePlayer(clientAuthData.platformId.ID, readOnlyInstances.userName, 0);
				}
			}
		}

		protected override void Update()
		{
			steamworksServer.Update();
			playerUpdateTimer -= Time.unscaledDeltaTime;
			if (playerUpdateTimer <= 0f)
			{
				playerUpdateTimer = playerUpdateInterval;
				RefreshSteamServerPlayers();
			}
			if (address == null)
			{
				address = steamworksServer.PublicIp;
				if (address != null)
				{
					OnAddressDiscovered();
				}
			}
		}

		private void OnAuthChange(ulong steamId, ulong ownerId, ServerAuth.Status status)
		{
			NetworkConnection networkConnection = ServerAuthManager.FindConnectionForSteamID(new PlatformID(steamId));
			if (networkConnection == null)
			{
				UnityEngine.Debug.LogWarningFormat("SteamworksServerManager.OnAuthChange(steamId={0}, ownerId={1}, status={2}): Could not find connection for steamId.", steamId, ownerId, status);
				return;
			}
			switch (status)
			{
			case ServerAuth.Status.OK:
				break;
			default:
				throw new ArgumentOutOfRangeException("status", status, null);
			case ServerAuth.Status.UserNotConnectedToSteam:
			case ServerAuth.Status.NoLicenseOrExpired:
			case ServerAuth.Status.VACBanned:
			case ServerAuth.Status.LoggedInElseWhere:
			case ServerAuth.Status.VACCheckTimedOut:
			case ServerAuth.Status.AuthTicketCanceled:
			case ServerAuth.Status.AuthTicketInvalidAlreadyUsed:
			case ServerAuth.Status.AuthTicketInvalid:
			case ServerAuth.Status.PublisherIssuedBan:
				NetworkManagerSystem.singleton.ServerKickClient(networkConnection, new NetworkManagerSystem.SimpleLocalizedKickReason("KICK_REASON_STEAMWORKS_AUTH_FAILURE", status.ToString()));
				break;
			}
		}

		[ConCommand(commandName = "steam_server_force_heartbeat", flags = ConVarFlags.None, helpText = "Forces the server to issue a heartbeat to the master server.")]
		private static void CCSteamServerForceHeartbeat(ConCommandArgs args)
		{
			(ServerManagerBase<SteamworksServerManager>.instance?.steamworksServer ?? throw new ConCommandException("No Steamworks server is running.")).ForceHeartbeat();
		}

		[ConCommand(commandName = "steam_server_print_info", flags = ConVarFlags.None, helpText = "Prints debug info about the currently hosted Steamworks server.")]
		private static void CCSteamServerPrintInfo(ConCommandArgs args)
		{
			Server server = ServerManagerBase<SteamworksServerManager>.instance?.steamworksServer;
			if (server == null)
			{
				throw new ConCommandException("No Steamworks server is running.");
			}
			string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat(string.Concat("" + $"IsValid={server.IsValid}\n", $"Product={server.Product}\n"), $"ModDir={server.ModDir}\n"), $"SteamId={server.SteamId}\n"), $"DedicatedServer={server.DedicatedServer}\n"), $"LoggedOn={server.LoggedOn}\n"), $"ServerName={server.ServerName}\n"), $"PublicIp={server.PublicIp}\n"), $"Passworded={server.Passworded}\n"), $"MaxPlayers={server.MaxPlayers}\n"), $"BotCount={server.BotCount}\n"), $"MapName={server.MapName}\n"), $"GameDescription={server.GameDescription}\n"), $"GameTags={server.GameTags}\n");
		}
	}
	public enum SurfaceDefIndex
	{
		Invalid = -1
	}
	public static class SurfaceDefCatalog
	{
		private static SurfaceDef[] surfaceDefs = Array.Empty<SurfaceDef>();

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetSurfaceDefs(ContentManager.surfaceDefs);
		}

		private static void SetSurfaceDefs(SurfaceDef[] newSurfaceDefs)
		{
			SurfaceDef[] array = surfaceDefs;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].surfaceDefIndex = SurfaceDefIndex.Invalid;
			}
			ArrayUtils.CloneTo(newSurfaceDefs, ref surfaceDefs);
			Array.Sort(surfaceDefs, (SurfaceDef a, SurfaceDef b) => string.CompareOrdinal(a.name, b.name));
			for (int j = 0; j < surfaceDefs.Length; j++)
			{
				surfaceDefs[j].surfaceDefIndex = (SurfaceDefIndex)j;
			}
		}

		public static SurfaceDef GetSurfaceDef(SurfaceDefIndex surfaceDefIndex)
		{
			return ArrayUtils.GetSafe(surfaceDefs, (int)surfaceDefIndex);
		}
	}
	public enum SurvivorIndex
	{
		None = -1
	}
	public static class SurvivorCatalog
	{
		public static int survivorMaxCount = 10;

		private static SurvivorDef[] survivorDefs = Array.Empty<SurvivorDef>();

		private static SurvivorDef[] _orderedSurvivorDefs = Array.Empty<SurvivorDef>();

		private static SurvivorIndex[] bodyIndexToSurvivorIndex = Array.Empty<SurvivorIndex>();

		private static BodyIndex[] survivorIndexToBodyIndex = Array.Empty<BodyIndex>();

		private static int[] survivorOrderPositions = Array.Empty<int>();

		private static string[] cachedSurvivorNames = Array.Empty<string>();

		public static SurvivorDef defaultSurvivor;

		public static int survivorCount => survivorDefs.Length;

		public static SurvivorIndex endIndex => (SurvivorIndex)survivorDefs.Length;

		public static IEnumerable<SurvivorDef> allSurvivorDefs => survivorDefs;

		public static IEnumerable<SurvivorDef> orderedSurvivorDefs => _orderedSurvivorDefs;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<SurvivorDef>> getAdditionalSurvivorDefs
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.SurvivorCatalog.getAdditionalSurvivorDefs", value, LegacyModContentPackProvider.instance.registrationContentPack.survivorDefs);
			}
			remove
			{
			}
		}

		private static void ValidateEntry(SurvivorDef survivorDef)
		{
			if ((bool)survivorDef.bodyPrefab)
			{
				CharacterBody component = survivorDef.bodyPrefab.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					if (string.IsNullOrEmpty(survivorDef.cachedName))
					{
						string text = BodyCatalog.GetBodyName(component.bodyIndex);
						string text2 = "Body";
						if (text.EndsWith(text2))
						{
							text = text.Substring(0, text.Length - text2.Length);
						}
						survivorDef.cachedName = text;
					}
					if (survivorDef.displayNameToken == null)
					{
						survivorDef.displayNameToken = component.baseNameToken;
					}
				}
			}
			survivorDef.displayNameToken = survivorDef.displayNameToken ?? "";
		}

		[CanBeNull]
		public static SurvivorDef GetSurvivorDef(SurvivorIndex survivorIndex)
		{
			return ArrayUtils.GetSafe(survivorDefs, (int)survivorIndex);
		}

		public static SurvivorIndex GetSurvivorIndexFromBodyIndex(BodyIndex bodyIndex)
		{
			SurvivorIndex[] array = bodyIndexToSurvivorIndex;
			SurvivorIndex defaultValue = SurvivorIndex.None;
			return ArrayUtils.GetSafe(array, (int)bodyIndex, in defaultValue);
		}

		public static BodyIndex GetBodyIndexFromSurvivorIndex(SurvivorIndex survivorIndex)
		{
			BodyIndex[] array = survivorIndexToBodyIndex;
			BodyIndex defaultValue = BodyIndex.None;
			return ArrayUtils.GetSafe(array, (int)survivorIndex, in defaultValue);
		}

		public static bool SurvivorIsUnlockedOnThisClient(SurvivorIndex survivorIndex)
		{
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				_ = readOnlyLocalUsers.userProfile;
			}
			return LocalUserManager.readOnlyLocalUsersList.Any((LocalUser localUser) => localUser.userProfile.HasSurvivorUnlocked(survivorIndex));
		}

		[CanBeNull]
		public static SurvivorDef FindSurvivorDefFromBody([CanBeNull] GameObject characterBodyPrefab)
		{
			for (int i = 0; i < survivorDefs.Length; i++)
			{
				SurvivorDef survivorDef = survivorDefs[i];
				GameObject gameObject = ((survivorDef != null) ? survivorDef.bodyPrefab : null);
				if (characterBodyPrefab == gameObject)
				{
					return survivorDef;
				}
			}
			return null;
		}

		[CanBeNull]
		public static Texture GetSurvivorPortrait(SurvivorIndex survivorIndex)
		{
			SurvivorDef survivorDef = GetSurvivorDef(survivorIndex);
			if (survivorDef.bodyPrefab != null)
			{
				CharacterBody component = survivorDef.bodyPrefab.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					return component.portraitIcon;
				}
			}
			return null;
		}

		public static SurvivorIndex FindSurvivorIndex([CanBeNull] string survivorName)
		{
			return (SurvivorIndex)Array.IndexOf(cachedSurvivorNames, survivorName);
		}

		public static SurvivorDef FindSurvivorDef([CanBeNull] string survivorName)
		{
			return GetSurvivorDef(FindSurvivorIndex(survivorName));
		}

		public static int GetSurvivorOrderedPosition(SurvivorIndex survivorIndex)
		{
			int[] array = survivorOrderPositions;
			int defaultValue = -1;
			return ArrayUtils.GetSafe(array, (int)survivorIndex, in defaultValue);
		}

		[SystemInitializer(new Type[] { typeof(BodyCatalog) })]
		private static void Init()
		{
			SetSurvivorDefs(ContentManager.survivorDefs);
		}

		private static void SetSurvivorDefs(SurvivorDef[] newSurvivorDefs)
		{
			SurvivorDef[] array = survivorDefs;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].survivorIndex = SurvivorIndex.None;
			}
			ArrayUtils.CloneTo(newSurvivorDefs, ref survivorDefs);
			Array.Resize(ref survivorIndexToBodyIndex, survivorDefs.Length);
			Array.Resize(ref cachedSurvivorNames, survivorDefs.Length);
			Array.Resize(ref _orderedSurvivorDefs, survivorDefs.Length);
			Array.Resize(ref survivorOrderPositions, survivorDefs.Length);
			Array.Resize(ref bodyIndexToSurvivorIndex, BodyCatalog.bodyCount);
			SurvivorIndex[] array2 = bodyIndexToSurvivorIndex;
			SurvivorIndex value = SurvivorIndex.None;
			ArrayUtils.SetAll(array2, in value);
			for (SurvivorIndex survivorIndex = (SurvivorIndex)0; (int)survivorIndex < survivorDefs.Length; survivorIndex++)
			{
				SurvivorDef survivorDef2 = survivorDefs[(int)survivorIndex];
				survivorDef2.survivorIndex = survivorIndex;
				ValidateEntry(survivorDef2);
				cachedSurvivorNames[(int)survivorIndex] = survivorDef2.cachedName;
				BodyIndex bodyIndex = BodyCatalog.FindBodyIndex(survivorDef2.bodyPrefab);
				survivorIndexToBodyIndex[(int)survivorIndex] = bodyIndex;
				bodyIndexToSurvivorIndex[(int)bodyIndex] = survivorIndex;
			}
			ArrayUtils.CloneTo(survivorDefs, ref _orderedSurvivorDefs);
			Array.Sort(_orderedSurvivorDefs, (SurvivorDef a, SurvivorDef b) => a.desiredSortPosition.CompareTo(b.desiredSortPosition));
			for (int j = 0; j < _orderedSurvivorDefs.Length; j++)
			{
				SurvivorIndex survivorIndex2 = _orderedSurvivorDefs[j].survivorIndex;
				survivorOrderPositions[(int)survivorIndex2] = j;
			}
			ViewablesCatalog.Node node = new ViewablesCatalog.Node("Survivors", isFolder: true);
			foreach (SurvivorDef survivorDef in allSurvivorDefs)
			{
				ViewablesCatalog.Node survivorEntryNode = new ViewablesCatalog.Node(survivorDef.cachedName, isFolder: false, node);
				survivorEntryNode.shouldShowUnviewed = (UserProfile userProfile) => !userProfile.HasViewedViewable(survivorEntryNode.fullName) && (bool)survivorDef.unlockableDef && userProfile.HasUnlockable(survivorDef.unlockableDef);
			}
			ViewablesCatalog.AddNodeToRoot(node);
			defaultSurvivor = FindSurvivorDef("Commando");
		}
	}
	[MeansImplicitUse]
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
	public class SystemInitializerAttribute : HG.Reflection.SearchableAttribute
	{
		private class SystemInitializationLogHandler : ILogHandler
		{
			public ILogHandler underlyingLogHandler;

			private SystemInitializerAttribute _currentInitializer;

			private string logPrefix = string.Empty;

			public SystemInitializerAttribute currentInitializer
			{
				get
				{
					return _currentInitializer;
				}
				set
				{
					_currentInitializer = value;
					logPrefix = "[" + currentInitializer.associatedType.FullName + "] ";
				}
			}

			public void LogException(Exception exception, UnityEngine.Object context)
			{
				LogFormat(LogType.Exception, context, exception.Message, null);
			}

			public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
			{
				underlyingLogHandler.LogFormat(logType, context, logPrefix + format, args);
			}
		}

		private class SystemTiming : IComparable
		{
			public string systemName;

			public long systemInitDuration;

			public long longestSingleIteration;

			public long externalTimeDuration;

			public long totalTimeSpent => externalTimeDuration + systemInitDuration;

			public int CompareTo(object obj)
			{
				SystemTiming systemTiming = obj as SystemTiming;
				return -totalTimeSpent.CompareTo(systemTiming.totalTimeSpent);
			}
		}

		public static bool hasExecuted = false;

		public Type[] dependencies = Array.Empty<Type>();

		private MethodInfo methodInfo;

		private Type associatedType;

		private static List<Type> preInitializedTypes = new List<Type>(5);

		private static Thread initThread;

		private static Queue<SystemInitializerAttribute> initializerAttributes;

		private static long FRAME_TIME_THRESHOLD_MS = 22L;

		public SystemInitializerAttribute(params Type[] dependencies)
		{
			if (dependencies != null)
			{
				this.dependencies = dependencies;
			}
		}

		public static void RegisterPreInitializedType(Type _type)
		{
			preInitializedTypes.Add(_type);
		}

		public static void Execute()
		{
			Queue<SystemInitializerAttribute> queue = new Queue<SystemInitializerAttribute>();
			foreach (SystemInitializerAttribute instance in HG.Reflection.SearchableAttribute.GetInstances<SystemInitializerAttribute>())
			{
				MethodInfo methodInfo = instance.target as MethodInfo;
				if (methodInfo != null && methodInfo.IsStatic)
				{
					queue.Enqueue(instance);
					instance.methodInfo = methodInfo;
					instance.associatedType = methodInfo.DeclaringType;
				}
			}
			HashSet<Type> initializedTypes = new HashSet<Type>();
			int num = 0;
			while (queue.Count > 0)
			{
				SystemInitializerAttribute systemInitializerAttribute2 = queue.Dequeue();
				if (!InitializerDependenciesMet(systemInitializerAttribute2))
				{
					queue.Enqueue(systemInitializerAttribute2);
					num++;
					if (num >= queue.Count)
					{
						break;
					}
				}
				else
				{
					systemInitializerAttribute2.methodInfo.Invoke(null, Array.Empty<object>());
					initializedTypes.Add(systemInitializerAttribute2.associatedType);
					num = 0;
				}
			}
			hasExecuted = true;
			bool InitializerDependenciesMet(SystemInitializerAttribute initializerAttribute)
			{
				Type[] array = initializerAttribute.dependencies;
				foreach (Type item in array)
				{
					if (!initializedTypes.Contains(item))
					{
						return false;
					}
				}
				return true;
			}
		}

		public static void ExecuteStatic()
		{
			int num = 0;
			Type[] assemblyTypes = RoR2Application.AssemblyTypes;
			foreach (Type type in assemblyTypes)
			{
				num++;
				MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo element in methods)
				{
					SystemInitializerAttribute customAttribute = CustomAttributeExtensions.GetCustomAttribute<SystemInitializerAttribute>(element);
					if (customAttribute != null)
					{
						initializerAttributes.Enqueue(customAttribute);
						customAttribute.methodInfo = element;
						customAttribute.associatedType = type;
					}
				}
			}
		}

		public static IEnumerator ExecuteCoroutine()
		{
			initializerAttributes = new Queue<SystemInitializerAttribute>();
			initThread = new Thread(ExecuteStatic);
			initThread.Start();
			yield return null;
			while (initThread.IsAlive)
			{
				yield return null;
			}
			initThread = null;
			HashSet<Type> initializedTypes = new HashSet<Type>();
			foreach (Type preInitializedType in preInitializedTypes)
			{
				initializedTypes.Add(preInitializedType);
			}
			preInitializedTypes.Clear();
			new Stopwatch().Start();
			Stopwatch multiLoopTimer = new Stopwatch();
			multiLoopTimer.Start();
			int yields = 0;
			int num = 0;
			while (initializerAttributes.Count > 0)
			{
				SystemInitializerAttribute initializerAttribute2 = initializerAttributes.Dequeue();
				if (!InitializerDependenciesMet(initializerAttribute2))
				{
					initializerAttributes.Enqueue(initializerAttribute2);
					num++;
					if (num >= initializerAttributes.Count)
					{
						UnityEngine.Debug.LogFormat("SystemInitializerAttribute infinite loop detected. currentMethod={0}", initializerAttribute2.associatedType.FullName + initializerAttribute2.methodInfo.Name);
						break;
					}
					continue;
				}
				IEnumerator thisStep = initializerAttribute2.methodInfo.Invoke(null, Array.Empty<object>()) as IEnumerator;
				List<IEnumerator> coroutineStack = new List<IEnumerator> { thisStep };
				multiLoopTimer.Stop();
				long accumulatedTime = multiLoopTimer.ElapsedMilliseconds;
				multiLoopTimer.Start();
				if (accumulatedTime > FRAME_TIME_THRESHOLD_MS)
				{
					accumulatedTime = 0L;
					multiLoopTimer.Stop();
					multiLoopTimer.Reset();
					multiLoopTimer.Start();
					yields++;
					yield return null;
				}
				while (thisStep != null)
				{
					while (accumulatedTime < FRAME_TIME_THRESHOLD_MS && thisStep != null)
					{
						if (!thisStep.MoveNext())
						{
							coroutineStack.RemoveAt(coroutineStack.Count - 1);
							thisStep = ((coroutineStack.Count <= 0) ? null : coroutineStack[coroutineStack.Count - 1]);
						}
						else if (thisStep.Current != null)
						{
							coroutineStack.Add(thisStep.Current as IEnumerator);
							thisStep = coroutineStack[coroutineStack.Count - 1];
						}
						multiLoopTimer.Stop();
						accumulatedTime = multiLoopTimer.ElapsedMilliseconds;
						multiLoopTimer.Start();
					}
					if (accumulatedTime > FRAME_TIME_THRESHOLD_MS)
					{
						accumulatedTime = 0L;
						multiLoopTimer.Stop();
						multiLoopTimer.Reset();
						multiLoopTimer.Start();
					}
					if (thisStep != null)
					{
						yields++;
						accumulatedTime = 0L;
						multiLoopTimer.Stop();
						multiLoopTimer.Reset();
						multiLoopTimer.Start();
						yield return null;
					}
				}
				initializedTypes.Add(initializerAttribute2.associatedType);
				num = 0;
			}
			initializerAttributes = null;
			hasExecuted = true;
			bool InitializerDependenciesMet(SystemInitializerAttribute initializerAttribute)
			{
				Type[] array = initializerAttribute.dependencies;
				foreach (Type item in array)
				{
					initializedTypes.Contains(item);
					if (!initializedTypes.Contains(item))
					{
						return false;
					}
				}
				return true;
			}
		}
	}
	public enum TeamIndex : sbyte
	{
		None = -1,
		Neutral,
		Player,
		Monster,
		Lunar,
		Void,
		Count
	}
	[Serializable]
	public struct TeamMask
	{
		[SerializeField]
		public byte a;

		public static readonly TeamMask none;

		public static readonly TeamMask allButNeutral;

		public static readonly TeamMask all;

		public bool HasTeam(TeamIndex teamIndex)
		{
			if (teamIndex < TeamIndex.Neutral || teamIndex >= TeamIndex.Count)
			{
				return false;
			}
			return (a & (1L << (int)teamIndex)) != 0;
		}

		public void AddTeam(TeamIndex teamIndex)
		{
			if (teamIndex >= TeamIndex.Neutral && teamIndex < TeamIndex.Count)
			{
				a |= (byte)(1 << (int)teamIndex);
			}
		}

		public void RemoveTeam(TeamIndex teamIndex)
		{
			if (teamIndex >= TeamIndex.Neutral && teamIndex < TeamIndex.Count)
			{
				a &= (byte)(~(1 << (int)teamIndex));
			}
		}

		static TeamMask()
		{
			all = default(TeamMask);
			for (TeamIndex teamIndex = TeamIndex.Neutral; teamIndex < TeamIndex.Count; teamIndex++)
			{
				all.AddTeam(teamIndex);
			}
			allButNeutral = all;
			allButNeutral.RemoveTeam(TeamIndex.Neutral);
		}

		public static TeamMask AllExcept(TeamIndex teamIndexToExclude)
		{
			TeamMask result = all;
			result.RemoveTeam(teamIndexToExclude);
			return result;
		}

		public static TeamMask GetUnprotectedTeams(TeamIndex attackerTeam)
		{
			if (FriendlyFireManager.friendlyFireMode == FriendlyFireManager.FriendlyFireMode.Off)
			{
				return AllExcept(attackerTeam);
			}
			return all;
		}

		public static TeamMask GetEnemyTeams(TeamIndex teamIndex)
		{
			if (FriendlyFireManager.friendlyFireMode == FriendlyFireManager.FriendlyFireMode.FreeForAll)
			{
				return all;
			}
			return AllExcept(teamIndex);
		}
	}
	public class TeamDef
	{
		public string nameToken;

		public int softCharacterLimit;

		public float friendlyFireScaling;

		public GameObject levelUpEffect;

		public string levelUpSound;
	}
	public static class TeamCatalog
	{
		private static TeamDef[] teamDefs;

		static TeamCatalog()
		{
			teamDefs = new TeamDef[5];
			Register(TeamIndex.Neutral, new TeamDef
			{
				nameToken = "TEAM_NEUTRAL_NAME",
				softCharacterLimit = 40,
				friendlyFireScaling = 1f
			});
			Register(TeamIndex.Player, new TeamDef
			{
				nameToken = "TEAM_PLAYER_NAME",
				softCharacterLimit = 20,
				friendlyFireScaling = 0.5f,
				levelUpEffect = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/LevelUpEffect"),
				levelUpSound = "Play_UI_levelUp_player"
			});
			Register(TeamIndex.Monster, new TeamDef
			{
				nameToken = "TEAM_MONSTER_NAME",
				softCharacterLimit = 40,
				friendlyFireScaling = 2f,
				levelUpEffect = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/LevelUpEffectEnemy"),
				levelUpSound = "Play_UI_levelUp_enemy"
			});
			Register(TeamIndex.Lunar, new TeamDef
			{
				nameToken = "TEAM_LUNAR_NAME",
				softCharacterLimit = 40,
				friendlyFireScaling = 2f,
				levelUpEffect = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/LevelUpEffectEnemy"),
				levelUpSound = "Play_UI_levelUp_enemy"
			});
			Register(TeamIndex.Void, new TeamDef
			{
				nameToken = "TEAM_VOID_NAME",
				softCharacterLimit = 40,
				friendlyFireScaling = 2f,
				levelUpEffect = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/LevelUpEffectEnemy"),
				levelUpSound = "Play_UI_levelUp_enemy"
			});
		}

		private static void Register(TeamIndex teamIndex, TeamDef teamDef)
		{
			teamDefs[(int)teamIndex] = teamDef;
		}

		[CanBeNull]
		public static TeamDef GetTeamDef(TeamIndex teamIndex)
		{
			return ArrayUtils.GetSafe(teamDefs, (int)teamIndex);
		}
	}
	public static class TeleportHelper
	{
		private class TeleportMessage : MessageBase
		{
			public GameObject gameObject;

			public UnityEngine.Vector3 newPosition;

			public UnityEngine.Vector3 delta;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(gameObject);
				writer.Write(newPosition);
				writer.Write(delta);
			}

			public override void Deserialize(NetworkReader reader)
			{
				gameObject = reader.ReadGameObject();
				newPosition = reader.ReadVector3();
				delta = reader.ReadVector3();
			}
		}

		private static readonly TeleportMessage messageBuffer = new TeleportMessage();

		public static void TeleportGameObject(GameObject gameObject, UnityEngine.Vector3 newPosition)
		{
			bool hasEffectiveAuthority = Util.HasEffectiveAuthority(gameObject);
			TeleportGameObject(gameObject, newPosition, newPosition - gameObject.transform.position, hasEffectiveAuthority);
		}

		private static void TeleportGameObject(GameObject gameObject, UnityEngine.Vector3 newPosition, UnityEngine.Vector3 delta, bool hasEffectiveAuthority)
		{
			OnTeleport(gameObject, newPosition, delta);
			if (NetworkServer.active || hasEffectiveAuthority)
			{
				TeleportMessage msg = new TeleportMessage
				{
					gameObject = gameObject,
					newPosition = newPosition,
					delta = delta
				};
				QosChannelIndex defaultReliable = QosChannelIndex.defaultReliable;
				if (NetworkServer.active)
				{
					NetworkServer.SendByChannelToAll(68, msg, defaultReliable.intVal);
				}
				else
				{
					NetworkManager.singleton.client.connection.SendByChannel(68, msg, defaultReliable.intVal);
				}
			}
		}

		private static void OnTeleport(GameObject gameObject, UnityEngine.Vector3 newPosition, UnityEngine.Vector3 delta)
		{
			CharacterMotor component = gameObject.GetComponent<CharacterMotor>();
			if ((bool)component)
			{
				component.Motor.SetPosition(newPosition);
				component.velocity = new UnityEngine.Vector3(0f, Mathf.Min(component.velocity.y, 0f), 0f);
			}
			else
			{
				gameObject.transform.position = newPosition;
			}
			ITeleportHandler[] componentsInChildren = gameObject.GetComponentsInChildren<ITeleportHandler>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].OnTeleport(newPosition - delta, newPosition);
			}
		}

		public static void TeleportBody(CharacterBody body, UnityEngine.Vector3 targetFootPosition)
		{
			if ((bool)body)
			{
				UnityEngine.Vector3 vector = new UnityEngine.Vector3(0f, 0.1f, 0f);
				UnityEngine.Vector3 vector2 = body.footPosition - body.transform.position;
				TeleportGameObject(body.gameObject, targetFootPosition - vector2 + vector);
				if ((bool)body.characterMotor)
				{
					body.characterMotor.disableAirControlUntilCollision = false;
				}
			}
		}

		[NetworkMessageHandler(client = true, server = true, msgType = 68)]
		private static void HandleTeleport(NetworkMessage netMsg)
		{
			if (Util.ConnectionIsLocal(netMsg.conn))
			{
				return;
			}
			netMsg.ReadMessage(messageBuffer);
			if ((bool)messageBuffer.gameObject)
			{
				bool flag = Util.HasEffectiveAuthority(messageBuffer.gameObject);
				if (!flag)
				{
					TeleportGameObject(messageBuffer.gameObject, messageBuffer.newPosition, messageBuffer.delta, flag);
				}
			}
		}

		public static UnityEngine.Vector3? FindSafeTeleportDestination(UnityEngine.Vector3 characterFootPosition, CharacterBody characterBodyOrPrefabComponent, Xoroshiro128Plus rng)
		{
			UnityEngine.Vector3? result = null;
			SpawnCard spawnCard = ScriptableObject.CreateInstance<SpawnCard>();
			spawnCard.hullSize = characterBodyOrPrefabComponent.hullClassification;
			spawnCard.nodeGraphType = MapNodeGroup.GraphType.Ground;
			spawnCard.prefab = LegacyResourcesAPI.Load<GameObject>("SpawnCards/HelperPrefab");
			GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.NearestNode,
				position = characterFootPosition
			}, rng));
			if (!gameObject)
			{
				gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.RandomNormalized,
					position = characterFootPosition
				}, rng));
			}
			if ((bool)gameObject)
			{
				result = gameObject.transform.position;
				UnityEngine.Object.Destroy(gameObject);
			}
			UnityEngine.Object.Destroy(spawnCard);
			return result;
		}
	}
	public class BugItCommands
	{
	}
	public class TimerQueue
	{
		public struct TimerHandle : IEquatable<TimerHandle>
		{
			public static readonly TimerHandle invalid = new TimerHandle(-1);

			public readonly int uid;

			public TimerHandle(int uid)
			{
				this.uid = uid;
			}

			public bool Equals(TimerHandle other)
			{
				return uid == other.uid;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is TimerHandle)
				{
					return Equals((TimerHandle)obj);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return uid;
			}
		}

		private struct Timer
		{
			public float time;

			public Action action;

			public TimerHandle handle;
		}

		private float internalTime;

		private int count;

		private Timer[] timers = Array.Empty<Timer>();

		private readonly IndexAllocator indexAllocator = new IndexAllocator();

		private Action[] actionsToCall = Array.Empty<Action>();

		private int actionsToCallCount;

		public TimerHandle CreateTimer(float time, Action action)
		{
			time += internalTime;
			int position = count;
			for (int i = 0; i < count; i++)
			{
				if (time < timers[i].time)
				{
					position = i;
					break;
				}
			}
			TimerHandle timerHandle = new TimerHandle(indexAllocator.RequestIndex());
			Timer timer = default(Timer);
			timer.time = time;
			timer.action = action;
			timer.handle = timerHandle;
			Timer value = timer;
			ArrayUtils.ArrayInsert(ref timers, ref count, position, in value);
			return timerHandle;
		}

		public void RemoveTimer(TimerHandle timerHandle)
		{
			for (int i = 0; i < count; i++)
			{
				if (timers[i].handle.Equals(timerHandle))
				{
					RemoveTimerAt(i);
					break;
				}
			}
		}

		private void RemoveTimerAt(int i)
		{
			indexAllocator.FreeIndex(timers[i].handle.uid);
			ArrayUtils.ArrayRemoveAt(timers, ref count, i);
		}

		public void Update(float deltaTime)
		{
			internalTime += deltaTime;
			for (int i = 0; i < count && timers[i].time <= internalTime; i++)
			{
				ArrayUtils.ArrayInsert(ref actionsToCall, ref actionsToCallCount, actionsToCallCount, in timers[i].action);
			}
			for (int num = actionsToCallCount - 1; num >= 0; num--)
			{
				RemoveTimerAt(num);
			}
			for (int j = 0; j < actionsToCallCount; j++)
			{
				ref Action reference = ref actionsToCall[j];
				try
				{
					reference();
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
				reference = null;
			}
			actionsToCallCount = 0;
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct Trajectory
	{
		private static float defaultGravity => Physics.gravity.y;

		public static float CalculateApex(float initialSpeed)
		{
			return CalculateApex(initialSpeed, defaultGravity);
		}

		public static float CalculateApex(float initialSpeed, float gravity)
		{
			return initialSpeed * initialSpeed / (2f * (0f - gravity));
		}

		public static float CalculateGroundSpeed(float time, float distance)
		{
			return distance / time;
		}

		public static float CalculateGroundTravelTime(float hSpeed, float hDistance)
		{
			return hDistance / hSpeed;
		}

		public static float CalculateInitialYSpeed(float timeToTarget, float destinationYOffset)
		{
			return CalculateInitialYSpeed(timeToTarget, destinationYOffset, defaultGravity);
		}

		public static float CalculateInitialYSpeed(float timeToTarget, float destinationYOffset, float gravity)
		{
			return (destinationYOffset + 0.5f * (0f - gravity) * timeToTarget * timeToTarget) / timeToTarget;
		}

		public static float CalculateInitialYSpeedForHeight(float height)
		{
			return CalculateInitialYSpeedForHeight(height, defaultGravity);
		}

		public static float CalculateInitialYSpeedForHeight(float height, float gravity)
		{
			return Mathf.Sqrt(height * (2f * (0f - gravity)));
		}

		public static UnityEngine.Vector3 CalculatePositionAtTime(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float t)
		{
			return CalculatePositionAtTime(origin, initialVelocity, t, defaultGravity);
		}

		public static UnityEngine.Vector3 CalculatePositionAtTime(UnityEngine.Vector3 origin, UnityEngine.Vector3 initialVelocity, float t, float gravity)
		{
			UnityEngine.Vector3 result = origin + initialVelocity * t;
			result.y += 0.5f * gravity * t * t;
			return result;
		}

		public static float CalculatePositionYAtTime(float originY, float initialVelocityY, float t)
		{
			return CalculatePositionYAtTime(originY, initialVelocityY, t, defaultGravity);
		}

		public static float CalculatePositionYAtTime(float originY, float initialVelocityY, float t, float gravity)
		{
			return originY + initialVelocityY * t + 0.5f * gravity * t * t;
		}

		public static float CalculateInitialYSpeedForFlightDuration(float duration)
		{
			return CalculateInitialYSpeedForFlightDuration(duration, defaultGravity);
		}

		public static float CalculateInitialYSpeedForFlightDuration(float duration, float gravity)
		{
			return duration * gravity * -0.5f;
		}

		public static float CalculateFlightDuration(float vSpeed)
		{
			return CalculateFlightDuration(vSpeed, defaultGravity);
		}

		public static float CalculateFlightDuration(float vSpeed, float gravity)
		{
			return 2f * vSpeed / (0f - gravity);
		}

		public static float CalculateFlightDuration(float originY, float endY, float vSpeed)
		{
			return CalculateFlightDuration(originY, endY, vSpeed, defaultGravity);
		}

		public static float CalculateFlightDuration(float originY, float endY, float vSpeed, float gravity)
		{
			float num = endY - originY;
			float num2 = Mathf.Sqrt(vSpeed * vSpeed - 4f * (0.5f * gravity) * (0f - num));
			return (0f - vSpeed - num2) / gravity;
		}

		public static float CalculateGroundSpeedToClearDistance(float vSpeed, float distance)
		{
			return CalculateGroundSpeedToClearDistance(vSpeed, distance, defaultGravity);
		}

		public static float CalculateGroundSpeedToClearDistance(float vSpeed, float distance, float gravity)
		{
			return distance / CalculateFlightDuration(vSpeed, gravity);
		}
	}
	public static class TrajectoryAimAssist
	{
		private struct AimAssistHit
		{
			public UnityEngine.Vector3 point;

			public float distance;

			public Collider collider;

			public HurtBox hitHurtBox;

			public GameObject entityObject;
		}

		private static readonly LayerMask hitMask = (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask;

		public static FloatConVar aimTrajectoryAssistMaxRadius = new FloatConVar("aim_trajectory_assist_max_radius", ConVarFlags.None, "3", "When mapping from the user's sensitivity setting to the actual spherecast radius, this will be the maximum value used.");

		public static FloatConVar aimTrajectoryAssistProjectileDistanceScale = new FloatConVar("aim_trajectory_assist_distance_scale", ConVarFlags.None, "0.5", "When using trajectory aim assist for a projectile, max distance will be set to speed scaled by this value");

		public static FloatConVar aimTrajectoryAssistMinProjectileSpeed = new FloatConVar("aim_trajectory_assist_min_projectile_speed", ConVarFlags.None, "60", "Trajectory aim assist will only be applied to projectiles which have speed greater than this value");

		public static FloatConVar aimTrajectoryAssistMaxChangeThreshold = new FloatConVar("aim_trajectory_assist_max_change_threshold", ConVarFlags.None, "0.8", "Controls maximum adjustment. If the dot product between original and adjusted aim vectors is less than this, the result will be discarded");

		private static void InitAimAssistHitFromRaycastHit(ref AimAssistHit aimAssistHit, UnityEngine.Vector3 origin, ref RaycastHit raycastHit)
		{
			aimAssistHit.distance = raycastHit.distance;
			aimAssistHit.collider = raycastHit.collider;
			aimAssistHit.point = ((aimAssistHit.distance == 0f) ? origin : raycastHit.point);
			HurtBox hurtBox = (aimAssistHit.hitHurtBox = aimAssistHit.collider.GetComponent<HurtBox>());
			aimAssistHit.entityObject = (((bool)hurtBox && (bool)hurtBox.healthComponent) ? hurtBox.healthComponent.gameObject : aimAssistHit.collider.gameObject);
		}

		private static bool ShouldUseTrajectoryAimAssist(GameObject owner)
		{
			if ((bool)owner)
			{
				CharacterBody component = owner.GetComponent<CharacterBody>();
				if ((object)component != null && component.isPlayerControlled)
				{
					return GetAimAssistRadius(owner) > 0f;
				}
			}
			return false;
		}

		private static float GetAimAssistRadius(GameObject owner)
		{
			if ((bool)owner)
			{
				CharacterBody component = owner.GetComponent<CharacterBody>();
				if ((object)component != null && (bool)component.master)
				{
					PlayerCharacterMasterController component2 = component.master.GetComponent<PlayerCharacterMasterController>();
					if ((object)component2 != null)
					{
						NetworkUser networkUser = component2.networkUser;
						if ((object)networkUser != null)
						{
							LocalUser localUser = networkUser.localUser;
							if (localUser != null)
							{
								UserProfile userProfile = localUser.userProfile;
								if (userProfile != null)
								{
									return Util.Remap((localUser.eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad) ? userProfile.gamePadTrajectoryAimAssistSensitivity : userProfile.mouseTrajectoryAimAssistSensitivity, 0f, 10f, 0f, aimTrajectoryAssistMaxRadius.value);
								}
							}
						}
					}
				}
			}
			return 0f;
		}

		public static void ApplyTrajectoryAimAssist(ref Ray ray, ref FireProjectileInfo projectileInfo, float radiusMultiplier = 1f)
		{
			if (ShouldUseTrajectoryAimAssist(projectileInfo.owner) && (bool)projectileInfo.projectilePrefab)
			{
				float num = (projectileInfo.useSpeedOverride ? projectileInfo.speedOverride : (projectileInfo.projectilePrefab.GetComponent<ProjectileSimple>()?.desiredForwardSpeed ?? 0f));
				if (!(num < aimTrajectoryAssistMinProjectileSpeed.value))
				{
					float maxDistance = num * aimTrajectoryAssistProjectileDistanceScale.value;
					UnityEngine.Vector3 forward = PerformAimAssistInternal(ray.direction, ray.origin, maxDistance, projectileInfo.owner, null, radiusMultiplier);
					projectileInfo.rotation = Util.QuaternionSafeLookRotation(forward);
				}
			}
		}

		public static void ApplyTrajectoryAimAssist(ref Ray ray, GameObject projectilePrefab, GameObject owner, float radiusMultiplier = 1f)
		{
			if (!ShouldUseTrajectoryAimAssist(owner) || !projectilePrefab)
			{
				return;
			}
			ProjectileSimple component = projectilePrefab.GetComponent<ProjectileSimple>();
			if ((object)component != null)
			{
				float desiredForwardSpeed = component.desiredForwardSpeed;
				if (!(desiredForwardSpeed < aimTrajectoryAssistMinProjectileSpeed.value))
				{
					float maxDistance = desiredForwardSpeed * aimTrajectoryAssistProjectileDistanceScale.value;
					ray.direction = PerformAimAssistInternal(ray.direction, ray.origin, maxDistance, owner, null, radiusMultiplier);
				}
			}
		}

		public static void ApplyTrajectoryAimAssist(ref Ray ray, float maxDistance, GameObject owner, float radiusMultiplier = 1f)
		{
			if (ShouldUseTrajectoryAimAssist(owner))
			{
				ray.direction = PerformAimAssistInternal(ray.direction, ray.origin, maxDistance, owner, null, radiusMultiplier);
			}
		}

		public static UnityEngine.Vector3 ApplyTrajectoryAimAssist(UnityEngine.Vector3 aimVector, UnityEngine.Vector3 origin, float maxDistance, GameObject owner, GameObject weapon = null, float radiusMultiplier = 1f)
		{
			if (!ShouldUseTrajectoryAimAssist(owner))
			{
				return aimVector;
			}
			return PerformAimAssistInternal(aimVector, origin, maxDistance, owner, weapon, radiusMultiplier);
		}

		private static UnityEngine.Vector3 PerformAimAssistInternal(UnityEngine.Vector3 aimVector, UnityEngine.Vector3 origin, float maxDistance, GameObject owner, GameObject weapon = null, float radiusMultiplier = 1f)
		{
			if (!owner || Mathf.Approximately(radiusMultiplier, 0f))
			{
				return aimVector;
			}
			float radius = GetAimAssistRadius(owner) * radiusMultiplier;
			List<AimAssistHit> list = new List<AimAssistHit>();
			RaycastHit[] array = Physics.SphereCastAll(origin, radius, aimVector, maxDistance, hitMask, QueryTriggerInteraction.Ignore);
			for (int i = 0; i < array.Length; i++)
			{
				AimAssistHit aimAssistHit = default(AimAssistHit);
				InitAimAssistHitFromRaycastHit(ref aimAssistHit, origin, ref array[i]);
				list.Add(aimAssistHit);
			}
			List<GameObject> list2 = new List<GameObject> { owner };
			if ((bool)weapon)
			{
				list2.Add(weapon);
			}
			UnityEngine.Vector3 targetPosition = origin;
			if (!ProcessPotentialTargets(list, ref targetPosition, list2, owner))
			{
				return aimVector;
			}
			UnityEngine.Vector3 normalized = (targetPosition - origin).normalized;
			if (!(UnityEngine.Vector3.Dot(aimVector, normalized) > aimTrajectoryAssistMaxChangeThreshold.value))
			{
				return aimVector;
			}
			return normalized;
		}

		private static bool ProcessPotentialTargets(List<AimAssistHit> hits, ref UnityEngine.Vector3 targetPosition, List<GameObject> ignoreList, GameObject owner)
		{
			TeamIndex attackerTeamIndex = TeamIndex.None;
			TeamComponent component = owner.GetComponent<TeamComponent>();
			if ((object)component != null)
			{
				attackerTeamIndex = component.teamIndex;
			}
			int count = hits.Count;
			int[] array = new int[count];
			for (int i = 0; i < count; i++)
			{
				array[i] = i;
			}
			for (int j = 0; j < count; j++)
			{
				float num = float.PositiveInfinity;
				int num2 = j;
				for (int k = j; k < count; k++)
				{
					int index = array[k];
					if (hits[index].distance < num)
					{
						num = hits[index].distance;
						num2 = k;
					}
				}
				GameObject entityObject = hits[array[num2]].entityObject;
				if (ignoreList.Contains(entityObject))
				{
					array[num2] = array[j];
					continue;
				}
				ignoreList.Add(entityObject);
				AimAssistHit aimAssistHit = hits[array[num2]];
				if (!aimAssistHit.collider || ((1 << aimAssistHit.collider.gameObject.layer) & (int)hitMask) == 0)
				{
					continue;
				}
				if ((bool)aimAssistHit.hitHurtBox)
				{
					HealthComponent healthComponent = aimAssistHit.hitHurtBox.healthComponent;
					if ((object)healthComponent != null && FriendlyFireManager.ShouldDirectHitProceed(healthComponent, attackerTeamIndex))
					{
						targetPosition = hits[array[num2]].point;
						return true;
					}
				}
				array[num2] = array[j];
			}
			return false;
		}
	}
	public class TypeRestrictedReferenceAttribute : PropertyAttribute
	{
		public readonly Type[] allowedTypes;

		public TypeRestrictedReferenceAttribute(params Type[] allowedTypes)
		{
			if (allowedTypes != null)
			{
				this.allowedTypes = allowedTypes;
			}
			else
			{
				this.allowedTypes = Array.Empty<Type>();
			}
		}
	}
	internal static class UnitySystemConsoleRedirector
	{
		private class OutWriter : UnityTextWriter
		{
			public override void WriteBufferToUnity(string str)
			{
			}
		}

		private class ErrorWriter : UnityTextWriter
		{
			public override void WriteBufferToUnity(string str)
			{
				UnityEngine.Debug.LogError(str);
			}
		}

		private abstract class UnityTextWriter : TextWriter
		{
			private StringBuilder buffer = new StringBuilder();

			public override Encoding Encoding => Encoding.Default;

			public override void Flush()
			{
				WriteBufferToUnity(buffer.ToString());
				buffer.Length = 0;
			}

			public abstract void WriteBufferToUnity(string str);

			public override void Write(string value)
			{
				buffer.Append(value);
				if (value != null)
				{
					int length = value.Length;
					if (length > 0 && value[length - 1] == '\n')
					{
						Flush();
					}
				}
			}

			public override void Write(char value)
			{
				buffer.Append(value);
				if (value == '\n')
				{
					Flush();
				}
			}

			public override void Write(char[] value, int index, int count)
			{
				Write(new string(value, index, count));
			}
		}

		private static TextWriter oldOut;

		private static TextWriter oldError;

		public static void Redirect()
		{
			oldOut = System.Console.Out;
			System.Console.SetOut(new OutWriter());
			oldError = System.Console.Error;
			System.Console.SetError(new ErrorWriter());
		}

		public static void Disengage()
		{
			if (oldOut != null)
			{
				System.Console.SetOut(oldOut);
				oldOut = null;
			}
			if (oldError != null)
			{
				System.Console.SetError(oldError);
				oldError = null;
			}
		}
	}
	public enum UnlockableIndex
	{
		None = -1
	}
	public static class UnlockableCatalog
	{
		private static readonly Dictionary<UnlockableIndex, ExpansionDef> unlockableToExpansionTable = new Dictionary<UnlockableIndex, ExpansionDef>();

		private static readonly Dictionary<string, UnlockableDef> nameToDefTable = new Dictionary<string, UnlockableDef>();

		private static UnlockableDef[] indexToDefTable;

		public static ResourceAvailability availability;

		public static int unlockableCount => indexToDefTable.Length;

		[CanBeNull]
		public static UnlockableDef GetUnlockableDef([NotNull] string name)
		{
			if (name == null)
			{
				return null;
			}
			nameToDefTable.TryGetValue(name, out var value);
			return value;
		}

		[CanBeNull]
		public static UnlockableDef GetUnlockableDef(UnlockableIndex index)
		{
			return ArrayUtils.GetSafe(indexToDefTable, (int)index);
		}

		[CanBeNull]
		public static ExpansionDef GetExpansionDefForUnlockable(UnlockableIndex index)
		{
			unlockableToExpansionTable.TryGetValue(index, out var value);
			return value;
		}

		[SystemInitializer(new Type[]
		{
			typeof(SurvivorCatalog),
			typeof(ItemCatalog),
			typeof(EquipmentCatalog),
			typeof(ArtifactCatalog),
			typeof(BodyCatalog)
		})]
		private static void Init()
		{
			SetUnlockableDefs(ContentManager.unlockableDefs);
		}

		private static void SetUnlockableDefs(UnlockableDef[] newUnlockableDefs)
		{
			nameToDefTable.Clear();
			indexToDefTable = ArrayUtils.Clone(newUnlockableDefs);
			for (UnlockableIndex unlockableIndex = (UnlockableIndex)0; (int)unlockableIndex < indexToDefTable.Length; unlockableIndex++)
			{
				UnlockableDef unlockableDef = indexToDefTable[(int)unlockableIndex];
				unlockableDef.index = unlockableIndex;
				nameToDefTable[unlockableDef.cachedName] = unlockableDef;
			}
			GenerateUnlockableMetaData(indexToDefTable);
		}

		private static void TryAddExpansionMapping(UnlockableDef unlockable, ExpansionDef expansion)
		{
			if ((bool)unlockable && (!unlockableToExpansionTable.ContainsKey(unlockable.index) || !unlockableToExpansionTable[unlockable.index]))
			{
				if ((bool)unlockable.requiredExpansion)
				{
					unlockableToExpansionTable[unlockable.index] = unlockable.requiredExpansion;
				}
				else
				{
					unlockableToExpansionTable[unlockable.index] = expansion;
				}
			}
		}

		private static void GenerateUnlockableMetaData(UnlockableDef[] unlockableDefs)
		{
			unlockableToExpansionTable.Clear();
			UnlockableDef[] array = unlockableDefs;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].sortScore = int.MaxValue;
			}
			HashSet<UnlockableDef> unlockableDefsSet = new HashSet<UnlockableDef>();
			array = unlockableDefs;
			foreach (UnlockableDef item in array)
			{
				unlockableDefsSet.Add(item);
			}
			int topSortValue = 0;
			foreach (ItemDef item2 in ItemCatalog.allItems.Select(ItemCatalog.GetItemDef).OrderBy(GetItemSortScore))
			{
				AssignUnlockableSortScore(item2.unlockableDef);
				TryAddExpansionMapping(item2.unlockableDef, item2.requiredExpansion);
			}
			foreach (EquipmentDef item3 in EquipmentCatalog.allEquipment.Select(EquipmentCatalog.GetEquipmentDef).OrderBy(GetEquipmentSortScore))
			{
				AssignUnlockableSortScore(item3.unlockableDef);
				TryAddExpansionMapping(item3.unlockableDef, item3.requiredExpansion);
			}
			foreach (SurvivorDef orderedSurvivorDef in SurvivorCatalog.orderedSurvivorDefs)
			{
				AssignUnlockableSortScore(orderedSurvivorDef.unlockableDef);
				BodyIndex bodyIndex = BodyCatalog.FindBodyIndex(orderedSurvivorDef.bodyPrefab);
				if (bodyIndex == BodyIndex.None)
				{
					continue;
				}
				ExpansionDef expansion = null;
				GameObject bodyPrefab = BodyCatalog.GetBodyPrefab(bodyIndex);
				if ((bool)bodyPrefab)
				{
					ExpansionRequirementComponent component = bodyPrefab.GetComponent<ExpansionRequirementComponent>();
					if ((bool)component)
					{
						expansion = component.requiredExpansion;
					}
				}
				TryAddExpansionMapping(orderedSurvivorDef.unlockableDef, expansion);
				GenericSkill[] bodyPrefabSkillSlots = BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex);
				for (int i = 0; i < bodyPrefabSkillSlots.Length; i++)
				{
					SkillFamily skillFamily = bodyPrefabSkillSlots[i].skillFamily;
					if ((bool)skillFamily)
					{
						SkillFamily.Variant[] variants = skillFamily.variants;
						for (int j = 0; j < variants.Length; j++)
						{
							SkillFamily.Variant variant = variants[j];
							AssignUnlockableSortScore(variant.unlockableDef);
							TryAddExpansionMapping(variant.unlockableDef, expansion);
						}
					}
				}
				SkinDef[] bodySkins = BodyCatalog.GetBodySkins(bodyIndex);
				foreach (SkinDef obj in bodySkins)
				{
					AssignUnlockableSortScore(obj.unlockableDef);
					TryAddExpansionMapping(obj.unlockableDef, expansion);
				}
			}
			for (ArtifactIndex artifactIndex = (ArtifactIndex)0; (int)artifactIndex < ArtifactCatalog.artifactCount; artifactIndex++)
			{
				ArtifactDef artifactDef = ArtifactCatalog.GetArtifactDef(artifactIndex);
				AssignUnlockableSortScore(artifactDef.unlockableDef);
				TryAddExpansionMapping(artifactDef.unlockableDef, artifactDef.requiredExpansion);
			}
			void AssignUnlockableSortScore(UnlockableDef unlockableDef)
			{
				if (unlockableDefsSet.Contains(unlockableDef) && unlockableDef.sortScore == int.MaxValue)
				{
					unlockableDef.sortScore = ++topSortValue;
				}
			}
			static int GetEquipmentSortScore(EquipmentDef equipmentDef)
			{
				if (equipmentDef.isLunar)
				{
					return 0;
				}
				return 1;
			}
			static int GetItemSortScore(ItemDef itemDef)
			{
				return itemDef.tier switch
				{
					ItemTier.Tier1 => 1, 
					ItemTier.Tier2 => 2, 
					ItemTier.Tier3 => 3, 
					ItemTier.Lunar => 5, 
					ItemTier.Boss => 4, 
					ItemTier.NoTier => 0, 
					_ => 0, 
				};
			}
		}

		public static int GetUnlockableSortScore(string unlockableName)
		{
			return GetUnlockableDef(unlockableName)?.sortScore ?? 0;
		}
	}
	public static class Util
	{
		private struct EasyTargetCandidate
		{
			public Transform transform;

			public float score;

			public float distance;
		}

		public const string attackSpeedRtpcName = "attackSpeed";

		private static readonly string strBackslash = "\\";

		private static readonly string strBackslashBackslash = strBackslash + strBackslash;

		private static readonly string strQuote = "\"";

		private static readonly string strBackslashQuote = strBackslash + strQuote;

		private static readonly Regex backlashSearch = new Regex(strBackslashBackslash);

		private static readonly Regex quoteSearch = new Regex(strQuote);

		public static readonly DateTime dateZero = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

		public static bool useCachedNetWriter = false;

		public static bool breakInVerify = true;

		public static bool logVerify = true;

		public static bool cacheBulletHitHurtBox = true;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		private static readonly Stack<string> sharedStringStack = new Stack<string>();

		private static readonly string cloneString = "(Clone)";

		public static void CleanseBody(CharacterBody characterBody, bool removeDebuffs, bool removeBuffs, bool removeCooldownBuffs, bool removeDots, bool removeStun, bool removeNearbyProjectiles)
		{
			if (removeDebuffs || removeBuffs || removeCooldownBuffs)
			{
				BuffIndex buffIndex = (BuffIndex)0;
				for (BuffIndex buffCount = (BuffIndex)BuffCatalog.buffCount; buffIndex < buffCount; buffIndex++)
				{
					BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex);
					if ((buffDef.isDebuff && removeDebuffs) || (buffDef.isCooldown && removeCooldownBuffs) || (!buffDef.isDebuff && !buffDef.isCooldown && removeBuffs))
					{
						characterBody.ClearTimedBuffs(buffIndex);
					}
				}
			}
			if (removeDots)
			{
				DotController.RemoveAllDots(characterBody.gameObject);
			}
			if (removeStun)
			{
				SetStateOnHurt component = characterBody.GetComponent<SetStateOnHurt>();
				if ((bool)component)
				{
					component.Cleanse();
				}
			}
			if (!removeNearbyProjectiles)
			{
				return;
			}
			float num = 6f * 6f;
			TeamIndex teamIndex = characterBody.teamComponent.teamIndex;
			List<ProjectileController> instancesList = InstanceTracker.GetInstancesList<ProjectileController>();
			List<ProjectileController> list = new List<ProjectileController>();
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				ProjectileController projectileController = instancesList[i];
				if (!projectileController.cannotBeDeleted && projectileController.teamFilter.teamIndex != teamIndex && (projectileController.transform.position - characterBody.corePosition).sqrMagnitude < num)
				{
					list.Add(projectileController);
				}
			}
			int j = 0;
			for (int count2 = list.Count; j < count2; j++)
			{
				ProjectileController projectileController2 = list[j];
				if ((bool)projectileController2)
				{
					UnityEngine.Object.Destroy(projectileController2.gameObject);
				}
			}
		}

		public static WeightedSelection<DirectorCard> CreateReasonableDirectorCardSpawnList(float availableCredit, int maximumNumberToSpawnBeforeSkipping, int minimumToSpawn)
		{
			WeightedSelection<DirectorCard> monsterSelection = ClassicStageInfo.instance.monsterSelection;
			WeightedSelection<DirectorCard> weightedSelection = new WeightedSelection<DirectorCard>();
			for (int i = 0; i < monsterSelection.Count; i++)
			{
				DirectorCard value = monsterSelection.choices[i].value;
				float combatDirectorHighestEliteCostMultiplier = CombatDirector.CalcHighestEliteCostMultiplier(value.spawnCard.eliteRules);
				if (DirectorCardIsReasonableChoice(availableCredit, maximumNumberToSpawnBeforeSkipping, minimumToSpawn, value, combatDirectorHighestEliteCostMultiplier))
				{
					weightedSelection.AddChoice(value, monsterSelection.choices[i].weight);
				}
			}
			return weightedSelection;
		}

		public static bool DirectorCardIsReasonableChoice(float availableCredit, int maximumNumberToSpawnBeforeSkipping, int minimumToSpawn, DirectorCard card, float combatDirectorHighestEliteCostMultiplier)
		{
			float num = (float)(card.cost * maximumNumberToSpawnBeforeSkipping) * ((card.spawnCard as CharacterSpawnCard).noElites ? 1f : combatDirectorHighestEliteCostMultiplier);
			if (card.IsAvailable() && (float)card.cost * (float)minimumToSpawn <= availableCredit)
			{
				return num / 2f > availableCredit;
			}
			return false;
		}

		public static CharacterBody HurtBoxColliderToBody(Collider collider)
		{
			HurtBox component = collider.GetComponent<HurtBox>();
			if ((bool)component && (bool)component.healthComponent)
			{
				return component.healthComponent.body;
			}
			return null;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float ConvertAmplificationPercentageIntoReductionPercentage(float amplificationPercentage)
		{
			return (1f - 100f / (100f + amplificationPercentage)) * 100f;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float ConvertAmplificationPercentageIntoReductionNormalized(float amplificationNormal)
		{
			return (1f - 1f / (1f + amplificationNormal)) * 1f;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float NonlinearLerp(float min, float max, float amplifactionNormalixed)
		{
			return Mathf.Lerp(min, max, ConvertAmplificationPercentageIntoReductionNormalized(amplifactionNormalixed));
		}

		public static UnityEngine.Vector3 ClosestPointOnLine(UnityEngine.Vector3 vA, UnityEngine.Vector3 vB, UnityEngine.Vector3 vPoint)
		{
			UnityEngine.Vector3 rhs = vPoint - vA;
			UnityEngine.Vector3 normalized = (vB - vA).normalized;
			float num = UnityEngine.Vector3.Distance(vA, vB);
			float num2 = UnityEngine.Vector3.Dot(normalized, rhs);
			if (num2 <= 0f)
			{
				return vA;
			}
			if (num2 >= num)
			{
				return vB;
			}
			UnityEngine.Vector3 vector = normalized * num2;
			return vA + vector;
		}

		public static CharacterBody TryToCreateGhost(CharacterBody targetBody, CharacterBody ownerBody, int duration)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'RoR2.CharacterBody RoR2.Util::TryToCreateGhost(RoR2.CharacterBody, RoR2.CharacterBody, int)' called on client");
				return null;
			}
			if (!targetBody)
			{
				return null;
			}
			GameObject bodyPrefab = BodyCatalog.FindBodyPrefab(targetBody);
			if (!bodyPrefab)
			{
				return null;
			}
			CharacterMaster characterMaster = MasterCatalog.allAiMasters.FirstOrDefault((CharacterMaster master) => master.bodyPrefab == bodyPrefab);
			if (!characterMaster)
			{
				return null;
			}
			MasterSummon obj = new MasterSummon
			{
				masterPrefab = characterMaster.gameObject,
				ignoreTeamMemberLimit = false,
				position = targetBody.footPosition
			};
			CharacterDirection component = targetBody.GetComponent<CharacterDirection>();
			obj.rotation = (component ? UnityEngine.Quaternion.Euler(0f, component.yaw, 0f) : targetBody.transform.rotation);
			obj.summonerBodyObject = (ownerBody ? ownerBody.gameObject : null);
			obj.inventoryToCopy = targetBody.inventory;
			obj.useAmbientLevel = null;
			obj.preSpawnSetupCallback = (Action<CharacterMaster>)Delegate.Combine(obj.preSpawnSetupCallback, new Action<CharacterMaster>(PreSpawnSetup));
			CharacterMaster characterMaster2 = obj.Perform();
			if (!characterMaster2)
			{
				return null;
			}
			CharacterBody body = characterMaster2.GetBody();
			if ((bool)body)
			{
				EntityStateMachine[] components = body.GetComponents<EntityStateMachine>();
				foreach (EntityStateMachine obj2 in components)
				{
					obj2.initialStateType = obj2.mainStateType;
				}
			}
			return body;
			void PreSpawnSetup(CharacterMaster newMaster)
			{
				newMaster.inventory.GiveItem(RoR2Content.Items.Ghost);
				newMaster.inventory.GiveItem(RoR2Content.Items.HealthDecay, duration);
				newMaster.inventory.GiveItem(RoR2Content.Items.BoostDamage, 150);
			}
		}

		public static float OnHitProcDamage(float damageThatProccedIt, float damageStat, float damageCoefficient)
		{
			float b = damageThatProccedIt * damageCoefficient;
			return Mathf.Max(1f, b);
		}

		public static float OnKillProcDamage(float baseDamage, float damageCoefficient)
		{
			return baseDamage * damageCoefficient;
		}

		public static UnityEngine.Quaternion QuaternionSafeLookRotation(UnityEngine.Vector3 forward)
		{
			UnityEngine.Quaternion result = UnityEngine.Quaternion.identity;
			if (forward.sqrMagnitude > Mathf.Epsilon && forward != UnityEngine.Vector3.zero)
			{
				result = UnityEngine.Quaternion.LookRotation(forward);
			}
			return result;
		}

		public static UnityEngine.Quaternion QuaternionSafeLookRotation(UnityEngine.Vector3 forward, UnityEngine.Vector3 upwards)
		{
			UnityEngine.Quaternion result = UnityEngine.Quaternion.identity;
			if (forward.sqrMagnitude > Mathf.Epsilon)
			{
				result = UnityEngine.Quaternion.LookRotation(forward, upwards);
			}
			return result;
		}

		public static bool HasParameterOfType(Animator animator, string name, AnimatorControllerParameterType type)
		{
			AnimatorControllerParameter[] parameters = animator.parameters;
			foreach (AnimatorControllerParameter animatorControllerParameter in parameters)
			{
				if (animatorControllerParameter.type == type && animatorControllerParameter.name == name)
				{
					return true;
				}
			}
			return false;
		}

		public static uint PlaySound(string soundString, GameObject gameObject)
		{
			if (string.IsNullOrEmpty(soundString))
			{
				return 0u;
			}
			if (gameObject == null)
			{
				return AkSoundEngine.PostEvent(soundString, ulong.MaxValue);
			}
			return AkSoundEngine.PostEvent(soundString, gameObject);
		}

		public static uint PlaySound(string soundString, GameObject gameObject, string RTPCstring, float RTPCvalue)
		{
			uint num = PlaySound(soundString, gameObject);
			if (num != 0)
			{
				AkSoundEngine.SetRTPCValueByPlayingID(RTPCstring, RTPCvalue, num);
			}
			return num;
		}

		public static uint PlayAttackSpeedSound(string soundString, GameObject gameObject, float attackSpeedStat)
		{
			uint num = PlaySound(soundString, gameObject);
			if (num != 0)
			{
				float in_value = CalculateAttackSpeedRtpcValue(attackSpeedStat);
				AkSoundEngine.SetRTPCValueByPlayingID("attackSpeed", in_value, num);
			}
			return num;
		}

		public static float CalculateAttackSpeedRtpcValue(float attackSpeedStat)
		{
			float num = Mathf.Log(attackSpeedStat, 2f);
			return 1200f * num / 96f + 50f;
		}

		public static void RotateAwayFromWalls(float raycastLength, int raycastCount, UnityEngine.Vector3 raycastOrigin, Transform referenceTransform)
		{
			float num = 360f / (float)raycastCount;
			float angle = 0f;
			float num2 = 0f;
			for (int i = 0; i < raycastCount; i++)
			{
				UnityEngine.Vector3 direction = UnityEngine.Quaternion.Euler(0f, num * (float)i, 0f) * UnityEngine.Vector3.forward;
				float num3 = raycastLength;
				if (Physics.Raycast(raycastOrigin, direction, out var hitInfo, raycastLength, LayerIndex.world.mask))
				{
					num3 = hitInfo.distance;
				}
				if (hitInfo.distance > num2)
				{
					angle = num * (float)i;
					num2 = num3;
				}
			}
			referenceTransform.Rotate(UnityEngine.Vector3.up, angle, Space.Self);
		}

		public static string GetActionDisplayString(ActionElementMap actionElementMap)
		{
			if (actionElementMap == null)
			{
				return "";
			}
			return actionElementMap.elementIdentifierName switch
			{
				"Left Mouse Button" => "M1", 
				"Right Mouse Button" => "M2", 
				"Left Shift" => "Shift", 
				_ => actionElementMap.elementIdentifierName, 
			};
		}

		public static float AngleSigned(UnityEngine.Vector3 v1, UnityEngine.Vector3 v2, UnityEngine.Vector3 n)
		{
			return Mathf.Atan2(UnityEngine.Vector3.Dot(n, UnityEngine.Vector3.Cross(v1, v2)), UnityEngine.Vector3.Dot(v1, v2)) * 57.29578f;
		}

		public static float Remap(float value, float inMin, float inMax, float outMin, float outMax)
		{
			return outMin + (value - inMin) / (inMax - inMin) * (outMax - outMin);
		}

		public static bool HasAnimationParameter(string paramName, Animator animator)
		{
			AnimatorControllerParameter[] parameters = animator.parameters;
			for (int i = 0; i < parameters.Length; i++)
			{
				if (parameters[i].name == paramName)
				{
					return true;
				}
			}
			return false;
		}

		public static bool HasAnimationParameter(int paramHash, AnimatorControllerParameter[] parameters)
		{
			int i = 0;
			for (int num = parameters.Length; i < num; i++)
			{
				if (parameters[i].nameHash == paramHash)
				{
					return true;
				}
			}
			return false;
		}

		public static bool HasAnimationParameter(int paramHash, Animator animator)
		{
			return HasAnimationParameter(paramHash, animator.parameters);
		}

		public static bool CheckRoll(float percentChance, float luck = 0f, CharacterMaster effectOriginMaster = null)
		{
			if (percentChance <= 0f)
			{
				return false;
			}
			int num = Mathf.CeilToInt(Mathf.Abs(luck));
			float num2 = UnityEngine.Random.Range(0f, 100f);
			float num3 = num2;
			for (int i = 0; i < num; i++)
			{
				float b = UnityEngine.Random.Range(0f, 100f);
				num2 = ((luck > 0f) ? Mathf.Min(num2, b) : Mathf.Max(num2, b));
			}
			if (num2 <= percentChance)
			{
				if (num3 > percentChance && (bool)effectOriginMaster)
				{
					GameObject bodyObject = effectOriginMaster.GetBodyObject();
					if ((bool)bodyObject)
					{
						CharacterBody component = bodyObject.GetComponent<CharacterBody>();
						if ((bool)component)
						{
							component.wasLucky = true;
						}
					}
				}
				return true;
			}
			return false;
		}

		public static bool CheckRoll(float percentChance, CharacterMaster master)
		{
			return CheckRoll(percentChance, master ? master.luck : 0f, master);
		}

		public static float EstimateSurfaceDistance(Collider a, Collider b)
		{
			UnityEngine.Vector3 center = a.bounds.center;
			UnityEngine.Vector3 center2 = b.bounds.center;
			RaycastHit hitInfo;
			UnityEngine.Vector3 a2 = ((!b.Raycast(new Ray(center, center2 - center), out hitInfo, float.PositiveInfinity)) ? b.ClosestPointOnBounds(center) : hitInfo.point);
			UnityEngine.Vector3 b2 = ((!a.Raycast(new Ray(center2, center - center2), out hitInfo, float.PositiveInfinity)) ? a.ClosestPointOnBounds(center2) : hitInfo.point);
			return UnityEngine.Vector3.Distance(a2, b2);
		}

		public static bool HasEffectiveAuthority(GameObject gameObject)
		{
			if ((bool)gameObject)
			{
				return HasEffectiveAuthority(gameObject.GetComponent<NetworkIdentity>());
			}
			return false;
		}

		public static bool HasEffectiveAuthority(NetworkIdentity networkIdentity)
		{
			if ((bool)networkIdentity)
			{
				if (!networkIdentity.hasAuthority)
				{
					if (NetworkServer.active)
					{
						return networkIdentity.clientAuthorityOwner == null;
					}
					return false;
				}
				return true;
			}
			return false;
		}

		public static float CalculateSphereVolume(float radius)
		{
			return 4.1887903f * radius * radius * radius;
		}

		public static float CalculateCylinderVolume(float radius, float height)
		{
			return MathF.PI * radius * radius * height;
		}

		public static float CalculateColliderVolume(Collider collider)
		{
			UnityEngine.Vector3 lossyScale = collider.transform.lossyScale;
			float num = lossyScale.x * lossyScale.y * lossyScale.z;
			float num2 = 0f;
			if (collider is BoxCollider)
			{
				UnityEngine.Vector3 size = ((BoxCollider)collider).size;
				num2 = size.x * size.y * size.z;
			}
			else if (collider is SphereCollider)
			{
				num2 = CalculateSphereVolume(((SphereCollider)collider).radius);
			}
			else if (collider is CapsuleCollider)
			{
				CapsuleCollider obj = (CapsuleCollider)collider;
				float radius = obj.radius;
				float num3 = CalculateSphereVolume(radius);
				float num4 = Mathf.Max(obj.height - num3, 0f);
				float num5 = MathF.PI * radius * radius * num4;
				num2 = num3 + num5;
			}
			else if (collider is CharacterController)
			{
				CharacterController obj2 = (CharacterController)collider;
				float radius2 = obj2.radius;
				float num6 = CalculateSphereVolume(radius2);
				float num7 = Mathf.Max(obj2.height - num6, 0f);
				float num8 = MathF.PI * radius2 * radius2 * num7;
				num2 = num6 + num8;
			}
			return num2 * num;
		}

		public static UnityEngine.Vector3 RandomColliderVolumePoint(Collider collider)
		{
			Transform transform = collider.transform;
			UnityEngine.Vector3 position = UnityEngine.Vector3.zero;
			if (collider is BoxCollider)
			{
				BoxCollider obj = (BoxCollider)collider;
				UnityEngine.Vector3 size = obj.size;
				UnityEngine.Vector3 center = obj.center;
				position = new UnityEngine.Vector3(center.x + UnityEngine.Random.Range(size.x * -0.5f, size.x * 0.5f), center.y + UnityEngine.Random.Range(size.y * -0.5f, size.y * 0.5f), center.z + UnityEngine.Random.Range(size.z * -0.5f, size.z * 0.5f));
			}
			else if (collider is SphereCollider)
			{
				SphereCollider sphereCollider = (SphereCollider)collider;
				position = sphereCollider.center + UnityEngine.Random.insideUnitSphere * sphereCollider.radius;
			}
			else if (collider is CapsuleCollider)
			{
				CapsuleCollider capsuleCollider = (CapsuleCollider)collider;
				float radius = capsuleCollider.radius;
				float num = Mathf.Max(capsuleCollider.height - radius, 0f);
				float num2 = CalculateSphereVolume(radius);
				float num3 = CalculateCylinderVolume(radius, num);
				float maxInclusive = num2 + num3;
				if (UnityEngine.Random.Range(0f, maxInclusive) <= num2)
				{
					position = UnityEngine.Random.insideUnitSphere * radius;
					float num4 = ((float)UnityEngine.Random.Range(0, 2) * 2f - 1f) * num * 0.5f;
					switch (capsuleCollider.direction)
					{
					case 0:
						position.x += num4;
						break;
					case 1:
						position.y += num4;
						break;
					case 2:
						position.z += num4;
						break;
					}
				}
				else
				{
					UnityEngine.Vector2 vector = UnityEngine.Random.insideUnitCircle * radius;
					float num5 = UnityEngine.Random.Range(num * -0.5f, num * 0.5f);
					switch (capsuleCollider.direction)
					{
					case 0:
						position = new UnityEngine.Vector3(num5, vector.x, vector.y);
						break;
					case 1:
						position = new UnityEngine.Vector3(vector.x, num5, vector.y);
						break;
					case 2:
						position = new UnityEngine.Vector3(vector.x, vector.y, num5);
						break;
					}
				}
				position += capsuleCollider.center;
			}
			else if (collider is CharacterController)
			{
				CharacterController characterController = (CharacterController)collider;
				float radius2 = characterController.radius;
				float num6 = Mathf.Max(characterController.height - radius2, 0f);
				float num7 = CalculateSphereVolume(radius2);
				float num8 = CalculateCylinderVolume(radius2, num6);
				float maxInclusive2 = num7 + num8;
				if (UnityEngine.Random.Range(0f, maxInclusive2) <= num7)
				{
					position = UnityEngine.Random.insideUnitSphere * radius2;
					float num9 = ((float)UnityEngine.Random.Range(0, 2) * 2f - 1f) * num6 * 0.5f;
					position.y += num9;
				}
				else
				{
					UnityEngine.Vector2 vector2 = UnityEngine.Random.insideUnitCircle * radius2;
					float y = UnityEngine.Random.Range(num6 * -0.5f, num6 * 0.5f);
					position = new UnityEngine.Vector3(vector2.x, y, vector2.y);
				}
				position += characterController.center;
			}
			return transform.TransformPoint(position);
		}

		public static CharacterBody GetFriendlyEasyTarget(CharacterBody casterBody, Ray aimRay, float maxDistance, float maxDeviation = 20f)
		{
			TeamIndex teamIndex = TeamIndex.Neutral;
			TeamComponent component = casterBody.GetComponent<TeamComponent>();
			if ((bool)component)
			{
				teamIndex = component.teamIndex;
			}
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(teamIndex);
			UnityEngine.Vector3 origin = aimRay.origin;
			UnityEngine.Vector3 direction = aimRay.direction;
			List<EasyTargetCandidate> candidatesList = new List<EasyTargetCandidate>(teamMembers.Count);
			List<int> list = new List<int>(teamMembers.Count);
			float num = Mathf.Cos(maxDeviation * (MathF.PI / 180f));
			for (int i = 0; i < teamMembers.Count; i++)
			{
				Transform transform = teamMembers[i].transform;
				UnityEngine.Vector3 vector = transform.position - origin;
				float magnitude = vector.magnitude;
				float num2 = UnityEngine.Vector3.Dot(vector * (1f / magnitude), direction);
				CharacterBody component2 = transform.GetComponent<CharacterBody>();
				if (num2 >= num && component2 != casterBody)
				{
					float num3 = 1f / magnitude;
					float score = num2 + num3;
					candidatesList.Add(new EasyTargetCandidate
					{
						transform = transform,
						score = score,
						distance = magnitude
					});
					list.Add(list.Count);
				}
			}
			list.Sort(delegate(int a, int b)
			{
				float score2 = candidatesList[a].score;
				float score3 = candidatesList[b].score;
				return (score2 != score3) ? ((!(score2 > score3)) ? 1 : (-1)) : 0;
			});
			for (int j = 0; j < list.Count; j++)
			{
				int index = list[j];
				CharacterBody component3 = candidatesList[index].transform.GetComponent<CharacterBody>();
				if ((bool)component3 && component3 != casterBody)
				{
					return component3;
				}
			}
			return null;
		}

		public static CharacterBody GetEnemyEasyTarget(CharacterBody casterBody, Ray aimRay, float maxDistance, float maxDeviation = 20f)
		{
			TeamIndex teamIndex = TeamIndex.Neutral;
			TeamComponent component = casterBody.GetComponent<TeamComponent>();
			if ((bool)component)
			{
				teamIndex = component.teamIndex;
			}
			List<TeamComponent> list = new List<TeamComponent>();
			for (TeamIndex teamIndex2 = TeamIndex.Neutral; teamIndex2 < TeamIndex.Count; teamIndex2++)
			{
				if (teamIndex2 != teamIndex)
				{
					list.AddRange(TeamComponent.GetTeamMembers(teamIndex2));
				}
			}
			UnityEngine.Vector3 origin = aimRay.origin;
			UnityEngine.Vector3 direction = aimRay.direction;
			List<EasyTargetCandidate> candidatesList = new List<EasyTargetCandidate>(list.Count);
			List<int> list2 = new List<int>(list.Count);
			float num = Mathf.Cos(maxDeviation * (MathF.PI / 180f));
			for (int i = 0; i < list.Count; i++)
			{
				Transform transform = list[i].transform;
				UnityEngine.Vector3 vector = transform.position - origin;
				float magnitude = vector.magnitude;
				float num2 = UnityEngine.Vector3.Dot(vector * (1f / magnitude), direction);
				CharacterBody component2 = transform.GetComponent<CharacterBody>();
				if (num2 >= num && component2 != casterBody && magnitude < maxDistance)
				{
					float num3 = 1f / magnitude;
					float score = num2 + num3;
					candidatesList.Add(new EasyTargetCandidate
					{
						transform = transform,
						score = score,
						distance = magnitude
					});
					list2.Add(list2.Count);
				}
			}
			list2.Sort(delegate(int a, int b)
			{
				float score2 = candidatesList[a].score;
				float score3 = candidatesList[b].score;
				return (score2 != score3) ? ((!(score2 > score3)) ? 1 : (-1)) : 0;
			});
			for (int j = 0; j < list2.Count; j++)
			{
				int index = list2[j];
				CharacterBody component3 = candidatesList[index].transform.GetComponent<CharacterBody>();
				if ((bool)component3 && component3 != casterBody)
				{
					return component3;
				}
			}
			return null;
		}

		public static float GetBodyPrefabFootOffset(GameObject prefab)
		{
			CapsuleCollider component = prefab.GetComponent<CapsuleCollider>();
			if ((bool)component)
			{
				return component.height * 0.5f - component.center.y;
			}
			return 0f;
		}

		public static void ShuffleList<T>(List<T> list)
		{
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = UnityEngine.Random.Range(0, num + 1);
				T value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
		}

		public static void ShuffleList<T>(List<T> list, Xoroshiro128Plus rng)
		{
			for (int num = list.Count - 1; num > 0; num--)
			{
				int index = rng.RangeInt(0, num + 1);
				T value = list[num];
				list[num] = list[index];
				list[index] = value;
			}
		}

		public static void ShuffleArray<T>(T[] array)
		{
			for (int num = array.Length - 1; num > 0; num--)
			{
				int num2 = UnityEngine.Random.Range(0, num + 1);
				T val = array[num];
				array[num] = array[num2];
				array[num2] = val;
			}
		}

		public static void ShuffleArray<T>(T[] array, Xoroshiro128Plus rng)
		{
			for (int num = array.Length - 1; num > 0; num--)
			{
				int num2 = rng.RangeInt(0, num + 1);
				T val = array[num];
				array[num] = array[num2];
				array[num2] = val;
			}
		}

		public static Transform FindNearest(UnityEngine.Vector3 position, List<Transform> transformsList, float range = float.PositiveInfinity)
		{
			Transform result = null;
			float num = range * range;
			for (int i = 0; i < transformsList.Count; i++)
			{
				float sqrMagnitude = (transformsList[i].position - position).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					result = transformsList[i];
				}
			}
			return result;
		}

		public static UnityEngine.Vector3 ApplySpread(UnityEngine.Vector3 aimDirection, float minSpread, float maxSpread, float spreadYawScale, float spreadPitchScale, float bonusYaw = 0f, float bonusPitch = 0f)
		{
			UnityEngine.Vector3 up = UnityEngine.Vector3.up;
			UnityEngine.Vector3 axis = UnityEngine.Vector3.Cross(up, aimDirection);
			float x = UnityEngine.Random.Range(minSpread, maxSpread);
			float z = UnityEngine.Random.Range(0f, 360f);
			UnityEngine.Vector3 vector = UnityEngine.Quaternion.Euler(0f, 0f, z) * (UnityEngine.Quaternion.Euler(x, 0f, 0f) * UnityEngine.Vector3.forward);
			float y = vector.y;
			vector.y = 0f;
			float angle = (Mathf.Atan2(vector.z, vector.x) * 57.29578f - 90f + bonusYaw) * spreadYawScale;
			float angle2 = (Mathf.Atan2(y, vector.magnitude) * 57.29578f + bonusPitch) * spreadPitchScale;
			return UnityEngine.Quaternion.AngleAxis(angle, up) * (UnityEngine.Quaternion.AngleAxis(angle2, axis) * aimDirection);
		}

		public static string GenerateColoredString(string str, Color32 color)
		{
			return string.Format(CultureInfo.InvariantCulture, "<color=#{0:X2}{1:X2}{2:X2}>{3}</color>", color.r, color.g, color.b, str);
		}

		public static bool GuessRenderBounds(GameObject gameObject, out Bounds bounds)
		{
			Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>();
			if (componentsInChildren.Length != 0)
			{
				bounds = componentsInChildren[0].bounds;
				for (int i = 1; i < componentsInChildren.Length; i++)
				{
					bounds.Encapsulate(componentsInChildren[i].bounds);
				}
				return true;
			}
			bounds = new Bounds(gameObject.transform.position, UnityEngine.Vector3.zero);
			return false;
		}

		public static bool GuessRenderBoundsMeshOnly(GameObject gameObject, out Bounds bounds)
		{
			Renderer[] array = (from renderer in gameObject.GetComponentsInChildren<Renderer>()
				where renderer is MeshRenderer || renderer is SkinnedMeshRenderer
				select renderer).ToArray();
			if (array.Length != 0)
			{
				bounds = array[0].bounds;
				for (int i = 1; i < array.Length; i++)
				{
					bounds.Encapsulate(array[i].bounds);
				}
				return true;
			}
			bounds = new Bounds(gameObject.transform.position, UnityEngine.Vector3.zero);
			return false;
		}

		public static GameObject FindNetworkObject(NetworkInstanceId networkInstanceId)
		{
			if (NetworkServer.active)
			{
				return NetworkServer.FindLocalObject(networkInstanceId);
			}
			return ClientScene.FindLocalObject(networkInstanceId);
		}

		public static string GetGameObjectHierarchyName(GameObject gameObject)
		{
			int num = 0;
			Transform transform = gameObject.transform;
			while ((bool)transform)
			{
				num++;
				transform = transform.parent;
			}
			string[] array = new string[num];
			Transform transform2 = gameObject.transform;
			while ((bool)transform2)
			{
				array[--num] = transform2.gameObject.name;
				transform2 = transform2.parent;
			}
			return string.Join("/", array);
		}

		public static string GetBestBodyName(GameObject bodyObject)
		{
			CharacterBody characterBody = null;
			string text = "???";
			if ((bool)bodyObject)
			{
				characterBody = bodyObject.GetComponent<CharacterBody>();
				if ((bool)characterBody)
				{
					text = characterBody.GetUserName();
				}
				else
				{
					IDisplayNameProvider component = bodyObject.GetComponent<IDisplayNameProvider>();
					if (component != null)
					{
						text = component.GetDisplayName();
					}
				}
			}
			string text2 = text;
			if ((bool)characterBody)
			{
				if (characterBody.isElite)
				{
					BuffIndex[] eliteBuffIndices = BuffCatalog.eliteBuffIndices;
					foreach (BuffIndex buffIndex in eliteBuffIndices)
					{
						if (characterBody.HasBuff(buffIndex))
						{
							text2 = Language.GetStringFormatted(BuffCatalog.GetBuffDef(buffIndex).eliteDef.modifierToken, text2);
						}
					}
				}
				if ((bool)characterBody.inventory)
				{
					if (characterBody.inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0)
					{
						text2 = Language.GetStringFormatted("BODY_MODIFIER_DOPPELGANGER", text2);
					}
					if (characterBody.inventory.GetItemCount(DLC1Content.Items.GummyCloneIdentifier) > 0)
					{
						text2 = Language.GetStringFormatted("BODY_MODIFIER_GUMMYCLONE", text2);
					}
				}
			}
			return text2;
		}

		public static string GetBestBodyNameColored(GameObject bodyObject)
		{
			if ((bool)bodyObject)
			{
				CharacterBody component = bodyObject.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					CharacterMaster master = component.master;
					if ((bool)master)
					{
						PlayerCharacterMasterController component2 = master.GetComponent<PlayerCharacterMasterController>();
						if ((bool)component2)
						{
							GameObject networkUserObject = component2.networkUserObject;
							if ((bool)networkUserObject)
							{
								NetworkUser component3 = networkUserObject.GetComponent<NetworkUser>();
								if ((bool)component3)
								{
									return GenerateColoredString(component3.userName, component3.userColor);
								}
							}
						}
					}
				}
				IDisplayNameProvider component4 = bodyObject.GetComponent<IDisplayNameProvider>();
				if (component4 != null)
				{
					return component4.GetDisplayName();
				}
			}
			return "???";
		}

		public static string GetBestMasterName(CharacterMaster characterMaster)
		{
			if ((bool)characterMaster)
			{
				string text = characterMaster.playerCharacterMasterController?.networkUser?.userName;
				if (text == null)
				{
					string text2 = characterMaster.bodyPrefab?.GetComponent<CharacterBody>().baseNameToken;
					if (text2 != null)
					{
						text = Language.GetString(text2);
					}
				}
				return text;
			}
			return "Null Master";
		}

		public static NetworkUser LookUpBodyNetworkUser(GameObject bodyObject)
		{
			if ((bool)bodyObject)
			{
				return LookUpBodyNetworkUser(bodyObject.GetComponent<CharacterBody>());
			}
			return null;
		}

		public static NetworkUser LookUpBodyNetworkUser(CharacterBody characterBody)
		{
			if ((bool)characterBody)
			{
				CharacterMaster master = characterBody.master;
				if ((bool)master)
				{
					PlayerCharacterMasterController component = master.GetComponent<PlayerCharacterMasterController>();
					if ((bool)component)
					{
						GameObject networkUserObject = component.networkUserObject;
						if ((bool)networkUserObject)
						{
							NetworkUser component2 = networkUserObject.GetComponent<NetworkUser>();
							if ((bool)component2)
							{
								return component2;
							}
						}
					}
				}
			}
			return null;
		}

		private static bool HandleCharacterPhysicsCastResults(GameObject bodyObject, Ray ray, int numHits, RaycastHit[] hits, out RaycastHit hitInfo)
		{
			int num = -1;
			float num2 = float.PositiveInfinity;
			for (int i = 0; i < numHits; i++)
			{
				if (bodyObject == hits[i].collider.gameObject)
				{
					continue;
				}
				float distance = hits[i].distance;
				if (!(distance < num2))
				{
					continue;
				}
				HurtBox component = hits[i].collider.GetComponent<HurtBox>();
				if ((bool)component)
				{
					HealthComponent healthComponent = component.healthComponent;
					if ((bool)healthComponent && healthComponent.gameObject == bodyObject)
					{
						continue;
					}
				}
				if (distance == 0f)
				{
					hitInfo = hits[i];
					hitInfo.point = ray.origin;
					return true;
				}
				num = i;
				num2 = distance;
			}
			if (num == -1)
			{
				hitInfo = default(RaycastHit);
				return false;
			}
			hitInfo = hits[num];
			return true;
		}

		public static bool CharacterRaycast(GameObject bodyObject, Ray ray, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask, QueryTriggerInteraction queryTriggerInteraction)
		{
			int num = 0;
			num = HGPhysics.RaycastAll(out var hits, ray.origin, ray.direction, maxDistance, layerMask, queryTriggerInteraction);
			bool result = HandleCharacterPhysicsCastResults(bodyObject, ray, num, hits, out hitInfo);
			HGPhysics.ReturnResults(hits);
			return result;
		}

		public static bool CharacterSpherecast(GameObject bodyObject, Ray ray, float radius, out RaycastHit hitInfo, float maxDistance, LayerMask layerMask, QueryTriggerInteraction queryTriggerInteraction)
		{
			RaycastHit[] hits;
			int numHits = HGPhysics.SphereCastAll(out hits, ray.origin, radius, ray.direction, maxDistance, layerMask, queryTriggerInteraction);
			bool result = HandleCharacterPhysicsCastResults(bodyObject, ray, numHits, hits, out hitInfo);
			HGPhysics.ReturnResults(hits);
			return result;
		}

		public static bool ConnectionIsLocal([NotNull] NetworkConnection conn)
		{
			if (conn is SteamNetworkConnection)
			{
				return false;
			}
			if (conn is EOSNetworkConnection)
			{
				return false;
			}
			return conn.GetType() != typeof(NetworkConnection);
		}

		public static string EscapeRichTextForTextMeshPro(string rtString)
		{
			string text = rtString;
			text = text.Replace("<", "</noparse><noparse><</noparse><noparse>");
			return "<noparse>" + text + "</noparse>";
		}

		public static string EscapeQuotes(string str)
		{
			str = backlashSearch.Replace(str, strBackslashBackslash);
			str = quoteSearch.Replace(str, strBackslashQuote);
			return str;
		}

		public static string RGBToHex(Color32 rgb)
		{
			return string.Format(CultureInfo.InvariantCulture, "{0:X2}{1:X2}{2:X2}", rgb.r, rgb.g, rgb.b);
		}

		public static UnityEngine.Vector2 Vector3XZToVector2XY(UnityEngine.Vector3 vector3)
		{
			return new UnityEngine.Vector2(vector3.x, vector3.z);
		}

		public static UnityEngine.Vector2 Vector3XZToVector2XY(ref UnityEngine.Vector3 vector3)
		{
			return new UnityEngine.Vector2(vector3.x, vector3.z);
		}

		public static void Vector3XZToVector2XY(UnityEngine.Vector3 vector3, out UnityEngine.Vector2 vector2)
		{
			vector2.x = vector3.x;
			vector2.y = vector3.z;
		}

		public static void Vector3XZToVector2XY(ref UnityEngine.Vector3 vector3, out UnityEngine.Vector2 vector2)
		{
			vector2.x = vector3.x;
			vector2.y = vector3.z;
		}

		public static UnityEngine.Vector2 RotateVector2(UnityEngine.Vector2 vector2, float degrees)
		{
			float num = Mathf.Sin(degrees * (MathF.PI / 180f));
			float num2 = Mathf.Cos(degrees * (MathF.PI / 180f));
			return new UnityEngine.Vector2(num2 * vector2.x - num * vector2.y, num * vector2.x + num2 * vector2.y);
		}

		public static UnityEngine.Quaternion SmoothDampQuaternion(UnityEngine.Quaternion current, UnityEngine.Quaternion target, ref float currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
		{
			float target2 = UnityEngine.Quaternion.Angle(current, target);
			target2 = Mathf.SmoothDamp(0f, target2, ref currentVelocity, smoothTime, maxSpeed, deltaTime);
			return UnityEngine.Quaternion.RotateTowards(current, target, target2);
		}

		public static UnityEngine.Quaternion SmoothDampQuaternion(UnityEngine.Quaternion current, UnityEngine.Quaternion target, ref float currentVelocity, float smoothTime)
		{
			float target2 = UnityEngine.Quaternion.Angle(current, target);
			target2 = Mathf.SmoothDamp(0f, target2, ref currentVelocity, smoothTime);
			return UnityEngine.Quaternion.RotateTowards(current, target, target2);
		}

		public static HurtBox FindBodyMainHurtBox(CharacterBody characterBody)
		{
			return characterBody.mainHurtBox;
		}

		public static HurtBox FindBodyMainHurtBox(GameObject bodyObject)
		{
			CharacterBody component = bodyObject.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				return FindBodyMainHurtBox(component);
			}
			return null;
		}

		public static UnityEngine.Vector3 GetCorePosition(CharacterBody characterBody)
		{
			return characterBody.corePosition;
		}

		public static UnityEngine.Vector3 GetCorePosition(GameObject bodyObject)
		{
			CharacterBody component = bodyObject.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				return GetCorePosition(component);
			}
			return bodyObject.transform.position;
		}

		public static Transform GetCoreTransform(GameObject bodyObject)
		{
			CharacterBody component = bodyObject.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				return component.coreTransform;
			}
			return bodyObject.transform;
		}

		public static float SphereRadiusToVolume(float radius)
		{
			return 4.1887903f * (radius * radius * radius);
		}

		public static float SphereVolumeToRadius(float volume)
		{
			return Mathf.Pow(3f * volume / (MathF.PI * 4f), 1f / 3f);
		}

		public static void CopyList<T>(List<T> src, List<T> dest)
		{
			dest.Clear();
			foreach (T item in src)
			{
				dest.Add(item);
			}
		}

		public static float ScanCharacterAnimationClipForMomentOfRootMotionStop(GameObject characterPrefab, string clipName, string rootBoneNameInChildLocator)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(characterPrefab);
			Transform modelTransform = gameObject.GetComponent<ModelLocator>().modelTransform;
			Transform transform = modelTransform.GetComponent<ChildLocator>().FindChild(rootBoneNameInChildLocator);
			AnimationClip animationClip = modelTransform.GetComponent<Animator>().runtimeAnimatorController.animationClips.FirstOrDefault((AnimationClip c) => c.name == clipName);
			float result = 1f;
			animationClip.SampleAnimation(gameObject, 0f);
			UnityEngine.Vector3 vector = transform.position;
			for (float num = 0.1f; num < 1f; num += 0.1f)
			{
				animationClip.SampleAnimation(gameObject, num);
				UnityEngine.Vector3 position = transform.position;
				if ((position - vector).magnitude == 0f)
				{
					result = num;
					break;
				}
				vector = position;
			}
			UnityEngine.Object.Destroy(gameObject);
			return result;
		}

		public static void DebugCross(UnityEngine.Vector3 position, float radius, UnityEngine.Color color, float duration)
		{
			UnityEngine.Debug.DrawLine(position - UnityEngine.Vector3.right * radius, position + UnityEngine.Vector3.right * radius, color, duration);
			UnityEngine.Debug.DrawLine(position - UnityEngine.Vector3.up * radius, position + UnityEngine.Vector3.up * radius, color, duration);
			UnityEngine.Debug.DrawLine(position - UnityEngine.Vector3.forward * radius, position + UnityEngine.Vector3.forward * radius, color, duration);
		}

		public static void DebugBounds(Bounds bounds, UnityEngine.Color color, float duration)
		{
			UnityEngine.Vector3 min = bounds.min;
			UnityEngine.Vector3 max = bounds.max;
			UnityEngine.Vector3 start = new UnityEngine.Vector3(min.x, min.y, min.z);
			UnityEngine.Vector3 vector = new UnityEngine.Vector3(min.x, min.y, max.z);
			UnityEngine.Vector3 vector2 = new UnityEngine.Vector3(min.x, max.y, min.z);
			UnityEngine.Vector3 end = new UnityEngine.Vector3(min.x, max.y, max.z);
			UnityEngine.Vector3 vector3 = new UnityEngine.Vector3(max.x, min.y, min.z);
			UnityEngine.Vector3 vector4 = new UnityEngine.Vector3(max.x, min.y, max.z);
			UnityEngine.Vector3 end2 = new UnityEngine.Vector3(max.x, max.y, min.z);
			UnityEngine.Vector3 start2 = new UnityEngine.Vector3(max.x, max.y, max.z);
			UnityEngine.Debug.DrawLine(start, vector, color, duration);
			UnityEngine.Debug.DrawLine(start, vector3, color, duration);
			UnityEngine.Debug.DrawLine(start, vector2, color, duration);
			UnityEngine.Debug.DrawLine(vector2, end, color, duration);
			UnityEngine.Debug.DrawLine(vector2, end2, color, duration);
			UnityEngine.Debug.DrawLine(start2, end, color, duration);
			UnityEngine.Debug.DrawLine(start2, end2, color, duration);
			UnityEngine.Debug.DrawLine(start2, vector4, color, duration);
			UnityEngine.Debug.DrawLine(vector4, vector3, color, duration);
			UnityEngine.Debug.DrawLine(vector4, vector, color, duration);
			UnityEngine.Debug.DrawLine(vector, end, color, duration);
			UnityEngine.Debug.DrawLine(vector3, end2, color, duration);
		}

		public static bool PositionIsValid(UnityEngine.Vector3 value)
		{
			float f = value.x + value.y + value.z;
			if (!float.IsInfinity(f))
			{
				return !float.IsNaN(f);
			}
			return false;
		}

		public static void Swap<T>(ref T a, ref T b)
		{
			T val = a;
			a = b;
			b = val;
		}

		public static DateTime UnixTimeStampToDateTimeUtc(uint unixTimeStamp)
		{
			DateTime dateTime = dateZero;
			return dateTime.AddSeconds(unixTimeStamp).ToUniversalTime();
		}

		public static double GetCurrentUnixEpochTimeInSeconds()
		{
			return Client.Instance.Utils.GetServerRealTime();
		}

		public static bool IsValid(UnityEngine.Object o)
		{
			return o;
		}

		[Conditional("VERIFY_COMPONENTS")]
		public static void VerifyComponent<T>(T a, T b) where T : Component
		{
			if (a != b)
			{
				if (logVerify)
				{
					UnityEngine.Debug.LogErrorFormat("Components are not the same!  {0} != {1}", (a != null) ? a.ToString() : "null", (b != null) ? b.ToString() : "null");
				}
				if (breakInVerify)
				{
					UnityEngine.Debug.DebugBreak();
				}
			}
		}

		[Conditional("VERIFY_COMPONENTS")]
		public static void VerifyNullComponent(Component a)
		{
			if (a != null)
			{
				if (logVerify)
				{
					UnityEngine.Debug.LogErrorFormat("Components is not null!  {0} != null", a.ToString());
				}
				if (breakInVerify)
				{
					UnityEngine.Debug.DebugBreak();
				}
			}
		}

		[Conditional("VERIFY_COMPONENTS")]
		public static void VerifyNonNullComponent<T>(T a, string desc) where T : Component
		{
			if (a == null)
			{
				if (logVerify)
				{
					UnityEngine.Debug.LogErrorFormat("Component is null!  {0}: {1}", typeof(T).ToString(), string.IsNullOrEmpty(desc) ? "" : desc);
				}
				if (breakInVerify)
				{
					UnityEngine.Debug.DebugBreak();
				}
			}
		}

		[Conditional("VERIFY_COMPONENTS")]
		public static void VerifyComponent<T>(T a, GameObject b) where T : Component
		{
			_ = b != null;
		}

		[Conditional("VERIFY_COMPONENTS")]
		public static void VerifyComponent<T, X>(T a, X b) where T : Component where X : Component
		{
			_ = b != null;
		}

		[Conditional("VERIFY_COMPONENTS")]
		public static void VerifyObject(GameObject a, GameObject b)
		{
			if (a != b)
			{
				if (logVerify)
				{
					UnityEngine.Debug.LogErrorFormat("Objects are not the same!  {0} != {1}", a.ToString(), b.ToString());
				}
				if (breakInVerify)
				{
					UnityEngine.Debug.DebugBreak();
				}
			}
		}

		[Conditional("VERIFY_COMPONENTS")]
		public static void VerifyTeam(TeamIndex a, Component b)
		{
			if (a != TeamComponent.GetObjectTeam(b.gameObject))
			{
				if (logVerify)
				{
					UnityEngine.Debug.LogErrorFormat("Objects are not the same!  {0} != {1}", a.ToString(), b.ToString());
				}
				if (breakInVerify)
				{
					UnityEngine.Debug.DebugBreak();
				}
			}
		}

		public static string BuildPrefabTransformPath(Transform root, Transform transform, bool appendCloneSuffix = false, bool includeRoot = false)
		{
			if (!root)
			{
				throw new ArgumentException("Value provided as 'root' is an invalid object.", "root");
			}
			if (!transform)
			{
				throw new ArgumentException("Value provided as 'transform' is an invalid object.", "transform");
			}
			try
			{
				Transform transform2 = transform;
				while ((object)transform2 != root)
				{
					if (!transform2)
					{
						string arg = TakeResult();
						throw new ArgumentException($"\"{arg}\" is not a child of \"{root}\".");
					}
					if (sharedStringStack.Count > 0)
					{
						sharedStringStack.Push("/");
					}
					sharedStringStack.Push(transform2.gameObject.name);
					transform2 = transform2.parent;
				}
				if (includeRoot)
				{
					if (sharedStringStack.Count > 0)
					{
						sharedStringStack.Push("/");
					}
					sharedStringStack.Push(root.gameObject.name);
				}
				return TakeResult();
			}
			finally
			{
				sharedStringBuilder.Clear();
				sharedStringStack.Clear();
			}
			string TakeResult()
			{
				while (sharedStringStack.Count > 0)
				{
					sharedStringBuilder.Append(sharedStringStack.Pop());
				}
				if (appendCloneSuffix)
				{
					sharedStringBuilder.Append(cloneString);
				}
				return sharedStringBuilder.Take();
			}
		}

		public static int GetItemCountForTeam(TeamIndex teamIndex, ItemIndex itemIndex, bool requiresAlive, bool requiresConnected = true)
		{
			int num = 0;
			ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
			int i = 0;
			for (int count = readOnlyInstancesList.Count; i < count; i++)
			{
				CharacterMaster characterMaster = readOnlyInstancesList[i];
				if (characterMaster.teamIndex == teamIndex && (!requiresAlive || characterMaster.hasBody) && (!requiresConnected || !characterMaster.playerCharacterMasterController || characterMaster.playerCharacterMasterController.isConnected))
				{
					num += characterMaster.inventory.GetItemCount(itemIndex);
				}
			}
			return num;
		}

		public static int GetItemCountGlobal(ItemIndex itemIndex, bool requiresAlive, bool requiresConnected = true)
		{
			int num = 0;
			ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
			int i = 0;
			for (int count = readOnlyInstancesList.Count; i < count; i++)
			{
				CharacterMaster characterMaster = readOnlyInstancesList[i];
				if ((!requiresAlive || characterMaster.hasBody) && (!requiresConnected || !characterMaster.playerCharacterMasterController || characterMaster.playerCharacterMasterController.isConnected))
				{
					num += characterMaster.inventory.GetItemCount(itemIndex);
				}
			}
			return num;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void NullifyIfInvalid<T>(ref T objRef) where T : UnityEngine.Object
		{
			if ((object)objRef != null && !objRef)
			{
				objRef = null;
			}
		}

		public static bool IsPrefab(GameObject gameObject)
		{
			if ((bool)gameObject)
			{
				return !gameObject.scene.IsValid();
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static uint IntToUintPlusOne(int value)
		{
			return (uint)(value + 1);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int UintToIntMinusOne(uint value)
		{
			return (int)(value - 1);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static ulong LongToUlongPlusOne(long value)
		{
			return (ulong)(value + 1);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static long UlongToLongMinusOne(ulong value)
		{
			return (long)(value - 1);
		}

		public static float GetExpAdjustedDropChancePercent(float baseChancePercent, GameObject characterBodyObject)
		{
			int num = 0;
			DeathRewards component = characterBodyObject.GetComponent<DeathRewards>();
			if ((bool)component)
			{
				num = component.spawnValue;
			}
			return baseChancePercent * Mathf.Log((float)num + 1f, 2f);
		}

		public static bool IsDontDestroyOnLoad(GameObject go)
		{
			return go.scene.name == "DontDestroyOnLoad";
		}
	}
	public class Utility_BreakOnDestroy : MonoBehaviour
	{
		private void OnDisable()
		{
			_ = base.gameObject.activeInHierarchy;
		}

		private void OnDestroy()
		{
		}
	}
	public class VFXHelper : IDisposable
	{
		private class VFXTransformController : MonoBehaviour
		{
			public Transform followedTransform;

			public bool usePosition;

			public bool useRotation;

			public bool useScale;

			protected new Transform transform { get; private set; }

			private void Awake()
			{
				transform = base.transform;
			}

			private void LateUpdate()
			{
				if ((bool)followedTransform)
				{
					if (usePosition)
					{
						transform.position = followedTransform.position;
					}
					if (useRotation)
					{
						transform.rotation = followedTransform.rotation;
					}
					if (useScale)
					{
						transform.localScale = followedTransform.lossyScale;
					}
				}
			}
		}

		private static readonly Stack<VFXHelper> pool = new Stack<VFXHelper>();

		private GameObject _vfxPrefabReference;

		private object _vfxPrefabAddress;

		public Transform followedTransform;

		public bool useFollowedTransformPosition = true;

		public bool useFollowedTransformRotation = true;

		public bool useFollowedTransformScale = true;

		public GameObject vfxPrefabReference
		{
			get
			{
				return _vfxPrefabReference;
			}
			set
			{
				_vfxPrefabReference = value;
				_vfxPrefabAddress = null;
			}
		}

		public object vfxPrefabAddress
		{
			get
			{
				return _vfxPrefabAddress;
			}
			set
			{
				_vfxPrefabReference = null;
				_vfxPrefabAddress = null;
			}
		}

		public GameObject vfxInstance { get; private set; }

		public Transform vfxInstanceTransform { get; private set; }

		private VFXTransformController vfxInstanceTransformController { get; set; }

		public bool enabled
		{
			get
			{
				return vfxInstance;
			}
			set
			{
				if ((bool)vfxInstance == value)
				{
					return;
				}
				if (value)
				{
					vfxInstance = null;
					vfxInstanceTransform = null;
					UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
					UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.identity;
					UnityEngine.Vector3 vector2 = UnityEngine.Vector3.one;
					if ((bool)followedTransform)
					{
						vector = (useFollowedTransformPosition ? followedTransform.position : vector);
						quaternion = (useFollowedTransformRotation ? followedTransform.rotation : quaternion);
						vector2 = (useFollowedTransformScale ? followedTransform.lossyScale : vector2);
					}
					if (vfxPrefabAddress != null)
					{
						vfxInstance = Addressables.InstantiateAsync(instantiateParameters: new InstantiationParameters(vector, quaternion, null), key: vfxPrefabAddress).WaitForCompletion();
					}
					else if ((bool)vfxPrefabReference)
					{
						vfxInstance = UnityEngine.Object.Instantiate(vfxPrefabReference, vector, quaternion);
					}
					if ((bool)vfxInstance)
					{
						vfxInstanceTransform = vfxInstance.transform;
						vfxInstanceTransform.localScale = vector2;
						vfxInstanceTransformController = vfxInstance.AddComponent<VFXTransformController>();
						vfxInstanceTransformController.usePosition = useFollowedTransformPosition;
						vfxInstanceTransformController.useRotation = useFollowedTransformRotation;
						vfxInstanceTransformController.useScale = useFollowedTransformScale;
					}
				}
				else
				{
					VfxKillBehavior.KillVfxObject(vfxInstance);
					vfxInstance = null;
					vfxInstanceTransform = null;
					vfxInstanceTransformController = null;
				}
			}
		}

		private VFXHelper()
		{
		}

		public static VFXHelper Rent()
		{
			if (pool.Count <= 0)
			{
				return new VFXHelper();
			}
			return pool.Pop();
		}

		public static VFXHelper Return(VFXHelper instance)
		{
			instance.Dispose();
			pool.Push(instance);
			return null;
		}

		public void Dispose()
		{
			enabled = false;
			vfxPrefabAddress = null;
			vfxPrefabReference = null;
			followedTransform = null;
			useFollowedTransformPosition = true;
			useFollowedTransformRotation = true;
			useFollowedTransformScale = true;
		}
	}
	public static class ViewablesCatalog
	{
		public class Node
		{
			public readonly string name;

			public readonly bool isFolder;

			private readonly List<Node> _children = new List<Node>();

			public ReadOnlyCollection<Node> children;

			private string _fullName;

			private bool fullNameDirty = true;

			public Func<UserProfile, bool> shouldShowUnviewed;

			public Node parent { get; private set; }

			public string fullName
			{
				get
				{
					if (fullNameDirty)
					{
						GenerateFullName();
					}
					return _fullName;
				}
			}

			public Node(string name, bool isFolder, Node parent = null)
			{
				this.name = name;
				this.isFolder = isFolder;
				shouldShowUnviewed = DefaultShouldShowUnviewedTest;
				children = _children.AsReadOnly();
				SetParent(parent);
			}

			public void SetParent(Node newParent)
			{
				if (parent != newParent)
				{
					parent?._children.Remove(this);
					parent = newParent;
					parent?._children.Add(this);
					fullNameDirty = true;
				}
			}

			private void GenerateFullName()
			{
				string text = name;
				if (parent != null)
				{
					text = parent.fullName + text;
				}
				if (isFolder)
				{
					text += "/";
				}
				_fullName = text;
				fullNameDirty = false;
			}

			public bool DefaultShouldShowUnviewedTest(UserProfile userProfile)
			{
				if (!isFolder && userProfile.HasViewedViewable(fullName))
				{
					return false;
				}
				foreach (Node child in children)
				{
					if (child.shouldShowUnviewed(userProfile))
					{
						return true;
					}
				}
				return false;
			}

			public IEnumerable<Node> Descendants()
			{
				yield return this;
				foreach (Node child in _children)
				{
					foreach (Node item in child.Descendants())
					{
						yield return item;
					}
				}
			}
		}

		private static readonly Node rootNode = new Node("", isFolder: true);

		private static readonly Dictionary<string, Node> fullNameToNodeMap = new Dictionary<string, Node>();

		public static void AddNodeToRoot(Node node)
		{
			node.SetParent(rootNode);
			foreach (Node item in node.Descendants())
			{
				if (fullNameToNodeMap.ContainsKey(item.fullName))
				{
					UnityEngine.Debug.LogFormat("Tried to add duplicate node {0}", item.fullName);
				}
				else
				{
					fullNameToNodeMap.Add(item.fullName, item);
				}
			}
		}

		public static Node FindNode(string fullName)
		{
			if (fullNameToNodeMap.TryGetValue(fullName, out var value))
			{
				return value;
			}
			return null;
		}

		[ConCommand(commandName = "viewables_list", flags = ConVarFlags.None, helpText = "Displays the full names of all viewables.")]
		private static void CCViewablesList(ConCommandArgs args)
		{
		}

		[ConCommand(commandName = "viewables_list_unviewed", flags = ConVarFlags.None, helpText = "Displays the full names of all unviewed viewables.")]
		private static void CCViewablesListUnviewed(ConCommandArgs args)
		{
			_ = args.GetSenderLocalUser().userProfile;
		}

		[ConCommand(commandName = "viewables_clear_viewed", flags = ConVarFlags.None, helpText = "Clears all viewed viewables")]
		private static void CCViewablesClearViewed(ConCommandArgs args)
		{
			args.GetSenderLocalUser().userProfile.ClearAllViewablesAsViewed();
		}
	}
	public enum VisibilityLevel
	{
		Invisible,
		Cloaked,
		Revealed,
		Visible
	}
	public static class WindowsConVars
	{
		private class TimerResolutionConVar : BaseConVar
		{
			private static TimerResolutionConVar instance = new TimerResolutionConVar("timer_resolution", ConVarFlags.Engine, null, "The Windows timer resolution.");

			private TimerResolutionConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				NtSetTimerResolution(BaseConVar.ParseIntInvariant(newValue), setResolution: true, out var currentResolution);
				UnityEngine.Debug.LogFormat("{0} set to {1}", name, currentResolution);
			}

			public override string GetString()
			{
				NtQueryTimerResolution(out var _, out var _, out var currentResolution);
				return TextSerialization.ToStringInvariant(currentResolution);
			}
		}

		[DllImport("ntdll.dll", SetLastError = true)]
		private static extern int NtSetTimerResolution(int desiredResolution, bool setResolution, out int currentResolution);

		[DllImport("ntdll.dll", SetLastError = true)]
		private static extern int NtQueryTimerResolution(out int minimumResolution, out int maximumResolution, out int currentResolution);
	}
	public class WireMeshBuilder : IDisposable
	{
		private struct LineVertex
		{
			public UnityEngine.Vector3 position;

			public UnityEngine.Color color;
		}

		private int uniqueVertexCount;

		private Dictionary<LineVertex, int> uniqueVertexToIndex = new Dictionary<LineVertex, int>();

		private List<int> indices = new List<int>();

		private List<UnityEngine.Vector3> positions = new List<UnityEngine.Vector3>();

		private List<UnityEngine.Color> colors = new List<UnityEngine.Color>();

		private int GetVertexIndex(LineVertex vertex)
		{
			if (!uniqueVertexToIndex.TryGetValue(vertex, out var value))
			{
				value = uniqueVertexCount++;
				positions.Add(vertex.position);
				colors.Add(vertex.color);
				uniqueVertexToIndex.Add(vertex, value);
			}
			return value;
		}

		public void Clear()
		{
			uniqueVertexToIndex.Clear();
			indices.Clear();
			positions.Clear();
			colors.Clear();
			uniqueVertexCount = 0;
		}

		public void AddLine(UnityEngine.Vector3 p1, UnityEngine.Color c1, UnityEngine.Vector3 p2, UnityEngine.Color c2)
		{
			LineVertex lineVertex = default(LineVertex);
			lineVertex.position = p1;
			lineVertex.color = c1;
			LineVertex vertex = lineVertex;
			lineVertex = default(LineVertex);
			lineVertex.position = p2;
			lineVertex.color = c2;
			LineVertex vertex2 = lineVertex;
			int vertexIndex = GetVertexIndex(vertex);
			int vertexIndex2 = GetVertexIndex(vertex2);
			indices.Add(vertexIndex);
			indices.Add(vertexIndex2);
		}

		public Mesh GenerateMesh()
		{
			Mesh mesh = new Mesh();
			GenerateMesh(mesh);
			return mesh;
		}

		public void GenerateMesh(Mesh dest)
		{
			dest.SetTriangles(Array.Empty<int>(), 0);
			dest.SetVertices(positions);
			dest.SetColors(colors);
			dest.SetIndices(indices.ToArray(), MeshTopology.Lines, 0);
		}

		public void Dispose()
		{
			uniqueVertexToIndex = null;
			indices = null;
			positions = null;
			colors = null;
		}
	}
	public static class WwiseIntegrationManager
	{
		private static GameObject wwiseGlobalObjectInstance;

		private static GameObject wwiseAudioObjectInstance;

		public static bool noAudio => false;

		public static void Init()
		{
			if (noAudio)
			{
				return;
			}
			if ((bool)UnityEngine.Object.FindObjectOfType<AkInitializer>())
			{
				UnityEngine.Debug.LogError("Attempting to initialize wwise when AkInitializer already exists! This will cause a crash!");
				return;
			}
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/WwiseGlobal", delegate(GameObject x)
			{
				wwiseGlobalObjectInstance = UnityEngine.Object.Instantiate(x);
			});
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/AudioManager", delegate(GameObject x)
			{
				wwiseAudioObjectInstance = UnityEngine.Object.Instantiate(x);
			});
		}
	}
}
namespace RoR2.WwiseUtils
{
	public static class CommonWwiseIds
	{
		public static uint none;

		public static uint alive;

		public static uint bossfight;

		public static uint dead;

		public static uint gameplay;

		public static uint menu;

		public static uint main;

		public static uint logbook;

		public static uint secretLevel;

		[InitDuringStartup]
		public static void Init()
		{
			Assign(ref none, "None");
			Assign(ref alive, "alive");
			Assign(ref dead, "dead");
			Assign(ref bossfight, "Bossfight");
			Assign(ref gameplay, "Gameplay");
			Assign(ref menu, "Menu");
			Assign(ref main, "Main");
			Assign(ref logbook, "Logbook");
			Assign(ref secretLevel, "SecretLevel");
			static void Assign(ref uint field, string name)
			{
				field = AkSoundEngine.GetIDFromString(name);
			}
		}
	}
	public class RtpcSetBehavior : MonoBehaviour
	{
		[SerializeField]
		private string valueName;

		[SerializeField]
		private float initialValue;

		private RtpcSetter rtpcSetter;

		public float value
		{
			get
			{
				return rtpcSetter.value;
			}
			set
			{
				rtpcSetter.value = value;
				rtpcSetter.FlushIfChanged();
			}
		}

		private void Start()
		{
			rtpcSetter = new RtpcSetter(valueName, base.gameObject);
			rtpcSetter.value = initialValue;
			rtpcSetter.FlushIfChanged();
		}
	}
	public struct RtpcSetter
	{
		private readonly string name;

		private readonly uint id;

		private readonly GameObject gameObject;

		private float expectedEngineValue;

		public float value;

		private bool gameObjectIsNull;

		public RtpcSetter(string name, GameObject gameObject = null)
		{
			this.name = name;
			id = AkSoundEngine.GetIDFromString(name);
			this.gameObject = gameObject;
			gameObjectIsNull = gameObject == null;
			expectedEngineValue = float.NegativeInfinity;
			value = expectedEngineValue;
		}

		public void FlushIfChanged()
		{
			if (!expectedEngineValue.Equals(value))
			{
				expectedEngineValue = value;
				if (gameObjectIsNull)
				{
					AkSoundEngine.SetRTPCValue(id, value, ulong.MaxValue);
				}
				else
				{
					AkSoundEngine.SetRTPCValue(id, value, gameObject);
				}
			}
		}
	}
	public class SoundbankLoader : MonoBehaviour
	{
		public string[] soundbankStrings;

		public bool decodeBank;

		public bool saveDecodedBank;

		private static int pendingLoads;

		public static bool doneLoading => pendingLoads == 0;

		private void Start()
		{
			for (int i = 0; i < soundbankStrings.Length; i++)
			{
				UnityEngine.Debug.LogFormat("Queueing Soundbank for load {0} ", soundbankStrings[i]);
				AkBankManager.LoadBankAsync(soundbankStrings[i], Callback);
				pendingLoads++;
			}
			UnityEngine.Debug.LogFormat("Soundbanks queued, pendingLoads = {0}", pendingLoads);
		}

		private void Callback(uint in_bankID, IntPtr in_InMemoryBankPtr, AKRESULT in_eLoadResult, object in_Cookie)
		{
			pendingLoads--;
			if (in_eLoadResult != AKRESULT.AK_BankAlreadyLoaded)
			{
				UnityEngine.Debug.LogFormat("Soundbank {0} loaded. {1} remaining", in_bankID, pendingLoads);
			}
			else
			{
				UnityEngine.Debug.LogFormat("Duplicate Soundbank loaded. {0} remaining", pendingLoads);
			}
		}
	}
	public struct StateSetter
	{
		private readonly string name;

		private readonly uint id;

		private uint expectedEngineValueId;

		public uint valueId;

		public StateSetter(string name)
		{
			this.name = name;
			id = AkSoundEngine.GetIDFromString(name);
			expectedEngineValueId = 0u;
			valueId = expectedEngineValueId;
		}

		public void FlushIfChanged()
		{
			if (!expectedEngineValueId.Equals(valueId))
			{
				expectedEngineValueId = valueId;
				AkSoundEngine.SetState(id, valueId);
			}
		}
	}
}
namespace RoR2.Stats
{
	[RequireComponent(typeof(PlayerCharacterMasterController))]
	[RequireComponent(typeof(CharacterMaster))]
	public class PlayerStatsComponent : NetworkBehaviour
	{
		public static readonly List<PlayerStatsComponent> instancesList = new List<PlayerStatsComponent>();

		private float serverTransmitTimer;

		private float serverTransmitInterval = 10f;

		private UnityEngine.Vector3 previousBodyPosition;

		private GameObject cachedBodyObject;

		private CharacterBody cachedCharacterBody;

		private CharacterMotor cachedBodyCharacterMotor;

		private Transform cachedBodyTransform;

		public StatSheet currentStats;

		private StatSheet clientDeltaStatsBuffer;

		private StatSheet recordedStats;

		public CharacterMaster characterMaster { get; private set; }

		public PlayerCharacterMasterController playerCharacterMasterController { get; private set; }

		private void Awake()
		{
			playerCharacterMasterController = GetComponent<PlayerCharacterMasterController>();
			characterMaster = GetComponent<CharacterMaster>();
			instancesList.Add(this);
			currentStats = StatSheet.New();
			if (NetworkClient.active)
			{
				recordedStats = StatSheet.New();
				clientDeltaStatsBuffer = StatSheet.New();
			}
		}

		private void OnDestroy()
		{
			if (NetworkServer.active)
			{
				SendUpdateToClient();
			}
			instancesList.Remove(this);
		}

		public static StatSheet FindBodyStatSheet(GameObject bodyObject)
		{
			if (!bodyObject)
			{
				return null;
			}
			return FindBodyStatSheet(bodyObject.GetComponent<CharacterBody>());
		}

		public static StatSheet FindBodyStatSheet(CharacterBody characterBody)
		{
			return characterBody?.master?.GetComponent<PlayerStatsComponent>()?.currentStats;
		}

		public static StatSheet FindMasterStatSheet(CharacterMaster master)
		{
			return FindMasterStatsComponent(master)?.currentStats;
		}

		public static PlayerStatsComponent FindBodyStatsComponent(GameObject bodyObject)
		{
			if (!bodyObject)
			{
				return null;
			}
			return FindBodyStatsComponent(bodyObject.GetComponent<CharacterBody>());
		}

		public static PlayerStatsComponent FindBodyStatsComponent(CharacterBody characterBody)
		{
			return characterBody?.master?.GetComponent<PlayerStatsComponent>();
		}

		public static PlayerStatsComponent FindMasterStatsComponent(CharacterMaster master)
		{
			return master?.playerStatsComponent;
		}

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
		private static void Init()
		{
			GlobalEventManager.onCharacterDeathGlobal += delegate(DamageReport damageReport)
			{
				if (NetworkServer.active)
				{
					PlayerStatsComponent playerStatsComponent = FindBodyStatsComponent(damageReport.victim.gameObject);
					if ((bool)playerStatsComponent)
					{
						playerStatsComponent.serverTransmitTimer = 0f;
					}
				}
			};
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				ServerFixedUpdate();
			}
		}

		[Server]
		public void ForceNextTransmit()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Stats.PlayerStatsComponent::ForceNextTransmit()' called on client");
			}
			else
			{
				serverTransmitTimer = 0f;
			}
		}

		[Server]
		private void ServerFixedUpdate()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Stats.PlayerStatsComponent::ServerFixedUpdate()' called on client");
				return;
			}
			float num = 0f;
			float runTime = 0f;
			if ((bool)Run.instance && !Run.instance.isRunStopwatchPaused)
			{
				num = Time.fixedDeltaTime;
				runTime = Run.instance.GetRunStopwatch();
			}
			StatManager.CharacterUpdateEvent e = default(StatManager.CharacterUpdateEvent);
			e.statsComponent = this;
			e.runTime = runTime;
			GameObject bodyObject = characterMaster.GetBodyObject();
			if (bodyObject != cachedBodyObject)
			{
				cachedBodyObject = bodyObject;
				cachedBodyObject = bodyObject;
				cachedBodyTransform = bodyObject?.transform;
				if ((bool)cachedBodyTransform)
				{
					previousBodyPosition = cachedBodyTransform.position;
				}
				cachedCharacterBody = bodyObject?.GetComponent<CharacterBody>();
				cachedBodyCharacterMotor = bodyObject?.GetComponent<CharacterMotor>();
			}
			if ((bool)cachedBodyTransform)
			{
				UnityEngine.Vector3 position = cachedBodyTransform.position;
				e.additionalDistanceTraveled = UnityEngine.Vector3.Distance(position, previousBodyPosition);
				previousBodyPosition = position;
			}
			if (characterMaster.hasBody)
			{
				e.additionalTimeAlive += num;
			}
			if ((bool)cachedCharacterBody)
			{
				e.level = (int)cachedCharacterBody.level;
			}
			StatManager.PushCharacterUpdateEvent(e);
			serverTransmitTimer -= Time.fixedDeltaTime;
			if (serverTransmitTimer <= 0f)
			{
				serverTransmitTimer = serverTransmitInterval;
				SendUpdateToClient();
			}
		}

		[Server]
		private void SendUpdateToClient()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Stats.PlayerStatsComponent::SendUpdateToClient()' called on client");
				return;
			}
			NetworkUser networkUser = playerCharacterMasterController.networkUser;
			if ((bool)networkUser)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				networkWriter.StartMessage(58);
				networkWriter.Write(base.gameObject);
				currentStats.WriteChanges(networkWriter);
				networkWriter.FinishMessage();
				networkUser.connectionToClient.SendWriter(networkWriter, GetNetworkChannel());
			}
		}

		[NetworkMessageHandler(client = true, msgType = 58)]
		private static void HandleStatsUpdate(NetworkMessage netMsg)
		{
			GameObject gameObject = netMsg.reader.ReadGameObject();
			if ((bool)gameObject)
			{
				PlayerStatsComponent component = gameObject.GetComponent<PlayerStatsComponent>();
				if ((bool)component)
				{
					component.InstanceHandleStatsUpdate(netMsg.reader);
				}
			}
		}

		[Client]
		private void InstanceHandleStatsUpdate(NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.Stats.PlayerStatsComponent::InstanceHandleStatsUpdate(UnityEngine.Networking.NetworkReader)' called on server");
				return;
			}
			if (!NetworkServer.active)
			{
				currentStats.Read(reader);
			}
			FlushStatsToUserProfile();
		}

		[Client]
		private void FlushStatsToUserProfile()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.Stats.PlayerStatsComponent::FlushStatsToUserProfile()' called on server");
				return;
			}
			StatSheet.GetDelta(clientDeltaStatsBuffer, currentStats, recordedStats);
			currentStats.ClearHasChangedFlags();
			StatSheet.Copy(currentStats, recordedStats);
			(playerCharacterMasterController.networkUser?.localUser)?.userProfile?.ApplyDeltaStatSheet(clientDeltaStatsBuffer);
		}

		[ConCommand(commandName = "print_stats", flags = ConVarFlags.None, helpText = "Prints all current stats of the sender.")]
		private static void CCPrintStats(ConCommandArgs args)
		{
			StatSheet statSheet = args.senderMasterObject?.GetComponent<PlayerStatsComponent>()?.currentStats;
			if (statSheet != null)
			{
				string[] array = new string[statSheet.fields.Length];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = $"[\"{statSheet.fields[i].name}\"]={statSheet.fields[i].ToString()}";
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public enum StatDataType
	{
		ULong,
		Double
	}
	public class StatDef
	{
		public delegate string DisplayValueFormatterDelegate(ref StatField statField);

		public static readonly List<StatDef> allStatDefs;

		private static readonly Dictionary<string, StatDef> nameToStatDef;

		public int index;

		public readonly string name;

		public readonly string displayToken;

		public readonly StatRecordType recordType;

		public readonly StatDataType dataType;

		public double pointValue;

		public readonly DisplayValueFormatterDelegate displayValueFormatter;

		public Action onChangeCallback;

		public static readonly StatDef totalGamesPlayed;

		public static readonly StatDef totalTimeAlive;

		public static readonly StatDef totalKills;

		public static readonly StatDef totalMinionKills;

		public static readonly StatDef totalDeaths;

		public static readonly StatDef totalDamageDealt;

		public static readonly StatDef totalMinionDamageDealt;

		public static readonly StatDef totalDamageTaken;

		public static readonly StatDef totalHealthHealed;

		public static readonly StatDef highestDamageDealt;

		public static readonly StatDef highestLevel;

		public static readonly StatDef goldCollected;

		public static readonly StatDef maxGoldCollected;

		public static readonly StatDef totalDistanceTraveled;

		public static readonly StatDef totalItemsCollected;

		public static readonly StatDef highestItemsCollected;

		public static readonly StatDef totalStagesCompleted;

		public static readonly StatDef highestStagesCompleted;

		public static readonly StatDef highestInfiniteTowerWaveReached;

		public static readonly StatDef totalPurchases;

		public static readonly StatDef highestPurchases;

		public static readonly StatDef totalGoldPurchases;

		public static readonly StatDef highestGoldPurchases;

		public static readonly StatDef totalBloodPurchases;

		public static readonly StatDef highestBloodPurchases;

		public static readonly StatDef totalLunarPurchases;

		public static readonly StatDef highestLunarPurchases;

		public static readonly StatDef totalTier1Purchases;

		public static readonly StatDef highestTier1Purchases;

		public static readonly StatDef totalTier2Purchases;

		public static readonly StatDef highestTier2Purchases;

		public static readonly StatDef totalTier3Purchases;

		public static readonly StatDef highestTier3Purchases;

		public static readonly StatDef totalDronesPurchased;

		public static readonly StatDef totalTurretsPurchased;

		public static readonly StatDef totalGreenSoupsPurchased;

		public static readonly StatDef totalRedSoupsPurchased;

		public static readonly StatDef suicideHermitCrabsAchievementProgress;

		public static readonly StatDef firstTeleporterCompleted;

		public static readonly StatDef totalEliteKills;

		public static readonly StatDef totalBurnDeaths;

		public static readonly StatDef totalDeathsWhileBurning;

		public static readonly StatDef totalTeleporterBossKillsWitnessed;

		public static readonly StatDef totalCrocoInfectionsInflicted;

		public static readonly StatDef totalCrocoWeakEnemyKills;

		public static readonly StatDef totalMaulingRockKills;

		public static readonly StatDef chefAlternateSpecialBarbecueBisonAchievementProgress;

		private static string[] bodyNames;

		[CanBeNull]
		public static StatDef Find(string statName)
		{
			nameToStatDef.TryGetValue(statName, out var value);
			return value;
		}

		private StatDef(string name, StatRecordType recordType, StatDataType dataType, double pointValue, DisplayValueFormatterDelegate displayValueFormatter)
		{
			this.name = name;
			this.recordType = recordType;
			this.dataType = dataType;
			this.pointValue = pointValue;
			this.displayValueFormatter = displayValueFormatter;
			displayToken = "STATNAME_" + name.ToUpper(CultureInfo.InvariantCulture);
		}

		static StatDef()
		{
			allStatDefs = new List<StatDef>();
			nameToStatDef = new Dictionary<string, StatDef>();
			totalGamesPlayed = Register("totalGamesPlayed", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalTimeAlive = Register("totalTimeAlive", StatRecordType.Sum, StatDataType.Double, 1.0, TimeMMSSDisplayValueFormatter);
			totalKills = Register("totalKills", StatRecordType.Sum, StatDataType.ULong, 10.0);
			totalMinionKills = Register("totalMinionKills", StatRecordType.Sum, StatDataType.ULong, 10.0);
			totalDeaths = Register("totalDeaths", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalDamageDealt = Register("totalDamageDealt", StatRecordType.Sum, StatDataType.ULong, 0.01);
			totalMinionDamageDealt = Register("totalMinionDamageDealt", StatRecordType.Sum, StatDataType.ULong, 0.01);
			totalDamageTaken = Register("totalDamageTaken", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalHealthHealed = Register("totalHealthHealed", StatRecordType.Sum, StatDataType.ULong, 0.01);
			highestDamageDealt = Register("highestDamageDealt", StatRecordType.Max, StatDataType.ULong, 1.0);
			highestLevel = Register("highestLevel", StatRecordType.Max, StatDataType.ULong, 100.0);
			goldCollected = Register("totalGoldCollected", StatRecordType.Sum, StatDataType.ULong, 1.0);
			maxGoldCollected = Register("maxGoldCollected", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalDistanceTraveled = Register("totalDistanceTraveled", StatRecordType.Sum, StatDataType.Double, 0.01, DistanceMarathonsDisplayValueFormatter);
			totalItemsCollected = Register("totalItemsCollected", StatRecordType.Sum, StatDataType.ULong, 110.0);
			highestItemsCollected = Register("highestItemsCollected", StatRecordType.Max, StatDataType.ULong, 10.0);
			totalStagesCompleted = Register("totalStagesCompleted", StatRecordType.Sum, StatDataType.ULong, 100.0);
			highestStagesCompleted = Register("highestStagesCompleted", StatRecordType.Max, StatDataType.ULong, 0.0);
			highestInfiniteTowerWaveReached = Register("highestInfiniteTowerWaveReached", StatRecordType.Max, StatDataType.ULong, 100.0);
			totalPurchases = Register("totalPurchases", StatRecordType.Sum, StatDataType.ULong, 35.0);
			highestPurchases = Register("highestPurchases", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalGoldPurchases = Register("totalGoldPurchases", StatRecordType.Sum, StatDataType.ULong, 0.0);
			highestGoldPurchases = Register("highestGoldPurchases", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalBloodPurchases = Register("totalBloodPurchases", StatRecordType.Sum, StatDataType.ULong, 0.0);
			highestBloodPurchases = Register("highestBloodPurchases", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalLunarPurchases = Register("totalLunarPurchases", StatRecordType.Sum, StatDataType.ULong, 0.0);
			highestLunarPurchases = Register("highestLunarPurchases", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalTier1Purchases = Register("totalTier1Purchases", StatRecordType.Sum, StatDataType.ULong, 0.0);
			highestTier1Purchases = Register("highestTier1Purchases", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalTier2Purchases = Register("totalTier2Purchases", StatRecordType.Sum, StatDataType.ULong, 0.0);
			highestTier2Purchases = Register("highestTier2Purchases", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalTier3Purchases = Register("totalTier3Purchases", StatRecordType.Sum, StatDataType.ULong, 0.0);
			highestTier3Purchases = Register("highestTier3Purchases", StatRecordType.Max, StatDataType.ULong, 0.0);
			totalDronesPurchased = Register("totalDronesPurchased", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalTurretsPurchased = Register("totalTurretsPurchased", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalGreenSoupsPurchased = Register("totalGreenSoupsPurchased", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalRedSoupsPurchased = Register("totalRedSoupsPurchased", StatRecordType.Sum, StatDataType.ULong, 0.0);
			suicideHermitCrabsAchievementProgress = Register("suicideHermitCrabsAchievementProgress", StatRecordType.Sum, StatDataType.ULong, 0.0);
			firstTeleporterCompleted = Register("firstTeleporterCompleted", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalEliteKills = Register("totalEliteKills", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalBurnDeaths = Register("totalBurnDeaths", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalDeathsWhileBurning = Register("totalDeathsWhileBurning", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalTeleporterBossKillsWitnessed = Register("totalTeleporterBossKillsWitnessed", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalCrocoInfectionsInflicted = Register("totalCrocoInfectionsInflicted", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalCrocoWeakEnemyKills = Register("totalCrocoWeakEnemyKills", StatRecordType.Sum, StatDataType.ULong, 0.0);
			totalMaulingRockKills = Register("totalMaulingRockKills", StatRecordType.Sum, StatDataType.ULong, 0.0);
			chefAlternateSpecialBarbecueBisonAchievementProgress = Register("chefAlternateSpecialBarbecueBisonAchievementProgress", StatRecordType.Sum, StatDataType.ULong, 0.0);
		}

		[SystemInitializer(new Type[]
		{
			typeof(BodyCatalog),
			typeof(ItemCatalog),
			typeof(EquipmentCatalog),
			typeof(SceneCatalog)
		})]
		private static void Init()
		{
			PerBodyStatDef.RegisterStatDefs();
			PerItemStatDef.RegisterStatDefs();
			PerEquipmentStatDef.RegisterStatDefs();
			PerStageStatDef.RegisterStatDefs();
		}

		public static StatDef Register(string name, StatRecordType recordType, StatDataType dataType, double pointValue, DisplayValueFormatterDelegate displayValueFormatter = null)
		{
			if (displayValueFormatter == null)
			{
				displayValueFormatter = DefaultDisplayValueFormatter;
			}
			StatDef statDef = new StatDef(name, recordType, dataType, pointValue, displayValueFormatter)
			{
				index = allStatDefs.Count
			};
			allStatDefs.Add(statDef);
			nameToStatDef.Add(statDef.name, statDef);
			return statDef;
		}

		public static string DefaultDisplayValueFormatter(ref StatField statField)
		{
			return statField.ToLocalNumeric();
		}

		public static string TimeMMSSDisplayValueFormatter(ref StatField statField)
		{
			ulong num = 0uL;
			num = statField.dataType switch
			{
				StatDataType.ULong => statField.GetULongValue(), 
				StatDataType.Double => (ulong)statField.GetDoubleValue(), 
				_ => throw new ArgumentOutOfRangeException(), 
			};
			ulong num2 = num / 60;
			ulong num3 = num - num2 * 60;
			return $"{num2:00}:{num3:00}";
		}

		public static string DistanceMarathonsDisplayValueFormatter(ref StatField statField)
		{
			double num = 0.0;
			return string.Format(arg0: statField.dataType switch
			{
				StatDataType.ULong => statField.GetULongValue(), 
				StatDataType.Double => statField.GetDoubleValue(), 
				_ => throw new ArgumentOutOfRangeException(), 
			} * 2.3699E-05, format: Language.GetString("STAT_VALUE_MARATHONS_FORMAT"));
		}
	}
	public class PerBodyStatDef
	{
		private readonly string prefix;

		private readonly StatRecordType recordType;

		private readonly StatDataType dataType;

		private readonly StatDef.DisplayValueFormatterDelegate displayValueFormatter;

		private readonly Dictionary<string, StatDef> bodyNameToStatDefDictionary = new Dictionary<string, StatDef>();

		public readonly string nameToken;

		private StatDef[] bodyIndexToStatDef;

		private static readonly List<PerBodyStatDef> instancesList;

		public static readonly PerBodyStatDef totalTimeAlive;

		public static readonly PerBodyStatDef totalWins;

		public static readonly PerBodyStatDef longestRun;

		public static readonly PerBodyStatDef damageDealtTo;

		public static readonly PerBodyStatDef damageDealtAs;

		public static readonly PerBodyStatDef minionDamageDealtAs;

		public static readonly PerBodyStatDef damageTakenFrom;

		public static readonly PerBodyStatDef damageTakenAs;

		public static readonly PerBodyStatDef killsAgainst;

		public static readonly PerBodyStatDef killsAgainstElite;

		public static readonly PerBodyStatDef deathsFrom;

		public static readonly PerBodyStatDef killsAs;

		public static readonly PerBodyStatDef minionKillsAs;

		public static readonly PerBodyStatDef deathsAs;

		public static readonly PerBodyStatDef timesPicked;

		public static readonly PerBodyStatDef highestInfiniteTowerWaveReachedEasy;

		public static readonly PerBodyStatDef highestInfiniteTowerWaveReachedNormal;

		public static readonly PerBodyStatDef highestInfiniteTowerWaveReachedHard;

		static PerBodyStatDef()
		{
			instancesList = new List<PerBodyStatDef>();
			totalTimeAlive = Register("totalTimeAlive", StatRecordType.Sum, StatDataType.Double);
			totalWins = Register("totalWins", StatRecordType.Sum, StatDataType.ULong);
			longestRun = Register("longestRun", StatRecordType.Max, StatDataType.Double, StatDef.TimeMMSSDisplayValueFormatter);
			damageDealtTo = Register("damageDealtTo", StatRecordType.Sum, StatDataType.ULong);
			damageDealtAs = Register("damageDealtAs", StatRecordType.Sum, StatDataType.ULong);
			minionDamageDealtAs = Register("minionDamageDealtAs", StatRecordType.Sum, StatDataType.ULong);
			damageTakenFrom = Register("damageTakenFrom", StatRecordType.Sum, StatDataType.ULong);
			damageTakenAs = Register("damageTakenAs", StatRecordType.Sum, StatDataType.ULong);
			killsAgainst = Register("killsAgainst", StatRecordType.Sum, StatDataType.ULong);
			killsAgainstElite = Register("killsAgainstElite", StatRecordType.Sum, StatDataType.ULong);
			deathsFrom = Register("deathsFrom", StatRecordType.Sum, StatDataType.ULong);
			killsAs = Register("killsAs", StatRecordType.Sum, StatDataType.ULong);
			minionKillsAs = Register("minionKillsAs", StatRecordType.Sum, StatDataType.ULong);
			deathsAs = Register("deathsAs", StatRecordType.Sum, StatDataType.ULong);
			timesPicked = Register("timesPicked", StatRecordType.Sum, StatDataType.ULong);
			highestInfiniteTowerWaveReachedEasy = Register("highestInfiniteTowerWaveReachedEasy", StatRecordType.Max, StatDataType.ULong);
			highestInfiniteTowerWaveReachedNormal = Register("highestInfiniteTowerWaveReachedNormal", StatRecordType.Max, StatDataType.ULong);
			highestInfiniteTowerWaveReachedHard = Register("highestInfiniteTowerWaveReachedHard", StatRecordType.Max, StatDataType.ULong);
		}

		public static void RegisterStatDefs()
		{
			foreach (PerBodyStatDef instances in instancesList)
			{
				instances.bodyIndexToStatDef = new StatDef[BodyCatalog.bodyCount];
				for (BodyIndex bodyIndex = (BodyIndex)0; (int)bodyIndex < BodyCatalog.bodyCount; bodyIndex++)
				{
					string bodyName = BodyCatalog.GetBodyName(bodyIndex);
					StatDef statDef = StatDef.Register(instances.prefix + "." + bodyName, instances.recordType, instances.dataType, 0.0, instances.displayValueFormatter);
					instances.bodyNameToStatDefDictionary.Add(bodyName, statDef);
					instances.bodyNameToStatDefDictionary.Add(bodyName + "(Clone)", statDef);
					instances.bodyIndexToStatDef[(int)bodyIndex] = statDef;
				}
			}
		}

		private PerBodyStatDef(string prefix, StatRecordType recordType, StatDataType dataType, StatDef.DisplayValueFormatterDelegate displayValueFormatter = null)
		{
			this.prefix = prefix;
			this.recordType = recordType;
			this.dataType = dataType;
			this.displayValueFormatter = displayValueFormatter;
			nameToken = "PERBODYSTATNAME_" + prefix.ToUpper(CultureInfo.InvariantCulture);
		}

		private static PerBodyStatDef Register(string prefix, StatRecordType recordType, StatDataType dataType, StatDef.DisplayValueFormatterDelegate displayValueFormatter = null)
		{
			PerBodyStatDef perBodyStatDef = new PerBodyStatDef(prefix, recordType, dataType, displayValueFormatter);
			instancesList.Add(perBodyStatDef);
			return perBodyStatDef;
		}

		public StatDef FindStatDef(string bodyName)
		{
			bodyNameToStatDefDictionary.TryGetValue(bodyName, out var value);
			return value;
		}

		public StatDef FindStatDef(BodyIndex bodyIndex)
		{
			return ArrayUtils.GetSafe(bodyIndexToStatDef, (int)bodyIndex);
		}
	}
	public class PerItemStatDef
	{
		private readonly string prefix;

		private readonly StatRecordType recordType;

		private readonly StatDataType dataType;

		private readonly StatDef[] keyToStatDef = ItemCatalog.GetPerItemBuffer<StatDef>();

		private static readonly List<PerItemStatDef> instancesList;

		public static readonly PerItemStatDef totalCollected;

		public static readonly PerItemStatDef highestCollected;

		static PerItemStatDef()
		{
			instancesList = new List<PerItemStatDef>();
			totalCollected = Register("totalCollected", StatRecordType.Sum, StatDataType.ULong);
			highestCollected = Register("highestCollected", StatRecordType.Max, StatDataType.ULong);
		}

		public static void RegisterStatDefs()
		{
			foreach (PerItemStatDef instances in instancesList)
			{
				foreach (ItemIndex allItem in ItemCatalog.allItems)
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(allItem);
					StatDef statDef = StatDef.Register(instances.prefix + "." + itemDef.name, instances.recordType, instances.dataType, 0.0);
					instances.keyToStatDef[(int)allItem] = statDef;
				}
			}
		}

		private PerItemStatDef(string prefix, StatRecordType recordType, StatDataType dataType)
		{
			this.prefix = prefix;
			this.recordType = recordType;
			this.dataType = dataType;
		}

		private static PerItemStatDef Register(string prefix, StatRecordType recordType, StatDataType dataType)
		{
			PerItemStatDef perItemStatDef = new PerItemStatDef(prefix, recordType, dataType);
			instancesList.Add(perItemStatDef);
			return perItemStatDef;
		}

		public StatDef FindStatDef(ItemIndex key)
		{
			return keyToStatDef[(int)key];
		}
	}
	public class PerEquipmentStatDef
	{
		private readonly string prefix;

		private readonly StatRecordType recordType;

		private readonly StatDataType dataType;

		private readonly StatDef[] keyToStatDef = EquipmentCatalog.GetPerEquipmentBuffer<StatDef>();

		private StatDef.DisplayValueFormatterDelegate displayValueFormatter;

		private static readonly List<PerEquipmentStatDef> instancesList;

		public static readonly PerEquipmentStatDef totalTimeHeld;

		public static readonly PerEquipmentStatDef totalTimesFired;

		static PerEquipmentStatDef()
		{
			instancesList = new List<PerEquipmentStatDef>();
			totalTimeHeld = Register("totalTimeHeld", StatRecordType.Sum, StatDataType.Double, StatDef.TimeMMSSDisplayValueFormatter);
			totalTimesFired = Register("totalTimesFired", StatRecordType.Sum, StatDataType.ULong);
		}

		public static void RegisterStatDefs()
		{
			foreach (PerEquipmentStatDef instances in instancesList)
			{
				foreach (EquipmentIndex item in EquipmentCatalog.allEquipment)
				{
					EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(item);
					StatDef statDef = StatDef.Register(instances.prefix + "." + equipmentDef.name, instances.recordType, instances.dataType, 0.0, instances.displayValueFormatter);
					instances.keyToStatDef[(int)item] = statDef;
				}
			}
		}

		private PerEquipmentStatDef(string prefix, StatRecordType recordType, StatDataType dataType, StatDef.DisplayValueFormatterDelegate displayValueFormatter)
		{
			this.prefix = prefix;
			this.recordType = recordType;
			this.dataType = dataType;
			this.displayValueFormatter = displayValueFormatter ?? new StatDef.DisplayValueFormatterDelegate(StatDef.DefaultDisplayValueFormatter);
		}

		private static PerEquipmentStatDef Register(string prefix, StatRecordType recordType, StatDataType dataType, StatDef.DisplayValueFormatterDelegate displayValueFormatter = null)
		{
			PerEquipmentStatDef perEquipmentStatDef = new PerEquipmentStatDef(prefix, recordType, dataType, displayValueFormatter);
			instancesList.Add(perEquipmentStatDef);
			return perEquipmentStatDef;
		}

		public StatDef FindStatDef(EquipmentIndex key)
		{
			return keyToStatDef[(int)key];
		}
	}
	public class PerStageStatDef
	{
		private readonly string prefix;

		private readonly StatRecordType recordType;

		private readonly StatDataType dataType;

		private readonly Dictionary<string, StatDef> keyToStatDef = new Dictionary<string, StatDef>();

		private StatDef.DisplayValueFormatterDelegate displayValueFormatter;

		private static readonly List<PerStageStatDef> instancesList;

		public static readonly PerStageStatDef totalTimesVisited;

		public static readonly PerStageStatDef totalTimesCleared;

		static PerStageStatDef()
		{
			instancesList = new List<PerStageStatDef>();
			totalTimesVisited = Register("totalTimesVisited", StatRecordType.Sum, StatDataType.ULong);
			totalTimesCleared = Register("totalTimesCleared", StatRecordType.Sum, StatDataType.ULong);
		}

		public static void RegisterStatDefs()
		{
			foreach (PerStageStatDef instances in instancesList)
			{
				foreach (string allBaseSceneName in SceneCatalog.allBaseSceneNames)
				{
					StatDef value = StatDef.Register(instances.prefix + "." + allBaseSceneName, instances.recordType, instances.dataType, 0.0, instances.displayValueFormatter);
					instances.keyToStatDef[allBaseSceneName] = value;
				}
			}
		}

		private PerStageStatDef(string prefix, StatRecordType recordType, StatDataType dataType, StatDef.DisplayValueFormatterDelegate displayValueFormatter)
		{
			this.prefix = prefix;
			this.recordType = recordType;
			this.dataType = dataType;
			this.displayValueFormatter = displayValueFormatter ?? new StatDef.DisplayValueFormatterDelegate(StatDef.DefaultDisplayValueFormatter);
		}

		[NotNull]
		private static PerStageStatDef Register(string prefix, StatRecordType recordType, StatDataType dataType, StatDef.DisplayValueFormatterDelegate displayValueFormatter = null)
		{
			PerStageStatDef perStageStatDef = new PerStageStatDef(prefix, recordType, dataType, displayValueFormatter);
			instancesList.Add(perStageStatDef);
			return perStageStatDef;
		}

		[CanBeNull]
		public StatDef FindStatDef(string key)
		{
			if (keyToStatDef.TryGetValue(key, out var value))
			{
				return value;
			}
			return null;
		}
	}
	public struct StatEvent
	{
		public enum Type
		{
			Damage,
			Kill,
			Walk,
			Die,
			Lose,
			Win
		}

		public string stringValue;

		public double doubleValue;

		public ulong ulongValue;
	}
	public struct StatField : IComparable<StatField>
	{
		[StructLayout(LayoutKind.Explicit)]
		private struct ValueUnion
		{
			[FieldOffset(0)]
			public readonly ulong ulongValue;

			[FieldOffset(0)]
			public readonly double doubleValue;

			public static explicit operator ulong(ValueUnion v)
			{
				return v.ulongValue;
			}

			public static explicit operator double(ValueUnion v)
			{
				return v.doubleValue;
			}

			public static implicit operator ValueUnion(ulong ulongValue)
			{
				return new ValueUnion(ulongValue);
			}

			public static implicit operator ValueUnion(double doubleValue)
			{
				return new ValueUnion(doubleValue);
			}

			private ValueUnion(ulong ulongValue)
			{
				this = default(ValueUnion);
				this.ulongValue = ulongValue;
			}

			private ValueUnion(double doubleValue)
			{
				this = default(ValueUnion);
				this.doubleValue = doubleValue;
			}
		}

		public StatDef statDef;

		public bool hasChanged;

		public bool nonDefaultValue;

		private ValueUnion value;

		public string name => statDef.name;

		public StatRecordType recordType => statDef.recordType;

		public StatDataType dataType => statDef.dataType;

		private ulong ulongValue
		{
			get
			{
				return value.ulongValue;
			}
			set
			{
				this.value = value;
			}
		}

		private double doubleValue
		{
			get
			{
				return value.doubleValue;
			}
			set
			{
				this.value = value;
			}
		}

		public override string ToString()
		{
			return dataType switch
			{
				StatDataType.ULong => TextSerialization.ToStringInvariant(value.ulongValue), 
				StatDataType.Double => TextSerialization.ToStringInvariant(value.doubleValue), 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		public string ToLocalNumeric()
		{
			return dataType switch
			{
				StatDataType.ULong => TextSerialization.ToStringNumeric(value.ulongValue), 
				StatDataType.Double => TextSerialization.ToStringNumeric(value.doubleValue), 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		public ulong CalculatePointValue()
		{
			throw new NotImplementedException();
		}

		[Pure]
		public static StatField GetDelta(ref StatField newerValue, ref StatField olderValue)
		{
			StatField result;
			if (newerValue.recordType != 0)
			{
				if (newerValue.dataType == StatDataType.ULong && newerValue.ulongValue == olderValue.ulongValue)
				{
					result = default(StatField);
					result.statDef = newerValue.statDef;
					result.hasChanged = false;
					result.ulongValue = newerValue.ulongValue;
					return result;
				}
				if (newerValue.dataType == StatDataType.Double && newerValue.doubleValue == olderValue.doubleValue)
				{
					result = default(StatField);
					result.statDef = newerValue.statDef;
					result.hasChanged = false;
					result.doubleValue = newerValue.doubleValue;
					return result;
				}
			}
			result = default(StatField);
			result.statDef = newerValue.statDef;
			result.hasChanged = false;
			StatField result2 = result;
			switch (newerValue.dataType)
			{
			case StatDataType.ULong:
				switch (newerValue.recordType)
				{
				case StatRecordType.Sum:
					result2.ulongValue = newerValue.ulongValue - olderValue.ulongValue;
					result2.hasChanged = result2.ulongValue != 0;
					break;
				case StatRecordType.Max:
					result2.ulongValue = Math.Max(newerValue.ulongValue, olderValue.ulongValue);
					result2.hasChanged = result2.ulongValue != olderValue.ulongValue;
					break;
				case StatRecordType.Newest:
					result2.ulongValue = newerValue.ulongValue;
					result2.hasChanged = result2.ulongValue != olderValue.ulongValue;
					break;
				}
				break;
			case StatDataType.Double:
				switch (newerValue.recordType)
				{
				case StatRecordType.Sum:
					result2.doubleValue = newerValue.doubleValue - olderValue.doubleValue;
					result2.hasChanged = result2.doubleValue != 0.0;
					break;
				case StatRecordType.Max:
					result2.doubleValue = Math.Max(newerValue.doubleValue, olderValue.doubleValue);
					result2.hasChanged = result2.doubleValue != olderValue.doubleValue;
					break;
				case StatRecordType.Newest:
					result2.doubleValue = newerValue.doubleValue;
					result2.hasChanged = result2.doubleValue != olderValue.doubleValue;
					break;
				}
				break;
			}
			return result2;
		}

		public void PushDelta(ref StatField deltaField)
		{
			switch (dataType)
			{
			case StatDataType.ULong:
				PushStatValue(deltaField.ulongValue);
				break;
			case StatDataType.Double:
				PushStatValue(deltaField.doubleValue);
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		public void Write(NetworkWriter writer)
		{
			switch (dataType)
			{
			case StatDataType.ULong:
				writer.WritePackedUInt64(ulongValue);
				break;
			case StatDataType.Double:
				writer.Write(doubleValue);
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		public void Read(NetworkReader reader)
		{
			switch (dataType)
			{
			case StatDataType.ULong:
			{
				ulong num2 = ulongValue;
				ulongValue = reader.ReadPackedUInt64();
				hasChanged = ulongValue != num2;
				break;
			}
			case StatDataType.Double:
			{
				double num = doubleValue;
				doubleValue = reader.ReadDouble();
				hasChanged = num != doubleValue;
				break;
			}
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		private void EnforceDataType(StatDataType otherDataType)
		{
			if (dataType != otherDataType)
			{
				throw new InvalidOperationException($"Expected data type {dataType}, got data type {otherDataType}.");
			}
		}

		public void PushStatValue(ulong incomingValue)
		{
			EnforceDataType(StatDataType.ULong);
			switch (recordType)
			{
			case StatRecordType.Sum:
				ulongValue += incomingValue;
				break;
			case StatRecordType.Max:
				ulongValue = Math.Max(incomingValue, ulongValue);
				break;
			case StatRecordType.Newest:
				ulongValue = incomingValue;
				break;
			}
			hasChanged = true;
			nonDefaultValue = ulongValue != 0;
		}

		public void PushStatValue(double incomingValue)
		{
			EnforceDataType(StatDataType.Double);
			switch (recordType)
			{
			case StatRecordType.Sum:
				doubleValue += incomingValue;
				break;
			case StatRecordType.Max:
				doubleValue = Math.Max(incomingValue, doubleValue);
				break;
			case StatRecordType.Newest:
				doubleValue = incomingValue;
				break;
			}
			hasChanged = true;
			nonDefaultValue = doubleValue != 0.0;
		}

		public void SetFromString(string valueString)
		{
			switch (dataType)
			{
			case StatDataType.ULong:
			{
				TextSerialization.TryParseInvariant(valueString, out ulong result2);
				value = result2;
				nonDefaultValue = ulongValue != 0;
				hasChanged = true;
				break;
			}
			case StatDataType.Double:
			{
				TextSerialization.TryParseInvariant(valueString, out double result);
				value = result;
				nonDefaultValue = doubleValue != 0.0;
				hasChanged = true;
				break;
			}
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		public ulong GetULongValue()
		{
			EnforceDataType(StatDataType.ULong);
			return ulongValue;
		}

		public double GetDoubleValue()
		{
			EnforceDataType(StatDataType.Double);
			return doubleValue;
		}

		public double GetValueAsDouble()
		{
			return dataType switch
			{
				StatDataType.ULong => ulongValue, 
				StatDataType.Double => doubleValue, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		[Obsolete]
		public decimal GetDecimalValue()
		{
			return dataType switch
			{
				StatDataType.ULong => ulongValue, 
				StatDataType.Double => (decimal)doubleValue, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		public bool IsDefault()
		{
			return dataType switch
			{
				StatDataType.ULong => ulongValue == 0, 
				StatDataType.Double => doubleValue == 0.0, 
				_ => true, 
			};
		}

		public void SetDefault()
		{
			switch (dataType)
			{
			case StatDataType.ULong:
				ulongValue = 0uL;
				break;
			case StatDataType.Double:
				doubleValue = 0.0;
				break;
			default:
				throw new NotImplementedException();
			}
			nonDefaultValue = false;
			hasChanged = false;
		}

		public ulong GetPointValue(double pointValue)
		{
			return dataType switch
			{
				StatDataType.ULong => (ulong)((double)ulongValue * pointValue), 
				StatDataType.Double => (ulong)(doubleValue * pointValue), 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		public int CompareTo(StatField other)
		{
			return CompareTo(in other);
		}

		public int CompareTo(in StatField other)
		{
			EnforceDataType(other.dataType);
			return dataType switch
			{
				StatDataType.ULong => ulongValue.CompareTo(other.ulongValue), 
				StatDataType.Double => doubleValue.CompareTo(other.doubleValue), 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		public void SetToMaxValue()
		{
			switch (dataType)
			{
			case StatDataType.ULong:
				ulongValue = ulong.MaxValue;
				break;
			case StatDataType.Double:
				doubleValue = double.MaxValue;
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			nonDefaultValue = true;
			hasChanged = true;
		}
	}
	internal class StatManager
	{
		private struct DamageEvent
		{
			[CanBeNull]
			public CharacterMaster attackerMaster;

			public BodyIndex attackerBodyIndex;

			[CanBeNull]
			public CharacterMaster attackerOwnerMaster;

			public BodyIndex attackerOwnerBodyIndex;

			[CanBeNull]
			public CharacterMaster victimMaster;

			public BodyIndex victimBodyIndex;

			public bool victimIsElite;

			public float damageDealt;

			public DotController.DotIndex dotType;
		}

		private struct DeathEvent
		{
			public DamageReport damageReport;

			public bool victimWasBurning;
		}

		private struct HealingEvent
		{
			[CanBeNull]
			public GameObject healee;

			public float healAmount;
		}

		private struct GoldEvent
		{
			[CanBeNull]
			public CharacterMaster characterMaster;

			public ulong amount;
		}

		[StructLayout(LayoutKind.Sequential, Size = 1)]
		private struct PurchaseStatEvent
		{
		}

		public struct CharacterUpdateEvent
		{
			public PlayerStatsComponent statsComponent;

			public float additionalDistanceTraveled;

			public float additionalTimeAlive;

			public int level;

			public float runTime;
		}

		private struct ItemCollectedEvent
		{
			[CanBeNull]
			public Inventory inventory;

			public ItemIndex itemIndex;

			public int quantity;

			public int newCount;
		}

		private static BodyIndex crocoBodyIndex = BodyIndex.None;

		private static readonly Queue<DamageEvent> damageEvents = new Queue<DamageEvent>();

		private static readonly Queue<DeathEvent> deathEvents = new Queue<DeathEvent>();

		private static readonly Queue<HealingEvent> healingEvents = new Queue<HealingEvent>();

		private static readonly Queue<GoldEvent> goldCollectedEvents = new Queue<GoldEvent>();

		private static readonly Queue<PurchaseStatEvent> purchaseStatEvents = new Queue<PurchaseStatEvent>();

		private static readonly Queue<CharacterUpdateEvent> characterUpdateEvents = new Queue<CharacterUpdateEvent>();

		private static readonly Queue<ItemCollectedEvent> itemCollectedEvents = new Queue<ItemCollectedEvent>();

		[SystemInitializer(new Type[]
		{
			typeof(BodyCatalog),
			typeof(ItemCatalog),
			typeof(EquipmentCatalog),
			typeof(PickupCatalog)
		})]
		private static void Init()
		{
			GlobalEventManager.onServerDamageDealt += OnDamageDealt;
			GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			GlobalEventManager.onServerCharacterExecuted += OnCharacterExecute;
			HealthComponent.onCharacterHealServer += OnCharacterHeal;
			Run.onPlayerFirstCreatedServer += OnPlayerFirstCreatedServer;
			Run.onServerGameOver += OnServerGameOver;
			Stage.onServerStageComplete += OnServerStageComplete;
			Stage.onServerStageBegin += OnServerStageBegin;
			Inventory.onServerItemGiven += OnServerItemGiven;
			RoR2Application.onFixedUpdate += ProcessEvents;
			EquipmentSlot.onServerEquipmentActivated += OnEquipmentActivated;
			InfiniteTowerRun.onWaveInitialized += OnInfiniteTowerWaveInitialized;
			crocoBodyIndex = BodyCatalog.FindBodyIndex("CrocoBody");
		}

		private static void OnInfiniteTowerWaveInitialized(InfiniteTowerWaveController waveController)
		{
			ulong statValue = (ulong)((Run.instance as InfiniteTowerRun)?.waveIndex ?? 0);
			foreach (PlayerStatsComponent instances in PlayerStatsComponent.instancesList)
			{
				if (!instances.playerCharacterMasterController.isConnected)
				{
					continue;
				}
				PerBodyStatDef perBodyStatDef = null;
				switch (Run.instance.selectedDifficulty)
				{
				case DifficultyIndex.Easy:
					perBodyStatDef = PerBodyStatDef.highestInfiniteTowerWaveReachedEasy;
					break;
				case DifficultyIndex.Normal:
					perBodyStatDef = PerBodyStatDef.highestInfiniteTowerWaveReachedNormal;
					break;
				case DifficultyIndex.Hard:
					perBodyStatDef = PerBodyStatDef.highestInfiniteTowerWaveReachedHard;
					break;
				}
				StatSheet currentStats = instances.currentStats;
				currentStats.PushStatValue(StatDef.highestInfiniteTowerWaveReached, statValue);
				if (perBodyStatDef != null)
				{
					CharacterBody body = instances.characterMaster.GetBody();
					if ((bool)body)
					{
						string bodyName = BodyCatalog.GetBodyName(body.bodyIndex);
						currentStats.PushStatValue(perBodyStatDef.FindStatDef(bodyName ?? ""), statValue);
					}
				}
			}
		}

		private static void OnServerGameOver(Run run, GameEndingDef gameEndingDef)
		{
			if (!gameEndingDef.isWin || !(run.GetType() == typeof(Run)))
			{
				return;
			}
			foreach (PlayerStatsComponent instances in PlayerStatsComponent.instancesList)
			{
				if (instances.playerCharacterMasterController.isConnected)
				{
					instances.currentStats.PushStatValue(PerBodyStatDef.totalWins.FindStatDef(instances.characterMaster.bodyPrefab?.name ?? ""), 1uL);
				}
			}
		}

		private static void OnPlayerFirstCreatedServer(Run run, PlayerCharacterMasterController playerCharacterMasterController)
		{
			playerCharacterMasterController.master.onBodyStart += OnBodyFirstStart;
		}

		private static void OnBodyFirstStart(CharacterBody body)
		{
			CharacterMaster master = body.master;
			if (!master)
			{
				return;
			}
			master.onBodyStart -= OnBodyFirstStart;
			PlayerCharacterMasterController component = master.GetComponent<PlayerCharacterMasterController>();
			if ((bool)component)
			{
				PlayerStatsComponent component2 = component.GetComponent<PlayerStatsComponent>();
				if ((bool)component2)
				{
					StatSheet currentStats = component2.currentStats;
					currentStats.PushStatValue(PerBodyStatDef.timesPicked.FindStatDef(body.name), 1uL);
					currentStats.PushStatValue(StatDef.totalGamesPlayed, 1uL);
				}
			}
		}

		public static void ForceUpdate()
		{
			ProcessEvents();
		}

		private static void ProcessEvents()
		{
			ProcessDamageEvents();
			ProcessDeathEvents();
			ProcessHealingEvents();
			ProcessGoldEvents();
			ProcessItemCollectedEvents();
			ProcessCharacterUpdateEvents();
		}

		public static void OnCharacterHeal(HealthComponent healthComponent, float amount, ProcChainMask procChainMask)
		{
			healingEvents.Enqueue(new HealingEvent
			{
				healee = healthComponent.gameObject,
				healAmount = amount
			});
		}

		public static void OnDamageDealt(DamageReport damageReport)
		{
			damageEvents.Enqueue(new DamageEvent
			{
				attackerMaster = damageReport.attackerMaster,
				attackerBodyIndex = damageReport.attackerBodyIndex,
				attackerOwnerMaster = damageReport.attackerOwnerMaster,
				attackerOwnerBodyIndex = damageReport.attackerOwnerBodyIndex,
				victimMaster = damageReport.victimMaster,
				victimBodyIndex = damageReport.victimBodyIndex,
				victimIsElite = damageReport.victimIsElite,
				damageDealt = damageReport.damageDealt,
				dotType = damageReport.dotType
			});
		}

		public static void OnCharacterExecute(DamageReport damageReport, float executionHealthLost)
		{
			damageEvents.Enqueue(new DamageEvent
			{
				attackerMaster = damageReport.attackerMaster,
				attackerBodyIndex = damageReport.attackerBodyIndex,
				attackerOwnerMaster = damageReport.attackerOwnerMaster,
				attackerOwnerBodyIndex = damageReport.attackerOwnerBodyIndex,
				victimMaster = damageReport.victimMaster,
				victimBodyIndex = damageReport.victimBodyIndex,
				victimIsElite = damageReport.victimIsElite,
				damageDealt = executionHealthLost,
				dotType = damageReport.dotType
			});
		}

		public static void OnCharacterDeath(DamageReport damageReport)
		{
			DotController dotController = DotController.FindDotController(damageReport.victim.gameObject);
			bool victimWasBurning = false;
			if ((bool)dotController)
			{
				victimWasBurning = dotController.HasDotActive(DotController.DotIndex.Burn) | dotController.HasDotActive(DotController.DotIndex.PercentBurn) | dotController.HasDotActive(DotController.DotIndex.Helfire) | dotController.HasDotActive(DotController.DotIndex.StrongerBurn);
			}
			deathEvents.Enqueue(new DeathEvent
			{
				damageReport = damageReport,
				victimWasBurning = victimWasBurning
			});
		}

		private static void ProcessHealingEvents()
		{
			while (healingEvents.Count > 0)
			{
				HealingEvent healingEvent = healingEvents.Dequeue();
				ulong statValue = (ulong)healingEvent.healAmount;
				PlayerStatsComponent.FindBodyStatSheet(healingEvent.healee)?.PushStatValue(StatDef.totalHealthHealed, statValue);
			}
		}

		private static void ProcessDamageEvents()
		{
			while (damageEvents.Count > 0)
			{
				DamageEvent damageEvent = damageEvents.Dequeue();
				ulong statValue = (ulong)damageEvent.damageDealt;
				StatSheet statSheet = PlayerStatsComponent.FindMasterStatSheet(damageEvent.victimMaster);
				StatSheet statSheet2 = PlayerStatsComponent.FindMasterStatSheet(damageEvent.attackerMaster);
				StatSheet statSheet3 = PlayerStatsComponent.FindMasterStatSheet(damageEvent.attackerOwnerMaster);
				if (statSheet != null)
				{
					statSheet.PushStatValue(StatDef.totalDamageTaken, statValue);
					if (damageEvent.attackerBodyIndex != BodyIndex.None)
					{
						statSheet.PushStatValue(PerBodyStatDef.damageTakenFrom, damageEvent.attackerBodyIndex, statValue);
					}
					if (damageEvent.victimBodyIndex != BodyIndex.None)
					{
						statSheet.PushStatValue(PerBodyStatDef.damageTakenAs, damageEvent.victimBodyIndex, statValue);
					}
				}
				if (statSheet2 != null)
				{
					statSheet2.PushStatValue(StatDef.totalDamageDealt, statValue);
					statSheet2.PushStatValue(StatDef.highestDamageDealt, statValue);
					if (damageEvent.attackerBodyIndex != BodyIndex.None)
					{
						statSheet2.PushStatValue(PerBodyStatDef.damageDealtAs, damageEvent.attackerBodyIndex, statValue);
					}
					if (damageEvent.victimBodyIndex != BodyIndex.None)
					{
						statSheet2.PushStatValue(PerBodyStatDef.damageDealtTo, damageEvent.victimBodyIndex, statValue);
					}
				}
				if (statSheet3 != null)
				{
					statSheet3.PushStatValue(StatDef.totalMinionDamageDealt, statValue);
					if (damageEvent.attackerOwnerBodyIndex != BodyIndex.None)
					{
						statSheet3.PushStatValue(PerBodyStatDef.minionDamageDealtAs, damageEvent.attackerOwnerBodyIndex, statValue);
					}
				}
			}
		}

		private static void ProcessDeathEvents()
		{
			while (deathEvents.Count > 0)
			{
				DeathEvent deathEvent = deathEvents.Dequeue();
				DamageReport damageReport = deathEvent.damageReport;
				StatSheet statSheet = PlayerStatsComponent.FindMasterStatSheet(damageReport.victimMaster);
				StatSheet statSheet2 = PlayerStatsComponent.FindMasterStatSheet(damageReport.attackerMaster);
				StatSheet statSheet3 = PlayerStatsComponent.FindMasterStatSheet(damageReport.attackerOwnerMaster);
				if (statSheet != null)
				{
					statSheet.PushStatValue(StatDef.totalDeaths, 1uL);
					statSheet.PushStatValue(PerBodyStatDef.deathsAs, damageReport.victimBodyIndex, 1uL);
					if (damageReport.attackerBodyIndex != BodyIndex.None)
					{
						statSheet.PushStatValue(PerBodyStatDef.deathsFrom, damageReport.attackerBodyIndex, 1uL);
					}
					if (damageReport.dotType != DotController.DotIndex.None)
					{
						DotController.DotIndex dotType = damageReport.dotType;
						if ((uint)(dotType - 1) <= 2u || dotType == DotController.DotIndex.StrongerBurn)
						{
							statSheet.PushStatValue(StatDef.totalBurnDeaths, 1uL);
						}
					}
					if (deathEvent.victimWasBurning)
					{
						statSheet.PushStatValue(StatDef.totalDeathsWhileBurning, 1uL);
					}
				}
				if (statSheet2 != null)
				{
					statSheet2.PushStatValue(StatDef.totalKills, 1uL);
					statSheet2.PushStatValue(PerBodyStatDef.killsAs, damageReport.attackerBodyIndex, 1uL);
					if (damageReport.victimBodyIndex != BodyIndex.None)
					{
						statSheet2.PushStatValue(PerBodyStatDef.killsAgainst, damageReport.victimBodyIndex, 1uL);
						if (damageReport.victimIsElite)
						{
							statSheet2.PushStatValue(StatDef.totalEliteKills, 1uL);
							statSheet2.PushStatValue(PerBodyStatDef.killsAgainstElite, damageReport.victimBodyIndex, 1uL);
						}
					}
					if (damageReport.attackerBodyIndex == crocoBodyIndex && damageReport.combinedHealthBeforeDamage <= 1f)
					{
						statSheet2.PushStatValue(StatDef.totalCrocoWeakEnemyKills, 1uL);
					}
					string text = damageReport.victimBody?.customKillTotalStatName;
					if (!string.IsNullOrEmpty(text))
					{
						StatDef statDef = StatDef.Find(text);
						if (statDef == null)
						{
							UnityEngine.Debug.LogWarningFormat("Stat def \"{0}\" could not be found.", text);
						}
						else
						{
							statSheet2.PushStatValue(statDef, 1uL);
						}
					}
				}
				if (statSheet3 != null)
				{
					statSheet3.PushStatValue(StatDef.totalMinionKills, 1uL);
					if (damageReport.attackerOwnerBodyIndex != BodyIndex.None)
					{
						statSheet3.PushStatValue(PerBodyStatDef.minionKillsAs, damageReport.attackerOwnerBodyIndex, 1uL);
					}
				}
				if (!damageReport.victimIsBoss)
				{
					continue;
				}
				int i = 0;
				for (int count = PlayerStatsComponent.instancesList.Count; i < count; i++)
				{
					PlayerStatsComponent playerStatsComponent = PlayerStatsComponent.instancesList[i];
					if (playerStatsComponent.characterMaster.hasBody)
					{
						playerStatsComponent.currentStats.PushStatValue(StatDef.totalTeleporterBossKillsWitnessed, 1uL);
					}
				}
			}
		}

		public static void OnGoldCollected(CharacterMaster characterMaster, ulong amount)
		{
			goldCollectedEvents.Enqueue(new GoldEvent
			{
				characterMaster = characterMaster,
				amount = amount
			});
		}

		private static void ProcessGoldEvents()
		{
			while (goldCollectedEvents.Count > 0)
			{
				GoldEvent goldEvent = goldCollectedEvents.Dequeue();
				StatSheet statSheet = goldEvent.characterMaster?.GetComponent<PlayerStatsComponent>()?.currentStats;
				if (statSheet != null)
				{
					statSheet.PushStatValue(StatDef.goldCollected, goldEvent.amount);
					statSheet.PushStatValue(StatDef.maxGoldCollected, statSheet.GetStatValueULong(StatDef.goldCollected));
				}
			}
		}

		public static void OnPurchase<T>(CharacterBody characterBody, CostTypeIndex costType, T statDefsToIncrement) where T : IEnumerable<StatDef>
		{
			StatSheet statSheet = PlayerStatsComponent.FindBodyStatSheet(characterBody);
			if (statSheet == null)
			{
				return;
			}
			StatDef statDef = null;
			StatDef statDef2 = null;
			switch (costType)
			{
			case CostTypeIndex.Money:
				statDef = StatDef.totalGoldPurchases;
				statDef2 = StatDef.highestGoldPurchases;
				break;
			case CostTypeIndex.PercentHealth:
				statDef = StatDef.totalBloodPurchases;
				statDef2 = StatDef.highestBloodPurchases;
				break;
			case CostTypeIndex.LunarCoin:
				statDef = StatDef.totalLunarPurchases;
				statDef2 = StatDef.highestLunarPurchases;
				break;
			case CostTypeIndex.WhiteItem:
				statDef = StatDef.totalTier1Purchases;
				statDef2 = StatDef.highestTier1Purchases;
				break;
			case CostTypeIndex.GreenItem:
				statDef = StatDef.totalTier2Purchases;
				statDef2 = StatDef.highestTier2Purchases;
				break;
			case CostTypeIndex.RedItem:
				statDef = StatDef.totalTier3Purchases;
				statDef2 = StatDef.highestTier3Purchases;
				break;
			}
			statSheet.PushStatValue(StatDef.totalPurchases, 1uL);
			statSheet.PushStatValue(StatDef.highestPurchases, statSheet.GetStatValueULong(StatDef.totalPurchases));
			if (statDef != null)
			{
				statSheet.PushStatValue(statDef, 1uL);
				if (statDef2 != null)
				{
					statSheet.PushStatValue(statDef2, statSheet.GetStatValueULong(statDef));
				}
			}
			if (statDefsToIncrement == null)
			{
				return;
			}
			foreach (StatDef item in statDefsToIncrement)
			{
				if (item != null)
				{
					statSheet.PushStatValue(item, 1uL);
				}
			}
		}

		public static void OnEquipmentActivated(EquipmentSlot activator, EquipmentIndex equipmentIndex)
		{
			PlayerStatsComponent.FindBodyStatSheet(activator.characterBody)?.PushStatValue(PerEquipmentStatDef.totalTimesFired.FindStatDef(equipmentIndex), 1uL);
		}

		public static void PushCharacterUpdateEvent(CharacterUpdateEvent e)
		{
			characterUpdateEvents.Enqueue(e);
		}

		private static void ProcessCharacterUpdateEvents()
		{
			while (characterUpdateEvents.Count > 0)
			{
				CharacterUpdateEvent characterUpdateEvent = characterUpdateEvents.Dequeue();
				if (!characterUpdateEvent.statsComponent)
				{
					continue;
				}
				StatSheet currentStats = characterUpdateEvent.statsComponent.currentStats;
				if (currentStats != null)
				{
					BodyIndex bodyIndex = characterUpdateEvent.statsComponent.characterMaster.GetBody()?.bodyIndex ?? BodyIndex.None;
					currentStats.PushStatValue(StatDef.totalTimeAlive, characterUpdateEvent.additionalTimeAlive);
					currentStats.PushStatValue(StatDef.highestLevel, (ulong)characterUpdateEvent.level);
					currentStats.PushStatValue(StatDef.totalDistanceTraveled, characterUpdateEvent.additionalDistanceTraveled);
					if (bodyIndex != BodyIndex.None)
					{
						currentStats.PushStatValue(PerBodyStatDef.totalTimeAlive, bodyIndex, characterUpdateEvent.additionalTimeAlive);
						currentStats.PushStatValue(PerBodyStatDef.longestRun, bodyIndex, characterUpdateEvent.runTime);
					}
					EquipmentIndex currentEquipmentIndex = characterUpdateEvent.statsComponent.characterMaster.inventory.currentEquipmentIndex;
					if (currentEquipmentIndex != EquipmentIndex.None)
					{
						currentStats.PushStatValue(PerEquipmentStatDef.totalTimeHeld.FindStatDef(currentEquipmentIndex), characterUpdateEvent.additionalTimeAlive);
					}
				}
			}
		}

		private static void OnServerItemGiven(Inventory inventory, ItemIndex itemIndex, int quantity)
		{
			itemCollectedEvents.Enqueue(new ItemCollectedEvent
			{
				inventory = inventory,
				itemIndex = itemIndex,
				quantity = quantity,
				newCount = inventory.GetItemCount(itemIndex)
			});
		}

		private static void ProcessItemCollectedEvents()
		{
			while (itemCollectedEvents.Count > 0)
			{
				ItemCollectedEvent itemCollectedEvent = itemCollectedEvents.Dequeue();
				if ((bool)itemCollectedEvent.inventory)
				{
					StatSheet statSheet = itemCollectedEvent.inventory.GetComponent<PlayerStatsComponent>()?.currentStats;
					if (statSheet != null)
					{
						statSheet.PushStatValue(StatDef.totalItemsCollected, (ulong)itemCollectedEvent.quantity);
						statSheet.PushStatValue(StatDef.highestItemsCollected, statSheet.GetStatValueULong(StatDef.totalItemsCollected));
						statSheet.PushStatValue(PerItemStatDef.totalCollected.FindStatDef(itemCollectedEvent.itemIndex), (ulong)itemCollectedEvent.quantity);
						statSheet.PushStatValue(PerItemStatDef.highestCollected.FindStatDef(itemCollectedEvent.itemIndex), (ulong)itemCollectedEvent.newCount);
					}
				}
			}
		}

		private static void OnServerStageBegin(Stage stage)
		{
			foreach (PlayerStatsComponent instances in PlayerStatsComponent.instancesList)
			{
				if (instances.playerCharacterMasterController.isConnected)
				{
					StatSheet currentStats = instances.currentStats;
					StatDef statDef = PerStageStatDef.totalTimesVisited.FindStatDef(stage.sceneDef ? stage.sceneDef.baseSceneName : string.Empty);
					if (statDef != null)
					{
						currentStats.PushStatValue(statDef, 1uL);
					}
				}
			}
		}

		private static void OnServerStageComplete(Stage stage)
		{
			foreach (PlayerStatsComponent instances in PlayerStatsComponent.instancesList)
			{
				if (instances.playerCharacterMasterController.isConnected)
				{
					StatSheet currentStats = instances.currentStats;
					if (SceneInfo.instance.countsAsStage)
					{
						currentStats.PushStatValue(StatDef.totalStagesCompleted, 1uL);
						currentStats.PushStatValue(StatDef.highestStagesCompleted, currentStats.GetStatValueULong(StatDef.totalStagesCompleted));
					}
					StatDef statDef = PerStageStatDef.totalTimesCleared.FindStatDef(stage.sceneDef ? stage.sceneDef.baseSceneName : string.Empty);
					if (statDef != null)
					{
						currentStats.PushStatValue(statDef, 1uL);
					}
				}
			}
		}
	}
	public enum StatRecordType
	{
		Sum,
		Max,
		Newest
	}
	public class StatSheet
	{
		private static StatField[] fieldsTemplate;

		private static bool[] nonDefaultFieldsBuffer;

		public readonly StatField[] fields;

		private UnlockableIndex[] unlockables = Array.Empty<UnlockableIndex>();

		public void SetStatValueFromString([CanBeNull] StatDef statDef, string value)
		{
			if (statDef != null)
			{
				fields[statDef.index].SetFromString(value);
			}
		}

		public void PushStatValue([CanBeNull] StatDef statDef, ulong statValue)
		{
			if (statDef != null)
			{
				int index = statDef.index;
				fields[index].PushStatValue(statValue);
			}
		}

		public void PushStatValue([CanBeNull] StatDef statDef, double statValue)
		{
			if (statDef != null)
			{
				fields[statDef.index].PushStatValue(statValue);
			}
		}

		public void PushStatValue([NotNull] PerBodyStatDef perBodyStatDef, BodyIndex bodyIndex, ulong statValue)
		{
			PushStatValue(perBodyStatDef.FindStatDef(bodyIndex), statValue);
		}

		public void PushStatValue([NotNull] PerBodyStatDef perBodyStatDef, BodyIndex bodyIndex, double statValue)
		{
			PushStatValue(perBodyStatDef.FindStatDef(bodyIndex), statValue);
		}

		public ulong GetStatValueULong([CanBeNull] StatDef statDef)
		{
			if (statDef == null)
			{
				return 0uL;
			}
			return fields[statDef.index].GetULongValue();
		}

		public double GetStatValueDouble([CanBeNull] StatDef statDef)
		{
			if (statDef == null)
			{
				return 0.0;
			}
			return fields[statDef.index].GetDoubleValue();
		}

		public double GetStatValueAsDouble([CanBeNull] StatDef statDef)
		{
			if (statDef == null)
			{
				return 0.0;
			}
			return fields[statDef.index].GetValueAsDouble();
		}

		[Obsolete]
		public decimal GetStatValueDecimal([CanBeNull] StatDef statDef)
		{
			if (statDef == null)
			{
				return 0m;
			}
			return fields[statDef.index].GetDecimalValue();
		}

		[NotNull]
		public string GetStatValueString([CanBeNull] StatDef statDef)
		{
			if (statDef == null)
			{
				return "INVALID_STAT";
			}
			return fields[statDef.index].ToString();
		}

		[NotNull]
		public string GetStatDisplayValue([CanBeNull] StatDef statDef)
		{
			if (statDef == null)
			{
				return "INVALID_STAT";
			}
			return statDef.displayValueFormatter(ref fields[statDef.index]);
		}

		public ulong GetStatPointValue([NotNull] StatDef statDef)
		{
			return fields[statDef.index].GetPointValue(statDef.pointValue);
		}

		public ulong GetStatValueULong([NotNull] PerBodyStatDef perBodyStatDef, [NotNull] string bodyName)
		{
			return GetStatValueULong(perBodyStatDef.FindStatDef(bodyName));
		}

		public double GetStatValueDouble([NotNull] PerBodyStatDef perBodyStatDef, [NotNull] string bodyName)
		{
			return GetStatValueDouble(perBodyStatDef.FindStatDef(bodyName));
		}

		[NotNull]
		public string GetStatValueString([NotNull] PerBodyStatDef perBodyStatDef, [NotNull] string bodyName)
		{
			return GetStatValueString(perBodyStatDef.FindStatDef(bodyName));
		}

		public BodyIndex FindBodyWithHighestStat([NotNull] PerBodyStatDef perBodyStatDef)
		{
			StatField statField = fields[perBodyStatDef.FindStatDef((BodyIndex)0).index];
			BodyIndex result = (BodyIndex)0;
			for (BodyIndex bodyIndex = (BodyIndex)1; (int)bodyIndex < BodyCatalog.bodyCount; bodyIndex++)
			{
				ref StatField reference = ref fields[perBodyStatDef.FindStatDef(bodyIndex).index];
				if (statField.CompareTo(in reference) < 0)
				{
					statField = reference;
					result = bodyIndex;
				}
			}
			if (statField.IsDefault())
			{
				return BodyIndex.None;
			}
			return result;
		}

		public EquipmentIndex FindEquipmentWithHighestStat([NotNull] PerEquipmentStatDef perEquipmentStatDef)
		{
			StatField statField = fields[perEquipmentStatDef.FindStatDef((EquipmentIndex)0).index];
			EquipmentIndex result = (EquipmentIndex)0;
			for (int i = 1; i < EquipmentCatalog.equipmentCount; i++)
			{
				ref StatField reference = ref fields[perEquipmentStatDef.FindStatDef((EquipmentIndex)i).index];
				if (statField.CompareTo(in reference) < 0)
				{
					statField = reference;
					result = (EquipmentIndex)i;
				}
			}
			if (statField.IsDefault())
			{
				return EquipmentIndex.None;
			}
			return result;
		}

		[SystemInitializer(new Type[] { typeof(StatDef) })]
		private static void Init()
		{
			OnFieldsFinalized();
		}

		static StatSheet()
		{
			HGXml.Register<StatSheet>(ToXml, FromXml);
		}

		public static void ToXml(XElement element, StatSheet statSheet)
		{
			element.RemoveAll();
			XElement xElement = new XElement("fields");
			element.Add(xElement);
			StatField[] array = statSheet.fields;
			for (int i = 0; i < array.Length; i++)
			{
				ref StatField reference = ref array[i];
				if (!reference.IsDefault())
				{
					xElement.Add(new XElement(reference.name, reference.ToString()));
				}
			}
		}

		public static bool FromXml(XElement element, ref StatSheet statSheet)
		{
			XElement xElement = element.Element("fields");
			if (xElement == null)
			{
				return false;
			}
			StatField[] array = statSheet.fields;
			for (int i = 0; i < array.Length; i++)
			{
				ref StatField reference = ref array[i];
				XElement xElement2 = xElement.Element(reference.name);
				if (xElement2 != null)
				{
					reference.SetFromString(xElement2.Value);
				}
			}
			return true;
		}

		private static void OnFieldsFinalized()
		{
			fieldsTemplate = StatDef.allStatDefs.Select(delegate(StatDef v)
			{
				StatField result = default(StatField);
				result.statDef = v;
				return result;
			}).ToArray();
			nonDefaultFieldsBuffer = new bool[fieldsTemplate.Length];
			PlatformSystems.saveSystem.isXmlReady = true;
		}

		private StatSheet([NotNull] StatField[] fields)
		{
			this.fields = fields;
		}

		public static StatSheet New()
		{
			StatField[] array = new StatField[fieldsTemplate.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = fieldsTemplate[i];
			}
			return new StatSheet(array);
		}

		public int GetUnlockableCount()
		{
			return unlockables.Length;
		}

		public UnlockableIndex GetUnlockableIndex(int index)
		{
			return unlockables[index];
		}

		public UnlockableDef GetUnlockable(int index)
		{
			return UnlockableCatalog.GetUnlockableDef(unlockables[index]);
		}

		public bool HasUnlockable([CanBeNull] UnlockableDef unlockableDef)
		{
			if (!unlockableDef || unlockableDef.index == UnlockableIndex.None)
			{
				return true;
			}
			for (int i = 0; i < unlockables.Length; i++)
			{
				if (unlockables[i] == unlockableDef.index)
				{
					return true;
				}
			}
			return false;
		}

		private void AllocateUnlockables(int desiredCount)
		{
			Array.Resize(ref unlockables, desiredCount);
		}

		public void AddUnlockable([NotNull] UnlockableDef unlockableDef)
		{
			AddUnlockable(unlockableDef.index);
		}

		public void AddUnlockable(UnlockableIndex unlockIndex)
		{
			if (Array.IndexOf(unlockables, unlockIndex) == -1)
			{
				Array.Resize(ref unlockables, unlockables.Length + 1);
				unlockables[unlockables.Length - 1] = unlockIndex;
			}
		}

		public void RemoveUnlockable(UnlockableIndex unlockIndex)
		{
			int num = Array.IndexOf(unlockables, unlockIndex);
			if (num != -1)
			{
				int arraySize = unlockables.Length;
				ArrayUtils.ArrayRemoveAt(unlockables, ref arraySize, num);
				Array.Resize(ref unlockables, arraySize);
			}
		}

		public void Write(NetworkWriter writer)
		{
			for (int i = 0; i < fields.Length; i++)
			{
				nonDefaultFieldsBuffer[i] = fields[i].nonDefaultValue;
			}
			writer.WriteBitArray(nonDefaultFieldsBuffer);
			for (int j = 0; j < fields.Length; j++)
			{
				if (nonDefaultFieldsBuffer[j])
				{
					fields[j].Write(writer);
				}
			}
			writer.Write((byte)unlockables.Length);
			for (int k = 0; k < unlockables.Length; k++)
			{
				writer.Write(unlockables[k]);
			}
		}

		public void WriteChanges(NetworkWriter writer)
		{
			for (int i = 0; i < fields.Length; i++)
			{
				nonDefaultFieldsBuffer[i] = fields[i].hasChanged;
			}
			writer.WriteBitArray(nonDefaultFieldsBuffer);
			for (int j = 0; j < fields.Length; j++)
			{
				if (nonDefaultFieldsBuffer[j])
				{
					fields[j].Write(writer);
				}
			}
			writer.Write((byte)unlockables.Length);
			for (int k = 0; k < unlockables.Length; k++)
			{
				writer.Write(unlockables[k]);
			}
		}

		public void Read(NetworkReader reader)
		{
			reader.ReadBitArray(nonDefaultFieldsBuffer);
			for (int i = 0; i < fields.Length; i++)
			{
				if (nonDefaultFieldsBuffer[i])
				{
					fields[i].Read(reader);
				}
			}
			int num = reader.ReadByte();
			AllocateUnlockables(num);
			for (int j = 0; j < num; j++)
			{
				unlockables[j] = reader.ReadUnlockableIndex();
			}
		}

		public void ReadOrSetDefault(NetworkReader reader)
		{
			reader.ReadBitArray(nonDefaultFieldsBuffer);
			for (int i = 0; i < fields.Length; i++)
			{
				if (nonDefaultFieldsBuffer[i])
				{
					fields[i].Read(reader);
				}
				else
				{
					fields[i].SetDefault();
				}
			}
			int num = reader.ReadByte();
			AllocateUnlockables(num);
			for (int j = 0; j < num; j++)
			{
				unlockables[j] = reader.ReadUnlockableIndex();
			}
		}

		public static void GetDelta(StatSheet result, StatSheet newerStats, StatSheet olderStats)
		{
			StatField[] array = result.fields;
			StatField[] array2 = newerStats.fields;
			StatField[] array3 = olderStats.fields;
			int num = array.Length;
			for (int i = 0; i < num; i++)
			{
				if (!array2[i].hasChanged)
				{
					array[i].hasChanged = false;
				}
				else
				{
					array[i] = StatField.GetDelta(ref array2[i], ref array3[i]);
				}
			}
			UnlockableIndex[] array4 = newerStats.unlockables;
			UnlockableIndex[] array5 = olderStats.unlockables;
			int num2 = 0;
			foreach (UnlockableIndex unlockableIndex in array4)
			{
				bool flag = false;
				for (int k = 0; k < array5.Length; k++)
				{
					if (array5[k] == unlockableIndex)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					num2++;
				}
			}
			result.AllocateUnlockables(num2);
			UnlockableIndex[] array6 = result.unlockables;
			int num3 = 0;
			foreach (UnlockableIndex unlockableIndex2 in array4)
			{
				bool flag2 = false;
				for (int m = 0; m < array5.Length; m++)
				{
					if (array5[m] == unlockableIndex2)
					{
						flag2 = true;
						break;
					}
				}
				if (!flag2)
				{
					array6[num3++] = unlockableIndex2;
				}
			}
		}

		public void ApplyDelta(StatSheet deltaSheet)
		{
			StatField[] array = deltaSheet.fields;
			for (int i = 0; i < fields.Length; i++)
			{
				if (array[i].hasChanged)
				{
					fields[i].PushDelta(ref array[i]);
					fields[i].hasChanged = false;
				}
			}
			for (int j = 0; j < deltaSheet.unlockables.Length; j++)
			{
				AddUnlockable(deltaSheet.unlockables[j]);
			}
		}

		public void ClearHasChangedFlags()
		{
			int num = fields.Length;
			for (int i = 0; i < num; i++)
			{
				fields[i].hasChanged = false;
			}
		}

		public void SetAllFieldsToMaxValue()
		{
			for (int i = 0; i < fields.Length; i++)
			{
				fields[i].SetToMaxValue();
			}
		}

		public static void Copy([NotNull] StatSheet src, [NotNull] StatSheet dest)
		{
			Array.Copy(src.fields, dest.fields, src.fields.Length);
			dest.AllocateUnlockables(src.unlockables.Length);
			Array.Copy(src.unlockables, dest.unlockables, src.unlockables.Length);
		}

		public void DebugDisplay(string _prefix = "")
		{
			string text = _prefix + "\n";
			for (int i = 0; i < 5; i++)
			{
				text = text + fields[i].name + ": " + ((fields[i].dataType == StatDataType.ULong) ? ((double)fields[i].GetULongValue()) : fields[i].GetDoubleValue());
			}
		}
	}
}
namespace RoR2.Social
{
	public struct SocialUserId
	{
		public readonly PlatformID steamId;

		public SocialUserId(PlatformID steamId)
		{
			this.steamId = steamId;
		}
	}
}
namespace RoR2.RemoteGameBrowser
{
	public class AdvancedFilterRemoteGameProvider : BaseAsyncRemoteGameProvider
	{
		public new struct SearchFilters : IEquatable<SearchFilters>
		{
			public bool allowPassword;

			public int requiredSlots;

			public int maxPing;

			public int minMaxPlayers;

			public int maxMaxPlayers;

			public bool allowDifficultyEasy;

			public bool allowDifficultyNormal;

			public bool allowDifficultyHard;

			public bool showGamesWithRuleVoting;

			public bool showGamesWithoutRuleVoting;

			public bool allowInProgressGames;

			public bool Equals(SearchFilters other)
			{
				if (allowPassword == other.allowPassword && requiredSlots == other.requiredSlots && maxPing == other.maxPing && minMaxPlayers == other.minMaxPlayers && maxMaxPlayers == other.maxMaxPlayers && allowDifficultyEasy == other.allowDifficultyEasy && allowDifficultyNormal == other.allowDifficultyNormal && allowDifficultyHard == other.allowDifficultyHard && showGamesWithRuleVoting == other.showGamesWithRuleVoting && showGamesWithoutRuleVoting == other.showGamesWithoutRuleVoting)
				{
					return allowInProgressGames == other.allowInProgressGames;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is SearchFilters other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((((((((((((((((((allowPassword.GetHashCode() * 397) ^ requiredSlots) * 397) ^ maxPing) * 397) ^ minMaxPlayers) * 397) ^ maxMaxPlayers) * 397) ^ allowDifficultyEasy.GetHashCode()) * 397) ^ allowDifficultyNormal.GetHashCode()) * 397) ^ allowDifficultyHard.GetHashCode()) * 397) ^ showGamesWithRuleVoting.GetHashCode()) * 397) ^ showGamesWithoutRuleVoting.GetHashCode()) * 397) ^ allowInProgressGames.GetHashCode();
			}
		}

		private IRemoteGameProvider src;

		private new SearchFilters searchFilters;

		public new SearchFilters GetSearchFilters()
		{
			return searchFilters;
		}

		public void SetSearchFilters(SearchFilters newSearchFilters)
		{
			if (!searchFilters.Equals(newSearchFilters))
			{
				searchFilters = newSearchFilters;
				SetDirty();
			}
		}

		protected override Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken)
		{
			RemoteGameInfo[] srcInfo = src.GetKnownGames();
			SearchFilters capturedSearchFilters = searchFilters;
			return new Task<RemoteGameInfo[]>(delegate
			{
				SearchFilters localSearchFilters = capturedSearchFilters;
				bool[] array = new bool[srcInfo.Length];
				int num = 0;
				for (int i = 0; i < srcInfo.Length; i++)
				{
					if (PassesFilters(in srcInfo[i]))
					{
						array[i] = true;
						num++;
					}
				}
				RemoteGameInfo[] array2 = new RemoteGameInfo[num];
				int j = 0;
				int k = 0;
				for (; j < array2.Length; j++)
				{
					for (; !array[k]; k++)
					{
					}
					array2[j] = srcInfo[k++];
				}
				return array2;
				bool PassesFilters(in RemoteGameInfo remoteGameInfo)
				{
					if (!localSearchFilters.allowPassword && remoteGameInfo.hasPassword.GetValueOrDefault(false))
					{
						return false;
					}
					if (localSearchFilters.requiredSlots > 0 && remoteGameInfo.availableSlots < localSearchFilters.requiredSlots)
					{
						return false;
					}
					if (localSearchFilters.maxPing > 0 && remoteGameInfo.ping.HasValue && remoteGameInfo.ping.Value > localSearchFilters.maxPing)
					{
						return false;
					}
					if (localSearchFilters.minMaxPlayers > remoteGameInfo.lesserMaxPlayers)
					{
						return false;
					}
					if (localSearchFilters.maxMaxPlayers < remoteGameInfo.greaterMaxPlayers)
					{
						return false;
					}
					DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(remoteGameInfo.currentDifficultyIndex ?? DifficultyIndex.Invalid);
					if (difficultyDef == null)
					{
						return false;
					}
					if (!localSearchFilters.allowDifficultyEasy && remoteGameInfo.currentDifficultyIndex == DifficultyIndex.Easy)
					{
						return false;
					}
					if (!localSearchFilters.allowDifficultyNormal && remoteGameInfo.currentDifficultyIndex == DifficultyIndex.Normal)
					{
						return false;
					}
					if (!localSearchFilters.allowDifficultyHard && difficultyDef.countsAsHardMode)
					{
						return false;
					}
					if (!localSearchFilters.showGamesWithRuleVoting && remoteGameInfo.HasTag("rv1"))
					{
						return false;
					}
					if (!localSearchFilters.showGamesWithoutRuleVoting && remoteGameInfo.HasTag("rv0"))
					{
						return false;
					}
					if (!localSearchFilters.allowInProgressGames && !string.IsNullOrEmpty(remoteGameInfo.currentSceneName) && !(remoteGameInfo.currentSceneName == "lobby"))
					{
						return false;
					}
					return true;
				}
			});
		}

		public override bool RequestRefresh()
		{
			return src.RequestRefresh();
		}

		public AdvancedFilterRemoteGameProvider([NotNull] IRemoteGameProvider src)
		{
			this.src = src;
			this.src.onNewInfoAvailable += base.SetDirty;
		}

		public override void Dispose()
		{
			src.onNewInfoAvailable -= base.SetDirty;
			base.Dispose();
		}

		public override bool IsBusy()
		{
			if (!base.IsBusy())
			{
				return src?.IsBusy() ?? false;
			}
			return true;
		}
	}
	public class AggregateRemoteGameProvider : BaseAsyncRemoteGameProvider
	{
		private IRemoteGameProvider[] providers = Array.Empty<IRemoteGameProvider>();

		public override void Dispose()
		{
			for (int num = providers.Length - 1; num >= 0; num--)
			{
				OnProviderLost(providers[num]);
			}
			providers = Array.Empty<IRemoteGameProvider>();
			base.Dispose();
		}

		public override bool RequestRefresh()
		{
			IRemoteGameProvider[] array = providers;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].RequestRefresh();
			}
			return true;
		}

		public void AddProvider(IRemoteGameProvider provider)
		{
			ArrayUtils.ArrayAppend(ref providers, in provider);
			OnProviderDiscovered(provider);
			SetDirty();
		}

		public void RemoveProvider(IRemoteGameProvider provider)
		{
			int num = Array.IndexOf(providers, provider);
			if (num != -1)
			{
				RemoveProviderAt(num);
			}
		}

		public void SetProviderAdded(IRemoteGameProvider provider, bool shouldUse)
		{
			int num = Array.IndexOf(providers, provider);
			if (num == -1)
			{
				if (shouldUse)
				{
					AddProvider(provider);
				}
			}
			else if (!shouldUse)
			{
				RemoveProviderAt(num);
			}
		}

		private void RemoveProviderAt(int index)
		{
			OnProviderLost(providers[index]);
			ArrayUtils.ArrayRemoveAtAndResize(ref providers, index);
			SetDirty();
		}

		private void OnProviderDiscovered(IRemoteGameProvider provider)
		{
			provider.onNewInfoAvailable += OnProviderNewInfoAvailable;
		}

		private void OnProviderLost(IRemoteGameProvider provider)
		{
			provider.onNewInfoAvailable -= OnProviderNewInfoAvailable;
		}

		private void OnProviderNewInfoAvailable()
		{
			SetDirty();
		}

		protected override Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken)
		{
			IList<IRemoteGameProvider> providers = this.providers;
			return new Task<RemoteGameInfo[]>(delegate
			{
				cancellationToken.ThrowIfCancellationRequested();
				IEnumerable<RemoteGameInfo>[] array = new IEnumerable<RemoteGameInfo>[providers.Count];
				for (int i = 0; i < providers.Count; i++)
				{
					array[i] = providers[i].GetKnownGames();
				}
				cancellationToken.ThrowIfCancellationRequested();
				int num = 0;
				for (int j = 0; j < providers.Count; j++)
				{
					num += array[j].Count();
				}
				cancellationToken.ThrowIfCancellationRequested();
				RemoteGameInfo[] array2 = new RemoteGameInfo[num];
				int k = 0;
				int num2 = 0;
				for (; k < providers.Count; k++)
				{
					cancellationToken.ThrowIfCancellationRequested();
					RemoteGameInfo[] knownGames = providers[k].GetKnownGames();
					foreach (RemoteGameInfo remoteGameInfo in knownGames)
					{
						array2[num2++] = remoteGameInfo;
					}
				}
				return array2;
			});
		}

		public override bool IsBusy()
		{
			if (!base.IsBusy())
			{
				return IsAnyProviderBusy();
			}
			return true;
			bool IsAnyProviderBusy()
			{
				for (int i = 0; i < providers.Length; i++)
				{
					if (providers[i].IsBusy())
					{
						return true;
					}
				}
				return false;
			}
		}
	}
	public abstract class BaseAsyncRemoteGameProvider : IRemoteGameProvider, IDisposable
	{
		public struct SearchFilters : IEquatable<SearchFilters>
		{
			public bool allowMismatchedMods;

			public bool Equals(SearchFilters other)
			{
				return allowMismatchedMods == other.allowMismatchedMods;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is SearchFilters other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return allowMismatchedMods.GetHashCode();
			}
		}

		protected struct TaskInfo
		{
			public Task task;

			public CancellationTokenSource cancellationTokenSource;

			public int taskNumber;

			public void Cancel()
			{
				cancellationTokenSource.Cancel();
			}
		}

		private RemoteGameInfo[] gameInfos = Array.Empty<RemoteGameInfo>();

		private readonly object gameInfosLock = new object();

		private readonly object isDirtyLock = new object();

		private readonly object disposedLock = new object();

		private readonly List<TaskInfo> activeTasks = new List<TaskInfo>();

		private int taskNumberProvider;

		protected int maxTasks = 2;

		private bool isDirty;

		public bool refreshOnFiltersChanged = true;

		protected SearchFilters searchFilters = new SearchFilters
		{
			allowMismatchedMods = false
		};

		protected bool disposed { get; private set; }

		public event Action onNewInfoAvailable;

		public SearchFilters GetSearchFilters()
		{
			return searchFilters;
		}

		public void SetSearchFilters(SearchFilters newSearchFilters)
		{
			if (!searchFilters.Equals(newSearchFilters))
			{
				searchFilters = newSearchFilters;
				if (refreshOnFiltersChanged)
				{
					RequestRefresh();
				}
				SetDirty();
			}
		}

		protected void SetDirty()
		{
			lock (disposedLock)
			{
				if (disposed)
				{
					return;
				}
				lock (isDirtyLock)
				{
					if (!isDirty)
					{
						isDirty = true;
						RoR2Application.onNextUpdate += DirtyUpdate;
					}
				}
			}
		}

		protected void DirtyUpdate()
		{
			lock (disposedLock)
			{
				if (disposed)
				{
					return;
				}
				lock (activeTasks)
				{
					if (activeTasks.Count >= maxTasks)
					{
						return;
					}
					lock (isDirtyLock)
					{
						isDirty = false;
						GenerateNewTask();
					}
				}
			}
		}

		private void GenerateNewTask()
		{
			CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
			CancellationToken cancellationToken = cancellationTokenSource.Token;
			Task<RemoteGameInfo[]> innerTask = CreateTask(cancellationToken);
			lock (activeTasks)
			{
				Task task = Task.Run(async delegate
				{
					try
					{
						innerTask.Start();
						RemoteGameInfo[] array = await innerTask;
						lock (gameInfosLock)
						{
							cancellationToken.ThrowIfCancellationRequested();
							gameInfos = array;
							lock (activeTasks)
							{
								for (int i = 0; i < activeTasks.Count; i++)
								{
									TaskInfo taskInfo = activeTasks[i];
									if (taskInfo.cancellationTokenSource == cancellationTokenSource)
									{
										OnTaskComplete(taskInfo);
										break;
									}
								}
							}
						}
					}
					finally
					{
						lock (activeTasks)
						{
							for (int num = activeTasks.Count - 1; num >= 0; num--)
							{
								if (activeTasks[num].cancellationTokenSource == cancellationTokenSource)
								{
									activeTasks.RemoveAt(num);
									break;
								}
							}
						}
					}
				}, cancellationToken);
				activeTasks.Add(new TaskInfo
				{
					task = task,
					cancellationTokenSource = cancellationTokenSource,
					taskNumber = taskNumberProvider++
				});
			}
		}

		protected abstract Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken);

		protected void OnTaskComplete(TaskInfo taskInfo)
		{
			lock (activeTasks)
			{
				for (int num = activeTasks.Count - 1; num >= 0; num--)
				{
					if (activeTasks[num].taskNumber < taskInfo.taskNumber)
					{
						activeTasks[num].Cancel();
					}
				}
			}
			this.onNewInfoAvailable?.Invoke();
		}

		public virtual void Dispose()
		{
			lock (disposedLock)
			{
				disposed = true;
				lock (activeTasks)
				{
					foreach (TaskInfo activeTask in activeTasks)
					{
						activeTask.Cancel();
					}
				}
			}
		}

		public abstract bool RequestRefresh();

		public RemoteGameInfo[] GetKnownGames()
		{
			return gameInfos;
		}

		public virtual bool IsBusy()
		{
			return activeTasks.Count > 0;
		}
	}
	public class EOSLobbyRemoteGameProvider : BaseAsyncRemoteGameProvider
	{
		private readonly List<LobbyDetails> lobbyList = new List<LobbyDetails>();

		private int waitingForLobbyCount;

		private static readonly char[] tagsSeparator = new char[1] { ',' };

		private EOSLobbyManager.Filter BuildFilter()
		{
			EOSLobbyManager.Filter filter = new EOSLobbyManager.Filter();
			if (!searchFilters.allowMismatchedMods)
			{
				AttributeData attributeData = default(AttributeData);
				attributeData.Key = "_mh";
				attributeData.Value = NetworkModCompatibilityHelper.networkModHash;
				AttributeData item = attributeData;
				filter.SearchData.Add(item);
			}
			return filter;
		}

		public override bool RequestRefresh()
		{
			EOSLobbyManager.Filter filter = BuildFilter();
			bool num = (PlatformSystems.lobbyManager as EOSLobbyManager).RequestLobbyList(this, filter, OnLobbyListReceived);
			if (num)
			{
				waitingForLobbyCount++;
			}
			return num;
		}

		private void OnLobbyListReceived(List<LobbyDetails> lobbies)
		{
			if (base.disposed)
			{
				return;
			}
			waitingForLobbyCount--;
			lock (lobbyList)
			{
				lobbyList.Clear();
				lobbyList.AddRange(lobbies);
				SetDirty();
			}
		}

		protected override Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken)
		{
			LobbyDetails[] lobbies;
			lock (lobbyList)
			{
				lobbies = lobbyList.ToArray();
			}
			return new Task<RemoteGameInfo[]>(delegate
			{
				RemoteGameInfo[] array = new RemoteGameInfo[lobbies.Length];
				for (int i = 0; i < lobbies.Length; i++)
				{
					CreateRemoteGameInfo(lobbies[i], out array[i]);
				}
				return array;
			}, cancellationToken);
		}

		private static void CreateRemoteGameInfo(LobbyDetails lobby, out RemoteGameInfo result)
		{
			result = default(RemoteGameInfo);
			LobbyDetailsCopyInfoOptions options = default(LobbyDetailsCopyInfoOptions);
			if (lobby.CopyInfo(ref options, out var outLobbyDetailsInfo) == Result.Success)
			{
				result.name = outLobbyDetailsInfo.Value.LobbyOwnerUserId.ToString();
				result.lobbyName = outLobbyDetailsInfo.Value.LobbyId;
				result.lobbyIdStr = outLobbyDetailsInfo.Value.LobbyId;
				string lobbyStringValue = EOSLobbyManager.GetLobbyStringValue(lobby, "_map");
				result.serverIdStr = EOSLobbyManager.GetLobbyStringValue(lobby, "server_id");
				result.serverAddress = GetAddressPortPair("server_address");
				result.serverName = EOSLobbyManager.GetLobbyStringValue(lobby, "_svnm");
				result.lobbyPlayerCount = GetInt("player_count", 1, int.MaxValue) ?? 1;
				result.lobbyMaxPlayers = GetInt("total_max_players", 1, int.MaxValue) ?? 1;
				result.serverPlayerCount = GetInt("_svplc", 0, int.MaxValue);
				result.serverMaxPlayers = GetInt("_svmpl", 0, int.MaxValue);
				result.inGame = result.IsServerIdValid() || result.serverAddress.HasValue;
				result.currentSceneName = lobbyStringValue;
				if (lobbyStringValue != null)
				{
					result.currentSceneIndex = SceneCatalog.GetSceneDefFromSceneName(lobbyStringValue)?.sceneDefIndex;
				}
				result.requestRefreshImplementation = RemoteGameInfoRequestRefresh;
				result.getPlayersImplementation = RemoteGameInfoGetPlayers;
				result.getRuleBookImplementation = RemoteGameInfoGetRuleBook;
				result.userData = lobby;
				result.hasPassword = GetBool("_pw");
				result.gameModeName = EOSLobbyManager.GetLobbyStringValue(lobby, "_svgm");
				result.buildId = EOSLobbyManager.GetLobbyStringValue(lobby, "build_id") ?? "UNKNOWN";
				result.modHash = EOSLobbyManager.GetLobbyStringValue(lobby, "_mh") ?? "UNKNOWN";
				result.SetTags(GetTags("_svtags"));
				result.CalcExtraFields();
			}
			AddressPortPair? GetAddressPortPair(string key)
			{
				if (!AddressPortPair.TryParse(EOSLobbyManager.GetLobbyStringValue(lobby, key), out var addressPortPair))
				{
					return null;
				}
				return addressPortPair;
			}
			bool? GetBool(string key)
			{
				return GetInt(key, int.MinValue, int.MaxValue) > 0;
			}
			int? GetInt(string key, int min, int max)
			{
				if (int.TryParse(EOSLobbyManager.GetLobbyStringValue(lobby, key), out var result2) && min <= result2 && result2 <= max)
				{
					return result2;
				}
				return null;
			}
			string[] GetTags(string key)
			{
				return EOSLobbyManager.GetLobbyStringValue(lobby, key)?.Split(tagsSeparator, StringSplitOptions.None);
			}
		}

		private static void RemoteGameInfoRequestRefresh(in RemoteGameInfo remoteGameInfo, RemoteGameInfo.RequestRefreshSuccessCallback successCallback, Action failureCallback, bool fetchDetails)
		{
			if (remoteGameInfo.userData is LobbyDetails)
			{
				CreateRemoteGameInfo(remoteGameInfo.userData as LobbyDetails, out var result);
				successCallback?.Invoke(in result);
			}
		}

		private static bool RemoteGameInfoGetRuleBook(in RemoteGameInfo remoteGameInfo, RuleBook dest)
		{
			if (remoteGameInfo.userData is LobbyDetails lobbyDetails)
			{
				KeyValueUnsplitter keyValueUnsplitter = new KeyValueUnsplitter("rulebook");
				List<KeyValuePair<string, string>> list = CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.RentCollection();
				try
				{
					LobbyDetailsGetAttributeCountOptions options = default(LobbyDetailsGetAttributeCountOptions);
					uint num = 0u;
					for (uint attributeCount = lobbyDetails.GetAttributeCount(ref options); num < attributeCount; num++)
					{
						LobbyDetailsCopyAttributeByIndexOptions lobbyDetailsCopyAttributeByIndexOptions = default(LobbyDetailsCopyAttributeByIndexOptions);
						lobbyDetailsCopyAttributeByIndexOptions.AttrIndex = num;
						LobbyDetailsCopyAttributeByIndexOptions options2 = lobbyDetailsCopyAttributeByIndexOptions;
						if (lobbyDetails.CopyAttributeByIndex(ref options2, out var outAttribute) == Result.Success)
						{
							AttributeData value = outAttribute.Value.Data.Value;
							list.Add(new KeyValuePair<string, string>(value.Key.ToString().ToLower(), value.Value.AsUtf8.ToString().ToLower()));
						}
					}
					string value2 = keyValueUnsplitter.GetValue(list);
					if (!string.IsNullOrEmpty(value2))
					{
						RuleBook.ReadBase64(value2, dest);
						return true;
					}
				}
				finally
				{
					list = CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.ReturnCollection(list);
				}
			}
			return false;
		}

		private static void RemoteGameInfoGetPlayers(in RemoteGameInfo remoteGameInfo, List<RemotePlayerInfo> output)
		{
			if (remoteGameInfo.userData is LobbyDetails lobbyDetails)
			{
				LobbyDetailsGetMemberCountOptions options = default(LobbyDetailsGetMemberCountOptions);
				uint memberCount = lobbyDetails.GetMemberCount(ref options);
				for (uint num = 0u; num < memberCount; num++)
				{
					output.Add(new RemotePlayerInfo
					{
						id = 0uL,
						name = "???"
					});
				}
			}
		}

		public override bool IsBusy()
		{
			if (!base.IsBusy())
			{
				return waitingForLobbyCount > 0;
			}
			return true;
		}
	}
	public interface IRemoteGameProvider
	{
		event Action onNewInfoAvailable;

		bool RequestRefresh();

		RemoteGameInfo[] GetKnownGames();

		bool IsBusy();
	}
	public class PageRemoteGameProvider : BaseAsyncRemoteGameProvider
	{
		private int gamesPerPage = 1;

		private int pageIndex;

		private int maxPages;

		private readonly IRemoteGameProvider source;

		public PageRemoteGameProvider([NotNull] IRemoteGameProvider source)
		{
			this.source = source;
			source.onNewInfoAvailable += OnSourceNewInfoAvailable;
			maxTasks = 1;
		}

		public override void Dispose()
		{
			source.onNewInfoAvailable -= OnSourceNewInfoAvailable;
			base.Dispose();
		}

		private void OnSourceNewInfoAvailable()
		{
			SetDirty();
		}

		public void SetGamesPerPage(int newGamesPerPage)
		{
			if (newGamesPerPage < 1)
			{
				newGamesPerPage = 1;
			}
			if (newGamesPerPage != gamesPerPage)
			{
				gamesPerPage = newGamesPerPage;
				SetDirty();
			}
		}

		public bool CanGoToNextPage()
		{
			return pageIndex + 1 < maxPages;
		}

		public bool CanGoToPreviousPage()
		{
			return pageIndex - 1 >= 0;
		}

		public bool GoToNextPage()
		{
			lock (this)
			{
				if (!CanGoToNextPage())
				{
					return false;
				}
				pageIndex++;
				SetDirty();
				return true;
			}
		}

		public bool GoToPreviousPage()
		{
			lock (this)
			{
				if (!CanGoToPreviousPage())
				{
					return false;
				}
				pageIndex--;
				SetDirty();
				return true;
			}
		}

		public void GetCurrentPageInfo(out int pageIndex, out int maxPages)
		{
			lock (this)
			{
				pageIndex = this.pageIndex;
				maxPages = this.maxPages;
			}
		}

		protected override Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken)
		{
			return new Task<RemoteGameInfo[]>(delegate
			{
				RemoteGameInfo[] knownGames = source.GetKnownGames();
				lock (this)
				{
					maxPages = (knownGames.Length + gamesPerPage - 1) / gamesPerPage;
					pageIndex = Math.Max(Math.Min(pageIndex, maxPages - 1), 0);
					int num = Math.Min(gamesPerPage * pageIndex, knownGames.Length);
					int num2 = Mathf.Min(num + gamesPerPage, knownGames.Length);
					if (num2 == num)
					{
						return Array.Empty<RemoteGameInfo>();
					}
					RemoteGameInfo[] array = new RemoteGameInfo[num2 - num];
					int i = num;
					int num3 = 0;
					for (; i < num2; i++)
					{
						array[num3++] = knownGames[i];
					}
					return array;
				}
			});
		}

		public override bool RequestRefresh()
		{
			return source.RequestRefresh();
		}

		public override bool IsBusy()
		{
			if (!base.IsBusy())
			{
				return source?.IsBusy() ?? false;
			}
			return true;
		}
	}
	public class RemoteGameBrowserController : MonoBehaviour
	{
		private class FilterInfo
		{
			public RemoteGameFilterValue value;

			public string token;

			public Func<Component, RemoteGameFilterValue?> getUIValue;

			public Action<Component, RemoteGameFilterValue> setUIValue;

			public GameObject controlGameObject;

			public Component controlMainComponent;

			public LanguageTextMeshController labelController;
		}

		private class FilterManager
		{
			[MeansImplicitUse(ImplicitUseKindFlags.Assign)]
			private class SetupAttribute : System.Attribute
			{
				public RemoteGameFilterValue defaultValue;

				public int minValue;

				public int maxValue;

				public SetupAttribute(bool defaultValue)
				{
					this.defaultValue = defaultValue;
				}

				public SetupAttribute(int defaultValue, int minValue = int.MinValue, int maxValue = int.MaxValue)
				{
					this.defaultValue = defaultValue;
					this.minValue = minValue;
					this.maxValue = maxValue;
				}

				public SetupAttribute(string defaultValue)
				{
					this.defaultValue = defaultValue;
				}
			}

			public readonly RemoteGameBrowserController owner;

			private RectTransform currentContainer;

			public List<FilterInfo> allFilters = new List<FilterInfo>();

			[Setup(true)]
			public FilterInfo showDedicatedServers;

			[Setup(true)]
			public FilterInfo showLobbies;

			[Setup(true)]
			public FilterInfo showDifficultyEasyGames;

			[Setup(true)]
			public FilterInfo showDifficultyNormalGames;

			[Setup(true)]
			public FilterInfo showDifficultyHardGames;

			[Setup(true)]
			public FilterInfo showGamesWithRuleVoting;

			[Setup(true)]
			public FilterInfo showGamesWithoutRuleVoting;

			[Setup(true)]
			public FilterInfo showPasswordedGames;

			[Setup(0, int.MinValue, int.MaxValue, minValue = 0, maxValue = 999)]
			public FilterInfo maxPing;

			[Setup(false)]
			public FilterInfo mustHavePlayers;

			[Setup(true)]
			public FilterInfo mustHaveEnoughSlots;

			[Setup(1, int.MinValue, int.MaxValue, minValue = 1)]
			public FilterInfo minMaxPlayers;

			[Setup(16, int.MinValue, int.MaxValue, minValue = 1)]
			public FilterInfo maxMaxPlayers;

			[Setup("")]
			public FilterInfo requiredTags;

			[Setup("")]
			public FilterInfo forbiddenTags;

			[Setup(false)]
			public FilterInfo showStartedGames;

			[Setup(true)]
			public FilterInfo hideIncompatibleGames;

			public FilterManager(RemoteGameBrowserController owner)
			{
				this.owner = owner;
				currentContainer = owner.filterControlContainer;
				GenerateFilters();
			}

			private FilterInfo AddFilter<T>(string token, RemoteGameFilterValue defaultValue, GameObject controlPrefab, Func<Component, RemoteGameFilterValue?> getUIValue, Action<Component, RemoteGameFilterValue> setUIValue) where T : Component
			{
				FilterInfo filterInfo = new FilterInfo
				{
					token = token,
					value = defaultValue,
					controlGameObject = UnityEngine.Object.Instantiate(controlPrefab, currentContainer),
					getUIValue = getUIValue,
					setUIValue = setUIValue
				};
				filterInfo.controlMainComponent = filterInfo.controlGameObject.transform.Find("MainControl").GetComponent<T>();
				filterInfo.labelController = filterInfo.controlGameObject.transform.Find("NameLabel").GetComponent<LanguageTextMeshController>();
				filterInfo.controlGameObject.SetActive(value: true);
				filterInfo.setUIValue(filterInfo.controlMainComponent, defaultValue);
				allFilters.Add(filterInfo);
				return filterInfo;
			}

			private FilterInfo AddBoolFilter(string token, bool defaultValue)
			{
				return AddFilter<MPToggle>(token, defaultValue, owner.togglePrefab, GetUIValue, SetUIValue);
				static RemoteGameFilterValue? GetUIValue(Component c)
				{
					return ((MPToggle)c).isOn;
				}
				static void SetUIValue(Component c, RemoteGameFilterValue value)
				{
					((MPToggle)c).isOn = value.boolValue;
				}
			}

			private FilterInfo AddIntFilter(string token, int defaultValue, int minValue = int.MinValue, int maxValue = int.MaxValue, uint minDigits = 1u, uint maxDigits = uint.MaxValue)
			{
				FilterInfo filterInfo = AddFilter<TMP_InputField>(token, defaultValue, owner.textFieldPrefab, GetUIValue, SetUIValue);
				((TMP_InputField)filterInfo.controlMainComponent).characterValidation = TMP_InputField.CharacterValidation.Integer;
				return filterInfo;
				RemoteGameFilterValue? GetUIValue(Component c)
				{
					if (int.TryParse(((TMP_InputField)c).text, out var result))
					{
						return Mathf.Clamp(result, minValue, maxValue);
					}
					return null;
				}
				void SetUIValue(Component c, RemoteGameFilterValue v)
				{
					StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
					stringBuilder.AppendInt(v.intValue, minDigits, maxDigits);
					((TMP_InputField)c).SetTextWithoutNotify(stringBuilder.ToString());
					HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
				}
			}

			private FilterInfo AddStringFilter(string token, string defaultValue)
			{
				return AddFilter<TMP_InputField>(token, defaultValue, owner.textFieldPrefab, GetUIValue, SetUIValue);
				static RemoteGameFilterValue? GetUIValue(Component c)
				{
					return ((TMP_InputField)c).text;
				}
				static void SetUIValue(Component c, RemoteGameFilterValue v)
				{
					((TMP_InputField)c).SetTextWithoutNotify(v.stringValue);
				}
			}

			private void GenerateFilters()
			{
				Regex regex = new Regex("([A-Z]?[a-z]+)");
				FieldInfo[] fields = typeof(FilterManager).GetFields();
				foreach (FieldInfo fieldInfo in fields)
				{
					if (fieldInfo.FieldType != typeof(FilterInfo))
					{
						continue;
					}
					SetupAttribute customAttribute = CustomAttributeExtensions.GetCustomAttribute<SetupAttribute>(fieldInfo);
					if (customAttribute == null)
					{
						return;
					}
					string name = fieldInfo.Name;
					StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
					stringBuilder.Append("GAME_BROWSER_FILTER");
					foreach (Match item in regex.Matches(name))
					{
						stringBuilder.Append("_");
						for (int j = 0; j < item.Length; j++)
						{
							stringBuilder.Append(char.ToUpperInvariant(name[item.Index + j]));
						}
					}
					string token = stringBuilder.ToString();
					HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
					FilterInfo filterInfo = null;
					filterInfo = customAttribute.defaultValue.valueType switch
					{
						RemoteGameFilterValue.ValueType.Bool => AddBoolFilter(token, customAttribute.defaultValue.boolValue), 
						RemoteGameFilterValue.ValueType.Int => AddIntFilter(token, customAttribute.defaultValue.intValue, customAttribute.minValue, customAttribute.maxValue), 
						RemoteGameFilterValue.ValueType.String => AddStringFilter(token, customAttribute.defaultValue.stringValue), 
						_ => throw new ArgumentOutOfRangeException(), 
					};
					fieldInfo.SetValue(this, filterInfo);
					filterInfo.labelController.token = filterInfo.token;
				}
				CopyInternalValuesToUI();
			}

			public void CopyInternalValuesToUI()
			{
				foreach (FilterInfo allFilter in allFilters)
				{
					allFilter.setUIValue(allFilter.controlMainComponent, allFilter.value);
				}
			}

			public void CopyUIValuesToInternal()
			{
				foreach (FilterInfo allFilter in allFilters)
				{
					allFilter.value = allFilter.getUIValue(allFilter.controlMainComponent) ?? allFilter.value;
				}
			}
		}

		public GameObject cardPrefab;

		public RectTransform cardContainer;

		public MPButton previousPageButton;

		public MPButton nextPageButton;

		public HGTextMeshProUGUI pageNumberLabel;

		public GameObject togglePrefab;

		public GameObject textFieldPrefab;

		public RectTransform filterControlContainer;

		public MPDropdown sortTypeDropdown;

		public MPToggle sortAscendToggle;

		public Graphic busyIcon;

		private UIElementAllocator<RemoteGameCardController> cardAllocator;

		private bool displayDataDirty;

		private float cardPrefabHeight = 1f;

		private float initialRequestTime = float.PositiveInfinity;

		private IRemoteGameProvider primaryRemoteGameProvider;

		private PageRemoteGameProvider pageRemoteGameProvider;

		private SortRemoteGameProvider sortRemoteGameProvider;

		private AdvancedFilterRemoteGameProvider advancedFilterRemoteGameProvider;

		private AggregateRemoteGameProvider aggregateRemoteGameProvider;

		private SteamworksServerRemoteGameProvider serverRemoteGameProvider;

		private BaseAsyncRemoteGameProvider lobbyRemoteGameProvider;

		private FilterManager filters;

		private void Awake()
		{
			cardAllocator = new UIElementAllocator<RemoteGameCardController>(cardContainer, cardPrefab);
			serverRemoteGameProvider = new SteamworksServerRemoteGameProvider(SteamworksServerRemoteGameProvider.Mode.Internet)
			{
				refreshOnFiltersChanged = true
			};
			if (PlatformSystems.ShouldUseEpicOnlineSystems)
			{
				lobbyRemoteGameProvider = new EOSLobbyRemoteGameProvider();
			}
			else
			{
				lobbyRemoteGameProvider = new SteamworksLobbyRemoteGameProvider();
			}
			aggregateRemoteGameProvider = new AggregateRemoteGameProvider();
			advancedFilterRemoteGameProvider = new AdvancedFilterRemoteGameProvider(aggregateRemoteGameProvider);
			sortRemoteGameProvider = new SortRemoteGameProvider(advancedFilterRemoteGameProvider);
			pageRemoteGameProvider = new PageRemoteGameProvider(sortRemoteGameProvider);
			primaryRemoteGameProvider = pageRemoteGameProvider;
			primaryRemoteGameProvider.onNewInfoAvailable += OnNewInfoAvailable;
			previousPageButton.onClick.AddListener(OnPreviousPageButtonClick);
			nextPageButton.onClick.AddListener(OnNextPageButtonClick);
			cardPrefabHeight = cardPrefab.GetComponent<LayoutElement>().preferredHeight;
		}

		private void Start()
		{
			filters = new FilterManager(this);
			initialRequestTime = Time.unscaledTime + 0.2f;
		}

		private void Update()
		{
			if (Input.GetKeyDown(KeyCode.F5) || initialRequestTime <= Time.unscaledTime)
			{
				initialRequestTime = float.PositiveInfinity;
				RequestRefresh();
			}
			UpdateSearchFiltersInternal();
			UpdateSorting();
			float height = cardContainer.rect.height;
			float num = cardPrefabHeight;
			int gamesPerPage = Mathf.FloorToInt(height / num);
			pageRemoteGameProvider.SetGamesPerPage(gamesPerPage);
			previousPageButton.interactable = pageRemoteGameProvider.CanGoToPreviousPage();
			nextPageButton.interactable = pageRemoteGameProvider.CanGoToNextPage();
			if (displayDataDirty)
			{
				SetDisplayData(primaryRemoteGameProvider.GetKnownGames());
			}
			UpdateBusyIcon();
		}

		private void OnDestroy()
		{
			pageRemoteGameProvider.Dispose();
			sortRemoteGameProvider.Dispose();
			advancedFilterRemoteGameProvider.Dispose();
			aggregateRemoteGameProvider.Dispose();
			lobbyRemoteGameProvider.Dispose();
			serverRemoteGameProvider.Dispose();
		}

		private void OnEnable()
		{
			primaryRemoteGameProvider.RequestRefresh();
			RebuildSortTypeDropdown();
		}

		private void OnPreviousPageButtonClick()
		{
			pageRemoteGameProvider.GoToPreviousPage();
		}

		private void OnNextPageButtonClick()
		{
			pageRemoteGameProvider.GoToNextPage();
		}

		public void RequestRefresh()
		{
			primaryRemoteGameProvider.RequestRefresh();
		}

		private void OnNewInfoAvailable()
		{
			displayDataDirty = true;
		}

		private void SetDisplayData(IList<RemoteGameInfo> remoteGameInfos)
		{
			displayDataDirty = false;
			cardAllocator.AllocateElements(remoteGameInfos.Count);
			ReadOnlyCollection<RemoteGameCardController> elements = cardAllocator.elements;
			for (int i = 0; i < elements.Count; i++)
			{
				elements[i].SetDisplayData(remoteGameInfos[i]);
			}
			if ((bool)pageNumberLabel)
			{
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				pageRemoteGameProvider.GetCurrentPageInfo(out var pageIndex, out var maxPages);
				stringBuilder.AppendInt(pageIndex + 1).Append("/").AppendInt(Math.Max(maxPages, 1));
				pageNumberLabel.SetText(stringBuilder);
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			}
		}

		private void UpdateSearchFiltersInternal()
		{
			filters.CopyUIValuesToInternal();
			if (!PlatformSystems.ShouldUseEpicOnlineSystems)
			{
				aggregateRemoteGameProvider.SetProviderAdded(serverRemoteGameProvider, filters.showDedicatedServers.value.boolValue);
				SteamworksServerRemoteGameProvider.SearchFilters searchFilters = serverRemoteGameProvider.GetSearchFilters();
				searchFilters.allowDedicatedServers = filters.showDedicatedServers.value.boolValue;
				searchFilters.allowListenServers = true;
				searchFilters.mustNotBeFull = filters.mustHaveEnoughSlots.value.boolValue;
				searchFilters.mustHavePlayers = filters.mustHavePlayers.value.boolValue;
				searchFilters.requiredTags = filters.requiredTags.value.stringValue;
				searchFilters.forbiddenTags = filters.forbiddenTags.value.stringValue;
				searchFilters.allowInProgressGames = filters.showStartedGames.value.boolValue;
				searchFilters.allowMismatchedMods = !filters.hideIncompatibleGames.value.boolValue;
				serverRemoteGameProvider.SetSearchFilters(searchFilters);
			}
			aggregateRemoteGameProvider.SetProviderAdded(lobbyRemoteGameProvider, filters.showLobbies.value.boolValue);
			BaseAsyncRemoteGameProvider.SearchFilters searchFilters2 = lobbyRemoteGameProvider.GetSearchFilters();
			searchFilters2.allowMismatchedMods = !filters.hideIncompatibleGames.value.boolValue;
			lobbyRemoteGameProvider.SetSearchFilters(searchFilters2);
			int requiredSlots = 0;
			if (!filters.mustHaveEnoughSlots.value.boolValue && PlatformSystems.lobbyManager.calculatedTotalPlayerCount > 0)
			{
				requiredSlots = PlatformSystems.lobbyManager.calculatedTotalPlayerCount;
			}
			AdvancedFilterRemoteGameProvider.SearchFilters searchFilters3 = advancedFilterRemoteGameProvider.GetSearchFilters();
			searchFilters3.allowPassword = filters.showPasswordedGames.value.boolValue;
			searchFilters3.minMaxPlayers = filters.minMaxPlayers.value.intValue;
			searchFilters3.maxMaxPlayers = filters.maxMaxPlayers.value.intValue;
			searchFilters3.maxPing = filters.maxPing.value.intValue;
			searchFilters3.requiredSlots = requiredSlots;
			searchFilters3.allowDifficultyEasy = filters.showDifficultyEasyGames.value.boolValue;
			searchFilters3.allowDifficultyNormal = filters.showDifficultyNormalGames.value.boolValue;
			searchFilters3.allowDifficultyHard = filters.showDifficultyHardGames.value.boolValue;
			searchFilters3.showGamesWithRuleVoting = filters.showGamesWithRuleVoting.value.boolValue;
			searchFilters3.showGamesWithoutRuleVoting = filters.showGamesWithoutRuleVoting.value.boolValue;
			searchFilters3.allowInProgressGames = filters.showStartedGames.value.boolValue;
			advancedFilterRemoteGameProvider.SetSearchFilters(searchFilters3);
		}

		private void RebuildSortTypeDropdown()
		{
			List<string> list = CollectionPool<string, List<string>>.RentCollection();
			sortTypeDropdown.ClearOptions();
			for (int i = 0; i < SortRemoteGameProvider.sorters.Length; i++)
			{
				list.Add(Language.GetString(SortRemoteGameProvider.sorters[i].nameToken));
			}
			sortTypeDropdown.AddOptions(list);
			SortRemoteGameProvider.Parameters parameters = sortRemoteGameProvider.GetParameters();
			sortTypeDropdown.SetValueWithoutNotify(parameters.sorterIndex);
			CollectionPool<string, List<string>>.ReturnCollection(list);
		}

		private void UpdateSorting()
		{
			SortRemoteGameProvider.Parameters parameters = sortRemoteGameProvider.GetParameters();
			parameters.ascending = sortAscendToggle.isOn;
			parameters.sorterIndex = sortTypeDropdown.value;
			sortRemoteGameProvider.SetParameters(parameters);
		}

		private void UpdateBusyIcon()
		{
			if ((bool)busyIcon)
			{
				UnityEngine.Color color = busyIcon.color;
				float num = 1f;
				if (!primaryRemoteGameProvider.IsBusy())
				{
					num = color.a - Time.unscaledDeltaTime;
				}
				if (num != color.a)
				{
					color.a = num;
					busyIcon.color = color;
				}
			}
		}

		[ContextMenu("Copy Filter Tokens")]
		private void CopyFilterTokens()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (FilterInfo allFilter in filters.allFilters)
			{
				stringBuilder.Append('"').Append(allFilter.token).Append('"')
					.Append(": \"\",")
					.AppendLine();
			}
			GUIUtility.systemCopyBuffer = stringBuilder.ToString();
		}
	}
	public class RemoteGameCardController : MonoBehaviour
	{
		public TextMeshProUGUI nameLabel;

		public TextMeshProUGUI playerCountLabel;

		public TextMeshProUGUI pingLabel;

		public TextMeshProUGUI tagsLabel;

		public TextMeshProUGUI typeLabel;

		public ArtifactDisplayPanelController artifactDisplayPanelController;

		public RawImage mapImage;

		public GameObject passwordIconObject;

		public GameObject difficultyIconObject;

		public UnityEngine.UI.Image difficultyIcon;

		private static List<ArtifactDef> artifactBuffer = new List<ArtifactDef>();

		private RemoteGameInfo currentGameInfo;

		public void OpenCurrentGameDetails()
		{
			RectTransform parent = (RectTransform)RoR2Application.instance.mainCanvas.transform;
			GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/RemoteGameBrowser/RemoteGameDetailsPanel"), parent);
			RectTransform obj2 = (RectTransform)obj.transform;
			UnityEngine.Vector2 vector = -(obj2.rect.size / 2f);
			vector.y = 0f - vector.y;
			obj2.localPosition = UnityEngine.Vector2.zero + vector;
			obj.GetComponent<RemoteGameDetailsPanelController>().SetGameInfo(currentGameInfo);
		}

		public void SetDisplayData(RemoteGameInfo remoteGameInfo)
		{
			currentGameInfo = remoteGameInfo;
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			Texture texture = null;
			if (remoteGameInfo.currentSceneIndex.HasValue)
			{
				texture = SceneCatalog.GetSceneDef(remoteGameInfo.currentSceneIndex.Value)?.previewTexture;
			}
			mapImage.enabled = texture != null;
			mapImage.texture = texture;
			passwordIconObject.SetActive(remoteGameInfo.hasPassword.GetValueOrDefault());
			playerCountLabel.SetText(stringBuilder.Clear().AppendInt(remoteGameInfo.lobbyPlayerCount ?? remoteGameInfo.serverPlayerCount.GetValueOrDefault()).Append("/")
				.AppendInt(remoteGameInfo.lobbyMaxPlayers ?? remoteGameInfo.serverMaxPlayers.GetValueOrDefault()));
			if (remoteGameInfo.currentDifficultyIndex.HasValue)
			{
				DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(remoteGameInfo.currentDifficultyIndex.Value);
				difficultyIcon.sprite = difficultyDef?.GetIconSprite();
				difficultyIcon.enabled = true;
			}
			else
			{
				difficultyIcon.enabled = false;
			}
			nameLabel.SetText(remoteGameInfo.serverName ?? remoteGameInfo.lobbyName);
			stringBuilder.Clear();
			if (remoteGameInfo.ping.HasValue)
			{
				stringBuilder.AppendInt(remoteGameInfo.ping ?? (-1));
			}
			else
			{
				stringBuilder.Append("N/A");
			}
			pingLabel.SetText(stringBuilder);
			stringBuilder.Clear();
			if (remoteGameInfo.tags != null && remoteGameInfo.tags.Length != 0)
			{
				stringBuilder.Append(remoteGameInfo.tags[0]);
				for (int i = 1; i < remoteGameInfo.tags.Length; i++)
				{
					stringBuilder.Append(", ").Append(remoteGameInfo.tags[i]);
				}
			}
			tagsLabel.SetText(stringBuilder);
			artifactBuffer.Clear();
			foreach (ArtifactDef enabledArtifact in remoteGameInfo.GetEnabledArtifacts())
			{
				artifactBuffer.Add(enabledArtifact);
			}
			List<ArtifactDef>.Enumerator enabledArtifacts = artifactBuffer.GetEnumerator();
			if ((bool)artifactDisplayPanelController)
			{
				artifactDisplayPanelController.SetDisplayData(ref enabledArtifacts);
			}
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}
	}
	public struct RemoteGameFilterValue
	{
		public enum ValueType
		{
			Bool,
			Int,
			String
		}

		public readonly ValueType valueType;

		public readonly int intValue;

		public readonly string stringValue;

		public bool boolValue => intValue != 0;

		public RemoteGameFilterValue(bool boolValue)
		{
			valueType = ValueType.Bool;
			intValue = (boolValue ? 1 : 0);
			stringValue = null;
		}

		public RemoteGameFilterValue(int intValue)
		{
			valueType = ValueType.Int;
			this.intValue = intValue;
			stringValue = null;
		}

		public RemoteGameFilterValue(string stringValue)
		{
			valueType = ValueType.String;
			intValue = 0;
			this.stringValue = stringValue;
		}

		public static implicit operator RemoteGameFilterValue(bool boolValue)
		{
			return new RemoteGameFilterValue(boolValue);
		}

		public static implicit operator RemoteGameFilterValue(int intValue)
		{
			return new RemoteGameFilterValue(intValue);
		}

		public static implicit operator RemoteGameFilterValue(string stringValue)
		{
			return new RemoteGameFilterValue(stringValue);
		}
	}
	public struct RemoteGameInfo
	{
		public delegate void GetPlayersDelegate(in RemoteGameInfo remoteGameInfo, [NotNull] List<RemotePlayerInfo> output);

		public delegate void RequestRefreshDelegate(in RemoteGameInfo remoteGameInfo, [CanBeNull] RequestRefreshSuccessCallback successCallback, [CanBeNull] Action failureCallback, bool fetchDetails);

		public delegate void RequestRefreshSuccessCallback(in RemoteGameInfo remoteGameInfo);

		public delegate bool GetRuleBookDelegate(in RemoteGameInfo remoteGameInfo, RuleBook dest);

		public struct ArtifactEnumerator : IEnumerator<ArtifactDef>, IEnumerator, IDisposable
		{
			public readonly string tagSource;

			private int readPos;

			public ArtifactDef Current => ArtifactCatalog.GetArtifactDef((ArtifactIndex)(tagSource[readPos] - 48));

			object IEnumerator.Current => Current;

			public ArtifactEnumerator(string tagSource)
			{
				this.tagSource = tagSource;
				readPos = 1;
			}

			public bool MoveNext()
			{
				readPos++;
				return readPos < tagSource.Length;
			}

			public void Reset()
			{
				readPos = 1;
			}

			public void Dispose()
			{
			}
		}

		public struct ArtifactEnumerable
		{
			public readonly string tagSource;

			public ArtifactEnumerable(string tagSource)
			{
				this.tagSource = tagSource;
			}

			public ArtifactEnumerator GetEnumerator()
			{
				ArtifactEnumerator result = new ArtifactEnumerator(tagSource);
				result.Reset();
				return result;
			}
		}

		public float retrievalTime;

		[CanBeNull]
		public string name;

		[CanBeNull]
		public string modHash;

		[CanBeNull]
		public string buildId;

		[CanBeNull]
		public string serverName;

		[CanBeNull]
		public string lobbyName;

		public string lobbyIdStr;

		public ulong? lobbyId;

		public string serverIdStr;

		public ulong? serverId;

		public AddressPortPair? serverAddress;

		public int? ping;

		public string currentSceneName;

		public SceneIndex? currentSceneIndex;

		public DifficultyIndex? currentDifficultyIndex;

		public int? lobbyPlayerCount;

		public int? lobbyMaxPlayers;

		public int? serverPlayerCount;

		public int? serverMaxPlayers;

		public bool? hasPassword;

		[CanBeNull]
		public string gameModeName;

		public bool? inGame;

		public bool? joinable;

		public bool? isBlacklisted;

		public bool? isFavorite;

		public bool? didRespond;

		[CanBeNull]
		public object userData;

		[CanBeNull]
		public GetPlayersDelegate getPlayersImplementation;

		[CanBeNull]
		public RequestRefreshDelegate requestRefreshImplementation;

		[CanBeNull]
		public GetRuleBookDelegate getRuleBookImplementation;

		public int availableSlots;

		public int availableLobbySlots;

		public int availableServerSlots;

		public int lesserPlayerCount;

		public int greaterPlayerCount;

		public int lesserMaxPlayers;

		public int greaterMaxPlayers;

		[CanBeNull]
		public string[] tags { get; private set; }

		public bool IsLobbyIdValid()
		{
			if (lobbyIdStr == null || !(lobbyIdStr != string.Empty))
			{
				return lobbyId.HasValue;
			}
			return true;
		}

		public bool IsServerIdValid()
		{
			if (serverIdStr == null || !(lobbyIdStr != string.Empty))
			{
				return serverId.HasValue;
			}
			return true;
		}

		public void GetPlayers(List<RemotePlayerInfo> output)
		{
			getPlayersImplementation?.Invoke(in this, output);
		}

		public bool GetRuleBook(RuleBook dest)
		{
			return getRuleBookImplementation?.Invoke(in this, dest) ?? false;
		}

		public void RequestRefresh([CanBeNull] RequestRefreshSuccessCallback successCallback, [CanBeNull] Action failureCallback, bool fetchDetails)
		{
			if (requestRefreshImplementation == null)
			{
				failureCallback?.Invoke();
			}
			else
			{
				requestRefreshImplementation(in this, successCallback, failureCallback, fetchDetails);
			}
		}

		public void SetTags(string[] newTags)
		{
			tags = newTags;
			if (tags == null)
			{
				return;
			}
			for (int i = 0; i < tags.Length; i++)
			{
				switch (tags[i])
				{
				case "dz":
					currentDifficultyIndex = DifficultyIndex.Easy;
					break;
				case "rs":
					currentDifficultyIndex = DifficultyIndex.Normal;
					break;
				case "mn":
					currentDifficultyIndex = DifficultyIndex.Hard;
					break;
				}
			}
		}

		public void CalcExtraFields()
		{
			lesserPlayerCount = int.MinValue;
			greaterPlayerCount = int.MaxValue;
			lesserMaxPlayers = int.MinValue;
			greaterMaxPlayers = int.MaxValue;
			Pick(lobbyPlayerCount, ref lesserPlayerCount, ref greaterPlayerCount);
			Pick(serverPlayerCount, ref lesserPlayerCount, ref greaterPlayerCount);
			Pick(lobbyMaxPlayers, ref lesserMaxPlayers, ref greaterMaxPlayers);
			Pick(serverMaxPlayers, ref lesserMaxPlayers, ref greaterMaxPlayers);
			if (lesserPlayerCount == int.MinValue)
			{
				lesserPlayerCount = 0;
			}
			if (greaterPlayerCount == int.MaxValue)
			{
				greaterPlayerCount = 0;
			}
			if (lesserMaxPlayers == int.MinValue)
			{
				lesserMaxPlayers = 0;
			}
			if (greaterMaxPlayers == int.MaxValue)
			{
				greaterMaxPlayers = 0;
			}
			availableSlots = int.MaxValue;
			int? num = lobbyMaxPlayers - lobbyPlayerCount;
			int? num2 = serverMaxPlayers - serverPlayerCount;
			if (num.HasValue)
			{
				availableSlots = Math.Min(availableSlots, num.Value);
			}
			if (num2.HasValue)
			{
				availableSlots = Math.Min(availableSlots, num2.Value);
			}
			availableLobbySlots = (lobbyMaxPlayers - lobbyPlayerCount).GetValueOrDefault();
			availableServerSlots = (serverMaxPlayers - serverPlayerCount).GetValueOrDefault();
			if (availableSlots == int.MaxValue)
			{
				availableSlots = 0;
			}
			static void Pick(int? inputValue, ref int lesserResult, ref int greaterResult)
			{
				if (inputValue.HasValue)
				{
					lesserResult = Math.Max(lesserResult, inputValue.Value);
					greaterResult = Math.Min(greaterResult, inputValue.Value);
				}
			}
		}

		public bool HasTag(string tag)
		{
			if (tags == null)
			{
				return false;
			}
			return Array.IndexOf(tags, tag) != -1;
		}

		public ArtifactEnumerable GetEnabledArtifacts()
		{
			ArtifactEnumerable result = new ArtifactEnumerable("");
			if (tags != null)
			{
				for (int i = 0; i < tags.Length; i++)
				{
					if (tags[i].StartsWith("a="))
					{
						result = new ArtifactEnumerable(tags[i]);
						break;
					}
				}
			}
			return result;
		}
	}
	public struct RemoteRules
	{
		public RuleBook ruleBook;
	}
	public struct RemotePlayerInfo
	{
		public string name;

		public ulong id;
	}
	public class SortRemoteGameProvider : BaseAsyncRemoteGameProvider
	{
		public delegate int RemoteGameProviderComparison(in RemoteGameInfo a, in RemoteGameInfo b);

		public struct Parameters : IEquatable<Parameters>
		{
			public int sorterIndex;

			public bool ascending;

			public bool Equals(Parameters other)
			{
				if (sorterIndex == other.sorterIndex)
				{
					return ascending == other.ascending;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is Parameters other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (sorterIndex * 397) ^ ascending.GetHashCode();
			}
		}

		public class Sorter
		{
			public string nameToken;

			public RemoteGameProviderComparison comparer;
		}

		private readonly IRemoteGameProvider source;

		private Parameters currentParameters;

		public static Sorter[] sorters = new Sorter[5]
		{
			new Sorter
			{
				nameToken = "GAME_BROWSER_SORTER_PING",
				comparer = ComparePing
			},
			new Sorter
			{
				nameToken = "GAME_BROWSER_SORTER_NAME",
				comparer = CompareName
			},
			new Sorter
			{
				nameToken = "GAME_BROWSER_SORTER_PLAYER_COUNT",
				comparer = ComparePlayerCount
			},
			new Sorter
			{
				nameToken = "GAME_BROWSER_SORTER_MAX_PLAYER_COUNT",
				comparer = CompareMaxPlayerCount
			},
			new Sorter
			{
				nameToken = "GAME_BROWSER_SORTER_AVAILABLE_SLOTS",
				comparer = CompareAvailableSlots
			}
		};

		public SortRemoteGameProvider([NotNull] IRemoteGameProvider source)
		{
			this.source = source;
			source.onNewInfoAvailable += OnSourceNewInfoAvailable;
			maxTasks = 1;
		}

		public override void Dispose()
		{
			source.onNewInfoAvailable -= OnSourceNewInfoAvailable;
			base.Dispose();
		}

		private void OnSourceNewInfoAvailable()
		{
			SetDirty();
		}

		protected override Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken)
		{
			Parameters parameters = GetParameters();
			RemoteGameInfo[] input = source.GetKnownGames();
			RemoteGameInfo[] output = new RemoteGameInfo[input.Length];
			Sorter sorter = sorters[parameters.sorterIndex];
			bool ascending = parameters.ascending;
			return new Task<RemoteGameInfo[]>(delegate
			{
				Sort(input, output, sorter, ascending, cancellationToken);
				return output;
			});
		}

		public override bool RequestRefresh()
		{
			return source.RequestRefresh();
		}

		public override bool IsBusy()
		{
			if (!base.IsBusy())
			{
				return source.IsBusy();
			}
			return true;
		}

		private static void Sort(RemoteGameInfo[] input, RemoteGameInfo[] output, Sorter sorter, bool ascending, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			int[] array = new int[input.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = i;
			}
			cancellationToken.ThrowIfCancellationRequested();
			RemoteGameProviderComparison comparer = sorter.comparer;
			cancellationToken.ThrowIfCancellationRequested();
			Array.Sort(array, Compare);
			cancellationToken.ThrowIfCancellationRequested();
			if (ascending)
			{
				for (int j = 0; j < array.Length; j++)
				{
					output[j] = input[array[j]];
				}
			}
			else
			{
				for (int k = 0; k < array.Length; k++)
				{
					output[k] = input[array[array.Length - 1 - k]];
				}
			}
			int Compare(int indexA, int indexB)
			{
				return comparer(in input[indexA], in input[indexB]);
			}
		}

		public Parameters GetParameters()
		{
			lock (this)
			{
				return currentParameters;
			}
		}

		public void SetParameters(Parameters newParameters)
		{
			if (!currentParameters.Equals(newParameters))
			{
				SetParametersInternal(newParameters);
			}
		}

		private void SetParametersInternal(Parameters newParameters)
		{
			lock (this)
			{
				currentParameters = newParameters;
				SetDirty();
			}
		}

		private static int ComparePing(in RemoteGameInfo a, in RemoteGameInfo b)
		{
			int num = a.ping ?? int.MinValue;
			int value = b.ping ?? int.MinValue;
			return num.CompareTo(value);
		}

		private static int ComparePlayerCount(in RemoteGameInfo a, in RemoteGameInfo b)
		{
			return a.lesserPlayerCount.CompareTo(b.lesserPlayerCount);
		}

		private static int CompareMaxPlayerCount(in RemoteGameInfo a, in RemoteGameInfo b)
		{
			return a.lesserPlayerCount.CompareTo(b.lesserPlayerCount);
		}

		private static int CompareName(in RemoteGameInfo a, in RemoteGameInfo b)
		{
			return a.name.CompareTo(b.name);
		}

		public static int CompareAvailableSlots(in RemoteGameInfo a, in RemoteGameInfo b)
		{
			return a.availableSlots.CompareTo(b.availableSlots);
		}
	}
	public class SteamworksLobbyRemoteGameProvider : BaseAsyncRemoteGameProvider
	{
		private readonly List<LobbyList.Lobby> lobbyList = new List<LobbyList.Lobby>();

		private int waitingForLobbyCount;

		private static readonly char[] tagsSeparator = new char[1] { ',' };

		private LobbyList.Filter BuildFilter()
		{
			LobbyList.Filter filter = new LobbyList.Filter();
			if (!searchFilters.allowMismatchedMods)
			{
				filter.StringFilters.Add("_mh", NetworkModCompatibilityHelper.networkModHash);
			}
			return filter;
		}

		public override bool RequestRefresh()
		{
			LobbyList.Filter filter = BuildFilter();
			bool num = (PlatformSystems.lobbyManager as SteamworksLobbyManager).RequestLobbyList(this, filter, OnLobbyListReceived);
			if (num)
			{
				waitingForLobbyCount++;
			}
			return num;
		}

		private void OnLobbyListReceived(List<LobbyList.Lobby> lobbies)
		{
			if (base.disposed)
			{
				return;
			}
			waitingForLobbyCount--;
			lock (lobbyList)
			{
				lobbyList.Clear();
				lobbyList.AddRange(lobbies);
				SetDirty();
			}
		}

		protected override Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken)
		{
			LobbyList.Lobby[] lobbies;
			lock (lobbyList)
			{
				lobbies = lobbyList.ToArray();
			}
			return new Task<RemoteGameInfo[]>(delegate
			{
				RemoteGameInfo[] array = new RemoteGameInfo[lobbies.Length];
				for (int i = 0; i < lobbies.Length; i++)
				{
					CreateRemoteGameInfo(lobbies[i], out array[i]);
				}
				return array;
			}, cancellationToken);
		}

		private static void CreateRemoteGameInfo(LobbyList.Lobby lobby, out RemoteGameInfo result)
		{
			result = default(RemoteGameInfo);
			result.name = lobby.Name;
			result.lobbyName = lobby.Name;
			result.lobbyId = lobby.LobbyID;
			string text = GetString("_map");
			result.serverId = GetULong("server_id");
			result.serverAddress = GetAddressPortPair("server_address");
			result.serverName = GetString("_svnm");
			result.lobbyPlayerCount = GetInt("player_count", 1, int.MaxValue) ?? 1;
			result.lobbyMaxPlayers = GetInt("total_max_players", 1, int.MaxValue) ?? 1;
			result.serverPlayerCount = GetInt("_svplc", 0, int.MaxValue);
			result.serverMaxPlayers = GetInt("_svmpl", 0, int.MaxValue);
			result.inGame = result.serverId.HasValue || result.serverAddress.HasValue;
			result.currentSceneName = text;
			if (text != null)
			{
				result.currentSceneIndex = SceneCatalog.GetSceneDefFromSceneName(text)?.sceneDefIndex;
			}
			result.requestRefreshImplementation = RemoteGameInfoRequestRefresh;
			result.getPlayersImplementation = RemoteGameInfoGetPlayers;
			result.getRuleBookImplementation = RemoteGameInfoGetRuleBook;
			result.userData = lobby;
			result.hasPassword = GetBool("_pw");
			result.gameModeName = GetString("_svgm");
			result.buildId = GetString("build_id") ?? "UNKNOWN";
			result.modHash = GetString("_mh") ?? "UNKNOWN";
			result.SetTags(GetTags("_svtags"));
			result.CalcExtraFields();
			AddressPortPair? GetAddressPortPair(string key)
			{
				if (!AddressPortPair.TryParse(GetString(key), out var addressPortPair))
				{
					return null;
				}
				return addressPortPair;
			}
			bool? GetBool(string key)
			{
				return GetInt(key, int.MinValue, int.MaxValue) > 0;
			}
			int? GetInt(string key, int min, int max)
			{
				if (int.TryParse(GetString(key), out var result2) && min <= result2 && result2 <= max)
				{
					return result2;
				}
				return null;
			}
			string GetString(string key)
			{
				string data = lobby.GetData(key);
				if (!(data == string.Empty))
				{
					return data;
				}
				return null;
			}
			string[] GetTags(string key)
			{
				return GetString(key)?.Split(tagsSeparator, StringSplitOptions.None);
			}
			ulong? GetULong(string key)
			{
				if (!ulong.TryParse(GetString(key), out var result3))
				{
					return null;
				}
				return result3;
			}
		}

		private static void RemoteGameInfoRequestRefresh(in RemoteGameInfo remoteGameInfo, RemoteGameInfo.RequestRefreshSuccessCallback successCallback, Action failureCallback, bool fetchDetails)
		{
			if (!(remoteGameInfo.userData is LobbyList.Lobby lobby))
			{
				return;
			}
			Task<LobbyList.Lobby> lobby2 = Client.Instance.LobbyList.GetLobby(lobby.LobbyID);
			if (lobby2 == null)
			{
				failureCallback?.Invoke();
				return;
			}
			lobby2.ContinueWith(delegate(Task<LobbyList.Lobby> antecedentTask)
			{
				RoR2Application.onNextUpdate += delegate
				{
					HandleRefresh(antecedentTask);
				};
			});
			void HandleRefresh(Task<LobbyList.Lobby> antecedentTask)
			{
				LobbyList.Lobby result = antecedentTask.Result;
				if (result == null)
				{
					failureCallback?.Invoke();
				}
				else
				{
					CreateRemoteGameInfo(result, out var result2);
					successCallback?.Invoke(in result2);
				}
			}
		}

		private static bool RemoteGameInfoGetRuleBook(in RemoteGameInfo remoteGameInfo, RuleBook dest)
		{
			if (remoteGameInfo.userData is LobbyList.Lobby lobby)
			{
				KeyValueUnsplitter keyValueUnsplitter = new KeyValueUnsplitter("rulebook");
				List<KeyValuePair<string, string>> list = CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.RentCollection();
				try
				{
					int i = 0;
					for (int dataCount = lobby.GetDataCount(); i < dataCount; i++)
					{
						if (lobby.GetDataByIndex(i, out var key, out var value))
						{
							list.Add(new KeyValuePair<string, string>(key, value));
						}
					}
					string value2 = keyValueUnsplitter.GetValue(list);
					if (!string.IsNullOrEmpty(value2))
					{
						RuleBook.ReadBase64(value2, dest);
						return true;
					}
				}
				finally
				{
					list = CollectionPool<KeyValuePair<string, string>, List<KeyValuePair<string, string>>>.ReturnCollection(list);
				}
			}
			return false;
		}

		private static void RemoteGameInfoGetPlayers(in RemoteGameInfo remoteGameInfo, List<RemotePlayerInfo> output)
		{
			if (remoteGameInfo.userData is LobbyList.Lobby lobby)
			{
				for (int i = 0; i < lobby.NumMembers; i++)
				{
					output.Add(new RemotePlayerInfo
					{
						id = 0uL,
						name = "???"
					});
				}
			}
		}

		public override bool IsBusy()
		{
			if (!base.IsBusy())
			{
				return waitingForLobbyCount > 0;
			}
			return true;
		}
	}
	public class SteamworksServerRemoteGameProvider : BaseAsyncRemoteGameProvider
	{
		public new struct SearchFilters : IEquatable<SearchFilters>
		{
			public bool allowDedicatedServers;

			public bool allowListenServers;

			public bool mustHavePlayers;

			public bool mustNotBeFull;

			public bool allowInProgressGames;

			public bool allowMismatchedMods;

			public string requiredTags;

			public string forbiddenTags;

			public bool Equals(SearchFilters other)
			{
				if (allowDedicatedServers == other.allowDedicatedServers && allowListenServers == other.allowListenServers && mustHavePlayers == other.mustHavePlayers && mustNotBeFull == other.mustNotBeFull && allowInProgressGames == other.allowInProgressGames && allowMismatchedMods == other.allowMismatchedMods && string.Equals(requiredTags, other.requiredTags))
				{
					return string.Equals(forbiddenTags, other.forbiddenTags);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is SearchFilters other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((((((((((((allowDedicatedServers.GetHashCode() * 397) ^ allowListenServers.GetHashCode()) * 397) ^ mustHavePlayers.GetHashCode()) * 397) ^ mustNotBeFull.GetHashCode()) * 397) ^ allowInProgressGames.GetHashCode()) * 397) ^ allowMismatchedMods.GetHashCode()) * 397) ^ ((requiredTags != null) ? requiredTags.GetHashCode() : 0)) * 397) ^ ((forbiddenTags != null) ? forbiddenTags.GetHashCode() : 0);
			}
		}

		public enum Mode
		{
			Internet,
			Favorites,
			History,
			Local,
			Friends
		}

		private struct FilterElement
		{
			public string key;

			public string value;

			public int operandCount;

			public bool isOperator;
		}

		private Mode mode;

		private ServerList.Filter filter;

		private ServerList.Request currentRequest;

		public new bool refreshOnFiltersChanged;

		private static readonly int k_cbMaxGameServerGameData = 2048;

		private static readonly int k_cbMaxGameServerGameDescription = 64;

		private static readonly int k_cbMaxGameServerGameDir = 32;

		private static readonly int k_cbMaxGameServerMapName = 32;

		private static readonly int k_cbMaxGameServerName = 64;

		private static readonly int k_cbMaxGameServerTags = 128;

		private new SearchFilters searchFilters;

		public SteamworksServerRemoteGameProvider(Mode mode)
		{
			this.mode = mode;
			filter = new ServerList.Filter();
		}

		public new SearchFilters GetSearchFilters()
		{
			return searchFilters;
		}

		public void SetSearchFilters(SearchFilters newSearchFilters)
		{
			if (!searchFilters.Equals(newSearchFilters))
			{
				searchFilters = newSearchFilters;
				BuildFilter();
				if (refreshOnFiltersChanged)
				{
					RequestRefresh();
				}
				SetDirty();
			}
		}

		private void BuildFilter()
		{
			filter.Clear();
			FilterElement[] elements = new FilterElement[64];
			int elementCount = 0;
			Stack<(int, int)> operatorIndicesAndCounts = new Stack<(int, int)>();
			int currentOperandCount = 0;
			PushOperation("and");
			AddOperand("appid", Client.Instance.AppId.ToString());
			if (searchFilters.allowDedicatedServers != searchFilters.allowListenServers)
			{
				if (searchFilters.allowListenServers)
				{
					PushOperation("nor");
					AddOperand("dedicated", "");
					PopOperation();
				}
				else
				{
					AddOperand("dedicated", "");
				}
			}
			if (searchFilters.mustHavePlayers)
			{
				AddOperand("hasplayers", "");
			}
			if (searchFilters.mustNotBeFull)
			{
				AddOperand("notfull", "");
			}
			if (!searchFilters.allowInProgressGames)
			{
				AddOperand("map", "lobby");
			}
			if (!string.IsNullOrEmpty(searchFilters.requiredTags))
			{
				AddOperand("gametagsand", searchFilters.requiredTags);
			}
			if (!string.IsNullOrEmpty(searchFilters.forbiddenTags))
			{
				AddOperand("gametagsnor", searchFilters.forbiddenTags);
			}
			AddOperand("gamedataand", ServerManagerBase<SteamworksServerManager>.GetVersionGameDataString());
			if (!searchFilters.allowMismatchedMods)
			{
				AddOperand("gamedataand", NetworkModCompatibilityHelper.steamworksGameserverGameDataValue);
			}
			PopOperation();
			for (int j = 0; j < elementCount; j++)
			{
				ref FilterElement reference = ref elements[j];
				filter.Add(reference.key, reference.isOperator ? reference.operandCount.ToString() : reference.value);
			}
			void AddOperand(string key, string value)
			{
				int num2 = currentOperandCount + 1;
				currentOperandCount = num2;
				GetElement(elementCount++) = new FilterElement
				{
					key = key,
					value = value,
					isOperator = false
				};
			}
			ref FilterElement GetElement(int i)
			{
				if (elements.Length < i)
				{
					Array.Resize(ref elements, elements.Length * 2);
				}
				return ref elements[i];
			}
			void PopOperation()
			{
				int num = currentOperandCount;
				int i2;
				(i2, currentOperandCount) = operatorIndicesAndCounts.Pop();
				currentOperandCount += num;
				GetElement(i2).operandCount = num;
			}
			void PushOperation(string operationCode)
			{
				int num3 = currentOperandCount + 1;
				currentOperandCount = num3;
				int num4 = elementCount++;
				GetElement(num4) = new FilterElement
				{
					key = operationCode,
					isOperator = true
				};
				operatorIndicesAndCounts.Push((num4, currentOperandCount));
				currentOperandCount = 0;
			}
		}

		public override bool RequestRefresh()
		{
			CancelCurrentRequest();
			currentRequest = CreateRequest(mode, filter);
			currentRequest.OnUpdate = OnCurrentRequestUpdated;
			currentRequest.OnFinished = OnCurrentRequestFinished;
			currentRequest.OnServerResponded = OnCurrentRequestServerResponded;
			return true;
		}

		private static Func<ServerList.Filter, ServerList.Request> GetRequestMethod(Mode mode)
		{
			ServerList serverList = Client.Instance.ServerList;
			return mode switch
			{
				Mode.Internet => serverList.Internet, 
				Mode.Favorites => serverList.Favourites, 
				Mode.History => serverList.History, 
				Mode.Local => serverList.Local, 
				Mode.Friends => serverList.Friends, 
				_ => throw new ArgumentOutOfRangeException(), 
			};
		}

		private static ServerList.Request CreateRequest(Mode mode, ServerList.Filter filter)
		{
			return GetRequestMethod(mode)(filter);
		}

		private void OnCurrentRequestServerResponded(ServerList.Server server)
		{
			SetDirty();
		}

		private void OnCurrentRequestFinished()
		{
			SetDirty();
		}

		private void OnCurrentRequestUpdated()
		{
			SetDirty();
		}

		private void CancelCurrentRequest()
		{
			if (currentRequest != null)
			{
				currentRequest.OnFinished = null;
				currentRequest.OnServerResponded = null;
				currentRequest.OnUpdate = null;
				currentRequest.Dispose();
				currentRequest = null;
			}
		}

		private static RemoteGameInfo[] GenerateRemoteGameInfoCache(ServerList.Server[] knownServers, CancellationToken cancellationToken)
		{
			cancellationToken.ThrowIfCancellationRequested();
			RemoteGameInfo[] array = new RemoteGameInfo[knownServers.Length];
			for (int i = 0; i < knownServers.Length; i++)
			{
				cancellationToken.ThrowIfCancellationRequested();
				ServerList.Server serverInfo = knownServers[i];
				GenerateRemoteGameInfo(ref array[i], serverInfo);
			}
			return array;
		}

		protected override Task<RemoteGameInfo[]> CreateTask(CancellationToken cancellationToken)
		{
			if (currentRequest == null)
			{
				return new Task<RemoteGameInfo[]>(() => Array.Empty<RemoteGameInfo>());
			}
			ServerList.Server[] servers = currentRequest.Responded.ToArray();
			return new Task<RemoteGameInfo[]>(() => GenerateRemoteGameInfoCache(servers, cancellationToken), cancellationToken);
		}

		public override void Dispose()
		{
			CancelCurrentRequest();
			base.Dispose();
		}

		public override bool IsBusy()
		{
			if (!base.IsBusy())
			{
				return !(currentRequest?.Finished ?? true);
			}
			return true;
		}

		private static void GenerateRemoteGameInfo(ref RemoteGameInfo remoteGameInfo, ServerList.Server serverInfo)
		{
			remoteGameInfo.name = serverInfo.Name;
			remoteGameInfo.serverAddress = new AddressPortPair(serverInfo.Address, (ushort)serverInfo.ConnectionPort);
			remoteGameInfo.serverName = serverInfo.Name;
			remoteGameInfo.serverId = serverInfo.SteamId;
			remoteGameInfo.hasPassword = serverInfo.Passworded;
			remoteGameInfo.serverPlayerCount = serverInfo.Players;
			remoteGameInfo.serverMaxPlayers = serverInfo.MaxPlayers;
			remoteGameInfo.ping = serverInfo.Ping;
			remoteGameInfo.SetTags(serverInfo.Tags);
			remoteGameInfo.isFavorite = serverInfo.Favourite;
			remoteGameInfo.userData = serverInfo;
			remoteGameInfo.getPlayersImplementation = RemoteGameInfoGetPlayers;
			remoteGameInfo.requestRefreshImplementation = RemoteGameInfoRequestRefresh;
			remoteGameInfo.getRuleBookImplementation = RemoteGameInfoGetRuleBook;
			remoteGameInfo.currentSceneName = serverInfo.Map;
			remoteGameInfo.currentSceneIndex = SceneCatalog.GetSceneDefFromSceneName(serverInfo.Map)?.sceneDefIndex;
			remoteGameInfo.CalcExtraFields();
		}

		private static void RemoteGameInfoRequestRefresh(in RemoteGameInfo remoteGameInfo, RemoteGameInfo.RequestRefreshSuccessCallback successCallback, Action failureCallback, bool fetchDetails)
		{
			if (remoteGameInfo.userData is ServerList.Server)
			{
				ServerList.Filter filter = new ServerList.Filter();
				filter.Add("and", "2");
				filter.Add("appid", Client.Instance.AppId.ToString());
				filter.Add("gameaddr", remoteGameInfo.serverAddress.ToString());
				ServerList.Request lanRefreshRequest = CreateRequest(Mode.Local, filter);
				lanRefreshRequest.OnFinished = delegate
				{
					ServerList.Server refreshedServerInfoFromRequest = GetRefreshedServerInfoFromRequest(lanRefreshRequest);
					if (refreshedServerInfoFromRequest != null)
					{
						HandleNewInfo(refreshedServerInfoFromRequest);
					}
					else
					{
						ServerList.Request internetRefreshRequest = CreateRequest(Mode.Internet, filter);
						internetRefreshRequest.OnFinished = delegate
						{
							ServerList.Server refreshedServerInfoFromRequest2 = GetRefreshedServerInfoFromRequest(internetRefreshRequest);
							if (refreshedServerInfoFromRequest2 != null)
							{
								HandleNewInfo(refreshedServerInfoFromRequest2);
							}
							else
							{
								failureCallback?.Invoke();
							}
						};
					}
				};
			}
			else
			{
				failureCallback?.Invoke();
			}
			static ServerList.Server GetRefreshedServerInfoFromRequest(ServerList.Request request)
			{
				if (request.Responded.Count > 0)
				{
					return request.Responded[0];
				}
				if (request.Unresponsive.Count > 0)
				{
					return request.Unresponsive[0];
				}
				return null;
			}
			void HandleNewInfo(ServerList.Server refreshedServerInfo)
			{
				RemoteGameInfo result = default(RemoteGameInfo);
				GenerateRemoteGameInfo(ref result, refreshedServerInfo);
				int awaitingRequests;
				if (fetchDetails)
				{
					awaitingRequests = 2;
					ServerList.Server server = refreshedServerInfo;
					server.OnReceivedPlayerInfos = (Action<bool>)Delegate.Combine(server.OnReceivedPlayerInfos, new Action<bool>(OnReceivedPlayerInfos));
					ServerList.Server server2 = refreshedServerInfo;
					server2.OnReceivedRules = (Action<bool>)Delegate.Combine(server2.OnReceivedRules, new Action<bool>(OnReceivedRules));
					refreshedServerInfo.FetchPlayerInfos();
					refreshedServerInfo.FetchRules();
				}
				else
				{
					successCallback?.Invoke(in result);
				}
				void OnReceivedPlayerInfos(bool success)
				{
					ServerList.Server server4 = refreshedServerInfo;
					server4.OnReceivedPlayerInfos = (Action<bool>)Delegate.Remove(server4.OnReceivedPlayerInfos, new Action<bool>(OnReceivedPlayerInfos));
					int num2 = awaitingRequests - 1;
					awaitingRequests = num2;
					TryComplete();
				}
				void OnReceivedRules(bool success)
				{
					ServerList.Server server3 = refreshedServerInfo;
					server3.OnReceivedRules = (Action<bool>)Delegate.Remove(server3.OnReceivedRules, new Action<bool>(OnReceivedRules));
					if (success && refreshedServerInfo.HasRules)
					{
						refreshedServerInfo.Rules.TryGetValue("gameMode", out result.gameModeName);
						refreshedServerInfo.Rules.TryGetValue("buildId", out result.buildId);
						refreshedServerInfo.Rules.TryGetValue("modHash", out result.modHash);
						result.buildId = result.buildId ?? "UNKNOWN";
						result.modHash = result.modHash ?? "UNKNOWN";
					}
					int num = awaitingRequests - 1;
					awaitingRequests = num;
					TryComplete();
				}
				void TryComplete()
				{
					if (awaitingRequests == 0)
					{
						successCallback?.Invoke(in result);
					}
				}
			}
		}

		private static bool RemoteGameInfoGetRuleBook(in RemoteGameInfo remoteGameInfo, RuleBook dest)
		{
			if (remoteGameInfo.userData is ServerList.Server { HasRules: not false } server)
			{
				dest.SetToDefaults();
				RuleBook.ReadBase64(new KeyValueUnsplitter("ruleBook").GetValue(server.Rules), dest);
				return true;
			}
			return false;
		}

		private static void RemoteGameInfoGetPlayers(in RemoteGameInfo remoteGameInfo, List<RemotePlayerInfo> output)
		{
			if (remoteGameInfo.userData is ServerList.Server { PlayerInfos: { } playerInfos })
			{
				for (int i = 0; i < playerInfos.Count; i++)
				{
					output.Add(new RemotePlayerInfo
					{
						name = playerInfos[i].name
					});
				}
			}
		}
	}
}
namespace RoR2.Gamecore
{
	public class GamecoreEngagementScreen : MonoBehaviour
	{
		public MainMenuController Menu;
	}
}
namespace RoR2.Navigation
{
	public interface IPosition3Getter<T>
	{
		UnityEngine.Vector3 GetPosition3(T item);
	}
	internal enum BlockMapCellIndex
	{
		Invalid = -1
	}
	internal struct BlockMapCell
	{
		public int itemStartIndex;

		public int itemCount;
	}
	public interface IBlockMapSearchFilter<TItem>
	{
		bool CheckItem(TItem item, ref bool shouldFinish);
	}
	public class BlockMap<TItem, TItemPositionGetter> where TItemPositionGetter : IPosition3Getter<TItem>
	{
		private struct ItemDistanceSqrPair
		{
			public int itemIndex;

			public float distanceSqr;
		}

		private interface ISearchResultHandler
		{
			bool OnEncounterResult(TItem result);
		}

		private struct SingleSearchResultHandler : ISearchResultHandler
		{
			public bool foundResult { get; private set; }

			public TItem result { get; private set; }

			public bool OnEncounterResult(TItem result)
			{
				foundResult = true;
				this.result = result;
				return false;
			}
		}

		private struct ListWriteSearchResultHandler : ISearchResultHandler
		{
			private readonly List<TItem> dest;

			public ListWriteSearchResultHandler(List<TItem> dest)
			{
				this.dest = dest;
			}

			public bool OnEncounterResult(TItem result)
			{
				dest.Add(result);
				return true;
			}
		}

		private struct GridEnumerator
		{
			private readonly Vector3Int startPos;

			private readonly Vector3Int endPos;

			private Vector3Int _current;

			public Vector3Int Current => _current;

			public GridEnumerator(in Vector3Int startCellIndex, in Vector3Int endCellIndex)
			{
				startPos = startCellIndex;
				endPos = endCellIndex;
				_current = startCellIndex;
				ref Vector3Int current = ref _current;
				int x = current.x - 1;
				current.x = x;
			}

			public bool MoveNext()
			{
				if (++_current.x >= endPos.x)
				{
					_current.x = startPos.x;
					if (++_current.z >= endPos.z)
					{
						_current.z = startPos.z;
						if (++_current.y >= endPos.y)
						{
							_current.y = startPos.y;
							return false;
						}
					}
				}
				return true;
			}

			public void Reset()
			{
				_current = startPos;
			}
		}

		private struct GridEnumerable
		{
			private readonly Vector3Int startPos;

			private readonly Vector3Int endPos;

			public GridEnumerable(Vector3Int startPos, Vector3Int endPos)
			{
				this.startPos = startPos;
				this.endPos = endPos;
			}

			public GridEnumerator GetEnumerator()
			{
				return new GridEnumerator(in startPos, in endPos);
			}
		}

		private const bool debugDraw = false;

		private const bool aggressiveDebug = false;

		private UnityEngine.Vector3 cellSize;

		private UnityEngine.Vector3 invCellSize;

		private Bounds worldBoundingBox;

		private BlockMapCell[] cells = Array.Empty<BlockMapCell>();

		private int cellCount1D;

		private Vector3Int cellCounts;

		private TItem[] itemsPackedByCell = Array.Empty<TItem>();

		private int itemCount;

		private TItemPositionGetter itemPositionGetter;

		public BlockMap()
			: this(new UnityEngine.Vector3(15f, 30f, 15f))
		{
		}

		public BlockMap(UnityEngine.Vector3 cellSize)
		{
			SetCellSize(cellSize);
		}

		public void Reset()
		{
			worldBoundingBox = default(Bounds);
			ArrayUtils.Clear(itemsPackedByCell, ref itemCount);
			cellCounts = Vector3Int.zero;
			cellCount1D = 0;
		}

		public void SetCellSize(UnityEngine.Vector3 newSize)
		{
			if (cellSize != newSize)
			{
				cellSize = newSize;
				invCellSize = new UnityEngine.Vector3(1f / cellSize.x, 1f / cellSize.y, 1f / cellSize.z);
				Reset();
			}
		}

		public void Set<T>(T newItems, int newItemsLength, TItemPositionGetter newItemPositionGetter) where T : IList<TItem>
		{
			Reset();
			NativeArray<BlockMapCellIndex> nativeArray = new NativeArray<BlockMapCellIndex>(newItemsLength, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
			try
			{
				itemPositionGetter = newItemPositionGetter;
				if (newItems.Count > 0)
				{
					worldBoundingBox = new Bounds(itemPositionGetter.GetPosition3(newItems[0]), UnityEngine.Vector3.zero);
					for (int i = 1; i < newItems.Count; i++)
					{
						worldBoundingBox.Encapsulate(itemPositionGetter.GetPosition3(newItems[i]));
					}
				}
				worldBoundingBox.min -= UnityEngine.Vector3.one;
				worldBoundingBox.max += UnityEngine.Vector3.one;
				UnityEngine.Vector3 size = worldBoundingBox.size;
				cellCounts = Vector3Int.Max(Vector3Int.CeilToInt(UnityEngine.Vector3.Scale(size, invCellSize)), Vector3Int.one);
				cellCount1D = cellCounts.x * cellCounts.y * cellCounts.z;
				Array.Resize(ref cells, cellCount1D);
				Array.Clear(cells, 0, cells.Length);
				_ = worldBoundingBox.min;
				for (int j = 0; j < newItems.Count; j++)
				{
					UnityEngine.Vector3 worldPosition = itemPositionGetter.GetPosition3(newItems[j]);
					Vector3Int gridPos = WorldPositionToGridPosFloor(in worldPosition);
					BlockMapCellIndex blockMapCellIndex2 = (nativeArray[j] = GridPosToCellIndex(in gridPos));
					cells[(int)blockMapCellIndex2].itemCount++;
				}
				int num = 0;
				for (int k = 0; k < cells.Length; k++)
				{
					ref BlockMapCell reference = ref cells[k];
					reference.itemStartIndex = num;
					num += reference.itemCount;
				}
				itemCount = newItems.Count;
				ArrayUtils.EnsureCapacity(ref itemsPackedByCell, itemCount);
				NativeArray<int> nativeArray2 = new NativeArray<int>(cells.Length, Allocator.Temp);
				for (int l = 0; l < itemCount; l++)
				{
					BlockMapCellIndex blockMapCellIndex3 = nativeArray[l];
					ref BlockMapCell reference2 = ref cells[(int)blockMapCellIndex3];
					TItem val = newItems[l];
					int num2 = nativeArray2[(int)blockMapCellIndex3]++;
					itemsPackedByCell[reference2.itemStartIndex + num2] = val;
				}
				nativeArray2.Dispose();
			}
			catch
			{
				Reset();
				throw;
			}
			finally
			{
				nativeArray.Dispose();
			}
		}

		private Vector3Int WorldPositionToGridPosFloor(in UnityEngine.Vector3 worldPosition)
		{
			UnityEngine.Vector3 localPosition = worldPosition - worldBoundingBox.min;
			return LocalPositionToGridPosFloor(in localPosition);
		}

		private Vector3Int WorldPositionToGridPosCeil(in UnityEngine.Vector3 worldPosition)
		{
			UnityEngine.Vector3 localPosition = worldPosition - worldBoundingBox.min;
			return LocalPositionToGridPosCeil(in localPosition);
		}

		private Vector3Int LocalPositionToGridPosFloor(in UnityEngine.Vector3 localPosition)
		{
			return Vector3Int.FloorToInt(UnityEngine.Vector3.Scale(localPosition, invCellSize));
		}

		private Vector3Int LocalPositionToGridPosCeil(in UnityEngine.Vector3 localPosition)
		{
			return Vector3Int.CeilToInt(UnityEngine.Vector3.Scale(localPosition, invCellSize));
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private BlockMapCellIndex GridPosToCellIndex(in Vector3Int gridPos)
		{
			return (BlockMapCellIndex)((gridPos.y * cellCounts.z + gridPos.z) * cellCounts.x + gridPos.x);
		}

		private Vector3Int CellIndexToGridPos(BlockMapCellIndex cellIndex)
		{
			int num = (int)cellIndex;
			Vector3Int zero = Vector3Int.zero;
			int num2 = cellCounts.x * cellCounts.z;
			zero.y = num / num2;
			num -= zero.y * num2;
			zero.z = num / cellCounts.x;
			num -= zero.z * cellCounts.x;
			zero.x = num;
			return zero;
		}

		private Bounds GridPosToBounds(in Vector3Int gridPos)
		{
			UnityEngine.Vector3 vector = gridPos;
			vector.Scale(cellSize);
			vector += worldBoundingBox.min;
			Bounds result = default(Bounds);
			result.SetMinMax(vector, vector + cellSize);
			return result;
		}

		private bool GridPosIsValid(Vector3Int gridPos)
		{
			if (gridPos.x >= 0 && gridPos.y >= 0 && gridPos.z >= 0 && gridPos.x < cellCounts.x && gridPos.y < cellCounts.y)
			{
				return gridPos.z < cellCounts.z;
			}
			return false;
		}

		public void GetItemsInSphere(UnityEngine.Vector3 point, float radius, List<TItem> dest)
		{
			Bounds bounds = GetSphereBounds(point, radius);
			int count = dest.Count;
			GetBoundOverlappingCellItems(in bounds, dest);
			float num = radius * radius;
			for (int num2 = dest.Count - 1; num2 >= count; num2--)
			{
				TItem item = dest[num2];
				if ((itemPositionGetter.GetPosition3(item) - point).sqrMagnitude > num)
				{
					dest.RemoveAt(num2);
				}
			}
		}

		public void GetItemsInBounds(in Bounds bounds, List<TItem> dest)
		{
			int count = dest.Count;
			GetBoundOverlappingCellItems(in bounds, dest);
			for (int num = dest.Count - 1; num >= count; num--)
			{
				TItem item = dest[num];
				UnityEngine.Vector3 position = itemPositionGetter.GetPosition3(item);
				if (!worldBoundingBox.Contains(position))
				{
					dest.RemoveAt(num);
				}
			}
		}

		private void GetBoundOverlappingCellItems(in Bounds bounds, List<TItem> dest)
		{
			List<BlockMapCellIndex> list = CollectionPool<BlockMapCellIndex, List<BlockMapCellIndex>>.RentCollection();
			GetBoundOverlappingCells(bounds, list);
			foreach (BlockMapCellIndex item in list)
			{
				ref BlockMapCell reference = ref cells[(int)item];
				int i = reference.itemStartIndex;
				for (int num = reference.itemStartIndex + reference.itemCount; i < num; i++)
				{
					dest.Add(itemsPackedByCell[i]);
				}
			}
			list = CollectionPool<BlockMapCellIndex, List<BlockMapCellIndex>>.ReturnCollection(list);
		}

		private void GetBoundOverlappingCells(Bounds bounds, List<BlockMapCellIndex> dest)
		{
			UnityEngine.Vector3 worldPosition = bounds.min;
			Vector3Int vector3Int = WorldPositionToGridPosFloor(in worldPosition);
			worldPosition = bounds.max;
			Vector3Int vector3Int2 = WorldPositionToGridPosCeil(in worldPosition);
			vector3Int.Clamp(Vector3Int.zero, cellCounts);
			vector3Int2.Clamp(Vector3Int.zero, cellCounts);
			Vector3Int gridPos = vector3Int;
			gridPos.y = vector3Int.y;
			while (gridPos.y < vector3Int2.y)
			{
				gridPos.z = vector3Int.z;
				int x;
				while (gridPos.z < vector3Int2.z)
				{
					gridPos.x = vector3Int.x;
					while (gridPos.x < vector3Int2.x)
					{
						dest.Add(GridPosToCellIndex(in gridPos));
						x = gridPos.x + 1;
						gridPos.x = x;
					}
					x = gridPos.z + 1;
					gridPos.z = x;
				}
				x = gridPos.y + 1;
				gridPos.y = x;
			}
		}

		public bool GetNearestItemWhichPassesFilter<TItemFilter>(UnityEngine.Vector3 position, float maxDistance, ref TItemFilter filter, out TItem dest) where TItemFilter : IBlockMapSearchFilter<TItem>
		{
			SingleSearchResultHandler searchResultHandler = default(SingleSearchResultHandler);
			GetNearestItemsWhichPassFilter(position, maxDistance, ref filter, ref searchResultHandler);
			dest = (searchResultHandler.foundResult ? searchResultHandler.result : default(TItem));
			return searchResultHandler.foundResult;
		}

		public void GetNearestItemsWhichPassFilter<TItemFilter>(UnityEngine.Vector3 position, float maxDistance, ref TItemFilter filter, List<TItem> dest) where TItemFilter : IBlockMapSearchFilter<TItem>
		{
			ListWriteSearchResultHandler searchResultHandler = new ListWriteSearchResultHandler(dest);
			GetNearestItemsWhichPassFilter(position, maxDistance, ref filter, ref searchResultHandler);
		}

		private void GetNearestItemsWhichPassFilter<TItemFilter, TSearchResultHandler>(UnityEngine.Vector3 position, float maxDistance, ref TItemFilter filter, ref TSearchResultHandler searchResultHandler) where TItemFilter : IBlockMapSearchFilter<TItem> where TSearchResultHandler : ISearchResultHandler
		{
			maxDistance = Mathf.Max(maxDistance, 0f);
			List<ItemDistanceSqrPair> candidatesInsideRadius = CollectionPool<ItemDistanceSqrPair, List<ItemDistanceSqrPair>>.RentCollection();
			List<ItemDistanceSqrPair> candidatesOutsideRadius = CollectionPool<ItemDistanceSqrPair, List<ItemDistanceSqrPair>>.RentCollection();
			float radiusSqr;
			try
			{
				Vector3Int gridPos = WorldPositionToGridPosFloor(in position);
				Bounds bounds = GridPosToBounds(in gridPos);
				Bounds currentBounds = bounds;
				float additionalRadius2 = cellSize.ComponentMin();
				float radius = DistanceToNearestWall(in position, in currentBounds);
				radiusSqr = radius * radius;
				BlockMapCellIndex cellIndex2 = GridPosToCellIndex(in gridPos);
				BoundsInt visitedCells = new BoundsInt(gridPos, Vector3Int.one);
				int visitedCellCount = 0;
				bool num = GridPosIsValid(gridPos);
				if (num)
				{
					VisitCell(cellIndex2);
				}
				if (!num)
				{
					AddRadius(Mathf.Sqrt(worldBoundingBox.SqrDistance(position)));
				}
				bool flag = true;
				while (flag)
				{
					while (candidatesInsideRadius.Count > 0)
					{
						int num2 = -1;
						float num3 = float.PositiveInfinity;
						for (int i = 0; i < candidatesInsideRadius.Count; i++)
						{
							ItemDistanceSqrPair itemDistanceSqrPair = candidatesInsideRadius[i];
							if (itemDistanceSqrPair.distanceSqr < num3)
							{
								num3 = itemDistanceSqrPair.distanceSqr;
								num2 = i;
							}
						}
						if (num2 != -1)
						{
							ItemDistanceSqrPair itemDistanceSqrPair2 = candidatesInsideRadius[num2];
							candidatesInsideRadius.RemoveAt(num2);
							bool shouldFinish = false;
							if ((filter.CheckItem(itemsPackedByCell[itemDistanceSqrPair2.itemIndex], ref shouldFinish) && !searchResultHandler.OnEncounterResult(itemsPackedByCell[itemDistanceSqrPair2.itemIndex])) || shouldFinish)
							{
								return;
							}
						}
					}
					flag = AddRadius(additionalRadius2);
				}
				bool AddRadius(float additionalRadius)
				{
					radius += additionalRadius;
					bool flag2 = radius >= maxDistance;
					if (flag2)
					{
						radius = maxDistance;
					}
					radiusSqr = radius * radius;
					currentBounds = GetSphereBounds(position, radius);
					for (int num4 = candidatesOutsideRadius.Count - 1; num4 >= 0; num4--)
					{
						ItemDistanceSqrPair item = candidatesOutsideRadius[num4];
						if (item.distanceSqr < radiusSqr)
						{
							candidatesOutsideRadius.RemoveAt(num4);
							candidatesInsideRadius.Add(item);
						}
					}
					bool flag3 = visitedCellCount >= cellCount1D;
					if (!flag3)
					{
						BoundsInt outer = WorldBoundsToOverlappingGridBoundsClamped(currentBounds);
						BoundsIntDifferenceEnumerable.BoundsIntDifferenceEnumerator enumerator = new BoundsIntDifferenceEnumerable(in outer, in visitedCells).GetEnumerator();
						while (enumerator.MoveNext())
						{
							Vector3Int gridPos2 = enumerator.Current;
							VisitCell(GridPosToCellIndex(in gridPos2));
						}
						visitedCells = outer;
					}
					if (candidatesInsideRadius.Count == 0)
					{
						if (flag2)
						{
							return false;
						}
						if (flag3 && candidatesOutsideRadius.Count == 0)
						{
							return false;
						}
					}
					return true;
				}
				void VisitCell(BlockMapCellIndex cellIndex)
				{
					int num5 = visitedCellCount + 1;
					visitedCellCount = num5;
					ref BlockMapCell reference = ref cells[(int)cellIndex];
					int j = reference.itemStartIndex;
					for (int num6 = reference.itemStartIndex + reference.itemCount; j < num6; j++)
					{
						VisitItem(j);
					}
				}
			}
			finally
			{
				candidatesOutsideRadius = CollectionPool<ItemDistanceSqrPair, List<ItemDistanceSqrPair>>.ReturnCollection(candidatesOutsideRadius);
				candidatesInsideRadius = CollectionPool<ItemDistanceSqrPair, List<ItemDistanceSqrPair>>.ReturnCollection(candidatesInsideRadius);
			}
			void VisitItem(int itemIndex)
			{
				UnityEngine.Vector3 position2 = itemPositionGetter.GetPosition3(itemsPackedByCell[itemIndex]);
				ItemDistanceSqrPair itemDistanceSqrPair3 = default(ItemDistanceSqrPair);
				itemDistanceSqrPair3.itemIndex = itemIndex;
				itemDistanceSqrPair3.distanceSqr = (position2 - position).sqrMagnitude;
				ItemDistanceSqrPair item2 = itemDistanceSqrPair3;
				((item2.distanceSqr < radiusSqr) ? candidatesInsideRadius : candidatesOutsideRadius).Add(item2);
			}
		}

		private float DistanceToNearestWall(in UnityEngine.Vector3 position, in Bounds bounds)
		{
			UnityEngine.Vector3 vector = position - bounds.min;
			UnityEngine.Vector3 vector2 = bounds.max - position;
			float x = vector.x;
			x = ((x < vector.y) ? x : vector.y);
			x = ((x < vector.z) ? x : vector.z);
			x = ((x < vector2.x) ? x : vector2.x);
			x = ((x < vector2.y) ? x : vector2.y);
			return (x < vector2.z) ? x : vector2.z;
		}

		private float DistanceToNearestWall(in Bounds innerBounds, in Bounds outerBounds)
		{
			UnityEngine.Vector3 vector = innerBounds.min - outerBounds.min;
			UnityEngine.Vector3 vector2 = outerBounds.max - innerBounds.max;
			float x = vector.x;
			x = ((x < vector.y) ? x : vector.y);
			x = ((x < vector.z) ? x : vector.z);
			x = ((x < vector2.x) ? x : vector2.x);
			x = ((x < vector2.y) ? x : vector2.y);
			return (x < vector2.z) ? x : vector2.z;
		}

		private static Bounds GetSphereBounds(UnityEngine.Vector3 origin, float radius)
		{
			float num = radius * 2f;
			return new Bounds(origin, new UnityEngine.Vector3(num, num, num));
		}

		private BoundsInt WorldBoundsOverlappingToGridBounds(Bounds worldBounds)
		{
			UnityEngine.Vector3 worldPosition = worldBounds.min;
			Vector3Int minPosition = WorldPositionToGridPosFloor(in worldPosition);
			worldPosition = worldBounds.max;
			Vector3Int maxPosition = WorldPositionToGridPosCeil(in worldPosition);
			BoundsInt result = default(BoundsInt);
			result.SetMinMax(minPosition, maxPosition);
			return result;
		}

		private BoundsInt WorldBoundsToOverlappingGridBoundsClamped(Bounds worldBounds)
		{
			UnityEngine.Vector3 worldPosition = worldBounds.min;
			Vector3Int minPosition = WorldPositionToGridPosFloor(in worldPosition);
			worldPosition = worldBounds.max;
			Vector3Int maxPosition = WorldPositionToGridPosCeil(in worldPosition);
			minPosition.Clamp(Vector3Int.zero, cellCounts);
			maxPosition.Clamp(Vector3Int.zero, cellCounts);
			BoundsInt result = default(BoundsInt);
			result.SetMinMax(minPosition, maxPosition);
			return result;
		}

		private GridEnumerable ValidGridPositionsInBounds(Bounds bounds)
		{
			UnityEngine.Vector3 worldPosition = bounds.min;
			Vector3Int startPos = WorldPositionToGridPosFloor(in worldPosition);
			worldPosition = bounds.max;
			Vector3Int endPos = WorldPositionToGridPosCeil(in worldPosition);
			startPos.Clamp(Vector3Int.zero, cellCounts);
			endPos.Clamp(Vector3Int.zero, cellCounts);
			return new GridEnumerable(startPos, endPos);
		}

		private GridEnumerable ValidGridPositionsInBoundsWithExclusion(Bounds bounds, BoundsInt excludedCells)
		{
			UnityEngine.Vector3 worldPosition = bounds.min;
			Vector3Int startPos = WorldPositionToGridPosFloor(in worldPosition);
			worldPosition = bounds.max;
			Vector3Int endPos = WorldPositionToGridPosCeil(in worldPosition);
			startPos.Clamp(Vector3Int.zero, cellCounts - Vector3Int.one);
			endPos.Clamp(Vector3Int.zero, cellCounts - Vector3Int.one);
			return new GridEnumerable(startPos, endPos);
		}
	}
	public abstract class BroadNavigationSystem : IDisposable
	{
		public enum AgentHandle
		{
			None = -1
		}

		protected struct BaseAgentData
		{
			public bool enabled;

			public bool isValid;

			public float localTime;

			public UnityEngine.Vector3? currentPosition;

			public UnityEngine.Vector3? goalPosition;

			public float maxWalkSpeed;

			public float maxSlopeAngle;

			public float maxJumpHeight;
		}

		public struct AgentOutput
		{
			public float desiredJumpVelocity { get; set; }

			public UnityEngine.Vector3? nextPosition { get; set; }

			public float lastPathUpdate { get; set; }

			public bool targetReachable { get; set; }

			public float time { get; set; }
		}

		public readonly struct Agent
		{
			public static readonly Agent invalid = new Agent(null, AgentHandle.None);

			public readonly BroadNavigationSystem system;

			public readonly AgentHandle handle;

			private ref BaseAgentData agentData => ref system.allAgentData[(int)handle];

			public bool enabled
			{
				get
				{
					return agentData.enabled;
				}
				set
				{
					agentData.enabled = value;
				}
			}

			public float maxSlopeAngle
			{
				get
				{
					return agentData.maxSlopeAngle;
				}
				set
				{
					agentData.maxSlopeAngle = value;
				}
			}

			public float maxWalkSpeed
			{
				get
				{
					return agentData.maxWalkSpeed;
				}
				set
				{
					agentData.maxWalkSpeed = value;
				}
			}

			public float maxJumpHeight
			{
				get
				{
					return agentData.maxJumpHeight;
				}
				set
				{
					agentData.maxJumpHeight = value;
				}
			}

			public UnityEngine.Vector3? currentPosition
			{
				get
				{
					return agentData.currentPosition;
				}
				set
				{
					agentData.currentPosition = value;
				}
			}

			public UnityEngine.Vector3? goalPosition
			{
				get
				{
					return agentData.goalPosition;
				}
				set
				{
					agentData.goalPosition = value;
				}
			}

			public AgentOutput output => system.agentOutputs[(int)handle];

			public Agent(BroadNavigationSystem system, AgentHandle handle)
			{
				this.handle = handle;
				this.system = system;
			}

			public void ConfigureFromBody(CharacterBody body)
			{
				system.ConfigureAgentFromBodyInternal(in handle, body);
			}

			public void InvalidatePath()
			{
				system.InvalidateAgentPathInternal(in handle);
			}
		}

		private static readonly List<BroadNavigationSystem> instancesList;

		private IndexAllocator agentIndexAllocator = new IndexAllocator();

		private BaseAgentData[] allAgentData = Array.Empty<BaseAgentData>();

		private AgentOutput[] agentOutputs = Array.Empty<AgentOutput>();

		protected float localTime;

		protected int agentCount { get; private set; }

		static BroadNavigationSystem()
		{
			instancesList = new List<BroadNavigationSystem>();
			RoR2Application.onFixedUpdate += StaticUpdate;
		}

		private static void StaticUpdate()
		{
			if (Time.fixedDeltaTime == 0f)
			{
				return;
			}
			foreach (BroadNavigationSystem instances in instancesList)
			{
				instances.Update(Time.fixedDeltaTime);
			}
		}

		public BroadNavigationSystem()
		{
			instancesList.Add(this);
		}

		public virtual void Dispose()
		{
			instancesList.Remove(this);
			for (AgentHandle index = (AgentHandle)0; (int)index < allAgentData.Length; index++)
			{
				if (allAgentData[(int)index].isValid)
				{
					DestroyAgentInternal(in index);
				}
			}
		}

		public void RequestAgent(ref Agent agent)
		{
			AgentHandle index = (AgentHandle)agentIndexAllocator.RequestIndex();
			CreateAgentInternal(in index);
			agent = GetAgent(index);
		}

		public void ReturnAgent(ref Agent agent)
		{
			DestroyAgentInternal(in agent.handle);
			agentIndexAllocator.FreeIndex((int)agent.handle);
			agent = Agent.invalid;
		}

		public Agent GetAgent(AgentHandle agentHandle)
		{
			return new Agent(this, agentHandle);
		}

		public bool IsValidHandle(in AgentHandle handle)
		{
			if (!ArrayUtils.IsInBounds(allAgentData, (int)handle))
			{
				return false;
			}
			return allAgentData[(int)handle].isValid;
		}

		public void GetAgentOutput(in AgentHandle handle, out AgentOutput output)
		{
			output = agentOutputs[(int)handle];
		}

		private void Update(float deltaTime)
		{
			localTime += deltaTime;
			UpdateAgentsInternal(deltaTime);
		}

		private void CreateAgentInternal(in AgentHandle index)
		{
			int num = agentCount + 1;
			agentCount = num;
			ArrayUtils.EnsureCapacity(ref allAgentData, agentCount);
			ArrayUtils.EnsureCapacity(ref agentOutputs, agentCount);
			ref BaseAgentData reference = ref allAgentData[(int)index];
			reference.isValid = true;
			reference.localTime = 0f;
			CreateAgent(in index);
		}

		private void DestroyAgentInternal(in AgentHandle index)
		{
			DestroyAgent(in index);
			allAgentData[(int)index] = default(BaseAgentData);
			agentOutputs[(int)index] = default(AgentOutput);
			int num = agentCount - 1;
			agentCount = num;
		}

		private void UpdateAgentsInternal(float deltaTime)
		{
			for (AgentHandle agentHandle = (AgentHandle)0; (int)agentHandle < allAgentData.Length; agentHandle++)
			{
				ref BaseAgentData reference = ref allAgentData[(int)agentHandle];
				if (reference.enabled)
				{
					reference.localTime += deltaTime;
				}
			}
			UpdateAgents(deltaTime);
		}

		private void ConfigureAgentFromBodyInternal(in AgentHandle index, CharacterBody body)
		{
			ref BaseAgentData reference = ref allAgentData[(int)index];
			reference.maxWalkSpeed = 0f;
			reference.maxSlopeAngle = 0f;
			reference.maxJumpHeight = 0f;
			reference.currentPosition = null;
			if ((bool)body)
			{
				reference.maxWalkSpeed = body.moveSpeed;
				reference.maxSlopeAngle = body.characterMotor?.Motor.MaxStableSlopeAngle ?? 0f;
				reference.maxJumpHeight = body.maxJumpHeight;
				reference.currentPosition = body.footPosition;
			}
			ConfigureAgentFromBody(in index, body);
		}

		private void InvalidateAgentPathInternal(in AgentHandle index)
		{
			InvalidateAgentPath(in index);
		}

		protected ref readonly BaseAgentData GetAgentData(in AgentHandle agentHandle)
		{
			return ref allAgentData[(int)agentHandle];
		}

		protected void SetAgentOutput(in AgentHandle agentHandle, in AgentOutput output)
		{
			ref AgentOutput reference = ref agentOutputs[(int)agentHandle];
			reference = output;
			reference.time = localTime;
		}

		protected abstract void CreateAgent(in AgentHandle index);

		protected abstract void DestroyAgent(in AgentHandle index);

		protected abstract void UpdateAgents(float deltaTime);

		protected abstract void ConfigureAgentFromBody(in AgentHandle index, CharacterBody body);

		protected abstract void InvalidateAgentPath(in AgentHandle index);
	}
	public class DisableWithGate : MonoBehaviour
	{
		public string gateToMatch;

		public bool invert;

		private void Start()
		{
			if ((bool)SceneInfo.instance && SceneInfo.instance.groundNodes.IsGateOpen(gateToMatch) == invert)
			{
				base.gameObject.SetActive(value: false);
			}
		}
	}
	public class GateStateSetter : MonoBehaviour
	{
		public string gateToEnableWhenEnabled;

		public string gateToDisableWhenEnabled;

		private void OnEnable()
		{
			UpdateGates(enabledState: true);
		}

		private void OnDisable()
		{
			UpdateGates(enabledState: false);
		}

		private void UpdateGates(bool enabledState)
		{
			if ((bool)SceneInfo.instance)
			{
				if (!string.IsNullOrEmpty(gateToEnableWhenEnabled))
				{
					SceneInfo.instance.SetGateState(gateToEnableWhenEnabled, enabledState);
				}
				if (!string.IsNullOrEmpty(gateToDisableWhenEnabled))
				{
					SceneInfo.instance.SetGateState(gateToDisableWhenEnabled, !enabledState);
				}
			}
		}

		[ContextMenu("ToggleGates as if Enabled")]
		private void ToggleEnable()
		{
			UpdateGates(enabledState: true);
		}

		[ContextMenu("ToggleGates as if Disabled")]
		private void ToggleDisable()
		{
			UpdateGates(enabledState: false);
		}
	}
	[ExecuteInEditMode]
	public class MapNode : MonoBehaviour
	{
		public struct Link
		{
			public MapNode nodeB;

			public float distanceScore;

			public float minJumpHeight;

			public int hullMask;

			public int jumpHullMask;

			public string gateName;
		}

		public class MoveProbe
		{
			public CharacterController testCharacterController;

			private float testTimeStep = 1f / 15f;

			public void Init()
			{
				GameObject gameObject = new GameObject();
				gameObject.name = "NodeGraphProbe";
				_ = gameObject.transform;
				testCharacterController = gameObject.AddComponent<CharacterController>();
				testCharacterController.stepOffset = 0.5f;
				testCharacterController.slopeLimit = 60f;
			}

			public void SetHull(HullClassification hullClassification)
			{
				HullDef hullDef = HullDef.Find(hullClassification);
				testCharacterController.radius = hullDef.radius;
				testCharacterController.height = hullDef.height;
			}

			public void Destroy()
			{
				UnityEngine.Object.DestroyImmediate(testCharacterController.gameObject);
			}

			private static float DistanceXZ(UnityEngine.Vector3 a, UnityEngine.Vector3 b)
			{
				a.y = 0f;
				b.y = 0f;
				return UnityEngine.Vector3.Distance(a, b);
			}

			public static UnityEngine.Vector3 GetGroundPosition(UnityEngine.Vector3 footPosition, float height, float radius)
			{
				UnityEngine.Vector3 vector = UnityEngine.Vector3.up * (height * 0.5f - radius);
				UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up * (height * 0.5f);
				UnityEngine.Vector3 vector3 = footPosition + vector2;
				float num = radius * 0.5f + 0.005f;
				UnityEngine.Vector3 vector4 = footPosition + UnityEngine.Vector3.up * num;
				UnityEngine.Vector3 vector5 = vector3 + UnityEngine.Vector3.up * num;
				if (Physics.CapsuleCast(vector5 + vector, vector5 - vector, radius, UnityEngine.Vector3.down, out var hitInfo, num * 2f + 0.005f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					UnityEngine.Vector3 vector6 = hitInfo.distance * UnityEngine.Vector3.down;
					return vector4 + vector6;
				}
				return footPosition;
			}

			public UnityEngine.Vector3 GetGroundPosition(UnityEngine.Vector3 footPosition)
			{
				return GetGroundPosition(footPosition, testCharacterController.height, testCharacterController.radius);
			}

			public bool CapsuleOverlapTest(UnityEngine.Vector3 centerOfCapsule)
			{
				UnityEngine.Vector3 vector = UnityEngine.Vector3.up * (testCharacterController.height * 0.5f - testCharacterController.radius);
				_ = UnityEngine.Vector3.up * (testCharacterController.height * 0.5f);
				return Physics.OverlapCapsule(centerOfCapsule + vector, centerOfCapsule - vector, testCharacterController.radius, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault, QueryTriggerInteraction.Ignore).Length == 0;
			}

			public bool FlyTest(UnityEngine.Vector3 startPos, UnityEngine.Vector3 endPos, float flySpeed)
			{
				UnityEngine.Vector3 vector = UnityEngine.Vector3.up * (testCharacterController.height * 0.5f - testCharacterController.radius);
				return !Physics.CapsuleCast(startPos + vector, startPos - vector, testCharacterController.radius, (endPos - startPos).normalized, (endPos - startPos).magnitude, LayerIndex.world.mask);
			}

			private void MoveCapsule(UnityEngine.Vector3 displacement)
			{
				testCharacterController.Move(displacement);
			}

			private void SetCapsulePosition(UnityEngine.Vector3 position)
			{
				testCharacterController.transform.position = position;
				Physics.SyncTransforms();
			}

			public bool GroundTest(UnityEngine.Vector3 startCenterOfCapsulePos, UnityEngine.Vector3 endCenterOfCapsulePos, float hSpeed)
			{
				MoveCapsule(UnityEngine.Vector3.zero);
				UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
				float num = DistanceXZ(startCenterOfCapsulePos, endCenterOfCapsulePos);
				SetCapsulePosition(startCenterOfCapsulePos + UnityEngine.Vector3.up);
				int num2 = Mathf.CeilToInt(num * 1.5f / hSpeed / testTimeStep);
				UnityEngine.Vector3 vector = testCharacterController.transform.position;
				for (int i = 0; i < num2; i++)
				{
					UnityEngine.Vector3 vector2 = endCenterOfCapsulePos - testCharacterController.transform.position;
					if (vector2.sqrMagnitude <= 0.25f)
					{
						return true;
					}
					UnityEngine.Vector3 vector3 = vector2;
					vector3.y = 0f;
					vector3.Normalize();
					zero.x = vector3.x * hSpeed;
					zero.z = vector3.z * hSpeed;
					zero += Physics.gravity * testTimeStep;
					MoveCapsule(zero * testTimeStep);
					UnityEngine.Vector3 position = testCharacterController.transform.position;
					if (position == vector)
					{
						return false;
					}
					vector = position;
				}
				return false;
			}

			public float JumpTest(UnityEngine.Vector3 startCenterOfCapsulePos, UnityEngine.Vector3 endCenterOfCapsulePos, float hSpeed)
			{
				float y = Trajectory.CalculateInitialYSpeed(Trajectory.CalculateGroundTravelTime(hSpeed, DistanceXZ(startCenterOfCapsulePos, endCenterOfCapsulePos)), endCenterOfCapsulePos.y - startCenterOfCapsulePos.y);
				testCharacterController.Move(UnityEngine.Vector3.zero);
				UnityEngine.Vector3 vector = endCenterOfCapsulePos - startCenterOfCapsulePos;
				vector.y = 0f;
				vector.Normalize();
				vector *= hSpeed;
				vector.y = y;
				float num = DistanceXZ(startCenterOfCapsulePos, endCenterOfCapsulePos);
				SetCapsulePosition(startCenterOfCapsulePos);
				int num2 = Mathf.CeilToInt(num * 1.5f / hSpeed / testTimeStep);
				float num3 = float.NegativeInfinity;
				UnityEngine.Vector3 vector2 = testCharacterController.transform.position;
				for (int i = 0; i < num2; i++)
				{
					UnityEngine.Vector3 vector3 = endCenterOfCapsulePos - testCharacterController.transform.position;
					if (vector3.sqrMagnitude <= 4f)
					{
						return num3 - startCenterOfCapsulePos.y;
					}
					num3 = Mathf.Max(testCharacterController.transform.position.y, num3);
					UnityEngine.Vector3 vector4 = vector3;
					vector4.y = 0f;
					vector4.Normalize();
					vector.x = vector4.x * hSpeed;
					vector.z = vector4.z * hSpeed;
					vector += Physics.gravity * testTimeStep;
					testCharacterController.Move(vector * testTimeStep);
					UnityEngine.Vector3 position = testCharacterController.transform.position;
					if (position == vector2)
					{
						return 0f;
					}
					vector2 = position;
				}
				return 0f;
			}
		}

		private static List<MapNode> _instances = new List<MapNode>();

		private static ReadOnlyCollection<MapNode> instancesReadOnly = _instances.AsReadOnly();

		public static readonly float maxConnectionDistance = 15f;

		public List<Link> links = new List<Link>();

		[EnumMask(typeof(HullMask))]
		public HullMask forbiddenHulls;

		[EnumMask(typeof(NodeFlags))]
		public NodeFlags flags;

		[Tooltip("The name of the nodegraph gate associated with this node. If the named gate is closed this node will be treated as though it does not exist.")]
		public string gateName = "";

		public static ReadOnlyCollection<MapNode> instances => instancesReadOnly;

		public void OnEnable()
		{
			_instances.Add(this);
		}

		public void OnDisable()
		{
			_instances.Remove(this);
		}

		private void AddLink(MapNode nodeB, float distanceScore, float minJumpHeight, HullClassification hullClassification)
		{
			int num = links.FindIndex((Link item) => item.nodeB == nodeB);
			if (num == -1)
			{
				links.Add(new Link
				{
					nodeB = nodeB
				});
				num = links.Count - 1;
			}
			Link value = links[num];
			value.distanceScore = Mathf.Max(value.distanceScore, distanceScore);
			value.minJumpHeight = Mathf.Max(value.minJumpHeight, minJumpHeight);
			value.hullMask |= 1 << (int)hullClassification;
			if (minJumpHeight > 0f)
			{
				value.jumpHullMask |= 1 << (int)hullClassification;
			}
			if (string.IsNullOrEmpty(value.gateName))
			{
				value.gateName = nodeB.gateName;
			}
			links[num] = value;
		}

		private void BuildGroundLinks(ReadOnlyCollection<MapNode> nodes, MoveProbe moveProbe)
		{
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < nodes.Count; i++)
			{
				MapNode mapNode = nodes[i];
				if (mapNode == this)
				{
					continue;
				}
				UnityEngine.Vector3 position2 = mapNode.transform.position;
				float num = maxConnectionDistance;
				float num2 = num * num;
				float sqrMagnitude = (position2 - position).sqrMagnitude;
				if (!(sqrMagnitude < num2))
				{
					continue;
				}
				float distanceScore = Mathf.Sqrt(sqrMagnitude);
				for (int j = 0; j < 3; j++)
				{
					moveProbe.SetHull((HullClassification)j);
					if (((uint)forbiddenHulls & (uint)(1 << j)) != 0 || ((uint)mapNode.forbiddenHulls & (uint)(1 << j)) != 0)
					{
						continue;
					}
					UnityEngine.Vector3 vector = UnityEngine.Vector3.up * (moveProbe.testCharacterController.height * 0.5f);
					UnityEngine.Vector3 vector2 = UnityEngine.Vector3.up * 0.01f;
					UnityEngine.Vector3 vector3 = moveProbe.GetGroundPosition(position) + vector2;
					UnityEngine.Vector3 vector4 = moveProbe.GetGroundPosition(position2) + vector2;
					UnityEngine.Vector3 vector5 = vector3 + vector;
					UnityEngine.Vector3 vector6 = vector4 + vector;
					if (moveProbe.CapsuleOverlapTest(vector5) && moveProbe.CapsuleOverlapTest(vector6))
					{
						bool num3 = moveProbe.GroundTest(vector5, vector6, 6f);
						float num4 = ((!num3) ? moveProbe.JumpTest(vector5, vector6, 7.5f) : 0f);
						if (num3 || (num4 > 0f && num4 < 10f))
						{
							AddLink(mapNode, distanceScore, num4, (HullClassification)j);
						}
					}
				}
			}
		}

		private void BuildAirLinks(ReadOnlyCollection<MapNode> nodes, MoveProbe moveProbe)
		{
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < nodes.Count; i++)
			{
				MapNode mapNode = nodes[i];
				if (mapNode == this)
				{
					continue;
				}
				UnityEngine.Vector3 position2 = mapNode.transform.position;
				float num = maxConnectionDistance * 2f;
				float num2 = num * num;
				float sqrMagnitude = (position2 - position).sqrMagnitude;
				if (!(sqrMagnitude < num2))
				{
					continue;
				}
				float distanceScore = Mathf.Sqrt(sqrMagnitude);
				for (int j = 0; j < 3; j++)
				{
					if (((uint)forbiddenHulls & (uint)(1 << j)) == 0 && ((uint)mapNode.forbiddenHulls & (uint)(1 << j)) == 0)
					{
						moveProbe.SetHull((HullClassification)j);
						UnityEngine.Vector3 vector = position;
						UnityEngine.Vector3 vector2 = position2;
						if (moveProbe.CapsuleOverlapTest(vector) && moveProbe.CapsuleOverlapTest(vector2) && moveProbe.FlyTest(vector, vector2, 6f))
						{
							AddLink(mapNode, distanceScore, 0f, (HullClassification)j);
						}
					}
				}
			}
		}

		private void BuildRailLinks(ReadOnlyCollection<MapNode> nodes, MoveProbe moveProbe)
		{
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < nodes.Count; i++)
			{
				MapNode mapNode = nodes[i];
				if (mapNode == this)
				{
					continue;
				}
				UnityEngine.Vector3 position2 = mapNode.transform.position;
				float num = maxConnectionDistance * 2f;
				float num2 = num * num;
				float sqrMagnitude = (position2 - position).sqrMagnitude;
				if (!(sqrMagnitude < num2))
				{
					continue;
				}
				float distanceScore = Mathf.Sqrt(sqrMagnitude);
				for (int j = 0; j < 3; j++)
				{
					HullDef hullDef = HullDef.Find((HullClassification)j);
					if (((uint)forbiddenHulls & (uint)(1 << j)) != 0 || ((uint)mapNode.forbiddenHulls & (uint)(1 << j)) != 0)
					{
						continue;
					}
					moveProbe.SetHull((HullClassification)j);
					UnityEngine.Vector3 vector = position;
					UnityEngine.Vector3 vector2 = position2;
					if (!(UnityEngine.Vector3.Angle(UnityEngine.Vector3.up, vector2 - vector) <= 50f))
					{
						vector.y += hullDef.height;
						vector2.y += hullDef.height;
						if (moveProbe.CapsuleOverlapTest(vector) && moveProbe.CapsuleOverlapTest(vector2) && moveProbe.FlyTest(vector, vector2, 6f))
						{
							AddLink(mapNode, distanceScore, 0f, (HullClassification)j);
						}
					}
				}
			}
		}

		public void BuildLinks(ReadOnlyCollection<MapNode> nodes, MapNodeGroup.GraphType graphType)
		{
			links.Clear();
			UnityEngine.Vector3 position = base.transform.position;
			MoveProbe moveProbe = new MoveProbe();
			moveProbe.Init();
			switch (graphType)
			{
			case MapNodeGroup.GraphType.Ground:
				BuildGroundLinks(nodes, moveProbe);
				break;
			case MapNodeGroup.GraphType.Air:
				BuildAirLinks(nodes, moveProbe);
				break;
			case MapNodeGroup.GraphType.Rail:
				BuildRailLinks(nodes, moveProbe);
				break;
			}
			MapNodeLink[] components = GetComponents<MapNodeLink>();
			foreach (MapNodeLink mapNodeLink in components)
			{
				if (!mapNodeLink.other)
				{
					continue;
				}
				Link link = default(Link);
				link.nodeB = mapNodeLink.other;
				link.distanceScore = UnityEngine.Vector3.Distance(position, mapNodeLink.other.transform.position);
				link.minJumpHeight = mapNodeLink.minJumpHeight;
				link.gateName = mapNodeLink.gateName;
				link.hullMask = -1;
				Link link2 = link;
				bool flag = false;
				for (int j = 0; j < links.Count; j++)
				{
					if (links[j].nodeB == mapNodeLink.other)
					{
						links[j] = link2;
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					links.Add(link2);
				}
			}
			moveProbe.Destroy();
		}

		public bool TestLineOfSight(MapNode other)
		{
			return !Physics.Linecast(base.transform.position + UnityEngine.Vector3.up, other.transform.position + UnityEngine.Vector3.up, LayerIndex.world.mask);
		}

		public bool TestNoCeiling()
		{
			return !Physics.Raycast(new Ray(base.transform.position, UnityEngine.Vector3.up), float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
		}

		public bool TestTeleporterOK()
		{
			float num = 15f;
			int num2 = 20;
			float num3 = 7f;
			float num4 = 3f;
			float num5 = 360f / (float)num2;
			for (int i = 0; i < num2; i++)
			{
				UnityEngine.Vector3 vector = UnityEngine.Quaternion.AngleAxis(num5 * (float)i, UnityEngine.Vector3.up) * (UnityEngine.Vector3.forward * num);
				UnityEngine.Vector3 origin = base.transform.position + vector + UnityEngine.Vector3.up * num3;
				if (!Physics.Raycast(new Ray(origin, UnityEngine.Vector3.down), out var _, num4 + num3, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					return false;
				}
			}
			UnityEngine.Debug.DrawRay(base.transform.position, base.transform.up * 20f, UnityEngine.Color.green, 15f);
			return true;
		}
	}
	public class MapNodeGroup : MonoBehaviour
	{
		public enum GraphType
		{
			Ground,
			Air,
			Rail
		}

		public NodeGraph nodeGraph;

		public Transform testPointA;

		public Transform testPointB;

		public HullClassification debugHullDef;

		public GraphType graphType;

		public void Clear()
		{
			for (int num = base.transform.childCount - 1; num >= 0; num--)
			{
				UnityEngine.Object.DestroyImmediate(base.transform.GetChild(num).gameObject);
			}
		}

		public GameObject AddNode(UnityEngine.Vector3 position)
		{
			GameObject obj = new GameObject();
			obj.transform.position = position;
			obj.transform.parent = base.transform;
			obj.AddComponent<MapNode>();
			obj.name = "MapNode";
			return obj;
		}

		public List<MapNode> GetNodes()
		{
			List<MapNode> result = new List<MapNode>();
			GetComponentsInChildren(includeInactive: false, result);
			return result;
		}

		public void UpdateNoCeilingMasks()
		{
			int num = 0;
			foreach (MapNode node in GetNodes())
			{
				node.flags &= ~NodeFlags.NoCeiling;
				if (node.TestNoCeiling())
				{
					num++;
					node.flags |= NodeFlags.NoCeiling;
				}
			}
			UnityEngine.Debug.LogFormat("{0} successful ceiling masks baked.", num);
		}

		public void UpdateTeleporterMasks()
		{
			int num = 0;
			foreach (MapNode node in GetNodes())
			{
				node.flags &= ~NodeFlags.TeleporterOK;
				if (node.TestTeleporterOK())
				{
					num++;
					node.flags |= NodeFlags.TeleporterOK;
				}
			}
			UnityEngine.Debug.LogFormat("{0} successful teleporter masks baked.", num);
		}

		public void Bake(NodeGraph nodeGraph)
		{
			List<MapNode> nodes = GetNodes();
			ReadOnlyCollection<MapNode> readOnlyCollection = nodes.AsReadOnly();
			for (int i = 0; i < nodes.Count; i++)
			{
				nodes[i].BuildLinks(readOnlyCollection, graphType);
			}
			List<SerializableBitArray> list = new List<SerializableBitArray>();
			for (int j = 0; j < nodes.Count; j++)
			{
				MapNode mapNode = nodes[j];
				SerializableBitArray serializableBitArray = new SerializableBitArray(nodes.Count);
				for (int k = 0; k < nodes.Count; k++)
				{
					MapNode other = nodes[k];
					serializableBitArray[k] = mapNode.TestLineOfSight(other);
				}
				list.Add(serializableBitArray);
			}
			nodeGraph.SetNodes(readOnlyCollection, list.AsReadOnly());
		}
	}
	[RequireComponent(typeof(MapNode))]
	public class MapNodeLink : MonoBehaviour
	{
		public MapNode other;

		public float minJumpHeight;

		[Tooltip("The gate name associated with this link. If the named gate is closed, this link will not be used in pathfinding.")]
		public string gateName = "";

		public GameObject[] objectsToEnableDuringTest;

		public GameObject[] objectsToDisableDuringTest;

		private void OnValidate()
		{
			if (other == this)
			{
				UnityEngine.Debug.LogWarning("Map node link cannot link a node to itself.");
				other = null;
			}
			if ((bool)other && other.GetComponentInParent<MapNodeGroup>() != GetComponentInParent<MapNodeGroup>())
			{
				UnityEngine.Debug.LogWarning("Map node link cannot link to a node in a separate node group.");
				other = null;
			}
		}

		private void OnDrawGizmos()
		{
			if ((bool)other)
			{
				UnityEngine.Vector3 position = base.transform.position;
				UnityEngine.Vector3 position2 = other.transform.position;
				UnityEngine.Vector3 vector = (position + position2) * 0.5f;
				UnityEngine.Color yellow = UnityEngine.Color.yellow;
				yellow.a = 0.5f;
				Gizmos.color = UnityEngine.Color.yellow;
				Gizmos.DrawLine(position, vector);
				Gizmos.color = yellow;
				Gizmos.DrawLine(vector, position2);
			}
		}
	}
	[Flags]
	public enum NodeFlags : byte
	{
		None = 0,
		NoCeiling = 1,
		TeleporterOK = 2,
		NoCharacterSpawn = 4,
		NoChestSpawn = 8,
		NoShrineSpawn = 0x10
	}
	public class PathTask
	{
		public enum TaskStatus
		{
			NotStarted,
			Running,
			Complete
		}

		public TaskStatus status;

		public bool wasReachable;

		public Path path { get; private set; }

		public PathTask(Path path)
		{
			this.path = path;
		}

		public void Wait()
		{
		}
	}
	[CreateAssetMenu(menuName = "RoR2/NodeGraph")]
	[PreferBinarySerialization]
	public class NodeGraph : ScriptableObject
	{
		[Serializable]
		public struct NodeIndex : IEquatable<NodeIndex>
		{
			public int nodeIndex;

			public static readonly NodeIndex invalid = new NodeIndex(-1);

			public NodeIndex(int nodeIndex)
			{
				this.nodeIndex = nodeIndex;
			}

			public static bool operator ==(NodeIndex lhs, NodeIndex rhs)
			{
				return lhs.nodeIndex == rhs.nodeIndex;
			}

			public static bool operator !=(NodeIndex lhs, NodeIndex rhs)
			{
				return lhs.nodeIndex != rhs.nodeIndex;
			}

			public override bool Equals(object other)
			{
				if (other is NodeIndex)
				{
					return ((NodeIndex)other).nodeIndex == nodeIndex;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return nodeIndex;
			}

			public bool Equals(NodeIndex other)
			{
				return nodeIndex == other.nodeIndex;
			}
		}

		[Serializable]
		public struct LinkIndex
		{
			public int linkIndex;

			public static readonly LinkIndex invalid = new LinkIndex
			{
				linkIndex = -1
			};

			public static bool operator ==(LinkIndex lhs, LinkIndex rhs)
			{
				return lhs.linkIndex == rhs.linkIndex;
			}

			public static bool operator !=(LinkIndex lhs, LinkIndex rhs)
			{
				return lhs.linkIndex != rhs.linkIndex;
			}

			public override bool Equals(object other)
			{
				if (other is LinkIndex)
				{
					return ((LinkIndex)other).linkIndex == linkIndex;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return linkIndex;
			}
		}

		[Serializable]
		public struct LinkListIndex
		{
			public int index;

			public uint size;
		}

		[Serializable]
		public struct Node
		{
			public UnityEngine.Vector3 position;

			public LinkListIndex linkListIndex;

			public HullMask forbiddenHulls;

			public SerializableBitArray lineOfSightMask;

			public byte gateIndex;

			public NodeFlags flags;
		}

		[Serializable]
		public struct Link
		{
			public NodeIndex nodeIndexA;

			public NodeIndex nodeIndexB;

			public float distanceScore;

			public float maxSlope;

			public float minJumpHeight;

			public int hullMask;

			public int jumpHullMask;

			public byte gateIndex;
		}

		private struct NodePositionGetter : IPosition3Getter<NodeIndex>
		{
			private readonly NodeGraph nodeGraph;

			public NodePositionGetter(NodeGraph nodeGraph)
			{
				this.nodeGraph = nodeGraph;
			}

			public UnityEngine.Vector3 GetPosition3(NodeIndex item)
			{
				return nodeGraph.nodes[item.nodeIndex].position;
			}
		}

		public readonly struct PathRequestPosition
		{
			public readonly NodeIndex? nodeIndex;

			public readonly UnityEngine.Vector3? position;

			private PathRequestPosition(NodeIndex nodeIndex)
			{
				this.nodeIndex = nodeIndex;
				position = null;
			}

			private PathRequestPosition(UnityEngine.Vector3 position)
			{
				nodeIndex = null;
				this.position = position;
			}

			public static implicit operator PathRequestPosition(NodeIndex nodeIndex)
			{
				return new PathRequestPosition(nodeIndex);
			}

			public static implicit operator PathRequestPosition(UnityEngine.Vector3 position)
			{
				return new PathRequestPosition(position);
			}
		}

		public class PathRequest
		{
			public Path path;

			public PathRequestPosition startPos;

			public PathRequestPosition endPos;

			public HullClassification hullClassification;

			public float maxSlope;

			public float maxJumpHeight;

			public float maxSpeed;

			public PathRequest()
			{
				Init();
			}

			public void Reset()
			{
				Init();
			}

			private void Init()
			{
				path = null;
				startPos = NodeIndex.invalid;
				endPos = NodeIndex.invalid;
				hullClassification = HullClassification.Human;
				maxSlope = 0f;
				maxJumpHeight = 0f;
				maxSpeed = 0f;
			}
		}

		private static class NodeFilters
		{
			public interface INodeCheckFilterComponent
			{
				bool CheckNode(NodeGraph nodeGraph, ref Node node);
			}

			public struct NodeCheckFilterAnd<TFilterA, TFilterB> : INodeCheckFilterComponent where TFilterA : INodeCheckFilterComponent where TFilterB : INodeCheckFilterComponent
			{
				private TFilterA filterA;

				private TFilterB filterB;

				public NodeCheckFilterAnd(TFilterA filterA, TFilterB filterB)
				{
					this.filterA = filterA;
					this.filterB = filterB;
				}

				public bool CheckNode(NodeGraph nodeGraph, ref Node node)
				{
					if (filterA.CheckNode(nodeGraph, ref node))
					{
						return filterB.CheckNode(nodeGraph, ref node);
					}
					return false;
				}
			}

			public struct NodeSearchFilter<TNodeCheckFilter> : IBlockMapSearchFilter<NodeIndex> where TNodeCheckFilter : INodeCheckFilterComponent
			{
				private readonly NodeGraph nodeGraph;

				private TNodeCheckFilter nodeCheckFilter;

				public NodeSearchFilter(NodeGraph nodeGraph, TNodeCheckFilter nodeCheckFilter)
				{
					this.nodeGraph = nodeGraph;
					this.nodeCheckFilter = nodeCheckFilter;
				}

				public bool CheckItem(NodeIndex item, ref bool shouldFinish)
				{
					return nodeCheckFilter.CheckNode(nodeGraph, ref nodeGraph.nodes[item.nodeIndex]);
				}
			}

			public readonly struct NodeHullFilter : INodeCheckFilterComponent
			{
				private readonly HullMask hullMask;

				public NodeHullFilter(HullMask hullMask)
				{
					this.hullMask = hullMask;
				}

				public NodeHullFilter(HullClassification hullClassification)
				{
					hullMask = (HullMask)(1 << (int)hullClassification);
				}

				public bool CheckNode(NodeGraph nodeGraph, ref Node node)
				{
					return (node.forbiddenHulls & hullMask) == 0;
				}
			}

			public readonly struct NodeFlagsFilter : INodeCheckFilterComponent
			{
				private readonly NodeFlags requiredFlags;

				private readonly NodeFlags forbiddenFlags;

				public NodeFlagsFilter(NodeFlags requiredFlags, NodeFlags forbiddenFlags)
				{
					this.requiredFlags = requiredFlags;
					this.forbiddenFlags = forbiddenFlags;
				}

				public bool CheckNode(NodeGraph nodeGraph, ref Node node)
				{
					NodeFlags flags = node.flags;
					if ((flags & forbiddenFlags) == 0)
					{
						return (flags & requiredFlags) == requiredFlags;
					}
					return false;
				}
			}

			[StructLayout(LayoutKind.Sequential, Size = 1)]
			public readonly struct NodeAvailableFilter : INodeCheckFilterComponent
			{
				public bool CheckNode(NodeGraph nodeGraph, ref Node node)
				{
					if (node.gateIndex != 0)
					{
						return nodeGraph.openGates[node.gateIndex];
					}
					return true;
				}
			}

			public struct NodeMinDistanceFilter : INodeCheckFilterComponent
			{
				private readonly UnityEngine.Vector3 position;

				private readonly float minDistanceSqr;

				public NodeMinDistanceFilter(UnityEngine.Vector3 position, float minDistance)
				{
					this.position = position;
					minDistanceSqr = minDistance * minDistance;
				}

				public bool CheckNode(NodeGraph nodeGraph, ref Node node)
				{
					return (node.position - position).sqrMagnitude >= minDistanceSqr;
				}
			}

			public struct NodeRaycastFilter : INodeCheckFilterComponent
			{
				private readonly UnityEngine.Vector3 raycastOrigin;

				private readonly UnityEngine.Vector3 raycastOffset;

				private readonly int maxRaycasts;

				private int raycastsPerformed;

				public NodeRaycastFilter(UnityEngine.Vector3 raycastOrigin, UnityEngine.Vector3 raycastOffset, int maxRaycasts)
				{
					this.raycastOrigin = raycastOrigin + raycastOffset;
					this.raycastOffset = raycastOffset;
					this.maxRaycasts = maxRaycasts;
					raycastsPerformed = 0;
				}

				public bool CheckNode(NodeGraph nodeGraph, ref Node node)
				{
					if (raycastsPerformed < maxRaycasts)
					{
						raycastsPerformed++;
						if (Physics.Linecast(raycastOrigin, node.position + raycastOffset, out var _, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
						{
							return false;
						}
					}
					return true;
				}
			}

			public struct NodeOverheadFilter : INodeCheckFilterComponent
			{
				private UnityEngine.Vector3 position;

				private bool enabled;

				public NodeOverheadFilter(UnityEngine.Vector3 position, bool enabled)
				{
					this.position = position;
					this.enabled = enabled;
				}

				public bool CheckNode(NodeGraph nodeGraph, ref Node node)
				{
					if (enabled && UnityEngine.Vector3.Dot((node.position - position).normalized, UnityEngine.Vector3.up) > 0.70710677f)
					{
						return false;
					}
					return true;
				}
			}

			public static NodeSearchFilter<TFilter> Create<TFilter>(NodeGraph nodeGraph, TFilter nodeCheckFilter) where TFilter : INodeCheckFilterComponent
			{
				return new NodeSearchFilter<TFilter>(nodeGraph, nodeCheckFilter);
			}

			public static NodeCheckFilterAnd<TFilterA, TFilterB> And<TFilterA, TFilterB>(TFilterA filterA, TFilterB filterB) where TFilterA : INodeCheckFilterComponent where TFilterB : INodeCheckFilterComponent
			{
				return new NodeCheckFilterAnd<TFilterA, TFilterB>(filterA, filterB);
			}

			public static NodeCheckFilterAnd<TFilterA, NodeCheckFilterAnd<TFilterB, TFilterC>> And<TFilterA, TFilterB, TFilterC>(TFilterA filterA, TFilterB filterB, TFilterC filterC) where TFilterA : INodeCheckFilterComponent where TFilterB : INodeCheckFilterComponent where TFilterC : INodeCheckFilterComponent
			{
				return And(filterA, And(filterB, filterC));
			}

			public static NodeCheckFilterAnd<TFilterA, NodeCheckFilterAnd<TFilterB, NodeCheckFilterAnd<TFilterC, TFilterD>>> And<TFilterA, TFilterB, TFilterC, TFilterD>(TFilterA filterA, TFilterB filterB, TFilterC filterC, TFilterD filterD) where TFilterA : INodeCheckFilterComponent where TFilterB : INodeCheckFilterComponent where TFilterC : INodeCheckFilterComponent where TFilterD : INodeCheckFilterComponent
			{
				return And(filterA, And(filterB, filterC, filterD));
			}

			public static NodeCheckFilterAnd<TFilterA, NodeCheckFilterAnd<TFilterB, NodeCheckFilterAnd<TFilterC, NodeCheckFilterAnd<TFilterD, TFilterE>>>> And<TFilterA, TFilterB, TFilterC, TFilterD, TFilterE>(TFilterA filterA, TFilterB filterB, TFilterC filterC, TFilterD filterD, TFilterE filterE) where TFilterA : INodeCheckFilterComponent where TFilterB : INodeCheckFilterComponent where TFilterC : INodeCheckFilterComponent where TFilterD : INodeCheckFilterComponent where TFilterE : INodeCheckFilterComponent
			{
				return And(filterA, And(filterB, filterC, filterD, filterE));
			}
		}

		[SerializeField]
		private Node[] nodes = Array.Empty<Node>();

		[SerializeField]
		private Link[] links = Array.Empty<Link>();

		[SerializeField]
		private List<string> gateNames = new List<string> { "" };

		private bool[] openGates = new bool[256];

		public UnityEngine.Vector3 cellSize = new UnityEngine.Vector3(15f, 30f, 15f);

		private BlockMap<NodeIndex, NodePositionGetter> blockMap = new BlockMap<NodeIndex, NodePositionGetter>();

		private FixedSizeArrayPool<bool> boolPerNodePool = new FixedSizeArrayPool<bool>(0);

		private FixedSizeArrayPool<float> floatPerNodePool = new FixedSizeArrayPool<float>(0);

		private FixedSizeArrayPool<NodeIndex> nodePerNodePool = new FixedSizeArrayPool<NodeIndex>(0);

		private FixedSizeArrayPool<LinkIndex> linkPerNodePool = new FixedSizeArrayPool<LinkIndex>(0);

		private const float overheadDotLimit = 0.70710677f;

		private void OnNodeCountChanged()
		{
			boolPerNodePool.lengthOfArrays = nodes.Length;
			floatPerNodePool.lengthOfArrays = nodes.Length;
			nodePerNodePool.lengthOfArrays = nodes.Length;
			linkPerNodePool.lengthOfArrays = nodes.Length;
		}

		private void Awake()
		{
			OnNodeCountChanged();
			RebuildBlockMap();
		}

		private void RebuildBlockMap()
		{
			NativeArray<NodeIndex> nativeArray = new NativeArray<NodeIndex>(nodes.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
			for (int i = 0; i < nodes.Length; i++)
			{
				nativeArray[i] = new NodeIndex(i);
			}
			try
			{
				blockMap.SetCellSize(cellSize);
				blockMap.Set(new NativeArrayIListWrapper<NodeIndex>(nativeArray), nativeArray.Length, new NodePositionGetter(this));
			}
			finally
			{
				nativeArray.Dispose();
			}
		}

		public void Clear()
		{
			nodes = Array.Empty<Node>();
			links = Array.Empty<Link>();
			gateNames.Clear();
			gateNames.Add("");
			blockMap.Reset();
			OnNodeCountChanged();
		}

		public void SetNodes(ReadOnlyCollection<MapNode> mapNodes, ReadOnlyCollection<SerializableBitArray> lineOfSightMasks)
		{
			Clear();
			Dictionary<MapNode, NodeIndex> dictionary = new Dictionary<MapNode, NodeIndex>();
			List<Node> list = new List<Node>();
			List<Link> list2 = new List<Link>();
			for (int i = 0; i < mapNodes.Count; i++)
			{
				MapNode key = mapNodes[i];
				dictionary[key] = new NodeIndex(i);
			}
			for (int j = 0; j < mapNodes.Count; j++)
			{
				MapNode mapNode = mapNodes[j];
				NodeIndex nodeIndexA = dictionary[mapNode];
				int count = list2.Count;
				for (int k = 0; k < mapNode.links.Count; k++)
				{
					MapNode.Link link = mapNode.links[k];
					if (!dictionary.ContainsKey(link.nodeB))
					{
						UnityEngine.Debug.LogErrorFormat(link.nodeB, "[{0}] Node {1} was not registered.", k, link.nodeB);
					}
					list2.Add(new Link
					{
						nodeIndexA = nodeIndexA,
						nodeIndexB = dictionary[link.nodeB],
						distanceScore = link.distanceScore,
						minJumpHeight = link.minJumpHeight,
						hullMask = link.hullMask,
						jumpHullMask = link.jumpHullMask,
						gateIndex = RegisterGateName(link.gateName)
					});
				}
				HullMask hullMask = mapNode.forbiddenHulls;
				for (HullClassification hullClassification = HullClassification.Human; hullClassification < HullClassification.Count; hullClassification++)
				{
					bool flag = false;
					int num = 1 << (int)hullClassification;
					List<MapNode.Link> list3 = mapNode.links;
					for (int l = 0; l < list3.Count; l++)
					{
						if ((list3[l].hullMask & num) != 0)
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						hullMask = (HullMask)((int)hullMask | num);
					}
				}
				list.Add(new Node
				{
					position = mapNode.transform.position,
					linkListIndex = new LinkListIndex
					{
						index = count,
						size = (uint)mapNode.links.Count
					},
					forbiddenHulls = hullMask,
					flags = mapNode.flags,
					lineOfSightMask = new SerializableBitArray(lineOfSightMasks[j]),
					gateIndex = RegisterGateName(mapNode.gateName)
				});
			}
			nodes = list.ToArray();
			links = list2.ToArray();
			OnNodeCountChanged();
			RebuildBlockMap();
		}

		public UnityEngine.Vector3 GetQuadraticCoordinates(float t, UnityEngine.Vector3 startPos, UnityEngine.Vector3 apexPos, UnityEngine.Vector3 endPos)
		{
			return Mathf.Pow(1f - t, 2f) * startPos + 2f * t * (1f - t) * apexPos + Mathf.Pow(t, 2f) * endPos;
		}

		public Mesh GenerateLinkDebugMesh(HullMask hullMask)
		{
			using WireMeshBuilder wireMeshBuilder = new WireMeshBuilder();
			Link[] array = links;
			for (int i = 0; i < array.Length; i++)
			{
				Link link = array[i];
				if (((uint)link.hullMask & (uint)hullMask) == 0)
				{
					continue;
				}
				UnityEngine.Vector3 position = nodes[link.nodeIndexA.nodeIndex].position;
				UnityEngine.Vector3 position2 = nodes[link.nodeIndexB.nodeIndex].position;
				UnityEngine.Vector3 vector = (position + position2) * 0.5f;
				bool num = ((uint)link.jumpHullMask & (uint)hullMask) != 0;
				UnityEngine.Color color = (num ? UnityEngine.Color.cyan : UnityEngine.Color.green);
				if (num)
				{
					UnityEngine.Vector3 apexPos = vector;
					apexPos.y = position.y + link.minJumpHeight;
					int num2 = 8;
					UnityEngine.Vector3 p = position;
					for (int j = 1; j <= num2; j++)
					{
						if (j > num2 / 2)
						{
							color.a = 0.1f;
						}
						UnityEngine.Vector3 quadraticCoordinates = GetQuadraticCoordinates((float)j / (float)num2, position, apexPos, position2);
						wireMeshBuilder.AddLine(p, color, quadraticCoordinates, color);
						p = quadraticCoordinates;
					}
				}
				else
				{
					UnityEngine.Color c = color;
					c.a = 0.1f;
					wireMeshBuilder.AddLine(position, color, (position + position2) * 0.5f, c);
				}
			}
			return wireMeshBuilder.GenerateMesh();
		}

		public void DebugDrawLinks(HullClassification hull)
		{
			int num = 1 << (int)hull;
			Link[] array = links;
			for (int i = 0; i < array.Length; i++)
			{
				Link link = array[i];
				if ((link.hullMask & num) == 0)
				{
					continue;
				}
				UnityEngine.Vector3 position = nodes[link.nodeIndexA.nodeIndex].position;
				UnityEngine.Vector3 position2 = nodes[link.nodeIndexB.nodeIndex].position;
				UnityEngine.Vector3 vector = (position + position2) * 0.5f;
				bool num2 = (link.jumpHullMask & num) != 0;
				UnityEngine.Color color = (num2 ? UnityEngine.Color.cyan : UnityEngine.Color.green);
				if (num2)
				{
					UnityEngine.Vector3 apexPos = vector;
					apexPos.y = position.y + link.minJumpHeight;
					int num3 = 8;
					UnityEngine.Vector3 start = position;
					for (int j = 1; j <= num3; j++)
					{
						if (j > num3 / 2)
						{
							color.a = 0.1f;
						}
						UnityEngine.Vector3 quadraticCoordinates = GetQuadraticCoordinates((float)j / (float)num3, position, apexPos, position2);
						UnityEngine.Debug.DrawLine(start, quadraticCoordinates, color, 10f);
						start = quadraticCoordinates;
					}
				}
				else
				{
					UnityEngine.Debug.DrawLine(position, vector, color, 10f, depthTest: false);
					UnityEngine.Color color2 = color;
					color2.a = 0.1f;
					UnityEngine.Debug.DrawLine(vector, position2, color2, 10f, depthTest: false);
				}
			}
		}

		public void DebugDrawPath(UnityEngine.Vector3 startPos, UnityEngine.Vector3 endPos)
		{
			Path path = new Path(this);
			ComputePath(new PathRequest
			{
				startPos = startPos,
				endPos = endPos,
				path = path,
				hullClassification = HullClassification.Human
			}).Wait();
			if (path.status == PathStatus.Valid)
			{
				for (int i = 1; i < path.waypointsCount; i++)
				{
					UnityEngine.Debug.DrawLine(nodes[path[i - 1].nodeIndex.nodeIndex].position, nodes[path[i].nodeIndex.nodeIndex].position, UnityEngine.Color.red, 10f);
				}
			}
		}

		public void DebugHighlightNodesWithNoLinks()
		{
			Node[] array = nodes;
			for (int i = 0; i < array.Length; i++)
			{
				Node node = array[i];
				if (node.linkListIndex.size == 0)
				{
					UnityEngine.Debug.DrawRay(node.position, UnityEngine.Vector3.up * 100f, UnityEngine.Color.cyan, 60f);
				}
			}
		}

		public int GetNodeCount()
		{
			return nodes.Length;
		}

		public List<NodeIndex> GetActiveNodesForHullMask(HullMask hullMask)
		{
			List<NodeIndex> list = new List<NodeIndex>(nodes.Length);
			GetActiveNodesForHullMask(hullMask, list);
			return list;
		}

		public void GetActiveNodesForHullMask(HullMask hullMask, List<NodeIndex> dest)
		{
			dest.Capacity = Math.Max(dest.Capacity, nodes.Length);
			for (int i = 0; i < nodes.Length; i++)
			{
				if ((nodes[i].forbiddenHulls & hullMask) == 0 && (nodes[i].gateIndex == 0 || openGates[nodes[i].gateIndex]))
				{
					dest.Add(new NodeIndex(i));
				}
			}
		}

		public List<NodeIndex> GetActiveNodesForHullMaskWithFlagConditions(HullMask hullMask, NodeFlags requiredFlags, NodeFlags forbiddenFlags)
		{
			List<NodeIndex> list = new List<NodeIndex>(nodes.Length);
			GetActiveNodesForHullMaskWithFlagConditions(hullMask, requiredFlags, forbiddenFlags, list);
			return list;
		}

		public void GetActiveNodesForHullMaskWithFlagConditions(HullMask hullMask, NodeFlags requiredFlags, NodeFlags forbiddenFlags, List<NodeIndex> dest)
		{
			for (int i = 0; i < nodes.Length; i++)
			{
				NodeFlags flags = nodes[i].flags;
				if ((flags & forbiddenFlags) == 0 && (flags & requiredFlags) == requiredFlags && (nodes[i].forbiddenHulls & hullMask) == 0 && (nodes[i].gateIndex == 0 || openGates[nodes[i].gateIndex]))
				{
					dest.Add(new NodeIndex(i));
				}
			}
		}

		public List<NodeIndex> FindNodesInRange(UnityEngine.Vector3 position, float minRange, float maxRange, HullMask hullMask)
		{
			List<NodeIndex> list = new List<NodeIndex>();
			FindNodesInRange(position, minRange, maxRange, hullMask, list);
			return list;
		}

		public void FindNodesInRange(UnityEngine.Vector3 position, float minRange, float maxRange, HullMask hullMask, List<NodeIndex> dest)
		{
			NodeFilters.NodeSearchFilter<NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeHullFilter, NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeAvailableFilter, NodeFilters.NodeMinDistanceFilter>>> filter = NodeFilters.Create(this, NodeFilters.And(new NodeFilters.NodeHullFilter(hullMask), default(NodeFilters.NodeAvailableFilter), new NodeFilters.NodeMinDistanceFilter(position, minRange)));
			blockMap.GetNearestItemsWhichPassFilter(position, maxRange, ref filter, dest);
		}

		public List<NodeIndex> FindNodesInRangeWithFlagConditions(UnityEngine.Vector3 position, float minRange, float maxRange, HullMask hullMask, NodeFlags requiredFlags, NodeFlags forbiddenFlags, bool preventOverhead)
		{
			List<NodeIndex> list = new List<NodeIndex>();
			FindNodesInRangeWithFlagConditions(position, minRange, maxRange, hullMask, requiredFlags, forbiddenFlags, preventOverhead, list);
			return list;
		}

		public void FindNodesInRangeWithFlagConditions(UnityEngine.Vector3 position, float minRange, float maxRange, HullMask hullMask, NodeFlags requiredFlags, NodeFlags forbiddenFlags, bool preventOverhead, List<NodeIndex> dest)
		{
			NodeFilters.NodeSearchFilter<NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeFlagsFilter, NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeHullFilter, NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeAvailableFilter, NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeOverheadFilter, NodeFilters.NodeMinDistanceFilter>>>>> filter = NodeFilters.Create(this, NodeFilters.And(new NodeFilters.NodeFlagsFilter(requiredFlags, forbiddenFlags), new NodeFilters.NodeHullFilter(hullMask), default(NodeFilters.NodeAvailableFilter), new NodeFilters.NodeOverheadFilter(position, preventOverhead), new NodeFilters.NodeMinDistanceFilter(position, minRange)));
			blockMap.GetNearestItemsWhichPassFilter(position, maxRange, ref filter, dest);
		}

		public bool GetNodePosition(NodeIndex nodeIndex, out UnityEngine.Vector3 position)
		{
			if (nodeIndex != NodeIndex.invalid && nodeIndex.nodeIndex < nodes.Length)
			{
				position = nodes[nodeIndex.nodeIndex].position;
				return true;
			}
			position = UnityEngine.Vector3.zero;
			return false;
		}

		public bool GetNodeFlags(NodeIndex nodeIndex, out NodeFlags flags)
		{
			if (nodeIndex != NodeIndex.invalid && nodeIndex.nodeIndex < nodes.Length)
			{
				flags = nodes[nodeIndex.nodeIndex].flags;
				return true;
			}
			flags = NodeFlags.None;
			return false;
		}

		public LinkIndex[] GetActiveNodeLinks(NodeIndex nodeIndex)
		{
			if (nodeIndex != NodeIndex.invalid && nodeIndex.nodeIndex < nodes.Length)
			{
				LinkListIndex linkListIndex = nodes[nodeIndex.nodeIndex].linkListIndex;
				LinkIndex[] array = new LinkIndex[linkListIndex.size];
				int index = linkListIndex.index;
				for (int i = 0; i < linkListIndex.size; i++)
				{
					array[i] = new LinkIndex
					{
						linkIndex = index++
					};
				}
				return array;
			}
			return null;
		}

		public void GetActiveNodeLinks(NodeIndex nodeIndex, List<LinkIndex> results)
		{
			if (nodeIndex != NodeIndex.invalid && nodeIndex.nodeIndex < nodes.Length)
			{
				LinkListIndex linkListIndex = nodes[nodeIndex.nodeIndex].linkListIndex;
				int index = linkListIndex.index;
				for (int i = 0; i < linkListIndex.size; i++)
				{
					results.Add(new LinkIndex
					{
						linkIndex = index++
					});
				}
			}
		}

		public bool TestNodeLineOfSight(NodeIndex nodeIndexA, NodeIndex nodeIndexB)
		{
			if (nodeIndexA != NodeIndex.invalid && nodeIndexA.nodeIndex < nodes.Length && nodeIndexB != NodeIndex.invalid && nodeIndexB.nodeIndex < nodes.Length)
			{
				return nodes[nodeIndexA.nodeIndex].lineOfSightMask[nodeIndexB.nodeIndex];
			}
			return false;
		}

		public bool GetPositionAlongLink(LinkIndex linkIndex, float t, out UnityEngine.Vector3 position)
		{
			if (linkIndex != LinkIndex.invalid && linkIndex.linkIndex < links.Length)
			{
				position = UnityEngine.Vector3.LerpUnclamped(nodes[links[linkIndex.linkIndex].nodeIndexA.nodeIndex].position, nodes[links[linkIndex.linkIndex].nodeIndexB.nodeIndex].position, t);
				return true;
			}
			position = UnityEngine.Vector3.zero;
			return false;
		}

		public bool IsLinkSuitableForHull(LinkIndex linkIndex, HullClassification hullClassification)
		{
			if (linkIndex != LinkIndex.invalid && linkIndex.linkIndex < links.Length)
			{
				if ((links[linkIndex.linkIndex].hullMask & (1 << (int)hullClassification)) != 0)
				{
					if (links[linkIndex.linkIndex].gateIndex != 0)
					{
						return openGates[links[linkIndex.linkIndex].gateIndex];
					}
					return true;
				}
				return false;
			}
			return false;
		}

		public bool IsLinkSuitableForHull(LinkIndex linkIndex, HullMask hullMask)
		{
			if (linkIndex != LinkIndex.invalid && linkIndex.linkIndex < links.Length)
			{
				if (((uint)links[linkIndex.linkIndex].hullMask & (uint)hullMask) != 0)
				{
					if (links[linkIndex.linkIndex].gateIndex != 0)
					{
						return openGates[links[linkIndex.linkIndex].gateIndex];
					}
					return true;
				}
				return false;
			}
			return false;
		}

		public NodeIndex GetLinkStartNode(LinkIndex linkIndex)
		{
			if (linkIndex != LinkIndex.invalid && linkIndex.linkIndex < links.Length)
			{
				return links[linkIndex.linkIndex].nodeIndexA;
			}
			return NodeIndex.invalid;
		}

		public NodeIndex GetLinkEndNode(LinkIndex linkIndex)
		{
			if (linkIndex != LinkIndex.invalid && linkIndex.linkIndex < links.Length)
			{
				return links[linkIndex.linkIndex].nodeIndexB;
			}
			return NodeIndex.invalid;
		}

		public NodeIndex FindClosestNode(UnityEngine.Vector3 position, HullClassification hullClassification, float maxDistance = float.PositiveInfinity)
		{
			NodeFilters.NodeSearchFilter<NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeHullFilter, NodeFilters.NodeAvailableFilter>> filter = NodeFilters.Create(this, NodeFilters.And(new NodeFilters.NodeHullFilter(hullClassification), default(NodeFilters.NodeAvailableFilter)));
			if (blockMap.GetNearestItemWhichPassesFilter(position, maxDistance, ref filter, out var dest))
			{
				return dest;
			}
			return NodeIndex.invalid;
		}

		public NodeIndex FindClosestNodeWithRaycast(UnityEngine.Vector3 position, HullClassification hullClassification, float maxDistance, int maxRaycasts)
		{
			NodeFilters.NodeSearchFilter<NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeHullFilter, NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeAvailableFilter, NodeFilters.NodeRaycastFilter>>> filter = NodeFilters.Create(this, NodeFilters.And(new NodeFilters.NodeHullFilter(hullClassification), default(NodeFilters.NodeAvailableFilter), new NodeFilters.NodeRaycastFilter(position, new UnityEngine.Vector3(0f, 0.2f, 0f), 3)));
			if (blockMap.GetNearestItemWhichPassesFilter(position, maxDistance, ref filter, out var dest))
			{
				return dest;
			}
			return NodeIndex.invalid;
		}

		public NodeIndex FindClosestNodeWithFlagConditions(UnityEngine.Vector3 position, HullClassification hullClassification, NodeFlags requiredFlags, NodeFlags forbiddenFlags, bool preventOverhead)
		{
			NodeFilters.NodeSearchFilter<NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeFlagsFilter, NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeHullFilter, NodeFilters.NodeCheckFilterAnd<NodeFilters.NodeAvailableFilter, NodeFilters.NodeOverheadFilter>>>> filter = NodeFilters.Create(this, NodeFilters.And(new NodeFilters.NodeFlagsFilter(requiredFlags, forbiddenFlags), new NodeFilters.NodeHullFilter(hullClassification), default(NodeFilters.NodeAvailableFilter), new NodeFilters.NodeOverheadFilter(position, preventOverhead)));
			if (blockMap.GetNearestItemWhichPassesFilter(position, float.PositiveInfinity, ref filter, out var dest))
			{
				return dest;
			}
			return NodeIndex.invalid;
		}

		private float HeuristicCostEstimate(UnityEngine.Vector3 startPos, UnityEngine.Vector3 endPos)
		{
			return UnityEngine.Vector3.Distance(startPos, endPos);
		}

		private static float DistanceXZ(UnityEngine.Vector3 a, UnityEngine.Vector3 b)
		{
			a.y = 0f;
			b.y = 0f;
			return UnityEngine.Vector3.Distance(a, b);
		}

		private static void ArrayRemoveNodeIndex(NodeIndex[] array, NodeIndex value, int count)
		{
			for (int i = 0; i < count; i++)
			{
				if (array[i] == value)
				{
					array[i] = array[count - 1];
					break;
				}
			}
		}

		private static void ArrayRemoveNodeIndexFromCachedPosition(NodeIndex[] array, int arrayIndex, int count)
		{
			array[arrayIndex] = array[count - 1];
		}

		public PathTask ComputePath(PathRequest pathRequest)
		{
			bool[] array = boolPerNodePool.Request();
			bool[] array2 = boolPerNodePool.Request();
			NodeIndex[] array3 = nodePerNodePool.Request();
			LinkIndex[] array4 = linkPerNodePool.Request();
			ArrayUtils.SetAll(array4, in LinkIndex.invalid);
			float[] array5 = floatPerNodePool.Request();
			float value = float.PositiveInfinity;
			ArrayUtils.SetAll(array5, in value);
			float[] array6 = floatPerNodePool.Request();
			value = float.PositiveInfinity;
			ArrayUtils.SetAll(array6, in value);
			try
			{
				ResolveNodePosition(in pathRequest.startPos, out var dest2, 100f, 2);
				ResolveNodePosition(in pathRequest.endPos, out var dest3, 500f, 0);
				PathTask pathTask = new PathTask(pathRequest.path);
				pathTask.status = PathTask.TaskStatus.Running;
				if (dest2.nodeIndex == NodeIndex.invalid.nodeIndex || dest3.nodeIndex == NodeIndex.invalid.nodeIndex)
				{
					pathRequest.path.Clear();
					pathTask.status = PathTask.TaskStatus.Complete;
					pathTask.wasReachable = false;
					return pathTask;
				}
				int num = 1 << (int)pathRequest.hullClassification;
				array2[dest2.nodeIndex] = true;
				int num2 = 1;
				array3[0] = dest2;
				array5[dest2.nodeIndex] = 0f;
				array6[dest2.nodeIndex] = HeuristicCostEstimate(nodes[dest2.nodeIndex].position, nodes[dest3.nodeIndex].position);
				int arrayIndex = -1;
				while (num2 > 0)
				{
					NodeIndex nodeIndex = NodeIndex.invalid;
					float num3 = float.PositiveInfinity;
					for (int i = 0; i < num2; i++)
					{
						int nodeIndex2 = array3[i].nodeIndex;
						if (array6[nodeIndex2] <= num3)
						{
							num3 = array6[nodeIndex2];
							nodeIndex = new NodeIndex(nodeIndex2);
							arrayIndex = i;
						}
					}
					if (nodeIndex.nodeIndex == dest3.nodeIndex)
					{
						ReconstructPath(pathRequest.path, array4, array4[nodeIndex.nodeIndex], pathRequest);
						pathTask.status = PathTask.TaskStatus.Complete;
						pathTask.wasReachable = true;
						return pathTask;
					}
					array2[nodeIndex.nodeIndex] = false;
					ArrayRemoveNodeIndexFromCachedPosition(array3, arrayIndex, num2);
					num2--;
					array[nodeIndex.nodeIndex] = true;
					LinkListIndex linkListIndex = nodes[nodeIndex.nodeIndex].linkListIndex;
					LinkIndex linkIndex = default(LinkIndex);
					linkIndex.linkIndex = linkListIndex.index;
					LinkIndex linkIndex2 = linkIndex;
					linkIndex = default(LinkIndex);
					linkIndex.linkIndex = linkListIndex.index + (int)linkListIndex.size;
					for (LinkIndex linkIndex3 = linkIndex; linkIndex2.linkIndex < linkIndex3.linkIndex; linkIndex2.linkIndex++)
					{
						Link link = links[linkIndex2.linkIndex];
						NodeIndex nodeIndexB = link.nodeIndexB;
						if (array[nodeIndexB.nodeIndex])
						{
							continue;
						}
						if ((num & link.jumpHullMask) != 0 && links[linkIndex2.linkIndex].minJumpHeight > 0f)
						{
							UnityEngine.Vector3 position = nodes[link.nodeIndexA.nodeIndex].position;
							UnityEngine.Vector3 position2 = nodes[link.nodeIndexB.nodeIndex].position;
							if (Trajectory.CalculateApex(Trajectory.CalculateInitialYSpeed(Trajectory.CalculateGroundTravelTime(pathRequest.maxSpeed, DistanceXZ(position, position2)), position2.y - position.y)) > pathRequest.maxJumpHeight)
							{
								continue;
							}
						}
						if ((link.hullMask & num) != 0 && (link.gateIndex == 0 || openGates[link.gateIndex]))
						{
							float distanceScore = link.distanceScore;
							float num4 = array5[nodeIndex.nodeIndex] + distanceScore;
							if (!array2[nodeIndexB.nodeIndex])
							{
								array2[nodeIndexB.nodeIndex] = true;
								array3[num2] = nodeIndexB;
								num2++;
							}
							else if (num4 >= array5[nodeIndexB.nodeIndex])
							{
								continue;
							}
							array4[nodeIndexB.nodeIndex] = linkIndex2;
							array5[nodeIndexB.nodeIndex] = num4;
							array6[nodeIndexB.nodeIndex] = num4 + HeuristicCostEstimate(nodes[nodeIndexB.nodeIndex].position, nodes[dest3.nodeIndex].position);
						}
					}
				}
				pathRequest.path.Clear();
				pathTask.status = PathTask.TaskStatus.Complete;
				return pathTask;
			}
			catch (Exception ex)
			{
				UnityEngine.Debug.LogError($"ComputePath exception:  {ex}\n\n{ex.StackTrace}");
			}
			finally
			{
				floatPerNodePool.Return(array6, FixedSizeArrayPool<float>.ClearType.NONE);
				floatPerNodePool.Return(array5, FixedSizeArrayPool<float>.ClearType.NONE);
				linkPerNodePool.Return(array4, FixedSizeArrayPool<LinkIndex>.ClearType.NONE);
				nodePerNodePool.Return(array3, FixedSizeArrayPool<NodeIndex>.ClearType.CLEAR);
				boolPerNodePool.Return(array2, FixedSizeArrayPool<bool>.ClearType.CLEAR);
				boolPerNodePool.Return(array, FixedSizeArrayPool<bool>.ClearType.CLEAR);
			}
			return null;
			void ResolveNodePosition(in PathRequestPosition pathRequestPosition, out NodeIndex dest, float maxSearchDistance, int maxRaycasts)
			{
				if (pathRequestPosition.nodeIndex.HasValue)
				{
					dest = pathRequestPosition.nodeIndex.Value;
				}
				else if (pathRequestPosition.position.HasValue)
				{
					dest = FindClosestNodeWithRaycast(pathRequestPosition.position.Value, pathRequest.hullClassification, maxSearchDistance, maxRaycasts);
				}
				else
				{
					dest = NodeIndex.invalid;
				}
			}
		}

		private LinkIndex Resolve(LinkIndex[] cameFrom, LinkIndex current)
		{
			if (current.linkIndex < 0 || current.linkIndex > links.Length)
			{
				UnityEngine.Debug.LogFormat("Link {0} is out of range [0,{1})", current.linkIndex, links.Length);
			}
			NodeIndex nodeIndexA = links[current.linkIndex].nodeIndexA;
			return cameFrom[nodeIndexA.nodeIndex];
		}

		private void ReconstructPath(Path path, LinkIndex[] cameFrom, LinkIndex current, PathRequest pathRequest)
		{
			int num = 1 << (int)pathRequest.hullClassification;
			path.Clear();
			if (current != LinkIndex.invalid)
			{
				path.PushWaypointToFront(links[current.linkIndex].nodeIndexB, 0f);
			}
			while (current != LinkIndex.invalid)
			{
				NodeIndex nodeIndexB = links[current.linkIndex].nodeIndexB;
				float minJumpHeight = 0f;
				if ((num & links[current.linkIndex].jumpHullMask) != 0 && links[current.linkIndex].minJumpHeight > 0f)
				{
					UnityEngine.Vector3 position = nodes[links[current.linkIndex].nodeIndexA.nodeIndex].position;
					UnityEngine.Vector3 position2 = nodes[links[current.linkIndex].nodeIndexB.nodeIndex].position;
					minJumpHeight = Trajectory.CalculateApex(Trajectory.CalculateInitialYSpeed(Trajectory.CalculateGroundTravelTime(pathRequest.maxSpeed, DistanceXZ(position, position2)), position2.y - position.y));
				}
				path.PushWaypointToFront(nodeIndexB, minJumpHeight);
				if (cameFrom[links[current.linkIndex].nodeIndexA.nodeIndex] == LinkIndex.invalid)
				{
					path.PushWaypointToFront(links[current.linkIndex].nodeIndexA, 0f);
				}
				current = cameFrom[links[current.linkIndex].nodeIndexA.nodeIndex];
			}
			path.status = PathStatus.Valid;
		}

		private byte RegisterGateName(string gateName)
		{
			if (string.IsNullOrEmpty(gateName))
			{
				return 0;
			}
			int num = gateNames.IndexOf(gateName);
			if (num == -1)
			{
				num = gateNames.Count;
				if (num >= 256)
				{
					UnityEngine.Debug.LogErrorFormat(this, "Nodegraph cannot have more than 255 gate names. Nodegraph={0} gateName={1}", this, gateName);
					num = 0;
				}
				else
				{
					gateNames.Add(gateName);
				}
			}
			return (byte)num;
		}

		public bool IsGateOpen(string gateName)
		{
			int num = gateNames.IndexOf(gateName);
			if (num == -1)
			{
				return false;
			}
			return openGates[num];
		}

		public void SetGateState(string gateName, bool open)
		{
			TrySetGateState(gateName, open);
		}

		public bool TrySetGateState(string gateName, bool open)
		{
			int num = gateNames.IndexOf(gateName);
			if (num == -1)
			{
				return false;
			}
			openGates[num] = open;
			return true;
		}
	}
	public class NodeGraphSpider
	{
		public class StepInfo
		{
			public NodeGraph.NodeIndex node;

			public StepInfo previousStep;
		}

		[NotNull]
		private NodeGraph nodeGraph;

		private List<StepInfo> uncheckedSteps;

		private BitArray visitedNodes;

		public HullMask hullMask;

		[NotNull]
		public List<StepInfo> collectedSteps { get; private set; }

		public NodeGraphSpider([NotNull] NodeGraph nodeGraph, HullMask hullMask)
		{
			if ((object)nodeGraph == null)
			{
				throw new ArgumentNullException("nodeGraph", "'nodeGraph' must be valid.");
			}
			this.nodeGraph = nodeGraph;
			this.hullMask = hullMask;
			collectedSteps = new List<StepInfo>();
			uncheckedSteps = new List<StepInfo>();
			visitedNodes = new BitArray(nodeGraph.GetNodeCount());
		}

		public bool PerformStep()
		{
			List<StepInfo> list = uncheckedSteps;
			uncheckedSteps = new List<StepInfo>();
			List<NodeGraph.LinkIndex> list2 = CollectionPool<NodeGraph.LinkIndex, List<NodeGraph.LinkIndex>>.RentCollection();
			for (int i = 0; i < list.Count; i++)
			{
				StepInfo stepInfo = list[i];
				list2.Clear();
				nodeGraph.GetActiveNodeLinks(stepInfo.node, list2);
				for (int j = 0; j < list2.Count; j++)
				{
					NodeGraph.LinkIndex linkIndex = list2[j];
					if (nodeGraph.IsLinkSuitableForHull(linkIndex, hullMask))
					{
						NodeGraph.NodeIndex linkEndNode = nodeGraph.GetLinkEndNode(linkIndex);
						if (!visitedNodes[linkEndNode.nodeIndex])
						{
							uncheckedSteps.Add(new StepInfo
							{
								node = linkEndNode,
								previousStep = stepInfo
							});
							visitedNodes[linkEndNode.nodeIndex] = true;
						}
					}
				}
				collectedSteps.Add(stepInfo);
			}
			list2 = CollectionPool<NodeGraph.LinkIndex, List<NodeGraph.LinkIndex>>.ReturnCollection(list2);
			return list.Count > 0;
		}

		public void AddNodeForNextStep(NodeGraph.NodeIndex nodeIndex)
		{
			if (!(nodeIndex == NodeGraph.NodeIndex.invalid) && !visitedNodes[nodeIndex.nodeIndex])
			{
				uncheckedSteps.Add(new StepInfo
				{
					node = nodeIndex,
					previousStep = null
				});
				visitedNodes[nodeIndex.nodeIndex] = true;
			}
		}
	}
	public class NodeGraphNavigationSystem : BroadNavigationSystem
	{
		public struct AgentData
		{
			public NodeGraph nodeGraph;

			public PathFollower pathFollower;

			public NodeGraph.PathRequest pathRequest;

			public HullClassification hullClassification;

			public PathTask pathTask;

			public float updateInterval;

			public float nextUpdate;

			public bool targetReachable;

			public float lastTargetReachableUpdate;

			public NodeGraph.NodeIndex? lastKnownNode;

			public float timeLastKnownNodeEncountered;

			public float estimatedArrivalTimeAtLastKnownNode;

			private PathFollower.Drawer pathDrawer;

			public bool drawPath
			{
				get
				{
					return pathDrawer != null;
				}
				set
				{
					if (drawPath != value)
					{
						if (!value)
						{
							pathDrawer.Dispose();
							pathDrawer = null;
						}
						else
						{
							pathDrawer = new PathFollower.Drawer(pathFollower);
						}
					}
				}
			}

			public void Initialize()
			{
				nextUpdate = float.NegativeInfinity;
				nodeGraph = null;
				updateInterval = 2f;
				hullClassification = HullClassification.Human;
				pathFollower = pathFollower ?? new PathFollower();
				pathRequest = pathRequest ?? new NodeGraph.PathRequest();
				targetReachable = false;
				lastTargetReachableUpdate = float.NegativeInfinity;
				lastKnownNode = null;
				timeLastKnownNodeEncountered = float.NegativeInfinity;
				estimatedArrivalTimeAtLastKnownNode = float.NegativeInfinity;
				drawPath = false;
			}

			public void Dispose()
			{
				drawPath = false;
				nodeGraph = null;
				nextUpdate = float.NegativeInfinity;
				pathFollower.Reset();
				pathRequest.Reset();
				pathTask = null;
			}

			public void InvalidatePath()
			{
				nextUpdate = float.NegativeInfinity;
				pathTask = null;
			}
		}

		public new struct Agent
		{
			private readonly BroadNavigationSystem.Agent inner;

			private NodeGraphNavigationSystem system => (NodeGraphNavigationSystem)inner.system;

			private ref AgentData agentData => ref system.allAgentData[(int)inner.handle];

			public NodeGraph nodeGraph
			{
				get
				{
					return agentData.nodeGraph;
				}
				set
				{
					agentData.nodeGraph = value;
				}
			}

			public HullClassification hullClassification
			{
				get
				{
					return agentData.hullClassification;
				}
				set
				{
					agentData.hullClassification = value;
				}
			}

			public bool drawPath
			{
				get
				{
					return agentData.drawPath;
				}
				set
				{
					agentData.drawPath = value;
				}
			}

			public PathFollower pathFollower
			{
				get
				{
					return agentData.pathFollower;
				}
				set
				{
					agentData.pathFollower = value;
				}
			}

			public Agent(BroadNavigationSystem.Agent inner)
			{
				this.inner = inner;
			}

			public void InvalidatePath()
			{
				agentData.InvalidatePath();
			}

			public void DebugDrawPath(UnityEngine.Color color, float duration)
			{
				agentData.pathFollower.DebugDrawPath(color, duration);
			}

			public static explicit operator Agent(BroadNavigationSystem.Agent other)
			{
				return new Agent(other);
			}
		}

		private AgentData[] allAgentData = Array.Empty<AgentData>();

		private int maxAgentUpdatesPerFrame = 1;

		private int remainingAgentUpdateBudget;

		public new Agent GetAgent(AgentHandle agentHandle)
		{
			return new Agent(base.GetAgent(agentHandle));
		}

		protected override void CreateAgent(in AgentHandle index)
		{
			ArrayUtils.EnsureCapacity(ref allAgentData, base.agentCount);
			allAgentData[(int)index].Initialize();
		}

		protected override void DestroyAgent(in AgentHandle index)
		{
			allAgentData[(int)index].Dispose();
		}

		protected override void UpdateAgents(float deltaTime)
		{
			remainingAgentUpdateBudget = maxAgentUpdatesPerFrame;
			for (AgentHandle agentHandle = (AgentHandle)0; (int)agentHandle < allAgentData.Length; agentHandle++)
			{
				UpdateAgent(in agentHandle);
			}
		}

		protected override void ConfigureAgentFromBody(in AgentHandle index, CharacterBody body)
		{
			ref AgentData reference = ref allAgentData[(int)index];
			if ((bool)body)
			{
				reference.hullClassification = body.hullClassification;
				reference.nodeGraph = (SceneInfo.instance ? SceneInfo.instance.GetNodeGraph(body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground) : null);
			}
			else
			{
				reference.hullClassification = HullClassification.Human;
				reference.nodeGraph = null;
				reference.InvalidatePath();
			}
		}

		protected override void InvalidateAgentPath(in AgentHandle index)
		{
			allAgentData[(int)index].InvalidatePath();
		}

		private void UpdateAgent(in AgentHandle agentHandle)
		{
			bool flag = false;
			ref readonly BaseAgentData agentData = ref GetAgentData(in agentHandle);
			if (!agentData.enabled)
			{
				return;
			}
			ref AgentData reference = ref allAgentData[(int)agentHandle];
			if (reference.pathTask == null && reference.nextUpdate <= localTime && remainingAgentUpdateBudget != 0)
			{
				flag = true;
				remainingAgentUpdateBudget--;
				reference.nextUpdate = localTime + reference.updateInterval;
				if (reference.lastKnownNode != reference.pathFollower.nextNode)
				{
					reference.lastKnownNode = reference.pathFollower.nextNode;
					reference.timeLastKnownNodeEncountered = localTime;
					UnityEngine.Vector3? nextPosition = reference.pathFollower.GetNextPosition();
					if (nextPosition.HasValue && agentData.currentPosition.HasValue && agentData.maxWalkSpeed > 0f)
					{
						reference.estimatedArrivalTimeAtLastKnownNode = localTime + (nextPosition.Value - agentData.currentPosition.Value).magnitude / agentData.maxWalkSpeed;
					}
					else
					{
						reference.estimatedArrivalTimeAtLastKnownNode = float.PositiveInfinity;
					}
				}
				if (agentData.currentPosition.HasValue && agentData.goalPosition.HasValue && (bool)reference.nodeGraph && reference.lastKnownNode.HasValue)
				{
					reference.pathRequest.startPos = agentData.currentPosition.Value;
					if (localTime <= reference.estimatedArrivalTimeAtLastKnownNode + 1f && reference.lastKnownNode.Value.nodeIndex != -1)
					{
						reference.nodeGraph.GetNodePosition(reference.lastKnownNode.Value, out var position);
						float num = (agentData.maxWalkSpeed + reference.updateInterval) * 1.5f;
						float num2 = num * num;
						if ((position - agentData.currentPosition.Value).sqrMagnitude < num2 && !Physics.Linecast(agentData.currentPosition.Value, position + new UnityEngine.Vector3(0f, 0.2f, 0f), out var _, LayerIndex.world.intVal, QueryTriggerInteraction.Ignore))
						{
							reference.pathRequest.startPos = reference.lastKnownNode.Value;
						}
					}
					reference.pathRequest.endPos = agentData.goalPosition.Value;
					reference.pathRequest.hullClassification = reference.hullClassification;
					reference.pathRequest.maxJumpHeight = agentData.maxJumpHeight;
					reference.pathRequest.maxSlope = agentData.maxSlopeAngle;
					reference.pathRequest.maxSpeed = agentData.maxWalkSpeed;
					reference.pathRequest.path = new Path(reference.nodeGraph);
					reference.pathTask = reference.nodeGraph.ComputePath(reference.pathRequest);
				}
			}
			if (reference.pathTask != null && (flag || remainingAgentUpdateBudget != 0))
			{
				if (!flag)
				{
					remainingAgentUpdateBudget--;
					flag = true;
				}
				if (reference.pathTask.status == PathTask.TaskStatus.Complete)
				{
					reference.pathFollower.SetPath(reference.pathTask.path);
					reference.lastTargetReachableUpdate = localTime;
					reference.targetReachable = reference.pathTask.wasReachable;
					reference.pathTask = null;
				}
			}
			if (agentData.currentPosition.HasValue)
			{
				reference.pathFollower.UpdatePosition(agentData.currentPosition.Value);
			}
			UnityEngine.Vector3? nextPosition2 = reference.pathFollower.GetNextPosition();
			if (reference.targetReachable && !nextPosition2.HasValue)
			{
				nextPosition2 = agentData.goalPosition;
			}
			AgentOutput agentOutput = default(AgentOutput);
			agentOutput.nextPosition = nextPosition2;
			agentOutput.desiredJumpVelocity = (reference.pathFollower.nextWaypointNeedsJump ? reference.pathFollower.CalculateJumpVelocityNeededToReachNextWaypoint(agentData.maxWalkSpeed) : 0f);
			agentOutput.targetReachable = reference.targetReachable;
			agentOutput.lastPathUpdate = reference.lastTargetReachableUpdate;
			AgentOutput output = agentOutput;
			SetAgentOutput(in agentHandle, in output);
		}
	}
}
namespace RoR2.Modding
{
	public class LegacyModContentPackProvider : IContentPackProvider
	{
		private ContentPack finalizedContentPack;

		public static LegacyModContentPackProvider instance { get; private set; } = new LegacyModContentPackProvider();


		public ContentPack registrationContentPack { get; private set; }

		public bool cutoffReached { get; private set; }

		public string identifier => "RoR2.LegacyModContent";

		private LegacyModContentPackProvider()
		{
			registrationContentPack = new ContentPack();
			finalizedContentPack = new ContentPack();
			ContentManager.collectContentPackProviders += delegate(ContentManager.AddContentPackProviderDelegate addContentPackProvider)
			{
				addContentPackProvider(this);
			};
		}

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			ContentPack.Copy(registrationContentPack, finalizedContentPack);
			yield break;
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			ContentPack.Copy(finalizedContentPack, args.output);
			yield break;
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			ContentPack.Copy(new ContentPack(), registrationContentPack);
			finalizedContentPack = null;
			yield break;
		}

		public void HandleLegacyGetAdditionalEntries<TAsset>(string eventName, Action<List<TAsset>> callback, NamedAssetCollection<TAsset> dest)
		{
			if (cutoffReached)
			{
				throw new InvalidOperationException("Legacy mod ContentPack has been finalized. It is too late to add additional entries via " + eventName + ".");
			}
			List<TAsset> list = new List<TAsset>();
			try
			{
				callback?.Invoke(list);
				dest.Add(list.ToArray());
				UnityEngine.Debug.LogWarning("Added content to legacy mod ContentPack via " + eventName + " succeeded. Do not use this code path; it will be removed in a future update. Use IContentPackProvider instead.");
			}
			catch (Exception arg)
			{
				UnityEngine.Debug.LogError($"Adding content to legacy mod ContentPack via {eventName} failed: {arg}.");
			}
		}
	}
	public class RoR2Mod
	{
		[NotNull]
		public readonly Mod mod;

		public IContentPackProvider contentPackProvider;

		public RoR2Mod([NotNull] Mod mod)
		{
			this.mod = mod;
		}
	}
}
namespace RoR2.GamepadVibration
{
	public class DefaultGamepadVibrationController : GamepadVibrationController
	{
		protected override void CalculateMotorValues(in VibrationContext vibrationContext, float[] motorValues)
		{
			float value = vibrationContext.CalcCamDisplacementMagnitude();
			ArrayUtils.SetRange(motorValues, in value, 0, motorValues.Length);
		}
	}
	public abstract class GamepadVibrationController : IDisposable
	{
		private Joystick _joystick;

		private float[] motorValues = Array.Empty<float>();

		private static List<(Func<Joystick, bool> predicate, Type vibrationControllerType)> vibrationControllerTypeResolver = new List<(Func<Joystick, bool>, Type)>();

		private static Type defaultVibrationControllerType = typeof(DefaultGamepadVibrationController);

		public Joystick joystick
		{
			get
			{
				return _joystick;
			}
			private set
			{
				if (_joystick != value)
				{
					_joystick = value;
					if (_joystick != null)
					{
						Array.Resize(ref motorValues, _joystick.vibrationMotorCount);
						OnJoystickAssigned(_joystick);
					}
				}
			}
		}

		protected virtual void OnJoystickAssigned(Joystick joystick)
		{
		}

		public void Dispose()
		{
			StopVibration();
			DisposeInternal();
			joystick = null;
		}

		protected virtual void DisposeInternal()
		{
		}

		public void ApplyVibration(in VibrationContext vibrationContext)
		{
			Array.Clear(motorValues, 0, motorValues.Length);
			try
			{
				CalculateMotorValues(in vibrationContext, motorValues);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			float userVibrationScale = vibrationContext.userVibrationScale;
			for (int i = 0; i < motorValues.Length; i++)
			{
				joystick.SetVibration(i, motorValues[i] * userVibrationScale);
			}
			try
			{
				ApplyNonStandardVibration(in vibrationContext);
			}
			catch (Exception message2)
			{
				UnityEngine.Debug.LogError(message2);
			}
		}

		protected virtual void CalculateMotorValues(in VibrationContext vibrationContext, float[] motorValues)
		{
		}

		protected virtual void ApplyNonStandardVibration(in VibrationContext vibrationContext)
		{
		}

		public void StopVibration()
		{
			try
			{
				StopNonStandardVibration();
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			joystick.StopVibration();
		}

		protected virtual void StopNonStandardVibration()
		{
		}

		public static GamepadVibrationController Create(Joystick joystick)
		{
			Type item = defaultVibrationControllerType;
			for (int i = 0; i < vibrationControllerTypeResolver.Count; i++)
			{
				try
				{
					(Func<Joystick, bool>, Type) tuple = vibrationControllerTypeResolver[i];
					if (tuple.Item1(joystick))
					{
						item = tuple.Item2;
						break;
					}
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
			GamepadVibrationController obj = (GamepadVibrationController)Activator.CreateInstance(item);
			obj.joystick = joystick;
			return obj;
		}

		public static void RegisterResolver(Func<Joystick, bool> predicate, Type vibrationControllerType)
		{
			predicate = predicate ?? throw new ArgumentNullException("predicate");
			vibrationControllerType = vibrationControllerType ?? throw new ArgumentNullException("vibrationControllerType");
			if (!vibrationControllerType.IsSubclassOf(typeof(GamepadVibrationController)))
			{
				throw new ArgumentException("vibrationControllerType must inherit from GamepadVibrationController");
			}
			vibrationControllerTypeResolver.Add((predicate, vibrationControllerType));
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			List<GamepadVibrationControllerResolverAttribute> list = new List<GamepadVibrationControllerResolverAttribute>();
			HG.Reflection.SearchableAttribute.GetInstances(list);
			foreach (GamepadVibrationControllerResolverAttribute item in list)
			{
				try
				{
					MethodInfo methodInfo = (MethodInfo)item.target;
					if (!methodInfo.IsStatic)
					{
						throw new Exception("GamepadVibrationControllerResolverAttribute target must be a static method. target=" + methodInfo.DeclaringType.FullName + "." + methodInfo.Name);
					}
					RegisterResolver((Func<Joystick, bool>)methodInfo.CreateDelegate(typeof(Func<Joystick, bool>)), item.vibrationControllerType);
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
		}
	}
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
	public class GamepadVibrationControllerResolverAttribute : HG.Reflection.SearchableAttribute
	{
		public readonly Type vibrationControllerType;

		public GamepadVibrationControllerResolverAttribute(Type vibrationControllerType)
		{
			this.vibrationControllerType = vibrationControllerType;
		}
	}
	public struct VibrationContext
	{
		public CameraRigController cameraRigController;

		public LocalUser localUser;

		public float userVibrationScale;

		public float CalcCamDisplacementMagnitude()
		{
			if (!cameraRigController || !Run.instance || !Run.instance.isRunning || localUser.cachedMasterController.master.lostBodyToDeath)
			{
				return 0f;
			}
			return cameraRigController.rawScreenShakeDisplacement.magnitude;
		}
	}
	public class Xbox360GamepadVibrationController : GamepadVibrationController
	{
		protected static readonly float deepRumbleFactor = 5f;

		protected override void CalculateMotorValues(in VibrationContext vibrationContext, float[] motorValues)
		{
			float num = vibrationContext.CalcCamDisplacementMagnitude();
			float num2 = num / deepRumbleFactor;
			float num3 = num;
			motorValues[0] = num2;
			motorValues[1] = num3;
		}

		[GamepadVibrationControllerResolver(typeof(Xbox360GamepadVibrationController))]
		private static bool Resolve(Joystick joystick)
		{
			if (joystick.vibrationMotorCount >= 2)
			{
				if (!joystick.name.Contains("Xbox"))
				{
					return joystick.name.Contains("XInput Gamepad ");
				}
				return true;
			}
			return false;
		}
	}
	public static class GamepadVibrationManager
	{
		private static readonly AssociationList<Joystick, GamepadVibrationController> joystickToVibrationController = new AssociationList<Joystick, GamepadVibrationController>(4);

		private static int[] joystickIndexToLocalUserIndex = new int[4];

		[SystemInitializer(new Type[] { typeof(GamepadVibrationController) })]
		private static void Init()
		{
			RoR2Application.onUpdate += Update;
			ReInput.ControllerConnectedEvent += OnControllerConnected;
			ReInput.ControllerPreDisconnectEvent += OnControllerPreDisconnect;
			RoR2Application.onShutDown = (Action)Delegate.Combine(RoR2Application.onShutDown, new Action(OnApplicationShutDown));
			foreach (Controller controller in ReInput.controllers.Controllers)
			{
				OnControllerConnected(new ControllerStatusChangedEventArgs(controller.name, controller.id, controller.type));
			}
		}

		private static void OnControllerConnected(ControllerStatusChangedEventArgs args)
		{
			if (args.controller is Joystick joystick)
			{
				joystickToVibrationController.Add(joystick, GamepadVibrationController.Create(joystick));
			}
		}

		private static void OnControllerPreDisconnect(ControllerStatusChangedEventArgs args)
		{
			if (args.controller is Joystick key)
			{
				int num = joystickToVibrationController.FindKeyIndex(key);
				if (num >= 0)
				{
					joystickToVibrationController[num].Value.Dispose();
					joystickToVibrationController.RemoveAt(num);
				}
			}
		}

		private static void OnApplicationShutDown()
		{
			for (int num = joystickToVibrationController.Count - 1; num >= 0; num--)
			{
				joystickToVibrationController[num].Value.Dispose();
				joystickToVibrationController.RemoveAt(num);
			}
		}

		private static void Update()
		{
			if (Time.deltaTime <= 0f)
			{
				foreach (KeyValuePair<Joystick, GamepadVibrationController> item in joystickToVibrationController)
				{
					item.Value.StopVibration();
				}
				return;
			}
			ReadOnlyCollection<LocalUser> readOnlyLocalUsersList = LocalUserManager.readOnlyLocalUsersList;
			ArrayUtils.EnsureCapacity(ref joystickIndexToLocalUserIndex, joystickToVibrationController.Count);
			int[] array = joystickIndexToLocalUserIndex;
			int value = -1;
			ArrayUtils.SetRange(array, in value, 0, joystickToVibrationController.Count);
			for (int i = 0; i < readOnlyLocalUsersList.Count; i++)
			{
				LocalUser localUser = readOnlyLocalUsersList[i];
				if (localUser.inputPlayer != null && (bool)localUser.eventSystem && localUser.eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad && localUser.inputPlayer?.controllers.GetLastActiveController<Joystick>() is Joystick key)
				{
					int num = joystickToVibrationController.FindKeyIndex(key);
					if (num >= 0)
					{
						joystickIndexToLocalUserIndex[num] = i;
					}
				}
			}
			for (int j = 0; j < joystickToVibrationController.Count; j++)
			{
				GamepadVibrationController value2 = joystickToVibrationController[j].Value;
				int num2 = joystickIndexToLocalUserIndex[j];
				LocalUser localUser2 = ((num2 >= 0) ? readOnlyLocalUsersList[num2] : null);
				if (localUser2 != null && localUser2.userProfile != null)
				{
					VibrationContext vibrationContext = default(VibrationContext);
					vibrationContext.localUser = localUser2;
					vibrationContext.cameraRigController = localUser2.cameraRigController;
					vibrationContext.userVibrationScale = localUser2.userProfile.gamepadVibrationScale;
					VibrationContext vibrationContext2 = vibrationContext;
					value2.ApplyVibration(in vibrationContext2);
				}
				else
				{
					value2.StopVibration();
				}
			}
		}
	}
}
namespace RoR2.VoidRaidCrab
{
	[RequireComponent(typeof(CharacterBody))]
	public class CentralLegController : MonoBehaviour
	{
		public class SuppressBreaksRequest : IDisposable
		{
			private Action<SuppressBreaksRequest> onDispose;

			public SuppressBreaksRequest(Action<SuppressBreaksRequest> onDispose)
			{
				this.onDispose = onDispose;
			}

			public void Dispose()
			{
				onDispose?.Invoke(this);
			}
		}

		private class LegSupportTracker
		{
			public bool allLegsNeededForAnimation;

			private LegController[] legControllers;

			private bool[] currentLegSupportStates;

			private int halfLegsCount;

			public readonly FixedSizeArrayPool<bool> legBoolsPool;

			public LegSupportTracker(LegController[] legControllers)
			{
				this.legControllers = legControllers;
				legBoolsPool = new FixedSizeArrayPool<bool>(legControllers.Length);
				currentLegSupportStates = new bool[legControllers.Length];
				halfLegsCount = legControllers.Length / 2;
			}

			public void Refresh()
			{
				for (int i = 0; i < legControllers.Length; i++)
				{
					currentLegSupportStates[i] = legControllers[i].IsSupportingWeight();
				}
			}

			public bool IsLegStateStable()
			{
				return IsLegStateStable(currentLegSupportStates);
			}

			public bool IsLegStateStable(bool[] legSupportStates)
			{
				int num = 0;
				for (int i = 0; i < legControllers.Length; i++)
				{
					if (legSupportStates[i])
					{
						num++;
					}
				}
				return num > halfLegsCount;
			}

			public bool IsLegNeededForSupport(int legIndex)
			{
				if (allLegsNeededForAnimation)
				{
					return true;
				}
				bool[] array = legBoolsPool.Request();
				Array.Copy(currentLegSupportStates, array, currentLegSupportStates.Length);
				array[legIndex] = false;
				bool result = !IsLegStateStable(array);
				legBoolsPool.Return(array);
				return result;
			}
		}

		[SerializeField]
		private LegController[] legControllers;

		private CharacterBody body;

		private EntityStateMachine bodyStateMachine;

		private List<SuppressBreaksRequest> suppressBreaksRequests = new List<SuppressBreaksRequest>();

		private LegSupportTracker legSupportTracker;

		private int stompRequesterLegIndex = -1;

		private const bool useComplexCollapseCheck = false;

		private bool hasEffectiveAuthority
		{
			get
			{
				if ((bool)body)
				{
					return body.hasEffectiveAuthority;
				}
				return false;
			}
		}

		private void Awake()
		{
			body = GetComponent<CharacterBody>();
			bodyStateMachine = EntityStateMachine.FindByCustomName(base.gameObject, "Body");
			legSupportTracker = new LegSupportTracker(legControllers);
			bodyStateMachine.nextStateModifier = ModifyBodyNextState;
		}

		private void FixedUpdate()
		{
			if (hasEffectiveAuthority)
			{
				UpdateLegsAuthority();
			}
		}

		private void ModifyBodyNextState(EntityStateMachine entityStateMachine, ref EntityState newNextState)
		{
			if (hasEffectiveAuthority && AreLegsBlockingBodyAnimation())
			{
				newNextState = new WaitForLegsAvailable
				{
					nextState = newNextState
				};
			}
		}

		private void UpdateLegsAuthority()
		{
			bool allLegsNeededForAnimation = !bodyStateMachine.IsInMainState();
			legSupportTracker.allLegsNeededForAnimation = allLegsNeededForAnimation;
			legSupportTracker.Refresh();
			if (bodyStateMachine.CanInterruptState(InterruptPriority.Pain))
			{
				bool flag = false;
				for (int i = 0; i < legControllers.Length; i++)
				{
					if (legControllers[i].IsBreakPending())
					{
						flag = true;
						legControllers[i].CompleteBreakAuthority();
					}
				}
				if (flag)
				{
					EntityState nextState = (legSupportTracker.IsLegStateStable() ? ((BaseState)new LegBreakStunState()) : ((BaseState)new Collapse()));
					bodyStateMachine.SetNextState(nextState);
				}
			}
			TryNextStompAuthority();
		}

		public bool AreLegsBlockingBodyAnimation()
		{
			for (int i = 0; i < legControllers.Length; i++)
			{
				if (legControllers[i].IsStomping())
				{
					return true;
				}
			}
			return false;
		}

		private void TryNextStompAuthority()
		{
		}

		private int WrapToRange(int value, int minInclusive, int maxExclusive)
		{
			if (maxExclusive <= minInclusive)
			{
				throw new ArgumentException("'max' must be greater than 'min'");
			}
			value -= minInclusive;
			int num = maxExclusive - minInclusive;
			int num2 = value % num;
			return minInclusive + ((num2 < 0) ? (num2 + num) : num2);
		}

		private LegController GetLegRingBuffered(int i)
		{
			return legControllers[WrapToRange(i, 0, legControllers.Length)];
		}

		private bool CheckLegsShouldCollapse()
		{
			int num = 0;
			int num2 = legControllers.Length / 2;
			for (int i = 0; i < legControllers.Length; i++)
			{
				if (legControllers[i].IsBroken())
				{
					num++;
					if (num >= num2)
					{
						return true;
					}
				}
			}
			return false;
		}

		public bool AreAnyBreaksPending()
		{
			LegController[] array = legControllers;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].IsBreakPending())
				{
					return true;
				}
			}
			return false;
		}

		public SuppressBreaksRequest SuppressBreaks()
		{
			if (suppressBreaksRequests.Count == 0)
			{
				LegController[] array = legControllers;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].isBreakSuppressed = true;
				}
			}
			SuppressBreaksRequest suppressBreaksRequest = new SuppressBreaksRequest(RemoveSuppressBreaksRequest);
			suppressBreaksRequests.Add(suppressBreaksRequest);
			return suppressBreaksRequest;
		}

		public void RegenerateAllBrokenServer()
		{
			LegController[] array = legControllers;
			foreach (LegController legController in array)
			{
				if (legController.IsBroken())
				{
					legController.RegenerateServer();
				}
			}
		}

		private void RemoveSuppressBreaksRequest(SuppressBreaksRequest request)
		{
			suppressBreaksRequests.Remove(request);
			if (suppressBreaksRequests.Count == 0)
			{
				LegController[] array = legControllers;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].isBreakSuppressed = false;
				}
			}
		}

		public bool IsBodyRelated(CharacterBody bodyToCheck)
		{
			if ((object)body == bodyToCheck)
			{
				return true;
			}
			LegController[] array = legControllers;
			foreach (LegController legController in array)
			{
				if ((object)bodyToCheck == legController.jointBody)
				{
					return true;
				}
			}
			return false;
		}
	}
	[RequireComponent(typeof(Animator))]
	public class CentralLegControllerAnimationEventReceiver : MonoBehaviour
	{
		public CentralLegController target;

		public ChildLocator childLocator;

		public void VoidRaidCrabFootStep(string targetName)
		{
			Transform transform = childLocator.FindChild(targetName);
			if ((bool)transform)
			{
				LegController componentInParent = transform.GetComponentInParent<LegController>();
				if ((bool)componentInParent && componentInParent.mainBodyHasEffectiveAuthority)
				{
					componentInParent.DoToeConcussionBlastAuthority();
				}
			}
		}
	}
	public class LegController : MonoBehaviour
	{
		private const string jointDeathStateMachineName = "Body";

		public EntityStateMachine stateMachine;

		public Animator animator;

		public string primaryLayerName;

		[Tooltip("The transform that should be considered the origin of this leg, points outward from the base, and provides a transform for consistent local space conversions. This field must always be set, and is available for the case that the object this component is attached to is not a bone meeting the metioned criteria.")]
		public Transform originTransform;

		[Header("Regeneration")]
		public float jointRegenDuration = 15f;

		[Header("Footstep Concussive Blast")]
		public float footstepBlastRadius = 20f;

		public BlastAttack.FalloffModel footstepFalloffModel = BlastAttack.FalloffModel.SweetSpot;

		public float footstepBlastForce = 500f;

		public UnityEngine.Vector3 footstepBonusForce;

		public GameObject footstepBlastEffectPrefab;

		[Header("Stomp")]
		public Transform stompRangeNearMarker;

		public Transform stompRangeFarMarker;

		public Transform stompRangeLeftMarker;

		public Transform stompRangeRightMarker;

		public float stompAimSpeed = 15f;

		public string stompXParameter;

		public string stompYParameter;

		public string stompPlaybackRateParam;

		private int stompXParameterHash;

		private int stompYParameterHash;

		private int stompPlaybackRateHash;

		[Header("Retraction")]
		public AnimationCurve retractionCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);

		public string retractionLayerName;

		private float currentRetractionWeight;

		private float desiredRetractionWeight;

		public float retractionBlendTransitionRate = 1f;

		public bool shouldRetract;

		[NonSerialized]
		public bool isBreakSuppressed;

		private bool wasJointBodyDead;

		private bool isJointBodyCurrentlyDying;

		private float jointRegenStopwatchServer;

		private UnityEngine.Vector3? stompTargetWorldPosition;

		private UnityEngine.Vector2 currentLocalStompPosition = UnityEngine.Vector2.zero;

		public CharacterBody mainBody { get; private set; }

		public GameObject mainBodyGameObject { get; private set; }

		public bool mainBodyHasEffectiveAuthority => mainBody?.hasEffectiveAuthority ?? false;

		public ChildLocator legChildLocator { get; private set; }

		public ChildLocator childLocator { get; private set; }

		public Transform toeTransform { get; private set; }

		public Transform toeTipTransform { get; private set; }

		public Transform footTranform { get; private set; }

		public CharacterMaster jointMaster { get; private set; }

		public CharacterBody jointBody
		{
			get
			{
				if (!jointMaster)
				{
					return null;
				}
				return jointMaster.GetBody();
			}
		}

		public bool IsBusy()
		{
			return !(stateMachine.state is EntityStates.VoidRaidCrab.Leg.Idle);
		}

		public bool IsStomping()
		{
			return stateMachine.state is BaseStompState;
		}

		private void OnEnable()
		{
			CharacterModel componentInParent = GetComponentInParent<CharacterModel>();
			mainBody = (componentInParent ? componentInParent.body : null);
			mainBodyGameObject = (mainBody ? mainBody.gameObject : null);
			childLocator = GetComponent<ChildLocator>();
			footTranform = childLocator.FindChild("Foot");
			toeTransform = childLocator.FindChild("Toe");
			toeTipTransform = childLocator.FindChild("ToeTip");
			stompXParameterHash = Animator.StringToHash(stompXParameter);
			stompYParameterHash = Animator.StringToHash(stompYParameter);
			stompPlaybackRateHash = Animator.StringToHash(stompPlaybackRateParam);
		}

		private void FixedUpdate()
		{
			desiredRetractionWeight = (shouldRetract ? 1f : 0f);
			currentRetractionWeight = Mathf.Clamp01(Mathf.MoveTowards(currentRetractionWeight, desiredRetractionWeight, Time.fixedDeltaTime * retractionBlendTransitionRate));
			int layerIndex = animator.GetLayerIndex(retractionLayerName);
			float weight = retractionCurve.Evaluate(currentRetractionWeight);
			animator.SetLayerWeight(layerIndex, weight);
			if (!wasJointBodyDead && IsBreakPending())
			{
				wasJointBodyDead = true;
				isJointBodyCurrentlyDying = true;
			}
			if (mainBodyHasEffectiveAuthority)
			{
				UpdateStompTargetPositionAuthority(Time.fixedDeltaTime);
			}
			if (NetworkServer.active && !jointBody)
			{
				jointRegenStopwatchServer += Time.fixedDeltaTime;
				if (jointRegenStopwatchServer >= jointRegenDuration)
				{
					RegenerateServer();
				}
			}
		}

		public bool RequestStomp(GameObject target)
		{
			if (!IsBusy())
			{
				stateMachine.SetNextState(new PreStompLegRaise
				{
					target = target
				});
				return true;
			}
			return false;
		}

		public void SetStompTargetWorldPosition(UnityEngine.Vector3? newStompTargetWorldPosition)
		{
			stompTargetWorldPosition = newStompTargetWorldPosition;
		}

		public bool SetJointMaster(CharacterMaster master, ChildLocator legChildLocator)
		{
			this.legChildLocator = legChildLocator;
			if (!jointMaster)
			{
				jointMaster = master;
				if ((bool)jointMaster)
				{
					jointMaster.onBodyDestroyed += OnJointBodyDestroyed;
					jointMaster.onBodyStart += OnJointBodyStart;
					MirrorLegJoints();
				}
				return true;
			}
			UnityEngine.Debug.LogError("LegController on " + base.gameObject.name + " already has a jointMaster set!");
			return false;
		}

		private void OnJointBodyStart(CharacterBody body)
		{
			wasJointBodyDead = false;
			isJointBodyCurrentlyDying = false;
			MirrorLegJoints();
		}

		private void OnJointBodyDestroyed(CharacterBody body)
		{
			isJointBodyCurrentlyDying = false;
		}

		public bool IsSupportingWeight()
		{
			if (!IsBroken() && !IsBreakPending())
			{
				return !IsBusy();
			}
			return false;
		}

		public bool CanBreak()
		{
			return jointBody;
		}

		public bool IsBreakPending()
		{
			if ((bool)jointBody)
			{
				HealthComponent healthComponent = jointBody.healthComponent;
				if ((bool)healthComponent)
				{
					return !healthComponent.alive;
				}
				return false;
			}
			return false;
		}

		public bool IsBroken()
		{
			if (!isJointBodyCurrentlyDying)
			{
				return !jointBody;
			}
			return true;
		}

		public bool DoesJointExist()
		{
			return jointBody;
		}

		public void CompleteBreakAuthority()
		{
			if (!jointMaster)
			{
				return;
			}
			CharacterBody characterBody = jointBody;
			if (!characterBody)
			{
				return;
			}
			HealthComponent healthComponent = characterBody.healthComponent;
			if ((bool)healthComponent)
			{
				if (NetworkServer.active)
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.crit = false;
					damageInfo.damage = healthComponent.fullCombinedHealth;
					damageInfo.procCoefficient = 0f;
					mainBody.healthComponent.TakeDamage(damageInfo);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
					GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
				}
				mainBody.healthComponent.UpdateLastHitTime(0f, UnityEngine.Vector3.zero, damageIsSilent: true, healthComponent.lastHitAttacker);
			}
			if (EntityStateMachine.FindByCustomName(characterBody.gameObject, "Body").state is PreDeathState preDeathState)
			{
				preDeathState.canProceed = true;
			}
		}

		public void RegenerateServer()
		{
			if ((bool)jointMaster)
			{
				jointRegenStopwatchServer = 0f;
				if (!jointMaster.GetBody())
				{
					jointMaster.Respawn(mainBody.transform.position, mainBody.transform.rotation);
				}
			}
		}

		private void MirrorLegJoints()
		{
			GameObject bodyObject = jointMaster.GetBodyObject();
			if ((bool)bodyObject && (bool)legChildLocator)
			{
				ChildLocatorMirrorController component = bodyObject.GetComponent<ChildLocatorMirrorController>();
				if ((bool)component)
				{
					component.referenceLocator = legChildLocator;
				}
			}
		}

		private UnityEngine.Vector2 WorldPointToLocalStompPoint(UnityEngine.Vector3 worldPoint)
		{
			UnityEngine.Vector3 vector = originTransform.InverseTransformVector(worldPoint);
			return new UnityEngine.Vector2(vector.x, vector.z);
		}

		private UnityEngine.Vector2 LocalStompPointToStompParams(UnityEngine.Vector2 stompPoint)
		{
			float x = originTransform.InverseTransformVector(stompRangeLeftMarker.position).x;
			float x2 = originTransform.InverseTransformVector(stompRangeRightMarker.position).x;
			float z = originTransform.InverseTransformVector(stompRangeNearMarker.position).z;
			float z2 = originTransform.InverseTransformVector(stompRangeFarMarker.position).z;
			float x3 = Util.Remap(currentLocalStompPosition.x, x, x2, -1f, 1f);
			float y = Util.Remap(currentLocalStompPosition.y, z, z2, -1f, 1f);
			return new UnityEngine.Vector2(x3, y);
		}

		private void UpdateStompTargetPositionAuthority(float deltaTime)
		{
			UnityEngine.Vector3 worldPoint = toeTipTransform.position;
			if (stompTargetWorldPosition.HasValue)
			{
				worldPoint = stompTargetWorldPosition.Value;
			}
			UnityEngine.Vector2 target = WorldPointToLocalStompPoint(worldPoint);
			currentLocalStompPosition = UnityEngine.Vector2.MoveTowards(currentLocalStompPosition, target, stompAimSpeed * deltaTime);
			UnityEngine.Vector2 vector = LocalStompPointToStompParams(currentLocalStompPosition);
			animator.SetFloat(stompXParameterHash, vector.x);
			animator.SetFloat(stompYParameterHash, vector.y);
		}

		private bool GetKneeToToeTipRaycast(out UnityEngine.Vector3 hitPosition, out UnityEngine.Vector3 hitNormal, out UnityEngine.Vector3 rayNormal)
		{
			UnityEngine.Vector3 position = footTranform.position;
			UnityEngine.Vector3 position2 = toeTipTransform.position;
			UnityEngine.Vector3 vector = position2 - position;
			float magnitude = vector.magnitude;
			if (magnitude <= Mathf.Epsilon)
			{
				hitPosition = position2;
				hitNormal = UnityEngine.Vector3.up;
				rayNormal = UnityEngine.Vector3.down;
				return false;
			}
			UnityEngine.Vector3 vector2 = vector / magnitude;
			RaycastHit[] array = Physics.RaycastAll(new Ray(position, vector2), magnitude, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
			float num = float.PositiveInfinity;
			int num2 = -1;
			for (int i = 0; i < array.Length; i++)
			{
				ref RaycastHit reference = ref array[i];
				if (reference.distance < num && !(reference.collider.transform.root == base.transform.root))
				{
					num2 = i;
					num = reference.distance;
				}
			}
			rayNormal = vector2;
			if (num2 != -1)
			{
				ref RaycastHit reference2 = ref array[num2];
				hitPosition = reference2.point;
				hitNormal = reference2.normal;
				return true;
			}
			hitPosition = toeTipTransform.position;
			hitNormal = -rayNormal;
			return false;
		}

		public void DoToeConcussionBlastAuthority(UnityEngine.Vector3? positionOverride = null, bool useEffect = true)
		{
			if (!mainBodyHasEffectiveAuthority)
			{
				throw new Exception("Caller does not have authority.");
			}
			UnityEngine.Vector3 hitPosition;
			if (positionOverride.HasValue)
			{
				hitPosition = positionOverride.Value;
			}
			else
			{
				GetKneeToToeTipRaycast(out hitPosition, out var _, out var _);
			}
			if (useEffect)
			{
				EffectData effectData = new EffectData();
				effectData.origin = hitPosition;
				effectData.scale = footstepBlastRadius;
				effectData.rotation = UnityEngine.Quaternion.identity;
				EffectManager.SpawnEffect(footstepBlastEffectPrefab, effectData, transmit: true);
			}
			BlastAttack blastAttack = new BlastAttack();
			blastAttack.attacker = mainBodyGameObject;
			blastAttack.teamIndex = (mainBody ? mainBody.teamComponent.teamIndex : TeamIndex.None);
			blastAttack.attackerFiltering = AttackerFiltering.NeverHitSelf;
			blastAttack.inflictor = mainBodyGameObject;
			blastAttack.radius = footstepBlastRadius;
			blastAttack.position = hitPosition;
			blastAttack.losType = BlastAttack.LoSType.None;
			blastAttack.procCoefficient = 0f;
			blastAttack.procChainMask = default(ProcChainMask);
			blastAttack.baseDamage = 0f;
			blastAttack.baseForce = footstepBlastForce;
			blastAttack.bonusForce = footstepBonusForce;
			blastAttack.canRejectForce = false;
			blastAttack.crit = false;
			blastAttack.damageColorIndex = DamageColorIndex.Default;
			blastAttack.damageType = DamageType.Silent;
			blastAttack.impactEffect = EffectIndex.Invalid;
			blastAttack.falloffModel = footstepFalloffModel;
			blastAttack.Fire();
		}

		public GameObject CheckForStompTarget()
		{
			UnityEngine.Vector3 a2 = stompRangeLeftMarker.position;
			UnityEngine.Vector3 b2 = stompRangeRightMarker.position;
			UnityEngine.Vector3 c2 = stompRangeNearMarker.position;
			UnityEngine.Vector3 d2 = stompRangeFarMarker.position;
			UnityEngine.Vector3 vector = Average(in a2, in b2, in c2, in d2);
			float a3 = UnityEngine.Vector3.Distance(vector, a2);
			float b3 = UnityEngine.Vector3.Distance(vector, b2);
			float c3 = UnityEngine.Vector3.Distance(vector, c2);
			float d3 = UnityEngine.Vector3.Distance(vector, d2);
			float num = Min(a3, b3, c3, d3);
			float num2 = Mathf.Sqrt(2f);
			float num3 = 1f / num2;
			float maxDistanceFilter = num * num3;
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = vector;
			bullseyeSearch.minDistanceFilter = 0f;
			bullseyeSearch.maxDistanceFilter = maxDistanceFilter;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.viewer = mainBody;
			bullseyeSearch.teamMaskFilter = TeamMask.AllExcept(mainBody.teamComponent.teamIndex);
			bullseyeSearch.filterByDistinctEntity = true;
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.RefreshCandidates();
			return bullseyeSearch.GetResults().FirstOrDefault()?.healthComponent?.gameObject;
			static UnityEngine.Vector3 Average(in UnityEngine.Vector3 a, in UnityEngine.Vector3 b, in UnityEngine.Vector3 c, in UnityEngine.Vector3 d)
			{
				UnityEngine.Vector3 a4 = Vector3Utils.Average(in a, in b);
				UnityEngine.Vector3 b4 = Vector3Utils.Average(in c, in d);
				return Vector3Utils.Average(in a4, in b4);
			}
			static float Min(float a, float b, float c, float d)
			{
				return Mathf.Min(Mathf.Min(a, b), Mathf.Min(c, d));
			}
		}
	}
	public class VoidRaidCrabAISkillDriverController : MonoBehaviour
	{
		[SerializeField]
		private AISkillDriver[] weaponSkillDrivers;

		[SerializeField]
		private AISkillDriver[] bodySkillDrivers;

		[SerializeField]
		private AISkillDriver[] gauntletSkillDrivers;

		[SerializeField]
		private AISkillDriver finalStandSkillDriver;

		[SerializeField]
		private CharacterMaster master;

		[SerializeField]
		private string bodyStateMachineName = "Body";

		[SerializeField]
		private AISkillDriver debugForceSkillDriver;

		private EntityStateMachine bodyStateMachine;

		private HealthComponent healthComponent;

		private bool isGauntletSkillAvailable;

		public bool CanUseWeaponSkills()
		{
			if (bodyStateMachine.state is GenericCharacterMain && !isGauntletSkillAvailable)
			{
				return !ShouldUseFinalStandSkill();
			}
			return false;
		}

		public bool CanUseBodySkills()
		{
			if (bodyStateMachine.IsInMainState() && !isGauntletSkillAvailable)
			{
				return !ShouldUseFinalStandSkill();
			}
			return false;
		}

		public bool ShouldUseGauntletSkills()
		{
			if (isGauntletSkillAvailable && bodyStateMachine.IsInMainState())
			{
				return !ShouldUseFinalStandSkill();
			}
			return false;
		}

		public bool ShouldUseFinalStandSkill()
		{
			return CanUsePhaseSkillDriver(finalStandSkillDriver);
		}

		private void FixedUpdate()
		{
			if ((bool)master && (!bodyStateMachine || !healthComponent))
			{
				GameObject bodyObject = master.GetBodyObject();
				if ((bool)bodyObject)
				{
					if (!bodyStateMachine)
					{
						bodyStateMachine = EntityStateMachine.FindByCustomName(bodyObject, bodyStateMachineName);
					}
					if (!healthComponent)
					{
						healthComponent = bodyObject.GetComponent<HealthComponent>();
					}
				}
			}
			if (!bodyStateMachine)
			{
				return;
			}
			isGauntletSkillAvailable = false;
			AISkillDriver[] array = gauntletSkillDrivers;
			foreach (AISkillDriver driver in array)
			{
				isGauntletSkillAvailable = isGauntletSkillAvailable || CanUsePhaseSkillDriver(driver);
			}
			if ((bool)debugForceSkillDriver)
			{
				SetSkillDriversEnabled(weaponSkillDrivers, driverEnabled: false);
				SetSkillDriversEnabled(bodySkillDrivers, driverEnabled: false);
				SetSkillDriversEnabled(gauntletSkillDrivers, driverEnabled: false);
				if ((bool)finalStandSkillDriver)
				{
					finalStandSkillDriver.enabled = false;
				}
				bool flag = false;
				array = weaponSkillDrivers;
				foreach (AISkillDriver aISkillDriver in array)
				{
					if ((object)aISkillDriver == debugForceSkillDriver)
					{
						aISkillDriver.enabled = CanUseWeaponSkills();
						flag = true;
					}
				}
				if (!flag)
				{
					array = bodySkillDrivers;
					foreach (AISkillDriver aISkillDriver2 in array)
					{
						if ((object)aISkillDriver2 == debugForceSkillDriver)
						{
							aISkillDriver2.enabled = CanUseBodySkills();
							flag = true;
						}
					}
				}
				if (!flag)
				{
					array = gauntletSkillDrivers;
					foreach (AISkillDriver aISkillDriver3 in array)
					{
						if ((object)aISkillDriver3 == debugForceSkillDriver)
						{
							aISkillDriver3.enabled = ShouldUseGauntletSkills();
							flag = true;
						}
					}
				}
				if (!flag && (object)debugForceSkillDriver == finalStandSkillDriver)
				{
					debugForceSkillDriver.enabled = ShouldUseFinalStandSkill();
					flag = true;
				}
				if (!flag)
				{
					debugForceSkillDriver.enabled = true;
				}
			}
			else
			{
				SetSkillDriversEnabled(weaponSkillDrivers, CanUseWeaponSkills());
				SetSkillDriversEnabled(bodySkillDrivers, CanUseBodySkills());
				SetSkillDriversEnabled(gauntletSkillDrivers, ShouldUseGauntletSkills());
				if ((bool)finalStandSkillDriver)
				{
					finalStandSkillDriver.enabled = ShouldUseFinalStandSkill();
				}
			}
		}

		private void SetSkillDriversEnabled(AISkillDriver[] skillDrivers, bool driverEnabled)
		{
			for (int i = 0; i < skillDrivers.Length; i++)
			{
				skillDrivers[i].enabled = driverEnabled;
			}
		}

		private bool CanUsePhaseSkillDriver(AISkillDriver driver)
		{
			if ((bool)driver)
			{
				float num = 1f;
				if ((bool)healthComponent)
				{
					num = healthComponent.combinedHealthFraction;
				}
				if (num < driver.maxUserHealthFraction)
				{
					if (driver.timesSelected >= driver.maxTimesSelected)
					{
						return driver.maxTimesSelected < 0;
					}
					return true;
				}
				return false;
			}
			return false;
		}
	}
	public class VoidRaidCrabHealthBarOverlayProvider : MonoBehaviour
	{
		[SerializeField]
		private GameObject healthbarOverlayPrefab;

		[SerializeField]
		private string overlayChildLocatorEntryName;

		[SerializeField]
		private PhasedInventorySetter phasedInventorySetter;

		private List<OverlayController> overlayControllers = new List<OverlayController>();

		private void OnEnable()
		{
			overlayControllers.Clear();
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Player);
			overlayControllers = new List<OverlayController>();
			foreach (TeamComponent item in teamMembers)
			{
				OverlayController overlayController = HudOverlayManager.AddOverlay(item.gameObject, new OverlayCreationParams
				{
					prefab = healthbarOverlayPrefab,
					childLocatorEntry = overlayChildLocatorEntryName
				});
				overlayController.onInstanceAdded += OnOverlayInstanceAdded;
				overlayControllers.Add(overlayController);
			}
		}

		private void OnOverlayInstanceAdded(OverlayController overlayController, GameObject instance)
		{
			if ((bool)instance && (bool)phasedInventorySetter)
			{
				VoidRaidCrabHealthBarPipController component = instance.GetComponent<VoidRaidCrabHealthBarPipController>();
				if ((bool)component)
				{
					component.InitializePips(phasedInventorySetter);
				}
			}
		}

		private void OnDisable()
		{
			foreach (OverlayController overlayController in overlayControllers)
			{
				HudOverlayManager.RemoveOverlay(overlayController);
			}
			overlayControllers.Clear();
		}
	}
}
namespace RoR2.Scripts.Utility
{
	internal class ScopedReset<T> : IDisposable
	{
		private T originalValue;

		private Action<T> _setter;

		public ScopedReset(Func<T> getter, Action<T> setter, T tempVal)
		{
			originalValue = getter();
			setter(tempVal);
			_setter = setter;
		}

		public void Dispose()
		{
			_setter(originalValue);
		}
	}
}
namespace RoR2.Scripts.Tutorial
{
	public class TutorialFirstLevelEventGate : MonoBehaviour
	{
		public UnityEvent ExecTutorialIsEnabled;

		public UnityEvent ExecTutorialIsDisabled;

		public void Exec()
		{
			if (TutorialManager.isTutorialEnabled && (bool)Run.instance && Run.instance.stageClearCount == 0)
			{
				ExecTutorialIsEnabled?.Invoke();
			}
			else
			{
				ExecTutorialIsDisabled?.Invoke();
			}
		}
	}
	public class TutorialObjectiveCrossfadeHelper : MonoBehaviour
	{
		public UnityEvent OnBeginFinishCrossfade;

		public Action FinishCrossfadeAction { get; set; }

		public void FinishCrossfade()
		{
			FinishCrossfadeAction?.Invoke();
			OnBeginFinishCrossfade?.Invoke();
		}
	}
	public class TutorialObjectiveHelper : MonoBehaviour
	{
		public GameObject SearchRoot;

		public HGTextMeshProUGUI TextToUpdate;

		private ObjectivePanelController _objectivePanelController;

		private TutorialObjectiveCrossfadeHelper _crossfadeHelper;

		private void Start()
		{
			if ((bool)SearchRoot)
			{
				ObjectivePanelController componentInChildren = SearchRoot.GetComponentInChildren<ObjectivePanelController>();
				if ((object)componentInChildren != null)
				{
					_objectivePanelController = componentInChildren;
				}
			}
		}

		public void GrabText()
		{
			if ((bool)_objectivePanelController && _objectivePanelController.GetPrimaryObjectiveTracker(out var primaryObjectiveTracker))
			{
				TextToUpdate.text = primaryObjectiveTracker.GetString();
				_crossfadeHelper = primaryObjectiveTracker.stripObject.GetComponent<TutorialObjectiveCrossfadeHelper>();
			}
		}

		public void TriggerObjectiveSideCrossfade()
		{
			if ((bool)_crossfadeHelper)
			{
				_crossfadeHelper.FinishCrossfade();
			}
		}
	}
}
namespace RoR2.Scripts.GameBehaviors.UI
{
	[Serializable]
	public struct ObjectiveStripAnimationParam
	{
		public string Param;

		public float Value;
	}
	public class ObjectiveStripAnimationParams : MonoBehaviour
	{
		[SerializeField]
		protected List<ObjectiveStripAnimationParam> Params;

		public float GetParam(string ParamName, float defaultValue)
		{
			int num = Params.FindIndex((ObjectiveStripAnimationParam objectiveStripAnimationParam) => objectiveStripAnimationParam.Param == ParamName);
			if (num >= 0)
			{
				return Params[num].Value;
			}
			return defaultValue;
		}
	}
}
namespace RoR2.SurvivorMannequins
{
	public class SurvivorMannequinDioramaController : MonoBehaviour
	{
		public bool showLocalPlayersFirst = true;

		[SerializeField]
		private SurvivorMannequinSlotController[] mannequinSlots = Array.Empty<SurvivorMannequinSlotController>();

		private bool sortedNetworkUsersDirty = true;

		private List<NetworkUser> sortedNetworkUsers = new List<NetworkUser>();

		private void OnEnable()
		{
			NetworkUser.onNetworkUserDiscovered += OnNetworkUserDiscovered;
			NetworkUser.onNetworkUserLost += OnNetworkUserLost;
		}

		private void OnDisable()
		{
			NetworkUser.onNetworkUserLost -= OnNetworkUserLost;
			NetworkUser.onNetworkUserDiscovered -= OnNetworkUserDiscovered;
			sortedNetworkUsers.Clear();
			UpdateMannequins();
		}

		private void Update()
		{
			if (sortedNetworkUsersDirty)
			{
				sortedNetworkUsersDirty = false;
				UpdateSortedNetworkUsersList();
			}
			UpdateMannequins();
		}

		private void UpdateSortedNetworkUsersList()
		{
			sortedNetworkUsers.Clear();
			if (showLocalPlayersFirst)
			{
				ListUtils.AddRange(sortedNetworkUsers, NetworkUser.readOnlyLocalPlayersList);
				for (int i = 0; i < NetworkUser.readOnlyInstancesList.Count; i++)
				{
					ListUtils.AddIfUnique(sortedNetworkUsers, NetworkUser.readOnlyInstancesList[i]);
				}
			}
		}

		private void OnNetworkUserLost(NetworkUser networkUser)
		{
			sortedNetworkUsersDirty = true;
		}

		private void OnNetworkUserDiscovered(NetworkUser networkUser)
		{
			sortedNetworkUsersDirty = true;
		}

		public void GetSlots(List<SurvivorMannequinSlotController> dest)
		{
			if (dest == null)
			{
				throw new ArgumentNullException("dest");
			}
			ListUtils.AddRange(dest, mannequinSlots);
		}

		public void SetSlots(SurvivorMannequinSlotController[] newMannequinSlots)
		{
			if (newMannequinSlots == null)
			{
				throw new ArgumentNullException("newMannequinSlots");
			}
			for (int i = 0; i < mannequinSlots.Length; i++)
			{
				SurvivorMannequinSlotController survivorMannequinSlotController = mannequinSlots[i];
				if ((bool)survivorMannequinSlotController && Array.IndexOf(newMannequinSlots, survivorMannequinSlotController) == -1)
				{
					survivorMannequinSlotController.networkUser = null;
				}
			}
			ArrayUtils.CloneTo(newMannequinSlots, ref mannequinSlots);
			UpdateMannequins();
		}

		private void UpdateMannequins()
		{
			AssignNetworkUsersToSlots(sortedNetworkUsers);
		}

		private void AssignNetworkUsersToSlots(List<NetworkUser> networkUsers)
		{
			int i = 0;
			for (int num = Math.Min(networkUsers.Count, mannequinSlots.Length); i < num; i++)
			{
				NetworkUser networkUser = networkUsers[i];
				SurvivorMannequinSlotController survivorMannequinSlotController = mannequinSlots[i];
				if (!survivorMannequinSlotController || (object)survivorMannequinSlotController.networkUser == networkUser)
				{
					continue;
				}
				for (int j = i + 1; j < mannequinSlots.Length; j++)
				{
					SurvivorMannequinSlotController survivorMannequinSlotController2 = mannequinSlots[j];
					if ((bool)survivorMannequinSlotController2)
					{
						SurvivorMannequinSlotController.Swap(survivorMannequinSlotController, survivorMannequinSlotController2);
						break;
					}
				}
				survivorMannequinSlotController.networkUser = networkUser;
			}
			for (int k = networkUsers.Count; k < mannequinSlots.Length; k++)
			{
				mannequinSlots[k].networkUser = null;
			}
		}
	}
	public class SurvivorMannequinSlotController : MonoBehaviour
	{
		public GameObject toggleableEffect;

		private NetworkUser _networkUser;

		private SurvivorDef _currentSurvivorDef;

		private Loadout currentLoadout;

		private bool loadoutDirty;

		private Transform mannequinInstanceTransform;

		private bool mannequinInstanceDirty;

		public NetworkUser networkUser
		{
			get
			{
				return _networkUser;
			}
			set
			{
				if ((object)_networkUser != value)
				{
					_networkUser = value;
					mannequinInstanceDirty = true;
					loadoutDirty = true;
				}
			}
		}

		private SurvivorDef currentSurvivorDef
		{
			get
			{
				return _currentSurvivorDef;
			}
			set
			{
				if ((object)_currentSurvivorDef != value)
				{
					_currentSurvivorDef = value;
					mannequinInstanceDirty = true;
				}
			}
		}

		private void Awake()
		{
			currentLoadout = new Loadout();
		}

		private void OnEnable()
		{
			NetworkUser.onLoadoutChangedGlobal += OnLoadoutChangedGlobal;
		}

		private void OnDisable()
		{
			NetworkUser.onLoadoutChangedGlobal -= OnLoadoutChangedGlobal;
		}

		private void Update()
		{
			SurvivorDef survivorDef = null;
			if ((bool)networkUser)
			{
				survivorDef = networkUser.GetSurvivorPreference();
			}
			currentSurvivorDef = survivorDef;
			if (mannequinInstanceDirty)
			{
				mannequinInstanceDirty = false;
				RebuildMannequinInstance();
			}
			if (loadoutDirty)
			{
				loadoutDirty = false;
				if ((bool)networkUser)
				{
					networkUser.networkLoadout.CopyLoadout(currentLoadout);
				}
				ApplyLoadoutToMannequinInstance();
			}
			if ((bool)toggleableEffect)
			{
				toggleableEffect.SetActive(networkUser);
			}
		}

		private void OnLoadoutChangedGlobal(NetworkUser networkUser)
		{
			if ((object)this.networkUser == networkUser)
			{
				loadoutDirty = true;
			}
		}

		private void ClearMannequinInstance()
		{
			if ((bool)mannequinInstanceTransform)
			{
				UnityEngine.Object.Destroy(mannequinInstanceTransform.gameObject);
			}
			mannequinInstanceTransform = null;
		}

		private void RebuildMannequinInstance()
		{
			ClearMannequinInstance();
			if ((bool)currentSurvivorDef && (bool)currentSurvivorDef.displayPrefab)
			{
				mannequinInstanceTransform = UnityEngine.Object.Instantiate(currentSurvivorDef.displayPrefab, base.transform.position, base.transform.rotation, base.transform).transform;
				CharacterSelectSurvivorPreviewDisplayController component = mannequinInstanceTransform.GetComponent<CharacterSelectSurvivorPreviewDisplayController>();
				if ((bool)component)
				{
					component.networkUser = networkUser;
				}
				ApplyLoadoutToMannequinInstance();
			}
		}

		private void ApplyLoadoutToMannequinInstance()
		{
			if (!mannequinInstanceTransform)
			{
				return;
			}
			BodyIndex bodyIndexFromSurvivorIndex = SurvivorCatalog.GetBodyIndexFromSurvivorIndex(currentSurvivorDef.survivorIndex);
			int skinIndex = (int)currentLoadout.bodyLoadoutManager.GetSkinIndex(bodyIndexFromSurvivorIndex);
			SkinDef safe = ArrayUtils.GetSafe(BodyCatalog.GetBodySkins(bodyIndexFromSurvivorIndex), skinIndex);
			if ((bool)safe)
			{
				CharacterModel componentInChildren = mannequinInstanceTransform.GetComponentInChildren<CharacterModel>();
				if ((bool)componentInChildren)
				{
					safe.Apply(componentInChildren.gameObject);
				}
			}
		}

		public static void Swap(SurvivorMannequinSlotController a, SurvivorMannequinSlotController b)
		{
			if ((bool)a.mannequinInstanceTransform)
			{
				a.mannequinInstanceTransform.SetParent(b.transform, worldPositionStays: false);
			}
			if ((bool)b.mannequinInstanceTransform)
			{
				b.mannequinInstanceTransform.SetParent(a.transform, worldPositionStays: false);
			}
			Util.Swap(ref a._networkUser, ref b._networkUser);
			Util.Swap(ref a._currentSurvivorDef, ref b._currentSurvivorDef);
			Util.Swap(ref a.currentLoadout, ref b.currentLoadout);
			Util.Swap(ref a.loadoutDirty, ref b.loadoutDirty);
			Util.Swap(ref a.mannequinInstanceDirty, ref b.mannequinInstanceDirty);
			Util.Swap(ref a.mannequinInstanceTransform, ref b.mannequinInstanceTransform);
		}
	}
}
namespace RoR2.PostProcess
{
	[RequireComponent(typeof(Camera))]
	[ExecuteAlways]
	public class SobelCommandBuffer : MonoBehaviour
	{
		public CameraEvent cameraEvent = CameraEvent.BeforeLighting;

		private Camera camera;

		private RenderTexture sobelInfoTex;

		private CommandBuffer sobelCommandBuffer;

		private CameraEvent sobelCommandBufferSubscribedEvent;

		private Material sobelBufferMaterial;

		private bool sobelBufferReferencesReady;

		private static Shader sobelShader;

		private static Action callbacksFromStaticMethod;

		private static bool currentlyPreloadingShader;

		[SystemInitializer(new Type[] { })]
		public static void PreloadShaderReference()
		{
			if (currentlyPreloadingShader || sobelShader != null)
			{
				if (sobelShader != null)
				{
					SetShaderReference(sobelShader);
				}
				return;
			}
			if (LegacyShaderAPI.TryToGetPreloadedShader("Hopoo Games/Internal/SobelBuffer", out var cachedShader))
			{
				SetShaderReference(cachedShader);
				return;
			}
			AsyncOperationHandle<Shader> asyncOperationHandle = Addressables.LoadAssetAsync<Shader>("780f79b2a62a0df439dedf59c533eee6");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<Shader> obj)
			{
				SetShaderReference(obj.Result);
			};
			currentlyPreloadingShader = true;
		}

		private static void SetShaderReference(Shader _shader)
		{
			if (_shader != null)
			{
				sobelShader = _shader;
				callbacksFromStaticMethod?.Invoke();
				callbacksFromStaticMethod = null;
				currentlyPreloadingShader = false;
			}
		}

		private void Awake()
		{
			Initialize();
		}

		private void OnDestroy()
		{
			DestroyTemporaryAsset(sobelBufferMaterial);
			sobelBufferReferencesReady = false;
		}

		private void OnEnable()
		{
			if (!Application.isPlaying)
			{
				Initialize();
			}
			camera.AddCommandBuffer(cameraEvent, sobelCommandBuffer);
			sobelCommandBufferSubscribedEvent = cameraEvent;
		}

		private void OnDisable()
		{
			DestroyTemporaryAsset(sobelInfoTex);
			camera.RemoveCommandBuffer(sobelCommandBufferSubscribedEvent, sobelCommandBuffer);
			sobelCommandBuffer.Clear();
		}

		private void OnPreRender()
		{
			Rebuild();
		}

		private void Initialize()
		{
			if (sobelShader == null)
			{
				callbacksFromStaticMethod = (Action)Delegate.Combine(callbacksFromStaticMethod, new Action(Initialize));
				PreloadShaderReference();
				return;
			}
			camera = GetComponent<Camera>();
			sobelBufferMaterial = new Material(sobelShader);
			sobelCommandBuffer = new CommandBuffer();
			sobelCommandBuffer.name = "Sobel Command Buffer";
			sobelBufferReferencesReady = true;
		}

		private void Rebuild()
		{
			if (!sobelBufferReferencesReady)
			{
				Initialize();
				return;
			}
			Vector2Int vector2Int = new Vector2Int(camera.pixelWidth, camera.pixelHeight);
			RenderTexture renderTexture = sobelInfoTex;
			if ((bool)sobelInfoTex && new Vector2Int(sobelInfoTex.width, sobelInfoTex.height) != vector2Int)
			{
				DestroyTemporaryAsset(sobelInfoTex);
				sobelInfoTex = null;
			}
			if (!sobelInfoTex && vector2Int.x > 0 && vector2Int.y > 0)
			{
				sobelInfoTex = new RenderTexture(vector2Int.x, vector2Int.y, 0, GraphicsFormat.R8_UNorm, 0);
				sobelInfoTex.name = "Sobel Outline Information";
			}
			if (renderTexture != sobelInfoTex)
			{
				int nameID = Shader.PropertyToID("_SobelTex");
				RenderTargetIdentifier renderTargetIdentifier = new RenderTargetIdentifier(sobelInfoTex);
				RenderTargetIdentifier source = new RenderTargetIdentifier(BuiltinRenderTextureType.ResolvedDepth);
				RenderTargetIdentifier renderTarget = new RenderTargetIdentifier(BuiltinRenderTextureType.CameraTarget);
				sobelCommandBuffer.Clear();
				sobelCommandBuffer.Blit(source, renderTargetIdentifier, sobelBufferMaterial);
				sobelCommandBuffer.SetGlobalTexture(nameID, renderTargetIdentifier);
				sobelCommandBuffer.SetRenderTarget(renderTarget);
			}
		}

		private void DestroyTemporaryAsset(UnityEngine.Object temporaryAsset)
		{
			if (Application.isPlaying)
			{
				UnityEngine.Object.Destroy(temporaryAsset);
			}
			else
			{
				UnityEngine.Object.DestroyImmediate(temporaryAsset);
			}
		}
	}
}
namespace RoR2.PostProcessing
{
	public class DamageIndicator : MonoBehaviour
	{
		private struct IndicatorTimestamp
		{
			public Run.FixedTimeStamp hitTimeStamp;

			public bool isActive;
		}

		private CameraRigController cameraRigController;

		public Material mat;

		public float boxCornerRadius = 0.5f;

		public float boxFeather = 0.5f;

		public float maxboxSize = 1f;

		public float minboxSize = 0.75f;

		[Tooltip("The color of the damage indicator.")]
		public UnityEngine.Color tintColor;

		[Tooltip("X and Y are the normalized screen position, and Z is the opacity of the indicator.")]
		public UnityEngine.Vector4[] indicators = new UnityEngine.Vector4[8];

		private IndicatorTimestamp[] _indicatorTimestamps = new IndicatorTimestamp[8];

		[Tooltip("The radius of the mask for the indicator. It will be scaled to fit the aspect ratio of the screen.")]
		public float indicatorRadius;

		[Tooltip("The opacity of the indicator over time.")]
		public AnimationCurve indicatorOpacity;

		[UnityEngine.Min(0.01f)]
		[Tooltip("The duration of the indicator. This will scale the opacity fade time.")]
		public float indicatorDuration = 1f;

		[Tooltip("The feather on the indicator mask.")]
		public float indicatorFeather = 0.5f;

		private float _indicatorValue;

		private bool isEnabled = true;

		private void Awake()
		{
			cameraRigController = GetComponentInParent<CameraRigController>();
			mat = UnityEngine.Object.Instantiate(mat);
		}

		private void OnEnable()
		{
			GlobalEventManager.onClientDamageNotified += OnClientDamage;
		}

		public void OnDisable()
		{
			GlobalEventManager.onClientDamageNotified -= OnClientDamage;
		}

		private float GetBoxSize(float value)
		{
			return Util.Remap(value, 0f, 1f, maxboxSize, minboxSize);
		}

		public void OnClientDamage(DamageDealtMessage damageDealtMessage)
		{
			if (!(damageDealtMessage.attacker == null) && !(damageDealtMessage.victim == null) && (bool)cameraRigController && damageDealtMessage.victim == cameraRigController.localUserViewer.cachedBodyObject)
			{
				_indicatorValue = cameraRigController.localUserViewer.userProfile.directionalDamageIndicatorScale;
				UnityEngine.Vector3 forward = cameraRigController.transform.forward;
				UnityEngine.Vector3 position = damageDealtMessage.victim.gameObject.transform.position;
				UnityEngine.Vector3 position2 = damageDealtMessage.attacker.gameObject.transform.position;
				UnityEngine.Vector2 to = new UnityEngine.Vector2(position.x, position.z) - new UnityEngine.Vector2(position2.x, position2.z);
				int num = Mathf.RoundToInt((0f - UnityEngine.Vector2.SignedAngle(new UnityEngine.Vector2(forward.x, forward.z), to) + 180f) / 45f) % 8;
				_indicatorTimestamps[num].hitTimeStamp = Run.FixedTimeStamp.now;
				_indicatorTimestamps[num].isActive = true;
			}
		}

		private void ResetIndicators()
		{
			for (int i = 0; i < _indicatorTimestamps.Length; i++)
			{
				_indicatorTimestamps[i].isActive = false;
				indicators[i].z = 0f;
			}
		}

		private void OnRenderImage(RenderTexture source, RenderTexture destination)
		{
			if (Mathf.Approximately(_indicatorValue, 0f))
			{
				if (isEnabled)
				{
					ResetIndicators();
					mat.SetVectorArray("_Indicators", indicators);
					isEnabled = false;
				}
				Graphics.Blit(source, destination, mat);
				return;
			}
			if (!isEnabled)
			{
				isEnabled = true;
			}
			mat.SetFloat("_BoxCornerRadius", boxCornerRadius);
			mat.SetFloat("_BoxFeather", boxFeather);
			mat.SetFloat("_BoxSize", GetBoxSize(_indicatorValue));
			mat.SetColor("_TintColor", tintColor);
			mat.SetFloat("_IndicatorRadius", indicatorRadius);
			mat.SetFloat("_IndicatorFeather", indicatorFeather);
			for (int i = 0; i < _indicatorTimestamps.Length; i++)
			{
				if (_indicatorTimestamps[i].isActive)
				{
					float timeSince = _indicatorTimestamps[i].hitTimeStamp.timeSince;
					if (timeSince >= indicatorDuration)
					{
						_indicatorTimestamps[i].isActive = false;
					}
					else
					{
						indicators[i].z = Mathf.Clamp(indicatorOpacity.Evaluate(timeSince / indicatorDuration), 0f, 1f);
					}
				}
			}
			mat.SetVectorArray("_Indicators", indicators);
			Graphics.Blit(source, destination, mat);
		}
	}
	[ExecuteInEditMode]
	public class HopooPostProcess : MonoBehaviour
	{
		public Material mat;

		private void Start()
		{
		}

		[ImageEffectOpaque]
		private void OnRenderImage(RenderTexture source, RenderTexture destination)
		{
			Graphics.Blit(source, destination, mat);
		}
	}
	public class ScreenDamage : MonoBehaviour
	{
		private CameraRigController cameraRigController;

		private PostProcessLayer postProcessLayer;

		private ScreenDamagePP postProcessSettings;

		[Header("Debug values")]
		public bool useDebugValues;

		public float debugTintValue;

		public float debugDesatValue;

		public float debugDistortionValue;

		[Header("Game-wide limits")]
		public float DistortionScale = 1f;

		public float DistortionPower = 1f;

		public float DesaturationScale = 1f;

		public float DesaturationPower = 1f;

		public float TintScale = 1f;

		public float TintPower = 1f;

		public float debugHealthPercentage;

		private float healthPercentage = 1f;

		private const float hitTintDecayTime = 0.6f;

		private const float hitTintScale = 1.6f;

		private const float deathWeight = 2f;

		private float oldDistortionStrength;

		private float oldDesaturationStrength;

		private float oldTintStrength;

		private ScreenDamageCalculatorDefault screenDamageCalculatorDefault = new ScreenDamageCalculatorDefault();

		private ScreenDamageCalculator workingScreenDamageCalculator;

		private void Awake()
		{
			InitPostProcessSettingsVars();
		}

		private void OnEnable()
		{
			InitPostProcessSettingsVars();
		}

		private void InitPostProcessSettingsVars()
		{
			if (!(postProcessSettings != null))
			{
				cameraRigController = GetComponentInParent<CameraRigController>();
				postProcessLayer = GetComponent<PostProcessLayer>();
				GetComponentInChildren<PostProcessVolume>().profile.TryGetSettings<ScreenDamagePP>(out postProcessSettings);
				if ((bool)postProcessSettings)
				{
					oldDistortionStrength = postProcessSettings.DistortionStrength.value;
					oldDesaturationStrength = postProcessSettings.DesaturationStrength.value;
					oldTintStrength = postProcessSettings.TintStrength.value;
				}
			}
		}

		public void Update()
		{
			InitPostProcessSettingsVars();
			if ((bool)cameraRigController)
			{
				if ((bool)cameraRigController.target)
				{
					HealthComponent component = cameraRigController.target.GetComponent<HealthComponent>();
					if (component != null && component.screenDamageCalculator != null)
					{
						workingScreenDamageCalculator = component.screenDamageCalculator;
					}
					else
					{
						workingScreenDamageCalculator = screenDamageCalculatorDefault;
					}
					workingScreenDamageCalculator.CalculateScreenDamage(this, component);
				}
				else
				{
					workingScreenDamageCalculator = screenDamageCalculatorDefault;
				}
				float num = (SettingsConVars.enableScreenDistortion.value ? DistortionScale : 0f);
				ScreenDamageData screenDamageData = workingScreenDamageCalculator.screenDamageData;
				postProcessSettings.DistortionStrength.Override(screenDamageData.distortionStrength * num);
				postProcessSettings.DesaturationStrength.Override(screenDamageData.desaturationStrength);
				postProcessSettings.TintStrength.Override(screenDamageData.tintStrength);
			}
			else
			{
				postProcessSettings.DistortionStrength.Override(0f);
				postProcessSettings.DesaturationStrength.Override(0f);
				postProcessSettings.TintStrength.Override(0f);
			}
			float value = postProcessSettings.DistortionStrength.value;
			float value2 = postProcessSettings.DesaturationStrength.value;
			float value3 = postProcessSettings.TintStrength.value;
			if (!Mathf.Approximately(oldDistortionStrength, value) || !Mathf.Approximately(oldDesaturationStrength, value2) || !Mathf.Approximately(oldTintStrength, value3))
			{
				postProcessLayer.OnVolumeSettingsChanged();
				oldDistortionStrength = postProcessSettings.DistortionStrength.value;
				oldDesaturationStrength = postProcessSettings.DesaturationStrength.value;
				oldTintStrength = postProcessSettings.TintStrength.value;
			}
		}
	}
	public abstract class ScreenDamageCalculator
	{
		public static int TypeCounter;

		public abstract ScreenDamageData screenDamageData { get; }

		public abstract void CalculateScreenDamage(ScreenDamage screenDamage, HealthComponent healthComponent);

		public abstract void End();
	}
	[Serializable]
	public class ScreenDamageData
	{
		public UnityEngine.Color IntendedTintColor;

		public float distortionStrength;

		public float desaturationStrength;

		public float tintStrength;

		public bool combineAdditively;

		public UnityEngine.Color tintColor
		{
			get
			{
				if (combineAdditively)
				{
					return IntendedTintColor;
				}
				return (UnityEngine.Color)UnityEngine.Vector4.one - IntendedTintColor;
			}
		}

		public ColorParameter colorParameter => new ColorParameter
		{
			value = tintColor
		};

		public ScreenDamageData(UnityEngine.Color _tintColor, float _distortionStrength, float _desatStrength, float _tintStrength, bool _combineAdditively)
		{
			IntendedTintColor = _tintColor;
			distortionStrength = _distortionStrength;
			desaturationStrength = _desatStrength;
			tintStrength = _tintStrength;
			combineAdditively = _combineAdditively;
		}

		public ScreenDamageData()
		{
			IntendedTintColor = UnityEngine.Color.red;
			distortionStrength = 0f;
			desaturationStrength = 0f;
			tintStrength = 0f;
			combineAdditively = false;
		}
	}
	public class ScreenDamageCalculatorDefault : ScreenDamageCalculator
	{
		private const float deathWeight = 0.5f;

		private const float hitTintDecayTime = 0.6f;

		private const float hitTintScale = 0.9f;

		private float healthPercentage;

		private float totalStrength;

		private float hitTint;

		private ScreenDamageData _screenDamageData = new ScreenDamageData(UnityEngine.Color.red, 0f, 0f, 0f, _combineAdditively: false);

		public override ScreenDamageData screenDamageData => _screenDamageData;

		public bool combineAdditively => false;

		public override void CalculateScreenDamage(ScreenDamage screenDamage, HealthComponent targetHealthComponent)
		{
			totalStrength = 0.5f;
			hitTint = 0f;
			if ((bool)targetHealthComponent)
			{
				healthPercentage = Mathf.Clamp(targetHealthComponent.health / targetHealthComponent.fullHealth, 0f, 1f);
				hitTint = Mathf.Clamp01(1f - targetHealthComponent.timeSinceLastHit / 0.6f) * 0.9f;
				if (targetHealthComponent.health <= 0f)
				{
					totalStrength = 0f;
				}
			}
			if (screenDamage.debugHealthPercentage != 0f)
			{
				healthPercentage = screenDamage.debugHealthPercentage;
			}
			_screenDamageData.distortionStrength = totalStrength * screenDamage.DistortionScale * Mathf.Pow(1f - healthPercentage, screenDamage.DistortionPower);
			_screenDamageData.desaturationStrength = totalStrength * screenDamage.DesaturationScale * Mathf.Pow(1f - healthPercentage, screenDamage.DesaturationPower);
			_screenDamageData.tintStrength = totalStrength * screenDamage.TintScale * (Mathf.Pow(1f - healthPercentage, screenDamage.TintPower) + hitTint);
		}

		public override void End()
		{
		}
	}
	public class ScreenDamageCalculatorDisabledSkills : ScreenDamageCalculator
	{
		private const float deathWeight = 0.5f;

		private const float hitTintDecayTime = 0.6f;

		private const float hitTintScale = 0.9f;

		private const float deSaturationBase = 0.8f;

		private const float tintBase = 0.03f;

		private const float tintMaximum = 0.17f;

		private float healthPercentage;

		private float totalStrength;

		private float hitTint;

		private ScreenDamageData _screenDamageData = new ScreenDamageData(UnityEngine.Color.grey, 0f, 0.7f, 0.3f, _combineAdditively: false);

		public override ScreenDamageData screenDamageData => _screenDamageData;

		public bool combineAdditively => false;

		public override void CalculateScreenDamage(ScreenDamage screenDamage, HealthComponent targetHealthComponent)
		{
			totalStrength = 0.5f;
			hitTint = 0f;
			if ((bool)targetHealthComponent)
			{
				healthPercentage = Mathf.Clamp(targetHealthComponent.health / targetHealthComponent.fullHealth, 0f, 1f);
				hitTint = Mathf.Clamp01(1f - targetHealthComponent.timeSinceLastHit / 0.6f) * 0.9f;
				if (targetHealthComponent.health <= 0f)
				{
					totalStrength = 0f;
				}
			}
			if (screenDamage.debugHealthPercentage != 0f)
			{
				healthPercentage = screenDamage.debugHealthPercentage;
			}
			float distortionStrength = totalStrength * screenDamage.DistortionScale * Mathf.Pow(1f - healthPercentage, screenDamage.DistortionPower);
			if (screenDamage.useDebugValues)
			{
				distortionStrength = screenDamage.debugDistortionValue;
			}
			_screenDamageData.distortionStrength = distortionStrength;
			distortionStrength = 0.8f;
			if (screenDamage.useDebugValues)
			{
				distortionStrength = screenDamage.debugDesatValue;
			}
			_screenDamageData.desaturationStrength = distortionStrength;
			distortionStrength = 0.03f;
			distortionStrength += (totalStrength * screenDamage.TintScale + 0.2f) * (Mathf.Pow(1f - healthPercentage, screenDamage.TintPower) + hitTint);
			distortionStrength = Mathf.Min(distortionStrength, 0.17f);
			if (screenDamage.useDebugValues)
			{
				distortionStrength = screenDamage.debugTintValue;
			}
			_screenDamageData.tintStrength = distortionStrength;
			ScreenDamagePPRenderer.ExtendTemporaryProps();
		}

		public override void End()
		{
			ScreenDamagePPRenderer.ClearTemporaryProps(this);
		}
	}
	public class ScreenDamageCalculatorSojourn : ScreenDamageCalculator
	{
		private float totalStrength;

		private float hitTint;

		private const float deathWeight = 0.5f;

		private const float hitTintDecayTime = 0.6f;

		private const float hitTintScale = 1.6f;

		private float healthPercentage;

		private ScreenDamageData _screenDamageData = new ScreenDamageData();

		public float minimumDamage = 0.2f;

		public float maximumDamage = 0.8f;

		public float duration = 4f;

		public bool _combineAdditively;

		private float timeStarted;

		private bool initialized;

		public override ScreenDamageData screenDamageData => _screenDamageData;

		public override void CalculateScreenDamage(ScreenDamage screenDamage, HealthComponent targetHealthComponent)
		{
			if (!initialized)
			{
				Initialize();
			}
			totalStrength = 0.5f;
			hitTint = 0f;
			float num = (Time.time - timeStarted) % duration / duration;
			if (num > 0.5f)
			{
				num = 0.5f - (num - 0.5f);
			}
			num /= 0.5f;
			healthPercentage = Mathf.Lerp(minimumDamage, maximumDamage, num);
			if (screenDamage.debugHealthPercentage != 0f)
			{
				healthPercentage = screenDamage.debugHealthPercentage;
			}
			_screenDamageData.distortionStrength = totalStrength * screenDamage.DistortionScale * Mathf.Pow(healthPercentage, screenDamage.DistortionPower);
			_screenDamageData.desaturationStrength = totalStrength * screenDamage.DesaturationScale * Mathf.Pow(healthPercentage, screenDamage.DesaturationPower);
			_screenDamageData.tintStrength = totalStrength * screenDamage.TintScale * (Mathf.Pow(healthPercentage, screenDamage.TintPower) + hitTint);
			ScreenDamagePPRenderer.ExtendTemporaryProps();
		}

		private void Initialize()
		{
			initialized = true;
			timeStarted = Time.time;
			if (_screenDamageData.tintColor == default(UnityEngine.Color))
			{
				_screenDamageData.IntendedTintColor = UnityEngine.Color.yellow;
			}
			ScreenDamagePPRenderer.SetTemporaryProps(this, _screenDamageData.colorParameter, null, _screenDamageData.combineAdditively);
		}

		public override void End()
		{
			if (initialized)
			{
				ScreenDamagePPRenderer.ClearTemporaryProps(this);
			}
		}
	}
	[RequireComponent(typeof(Camera))]
	public class VisionLimitEffect : MonoBehaviour
	{
		private static class ShaderParamsIDs
		{
			public static int origin = Shader.PropertyToID("_Origin");

			public static int rangeStart = Shader.PropertyToID("_RangeStart");

			public static int rangeEnd = Shader.PropertyToID("_RangeEnd");

			public static int color = Shader.PropertyToID("_Color");
		}

		public CameraRigController cameraRigController;

		private Camera camera;

		private float desiredVisionDistance = float.PositiveInfinity;

		private CommandBuffer commandBuffer;

		private Material material;

		private UnityEngine.Vector3 lastKnownTargetPosition;

		private float currentAlpha;

		private float alphaVelocity;

		private float currentVisionDistance;

		private float currentVisionDistanceVelocity;

		private void Awake()
		{
			camera = GetComponent<Camera>();
			commandBuffer = new CommandBuffer();
			commandBuffer.name = "VisionLimitEffect";
			Shader shader = LegacyShaderAPI.Find("Hopoo Games/Internal/VisionLimit");
			material = new Material(shader);
			material.name = "VisionLimitEffectMaterial";
		}

		private void OnDestroy()
		{
			DestroyTemporaryAsset(material);
			commandBuffer = null;
			camera = null;
		}

		private void OnEnable()
		{
			camera.AddCommandBuffer(CameraEvent.AfterImageEffectsOpaque, commandBuffer);
		}

		private void OnDisable()
		{
			camera.RemoveCommandBuffer(CameraEvent.AfterImageEffectsOpaque, commandBuffer);
		}

		private void OnPreCull()
		{
			UpdateCommandBuffer();
		}

		private void LateUpdate()
		{
			Transform transform = (cameraRigController.target ? cameraRigController.target.transform : null);
			CharacterBody targetBody = cameraRigController.targetBody;
			if ((bool)transform)
			{
				lastKnownTargetPosition = transform.position;
			}
			desiredVisionDistance = (targetBody ? targetBody.visionDistance : float.PositiveInfinity);
			float target = 0f;
			float target2 = 4000f;
			if (desiredVisionDistance != float.PositiveInfinity)
			{
				target = 1f;
				target2 = desiredVisionDistance;
			}
			currentAlpha = Mathf.SmoothDamp(currentAlpha, target, ref alphaVelocity, 0.2f, float.PositiveInfinity, Time.deltaTime);
			currentVisionDistance = Mathf.SmoothDamp(currentVisionDistance, target2, ref currentVisionDistanceVelocity, 0.2f, float.PositiveInfinity, Time.deltaTime);
		}

		private void UpdateCommandBuffer()
		{
			commandBuffer.Clear();
			if (!(currentAlpha <= 0f))
			{
				float num = Mathf.Max(0f, currentVisionDistance * 0.5f);
				float value = Mathf.Max(num + 0.01f, currentVisionDistance);
				material.SetVector(ShaderParamsIDs.origin, lastKnownTargetPosition);
				material.SetFloat(ShaderParamsIDs.rangeStart, num);
				material.SetFloat(ShaderParamsIDs.rangeEnd, value);
				material.SetColor(ShaderParamsIDs.color, new UnityEngine.Color(0f, 0f, 0f, currentAlpha));
				commandBuffer.Blit(null, BuiltinRenderTextureType.CurrentActive, material);
			}
		}

		private void DestroyTemporaryAsset(UnityEngine.Object temporaryAsset)
		{
			if (Application.isPlaying)
			{
				UnityEngine.Object.Destroy(temporaryAsset);
			}
			else
			{
				UnityEngine.Object.DestroyImmediate(temporaryAsset);
			}
		}
	}
}
namespace RoR2.Mecanim
{
	public class ClearLayerWeight : StateMachineBehaviour
	{
		public bool resetOnExit = true;

		public string layerName;

		public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			base.OnStateEnter(animator, stateInfo, layerIndex);
			int layerIndex2 = layerIndex;
			if (layerName.Length > 0)
			{
				layerIndex2 = animator.GetLayerIndex(layerName);
			}
			animator.SetLayerWeight(layerIndex2, 0f);
		}

		public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			base.OnStateExit(animator, stateInfo, layerIndex);
			if (resetOnExit)
			{
				int layerIndex2 = layerIndex;
				if (layerName.Length > 0)
				{
					layerIndex2 = animator.GetLayerIndex(layerName);
				}
				animator.SetLayerWeight(layerIndex2, 1f);
			}
		}
	}
	public class ClockParamWriter : StateMachineBehaviour
	{
		public string targetParamName = "time";

		public float cyclesPerDay = 2f;

		private const float secondsPerDay = 86400f;

		public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			base.OnStateUpdate(animator, stateInfo, layerIndex);
			float num = 0f;
			num = ((!Run.instance) ? ((float)(DateTime.Now - DateTime.Today).TotalSeconds) : Run.instance.GetRunStopwatch());
			animator.SetFloat(targetParamName, cyclesPerDay * num / 86400f);
		}
	}
	public class CrouchMecanim : MonoBehaviour
	{
		public float duckHeight;

		public Animator animator;

		public float smoothdamp;

		public float initialVerticalOffset;

		public Transform crouchOriginOverride;

		private float crouchCycle;

		private const float crouchRaycastFrequency = 2f;

		private float crouchStopwatch;

		private static readonly int crouchCycleOffsetParamNameHash = Animator.StringToHash("crouchCycleOffset");

		private void FixedUpdate()
		{
			crouchStopwatch -= Time.fixedDeltaTime;
			if (crouchStopwatch <= 0f)
			{
				crouchStopwatch = 0.5f;
				Transform transform = (crouchOriginOverride ? crouchOriginOverride : base.transform);
				UnityEngine.Vector3 up = transform.up;
				RaycastHit hitInfo;
				bool flag = Physics.Raycast(new Ray(transform.position - up * initialVerticalOffset, up), out hitInfo, duckHeight + initialVerticalOffset, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
				crouchCycle = (flag ? Mathf.Clamp01(1f - (hitInfo.distance - initialVerticalOffset) / duckHeight) : 0f);
			}
		}

		private void Update()
		{
			if ((bool)animator)
			{
				animator.SetFloat(crouchCycleOffsetParamNameHash, crouchCycle, smoothdamp, Time.deltaTime);
			}
		}

		private void OnDrawGizmos()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			Gizmos.DrawLine(base.transform.position, base.transform.position + base.transform.up * duckHeight);
			Gizmos.color = UnityEngine.Color.red;
			Gizmos.DrawLine(base.transform.position, base.transform.position + -base.transform.up * initialVerticalOffset);
		}
	}
	public class PlaySoundOnEnter : StateMachineBehaviour
	{
		public string soundString;

		public string stopSoundString;

		public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			base.OnStateEnter(animator, stateInfo, layerIndex);
			Util.PlaySound(soundString, animator.gameObject);
		}

		public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			base.OnStateEnter(animator, stateInfo, layerIndex);
			Util.PlaySound(stopSoundString, animator.gameObject);
		}
	}
	public class RandomBlinkController : MonoBehaviour
	{
		public Animator animator;

		public string[] blinkTriggers;

		public float blinkChancePerUpdate;

		private float stopwatch;

		private const float updateFrequency = 4f;

		private void FixedUpdate()
		{
			stopwatch += Time.fixedDeltaTime;
			if (!(stopwatch >= 0.25f))
			{
				return;
			}
			stopwatch = 0f;
			for (int i = 0; i < blinkTriggers.Length; i++)
			{
				if (Util.CheckRoll(blinkChancePerUpdate))
				{
					animator.SetTrigger(blinkTriggers[i]);
				}
			}
		}
	}
	public class ResetFootsteps : StateMachineBehaviour
	{
		public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			_ = (bool)animator.GetComponent<FootstepHandler>();
		}
	}
	public class SetCorrectiveLayer : StateMachineBehaviour
	{
		public string referenceOverrideLayerName;

		public float maxWeight = 1f;

		private float smoothVelocity;

		public override void OnStateMachineEnter(Animator animator, int stateMachinePathHash)
		{
			base.OnStateMachineEnter(animator, stateMachinePathHash);
		}

		public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			int layerIndex2 = animator.GetLayerIndex(referenceOverrideLayerName);
			float target = Mathf.Min(animator.GetLayerWeight(layerIndex2), maxWeight);
			float weight = Mathf.SmoothDamp(animator.GetLayerWeight(layerIndex), target, ref smoothVelocity, 0.2f);
			animator.SetLayerWeight(layerIndex, weight);
			base.OnStateUpdate(animator, stateInfo, layerIndex);
		}
	}
	public class SetRandomIntOnEnter : StateMachineBehaviour
	{
		public string intParameterName;

		public int rangeMin;

		public int rangeMax;

		public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			base.OnStateEnter(animator, stateInfo, layerIndex);
			animator.SetInteger(intParameterName, UnityEngine.Random.Range(rangeMin, rangeMax + 1));
		}
	}
	public class StayInStateForDuration : StateMachineBehaviour
	{
		[Tooltip("The reference float - this is how long we will stay in this state")]
		public string durationFloatParameterName;

		private int durationFloatParameterHash;

		[Tooltip("The counter float - this is exposed incase we want to reset it")]
		public string stopwatchFloatParameterName;

		private int stopwatchFloatParameterHash;

		[Tooltip("The bool that will be set to 'false' once the duration is up, and 'true' when entering this state.")]
		public string deactivationBoolParameterName;

		private int deactivationBoolParameterHash;

		public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
		{
			base.OnStateEnter(animator, stateInfo, layerIndex);
			durationFloatParameterHash = Animator.StringToHash(durationFloatParameterName);
			stopwatchFloatParameterHash = Animator.StringToHash(stopwatchFloatParameterName);
			deactivationBoolParameterHash = Animator.StringToHash(deactivationBoolParameterName);
			animator.SetBool(deactivationBoolParameterHash, value: true);
		}

		public override void OnStateUpdate(Animator animator, AnimatorStateInfo animatorStateInfo, int layerIndex)
		{
			base.OnStateUpdate(animator, animatorStateInfo, layerIndex);
			float @float = animator.GetFloat(stopwatchFloatParameterHash);
			float float2 = animator.GetFloat(durationFloatParameterHash);
			@float += Time.deltaTime;
			if (@float >= float2)
			{
				animator.SetFloat(stopwatchFloatParameterHash, 0f);
				animator.SetBool(deactivationBoolParameterHash, value: false);
			}
			else
			{
				animator.SetFloat(stopwatchFloatParameterHash, @float);
			}
		}
	}
}
namespace RoR2.Items
{
	public class ImmuneToDebuffBehavior : BaseItemBodyBehavior
	{
		public const float barrierFraction = 0.1f;

		public const float cooldownSeconds = 5f;

		private HealthComponent healthComponent;

		private bool isProtected;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return DLC1Content.Items.ImmuneToDebuff;
		}

		public static bool OverrideDebuff(BuffIndex buffIndex, CharacterBody body)
		{
			BuffDef buffDef = BuffCatalog.GetBuffDef(buffIndex);
			if ((bool)buffDef)
			{
				return OverrideDebuff(buffDef, body);
			}
			return false;
		}

		public static bool OverrideDebuff(BuffDef buffDef, CharacterBody body)
		{
			if (buffDef.buffIndex != BuffIndex.None && buffDef.isDebuff)
			{
				return TryApplyOverride(body);
			}
			return false;
		}

		public static bool OverrideDot(InflictDotInfo inflictDotInfo)
		{
			CharacterBody characterBody = inflictDotInfo.victimObject?.GetComponent<CharacterBody>();
			if ((bool)characterBody)
			{
				return TryApplyOverride(characterBody);
			}
			return false;
		}

		private static bool TryApplyOverride(CharacterBody body)
		{
			ImmuneToDebuffBehavior component = body.GetComponent<ImmuneToDebuffBehavior>();
			if ((bool)component)
			{
				if (component.isProtected)
				{
					return true;
				}
				if (body.HasBuff(DLC1Content.Buffs.ImmuneToDebuffReady) && (bool)component.healthComponent)
				{
					component.healthComponent.AddBarrier(0.1f * component.healthComponent.fullCombinedHealth);
					body.RemoveBuff(DLC1Content.Buffs.ImmuneToDebuffReady);
					EffectManager.SimpleImpactEffect(Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/ImmuneToDebuff/ImmuneToDebuffEffect.prefab").WaitForCompletion(), body.corePosition, UnityEngine.Vector3.up, transmit: true);
					if (!body.HasBuff(DLC1Content.Buffs.ImmuneToDebuffReady))
					{
						body.AddTimedBuff(DLC1Content.Buffs.ImmuneToDebuffCooldown, 5f);
					}
					component.isProtected = true;
					return true;
				}
			}
			return false;
		}

		private void OnEnable()
		{
			healthComponent = GetComponent<HealthComponent>();
		}

		private void OnDisable()
		{
			healthComponent = null;
			if ((bool)base.body)
			{
				while (base.body.GetBuffCount(DLC1Content.Buffs.ImmuneToDebuffReady) > 0)
				{
					base.body.RemoveBuff(DLC1Content.Buffs.ImmuneToDebuffReady);
				}
				if (base.body.HasBuff(DLC1Content.Buffs.ImmuneToDebuffCooldown))
				{
					base.body.RemoveBuff(DLC1Content.Buffs.ImmuneToDebuffCooldown);
				}
			}
		}

		private void FixedUpdate()
		{
			isProtected = false;
			bool flag = base.body.HasBuff(DLC1Content.Buffs.ImmuneToDebuffCooldown);
			bool flag2 = base.body.HasBuff(DLC1Content.Buffs.ImmuneToDebuffReady);
			if (!flag && !flag2)
			{
				for (int i = 0; i < stack; i++)
				{
					base.body.AddBuff(DLC1Content.Buffs.ImmuneToDebuffReady);
				}
			}
			if (flag2 && flag)
			{
				base.body.RemoveBuff(DLC1Content.Buffs.ImmuneToDebuffReady);
			}
		}
	}
	public abstract class BaseItemBodyBehavior : MonoBehaviour
	{
		private struct ItemTypePair
		{
			public ItemIndex itemIndex;

			public Type behaviorType;
		}

		private struct NetworkContextSet
		{
			public ItemTypePair[] itemTypePairs;

			public FixedSizeArrayPool<BaseItemBodyBehavior> behaviorArraysPool;

			public void SetItemTypePairs(List<ItemTypePair> itemTypePairs)
			{
				this.itemTypePairs = itemTypePairs.ToArray();
				behaviorArraysPool = new FixedSizeArrayPool<BaseItemBodyBehavior>(this.itemTypePairs.Length);
			}
		}

		[MeansImplicitUse]
		[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
		public class ItemDefAssociationAttribute : HG.Reflection.SearchableAttribute
		{
			public Type behaviorTypeOverride;

			public bool useOnServer = true;

			public bool useOnClient = true;
		}

		public int stack;

		private static NetworkContextSet server;

		private static NetworkContextSet client;

		private static NetworkContextSet shared;

		private static CharacterBody earlyAssignmentBody = null;

		private static Dictionary<UnityObjectWrapperKey<CharacterBody>, BaseItemBodyBehavior[]> bodyToItemBehaviors = new Dictionary<UnityObjectWrapperKey<CharacterBody>, BaseItemBodyBehavior[]>();

		public CharacterBody body { get; private set; }

		protected void Awake()
		{
			body = earlyAssignmentBody;
			earlyAssignmentBody = null;
		}

		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			List<ItemTypePair> list = new List<ItemTypePair>();
			List<ItemTypePair> list2 = new List<ItemTypePair>();
			List<ItemTypePair> list3 = new List<ItemTypePair>();
			List<ItemDefAssociationAttribute> list4 = new List<ItemDefAssociationAttribute>();
			HG.Reflection.SearchableAttribute.GetInstances(list4);
			Type typeFromHandle = typeof(BaseItemBodyBehavior);
			Type typeFromHandle2 = typeof(ItemDef);
			foreach (ItemDefAssociationAttribute item in list4)
			{
				if (!(item.target is MethodInfo methodInfo))
				{
					UnityEngine.Debug.LogError("ItemDefAssociationAttribute cannot be applied to object of type '" + item?.GetType().FullName + "'");
					continue;
				}
				if (!methodInfo.IsStatic)
				{
					UnityEngine.Debug.LogError("ItemDefAssociationAttribute cannot be applied to method " + methodInfo.DeclaringType.FullName + "." + methodInfo.Name + ": Method is not static.");
					continue;
				}
				Type type = item.behaviorTypeOverride ?? methodInfo.DeclaringType;
				if (!typeFromHandle.IsAssignableFrom(type))
				{
					UnityEngine.Debug.LogError("ItemDefAssociationAttribute cannot be applied to method " + methodInfo.DeclaringType.FullName + "." + methodInfo.Name + ": " + methodInfo.DeclaringType.FullName + " does not derive from " + typeFromHandle.FullName + ".");
					continue;
				}
				if (type.IsAbstract)
				{
					UnityEngine.Debug.LogError("ItemDefAssociationAttribute cannot be applied to method " + methodInfo.DeclaringType.FullName + "." + methodInfo.Name + ": " + methodInfo.DeclaringType.FullName + " is an abstract type.");
					continue;
				}
				if (!typeFromHandle2.IsAssignableFrom(methodInfo.ReturnType))
				{
					UnityEngine.Debug.LogError(string.Format("{0} cannot be applied to method {1}.{2}: {3}.{4} returns type '{5}' instead of {6}.", "ItemDefAssociationAttribute", methodInfo.DeclaringType.FullName, methodInfo.Name, methodInfo.DeclaringType.FullName, methodInfo, methodInfo.ReturnType?.FullName ?? "void", typeFromHandle2.FullName));
					continue;
				}
				if (methodInfo.GetGenericArguments().Length != 0)
				{
					UnityEngine.Debug.LogError(string.Format("{0} cannot be applied to method {1}.{2}: {3}.{4} must take no arguments.", "ItemDefAssociationAttribute", methodInfo.DeclaringType.FullName, methodInfo.Name, methodInfo.DeclaringType.FullName, methodInfo));
					continue;
				}
				ItemDef itemDef = (ItemDef)methodInfo.Invoke(null, Array.Empty<object>());
				if (!itemDef)
				{
					UnityEngine.Debug.LogError(methodInfo.DeclaringType.FullName + "." + methodInfo.Name + " returned null.");
					continue;
				}
				if (itemDef.itemIndex < ItemIndex.Count)
				{
					UnityEngine.Debug.LogError($"{methodInfo.DeclaringType.FullName}.{methodInfo.Name} returned an ItemDef that's not registered in the ItemCatalog. result={itemDef}");
					continue;
				}
				if (item.useOnServer)
				{
					list.Add(new ItemTypePair
					{
						itemIndex = itemDef.itemIndex,
						behaviorType = type
					});
				}
				if (item.useOnClient)
				{
					list2.Add(new ItemTypePair
					{
						itemIndex = itemDef.itemIndex,
						behaviorType = type
					});
				}
				if (item.useOnServer || item.useOnClient)
				{
					list3.Add(new ItemTypePair
					{
						itemIndex = itemDef.itemIndex,
						behaviorType = type
					});
				}
			}
			server.SetItemTypePairs(list);
			client.SetItemTypePairs(list2);
			shared.SetItemTypePairs(list3);
			CharacterBody.onBodyAwakeGlobal += OnBodyAwakeGlobal;
			CharacterBody.onBodyDestroyGlobal += OnBodyDestroyGlobal;
			CharacterBody.onBodyInventoryChangedGlobal += OnBodyInventoryChangedGlobal;
		}

		private static ref NetworkContextSet GetNetworkContext()
		{
			bool active = NetworkServer.active;
			bool active2 = NetworkClient.active;
			if (active)
			{
				if (active2)
				{
					return ref shared;
				}
				return ref server;
			}
			if (active2)
			{
				return ref client;
			}
			throw new InvalidOperationException("Neither server nor client is running.");
		}

		private static void OnBodyAwakeGlobal(CharacterBody body)
		{
			BaseItemBodyBehavior[] value = GetNetworkContext().behaviorArraysPool.Request();
			bodyToItemBehaviors.Add(body, value);
		}

		private static void OnBodyDestroyGlobal(CharacterBody body)
		{
			BaseItemBodyBehavior[] array = bodyToItemBehaviors[body];
			for (int i = 0; i < array.Length; i++)
			{
				UnityEngine.Object.Destroy(array[i]);
			}
			bodyToItemBehaviors.Remove(body);
			if (NetworkServer.active || NetworkClient.active)
			{
				GetNetworkContext().behaviorArraysPool.Return(array);
			}
		}

		private static void OnBodyInventoryChangedGlobal(CharacterBody body)
		{
			UpdateBodyItemBehaviorStacks(body);
		}

		private static void UpdateBodyItemBehaviorStacks(CharacterBody body)
		{
			ref NetworkContextSet networkContext = ref GetNetworkContext();
			BaseItemBodyBehavior[] array = bodyToItemBehaviors[body];
			ItemTypePair[] itemTypePairs = networkContext.itemTypePairs;
			Inventory inventory = body.inventory;
			if ((bool)inventory)
			{
				for (int i = 0; i < itemTypePairs.Length; i++)
				{
					ItemTypePair itemTypePair = itemTypePairs[i];
					SetItemStack(body, ref array[i], itemTypePair.behaviorType, inventory.GetItemCount(itemTypePair.itemIndex));
				}
				return;
			}
			for (int j = 0; j < itemTypePairs.Length; j++)
			{
				ref BaseItemBodyBehavior reference = ref array[j];
				if ((object)reference != null)
				{
					UnityEngine.Object.Destroy(reference);
					reference = null;
				}
			}
		}

		private static void SetItemStack(CharacterBody body, ref BaseItemBodyBehavior behavior, Type behaviorType, int stack)
		{
			if ((object)behavior == null != stack <= 0)
			{
				if (stack <= 0)
				{
					UnityEngine.Object.Destroy(behavior);
					behavior = null;
				}
				else
				{
					earlyAssignmentBody = body;
					behavior = (BaseItemBodyBehavior)body.gameObject.AddComponent(behaviorType);
					earlyAssignmentBody = null;
				}
			}
			if ((object)behavior != null)
			{
				behavior.stack = stack;
			}
		}
	}
	public class BeetleGlandBodyBehavior : BaseItemBodyBehavior
	{
		private static readonly float timeBetweenGuardResummons = 30f;

		private static readonly float timeBetweenGuardRetryResummons = 1f;

		private float guardResummonCooldown;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.BeetleGland;
		}

		private void FixedUpdate()
		{
			int num = stack;
			CharacterMaster bodyMaster = base.body.master;
			if (!bodyMaster)
			{
				return;
			}
			int deployableCount = bodyMaster.GetDeployableCount(DeployableSlot.BeetleGuardAlly);
			if (deployableCount >= num)
			{
				return;
			}
			guardResummonCooldown -= Time.fixedDeltaTime;
			if (guardResummonCooldown <= 0f)
			{
				DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/CharacterSpawnCards/cscBeetleGuardAlly"), new DirectorPlacementRule
				{
					placementMode = DirectorPlacementRule.PlacementMode.Approximate,
					minDistance = 3f,
					maxDistance = 40f,
					spawnOnTarget = base.transform
				}, RoR2Application.rng);
				directorSpawnRequest.summonerBodyObject = base.gameObject;
				directorSpawnRequest.onSpawnedServer = OnGuardMasterSpawned;
				DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
				if (deployableCount < num)
				{
					guardResummonCooldown = timeBetweenGuardRetryResummons;
				}
				else
				{
					guardResummonCooldown = timeBetweenGuardResummons;
				}
			}
			void OnGuardMasterSpawned(SpawnCard.SpawnResult spawnResult)
			{
				GameObject spawnedInstance = spawnResult.spawnedInstance;
				if ((bool)spawnedInstance)
				{
					CharacterMaster component = spawnedInstance.GetComponent<CharacterMaster>();
					if ((bool)component)
					{
						component.inventory.GiveItem(RoR2Content.Items.BoostDamage, 30);
						component.inventory.GiveItem(RoR2Content.Items.BoostHp, 10);
						Deployable component2 = component.GetComponent<Deployable>();
						if ((bool)component2)
						{
							bodyMaster.AddDeployable(component2, DeployableSlot.BeetleGuardAlly);
						}
					}
				}
			}
		}
	}
	public class CaptainDefenseMatrixBodyBehavior : BaseItemBodyBehavior
	{
		private GameObject attachmentGameObject;

		private NetworkedBodyAttachment attachment;

		private bool attachmentActive
		{
			get
			{
				return (object)attachment != null;
			}
			set
			{
				if (value != attachmentActive)
				{
					if (value)
					{
						attachmentGameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/BodyAttachments/CaptainDefenseMatrixItemBodyAttachment"));
						attachment = attachmentGameObject.GetComponent<NetworkedBodyAttachment>();
						attachment.AttachToGameObjectAndSpawn(base.body.gameObject);
					}
					else
					{
						UnityEngine.Object.Destroy(attachmentGameObject);
						attachmentGameObject = null;
						attachment = null;
					}
				}
			}
		}

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.CaptainDefenseMatrix;
		}

		private void OnDisable()
		{
			attachmentActive = false;
		}

		private void FixedUpdate()
		{
			attachmentActive = base.body.healthComponent.alive;
		}
	}
	public static class ContagiousItemManager
	{
		public struct TransformationInfo
		{
			public ItemIndex originalItem;

			public ItemIndex transformedItem;
		}

		private struct InventoryReplacementCandidate
		{
			public Inventory inventory;

			public ItemIndex originalItem;

			public Run.FixedTimeStamp time;

			public bool isForced;
		}

		public static readonly float transformDelay = 0.5f;

		private static ItemIndex[] originalToTransformed = Array.Empty<ItemIndex>();

		private static bool[] itemsToCheck = Array.Empty<bool>();

		private static TransformationInfo[] _transformationInfos = Array.Empty<TransformationInfo>();

		public static ReadOnlyArray<TransformationInfo> transformationInfos = new ReadOnlyArray<TransformationInfo>(_transformationInfos);

		private static List<InventoryReplacementCandidate> pendingChanges = new List<InventoryReplacementCandidate>();

		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			InitTransformationTable();
			Inventory.onInventoryChangedGlobal += OnInventoryChangedGlobal;
			RoR2Application.onFixedUpdate += StaticFixedUpdate;
		}

		private static void StaticFixedUpdate()
		{
			if (pendingChanges.Count > 0)
			{
				ProcessPendingChanges();
			}
		}

		private static void InitTransformationTable()
		{
			originalToTransformed = new ItemIndex[ItemCatalog.itemCount];
			ItemIndex[] array = originalToTransformed;
			ItemIndex value = ItemIndex.None;
			ArrayUtils.SetAll(array, in value);
			itemsToCheck = new bool[ItemCatalog.itemCount];
			foreach (ItemDef.Pair item in ItemCatalog.GetItemPairsForRelationship(DLC1Content.ItemRelationshipTypes.ContagiousItem))
			{
				originalToTransformed[(int)item.itemDef1.itemIndex] = item.itemDef2.itemIndex;
				itemsToCheck[(int)item.itemDef1.itemIndex] = true;
				itemsToCheck[(int)item.itemDef2.itemIndex] = true;
				TransformationInfo value2 = new TransformationInfo
				{
					originalItem = item.itemDef1.itemIndex,
					transformedItem = item.itemDef2.itemIndex
				};
				ArrayUtils.ArrayAppend(ref _transformationInfos, in value2);
			}
			transformationInfos = new ReadOnlyArray<TransformationInfo>(_transformationInfos);
		}

		public static ItemIndex GetTransformedItemIndex(ItemIndex itemIndex)
		{
			if (itemIndex >= ItemIndex.Count && (int)itemIndex < originalToTransformed.Length)
			{
				return originalToTransformed[(int)itemIndex];
			}
			return ItemIndex.None;
		}

		public static ItemIndex GetOriginalItemIndex(ItemIndex transformedItemIndex)
		{
			TransformationInfo[] array = _transformationInfos;
			for (int i = 0; i < array.Length; i++)
			{
				TransformationInfo transformationInfo = array[i];
				if (transformedItemIndex == transformationInfo.transformedItem)
				{
					return transformationInfo.originalItem;
				}
			}
			return ItemIndex.None;
		}

		private static int FindInventoryReplacementCandidateIndex(Inventory inventory, ItemIndex originalItem)
		{
			for (int i = 0; i < pendingChanges.Count; i++)
			{
				InventoryReplacementCandidate inventoryReplacementCandidate = pendingChanges[i];
				if ((object)inventoryReplacementCandidate.inventory == inventory && inventoryReplacementCandidate.originalItem == originalItem)
				{
					return i;
				}
			}
			return -1;
		}

		private static void ProcessPendingChanges()
		{
			if (!NetworkServer.active || !Run.instance)
			{
				pendingChanges.Clear();
				return;
			}
			for (int num = pendingChanges.Count - 1; num >= 0; num--)
			{
				InventoryReplacementCandidate value = pendingChanges[num];
				if (value.time.hasPassed)
				{
					if (!StepInventoryInfection(value.inventory, value.originalItem, int.MaxValue, value.isForced))
					{
						pendingChanges.RemoveAt(num);
					}
					else
					{
						value.time = Run.FixedTimeStamp.now + transformDelay;
						pendingChanges[num] = value;
					}
				}
			}
		}

		private static void OnInventoryChangedGlobal(Inventory inventory)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			for (int i = 0; i < _transformationInfos.Length; i++)
			{
				ref TransformationInfo reference = ref _transformationInfos[i];
				if (inventory.GetItemCount(reference.transformedItem) > 0)
				{
					TryQueueReplacement(inventory, reference.originalItem, reference.transformedItem, isForced: false);
				}
			}
		}

		private static void TryQueueReplacement(Inventory inventory, ItemIndex originalItemIndex, ItemIndex transformedItemIndex, bool isForced)
		{
			if (inventory.GetItemCount(originalItemIndex) > 0 && FindInventoryReplacementCandidateIndex(inventory, transformedItemIndex) == -1)
			{
				pendingChanges.Add(new InventoryReplacementCandidate
				{
					inventory = inventory,
					originalItem = originalItemIndex,
					time = Run.FixedTimeStamp.now + transformDelay,
					isForced = isForced
				});
			}
		}

		public static void TryForceReplacement(Inventory inventory, ItemIndex originalItemIndex)
		{
			ItemIndex transformedItemIndex = GetTransformedItemIndex(originalItemIndex);
			if (transformedItemIndex != ItemIndex.None && Run.instance.IsItemAvailable(transformedItemIndex))
			{
				TryQueueReplacement(inventory, originalItemIndex, transformedItemIndex, isForced: true);
			}
		}

		private static bool StepInventoryInfection(Inventory inventory, ItemIndex originalItem, int limit, bool isForced)
		{
			ItemIndex itemIndex = originalToTransformed[(int)originalItem];
			int itemCount = inventory.GetItemCount(itemIndex);
			if (isForced || itemCount > 0)
			{
				int itemCount2 = inventory.GetItemCount(originalItem);
				int num = Math.Min(limit, itemCount2);
				if (num > 0)
				{
					inventory.RemoveItem(originalItem, num);
					inventory.GiveItem(itemIndex, num);
					CharacterMaster component = inventory.GetComponent<CharacterMaster>();
					if ((bool)component)
					{
						CharacterMasterNotificationQueue.SendTransformNotification(component, originalItem, itemIndex, CharacterMasterNotificationQueue.TransformationType.ContagiousVoid);
					}
					return true;
				}
			}
			return false;
		}
	}
	public static class CrippleWardOnLevelManager
	{
		private static GameObject wardPrefab;

		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			Run.onRunAmbientLevelUp += onRunAmbientLevelUp;
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/CrippleWard", delegate(GameObject operationResult)
			{
				wardPrefab = operationResult;
			});
		}

		private static void onRunAmbientLevelUp(Run run)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (CharacterMaster readOnlyInstances in CharacterMaster.readOnlyInstancesList)
			{
				int itemCount = readOnlyInstances.inventory.GetItemCount(RoR2Content.Items.CrippleWardOnLevel);
				if (itemCount > 0)
				{
					CharacterBody body = readOnlyInstances.GetBody();
					if ((bool)body)
					{
						GameObject gameObject = UnityEngine.Object.Instantiate(wardPrefab, body.transform.position, UnityEngine.Quaternion.identity);
						gameObject.GetComponent<BuffWard>().Networkradius = 8f + 8f * (float)itemCount;
						NetworkServer.Spawn(gameObject);
					}
				}
			}
		}
	}
	public static class ExtraLifeVoidManager
	{
		private const ulong seedSalt = 733uL;

		private static Xoroshiro128Plus rng;

		private static string[] voidBodyNames;

		public static GameObject rezEffectPrefab { get; private set; }

		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/Effects/VoidRezEffect", delegate(GameObject operationResult)
			{
				rezEffectPrefab = operationResult;
			});
			voidBodyNames = new string[1] { "NullifierBody" };
			Run.onRunStartGlobal += OnRunStart;
		}

		private static void OnRunStart(Run run)
		{
			rng = new Xoroshiro128Plus(run.seed ^ 0x2DD);
		}

		public static GameObject GetNextBodyPrefab()
		{
			return BodyCatalog.FindBodyPrefab(voidBodyNames[rng.RangeInt(0, voidBodyNames.Length)]);
		}
	}
	public class HeadstomperBodyBehavior : BaseItemBodyBehavior
	{
		private GameObject headstompersControllerObject;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.FallBoots;
		}

		private void OnEnable()
		{
			headstompersControllerObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/HeadstompersController"));
			headstompersControllerObject.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.body.gameObject);
		}

		private void OnDisable()
		{
			if ((bool)headstompersControllerObject)
			{
				UnityEngine.Object.Destroy(headstompersControllerObject);
				headstompersControllerObject = null;
			}
		}
	}
	public class IcicleBodyBehavior : BaseItemBodyBehavior
	{
		private static GameObject icicleAuraPrefab;

		private IcicleAuraController icicleAura;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.Icicle;
		}

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/NetworkedObjects/IcicleAura");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				icicleAuraPrefab = x.Result;
			};
		}

		private void OnEnable()
		{
			GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
			GameObject gameObject = UnityEngine.Object.Instantiate(icicleAuraPrefab, base.transform.position, UnityEngine.Quaternion.identity);
			icicleAura = gameObject.GetComponent<IcicleAuraController>();
			icicleAura.Networkowner = base.gameObject;
			NetworkServer.Spawn(gameObject);
		}

		private void OnDisable()
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
			if ((bool)icicleAura)
			{
				UnityEngine.Object.Destroy(icicleAura);
				icicleAura = null;
			}
		}

		private void OnCharacterDeathGlobal(DamageReport damageReport)
		{
			if ((object)damageReport.attackerBody == base.body && (bool)icicleAura)
			{
				icicleAura.OnOwnerKillOther();
			}
		}
	}
	public class LaserTurbineBodyBehavior : BaseItemBodyBehavior
	{
		private GameObject laserTurbineControllerInstance;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.LaserTurbine;
		}

		private void OnEnable()
		{
			laserTurbineControllerInstance = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/LaserTurbineController"), base.body.corePosition, UnityEngine.Quaternion.identity);
			laserTurbineControllerInstance.GetComponent<GenericOwnership>().ownerObject = base.gameObject;
			laserTurbineControllerInstance.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.gameObject);
		}

		private void OnDestroy()
		{
			UnityEngine.Object.Destroy(laserTurbineControllerInstance);
			laserTurbineControllerInstance = null;
		}
	}
	public class MinionLeashBodyBehavior : BaseItemBodyBehavior
	{
		public const float leashDistSq = 160000f;

		public const float teleportDelayTime = 10f;

		public const float minTeleportDistance = 10f;

		public const float maxTeleportDistance = 40f;

		private GameObject helperPrefab;

		private RigidbodyMotor rigidbodyMotor;

		private float teleportAttemptTimer = 10f;

		private float currentTeleportDelayTimer;

		[ItemDefAssociation(useOnServer = true, useOnClient = true)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.MinionLeash;
		}

		private void OnEnable()
		{
			if (SceneInfo.instance.sceneDef.cachedName == "meridian")
			{
				MeridianEventTriggerInteraction.MeridianEventStart.OnMeridianEventStart += StartTeleporting;
			}
		}

		private void OnDisable()
		{
			if (SceneInfo.instance.sceneDef.cachedName == "meridian")
			{
				MeridianEventTriggerInteraction.MeridianEventStart.OnMeridianEventStart -= StartTeleporting;
			}
		}

		public void Start()
		{
			if (base.body.hasEffectiveAuthority)
			{
				helperPrefab = LegacyResourcesAPI.Load<GameObject>("SpawnCards/HelperPrefab");
				rigidbodyMotor = GetComponent<RigidbodyMotor>();
			}
		}

		private void FixedUpdate()
		{
			if (!base.body.hasEffectiveAuthority)
			{
				return;
			}
			CharacterMaster master = base.body.master;
			CharacterMaster characterMaster = (master ? master.minionOwnership.ownerMaster : null);
			CharacterBody characterBody = (characterMaster ? characterMaster.GetBody() : null);
			if (!characterBody)
			{
				return;
			}
			UnityEngine.Vector3 corePosition = characterBody.corePosition;
			UnityEngine.Vector3 corePosition2 = base.body.corePosition;
			if (((!base.body.characterMotor || !(base.body.characterMotor.walkSpeed > 0f)) && (!rigidbodyMotor || !(base.body.moveSpeed > 0f))) || !((corePosition2 - corePosition).sqrMagnitude > 160000f))
			{
				return;
			}
			teleportAttemptTimer -= Time.fixedDeltaTime;
			if (!(teleportAttemptTimer <= 0f))
			{
				return;
			}
			teleportAttemptTimer = 10f;
			SpawnCard spawnCard = ScriptableObject.CreateInstance<SpawnCard>();
			spawnCard.hullSize = base.body.hullClassification;
			spawnCard.nodeGraphType = (base.body.isFlying ? MapNodeGroup.GraphType.Air : MapNodeGroup.GraphType.Ground);
			spawnCard.prefab = helperPrefab;
			GameObject gameObject = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(spawnCard, new DirectorPlacementRule
			{
				placementMode = DirectorPlacementRule.PlacementMode.Approximate,
				position = corePosition,
				minDistance = 10f,
				maxDistance = 40f
			}, RoR2Application.rng));
			if ((bool)gameObject)
			{
				UnityEngine.Vector3 position = gameObject.transform.position;
				if ((position - corePosition).sqrMagnitude < 160000f)
				{
					TeleportHelper.TeleportBody(base.body, position);
					GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(base.body.gameObject);
					if ((bool)teleportEffectPrefab)
					{
						EffectManager.SimpleEffect(teleportEffectPrefab, position, UnityEngine.Quaternion.identity, transmit: true);
					}
					UnityEngine.Object.Destroy(gameObject);
				}
			}
			UnityEngine.Object.Destroy(spawnCard);
		}

		private void StartTeleporting()
		{
			CharacterMaster master = base.body.master;
			CharacterMaster characterMaster = (master ? master.minionOwnership.ownerMaster : null);
			CharacterBody characterBody = (characterMaster ? characterMaster.GetBody() : null);
			if (base.body.hasEffectiveAuthority && (bool)characterBody && (((bool)base.body.characterMotor && base.body.characterMotor.walkSpeed > 0f) || ((bool)rigidbodyMotor && base.body.moveSpeed > 0f)))
			{
				StartCoroutine(Teleport());
			}
		}

		private IEnumerator Teleport()
		{
			currentTeleportDelayTimer = 0f;
			while (currentTeleportDelayTimer < 10f)
			{
				currentTeleportDelayTimer += Time.deltaTime;
				yield return null;
			}
			CharacterMaster master = base.body.master;
			CharacterMaster characterMaster = (master ? master.minionOwnership.ownerMaster : null);
			CharacterBody ownerBody = (characterMaster ? characterMaster.GetBody() : null);
			NodeGraph nodeGraph = SceneInfo.instance.GetNodeGraph(MapNodeGroup.GraphType.Ground);
			if (!ownerBody)
			{
				yield break;
			}
			List<NodeGraph.NodeIndex> list = nodeGraph.FindNodesInRangeWithFlagConditions(ownerBody.transform.position, 3f, 20f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false);
			while (list.Count == 0)
			{
				yield return new WaitForSeconds(1f);
				list = nodeGraph.FindNodesInRangeWithFlagConditions(ownerBody.transform.position, 3f, 20f, HullMask.None, NodeFlags.None, NodeFlags.NoCharacterSpawn, preventOverhead: false);
			}
			while (list.Count > 0)
			{
				int index = UnityEngine.Random.Range(0, list.Count);
				NodeGraph.NodeIndex nodeIndex = list[index];
				if (nodeGraph.GetNodePosition(nodeIndex, out var position))
				{
					TeleportHelper.TeleportBody(base.body, position);
					GameObject teleportEffectPrefab = Run.instance.GetTeleportEffectPrefab(base.body.gameObject);
					if ((bool)teleportEffectPrefab)
					{
						EffectManager.SimpleEffect(teleportEffectPrefab, position, UnityEngine.Quaternion.identity, transmit: true);
					}
					break;
				}
			}
		}
	}
	public static class MultiShopCardUtils
	{
		private const float refundPercentage = 0.1f;

		public static void OnNonMoneyPurchase(CostTypeDef.PayCostContext context)
		{
			OnPurchase(context, 0);
		}

		public static void OnMoneyPurchase(CostTypeDef.PayCostContext context)
		{
			OnPurchase(context, context.cost);
		}

		private static void OnPurchase(CostTypeDef.PayCostContext context, int moneyCost)
		{
			CharacterMaster activatorMaster = context.activatorMaster;
			if (!activatorMaster || !activatorMaster.hasBody || !activatorMaster.inventory || activatorMaster.inventory.currentEquipmentIndex != DLC1Content.Equipment.MultiShopCard.equipmentIndex)
			{
				return;
			}
			CharacterBody body = activatorMaster.GetBody();
			if (body.equipmentSlot.stock <= 0)
			{
				return;
			}
			bool flag = false;
			if (moneyCost > 0)
			{
				flag = true;
				GoldOrb goldOrb = new GoldOrb();
				goldOrb.origin = context.purchasedObject?.transform?.position ?? body.corePosition;
				goldOrb.target = body.mainHurtBox;
				goldOrb.goldAmount = (uint)(0.1f * (float)moneyCost);
				OrbManager.instance.AddOrb(goldOrb);
			}
			ShopTerminalBehavior shopTerminalBehavior = context.purchasedObject?.GetComponent<ShopTerminalBehavior>();
			if ((bool)shopTerminalBehavior && (bool)shopTerminalBehavior.serverMultiShopController)
			{
				flag = true;
				shopTerminalBehavior.serverMultiShopController.SetCloseOnTerminalPurchase(context.purchasedObject.GetComponent<PurchaseInteraction>(), doCloseMultiShop: false);
			}
			if (flag)
			{
				if (body.hasAuthority)
				{
					body.equipmentSlot.OnEquipmentExecuted();
				}
				else
				{
					body.equipmentSlot.CallCmdOnEquipmentExecuted();
				}
			}
		}
	}
	public class MushroomBodyBehavior : BaseItemBodyBehavior
	{
		private static GameObject mushroomWardPrefab;

		private const float baseHealFractionPerSecond = 0.045f;

		private const float healFractionPerSecondPerStack = 0.0225f;

		private GameObject mushroomWardGameObject;

		private HealingWard mushroomHealingWard;

		private TeamFilter mushroomWardTeamFilter;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.Mushroom;
		}

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/NetworkedObjects/MushroomWard");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				mushroomWardPrefab = x.Result;
			};
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			int num = stack;
			bool flag = num > 0 && base.body.GetNotMoving();
			float networkradius = base.body.radius + 1.5f + 1.5f * (float)num;
			if ((bool)mushroomWardGameObject != flag)
			{
				if (flag)
				{
					mushroomWardGameObject = UnityEngine.Object.Instantiate(mushroomWardPrefab, base.body.footPosition, UnityEngine.Quaternion.identity);
					mushroomWardTeamFilter = mushroomWardGameObject.GetComponent<TeamFilter>();
					mushroomHealingWard = mushroomWardGameObject.GetComponent<HealingWard>();
					NetworkServer.Spawn(mushroomWardGameObject);
				}
				else
				{
					UnityEngine.Object.Destroy(mushroomWardGameObject);
					mushroomWardGameObject = null;
				}
			}
			if ((bool)mushroomHealingWard)
			{
				mushroomHealingWard.interval = 0.25f;
				mushroomHealingWard.healFraction = (0.045f + 0.0225f * (float)(num - 1)) * mushroomHealingWard.interval;
				mushroomHealingWard.healPoints = 0f;
				mushroomHealingWard.Networkradius = networkradius;
			}
			if ((bool)mushroomWardTeamFilter)
			{
				mushroomWardTeamFilter.teamIndex = base.body.teamComponent.teamIndex;
			}
		}

		private void OnDisable()
		{
			if ((bool)mushroomWardGameObject)
			{
				UnityEngine.Object.Destroy(mushroomWardGameObject);
			}
		}
	}
	public class NearbyDamageBonusBodyBehavior : BaseItemBodyBehavior
	{
		private GameObject nearbyDamageBonusIndicator;

		private bool indicatorEnabled
		{
			get
			{
				return nearbyDamageBonusIndicator;
			}
			set
			{
				if (indicatorEnabled != value)
				{
					if (value)
					{
						GameObject original = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/NearbyDamageBonusIndicator");
						nearbyDamageBonusIndicator = UnityEngine.Object.Instantiate(original, base.body.corePosition, UnityEngine.Quaternion.identity);
						nearbyDamageBonusIndicator.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.gameObject);
					}
					else
					{
						UnityEngine.Object.Destroy(nearbyDamageBonusIndicator);
						nearbyDamageBonusIndicator = null;
					}
				}
			}
		}

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.NearbyDamageBonus;
		}

		private void OnEnable()
		{
			indicatorEnabled = true;
		}

		private void OnDisable()
		{
			indicatorEnabled = false;
		}
	}
	public class NovaOnLowHealthBodyBehavior : BaseItemBodyBehavior
	{
		private NetworkedBodyAttachment attachment;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.NovaOnLowHealth;
		}

		private void Start()
		{
			attachment = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/BodyAttachments/VagrantNovaItemBodyAttachment")).GetComponent<NetworkedBodyAttachment>();
			attachment.AttachToGameObjectAndSpawn(base.body.gameObject);
		}

		private void FixedUpdate()
		{
			if (!base.body.healthComponent.alive)
			{
				UnityEngine.Object.Destroy(this);
			}
		}

		private void OnDestroy()
		{
			if ((bool)attachment)
			{
				UnityEngine.Object.Destroy(attachment.gameObject);
				attachment = null;
			}
		}
	}
	public class PhasingBodyBehavior : BaseItemBodyBehavior
	{
		private readonly float baseRechargeSeconds = 30f;

		private readonly float rechargeReductionMultiplierPerStack = 0.5f;

		private readonly float buffDuration = 5f;

		private float rechargeStopwatch;

		private GameObject effectPrefab;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.Phasing;
		}

		private void Start()
		{
			rechargeStopwatch = baseRechargeSeconds;
			effectPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ProcStealthkit");
		}

		private void FixedUpdate()
		{
			if (base.body.healthComponent.alive)
			{
				rechargeStopwatch += Time.fixedDeltaTime;
				if (base.body.healthComponent.isHealthLow && !base.body.hasCloakBuff && rechargeStopwatch >= buffDuration + baseRechargeSeconds * Mathf.Pow(rechargeReductionMultiplierPerStack, stack - 1))
				{
					base.body.AddTimedBuff(RoR2Content.Buffs.Cloak, buffDuration);
					base.body.AddTimedBuff(RoR2Content.Buffs.CloakSpeed, buffDuration);
					EffectManager.SpawnEffect(effectPrefab, new EffectData
					{
						origin = base.transform.position,
						rotation = UnityEngine.Quaternion.identity
					}, transmit: true);
					rechargeStopwatch = 0f;
				}
			}
		}
	}
	public class RandomDamageZoneBodyBehavior : BaseItemBodyBehavior
	{
		private static readonly float wardDuration = 25f;

		private static readonly float wardRespawnRetryTime = 1f;

		private static readonly float baseWardRadius = 16f;

		private static readonly float wardRadiusMultiplierPerStack = 1.5f;

		private float wardResummonCooldown;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.RandomDamageZone;
		}

		private void FixedUpdate()
		{
			CharacterMaster master = base.body.master;
			if (!master || !master.IsDeployableSlotAvailable(DeployableSlot.PowerWard))
			{
				return;
			}
			wardResummonCooldown -= Time.fixedDeltaTime;
			if (!(wardResummonCooldown <= 0f))
			{
				return;
			}
			wardResummonCooldown = wardRespawnRetryTime;
			if (master.IsDeployableSlotAvailable(DeployableSlot.PowerWard))
			{
				UnityEngine.Vector3? vector = FindWardSpawnPosition(base.body.corePosition);
				if (vector.HasValue)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/DamageZoneWard"), vector.Value, UnityEngine.Quaternion.identity);
					Util.PlaySound("Play_randomDamageZone_appear", gameObject.gameObject);
					gameObject.GetComponent<TeamFilter>().teamIndex = TeamIndex.None;
					BuffWard component = gameObject.GetComponent<BuffWard>();
					component.Networkradius = baseWardRadius * Mathf.Pow(wardRadiusMultiplierPerStack, stack - 1);
					component.expireDuration = wardDuration;
					NetworkServer.Spawn(gameObject);
					Deployable component2 = gameObject.GetComponent<Deployable>();
					master.AddDeployable(component2, DeployableSlot.PowerWard);
				}
			}
		}

		private UnityEngine.Vector3? FindWardSpawnPosition(UnityEngine.Vector3 ownerPosition)
		{
			if (!SceneInfo.instance)
			{
				return null;
			}
			NodeGraph groundNodes = SceneInfo.instance.groundNodes;
			if (!groundNodes)
			{
				return null;
			}
			List<NodeGraph.NodeIndex> list = groundNodes.FindNodesInRange(ownerPosition, 0f, 50f, HullMask.None);
			if (list.Count > 0 && groundNodes.GetNodePosition(list[(int)UnityEngine.Random.Range(0f, list.Count)], out var position))
			{
				return position;
			}
			return null;
		}
	}
	public static class RandomlyLunarUtils
	{
		private const float replacePercentagePerStack = 0.05f;

		public static PickupIndex CheckForLunarReplacement(PickupIndex pickupIndex, Xoroshiro128Plus rng)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (CanReplace(pickupDef))
			{
				int itemCountGlobal = Util.GetItemCountGlobal(DLC1Content.Items.RandomlyLunar.itemIndex, requiresAlive: false, requiresConnected: false);
				if (itemCountGlobal > 0)
				{
					List<PickupIndex> list = null;
					if (pickupDef.itemIndex != ItemIndex.None)
					{
						list = Run.instance.availableLunarItemDropList;
					}
					else if (pickupDef.equipmentIndex != EquipmentIndex.None)
					{
						list = Run.instance.availableLunarEquipmentDropList;
					}
					if (list != null && list.Count > 0 && rng.nextNormalizedFloat < 0.05f * (float)itemCountGlobal)
					{
						int index = rng.RangeInt(0, list.Count);
						return list[index];
					}
				}
			}
			return pickupIndex;
		}

		public static void CheckForLunarReplacementUniqueArray(PickupIndex[] pickupIndices, Xoroshiro128Plus rng)
		{
			int itemCountGlobal = Util.GetItemCountGlobal(DLC1Content.Items.RandomlyLunar.itemIndex, requiresAlive: false, requiresConnected: false);
			if (itemCountGlobal <= 0)
			{
				return;
			}
			List<PickupIndex> list = null;
			List<PickupIndex> list2 = null;
			for (int i = 0; i < pickupIndices.Length; i++)
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndices[i]);
				if (!CanReplace(pickupDef) || !(rng.nextNormalizedFloat < 0.05f * (float)itemCountGlobal))
				{
					continue;
				}
				List<PickupIndex> list3 = null;
				if (pickupDef.itemIndex != ItemIndex.None)
				{
					if (list == null)
					{
						list = new List<PickupIndex>(Run.instance.availableLunarItemDropList);
						Util.ShuffleList(list, rng);
					}
					list3 = list;
				}
				else if (pickupDef.equipmentIndex != EquipmentIndex.None)
				{
					if (list2 == null)
					{
						list2 = new List<PickupIndex>(Run.instance.availableLunarEquipmentDropList);
						Util.ShuffleList(list2, rng);
					}
					list3 = list2;
				}
				if (list3 != null && list3.Count > 0)
				{
					pickupIndices[i] = list3[i % list3.Count];
				}
			}
		}

		public static bool CanReplace(PickupDef pickupDef)
		{
			return !(pickupDef?.isLunar ?? true);
		}
	}
	internal class RedWhipBodyBehavior : BaseItemBodyBehavior
	{
		private bool providingBuff;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.SprintOutOfCombat;
		}

		private void SetProvidingBuff(bool shouldProvideBuff)
		{
			if (shouldProvideBuff == providingBuff)
			{
				return;
			}
			providingBuff = shouldProvideBuff;
			if (providingBuff)
			{
				base.body.AddBuff(RoR2Content.Buffs.WhipBoost);
				EffectData effectData = new EffectData();
				effectData.origin = base.body.corePosition;
				CharacterDirection characterDirection = base.body.characterDirection;
				bool flag = false;
				if ((bool)characterDirection && characterDirection.moveVector != UnityEngine.Vector3.zero)
				{
					effectData.rotation = Util.QuaternionSafeLookRotation(characterDirection.moveVector);
					flag = true;
				}
				if (!flag)
				{
					effectData.rotation = base.body.transform.rotation;
				}
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/SprintActivate"), effectData, transmit: true);
			}
			else
			{
				base.body.RemoveBuff(RoR2Content.Buffs.WhipBoost);
			}
		}

		private void OnDisable()
		{
			SetProvidingBuff(shouldProvideBuff: false);
		}

		private void FixedUpdate()
		{
			SetProvidingBuff(base.body.outOfCombat);
		}
	}
	public class RoboBallBuddyBodyBehavior : BaseItemBodyBehavior
	{
		private class InventorySync : MonoBehaviour
		{
			public Inventory srcInventory;

			public Inventory destInventory;

			private int granted;

			private void FixedUpdate()
			{
				if ((bool)srcInventory && (bool)destInventory)
				{
					int itemCount = srcInventory.GetItemCount(RoR2Content.Items.RoboBallBuddy);
					int num = itemCount - granted;
					if (num != 0)
					{
						destInventory.GiveItem(RoR2Content.Items.TeamSizeDamageBonus, num);
						granted = itemCount;
					}
				}
			}
		}

		private DeployableMinionSpawner redBuddySpawner;

		private DeployableMinionSpawner greenBuddySpawner;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.RoboBallBuddy;
		}

		private void FixedUpdate()
		{
			if (redBuddySpawner == null && base.isActiveAndEnabled)
			{
				CreateSpawners();
			}
		}

		private void OnDisable()
		{
			DestroySpawners();
		}

		private void CreateSpawners()
		{
			Xoroshiro128Plus rng = new Xoroshiro128Plus(Run.instance.seed ^ (ulong)GetInstanceID());
			CreateSpawner(ref redBuddySpawner, DeployableSlot.RoboBallRedBuddy, LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/CharacterSpawnCards/cscRoboBallRedBuddy"));
			CreateSpawner(ref greenBuddySpawner, DeployableSlot.RoboBallGreenBuddy, LegacyResourcesAPI.Load<SpawnCard>("SpawnCards/CharacterSpawnCards/cscRoboBallGreenBuddy"));
			void CreateSpawner(ref DeployableMinionSpawner buddySpawner, DeployableSlot deployableSlot, SpawnCard spawnCard)
			{
				buddySpawner = new DeployableMinionSpawner(base.body.master, deployableSlot, rng)
				{
					respawnInterval = 30f,
					spawnCard = spawnCard
				};
				buddySpawner.onMinionSpawnedServer += OnMinionSpawnedServer;
			}
		}

		private void DestroySpawners()
		{
			redBuddySpawner?.Dispose();
			redBuddySpawner = null;
			greenBuddySpawner?.Dispose();
			greenBuddySpawner = null;
		}

		private void OnMinionSpawnedServer(SpawnCard.SpawnResult spawnResult)
		{
			GameObject spawnedInstance = spawnResult.spawnedInstance;
			if (!spawnedInstance)
			{
				return;
			}
			CharacterMaster component = spawnedInstance.GetComponent<CharacterMaster>();
			if ((bool)component)
			{
				Inventory inventory = base.body.inventory;
				Inventory inventory2 = component.inventory;
				if ((bool)inventory)
				{
					InventorySync inventorySync = spawnedInstance.AddComponent<InventorySync>();
					inventorySync.srcInventory = inventory;
					inventorySync.destInventory = inventory2;
				}
			}
		}
	}
	public class ShockNearbyBodyBehavior : BaseItemBodyBehavior
	{
		private float teslaBuffRollTimer;

		private const float teslaRollInterval = 10f;

		private float teslaFireTimer;

		private float teslaResetListTimer;

		private float teslaResetListInterval = 0.5f;

		private const float teslaFireInterval = 1f / 12f;

		private bool teslaCrit;

		private bool teslaIsOn;

		private List<HealthComponent> previousTeslaTargetList = new List<HealthComponent>();

		private bool _grantingBuff;

		private BuffDef grantedBuff => RoR2Content.Buffs.TeslaField;

		private bool grantingBuff
		{
			get
			{
				return _grantingBuff;
			}
			set
			{
				if (_grantingBuff != value)
				{
					_grantingBuff = value;
					if (_grantingBuff)
					{
						base.body.AddBuff(grantedBuff);
					}
					else
					{
						base.body.RemoveBuff(grantedBuff);
					}
				}
			}
		}

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.ShockNearby;
		}

		private void FixedUpdate()
		{
			teslaBuffRollTimer += Time.fixedDeltaTime;
			if (teslaBuffRollTimer >= 10f)
			{
				teslaBuffRollTimer = 0f;
				teslaCrit = base.body.RollCrit();
				grantingBuff = !grantingBuff;
			}
			if (!grantingBuff)
			{
				return;
			}
			teslaFireTimer += Time.fixedDeltaTime;
			teslaResetListTimer += Time.fixedDeltaTime;
			if (teslaFireTimer >= 1f / 12f)
			{
				teslaFireTimer = 0f;
				LightningOrb lightningOrb = new LightningOrb
				{
					origin = base.body.corePosition,
					damageValue = base.body.damage * 2f,
					isCrit = teslaCrit,
					bouncesRemaining = 2 * stack,
					teamIndex = base.body.teamComponent.teamIndex,
					attacker = base.gameObject,
					procCoefficient = 0.3f,
					bouncedObjects = previousTeslaTargetList,
					lightningType = LightningOrb.LightningType.Tesla,
					damageColorIndex = DamageColorIndex.Item,
					range = 35f
				};
				HurtBox hurtBox = lightningOrb.PickNextTarget(base.transform.position);
				if ((bool)hurtBox)
				{
					previousTeslaTargetList.Add(hurtBox.healthComponent);
					lightningOrb.target = hurtBox;
					OrbManager.instance.AddOrb(lightningOrb);
				}
			}
			if (teslaResetListTimer >= teslaResetListInterval)
			{
				teslaResetListTimer -= teslaResetListInterval;
				previousTeslaTargetList.Clear();
			}
		}

		private void OnDisable()
		{
			if ((bool)base.body && base.body.HasBuff(grantedBuff))
			{
				base.body.RemoveBuff(grantedBuff);
			}
		}
	}
	public class SiphonOnLowHealthItemBodyBehavior : BaseItemBodyBehavior
	{
		private NetworkedBodyAttachment attachment;

		private SiphonNearbyController siphonNearbyController;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.SiphonOnLowHealth;
		}

		private void OnEnable()
		{
			attachment = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/BodyAttachments/SiphonNearbyBodyAttachment")).GetComponent<NetworkedBodyAttachment>();
			attachment.AttachToGameObjectAndSpawn(base.body.gameObject);
			siphonNearbyController = attachment.GetComponent<SiphonNearbyController>();
		}

		private void OnDisable()
		{
			DestroyAttachment();
		}

		private void FixedUpdate()
		{
			siphonNearbyController.NetworkmaxTargets = (base.body.healthComponent.alive ? stack : 0);
		}

		private void DestroyAttachment()
		{
			if ((bool)attachment)
			{
				UnityEngine.Object.Destroy(attachment.gameObject);
			}
			attachment = null;
			siphonNearbyController = null;
		}
	}
	public class SprintWispBodyBehavior : BaseItemBodyBehavior
	{
		private static readonly float fireRate = 3f / 35f;

		private static readonly float searchRadius = 40f;

		private static readonly float damageCoefficient = 3f;

		private float fireTimer;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.SprintWisp;
		}

		private void FixedUpdate()
		{
			if (base.body.isSprinting)
			{
				fireTimer -= Time.fixedDeltaTime;
				if (fireTimer <= 0f && base.body.moveSpeed > 0f)
				{
					fireTimer += 1f / (fireRate * base.body.moveSpeed);
					Fire();
				}
			}
		}

		private void Fire()
		{
			DevilOrb devilOrb = new DevilOrb
			{
				origin = base.body.corePosition,
				damageValue = base.body.damage * damageCoefficient * (float)stack,
				teamIndex = base.body.teamComponent.teamIndex,
				attacker = base.gameObject,
				damageColorIndex = DamageColorIndex.Item,
				scale = 1f,
				effectType = DevilOrb.EffectType.Wisp,
				procCoefficient = 1f
			};
			if ((bool)(devilOrb.target = devilOrb.PickNextTarget(devilOrb.origin, searchRadius)))
			{
				devilOrb.isCrit = Util.CheckRoll(base.body.crit, base.body.master);
				OrbManager.instance.AddOrb(devilOrb);
			}
		}
	}
	public class SummonedEchoBodyBehavior : BaseItemBodyBehavior
	{
		private float fireTimer;

		private float fireInterval = 3f;

		private float damageCoefficient = 3f;

		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.SummonedEcho;
		}

		private void FixedUpdate()
		{
			fireTimer -= Time.fixedDeltaTime;
			if (fireTimer <= 0f)
			{
				fireTimer = fireInterval;
				FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
				fireProjectileInfo.crit = false;
				fireProjectileInfo.damage = base.body.damage * damageCoefficient;
				fireProjectileInfo.damageColorIndex = DamageColorIndex.Default;
				fireProjectileInfo.damageTypeOverride = DamageType.SlowOnHit;
				fireProjectileInfo.owner = base.body.gameObject;
				fireProjectileInfo.position = base.body.aimOrigin;
				fireProjectileInfo.rotation = UnityEngine.Quaternion.LookRotation(UnityEngine.Vector3.up);
				fireProjectileInfo.procChainMask = default(ProcChainMask);
				fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/EchoHunterProjectile");
				fireProjectileInfo.force = 400f;
				fireProjectileInfo.target = null;
				FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
				ProjectileManager.instance.FireProjectile(fireProjectileInfo2);
			}
		}
	}
	public static class SuppressedItemManager
	{
		private static Dictionary<ItemIndex, ItemIndex> transformationMap = new Dictionary<ItemIndex, ItemIndex>();

		private static GameObject networkedInventoryPrefab;

		private static HashSet<Inventory> pendingTransformationInventories = new HashSet<Inventory>();

		public static Inventory suppressedInventory { get; private set; }

		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			Run.onRunStartGlobal += OnRunStart;
			Run.onRunDestroyGlobal += OnRunDestroyGlobal;
			Inventory.onInventoryChangedGlobal += OnInventoryChangedGlobal;
			RoR2Application.onFixedUpdate += StaticFixedUpdate;
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/SuppressedItemInventory", delegate(GameObject operationResult)
			{
				networkedInventoryPrefab = operationResult;
			});
		}

		public static bool HasItemBeenSuppressed(ItemIndex itemIndex)
		{
			return transformationMap.ContainsKey(itemIndex);
		}

		public static bool HasAnyItemBeenSuppressed()
		{
			return transformationMap.Count > 0;
		}

		public static bool SuppressItem(ItemIndex suppressedIndex, ItemIndex transformedIndex = ItemIndex.None)
		{
			if (!transformationMap.ContainsKey(suppressedIndex))
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(suppressedIndex);
				if ((bool)itemDef)
				{
					ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(itemDef.tier);
					ItemIndex itemIndex = ItemIndex.None;
					bool flag = false;
					if ((bool)itemTierDef)
					{
						switch (itemTierDef.tier)
						{
						case ItemTier.Tier3:
							itemIndex = DLC1Content.Items.ScrapRedSuppressed.itemIndex;
							flag = Run.instance.availableTier3DropList.Count == 1;
							break;
						case ItemTier.Tier2:
							itemIndex = DLC1Content.Items.ScrapGreenSuppressed.itemIndex;
							flag = Run.instance.availableTier2DropList.Count == 1;
							break;
						case ItemTier.Tier1:
							itemIndex = DLC1Content.Items.ScrapWhiteSuppressed.itemIndex;
							flag = Run.instance.availableTier1DropList.Count == 1;
							break;
						}
					}
					if (itemIndex != suppressedIndex)
					{
						PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(suppressedIndex);
						transformationMap.Add(suppressedIndex, transformedIndex);
						suppressedInventory.GiveItem(suppressedIndex);
						Run.instance.DisableItemDrop(suppressedIndex);
						if (flag)
						{
							Run.instance.EnableItemDrop(itemIndex);
						}
						if (transformedIndex != ItemIndex.None)
						{
							Inventory[] array = UnityEngine.Object.FindObjectsOfType<Inventory>();
							foreach (Inventory inventory in array)
							{
								if ((object)inventory != suppressedInventory)
								{
									TransformItem(inventory, suppressedIndex, transformedIndex);
								}
							}
						}
						ChestBehavior[] array2 = UnityEngine.Object.FindObjectsOfType<ChestBehavior>();
						foreach (ChestBehavior chestBehavior in array2)
						{
							if (chestBehavior.HasRolledPickup(pickupIndex))
							{
								chestBehavior.Roll();
							}
						}
						OptionChestBehavior[] array3 = UnityEngine.Object.FindObjectsOfType<OptionChestBehavior>();
						foreach (OptionChestBehavior optionChestBehavior in array3)
						{
							if (optionChestBehavior.HasRolledPickup(pickupIndex))
							{
								optionChestBehavior.Roll();
							}
						}
						ShopTerminalBehavior[] array4 = UnityEngine.Object.FindObjectsOfType<ShopTerminalBehavior>();
						foreach (ShopTerminalBehavior shopTerminalBehavior in array4)
						{
							if (shopTerminalBehavior.CurrentPickupIndex() == pickupIndex)
							{
								shopTerminalBehavior.GenerateNewPickupServer();
							}
						}
						VoidSuppressorBehavior[] array5 = UnityEngine.Object.FindObjectsOfType<VoidSuppressorBehavior>();
						for (int i = 0; i < array5.Length; i++)
						{
							array5[i].RefreshItems();
						}
						return true;
					}
				}
			}
			return false;
		}

		private static void OnRunStart(Run run)
		{
			if (NetworkServer.active)
			{
				transformationMap = new Dictionary<ItemIndex, ItemIndex>();
				suppressedInventory = UnityEngine.Object.Instantiate(networkedInventoryPrefab).GetComponent<Inventory>();
				NetworkServer.Spawn(suppressedInventory.gameObject);
			}
		}

		private static void OnRunDestroyGlobal(Run run)
		{
			if ((bool)suppressedInventory)
			{
				NetworkServer.Destroy(suppressedInventory.gameObject);
			}
			suppressedInventory = null;
		}

		private static void TransformItem(Inventory inventory, ItemIndex suppressedIndex, ItemIndex transformedIndex)
		{
			int itemCount = inventory.GetItemCount(suppressedIndex);
			if (itemCount > 0)
			{
				inventory.RemoveItem(suppressedIndex, itemCount);
				inventory.GiveItem(transformedIndex, itemCount);
				CharacterMaster component = inventory.GetComponent<CharacterMaster>();
				if ((bool)component)
				{
					CharacterMasterNotificationQueue.SendTransformNotification(component, suppressedIndex, transformedIndex, CharacterMasterNotificationQueue.TransformationType.Suppressed);
				}
			}
		}

		private static void StaticFixedUpdate()
		{
			foreach (Inventory pendingTransformationInventory in pendingTransformationInventories)
			{
				foreach (KeyValuePair<ItemIndex, ItemIndex> item in transformationMap)
				{
					if (item.Value != ItemIndex.None)
					{
						TransformItem(pendingTransformationInventory, item.Key, item.Value);
					}
				}
			}
			pendingTransformationInventories.Clear();
		}

		private static void OnInventoryChangedGlobal(Inventory inventory)
		{
			if ((object)inventory == suppressedInventory || pendingTransformationInventories.Contains(inventory))
			{
				return;
			}
			foreach (KeyValuePair<ItemIndex, ItemIndex> item in transformationMap)
			{
				if (item.Value != ItemIndex.None && inventory.GetItemCount(item.Key) > 0)
				{
					pendingTransformationInventories.Add(inventory);
					break;
				}
			}
		}
	}
	public class TeamSizeDamageBonusBodyBehavior : BaseItemBodyBehavior
	{
		[ItemDefAssociation(useOnServer = true, useOnClient = true)]
		private static ItemDef GetItemDef()
		{
			return RoR2Content.Items.TeamSizeDamageBonus;
		}

		private void OnJoinTeamGlobal(TeamComponent teamComponent, TeamIndex newTeamIndex)
		{
			if ((object)teamComponent == base.body.teamComponent || newTeamIndex == base.body.teamComponent.teamIndex)
			{
				base.body.MarkAllStatsDirty();
			}
		}

		private void OnLeaveTeamGlobal(TeamComponent teamComponent, TeamIndex oldTeamIndex)
		{
			if ((object)teamComponent == base.body.teamComponent || oldTeamIndex == base.body.teamComponent.teamIndex)
			{
				base.body.MarkAllStatsDirty();
			}
		}

		private void OnEnable()
		{
			TeamComponent.onJoinTeamGlobal += OnJoinTeamGlobal;
			TeamComponent.onLeaveTeamGlobal += OnLeaveTeamGlobal;
		}

		private void OnDisable()
		{
			TeamComponent.onJoinTeamGlobal -= OnJoinTeamGlobal;
			TeamComponent.onLeaveTeamGlobal -= OnLeaveTeamGlobal;
		}
	}
	public class UseAmbientLevelManager
	{
		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			Run.onRunAmbientLevelUp += OnRunAmbientLevelUp;
		}

		private static void OnRunAmbientLevelUp(Run run)
		{
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			int i = 0;
			for (int count = readOnlyInstancesList.Count; i < count; i++)
			{
				CharacterBody characterBody = readOnlyInstancesList[i];
				Inventory inventory = characterBody.inventory;
				if ((bool)inventory && inventory.GetItemCount(RoR2Content.Items.UseAmbientLevel) > 0)
				{
					characterBody.MarkAllStatsDirty();
				}
			}
		}
	}
	public class WarCryOnCombatBodyBehavior : BaseItemBodyBehavior
	{
		private static readonly float warCryChargeDuration = 30f;

		private float warCryTimer;

		private GameObject warCryAuraController;

		private bool wasOutOfCombat;

		[ItemDefAssociation(useOnServer = true, useOnClient = false)]
		private static ItemDef GetItemDef()
		{
			return JunkContent.Items.WarCryOnCombat;
		}

		private void OnEnable()
		{
			warCryTimer = warCryChargeDuration;
		}

		private void FixedUpdate()
		{
			warCryTimer -= Time.fixedDeltaTime;
			if (warCryTimer <= 0f && !base.body.outOfCombat && wasOutOfCombat)
			{
				warCryTimer = warCryChargeDuration;
				ActivateWarCryAura(stack);
			}
			wasOutOfCombat = base.body.outOfCombat;
		}

		private void ActivateWarCryAura(int stacks)
		{
			if ((bool)warCryAuraController)
			{
				UnityEngine.Object.Destroy(warCryAuraController);
			}
			warCryAuraController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/WarCryAura"), base.transform.position, base.transform.rotation, base.transform);
			warCryAuraController.GetComponent<TeamFilter>().teamIndex = base.body.teamComponent.teamIndex;
			BuffWard component = warCryAuraController.GetComponent<BuffWard>();
			component.expireDuration = 2f + 4f * (float)stacks;
			component.Networkradius = 8f + 4f * (float)stacks;
			warCryAuraController.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(base.gameObject);
		}
	}
	public static class WardOnLevelManager
	{
		private static GameObject wardPrefab;

		[SystemInitializer(new Type[] { typeof(ItemCatalog) })]
		private static void Init()
		{
			GlobalEventManager.onCharacterLevelUp += OnCharacterLevelUp;
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/WarbannerWard", delegate(GameObject operationResult)
			{
				wardPrefab = operationResult;
			});
		}

		private static void OnCharacterLevelUp(CharacterBody characterBody)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			Inventory inventory = characterBody.inventory;
			if ((bool)inventory)
			{
				int itemCount = inventory.GetItemCount(RoR2Content.Items.WardOnLevel);
				if (itemCount > 0)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(wardPrefab, characterBody.transform.position, UnityEngine.Quaternion.identity);
					gameObject.GetComponent<TeamFilter>().teamIndex = characterBody.teamComponent.teamIndex;
					gameObject.GetComponent<BuffWard>().Networkradius = 8f + 8f * (float)itemCount;
					NetworkServer.Spawn(gameObject);
				}
			}
		}
	}
}
namespace RoR2.HudOverlay
{
	public static class HudOverlayManager
	{
		private static Dictionary<GameObject, TargetTracker> targetToTargetTracker = new Dictionary<GameObject, TargetTracker>();

		private static List<OverlayController> globalOverlays = new List<OverlayController>();

		public static OverlayController AddOverlay(GameObject target, OverlayCreationParams overlayCreationParams)
		{
			if (target != null)
			{
				TargetTracker andIncrementTargetTracker = GetAndIncrementTargetTracker(target);
				OverlayController overlayController = new OverlayController(andIncrementTargetTracker, overlayCreationParams);
				andIncrementTargetTracker.AddOverlay(overlayController);
				return overlayController;
			}
			UnityEngine.Debug.LogError("AddOverlay can't be called with no target--did you mean to use AddGlobalOverlay?");
			return null;
		}

		public static void RemoveOverlay(OverlayController overlayController)
		{
			TargetTracker owner = overlayController.owner;
			if (owner != null)
			{
				owner.RemoveOverlay(overlayController);
				DecrementTargetTracker(owner);
			}
			else
			{
				UnityEngine.Debug.LogError("RemoveOverlay can't be called on an OverlayController with no target--did you mean to use RemoveGlobalOverlay?");
			}
		}

		public static OverlayController AddGlobalOverlay(OverlayCreationParams overlayCreationParams)
		{
			OverlayController overlayController = new OverlayController(null, overlayCreationParams);
			globalOverlays.Add(overlayController);
			return overlayController;
		}

		public static void RemoveGlobalOverlay(OverlayController overlayController)
		{
			if (overlayController.owner == null)
			{
				globalOverlays.Remove(overlayController);
			}
			else
			{
				UnityEngine.Debug.LogError("RemoveGlobalOverlay can't be called on an OverlayController with a target--did you mean to use RemoveOverlay?");
			}
		}

		public static void GetGlobalOverlayControllers(List<OverlayController> dest)
		{
			ListUtils.AddRange(dest, globalOverlays);
		}

		private static TargetTracker GetAndIncrementTargetTracker(GameObject target)
		{
			if (!targetToTargetTracker.TryGetValue(target, out var value))
			{
				value = CreateTargetTracker(target);
			}
			value.refCount++;
			return value;
		}

		private static void DecrementTargetTracker(TargetTracker targetTracker)
		{
			targetTracker.refCount--;
			if (targetTracker.refCount <= 0)
			{
				targetToTargetTracker.Remove(targetTracker.target);
				targetTracker.Dispose();
			}
		}

		private static TargetTracker CreateTargetTracker(GameObject target)
		{
			TargetTracker targetTracker = new TargetTracker
			{
				target = target
			};
			targetToTargetTracker.Add(target, targetTracker);
			return targetTracker;
		}

		public static TargetTracker GetTargetTracker(GameObject target)
		{
			if ((object)target != null && targetToTargetTracker.TryGetValue(target, out var value))
			{
				return value;
			}
			return null;
		}
	}
	public class HudOverlayViewer : MonoBehaviour
	{
		public HUD hud;

		public ChildLocator childLocator;

		private CameraRigController _cameraRigController;

		private GameObject _target;

		private AssociationList<OverlayController, GameObject> overlayControllerToInstance = new AssociationList<OverlayController, GameObject>();

		private CameraRigController cameraRigController
		{
			get
			{
				return _cameraRigController;
			}
			set
			{
				if ((object)_cameraRigController != value)
				{
					if ((object)_cameraRigController != null)
					{
						OnCameraRigControllerLost(_cameraRigController);
					}
					_cameraRigController = value;
					if ((object)_cameraRigController != null)
					{
						OnCameraRigControllerDiscovered(_cameraRigController);
					}
				}
			}
		}

		public GameObject target
		{
			get
			{
				return _target;
			}
			private set
			{
				if ((object)_target != value)
				{
					if ((object)_target != null)
					{
						OnTargetLost(_target);
					}
					_target = value;
					if ((object)_target != null)
					{
						OnTargetDiscovered(_target);
					}
				}
			}
		}

		public event Action<HudOverlayViewer, GameObject> onTargetDiscovered;

		public event Action<HudOverlayViewer, GameObject> onTargetLost;

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		private void OnDestroy()
		{
			target = null;
			cameraRigController = null;
			List<OverlayController> list = CollectionPool<OverlayController, List<OverlayController>>.RentCollection();
			SetOverlays(list);
			CollectionPool<OverlayController, List<OverlayController>>.ReturnCollection(list);
		}

		private void Update()
		{
			cameraRigController = (hud ? hud.cameraRigController : null);
			target = (cameraRigController ? cameraRigController.target : null);
			List<OverlayController> list = CollectionPool<OverlayController, List<OverlayController>>.RentCollection();
			HudOverlayManager.GetGlobalOverlayControllers(list);
			HudOverlayManager.GetTargetTracker(target)?.GetOverlayControllers(list);
			SetOverlays(list);
			CollectionPool<OverlayController, List<OverlayController>>.ReturnCollection(list);
		}

		private void OnCameraRigControllerDiscovered(CameraRigController cameraRigController)
		{
			target = cameraRigController.target;
		}

		private void OnCameraRigControllerLost(CameraRigController cameraRigController)
		{
			target = null;
		}

		private void OnTargetDiscovered(GameObject target)
		{
		}

		private void OnTargetLost(GameObject target)
		{
		}

		private void AddOverlay(OverlayController overlayController)
		{
			Transform transform = childLocator.FindChild(overlayController.creationParams.childLocatorEntry);
			if ((bool)transform)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(overlayController.creationParams.prefab, transform);
				overlayControllerToInstance[overlayController] = gameObject;
				overlayController.OnInstanceAdded(gameObject);
			}
		}

		private void RemoveOverlay(OverlayController overlayController)
		{
			if (overlayControllerToInstance.TryGetValue(overlayController, out var value))
			{
				overlayControllerToInstance.Remove(overlayController);
				overlayController.OnInstanceRemoved(value);
				UnityEngine.Object.Destroy(value);
			}
		}

		private void SetOverlays(List<OverlayController> newOverlayControllers)
		{
			List<OverlayController> list = CollectionPool<OverlayController, List<OverlayController>>.RentCollection();
			List<OverlayController> list2 = CollectionPool<OverlayController, List<OverlayController>>.RentCollection();
			for (int num = overlayControllerToInstance.Count - 1; num >= 0; num--)
			{
				OverlayController key = overlayControllerToInstance[num].Key;
				if (!newOverlayControllers.Contains(key))
				{
					list2.Add(key);
				}
			}
			for (int i = 0; i < newOverlayControllers.Count; i++)
			{
				OverlayController overlayController = newOverlayControllers[i];
				if (!overlayControllerToInstance.ContainsKey(overlayController))
				{
					list.Add(overlayController);
				}
			}
			foreach (OverlayController item in list2)
			{
				RemoveOverlay(item);
			}
			foreach (OverlayController item2 in list)
			{
				AddOverlay(item2);
			}
			CollectionPool<OverlayController, List<OverlayController>>.ReturnCollection(list2);
			CollectionPool<OverlayController, List<OverlayController>>.ReturnCollection(list);
		}
	}
	public class OverlayController
	{
		public readonly TargetTracker owner;

		public readonly OverlayCreationParams creationParams;

		private readonly List<GameObject> _instancesList = new List<GameObject>();

		private bool _active = true;

		private float _alpha = 1f;

		public IReadOnlyList<GameObject> instancesList => _instancesList;

		public bool active
		{
			get
			{
				return _active;
			}
			set
			{
				if (_active == value)
				{
					return;
				}
				_active = value;
				foreach (GameObject instances in _instancesList)
				{
					instances.SetActive(_active);
				}
			}
		}

		public float alpha
		{
			get
			{
				return _alpha;
			}
			set
			{
				if (_alpha.Equals(value))
				{
					return;
				}
				_alpha = value;
				foreach (GameObject instances in _instancesList)
				{
					PushAlphaToInstance(instances);
				}
			}
		}

		public event Action<OverlayController, GameObject> onInstanceAdded;

		public event Action<OverlayController, GameObject> onInstanceRemove;

		public OverlayController(TargetTracker owner, OverlayCreationParams creationParams)
		{
			this.owner = owner;
			this.creationParams = creationParams;
		}

		public void OnInstanceAdded(GameObject instance)
		{
			_instancesList.Add(instance);
			try
			{
				this.onInstanceAdded?.Invoke(this, instance);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			instance.SetActive(active);
			PushAlphaToInstance(instance);
		}

		public void OnInstanceRemoved(GameObject instance)
		{
			try
			{
				this.onInstanceRemove?.Invoke(this, instance);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			_instancesList.Remove(instance);
		}

		private void PushAlphaToInstance(GameObject instance)
		{
			CanvasGroup component = instance.GetComponent<CanvasGroup>();
			if ((bool)component)
			{
				component.alpha = alpha;
			}
		}
	}
	public struct OverlayCreationParams
	{
		public GameObject prefab;

		public string childLocatorEntry;
	}
	public class TargetTracker : IDisposable
	{
		public GameObject target;

		public int refCount;

		private List<OverlayController> overlayControllers;

		private bool disposed;

		public TargetTracker()
		{
			overlayControllers = CollectionPool<OverlayController, List<OverlayController>>.RentCollection();
		}

		public void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				while (overlayControllers.Count > 0)
				{
					RemoveOverlayAt(overlayControllers.Count - 1);
				}
				overlayControllers = CollectionPool<OverlayController, List<OverlayController>>.ReturnCollection(overlayControllers);
			}
		}

		public void AddOverlay(OverlayController overlayController)
		{
			overlayControllers.Add(overlayController);
		}

		public void RemoveOverlay(OverlayController overlayController)
		{
			int i = overlayControllers.IndexOf(overlayController);
			RemoveOverlayAt(i);
		}

		private void RemoveOverlayAt(int i)
		{
			overlayControllers.RemoveAt(i);
		}

		public void GetOverlayControllers(List<OverlayController> dest)
		{
			ListUtils.AddRange(dest, overlayControllers);
		}
	}
}
namespace RoR2.Hologram
{
	public class HologramProjector : MonoBehaviour
	{
		[Tooltip("The range in meters at which the hologram begins to display.")]
		public float displayDistance = 15f;

		[Tooltip("The position at which to display the hologram.")]
		public Transform hologramPivot;

		[Tooltip("Whether or not the hologram will pivot to the player")]
		public bool disableHologramRotation;

		private float transformDampVelocity;

		private IHologramContentProvider contentProvider;

		private float viewerReselectTimer;

		private float viewerReselectInterval = 0.25f;

		private Transform cachedViewer;

		private CharacterBody cachedViewerBody;

		private NetworkInstanceId cachedViewerObjectId;

		private NetworkIdentity cachedNetworkIdentity;

		public GameObject hologramContentInstance;

		private Transform viewerTransform;

		private CharacterBody viewerBody;

		private void Awake()
		{
			contentProvider = GetComponent<IHologramContentProvider>();
			cachedNetworkIdentity = GetComponent<NetworkIdentity>();
		}

		private Transform FindViewer(UnityEngine.Vector3 position)
		{
			if (viewerReselectTimer > 0f)
			{
				return cachedViewer;
			}
			viewerReselectTimer = viewerReselectInterval;
			cachedViewer = null;
			float num = float.PositiveInfinity;
			ReadOnlyCollection<PlayerCharacterMasterController> instances = PlayerCharacterMasterController.instances;
			int i = 0;
			for (int count = instances.Count; i < count; i++)
			{
				GameObject bodyObject = instances[i].master.GetBodyObject();
				if ((bool)bodyObject)
				{
					float sqrMagnitude = (bodyObject.transform.position - position).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						cachedViewer = bodyObject.transform;
						cachedViewerBody = bodyObject.GetComponent<CharacterBody>();
					}
				}
			}
			return cachedViewer;
		}

		private void CacheViewerBody(Transform _viewer)
		{
			if (!(_viewer == null) && (!viewerBody || !(viewerTransform == _viewer)) && _viewer.TryGetComponent<CharacterBody>(out var component))
			{
				viewerTransform = _viewer;
				viewerBody = component;
			}
		}

		public UnityEngine.Vector3 GetHologramPivotPosition()
		{
			if (!hologramPivot)
			{
				return base.transform.position;
			}
			return hologramPivot.position;
		}

		public CharacterBody GetCachedViewerBody()
		{
			return cachedViewerBody;
		}

		public NetworkInstanceId GetCachedViewerObjectId()
		{
			return cachedViewerObjectId;
		}

		public void UpdateForViewer(Transform viewer, UnityEngine.Vector3 pivotPosition)
		{
			bool flag = false;
			UnityEngine.Vector3 vector = (viewer ? viewer.position : base.transform.position);
			UnityEngine.Vector3 forward = UnityEngine.Vector3.zero;
			if ((bool)viewer)
			{
				forward = pivotPosition - vector;
				if (forward.sqrMagnitude <= displayDistance * displayDistance)
				{
					flag = true;
				}
			}
			if (flag)
			{
				flag = contentProvider.ShouldDisplayHologram(viewer.gameObject);
			}
			if (flag)
			{
				if (!hologramContentInstance)
				{
					BuildHologram();
				}
				if ((bool)hologramContentInstance && contentProvider != null)
				{
					contentProvider.UpdateHologramContent(hologramContentInstance, viewer);
					if (!disableHologramRotation)
					{
						hologramContentInstance.transform.rotation = Util.SmoothDampQuaternion(hologramContentInstance.transform.rotation, Util.QuaternionSafeLookRotation(forward), ref transformDampVelocity, 0.2f);
					}
				}
			}
			else
			{
				DestroyHologram();
			}
		}

		private void Update()
		{
			viewerReselectTimer -= Time.deltaTime;
			UnityEngine.Vector3 hologramPivotPosition = GetHologramPivotPosition();
			Transform viewer = FindViewer(hologramPivotPosition);
			UpdateForViewer(viewer, hologramPivotPosition);
		}

		private void BuildHologram()
		{
			DestroyHologram();
			if (contentProvider == null)
			{
				return;
			}
			GameObject hologramContentPrefab = contentProvider.GetHologramContentPrefab();
			if ((bool)hologramContentPrefab)
			{
				hologramContentInstance = UnityEngine.Object.Instantiate(hologramContentPrefab);
				hologramContentInstance.transform.parent = (hologramPivot ? hologramPivot : base.transform);
				hologramContentInstance.transform.localPosition = UnityEngine.Vector3.zero;
				hologramContentInstance.transform.localRotation = UnityEngine.Quaternion.identity;
				hologramContentInstance.transform.localScale = UnityEngine.Vector3.one;
				if ((bool)viewerTransform && !disableHologramRotation)
				{
					UnityEngine.Vector3 obj = (hologramPivot ? hologramPivot.position : base.transform.position);
					_ = viewerTransform.position;
					UnityEngine.Vector3 forward = obj - viewerTransform.position;
					hologramContentInstance.transform.rotation = Util.QuaternionSafeLookRotation(forward);
				}
				contentProvider.UpdateHologramContent(hologramContentInstance, viewerTransform);
			}
		}

		private void DestroyHologram()
		{
			if ((bool)hologramContentInstance)
			{
				UnityEngine.Object.Destroy(hologramContentInstance);
			}
			hologramContentInstance = null;
		}
	}
}
namespace RoR2.DispatachableEffects
{
	[RequireComponent(typeof(EffectComponent))]
	[RequireComponent(typeof(TemporaryOverlay))]
	public class AddOverlayToReferencedObject : MonoBehaviour
	{
		public bool effectDataGenericFloatOverridesDuration = true;

		protected void Start()
		{
			EffectComponent component = GetComponent<EffectComponent>();
			ApplyOverlay(component.GetReferencedObject(), component.effectData.genericFloat);
		}

		protected void ApplyOverlay(GameObject targetObject, float duration)
		{
			if (!targetObject)
			{
				return;
			}
			ModelLocator component = targetObject.GetComponent<ModelLocator>();
			if (!component)
			{
				return;
			}
			Transform modelTransform = component.modelTransform;
			if (!modelTransform)
			{
				return;
			}
			CharacterModel component2 = modelTransform.GetComponent<CharacterModel>();
			if ((bool)component2)
			{
				TemporaryOverlay component3 = GetComponent<TemporaryOverlay>();
				if ((bool)component3)
				{
					component3.AddToCharacerModel(component2);
				}
				if (effectDataGenericFloatOverridesDuration)
				{
					component3.durationInstance = duration;
				}
			}
		}
	}
}
namespace RoR2.CharacterSpeech
{
	[RequireComponent(typeof(CharacterSpeechController))]
	public class BaseCharacterSpeechDriver : MonoBehaviour
	{
		protected CharacterSpeechController characterSpeechController { get; private set; }

		protected CharacterBody currentCharacterBody { get; private set; }

		protected void Awake()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
			}
			else
			{
				characterSpeechController = GetComponent<CharacterSpeechController>();
			}
		}

		protected void OnEnable()
		{
			if (NetworkServer.active)
			{
				characterSpeechController.onCharacterBodyDiscovered += OnCharacterBodyDiscovered;
				characterSpeechController.onCharacterBodyLost += OnCharacterBodyLost;
				if ((object)characterSpeechController.currentCharacterBody != null)
				{
					OnCharacterBodyDiscovered(characterSpeechController.currentCharacterBody);
				}
			}
		}

		protected void OnDisable()
		{
			if (NetworkServer.active)
			{
				if ((object)currentCharacterBody != null)
				{
					OnCharacterBodyLost(currentCharacterBody);
				}
				characterSpeechController.onCharacterBodyLost -= OnCharacterBodyLost;
				characterSpeechController.onCharacterBodyDiscovered -= OnCharacterBodyDiscovered;
			}
		}

		protected void OnDestroy()
		{
			_ = NetworkServer.active;
		}

		protected virtual void OnCharacterBodyDiscovered(CharacterBody characterBody)
		{
			currentCharacterBody = characterBody;
		}

		protected virtual void OnCharacterBodyLost(CharacterBody characterBody)
		{
			currentCharacterBody = null;
		}
	}
	[RequireComponent(typeof(CharacterSpeechController))]
	[RequireComponent(typeof(SimpleCombatSpeechDriver))]
	public class BrotherSpeechDriver : BaseCharacterSpeechDriver
	{
		public CharacterSpeechController.SpeechInfo[] seeHereticResponses;

		public CharacterSpeechController.SpeechInfo[] seeTitanGoldResponses;

		public CharacterSpeechController.SpeechInfo[] seeHereticAndTitanGoldResponses;

		public CharacterSpeechController.SpeechInfo[] killMechanicalResponses;

		public CharacterSpeechController.SpeechInfo[] killHereticResponses;

		public CharacterSpeechController.SpeechInfo[] killTitanGoldReponses;

		public UnityEvent onTitanGoldSighted;

		private SimpleCombatSpeechDriver simpleCombatSpeechDriver;

		private static BodyIndex hereticBodyIndex = BodyIndex.None;

		private static BodyIndex titanGoldBodyIndex = BodyIndex.None;

		[SystemInitializer(new Type[] { typeof(BodyCatalog) })]
		private static void Init()
		{
			hereticBodyIndex = BodyCatalog.FindBodyIndex("HereticBody");
			titanGoldBodyIndex = BodyCatalog.FindBodyIndex("TitanGoldBody");
		}

		protected new void Awake()
		{
			base.Awake();
			if (NetworkServer.active)
			{
				simpleCombatSpeechDriver = GetComponent<SimpleCombatSpeechDriver>();
				simpleCombatSpeechDriver.onBodyKill.AddListener(OnBodyKill);
				CharacterBody.onBodyStartGlobal += OnCharacterBodyStartGlobal;
			}
		}

		protected new void OnDestroy()
		{
			CharacterBody.onBodyStartGlobal -= OnCharacterBodyStartGlobal;
			base.OnDestroy();
		}

		private void OnCharacterBodyStartGlobal(CharacterBody characterBody)
		{
			if (characterBody.bodyIndex == titanGoldBodyIndex)
			{
				onTitanGoldSighted?.Invoke();
			}
		}

		public void DoInitialSightResponse()
		{
			bool flag = false;
			bool flag2 = false;
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				BodyIndex bodyIndex = readOnlyInstancesList[i].bodyIndex;
				flag |= bodyIndex == hereticBodyIndex;
				flag2 |= bodyIndex == titanGoldBodyIndex;
			}
			CharacterSpeechController.SpeechInfo[] responsePool = Array.Empty<CharacterSpeechController.SpeechInfo>();
			if (flag && flag2)
			{
				TrySetResponsePool(seeHereticAndTitanGoldResponses);
			}
			if (flag)
			{
				TrySetResponsePool(seeHereticResponses);
			}
			if (flag2)
			{
				TrySetResponsePool(seeTitanGoldResponses);
			}
			SendReponseFromPool(responsePool);
			void TrySetResponsePool(CharacterSpeechController.SpeechInfo[] newResponsePool)
			{
				if (responsePool.Length == 0)
				{
					responsePool = newResponsePool;
				}
			}
		}

		private void OnBodyKill(DamageReport damageReport)
		{
			CharacterSpeechController.SpeechInfo[] responsePool;
			if ((bool)damageReport.victimBody)
			{
				responsePool = Array.Empty<CharacterSpeechController.SpeechInfo>();
				if (damageReport.victimBodyIndex == hereticBodyIndex)
				{
					TrySetResponsePool(killHereticResponses);
				}
				else if (damageReport.victimBodyIndex == titanGoldBodyIndex)
				{
					TrySetResponsePool(killTitanGoldReponses);
				}
				else if ((damageReport.victimBody.bodyFlags &= CharacterBody.BodyFlags.Mechanical) == CharacterBody.BodyFlags.Mechanical && killMechanicalResponses.Length != 0)
				{
					TrySetResponsePool(killMechanicalResponses);
				}
				SendReponseFromPool(responsePool);
			}
			void TrySetResponsePool(CharacterSpeechController.SpeechInfo[] newResponsePool)
			{
				if (responsePool.Length == 0)
				{
					responsePool = newResponsePool;
				}
			}
		}

		private void SendReponseFromPool(CharacterSpeechController.SpeechInfo[] responsePool)
		{
			if (responsePool.Length != 0)
			{
				base.characterSpeechController.EnqueueSpeech(in responsePool[UnityEngine.Random.Range(0, responsePool.Length - 1)]);
			}
		}
	}
	public class CharacterSpeechController : MonoBehaviour
	{
		[Serializable]
		public struct SpeechInfo
		{
			public string token;

			public float duration;

			public float maxWait;

			public float priority;

			public bool mustPlay;

			public override string ToString()
			{
				return $"{{ token=\"{token}\" duration={duration} maxWait={maxWait} priority={priority} mustPlay={mustPlay} }}";
			}
		}

		[Serializable]
		private struct SpeechRequest
		{
			public SpeechInfo speechInfo;

			public float submitTime;

			public override string ToString()
			{
				return $"{{ speechInfo={speechInfo} submitTime={submitTime} }}";
			}
		}

		public CharacterMaster initialCharacterMaster;

		public string chatFormatToken;

		private float localTime;

		private float nextSpeakTime;

		private List<SpeechRequest> speechRequestQueue;

		private CharacterMaster _characterMaster;

		private CharacterBody _currentCharacterBody;

		private static readonly BoolConVar cvEnableLogging = new BoolConVar("character_speech_debug", ConVarFlags.None, "0", "Enables/disables debug logging for CharacterSpeechController");

		public CharacterMaster characterMaster
		{
			get
			{
				return _characterMaster;
			}
			set
			{
				if ((object)_characterMaster != value)
				{
					if ((object)_characterMaster != null)
					{
						OnCharacterMasterLost(_characterMaster);
					}
					_characterMaster = value;
					if ((object)_characterMaster != null)
					{
						OnCharacterMasterDiscovered(_characterMaster);
					}
				}
			}
		}

		public CharacterBody currentCharacterBody
		{
			get
			{
				return _currentCharacterBody;
			}
			private set
			{
				if ((object)_currentCharacterBody != value)
				{
					if ((object)_currentCharacterBody != null)
					{
						OnCharacterBodyLost(_currentCharacterBody);
					}
					_currentCharacterBody = value;
					if ((object)_currentCharacterBody != null)
					{
						OnCharacterBodyDiscovered(_currentCharacterBody);
					}
				}
			}
		}

		public event Action<CharacterMaster> onCharacterMasterDiscovered;

		public event Action<CharacterMaster> onCharacterMasterLost;

		public event Action<CharacterBody> onCharacterBodyDiscovered;

		public event Action<CharacterBody> onCharacterBodyLost;

		private void Awake()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
			}
			else
			{
				speechRequestQueue = new List<SpeechRequest>();
			}
		}

		private void Start()
		{
			if ((object)characterMaster == null)
			{
				characterMaster = initialCharacterMaster;
			}
		}

		private void FixedUpdate()
		{
			Process(Time.fixedDeltaTime);
		}

		private void OnDestroy()
		{
			if (NetworkServer.active)
			{
				characterMaster = null;
			}
		}

		public void SpeakNow(in SpeechInfo speechInfo)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			if (cvEnableLogging.value)
			{
				Log($"Playing speech: {speechInfo}");
			}
			nextSpeakTime = localTime + speechInfo.duration;
			CharacterBody characterBody = null;
			GameObject sender = null;
			SfxLocator sfxLocator = null;
			if ((bool)characterMaster)
			{
				characterBody = characterMaster.GetBody();
				if ((bool)characterBody)
				{
					sfxLocator = characterBody.GetComponent<SfxLocator>();
				}
			}
			Chat.SendBroadcastChat(new Chat.NpcChatMessage
			{
				baseToken = speechInfo.token,
				formatStringToken = chatFormatToken,
				sender = sender,
				sound = sfxLocator?.barkSound
			});
		}

		public void EnqueueSpeech(in SpeechInfo speechInfo)
		{
			if (NetworkServer.active)
			{
				SpeechRequest speechRequest = default(SpeechRequest);
				speechRequest.speechInfo = speechInfo;
				speechRequest.submitTime = localTime;
				SpeechRequest speechRequest2 = speechRequest;
				speechRequestQueue.Add(speechRequest2);
				if (cvEnableLogging.value)
				{
					Log($"Enqueued speech: {speechRequest2}");
				}
			}
		}

		private void Process(float deltaTime)
		{
			localTime += deltaTime;
			if (!(nextSpeakTime <= localTime))
			{
				return;
			}
			int bestNextRequestIndex = GetBestNextRequestIndex();
			if (bestNextRequestIndex == -1)
			{
				return;
			}
			SpeechRequest speechRequest = speechRequestQueue[bestNextRequestIndex];
			if (cvEnableLogging.value)
			{
				Log($"Found best request: bestNextRequestIndex={bestNextRequestIndex} bestNextRequest={speechRequest}");
				for (int i = 0; i < bestNextRequestIndex; i++)
				{
					Log($"Dropping request: i={i} request={speechRequestQueue[i]}");
				}
			}
			speechRequestQueue.RemoveRange(0, bestNextRequestIndex + 1);
			SpeakNow(in speechRequest.speechInfo);
		}

		private int GetBestNextRequestIndex()
		{
			if (speechRequestQueue.Count == 0)
			{
				return -1;
			}
			for (int i = 0; i < speechRequestQueue.Count; i++)
			{
				SpeechRequest speechRequest = speechRequestQueue[i];
				SpeechInfo speechInfo = speechRequest.speechInfo;
				if (speechInfo.mustPlay)
				{
					return i;
				}
				float num = speechRequest.submitTime + speechInfo.maxWait;
				if (localTime > num)
				{
					continue;
				}
				float num2 = localTime + speechInfo.duration;
				bool flag = false;
				for (int j = i + 1; j < speechRequestQueue.Count; j++)
				{
					SpeechRequest speechRequest2 = speechRequestQueue[j];
					SpeechInfo speechInfo2 = speechRequest2.speechInfo;
					if (!(speechInfo.priority >= speechInfo2.priority) || speechInfo2.mustPlay)
					{
						if (speechRequest2.submitTime + speechInfo2.maxWait < num2)
						{
							flag = true;
							break;
						}
						num2 += speechInfo2.duration;
					}
				}
				if (!flag)
				{
					return i;
				}
			}
			return -1;
		}

		private void OnCharacterMasterDiscovered(CharacterMaster characterMaster)
		{
			characterMaster.onBodyStart += OnCharacterMasterBodyStart;
			this.onCharacterMasterDiscovered?.Invoke(characterMaster);
			currentCharacterBody = characterMaster.GetBody();
		}

		private void OnCharacterMasterLost(CharacterMaster characterMaster)
		{
			currentCharacterBody = null;
			this.onCharacterMasterLost?.Invoke(characterMaster);
			characterMaster.onBodyDestroyed -= OnCharacterMasterBodyDestroyed;
		}

		private void OnCharacterMasterBodyStart(CharacterBody characterBody)
		{
			currentCharacterBody = characterBody;
		}

		private void OnCharacterMasterBodyDestroyed(CharacterBody characterBody)
		{
			if ((object)characterBody == currentCharacterBody)
			{
				currentCharacterBody = null;
			}
		}

		private void OnCharacterBodyDiscovered(CharacterBody characterBody)
		{
			this.onCharacterBodyDiscovered?.Invoke(characterBody);
		}

		private void OnCharacterBodyLost(CharacterBody characterBody)
		{
			this.onCharacterBodyLost?.Invoke(characterBody);
		}

		private void Log(string str)
		{
		}
	}
	[RequireComponent(typeof(CharacterSpeechController))]
	[RequireComponent(typeof(SimpleCombatSpeechDriver))]
	public class FalseSonBossSpeechDriver : BaseCharacterSpeechDriver
	{
		public CharacterSpeechController.SpeechInfo[] seeHereticResponses;

		public CharacterSpeechController.SpeechInfo[] seeTitanGoldResponses;

		public CharacterSpeechController.SpeechInfo[] seeHereticAndTitanGoldResponses;

		public CharacterSpeechController.SpeechInfo[] killMechanicalResponses;

		public CharacterSpeechController.SpeechInfo[] killHereticResponses;

		public CharacterSpeechController.SpeechInfo[] killTitanGoldReponses;

		public CharacterSpeechController.SpeechInfo[] killPlayerWithLightningResponses;

		public CharacterSpeechController.SpeechInfo[] purifyFalseSonResponses;

		public UnityEvent onTitanGoldSighted;

		private SimpleCombatSpeechDriver simpleCombatSpeechDriver;

		private static BodyIndex hereticBodyIndex = BodyIndex.None;

		private static BodyIndex titanGoldBodyIndex = BodyIndex.None;

		[SystemInitializer(new Type[] { typeof(BodyCatalog) })]
		private static void Init()
		{
			hereticBodyIndex = BodyCatalog.FindBodyIndex("HereticBody");
			titanGoldBodyIndex = BodyCatalog.FindBodyIndex("TitanGoldBody");
		}

		protected new void Awake()
		{
			base.Awake();
			if (NetworkServer.active)
			{
				simpleCombatSpeechDriver = GetComponent<SimpleCombatSpeechDriver>();
				simpleCombatSpeechDriver.onBodyKill.AddListener(OnBodyKill);
				simpleCombatSpeechDriver.onBossAllyDeath.AddListener(OnBossAllyDeath);
				CharacterBody.onBodyStartGlobal += OnCharacterBodyStartGlobal;
				SkyJumpDeathState.falseSonUnlockEvent += FalseSonPurifiedResponse;
			}
		}

		protected new void OnDestroy()
		{
			CharacterBody.onBodyStartGlobal -= OnCharacterBodyStartGlobal;
			SkyJumpDeathState.falseSonUnlockEvent -= FalseSonPurifiedResponse;
			base.OnDestroy();
		}

		private void OnCharacterBodyStartGlobal(CharacterBody characterBody)
		{
			if (characterBody.bodyIndex == titanGoldBodyIndex)
			{
				onTitanGoldSighted?.Invoke();
			}
		}

		public void DoInitialSightResponse()
		{
			bool flag = false;
			bool flag2 = false;
			ReadOnlyCollection<CharacterBody> readOnlyInstancesList = CharacterBody.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				BodyIndex bodyIndex = readOnlyInstancesList[i].bodyIndex;
				flag |= bodyIndex == hereticBodyIndex;
				flag2 |= bodyIndex == titanGoldBodyIndex;
			}
			CharacterSpeechController.SpeechInfo[] responsePool = Array.Empty<CharacterSpeechController.SpeechInfo>();
			if (flag && flag2)
			{
				TrySetResponsePool(seeHereticAndTitanGoldResponses);
			}
			if (flag)
			{
				TrySetResponsePool(seeHereticResponses);
			}
			if (flag2)
			{
				TrySetResponsePool(seeTitanGoldResponses);
			}
			SendReponseFromPool(responsePool);
			void TrySetResponsePool(CharacterSpeechController.SpeechInfo[] newResponsePool)
			{
				if (responsePool.Length == 0)
				{
					responsePool = newResponsePool;
				}
			}
		}

		private void OnBodyKill(DamageReport damageReport)
		{
			if (!damageReport.victimBody)
			{
				return;
			}
			CharacterSpeechController.SpeechInfo[] responsePool = Array.Empty<CharacterSpeechController.SpeechInfo>();
			if (damageReport.victimBodyIndex == hereticBodyIndex)
			{
				TrySetResponsePool(killHereticResponses);
			}
			else if ((damageReport.victimBody.bodyFlags &= CharacterBody.BodyFlags.Mechanical) == CharacterBody.BodyFlags.Mechanical)
			{
				if (killMechanicalResponses.Length != 0)
				{
					TrySetResponsePool(killMechanicalResponses);
				}
			}
			else if ((ulong)(damageReport.damageInfo.damageType & DamageType.LunarRuin) != 0 && damageReport.attacker == null)
			{
				TrySetResponsePool(killPlayerWithLightningResponses);
			}
			SendReponseFromPool(responsePool);
			void TrySetResponsePool(CharacterSpeechController.SpeechInfo[] newResponsePool)
			{
				if (responsePool.Length == 0)
				{
					responsePool = newResponsePool;
				}
			}
		}

		private void OnBossAllyDeath(DamageReport damageReport)
		{
			CharacterSpeechController.SpeechInfo[] responsePool;
			if ((bool)damageReport.victimBody)
			{
				responsePool = Array.Empty<CharacterSpeechController.SpeechInfo>();
				if (damageReport.victimBodyIndex == titanGoldBodyIndex)
				{
					TrySetResponsePool(killTitanGoldReponses);
				}
				SendReponseFromPool(responsePool);
			}
			void TrySetResponsePool(CharacterSpeechController.SpeechInfo[] newResponsePool)
			{
				if (responsePool.Length == 0)
				{
					responsePool = newResponsePool;
				}
			}
		}

		private void FalseSonPurifiedResponse()
		{
			CharacterSpeechController.SpeechInfo[] responsePool = Array.Empty<CharacterSpeechController.SpeechInfo>();
			TrySetResponsePool(purifyFalseSonResponses);
			SendReponseFromPool(responsePool);
			void TrySetResponsePool(CharacterSpeechController.SpeechInfo[] newResponsePool)
			{
				if (responsePool.Length == 0)
				{
					responsePool = newResponsePool;
				}
			}
		}

		private void SendReponseFromPool(CharacterSpeechController.SpeechInfo[] responsePool)
		{
			if (responsePool.Length != 0)
			{
				base.characterSpeechController.EnqueueSpeech(in responsePool[UnityEngine.Random.Range(0, responsePool.Length - 1)]);
			}
		}
	}
	[RequireComponent(typeof(CharacterSpeechController))]
	public class SimpleCombatSpeechDriver : BaseCharacterSpeechDriver
	{
		[Serializable]
		public struct SpeechCategory
		{
			public string refName;

			public float chanceToTrigger;

			public SpeechInfo[] speechInfos;

			public WeightedSelection<SpeechInfo> speechSelection;
		}

		[Serializable]
		public struct SpeechInfo
		{
			public string nameToken;

			public float weight;
		}

		[Header("Speech Info")]
		public float minimumDurationBetweenSpeech;

		public bool removeRepeats;

		[SerializeField]
		public SpeechCategory[] speechCategories;

		[Tooltip("The refname to automatically submit speech for when damage is dealt.")]
		public string damageDealtRefName;

		[Header("Combat Parameters")]
		public bool scaleChanceOnDamageDealtByHealthFractionDealt = true;

		public float scaleChanceOnDamageDealtMultiplier = 1f;

		[Header("Events")]
		public DamageReportUnityEvent onBodyDamageDealt;

		public UnityEvent onStart;

		public DamageReportUnityEvent onBodyKill;

		public DamageReportUnityEvent onBodyDeath;

		public DamageReportUnityEvent onBossAllyDeath;

		private float lastSpeechStopwatch = float.PositiveInfinity;

		protected new void Awake()
		{
			base.Awake();
		}

		protected void Start()
		{
			if (NetworkServer.active)
			{
				Initialize();
				onStart?.Invoke();
			}
		}

		protected new void OnDestroy()
		{
			base.OnDestroy();
		}

		protected void FixedUpdate()
		{
			lastSpeechStopwatch += Time.fixedDeltaTime;
		}

		public void TriggerSpeech(string refName)
		{
			if (lastSpeechStopwatch < minimumDurationBetweenSpeech)
			{
				return;
			}
			int num = FindSpeechCategoryIndexByName(refName);
			if (num == -1)
			{
				UnityEngine.Debug.LogWarningFormat("Speech category \"{0}\" could not be found.", refName);
				return;
			}
			ref SpeechCategory reference = ref speechCategories[num];
			if (UnityEngine.Random.value < reference.chanceToTrigger)
			{
				SubmitSpeechRequestFromCategory(ref reference);
			}
		}

		private void SubmitSpeechRequestFromCategory(ref SpeechCategory category)
		{
			if (category.speechSelection == null || category.speechSelection.Count <= 0)
			{
				if (category.speechInfos.Length == 0)
				{
					return;
				}
				InitializeCategory(ref category);
			}
			int num = category.speechSelection.EvaluateToChoiceIndex(UnityEngine.Random.value);
			SpeechInfo value = category.speechSelection.GetChoice(num).value;
			if (removeRepeats)
			{
				category.speechSelection.RemoveChoice(num);
			}
			lastSpeechStopwatch = 0f;
			CharacterSpeechController obj = base.characterSpeechController;
			CharacterSpeechController.SpeechInfo speechInfo = new CharacterSpeechController.SpeechInfo
			{
				token = value.nameToken,
				duration = minimumDurationBetweenSpeech,
				maxWait = minimumDurationBetweenSpeech,
				mustPlay = false
			};
			obj.EnqueueSpeech(in speechInfo);
		}

		private int FindSpeechCategoryIndexByName(string refName)
		{
			for (int i = 0; i < speechCategories.Length; i++)
			{
				if (string.Equals(speechCategories[i].refName, refName, StringComparison.Ordinal))
				{
					return i;
				}
			}
			return -1;
		}

		private void Initialize()
		{
			for (int i = 0; i < speechCategories.Length; i++)
			{
				InitializeCategory(ref speechCategories[i]);
			}
		}

		private void InitializeCategory(ref SpeechCategory speechCategory)
		{
			WeightedSelection<SpeechInfo> weightedSelection = new WeightedSelection<SpeechInfo>();
			for (int i = 0; i < speechCategory.speechInfos.Length; i++)
			{
				SpeechInfo value = speechCategory.speechInfos[i];
				weightedSelection.AddChoice(value, value.weight);
			}
			speechCategory.speechSelection = weightedSelection;
		}

		protected override void OnCharacterBodyDiscovered(CharacterBody characterBody)
		{
			base.OnCharacterBodyDiscovered(characterBody);
			GlobalEventManager.onServerDamageDealt += OnServerDamageDealt;
			GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
		}

		protected override void OnCharacterBodyLost(CharacterBody characterBody)
		{
			GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
			GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt;
			base.OnCharacterBodyLost(characterBody);
		}

		private void OnServerDamageDealt(DamageReport damageReport)
		{
			if ((object)damageReport.attackerBody == base.currentCharacterBody)
			{
				OnBodyDamageDealt(damageReport);
			}
			if ((object)damageReport.victimBody == base.currentCharacterBody)
			{
				OnBodyDamageTaken(damageReport);
			}
		}

		private void OnCharacterDeathGlobal(DamageReport damageReport)
		{
			CharacterBody characterBody = base.currentCharacterBody;
			if (!(characterBody == null))
			{
				if ((object)damageReport.attackerBody == characterBody)
				{
					OnBodyKill(damageReport);
				}
				if ((object)damageReport.victimBody == characterBody)
				{
					OnBodyDeath(damageReport);
				}
				else if (damageReport.victimBody.teamComponent.teamIndex == characterBody.teamComponent.teamIndex)
				{
					OnBossAllyDeath(damageReport);
				}
			}
		}

		private void OnBodyDamageDealt(DamageReport damageReport)
		{
			if (scaleChanceOnDamageDealtByHealthFractionDealt && (bool)damageReport.victim && !string.IsNullOrEmpty(damageDealtRefName))
			{
				int num = FindSpeechCategoryIndexByName(damageDealtRefName);
				if (num == -1)
				{
					UnityEngine.Debug.LogWarningFormat("Speech category \"{0}\" could not be found.", damageDealtRefName);
				}
				else
				{
					ref SpeechCategory reference = ref speechCategories[num];
					float num2 = reference.chanceToTrigger;
					if (scaleChanceOnDamageDealtByHealthFractionDealt)
					{
						float fullCombinedHealth = damageReport.victim.fullCombinedHealth;
						float num3 = damageReport.damageDealt / fullCombinedHealth;
						num2 *= num3;
					}
					num2 *= scaleChanceOnDamageDealtMultiplier;
					if (UnityEngine.Random.value < num2)
					{
						SubmitSpeechRequestFromCategory(ref reference);
					}
				}
			}
			onBodyDamageDealt?.Invoke(damageReport);
		}

		private void OnBodyDamageTaken(DamageReport damageReport)
		{
		}

		private void OnBodyKill(DamageReport damageReport)
		{
			onBodyKill?.Invoke(damageReport);
		}

		private void OnBodyDeath(DamageReport damageReport)
		{
			onBodyDeath?.Invoke(damageReport);
		}

		private void OnBossAllyDeath(DamageReport damageReport)
		{
			onBossAllyDeath?.Invoke(damageReport);
		}
	}
}
namespace RoR2.Networking
{
	public class CharacterNetworkTransform : NetworkBehaviour
	{
		public struct Snapshot
		{
			public float serverTime;

			public UnityEngine.Vector3 position;

			public UnityEngine.Vector3 moveVector;

			public UnityEngine.Vector3 aimDirection;

			public UnityEngine.Quaternion rotation;

			public bool isGrounded;

			public UnityEngine.Vector3 groundNormal;

			private static bool LerpGroundNormal(ref Snapshot a, ref Snapshot b, float t, out UnityEngine.Vector3 groundNormal)
			{
				groundNormal = UnityEngine.Vector3.zero;
				bool num = ((t > 0f) ? b.isGrounded : a.isGrounded);
				if (num)
				{
					if (b.isGrounded)
					{
						if (a.isGrounded)
						{
							groundNormal = UnityEngine.Vector3.Slerp(a.groundNormal, b.groundNormal, t);
							return num;
						}
						groundNormal = b.groundNormal;
						return num;
					}
					groundNormal = a.groundNormal;
				}
				return num;
			}

			public static Snapshot Lerp(Snapshot a, Snapshot b, float t)
			{
				UnityEngine.Vector3 vector;
				bool flag = LerpGroundNormal(ref a, ref b, t, out vector);
				Snapshot result = default(Snapshot);
				result.position = UnityEngine.Vector3.Lerp(a.position, b.position, t);
				result.moveVector = UnityEngine.Vector3.Lerp(a.moveVector, b.moveVector, t);
				result.aimDirection = UnityEngine.Vector3.Slerp(a.aimDirection, b.moveVector, t);
				result.rotation = UnityEngine.Quaternion.Lerp(a.rotation, b.rotation, t);
				result.isGrounded = flag;
				result.groundNormal = vector;
				return result;
			}

			public static Snapshot Interpolate(Snapshot a, Snapshot b, float serverTime)
			{
				float t = (serverTime - a.serverTime) / (b.serverTime - a.serverTime);
				UnityEngine.Vector3 vector;
				bool flag = LerpGroundNormal(ref a, ref b, t, out vector);
				Snapshot result = default(Snapshot);
				result.serverTime = serverTime;
				result.position = UnityEngine.Vector3.LerpUnclamped(a.position, b.position, t);
				result.moveVector = UnityEngine.Vector3.Lerp(a.moveVector, b.moveVector, t);
				result.aimDirection = UnityEngine.Vector3.Slerp(a.aimDirection, b.aimDirection, t);
				result.rotation = UnityEngine.Quaternion.Lerp(a.rotation, b.rotation, t);
				result.isGrounded = flag;
				result.groundNormal = vector;
				return result;
			}
		}

		private static List<CharacterNetworkTransform> instancesList = new List<CharacterNetworkTransform>();

		private static ReadOnlyCollection<CharacterNetworkTransform> _readOnlyInstancesList = new ReadOnlyCollection<CharacterNetworkTransform>(instancesList);

		[Tooltip("The delay in seconds between position network updates.")]
		public float positionTransmitInterval = 0.1f;

		[HideInInspector]
		public float lastPositionTransmitTime = float.NegativeInfinity;

		[Tooltip("The number of packets of buffers to have.")]
		public float interpolationFactor = 2f;

		public Snapshot newestNetSnapshot;

		private List<Snapshot> snapshots = new List<Snapshot>();

		public bool debugDuplicatePositions;

		public bool debugSnapshotReceived;

		private bool rigidbodyStartedKinematic = true;

		public static ReadOnlyCollection<CharacterNetworkTransform> readOnlyInstancesList => _readOnlyInstancesList;

		public new Transform transform { get; private set; }

		public InputBankTest inputBank { get; private set; }

		public CharacterMotor characterMotor { get; set; }

		public CharacterDirection characterDirection { get; private set; }

		private Rigidbody rigidbody { get; set; }

		public float interpolationDelay => positionTransmitInterval * interpolationFactor;

		public bool hasEffectiveAuthority { get; private set; }

		private Snapshot CalcCurrentSnapshot(float time, float interpolationDelay)
		{
			float num = time - interpolationDelay;
			if (snapshots.Count < 2)
			{
				Snapshot result = ((snapshots.Count == 0) ? BuildSnapshot() : snapshots[0]);
				result.serverTime = num;
				return result;
			}
			int i;
			for (i = 0; i < snapshots.Count - 2 && (!(snapshots[i].serverTime <= num) || !(snapshots[i + 1].serverTime >= num)); i++)
			{
			}
			return Snapshot.Interpolate(snapshots[i], snapshots[i + 1], num);
		}

		private Snapshot BuildSnapshot()
		{
			Snapshot result = default(Snapshot);
			result.serverTime = PlatformSystems.networkManager.serverFixedTime;
			result.position = transform.position;
			result.moveVector = (inputBank ? inputBank.moveVector : UnityEngine.Vector3.zero);
			result.aimDirection = (inputBank ? inputBank.aimDirection : UnityEngine.Vector3.zero);
			result.rotation = (characterDirection ? UnityEngine.Quaternion.Euler(0f, characterDirection.yaw, 0f) : transform.rotation);
			result.isGrounded = (bool)characterMotor && characterMotor.isGrounded;
			result.groundNormal = (characterMotor ? characterMotor.estimatedGroundNormal : UnityEngine.Vector3.zero);
			return result;
		}

		public void PushSnapshot(Snapshot newSnapshot)
		{
			if (debugSnapshotReceived)
			{
				UnityEngine.Debug.LogFormat("{0} CharacterNetworkTransform snapshot received.", base.gameObject);
			}
			if (snapshots.Count > 0)
			{
				_ = newSnapshot.serverTime;
				_ = snapshots[snapshots.Count - 1].serverTime;
			}
			if (debugDuplicatePositions && snapshots.Count > 0)
			{
				_ = newSnapshot.position == snapshots[snapshots.Count - 1].position;
			}
			if (((snapshots.Count > 0) ? snapshots[snapshots.Count - 1].serverTime : float.NegativeInfinity) < newSnapshot.serverTime)
			{
				snapshots.Add(newSnapshot);
				newestNetSnapshot = newSnapshot;
				UnityEngine.Debug.DrawLine(newSnapshot.position + UnityEngine.Vector3.up, newSnapshot.position + UnityEngine.Vector3.down, UnityEngine.Color.white, 0.25f);
			}
			float num = PlatformSystems.networkManager.serverFixedTime - interpolationDelay * 2f;
			while (snapshots.Count > 2 && snapshots[1].serverTime < num)
			{
				snapshots.RemoveAt(0);
			}
		}

		private void Awake()
		{
			transform = base.transform;
			inputBank = GetComponent<InputBankTest>();
			characterMotor = GetComponent<CharacterMotor>();
			characterDirection = GetComponent<CharacterDirection>();
			rigidbody = GetComponent<Rigidbody>();
			if ((bool)rigidbody)
			{
				rigidbodyStartedKinematic = rigidbody.isKinematic;
			}
		}

		private void Start()
		{
			newestNetSnapshot = BuildSnapshot();
			UpdateAuthority();
		}

		private void OnEnable()
		{
			bool num = instancesList.Contains(this);
			instancesList.Add(this);
			if (num)
			{
				UnityEngine.Debug.LogError("Instance already in list!");
			}
		}

		private void OnDisable()
		{
			instancesList.Remove(this);
			if (instancesList.Contains(this))
			{
				UnityEngine.Debug.LogError("Instance was not fully removed from list!");
			}
		}

		private void UpdateAuthority()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
			if ((bool)rigidbody)
			{
				rigidbody.isKinematic = !hasEffectiveAuthority || rigidbodyStartedKinematic;
			}
		}

		public override void OnStartAuthority()
		{
			UpdateAuthority();
		}

		public override void OnStopAuthority()
		{
			UpdateAuthority();
		}

		private void ApplyCurrentSnapshot(float currentTime)
		{
			Snapshot snapshot = CalcCurrentSnapshot(currentTime, interpolationDelay);
			if (!characterMotor)
			{
				if (rigidbodyStartedKinematic)
				{
					transform.position = snapshot.position;
				}
				else
				{
					rigidbody.MovePosition(snapshot.position);
				}
			}
			if ((bool)inputBank)
			{
				inputBank.moveVector = snapshot.moveVector;
				inputBank.aimDirection = snapshot.aimDirection;
			}
			if ((bool)characterMotor)
			{
				characterMotor.netIsGrounded = snapshot.isGrounded;
				characterMotor.netGroundNormal = snapshot.groundNormal;
				if (characterMotor.Motor.enabled)
				{
					characterMotor.Motor.MoveCharacter(snapshot.position);
				}
				else
				{
					characterMotor.Motor.SetPosition(snapshot.position);
				}
			}
			if ((bool)characterDirection)
			{
				characterDirection.yaw = snapshot.rotation.eulerAngles.y;
			}
			else if (rigidbodyStartedKinematic)
			{
				transform.rotation = snapshot.rotation;
			}
			else
			{
				rigidbody.MoveRotation(snapshot.rotation);
			}
		}

		private void FixedUpdate()
		{
			if (!hasEffectiveAuthority)
			{
				ApplyCurrentSnapshot(PlatformSystems.networkManager.serverFixedTime);
			}
			else
			{
				newestNetSnapshot = BuildSnapshot();
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class CharacterNetworkTransformManager : MonoBehaviour
	{
		private class CharacterUpdateMessage : MessageBase
		{
			private static readonly int byteSize = 1;

			private static readonly int floatSize = 4;

			private static readonly int vector3Size = floatSize * 3;

			private static readonly int packedUint32MaxSize = 5;

			private static readonly int gameObjectSize = packedUint32MaxSize;

			private static readonly int packedUnitVector3Size = 2;

			private static readonly int quaternionSize = floatSize * 4;

			public static readonly int maxNetworkSize = byteSize + floatSize + gameObjectSize + vector3Size + packedUnitVector3Size + vector3Size + quaternionSize + packedUnitVector3Size;

			private static readonly byte nonIdentityRotationBit = 2;

			private static readonly byte isGroundedBit = 4;

			public float timestamp;

			public GameObject gameObject;

			public UnityEngine.Vector3 newPosition;

			public UnityEngine.Vector3 aimDirection;

			public UnityEngine.Vector3 moveVector;

			public UnityEngine.Quaternion rotation;

			public bool isGrounded;

			public UnityEngine.Vector3 groundNormal;

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
				byte b = 0;
				bool num = rotation != UnityEngine.Quaternion.identity;
				if (num)
				{
					b |= nonIdentityRotationBit;
				}
				if (isGrounded)
				{
					b |= isGroundedBit;
				}
				writer.Write(b);
				writer.Write(timestamp);
				writer.Write(gameObject);
				writer.Write(newPosition);
				writer.Write(new PackedUnitVector3(aimDirection));
				writer.Write(moveVector);
				if (num)
				{
					writer.Write(rotation);
				}
				if (isGrounded)
				{
					writer.Write(new PackedUnitVector3(groundNormal));
				}
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
				byte b = reader.ReadByte();
				bool num = (b & nonIdentityRotationBit) != 0;
				isGrounded = (b & isGroundedBit) != 0;
				timestamp = reader.ReadSingle();
				gameObject = reader.ReadGameObject();
				newPosition = reader.ReadVector3();
				aimDirection = reader.ReadPackedUnitVector3().Unpack();
				moveVector = reader.ReadVector3();
				if (num)
				{
					rotation = reader.ReadQuaternion();
				}
				else
				{
					rotation = UnityEngine.Quaternion.identity;
				}
				if (isGrounded)
				{
					groundNormal = reader.ReadPackedUnitVector3().Unpack();
				}
			}
		}

		public struct NetSnapshot
		{
			public GameObject gameObject;

			public CharacterNetworkTransform.Snapshot snapshot;
		}

		private static CharacterNetworkTransformManager instance;

		private CharacterUpdateMessage currentInMessage = new CharacterUpdateMessage();

		private CharacterUpdateMessage currentOutMessage = new CharacterUpdateMessage();

		private readonly Queue<NetSnapshot> snapshotQueue = new Queue<NetSnapshot>();

		private void Awake()
		{
			instance = this;
		}

		[NetworkMessageHandler(msgType = 51, client = true, server = true)]
		private static void HandleTransformUpdates(NetworkMessage netMsg)
		{
			if ((bool)instance)
			{
				instance.HandleTransformUpdatesInternal(netMsg);
			}
		}

		private void HandleTransformUpdatesInternal(NetworkMessage netMsg)
		{
			uint num = netMsg.reader.ReadByte();
			float filteredClientRttFixed = PlatformSystems.networkManager.filteredClientRttFixed;
			for (int i = 0; i < num; i++)
			{
				netMsg.ReadMessage(currentInMessage);
				GameObject gameObject = currentInMessage.gameObject;
				if (!gameObject || (NetworkServer.active && gameObject.GetComponent<NetworkIdentity>().clientAuthorityOwner != netMsg.conn))
				{
					continue;
				}
				CharacterNetworkTransform component = gameObject.GetComponent<CharacterNetworkTransform>();
				if ((bool)component && !component.hasEffectiveAuthority)
				{
					CharacterNetworkTransform.Snapshot snapshot = default(CharacterNetworkTransform.Snapshot);
					snapshot.serverTime = currentInMessage.timestamp;
					snapshot.position = currentInMessage.newPosition;
					snapshot.moveVector = currentInMessage.moveVector;
					snapshot.aimDirection = currentInMessage.aimDirection;
					snapshot.rotation = currentInMessage.rotation;
					snapshot.isGrounded = currentInMessage.isGrounded;
					snapshot.groundNormal = currentInMessage.groundNormal;
					CharacterNetworkTransform.Snapshot snapshot2 = snapshot;
					if (NetworkClient.active)
					{
						snapshot2.serverTime += filteredClientRttFixed;
					}
					component.PushSnapshot(snapshot2);
					if (NetworkServer.active)
					{
						snapshotQueue.Enqueue(new NetSnapshot
						{
							gameObject = component.gameObject,
							snapshot = snapshot2
						});
					}
				}
			}
		}

		private void ProcessQueue()
		{
			if (snapshotQueue.Count != 0)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				networkWriter.StartMessage(51);
				int num = Mathf.Min(Mathf.FloorToInt((float)(1000 - networkWriter.Position) / (float)CharacterUpdateMessage.maxNetworkSize), snapshotQueue.Count);
				networkWriter.Write((byte)num);
				for (int i = 0; i < num; i++)
				{
					NetSnapshot netSnapshot = snapshotQueue.Dequeue();
					currentOutMessage.gameObject = netSnapshot.gameObject;
					currentOutMessage.newPosition = netSnapshot.snapshot.position;
					currentOutMessage.aimDirection = netSnapshot.snapshot.aimDirection;
					currentOutMessage.moveVector = netSnapshot.snapshot.moveVector;
					currentOutMessage.rotation = netSnapshot.snapshot.rotation;
					currentOutMessage.isGrounded = netSnapshot.snapshot.isGrounded;
					currentOutMessage.timestamp = netSnapshot.snapshot.serverTime;
					currentOutMessage.groundNormal = netSnapshot.snapshot.groundNormal;
					networkWriter.Write(currentOutMessage);
				}
				networkWriter.FinishMessage();
				if (NetworkServer.active)
				{
					NetworkServer.SendWriterToReady(null, networkWriter, QosChannelIndex.characterTransformUnreliable.intVal);
				}
				else if (ClientScene.readyConnection != null)
				{
					ClientScene.readyConnection.SendWriter(networkWriter, QosChannelIndex.characterTransformUnreliable.intVal);
				}
			}
		}

		private void FixedUpdate()
		{
			if (!NetworkManager.singleton || RoR2Application.isInSinglePlayer)
			{
				return;
			}
			ReadOnlyCollection<CharacterNetworkTransform> readOnlyInstancesList = CharacterNetworkTransform.readOnlyInstancesList;
			float fixedTime = Time.fixedTime;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CharacterNetworkTransform characterNetworkTransform = readOnlyInstancesList[i];
				if (characterNetworkTransform.hasEffectiveAuthority && fixedTime - characterNetworkTransform.lastPositionTransmitTime > characterNetworkTransform.positionTransmitInterval)
				{
					characterNetworkTransform.lastPositionTransmitTime = fixedTime;
					snapshotQueue.Enqueue(new NetSnapshot
					{
						gameObject = characterNetworkTransform.gameObject,
						snapshot = characterNetworkTransform.newestNetSnapshot
					});
				}
			}
			while (snapshotQueue.Count > 0)
			{
				ProcessQueue();
			}
		}
	}
	public class GenericSceneSpawnPoint : MonoBehaviour
	{
		public GameObject networkedObjectPrefab;

		private void Start()
		{
			if (NetworkServer.active)
			{
				NetworkServer.Spawn(UnityEngine.Object.Instantiate(networkedObjectPrefab, base.transform.position, base.transform.rotation));
				base.gameObject.SetActive(value: false);
			}
			else
			{
				base.gameObject.SetActive(value: false);
			}
		}
	}
	public class NetworkEnableObjectIfLocal : NetworkBehaviour
	{
		[Tooltip("The GameObject to enable/disable.")]
		public GameObject target;

		private void Start()
		{
			if ((bool)target)
			{
				target.SetActive(base.hasAuthority);
			}
		}

		public override void OnStartAuthority()
		{
			base.OnStartAuthority();
			if ((bool)target)
			{
				target.SetActive(value: true);
			}
		}

		public override void OnStopAuthority()
		{
			if ((bool)target)
			{
				target.SetActive(value: false);
			}
			base.OnStopAuthority();
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public static class RttManager
	{
		private struct ConnectionRttInfo
		{
			public readonly NetworkConnection connection;

			public float newestRttInSeconds;

			public uint newestRttInMilliseconds;

			public float frameSmoothedRtt;

			public float frameVelocity;

			public float fixedSmoothedRtt;

			public float fixedVelocity;

			public ConnectionRttInfo(NetworkConnection connection)
			{
				this.connection = connection;
				newestRttInMilliseconds = 0u;
				newestRttInSeconds = 0f;
				frameSmoothedRtt = 0f;
				frameVelocity = 0f;
				fixedSmoothedRtt = 0f;
				fixedVelocity = 0f;
			}
		}

		private class PingMessage : MessageBase
		{
			public uint timeStampMs;

			public override void Serialize(NetworkWriter writer)
			{
				writer.WritePackedUInt32(timeStampMs);
			}

			public override void Deserialize(NetworkReader reader)
			{
				timeStampMs = reader.ReadPackedUInt32();
			}
		}

		private static ConnectionRttInfo[] entries = Array.Empty<ConnectionRttInfo>();

		private static readonly FloatConVar cvRttSmoothDuration = new FloatConVar("net_rtt_smooth_duration", ConVarFlags.None, "0.1", "The smoothing duration for round-trip time values.");

		public static float GetConnectionRTT(NetworkConnection connection)
		{
			if (FindConnectionIndex(connection, out var entryIndex))
			{
				return entries[entryIndex].newestRttInSeconds;
			}
			return 0f;
		}

		public static uint GetConnectionRTTInMilliseconds(NetworkConnection connection)
		{
			if (FindConnectionIndex(connection, out var entryIndex))
			{
				return entries[entryIndex].newestRttInMilliseconds;
			}
			return 0u;
		}

		public static float GetConnectionFrameSmoothedRtt(NetworkConnection connection)
		{
			if (FindConnectionIndex(connection, out var entryIndex))
			{
				return entries[entryIndex].frameSmoothedRtt;
			}
			return 0f;
		}

		public static float GetConnectionFixedSmoothedRtt(NetworkConnection connection)
		{
			if (FindConnectionIndex(connection, out var entryIndex))
			{
				return entries[entryIndex].fixedSmoothedRtt;
			}
			return 0f;
		}

		private static void OnConnectionDiscovered(NetworkConnection connection)
		{
			ConnectionRttInfo value = new ConnectionRttInfo(connection);
			ArrayUtils.ArrayAppend(ref entries, in value);
		}

		private static void OnConnectionLost(NetworkConnection connection)
		{
			if (FindConnectionIndex(connection, out var entryIndex))
			{
				ArrayUtils.ArrayRemoveAtAndResize(ref entries, entryIndex);
			}
		}

		private static bool FindConnectionIndex(NetworkConnection connection, out int entryIndex)
		{
			ConnectionRttInfo[] array = entries;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].connection == connection)
				{
					entryIndex = i;
					return true;
				}
			}
			entryIndex = -1;
			return false;
		}

		private static void UpdateFilteredRtt(float deltaTime, float targetValue, ref float currentValue, ref float velocity)
		{
			if (currentValue == 0f)
			{
				currentValue = targetValue;
				velocity = 0f;
			}
			else
			{
				currentValue = Mathf.SmoothDamp(currentValue, targetValue, ref velocity, cvRttSmoothDuration.value, 100f, deltaTime);
			}
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			NetworkManagerSystem.onClientConnectGlobal += OnConnectionDiscovered;
			NetworkManagerSystem.onClientDisconnectGlobal += OnConnectionLost;
			NetworkManagerSystem.onServerConnectGlobal += OnConnectionDiscovered;
			NetworkManagerSystem.onServerDisconnectGlobal += OnConnectionLost;
			RoR2Application.onUpdate += Update;
			RoR2Application.onFixedUpdate += FixedUpdate;
		}

		private static void Update()
		{
			float deltaTime = Time.deltaTime;
			ConnectionRttInfo[] array = entries;
			for (int i = 0; i < array.Length; i++)
			{
				ref ConnectionRttInfo reference = ref array[i];
				UpdateFilteredRtt(deltaTime, reference.newestRttInSeconds, ref reference.frameSmoothedRtt, ref reference.frameVelocity);
			}
		}

		private static void FixedUpdate()
		{
			float fixedDeltaTime = Time.fixedDeltaTime;
			ConnectionRttInfo[] array = entries;
			for (int i = 0; i < array.Length; i++)
			{
				ref ConnectionRttInfo reference = ref array[i];
				UpdateFilteredRtt(fixedDeltaTime, reference.newestRttInSeconds, ref reference.fixedSmoothedRtt, ref reference.fixedVelocity);
			}
		}

		[NetworkMessageHandler(msgType = 65, client = true, server = true)]
		private static void HandlePing(NetworkMessage netMsg)
		{
			NetworkReader reader = netMsg.reader;
			netMsg.conn.SendByChannel(66, reader.ReadMessage<PingMessage>(), netMsg.channelId);
		}

		[NetworkMessageHandler(msgType = 66, client = true, server = true)]
		private static void HandlePingResponse(NetworkMessage netMsg)
		{
			uint timeStampMs = netMsg.reader.ReadMessage<PingMessage>().timeStampMs;
			uint num = (uint)(int)RoR2Application.stopwatch.ElapsedMilliseconds - timeStampMs;
			if (FindConnectionIndex(netMsg.conn, out var entryIndex))
			{
				ref ConnectionRttInfo reference = ref entries[entryIndex];
				reference.newestRttInMilliseconds = num;
				reference.newestRttInSeconds = (float)num * 0.001f;
			}
		}

		public static void Ping(NetworkConnection conn, int channelId)
		{
			conn.SendByChannel(65, new PingMessage
			{
				timeStampMs = (uint)RoR2Application.stopwatch.ElapsedMilliseconds
			}, channelId);
		}
	}
	public struct AddressPortPair : IEquatable<AddressPortPair>
	{
		public string address;

		public ushort port;

		public bool isValid => !string.IsNullOrEmpty(address);

		public AddressPortPair(string address, ushort port)
		{
			this.address = address;
			this.port = port;
		}

		public AddressPortPair(IPAddress address, ushort port)
		{
			this.address = address.ToString();
			this.port = port;
		}

		public static bool TryParse(string str, out AddressPortPair addressPortPair)
		{
			if (!string.IsNullOrEmpty(str))
			{
				int num = str.Length - 1;
				while (num >= 0 && str[num] != ':')
				{
					num--;
				}
				if (num >= 0)
				{
					string text = str.Substring(0, num);
					string s = str.Substring(num + 1, str.Length - num - 1);
					addressPortPair.address = text;
					addressPortPair.port = (ushort)(TextSerialization.TryParseInvariant(s, out ushort result) ? result : 0);
					return true;
				}
			}
			addressPortPair.address = "";
			addressPortPair.port = 0;
			return false;
		}

		public override string ToString()
		{
			return string.Format(CultureInfo.InvariantCulture, "{0}:{1}", address, port);
		}

		public bool Equals(AddressPortPair other)
		{
			if (string.Equals(address, other.address))
			{
				return port == other.port;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is AddressPortPair other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((address != null) ? address.GetHashCode() : 0) * 397) ^ port.GetHashCode();
		}
	}
	public class NetworkAnimatorParams : NetworkBehaviour
	{
		public Animator targetAnimator;

		public string[] targetAnimatorParamNames;

		public float transmitInterval = 0.1f;

		private NetworkIdentity networkIdentity;

		private static readonly uint animatorParamsDirtyBit;

		private static readonly uint allDirtyBits;

		private int[] targetAnimatorParamHashes;

		private NetworkLerpedFloat[] targetAnimatorParamNetworkValues;

		private float transmitTimerAuthority;

		private bool animatorParamsDirtyAuthority;

		private static int kCmdCmdReceiveAnimatorParams;

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
			targetAnimatorParamHashes = new int[targetAnimatorParamNames.Length];
			for (int i = 0; i < targetAnimatorParamNames.Length; i++)
			{
				targetAnimatorParamHashes[i] = Animator.StringToHash(targetAnimatorParamNames[i]);
			}
			targetAnimatorParamNetworkValues = new NetworkLerpedFloat[targetAnimatorParamNames.Length];
		}

		private void FixedUpdate()
		{
			if (Util.HasEffectiveAuthority(networkIdentity))
			{
				FixedUpdateAuthority();
			}
		}

		private void Update()
		{
			if (!Util.HasEffectiveAuthority(networkIdentity))
			{
				ApplyAnimatorParamsNonAuthority();
			}
		}

		private void FixedUpdateAuthority()
		{
			CollectAnimatorParamsAuthority(out var animatorParamsChanged);
			animatorParamsDirtyAuthority |= animatorParamsChanged;
			transmitTimerAuthority -= Time.fixedDeltaTime;
			if (!(transmitTimerAuthority <= 0f))
			{
				return;
			}
			transmitTimerAuthority = transmitInterval;
			if (!animatorParamsDirtyAuthority)
			{
				return;
			}
			animatorParamsDirtyAuthority = false;
			if (NetworkServer.active)
			{
				SetDirtyBit(animatorParamsDirtyBit);
				return;
			}
			float[] array = new float[targetAnimatorParamNetworkValues.Length];
			for (int i = 0; i < targetAnimatorParamNetworkValues.Length; i++)
			{
				array[i] = targetAnimatorParamNetworkValues[i].GetAuthoritativeValue();
			}
			CallCmdReceiveAnimatorParams(array);
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = (initialState ? allDirtyBits : base.syncVarDirtyBits);
			bool num2 = (num & animatorParamsDirtyBit) != 0;
			writer.WritePackedUInt32(num);
			if (num2)
			{
				for (int i = 0; i < targetAnimatorParamNetworkValues.Length; i++)
				{
					writer.Write(targetAnimatorParamNetworkValues[i].GetAuthoritativeValue());
				}
			}
			return num != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if ((reader.ReadPackedUInt32() & animatorParamsDirtyBit) != 0)
			{
				for (int i = 0; i < targetAnimatorParamNetworkValues.Length; i++)
				{
					targetAnimatorParamNetworkValues[i].PushValue(reader.ReadSingle());
				}
			}
		}

		private void ApplyAnimatorParamsNonAuthority()
		{
			for (int i = 0; i < targetAnimatorParamHashes.Length; i++)
			{
				targetAnimator.SetFloat(targetAnimatorParamHashes[i], targetAnimatorParamNetworkValues[i].GetCurrentValue(hasAuthority: false));
			}
		}

		private void CollectAnimatorParamsAuthority(out bool animatorParamsChanged)
		{
			animatorParamsChanged = false;
			for (int i = 0; i < targetAnimatorParamHashes.Length; i++)
			{
				float @float = targetAnimator.GetFloat(targetAnimatorParamHashes[i]);
				ref NetworkLerpedFloat reference = ref targetAnimatorParamNetworkValues[i];
				float currentValue = reference.GetCurrentValue(hasAuthority: true);
				if (@float != currentValue)
				{
					animatorParamsChanged = true;
					reference.SetValueImmediate(@float);
				}
			}
		}

		[Command]
		private void CmdReceiveAnimatorParams(float[] animatorParamValues)
		{
			int i = 0;
			for (int num = Math.Min(animatorParamValues.Length, targetAnimatorParamNetworkValues.Length); i < num; i++)
			{
				targetAnimatorParamNetworkValues[i].PushValue(animatorParamValues[i]);
			}
			SetDirtyBit(animatorParamsDirtyBit);
		}

		static NetworkAnimatorParams()
		{
			animatorParamsDirtyBit = 1u;
			allDirtyBits = animatorParamsDirtyBit;
			kCmdCmdReceiveAnimatorParams = -1267054443;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkAnimatorParams), kCmdCmdReceiveAnimatorParams, InvokeCmdCmdReceiveAnimatorParams);
			NetworkCRC.RegisterBehaviour("NetworkAnimatorParams", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdReceiveAnimatorParams(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdReceiveAnimatorParams called on client.");
			}
			else
			{
				((NetworkAnimatorParams)obj).CmdReceiveAnimatorParams(GeneratedNetworkCode._ReadArraySingle_None(reader));
			}
		}

		public void CallCmdReceiveAnimatorParams(float[] animatorParamValues)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdReceiveAnimatorParams called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdReceiveAnimatorParams(animatorParamValues);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdReceiveAnimatorParams);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteArraySingle_None(networkWriter, animatorParamValues);
			SendCommandInternal(networkWriter, 0, "CmdReceiveAnimatorParams");
		}

		public override void PreStartClient()
		{
		}
	}
	public class NetworkChildActivation : NetworkBehaviour
	{
		private class GameObjectActiveTracker : MonoBehaviour
		{
			public NetworkChildActivation networkChildActivation;

			public int index = -1;

			private void OnEnable()
			{
				if ((bool)networkChildActivation)
				{
					networkChildActivation.SetChildActiveState(index, active: true);
				}
			}

			private void OnDisable()
			{
				if ((bool)networkChildActivation)
				{
					networkChildActivation.SetChildActiveState(index, active: false);
				}
			}
		}

		[Tooltip("The list of child objects this object will handle activating and deactivating over the network. Client and server must have matching lists (ie DO NOT CHANGE AT RUNTIME.)")]
		public GameObject[] children = Array.Empty<GameObject>();

		private GameObjectActiveTracker[] trackers = Array.Empty<GameObjectActiveTracker>();

		private bool[] childrenActiveStates = Array.Empty<bool>();

		private static readonly uint activeStatesDirtyBit = 1u;

		private static readonly uint allDirtyBits = activeStatesDirtyBit;

		private GameObject[] trackedChildren = Array.Empty<GameObject>();

		private void BuildTrackersForChildren(GameObject[] newTrackedChildren)
		{
			if (trackedChildren == newTrackedChildren)
			{
				return;
			}
			trackedChildren = newTrackedChildren;
			for (int i = 0; i < trackers.Length; i++)
			{
				UnityEngine.Object.Destroy(trackers[i]);
			}
			Array.Resize(ref trackers, newTrackedChildren.Length);
			for (int j = 0; j < newTrackedChildren.Length; j++)
			{
				GameObject gameObject = newTrackedChildren[j];
				if ((bool)gameObject)
				{
					GameObjectActiveTracker gameObjectActiveTracker = gameObject.AddComponent<GameObjectActiveTracker>();
					gameObjectActiveTracker.index = j;
					gameObjectActiveTracker.networkChildActivation = this;
					trackers[j] = gameObjectActiveTracker;
					SetChildActiveState(j, gameObject.gameObject.activeInHierarchy);
				}
			}
		}

		private void SetChildActiveState(int index, bool active)
		{
			childrenActiveStates[index] = active;
			SetDirtyBit(activeStatesDirtyBit);
		}

		private void Awake()
		{
			Array.Resize(ref childrenActiveStates, children.Length);
			Array.Clear(childrenActiveStates, 0, childrenActiveStates.Length);
			if (NetworkServer.active)
			{
				BuildTrackersForChildren(children);
			}
		}

		private void OnDestroy()
		{
			if (NetworkServer.active)
			{
				BuildTrackersForChildren(Array.Empty<GameObject>());
			}
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			base.OnSerialize(writer, initialState);
			uint num = (initialState ? allDirtyBits : base.syncVarDirtyBits);
			writer.WritePackedUInt32(num);
			if ((num & activeStatesDirtyBit) != 0)
			{
				writer.WriteBitArray(childrenActiveStates, childrenActiveStates.Length);
			}
			return num != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
			if ((reader.ReadPackedUInt32() & activeStatesDirtyBit) == 0)
			{
				return;
			}
			reader.ReadBitArray(childrenActiveStates);
			for (int i = 0; i < childrenActiveStates.Length; i++)
			{
				GameObject gameObject = children[i];
				if ((bool)gameObject)
				{
					try
					{
						gameObject.SetActive(childrenActiveStates[i]);
					}
					catch (Exception message)
					{
						UnityEngine.Debug.LogError(message);
					}
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class NetworkContextActivationGuard : MonoBehaviour
	{
		public enum Rule
		{
			Neutral,
			MustBeTrue,
			MustBeFalse
		}

		public Rule server;

		public Rule client;

		private void Awake()
		{
			bool flag = true;
			flag &= CheckRule(server, NetworkServer.active);
			flag &= CheckRule(client, NetworkClient.active);
			base.gameObject.SetActive(flag);
		}

		private bool CheckRule(Rule rule, bool value)
		{
			return rule switch
			{
				Rule.Neutral => true, 
				Rule.MustBeTrue => value, 
				Rule.MustBeFalse => !value, 
				_ => false, 
			};
		}
	}
	[Serializable]
	public struct NetworkDateTime : IEquatable<NetworkDateTime>
	{
		public long _binaryValue;

		public static explicit operator NetworkDateTime(DateTime dateTime)
		{
			NetworkDateTime result = default(NetworkDateTime);
			result._binaryValue = dateTime.ToBinary();
			return result;
		}

		public static explicit operator DateTime(NetworkDateTime networkDateTime)
		{
			return DateTime.FromBinary(networkDateTime._binaryValue);
		}

		public static void Serialize(in NetworkDateTime networkDateTime, NetworkWriter writer)
		{
			writer.Write(networkDateTime._binaryValue);
		}

		public static void Deserialize(out NetworkDateTime networkDateTime, NetworkReader reader)
		{
			networkDateTime._binaryValue = reader.ReadInt64();
		}

		public bool Equals(NetworkDateTime other)
		{
			return _binaryValue == other._binaryValue;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is NetworkDateTime other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return _binaryValue.GetHashCode();
		}
	}
	public static class NetworkExtensions
	{
		public static void Write(this NetworkWriter writer, in NetworkDateTime networkDateTime)
		{
			NetworkDateTime.Serialize(in networkDateTime, writer);
		}

		public static NetworkDateTime ReadNetworkDateTime(this NetworkReader reader)
		{
			NetworkDateTime.Deserialize(out var networkDateTime, reader);
			return networkDateTime;
		}

		public static void WriteNetworkGuid(this NetworkWriter networkWriter, in NetworkGuid guid)
		{
			guid.Serialize(networkWriter);
		}

		public static void WriteGuid(this NetworkWriter networkWriter, in Guid guid)
		{
			NetworkGuid guid2 = (NetworkGuid)guid;
			networkWriter.WriteNetworkGuid(in guid2);
		}

		public static NetworkGuid ReadNetworkGuid(this NetworkReader networkReader)
		{
			NetworkGuid result = default(NetworkGuid);
			result.Deserialize(networkReader);
			return result;
		}

		public static Guid ReadGuid(this NetworkReader networkReader)
		{
			return (Guid)networkReader.ReadNetworkGuid();
		}
	}
	public class NetworkedViewAngles : NetworkBehaviour
	{
		public PitchYawPair viewAngles;

		private PitchYawPair networkDesiredViewAngles;

		private PitchYawPair velocity;

		private NetworkIdentity networkIdentity;

		public float sendRate = 0.05f;

		public float bufferMultiplier = 3f;

		public float maxSmoothVelocity = 1440f;

		private float sendTimer;

		private static int kCmdCmdUpdateViewAngles;

		public bool hasEffectiveAuthority { get; private set; }

		private void Awake()
		{
			networkIdentity = GetComponent<NetworkIdentity>();
		}

		private void Update()
		{
			hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity);
			if (hasEffectiveAuthority)
			{
				networkDesiredViewAngles = viewAngles;
			}
			else
			{
				viewAngles = PitchYawPair.SmoothDamp(viewAngles, networkDesiredViewAngles, ref velocity, GetNetworkSendInterval() * bufferMultiplier, maxSmoothVelocity);
			}
		}

		public override float GetNetworkSendInterval()
		{
			return sendRate;
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				SetDirtyBit(1u);
			}
			hasEffectiveAuthority = Util.HasEffectiveAuthority(networkIdentity);
			if (!hasEffectiveAuthority)
			{
				return;
			}
			networkDesiredViewAngles = viewAngles;
			if (!NetworkServer.active)
			{
				sendTimer -= Time.deltaTime;
				if (sendTimer <= 0f)
				{
					CallCmdUpdateViewAngles(viewAngles.pitch, viewAngles.yaw);
					sendTimer = GetNetworkSendInterval();
				}
			}
		}

		[Command(channel = 5)]
		public void CmdUpdateViewAngles(float pitch, float yaw)
		{
			networkDesiredViewAngles = new PitchYawPair(pitch, yaw);
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			writer.Write(networkDesiredViewAngles);
			return true;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			PitchYawPair pitchYawPair = reader.ReadPitchYawPair();
			if (!hasEffectiveAuthority)
			{
				networkDesiredViewAngles = pitchYawPair;
				if (initialState)
				{
					viewAngles = pitchYawPair;
					velocity = PitchYawPair.zero;
				}
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdUpdateViewAngles(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdUpdateViewAngles called on client.");
			}
			else
			{
				((NetworkedViewAngles)obj).CmdUpdateViewAngles(reader.ReadSingle(), reader.ReadSingle());
			}
		}

		public void CallCmdUpdateViewAngles(float pitch, float yaw)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdUpdateViewAngles called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdUpdateViewAngles(pitch, yaw);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdUpdateViewAngles);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(pitch);
			networkWriter.Write(yaw);
			SendCommandInternal(networkWriter, 5, "CmdUpdateViewAngles");
		}

		static NetworkedViewAngles()
		{
			kCmdCmdUpdateViewAngles = -1684781536;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkedViewAngles), kCmdCmdUpdateViewAngles, InvokeCmdCmdUpdateViewAngles);
			NetworkCRC.RegisterBehaviour("NetworkedViewAngles", 0);
		}

		public override void PreStartClient()
		{
		}
	}
	[Serializable]
	public struct NetworkGuid : IEquatable<NetworkGuid>
	{
		[StructLayout(LayoutKind.Explicit)]
		private struct ConverterUnion
		{
			[FieldOffset(0)]
			public Guid guildValue;

			[FieldOffset(0)]
			public NetworkGuid networkGuidValue;
		}

		public ulong _a;

		public ulong _b;

		public static explicit operator NetworkGuid(Guid guid)
		{
			ConverterUnion converterUnion = default(ConverterUnion);
			converterUnion.guildValue = guid;
			return converterUnion.networkGuidValue;
		}

		public static explicit operator Guid(NetworkGuid networkGuid)
		{
			ConverterUnion converterUnion = default(ConverterUnion);
			converterUnion.networkGuidValue = networkGuid;
			return converterUnion.guildValue;
		}

		public bool Equals(NetworkGuid other)
		{
			if (_a == other._a)
			{
				return _b == other._b;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is NetworkGuid other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (_a.GetHashCode() * 397) ^ _b.GetHashCode();
		}

		public static bool operator ==(NetworkGuid left, NetworkGuid right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(NetworkGuid left, NetworkGuid right)
		{
			return !left.Equals(right);
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_a);
			writer.Write(_b);
		}

		public void Deserialize(NetworkReader reader)
		{
			_a = reader.ReadUInt64();
			_b = reader.ReadUInt64();
		}
	}
	public class NetworkLoadout : NetworkBehaviour
	{
		private static readonly Loadout temp;

		private readonly Loadout loadout = new Loadout();

		private static int kCmdCmdSendLoadout;

		public event Action onLoadoutUpdated;

		public void CopyLoadout(Loadout dest)
		{
			loadout.Copy(dest);
		}

		public void SetLoadout(Loadout src)
		{
			src.Copy(loadout);
			if (NetworkServer.active)
			{
				SetDirtyBit(1u);
			}
			else if (base.isLocalPlayer)
			{
				SendLoadoutClient();
			}
			OnLoadoutUpdated();
		}

		[Command]
		private void CmdSendLoadout(byte[] bytes)
		{
			NetworkReader reader = new NetworkReader(bytes);
			temp.Deserialize(reader);
			SetLoadout(temp);
		}

		[Client]
		private void SendLoadoutClient()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.Networking.NetworkLoadout::SendLoadoutClient()' called on server");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			loadout.Serialize(networkWriter);
			CallCmdSendLoadout(networkWriter.ToArray());
		}

		private void OnLoadoutUpdated()
		{
			this.onLoadoutUpdated?.Invoke();
		}

		public override bool OnSerialize(NetworkWriter writer, bool initialState)
		{
			uint num = base.syncVarDirtyBits;
			if (initialState)
			{
				num = 1u;
			}
			writer.WritePackedUInt32(num);
			if ((num & (true ? 1u : 0u)) != 0)
			{
				loadout.Serialize(writer);
			}
			return num != 0;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if ((reader.ReadPackedUInt32() & (true ? 1u : 0u)) != 0)
			{
				temp.Deserialize(reader);
				if (!base.isLocalPlayer)
				{
					temp.Copy(loadout);
					OnLoadoutUpdated();
				}
			}
		}

		static NetworkLoadout()
		{
			temp = new Loadout();
			kCmdCmdSendLoadout = 1217513894;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkLoadout), kCmdCmdSendLoadout, InvokeCmdCmdSendLoadout);
			NetworkCRC.RegisterBehaviour("NetworkLoadout", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdSendLoadout(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSendLoadout called on client.");
			}
			else
			{
				((NetworkLoadout)obj).CmdSendLoadout(reader.ReadBytesAndSize());
			}
		}

		public void CallCmdSendLoadout(byte[] bytes)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSendLoadout called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSendLoadout(bytes);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSendLoadout);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WriteBytesFull(bytes);
			SendCommandInternal(networkWriter, 0, "CmdSendLoadout");
		}

		public override void PreStartClient()
		{
		}
	}
	public struct QosChannelIndex
	{
		public int intVal;

		public static QosChannelIndex defaultReliable = new QosChannelIndex
		{
			intVal = 0
		};

		public static QosChannelIndex defaultUnreliable = new QosChannelIndex
		{
			intVal = 1
		};

		public static QosChannelIndex characterTransformUnreliable = new QosChannelIndex
		{
			intVal = 2
		};

		public static QosChannelIndex time = new QosChannelIndex
		{
			intVal = 3
		};

		public static QosChannelIndex chat = new QosChannelIndex
		{
			intVal = 4
		};

		public const int viewAnglesChannel = 5;

		public static QosChannelIndex viewAngles = new QosChannelIndex
		{
			intVal = 5
		};

		public static QosChannelIndex ping = new QosChannelIndex
		{
			intVal = 6
		};

		public static QosChannelIndex effects = new QosChannelIndex
		{
			intVal = 7
		};
	}
	public class ClientAuthData : MessageBase
	{
		public PlatformID platformId = PlatformID.nil;

		public byte[] authTicket;

		public string[] entitlements;

		public string password;

		public string version;

		public string modHash;

		public override void Serialize(NetworkWriter writer)
		{
			GeneratedNetworkCode._WritePlatformID_None(writer, platformId);
			writer.WriteBytesFull(authTicket);
			GeneratedNetworkCode._WriteArrayString_None(writer, entitlements);
			writer.Write(password);
			writer.Write(version);
			writer.Write(modHash);
		}

		public override void Deserialize(NetworkReader reader)
		{
			platformId = GeneratedNetworkCode._ReadPlatformID_None(reader);
			authTicket = reader.ReadBytesAndSize();
			entitlements = GeneratedNetworkCode._ReadArrayString_None(reader);
			password = reader.ReadString();
			version = reader.ReadString();
			modHash = reader.ReadString();
		}
	}
	public static class ServerAuthManager
	{
		public struct KeyValue
		{
			public readonly NetworkConnection conn;

			public readonly ClientAuthData authData;

			public KeyValue(NetworkConnection conn, ClientAuthData authData)
			{
				this.conn = conn;
				this.authData = authData;
			}
		}

		private static readonly int initialSize = 16;

		public static KeyValue[] instances = new KeyValue[initialSize];

		private static int instanceCount = 0;

		public static event Action<NetworkConnection, ClientAuthData> onAuthDataReceivedFromClient;

		public static event Action<NetworkConnection, ClientAuthData> onAuthExpired;

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			NetworkManagerSystem.onServerConnectGlobal += OnConnectionDiscovered;
			NetworkManagerSystem.onServerDisconnectGlobal += OnConnectionLost;
		}

		private static void OnConnectionDiscovered(NetworkConnection conn)
		{
		}

		private static void OnConnectionLost(NetworkConnection conn)
		{
			for (int i = 0; i < instanceCount; i++)
			{
				if (instances[i].conn == conn)
				{
					ServerAuthManager.onAuthExpired?.Invoke(conn, instances[i].authData);
					ArrayUtils.ArrayRemoveAt(instances, ref instanceCount, i);
					break;
				}
			}
		}

		public static ClientAuthData FindAuthData(NetworkConnection conn)
		{
			for (int i = 0; i < instanceCount; i++)
			{
				if (instances[i].conn == conn)
				{
					return instances[i].authData;
				}
			}
			return null;
		}

		public static NetworkConnection FindConnectionForSteamID(PlatformID steamId)
		{
			for (int i = 0; i < instanceCount; i++)
			{
				if (instances[i].authData.platformId == steamId)
				{
					return instances[i].conn;
				}
			}
			return null;
		}

		[NetworkMessageHandler(client = false, server = true, msgType = 74)]
		private static void HandleSetClientAuth(NetworkMessage netMsg)
		{
			if (netMsg.conn == null)
			{
				UnityEngine.Debug.LogWarning("ServerAuthManager.HandleSetClientAuth(): Connection is null.");
			}
			else
			{
				if (FindAuthData(netMsg.conn) != null)
				{
					return;
				}
				bool flag = Util.ConnectionIsLocal(netMsg.conn);
				NetworkManagerSystem.BaseKickReason baseKickReason = null;
				try
				{
					ClientAuthData clientAuthData = netMsg.ReadMessage<ClientAuthData>();
					NetworkConnection networkConnection = FindConnectionForSteamID(clientAuthData.platformId);
					if (networkConnection != null)
					{
						UnityEngine.Debug.LogFormat("SteamID {0} is already claimed by connection [{1}]. Connection [{2}] rejected.", clientAuthData.platformId, networkConnection, netMsg.conn);
						PlatformSystems.networkManager.ServerKickClient(netMsg.conn, new NetworkManagerSystem.SimpleLocalizedKickReason("KICK_REASON_ACCOUNT_ALREADY_ON_SERVER"));
						return;
					}
					KeyValue value = new KeyValue(netMsg.conn, clientAuthData);
					ArrayUtils.ArrayAppend(ref instances, ref instanceCount, in value);
					string value2 = NetworkManagerSystem.SvPasswordConVar.instance.value;
					if (!flag && value2.Length != 0 && !(clientAuthData.password == value2))
					{
						UnityEngine.Debug.LogFormat("Rejecting connection from [{0}]: {1}", netMsg.conn, "Bad password.");
						baseKickReason = new NetworkManagerSystem.SimpleLocalizedKickReason("KICK_REASON_BADPASSWORD");
					}
					string version = clientAuthData.version;
					string buildId = RoR2Application.GetBuildId();
					if (!string.Equals(version, buildId, StringComparison.OrdinalIgnoreCase))
					{
						UnityEngine.Debug.LogFormat("Rejecting connection from [{0}]: {1}", netMsg.conn, "Bad version.");
						baseKickReason = new NetworkManagerSystem.SimpleLocalizedKickReason("KICK_REASON_BADVERSION", version, buildId);
					}
					string modHash = clientAuthData.modHash;
					string networkModHash = NetworkModCompatibilityHelper.networkModHash;
					if (!string.Equals(modHash, networkModHash, StringComparison.OrdinalIgnoreCase))
					{
						UnityEngine.Debug.LogFormat("Rejecting connection from [{0}]: {1}", netMsg.conn, "Mod mismatch.");
						baseKickReason = new NetworkManagerSystem.ModMismatchKickReason(NetworkModCompatibilityHelper.networkModList);
					}
					ServerAuthManager.onAuthDataReceivedFromClient?.Invoke(value.conn, value.authData);
				}
				catch
				{
					UnityEngine.Debug.LogFormat("Rejecting connection from [{0}]: {1}", netMsg.conn, "Malformed auth data.");
					baseKickReason = new NetworkManagerSystem.SimpleLocalizedKickReason("KICK_REASON_MALFORMED_AUTH_DATA");
				}
				if (baseKickReason != null)
				{
					PlatformSystems.networkManager.ServerKickClient(netMsg.conn, baseKickReason);
				}
			}
		}

		[CanBeNull]
		public static ClientAuthData GetClientAuthData(NetworkConnection networkConnection)
		{
			for (int i = 0; i < instances.Length; i++)
			{
				if (instances[i].conn == networkConnection)
				{
					return instances[i].authData;
				}
			}
			return null;
		}
	}
	public class SteamLobbyFinder : MonoBehaviour
	{
		private class LobbyStateBase : BaseState
		{
			protected SteamLobbyFinder lobbyFinder;

			public override void OnEnter()
			{
				base.OnEnter();
				lobbyFinder = GetComponent<SteamLobbyFinder>();
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onLobbyOwnershipGained = (Action)Delegate.Combine(lobbyManager.onLobbyOwnershipGained, new Action(OnLobbyOwnershipGained));
				LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
				lobbyManager2.onLobbyOwnershipLost = (Action)Delegate.Combine(lobbyManager2.onLobbyOwnershipLost, new Action(OnLobbyOwnershipLost));
			}

			public override void OnExit()
			{
				LobbyManager lobbyManager = PlatformSystems.lobbyManager;
				lobbyManager.onLobbyOwnershipGained = (Action)Delegate.Remove(lobbyManager.onLobbyOwnershipGained, new Action(OnLobbyOwnershipGained));
				LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
				lobbyManager2.onLobbyOwnershipLost = (Action)Delegate.Remove(lobbyManager2.onLobbyOwnershipLost, new Action(OnLobbyOwnershipLost));
				base.OnExit();
			}

			public virtual void OnLobbiesUpdated()
			{
			}

			private void OnLobbyOwnershipGained()
			{
				outer.SetNextState(new LobbyStateStart());
			}

			private void OnLobbyOwnershipLost()
			{
				outer.SetNextState(new LobbyStateNonLeader());
			}
		}

		private class LobbyStateNonLeader : LobbyStateBase
		{
			public override void Update()
			{
				base.Update();
				if (PlatformSystems.lobbyManager.ownsLobby)
				{
					if (PlatformSystems.lobbyManager.hasMinimumPlayerCount)
					{
						outer.SetNextState(new LobbyStateMultiSearch());
					}
					else
					{
						outer.SetNextState(new LobbyStateSingleSearch());
					}
				}
			}
		}

		private class LobbyStateStart : LobbyStateBase
		{
			public override void Update()
			{
				base.Update();
				if (lobbyFinder.startDelayDuration <= base.age)
				{
					outer.SetNextState(PlatformSystems.lobbyManager.hasMinimumPlayerCount ? ((LobbyStateBase)new LobbyStateMultiSearch()) : ((LobbyStateBase)new LobbyStateSingleSearch()));
				}
			}
		}

		private class LobbyStateSingleSearch : LobbyStateBase
		{
			public override void OnEnter()
			{
				base.OnEnter();
				(PlatformSystems.lobbyManager as SteamworksLobbyManager).SetLobbyQuickPlayCutoffTimeIfOwner(null);
			}

			public override void Update()
			{
				base.Update();
				if (PlatformSystems.lobbyManager.hasMinimumPlayerCount)
				{
					outer.SetNextState(new LobbyStateMultiSearch());
				}
				else if (lobbyFinder.refreshTimer <= 0f)
				{
					if (base.age >= lobbyFinder.joinOnlyDuration && steamClient.Lobby.LobbyType != Lobby.Type.Public)
					{
						UnityEngine.Debug.LogFormat("Unable to find joinable lobby after {0} seconds. Setting lobby to public.", lobbyFinder.age);
						steamClient.Lobby.LobbyType = Lobby.Type.Public;
					}
					lobbyFinder.refreshTimer = lobbyFinder.refreshInterval;
					lobbyFinder.RequestLobbyListRefresh();
				}
			}

			public override void OnLobbiesUpdated()
			{
				base.OnLobbiesUpdated();
				if (!steamClient.IsValid)
				{
					return;
				}
				List<LobbyList.Lobby> lobbies = steamClient.LobbyList.Lobbies;
				List<LobbyList.Lobby> list = new List<LobbyList.Lobby>();
				ulong currentLobby = steamClient.Lobby.CurrentLobby;
				bool isValid = steamClient.Lobby.IsValid;
				int currentLobbySize = (isValid ? GetCurrentLobbyRealPlayerCount() : LocalUserManager.readOnlyLocalUsersList.Count);
				if (PlatformSystems.lobbyManager.ownsLobby || !isValid)
				{
					for (int i = 0; i < lobbies.Count; i++)
					{
						if ((!isValid || lobbies[i].LobbyID < currentLobby) && CanJoinLobby(currentLobbySize, lobbies[i]))
						{
							list.Add(lobbies[i]);
						}
					}
					if (list.Count > 0)
					{
						PlatformID join = new PlatformID(list[0].LobbyID);
						PlatformSystems.lobbyManager.JoinLobby(join);
					}
				}
				UnityEngine.Debug.LogFormat("Found {0} lobbies, {1} joinable.", lobbies.Count, list.Count);
			}
		}

		private class LobbyStateMultiSearch : LobbyStateBase
		{
			public override void OnEnter()
			{
				base.OnEnter();
				steamClient.Lobby.LobbyType = Lobby.Type.Public;
				TimeSpan timeSpan = Util.UnixTimeStampToDateTimeUtc(steamClient.Utils.GetServerRealTime()) + TimeSpan.FromSeconds(lobbyFinder.waitForFullDuration) - Util.dateZero;
				(PlatformSystems.lobbyManager as SteamworksLobbyManager).SetLobbyQuickPlayCutoffTimeIfOwner((uint)timeSpan.TotalSeconds);
			}

			public override void OnExit()
			{
				(PlatformSystems.lobbyManager as SteamworksLobbyManager).SetLobbyQuickPlayCutoffTimeIfOwner(null);
				base.OnExit();
			}

			public override void Update()
			{
				base.Update();
				if (!PlatformSystems.lobbyManager.hasMinimumPlayerCount)
				{
					outer.SetNextState(new LobbyStateSingleSearch());
				}
				else if (lobbyFinder.waitForFullDuration <= base.age)
				{
					outer.SetNextState(new LobbyStateBeginGame());
				}
			}
		}

		private class LobbyStateBeginGame : LobbyStateBase
		{
			public override void OnEnter()
			{
				base.OnEnter();
				steamClient.Lobby.LobbyType = (Lobby.Type)PlatformSystems.lobbyManager.preferredLobbyType;
				(PlatformSystems.lobbyManager as SteamworksLobbyManager).SetStartingIfOwner(startingState: true);
				string arg = "ClassicRun";
				Console.instance.SubmitCmd(null, $"transition_command \"gamemode {arg}; host 1;\"");
			}
		}

		private float age;

		public float joinOnlyDuration = 5f;

		public float waitForFullDuration = 30f;

		public float startDelayDuration = 1f;

		public float refreshInterval = 2f;

		private float refreshTimer;

		private EntityStateMachine stateMachine;

		private static SteamLobbyFinder instance;

		private static bool _userRequestedQuickplayQueue;

		private static bool _lobbyIsInQuickplayQueue;

		private static Client steamClient => Client.Instance;

		public static bool userRequestedQuickplayQueue
		{
			get
			{
				return _userRequestedQuickplayQueue;
			}
			set
			{
				if (_userRequestedQuickplayQueue != value)
				{
					_userRequestedQuickplayQueue = value;
					running = _lobbyIsInQuickplayQueue || _userRequestedQuickplayQueue;
				}
			}
		}

		private static bool lobbyIsInQuickplayQueue
		{
			get
			{
				return _lobbyIsInQuickplayQueue;
			}
			set
			{
				if (_lobbyIsInQuickplayQueue != value)
				{
					_lobbyIsInQuickplayQueue = value;
					running = _lobbyIsInQuickplayQueue || _userRequestedQuickplayQueue;
				}
			}
		}

		public static bool running
		{
			get
			{
				return instance;
			}
			private set
			{
				if ((bool)instance != value)
				{
					if (value)
					{
						instance = new GameObject("SteamLobbyFinder", typeof(SteamLobbyFinder), typeof(SetDontDestroyOnLoad)).GetComponent<SteamLobbyFinder>();
					}
					else
					{
						UnityEngine.Object.Destroy(instance.gameObject);
						instance = null;
					}
				}
			}
		}

		private void Awake()
		{
			stateMachine = base.gameObject.AddComponent<EntityStateMachine>();
			stateMachine.initialStateType = new SerializableEntityStateType(typeof(LobbyStateStart));
		}

		private void OnDestroy()
		{
			UnityEngine.Object.Destroy(stateMachine);
		}

		private void Update()
		{
			if (steamClient.Lobby.IsValid && !PlatformSystems.lobbyManager.ownsLobby)
			{
				if (stateMachine.state.GetType() != typeof(LobbyStateNonLeader))
				{
					stateMachine.SetNextState(new LobbyStateNonLeader());
				}
			}
			else
			{
				refreshTimer -= Time.unscaledDeltaTime;
				age += Time.unscaledDeltaTime;
			}
		}

		private void RequestLobbyListRefresh()
		{
			LobbyList.Filter filter = new LobbyList.Filter
			{
				StringFilters = 
				{
					["appid"] = TextSerialization.ToStringInvariant(steamClient.AppId),
					["build_id"] = RoR2Application.GetBuildId(),
					["qp"] = "1",
					["total_max_players"] = TextSerialization.ToStringInvariant(RoR2Application.maxPlayers)
				}
			};
			(PlatformSystems.lobbyManager as SteamworksLobbyManager).RequestLobbyList(this, filter, OnLobbyListReceived);
		}

		private void OnLobbyListReceived(List<LobbyList.Lobby> newLobbies)
		{
			if ((bool)this)
			{
				(stateMachine.state as LobbyStateBase)?.OnLobbiesUpdated();
			}
		}

		private static bool CanJoinLobby(int currentLobbySize, LobbyList.Lobby lobby)
		{
			return currentLobbySize + GetRealLobbyPlayerCount(lobby) <= lobby.MemberLimit;
		}

		private static int GetRealLobbyPlayerCount(LobbyList.Lobby lobby)
		{
			string data = lobby.GetData("player_count");
			if (data != null && TextSerialization.TryParseInvariant(data, out int result))
			{
				return result;
			}
			return steamClient.Lobby.MaxMembers;
		}

		private static int GetCurrentLobbyRealPlayerCount()
		{
			return PlatformSystems.lobbyManager.newestLobbyData.totalPlayerCount;
		}

		[ConCommand(commandName = "steam_quickplay_start")]
		private static void CCSteamQuickplayStart(ConCommandArgs args)
		{
			NetworkManagerSystemSteam.CheckSteamworks();
			userRequestedQuickplayQueue = true;
			(PlatformSystems.lobbyManager as SteamworksLobbyManager).SetLobbyQuickPlayQueuedIfOwner(quickplayQueuedState: true);
		}

		[ConCommand(commandName = "steam_quickplay_stop")]
		private static void CCSteamQuickplayStop(ConCommandArgs args)
		{
			NetworkManagerSystemSteam.CheckSteamworks();
			userRequestedQuickplayQueue = false;
			PlatformSystems.lobbyManager.CreateLobby();
		}

		public static void Init()
		{
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyDataUpdated = (Action)Delegate.Combine(lobbyManager.onLobbyDataUpdated, new Action(OnLobbyDataUpdated));
			NetworkManagerSystem.onStartClientGlobal += delegate
			{
				(PlatformSystems.lobbyManager as SteamworksLobbyManager).SetLobbyQuickPlayQueuedIfOwner(quickplayQueuedState: false);
				userRequestedQuickplayQueue = false;
			};
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyOwnershipGained = (Action)Delegate.Combine(lobbyManager2.onLobbyOwnershipGained, (Action)delegate
			{
				if (PlatformSystems.lobbyManager.newestLobbyData.quickplayQueued)
				{
					userRequestedQuickplayQueue = true;
				}
			});
			LobbyManager lobbyManager3 = PlatformSystems.lobbyManager;
			lobbyManager3.onLobbyOwnershipLost = (Action)Delegate.Combine(lobbyManager3.onLobbyOwnershipLost, (Action)delegate
			{
				userRequestedQuickplayQueue = false;
			});
		}

		private static void OnLobbyDataUpdated()
		{
			lobbyIsInQuickplayQueue = PlatformSystems.lobbyManager.newestLobbyData.quickplayQueued;
		}

		public static string GetResolvedStateString()
		{
			if (!steamClient.Lobby.IsValid)
			{
				return Language.GetString("STEAM_LOBBY_STATUS_NOT_IN_LOBBY");
			}
			bool flag = steamClient.Lobby.LobbyType == Lobby.Type.Public;
			if ((bool)instance)
			{
				_ = instance.stateMachine.state is LobbyStateSingleSearch;
			}
			else
				_ = 0;
			_ = PlatformSystems.lobbyManager.newestLobbyData.totalPlayerCount;
			_ = PlatformSystems.lobbyManager.newestLobbyData.totalMaxPlayers;
			_ = PlatformSystems.lobbyManager.isFull;
			string token = string.Empty;
			object[] args = Array.Empty<object>();
			if (NetworkManagerSystem.singleton.isHost || PlatformSystems.lobbyManager.state == LobbyManager.State.Hosting)
			{
				token = "STEAM_LOBBY_STATUS_STARTING_SERVER";
			}
			else if (PlatformSystems.lobbyManager.newestLobbyData.starting)
			{
				token = "STEAM_LOBBY_STATUS_GAME_STARTING";
			}
			else if (PlatformSystems.lobbyManager.newestLobbyData.shouldConnect)
			{
				token = "STEAM_LOBBY_STATUS_CONNECTING_TO_HOST";
			}
			else if ((bool)instance && instance.stateMachine.state is LobbyStateStart)
			{
				token = "STEAM_LOBBY_STATUS_LAUNCHING_QUICKPLAY";
			}
			else if (PlatformSystems.lobbyManager.isInLobby)
			{
				if (PlatformSystems.lobbyManager.newestLobbyData.quickplayQueued)
				{
					if (!flag)
					{
						token = "STEAM_LOBBY_STATUS_QUICKPLAY_SEARCHING_FOR_EXISTING_LOBBY";
					}
					else
					{
						DateTime dateTime = Util.UnixTimeStampToDateTimeUtc(steamClient.Utils.GetServerRealTime());
						DateTime? quickplayCutoffTime = PlatformSystems.lobbyManager.newestLobbyData.quickplayCutoffTime;
						if (!quickplayCutoffTime.HasValue)
						{
							token = "STEAM_LOBBY_STATUS_QUICKPLAY_WAITING_BELOW_MINIMUM_PLAYERS";
							args = new object[2]
							{
								PlatformSystems.lobbyManager.newestLobbyData.totalPlayerCount,
								PlatformSystems.lobbyManager.newestLobbyData.totalMaxPlayers
							};
						}
						else
						{
							TimeSpan timeSpan = quickplayCutoffTime.Value - dateTime;
							token = "STEAM_LOBBY_STATUS_QUICKPLAY_WAITING_ABOVE_MINIMUM_PLAYERS";
							args = new object[3]
							{
								PlatformSystems.lobbyManager.newestLobbyData.totalPlayerCount,
								PlatformSystems.lobbyManager.newestLobbyData.totalMaxPlayers,
								Math.Max(0.0, timeSpan.TotalSeconds)
							};
						}
					}
				}
				else
				{
					token = "STEAM_LOBBY_STATUS_OUT_OF_QUICKPLAY";
				}
			}
			return Language.GetStringFormatted(token, args);
		}
	}
	public class SteamNetworkClient : NetworkClient
	{
		public SteamNetworkConnection steamConnection => (SteamNetworkConnection)base.connection;

		public string status => m_AsyncConnect.ToString();

		public void Connect()
		{
			Connect("localhost", 0);
			m_AsyncConnect = ConnectState.Connected;
			base.connection.ForceInitialize(base.hostTopology);
		}

		public SteamNetworkClient(NetworkConnection conn)
			: base(conn)
		{
			SetNetworkConnectionClass<SteamNetworkConnection>();
		}
	}
	public class SteamNetworkConnection : NetworkConnection
	{
		private BaseSteamworks steamworks;

		private Facepunch.Steamworks.Networking networking;

		private static List<SteamNetworkConnection> instancesList = new List<SteamNetworkConnection>();

		public bool ignore;

		public uint rtt;

		public static BoolConVar cvNetP2PDebugTransport = new BoolConVar("net_p2p_debug_transport", ConVarFlags.None, "0", "Allows p2p transport information to print to the console.");

		private static BoolConVar cvNetP2PLogMessages = new BoolConVar("net_p2p_log_messages", ConVarFlags.None, "0", "Enables logging of network messages.");

		public PlatformID myId { get; private set; }

		public PlatformID steamId { get; private set; }

		public SteamNetworkConnection()
		{
		}

		public SteamNetworkConnection([NotNull] BaseSteamworks steamworks, PlatformID endpointId)
		{
			myId = new PlatformID((steamworks as Client)?.SteamId ?? (steamworks as Server)?.SteamId ?? 0);
			steamId = endpointId;
			this.steamworks = steamworks;
			networking = steamworks.Networking;
			networking.CloseSession(endpointId.ID);
			instancesList.Add(this);
		}

		public bool SendConnectionRequest()
		{
			return networking.SendP2PPacket(steamId.ID, null, 0);
		}

		public override bool TransportSend(byte[] bytes, int numBytes, int channelId, out byte error)
		{
			if (ignore)
			{
				error = 0;
				return true;
			}
			logNetworkMessages = cvNetP2PLogMessages.value;
			if (steamId == myId)
			{
				TransportReceive(bytes, numBytes, channelId);
				error = 0;
				if (cvNetP2PDebugTransport.value)
				{
					UnityEngine.Debug.LogFormat("SteamNetworkConnection.TransportSend steamId=self numBytes={1} channelId={2}", numBytes, channelId);
				}
				return true;
			}
			Facepunch.Steamworks.Networking.SendType eP2PSendType = Facepunch.Steamworks.Networking.SendType.Reliable;
			QosType qOS = PlatformSystems.networkManager.connectionConfig.Channels[channelId].QOS;
			if (qOS == QosType.Unreliable || qOS == QosType.UnreliableFragmented || qOS == QosType.UnreliableSequenced)
			{
				eP2PSendType = Facepunch.Steamworks.Networking.SendType.Unreliable;
			}
			if (networking.SendP2PPacket(steamId.ID, bytes, numBytes, eP2PSendType))
			{
				error = 0;
				if (cvNetP2PDebugTransport.value)
				{
					UnityEngine.Debug.LogFormat("SteamNetworkConnection.TransportSend steamId={0} numBytes={1} channelId={2} error={3}", steamId.value, numBytes, channelId, error);
				}
				return true;
			}
			error = 1;
			if (cvNetP2PDebugTransport.value)
			{
				UnityEngine.Debug.LogFormat("SteamNetworkConnection.TransportSend steamId={0} numBytes={1} channelId={2} error={3}", steamId.value, numBytes, channelId, error);
			}
			return false;
		}

		public override void TransportReceive(byte[] bytes, int numBytes, int channelId)
		{
			if (!ignore)
			{
				logNetworkMessages = cvNetP2PLogMessages.value;
				base.TransportReceive(bytes, numBytes, channelId);
			}
		}

		protected override void Dispose(bool disposing)
		{
			instancesList.Remove(this);
			if (networking != null && steamId.ID != 0L)
			{
				networking.CloseSession(steamId.ID);
				steamId = PlatformID.nil;
			}
			base.Dispose(disposing);
		}

		public static SteamNetworkConnection Find(BaseSteamworks owner, PlatformID endpoint)
		{
			for (int i = 0; i < instancesList.Count; i++)
			{
				SteamNetworkConnection steamNetworkConnection = instancesList[i];
				if (steamNetworkConnection.steamId == endpoint && owner == steamNetworkConnection.steamworks)
				{
					return steamNetworkConnection;
				}
			}
			return null;
		}
	}
	public static class UNETExtensions
	{
		public static void ForceInitialize(this NetworkConnection conn, HostTopology hostTopology)
		{
			int num = 0;
			conn.Initialize("localhost", num, num, hostTopology);
		}
	}
	[MeansImplicitUse]
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
	public class NetworkMessageHandlerAttribute : HG.Reflection.SearchableAttribute
	{
		public short msgType;

		public bool server;

		public bool client;

		private NetworkMessageDelegate messageHandler;

		private static List<NetworkMessageHandlerAttribute> clientMessageHandlers = new List<NetworkMessageHandlerAttribute>();

		private static List<NetworkMessageHandlerAttribute> serverMessageHandlers = new List<NetworkMessageHandlerAttribute>();

		[InitDuringStartup]
		private static void CollectHandlers()
		{
			clientMessageHandlers.Clear();
			serverMessageHandlers.Clear();
			HashSet<short> hashSet = new HashSet<short>();
			foreach (NetworkMessageHandlerAttribute instance in HG.Reflection.SearchableAttribute.GetInstances<NetworkMessageHandlerAttribute>())
			{
				MethodInfo methodInfo = instance.target as MethodInfo;
				if (methodInfo == null || !methodInfo.IsStatic)
				{
					continue;
				}
				instance.messageHandler = (NetworkMessageDelegate)Delegate.CreateDelegate(typeof(NetworkMessageDelegate), methodInfo);
				if (instance.messageHandler != null)
				{
					if (instance.client)
					{
						clientMessageHandlers.Add(instance);
						hashSet.Add(instance.msgType);
					}
					if (instance.server)
					{
						serverMessageHandlers.Add(instance);
						hashSet.Add(instance.msgType);
					}
				}
				if (instance.messageHandler == null)
				{
					UnityEngine.Debug.LogWarningFormat("Could not register message handler for {0}. The function signature is likely incorrect.", methodInfo.Name);
				}
				if (!instance.client && !instance.server)
				{
					UnityEngine.Debug.LogWarningFormat("Could not register message handler for {0}. It is marked as neither server nor client.", methodInfo.Name);
				}
			}
			for (short num = 48; num < 80; num++)
			{
				if (!hashSet.Contains(num))
				{
					UnityEngine.Debug.LogWarningFormat("Network message MsgType.Highest + {0} is unregistered.", num - 47);
				}
			}
		}

		public static void RegisterServerMessages()
		{
			foreach (NetworkMessageHandlerAttribute serverMessageHandler in serverMessageHandlers)
			{
				NetworkServer.RegisterHandler(serverMessageHandler.msgType, serverMessageHandler.messageHandler);
			}
		}

		public static void RegisterClientMessages(NetworkClient client)
		{
			foreach (NetworkMessageHandlerAttribute clientMessageHandler in clientMessageHandlers)
			{
				client.RegisterHandler(clientMessageHandler.msgType, clientMessageHandler.messageHandler);
			}
		}
	}
	public class UmsgType
	{
		public const short Lowest = 48;

		public const short SetEntityState = 48;

		public const short PlayerFireProjectile = 49;

		public const short ReleaseProjectilePredictionId = 50;

		public const short CharacterTransformUpdate = 51;

		public const short Effect = 52;

		public const short BulletDamage = 53;

		public const short UpdateTime = 54;

		public const short CreateExpEffect = 55;

		public const short ResetSkills = 56;

		public const short PickupItem = 57;

		public const short StatsUpdate = 58;

		public const short BroadcastChat = 59;

		public const short DamageDealt = 60;

		public const short Heal = 61;

		public const short ConstructTurret = 62;

		public const short AmmoPackPickup = 63;

		public const short Test = 64;

		public const short Ping = 65;

		public const short PingResponse = 66;

		public const short Kick = 67;

		public const short Teleport = 68;

		public const short SetJetpackJumpState = 69;

		public const short PreGameRuleVoteControllerSendClientVotes = 70;

		public const short OverlapAttackHits = 71;

		public const short EmitPointSound = 72;

		public const short EmitEntitySound = 73;

		public const short SetClientAuth = 74;

		public const short ReportBlastAttackDamage = 75;

		public const short NetworkUIPromptMessage = 76;

		public const short ReportMercFocusedAssaultHitReplaceMeLater = 77;

		public const short TransformPickup = 78;

		public const short Pause = 79;

		public const short TransmitWokDataToServer = 80;

		public const short Highest = 80;
	}
	public class EOSNetworkClient : NetworkClient
	{
		public EOSNetworkConnection eosConnection => (EOSNetworkConnection)base.connection;

		public string status => m_AsyncConnect.ToString();

		public void Connect()
		{
			Connect("localhost", 0);
			m_AsyncConnect = ConnectState.Connected;
			base.connection.ForceInitialize(base.hostTopology);
		}

		public EOSNetworkClient(NetworkConnection conn)
			: base(conn)
		{
			SetNetworkConnectionClass<EOSNetworkConnection>();
		}
	}
	public class EOSNetworkConnection : NetworkConnection
	{
		private static List<EOSNetworkConnection> instancesList = new List<EOSNetworkConnection>();

		public bool ignore;

		public static BoolConVar cvNetP2PDebugTransport = new BoolConVar("net_p2p_debug_transport", ConVarFlags.None, "0", "Allows p2p transport information to print to the console.");

		private static BoolConVar cvNetP2PLogMessages = new BoolConVar("net_p2p_log_messages", ConVarFlags.None, "0", "Enables logging of network messages.");

		public ProductUserId LocalUserID { get; }

		public ProductUserId RemoteUserID { get; private set; }

		public EOSNetworkConnection()
		{
		}

		public EOSNetworkConnection(ProductUserId localUserID, ProductUserId remoteUserID)
		{
			LocalUserID = localUserID;
			RemoteUserID = remoteUserID;
			instancesList.Add(this);
		}

		public bool SendConnectionRequest()
		{
			SendPacketOptions sendPacketOptions = default(SendPacketOptions);
			sendPacketOptions.LocalUserId = LocalUserID;
			sendPacketOptions.RemoteUserId = RemoteUserID;
			sendPacketOptions.AllowDelayedDelivery = true;
			sendPacketOptions.Channel = 0;
			sendPacketOptions.Reliability = PacketReliability.ReliableOrdered;
			sendPacketOptions.SocketId = NetworkManagerSystemEOS.socketId;
			SendPacketOptions options = sendPacketOptions;
			return NetworkManagerSystemEOS.P2pInterface.SendPacket(ref options) == Result.Success;
		}

		public override bool TransportSend(byte[] bytes, int numBytes, int channelId, out byte error)
		{
			if (ignore)
			{
				error = 0;
				return true;
			}
			logNetworkMessages = cvNetP2PLogMessages.value;
			if (LocalUserID == RemoteUserID)
			{
				TransportReceive(bytes, numBytes, channelId);
				error = 0;
				_ = cvNetP2PDebugTransport.value;
				return true;
			}
			QosType qOS = NetworkManagerSystem.singleton.connectionConfig.Channels[channelId].QOS;
			PacketReliability packetReliability = PacketReliability.ReliableOrdered;
			packetReliability = ((qOS != 0 && qOS != QosType.UnreliableFragmented && qOS != QosType.UnreliableSequenced) ? PacketReliability.ReliableOrdered : PacketReliability.UnreliableUnordered);
			ArraySegment<byte> data = new ArraySegment<byte>(bytes, 0, numBytes);
			SendPacketOptions sendPacketOptions = default(SendPacketOptions);
			sendPacketOptions.AllowDelayedDelivery = true;
			sendPacketOptions.Data = data;
			sendPacketOptions.Channel = 0;
			sendPacketOptions.LocalUserId = LocalUserID;
			sendPacketOptions.RemoteUserId = RemoteUserID;
			sendPacketOptions.SocketId = NetworkManagerSystemEOS.socketId;
			sendPacketOptions.Reliability = packetReliability;
			SendPacketOptions options = sendPacketOptions;
			if (NetworkManagerSystemEOS.P2pInterface.SendPacket(ref options) == Result.Success)
			{
				error = 0;
				return true;
			}
			error = 1;
			return false;
		}

		public override void TransportReceive(byte[] bytes, int numBytes, int channelId)
		{
			if (!ignore)
			{
				logNetworkMessages = cvNetP2PLogMessages.value;
				base.TransportReceive(bytes, numBytes, channelId);
			}
		}

		protected override void Dispose(bool disposing)
		{
			instancesList.Remove(this);
			P2PInterface p2PInterface = EOSPlatformManager.GetPlatformInterface().GetP2PInterface();
			if (p2PInterface != null)
			{
				CloseConnectionOptions closeConnectionOptions = default(CloseConnectionOptions);
				closeConnectionOptions.LocalUserId = LocalUserID;
				closeConnectionOptions.RemoteUserId = RemoteUserID;
				closeConnectionOptions.SocketId = NetworkManagerSystemEOS.socketId;
				CloseConnectionOptions options = closeConnectionOptions;
				p2PInterface.CloseConnection(ref options);
			}
			base.Dispose(disposing);
		}

		public static EOSNetworkConnection Find(ProductUserId owner, ProductUserId endpoint)
		{
			return instancesList.Where((EOSNetworkConnection instance) => instance.RemoteUserID == endpoint).FirstOrDefault((EOSNetworkConnection instance) => (object)owner == instance.LocalUserID);
		}
	}
	public class NetworkManagerSystemEOS : NetworkManagerSystem
	{
		public ProductUserId myUserId;

		private int packetsRecieved;

		private Dictionary<ulong, byte> sequenceNumber = new Dictionary<ulong, byte>();

		private Dictionary<ulong, List<Tuple<byte, byte[], uint>>> outOfOrderPackets = new Dictionary<ulong, List<Tuple<byte, byte[], uint>>>();

		private List<ProductUserId> epicIdBanList = new List<ProductUserId>();

		public static SocketId socketId = new SocketId
		{
			SocketName = "RoR2EOS"
		};

		public static P2PInterface P2pInterface { get; private set; }

		protected override void Start()
		{
			myUserId = null;
			foreach (QosType channel in base.channels)
			{
				base.connectionConfig.AddChannel(channel);
			}
			base.connectionConfig.PacketSize = 1200;
			StartCoroutine(FireOnStartGlobalEvent());
		}

		protected override void Update()
		{
			if (!(EOSLoginManager.loggedInProductId == null))
			{
				UpdateTime(ref _unpredictedServerFrameTime, ref _unpredictedServerFrameTimeSmoothed, ref unpredictedServerFrameTimeVelocity, Time.deltaTime);
				EnsureDesiredHost();
				UpdateServer();
				UpdateClient();
				UpdateNetworkReceiveLoop();
			}
		}

		public void ResetSequencing()
		{
			packetsRecieved = 0;
			sequenceNumber.Clear();
			outOfOrderPackets.Clear();
		}

		private void UpdateNetworkReceiveLoop()
		{
			if (!(P2pInterface == null))
			{
				byte[] array = new byte[base.connectionConfig.PacketSize];
				ArraySegment<byte> arraySegment = new ArraySegment<byte>(array);
				int num = 0;
				bool flag = true;
				while (flag)
				{
					ReceivePacketOptions receivePacketOptions = default(ReceivePacketOptions);
					receivePacketOptions.LocalUserId = EOSLoginManager.loggedInProductId;
					receivePacketOptions.MaxDataSizeBytes = base.connectionConfig.PacketSize;
					ReceivePacketOptions options = receivePacketOptions;
					num++;
					ProductUserId outPeerId;
					SocketId outSocketId;
					byte outChannel;
					uint outBytesWritten;
					Result result = P2pInterface.ReceivePacket(ref options, out outPeerId, out outSocketId, out outChannel, arraySegment, out outBytesWritten);
					flag = ProcessData(result, outPeerId, arraySegment, (int)outBytesWritten, outChannel);
				}
			}
		}

		private bool ProcessData(Result result, ProductUserId incomingUserId, ArraySegment<byte> buf, int outBytesWritten, int channelId)
		{
			switch (result)
			{
			case Result.Success:
			{
				EOSNetworkConnection eOSNetworkConnection = EOSNetworkConnection.Find(myUserId, incomingUserId);
				if (eOSNetworkConnection != null)
				{
					eOSNetworkConnection.TransportReceive(buf.Array, outBytesWritten, 0);
				}
				else
				{
					UnityEngine.Debug.LogFormat("Rejecting data from sender: Not associated with a registered connection. id={0} dataLength={1}", incomingUserId, buf.Count);
				}
				return true;
			}
			case Result.InvalidParameters:
			case Result.NotFound:
				return false;
			default:
				UnityEngine.Debug.LogError("P2PInterface ReceivePacket returned a failure: " + result);
				return false;
			}
		}

		protected override void EnsureDesiredHost()
		{
			if (false | serverShuttingDown | base.clientIsConnecting | (NetworkServer.active && NetworkManagerSystem.isLoadingScene) | (!NetworkClient.active && NetworkManagerSystem.isLoadingScene))
			{
				return;
			}
			bool isAnyUserSignedIn = LocalUserManager.isAnyUserSignedIn;
			if (base.desiredHost.isRemote && !isAnyUserSignedIn)
			{
				return;
			}
			if (isNetworkActive && !actedUponDesiredHost && !base.desiredHost.DescribesCurrentHost())
			{
				Disconnect();
			}
			else
			{
				if (actedUponDesiredHost)
				{
					return;
				}
				int maxPlayers = RoR2Application.maxPlayers;
				if (base.desiredHost.hostType == HostDescription.HostType.Self)
				{
					if (NetworkServer.active)
					{
						return;
					}
					actedUponDesiredHost = true;
					base.maxConnections = base.desiredHost.hostingParameters.maxPlayers;
					NetworkServer.dontListen = !base.desiredHost.hostingParameters.listen;
					if (!isAnyUserSignedIn)
					{
						StartServer(base.connectionConfig, maxPlayers);
					}
					else
					{
						StartHost(base.connectionConfig, maxPlayers);
					}
				}
				if (base.desiredHost.hostType == HostDescription.HostType.EOS && Time.unscaledTime - lastDesiredHostSetTime >= 0f)
				{
					actedUponDesiredHost = true;
					StartClient(base.desiredHost.userID.productUserID);
				}
				if (base.desiredHost.hostType == HostDescription.HostType.IPv4 && Time.unscaledTime - lastDesiredHostSetTime >= 0f)
				{
					actedUponDesiredHost = true;
					UnityEngine.Debug.LogFormat("Attempting connection. ip={0} port={1}", base.desiredHost.addressPortPair.address, base.desiredHost.addressPortPair.port);
					NetworkManagerSystem.singleton.networkAddress = base.desiredHost.addressPortPair.address;
					NetworkManagerSystem.singleton.networkPort = base.desiredHost.addressPortPair.port;
					NetworkManagerSystem.singleton.StartClient(matchInfo, base.connectionConfig);
				}
			}
		}

		public override void ForceCloseAllConnections()
		{
			foreach (NetworkConnection connection in NetworkServer.connections)
			{
				if (connection is EOSNetworkConnection eOSNetworkConnection)
				{
					CloseConnectionOptions closeConnectionOptions = default(CloseConnectionOptions);
					closeConnectionOptions.LocalUserId = eOSNetworkConnection.LocalUserID;
					closeConnectionOptions.RemoteUserId = eOSNetworkConnection.RemoteUserID;
					closeConnectionOptions.SocketId = socketId;
					CloseConnectionOptions options = closeConnectionOptions;
					P2pInterface.CloseConnection(ref options);
				}
			}
			if (client?.connection is EOSNetworkConnection eOSNetworkConnection2)
			{
				CloseConnectionOptions closeConnectionOptions = default(CloseConnectionOptions);
				closeConnectionOptions.LocalUserId = eOSNetworkConnection2.LocalUserID;
				closeConnectionOptions.RemoteUserId = eOSNetworkConnection2.RemoteUserID;
				closeConnectionOptions.SocketId = socketId;
				CloseConnectionOptions options2 = closeConnectionOptions;
				P2pInterface.CloseConnection(ref options2);
			}
			myUserId = null;
		}

		public override NetworkConnection GetClient(PlatformID clientID)
		{
			if (!NetworkServer.active)
			{
				return null;
			}
			if (clientID.productUserID == myUserId && NetworkServer.connections.Count > 0)
			{
				return NetworkServer.connections[0];
			}
			foreach (NetworkConnection connection in NetworkServer.connections)
			{
				if (connection is EOSNetworkConnection eOSNetworkConnection && eOSNetworkConnection.RemoteUserID == clientID.productUserID)
				{
					return eOSNetworkConnection;
				}
			}
			UnityEngine.Debug.LogError("Client not found");
			return null;
		}

		public override void OnServerConnect(NetworkConnection conn)
		{
			base.OnServerConnect(conn);
			if (NetworkUser.readOnlyInstancesList.Count >= base.maxConnections)
			{
				ServerKickClient(conn, new SimpleLocalizedKickReason("KICK_REASON_SERVERFULL"));
			}
			else
			{
				FireServerConnectGlobalEvent(conn);
			}
		}

		public override void OnServerDisconnect(NetworkConnection conn)
		{
			if (conn == null)
			{
				return;
			}
			FireServerDisconnectGlobalEvent(conn);
			if (conn?.clientOwnedObjects != null)
			{
				foreach (NetworkInstanceId item in new HashSet<NetworkInstanceId>(conn.clientOwnedObjects))
				{
					if (item.IsEmpty())
					{
						break;
					}
					GameObject gameObject = NetworkServer.FindLocalObject(item);
					if (gameObject != null && (bool)gameObject.GetComponent<CharacterMaster>() && gameObject.TryGetComponent<NetworkIdentity>(out var component) && component.clientAuthorityOwner == conn)
					{
						component.RemoveClientAuthority(conn);
					}
				}
			}
			List<UnityEngine.Networking.PlayerController> list = conn?.playerControllers;
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i]?.gameObject != null && list[i].gameObject.TryGetComponent<NetworkUser>(out var component2))
				{
					Chat.SendPlayerDisconnectedMessage(component2);
				}
			}
			if (conn is EOSNetworkConnection eOSNetworkConnection)
			{
				_ = eOSNetworkConnection.RemoteUserID != null;
			}
			base.OnServerDisconnect(conn);
		}

		public override void OnStartServer()
		{
			base.OnStartServer();
			ServerManagerBase<EOSServerManager>.StartServer();
			InitP2P();
			NetworkMessageHandlerAttribute.RegisterServerMessages();
			InitializeTime();
			if (NetworkManager.singleton == null)
			{
				serverNetworkSessionInstance = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkSession"));
			}
			else
			{
				serverNetworkSessionInstance = NetworkManager.singleton.gameObject;
			}
			FireStartServerGlobalEvent();
		}

		public override void OnStopServer()
		{
			FireStopServerGlobalEvent();
			for (int i = 0; i < NetworkServer.connections.Count; i++)
			{
				NetworkConnection networkConnection = NetworkServer.connections[i];
				if (networkConnection != null)
				{
					OnServerDisconnect(networkConnection);
				}
			}
			serverNetworkSessionInstance = null;
			ServerManagerBase<EOSServerManager>.StopServer();
			myUserId = null;
			base.OnStopServer();
		}

		public override void ServerBanClient(NetworkConnection conn)
		{
			if (conn is EOSNetworkConnection eOSNetworkConnection)
			{
				epicIdBanList.Add(eOSNetworkConnection.RemoteUserID);
			}
		}

		protected override NetworkUserId AddPlayerIdFromPlatform(NetworkConnection conn, AddPlayerMessage message, byte playerControllerId)
		{
			NetworkUserId result = NetworkUserId.FromIp(conn.address, playerControllerId);
			PlatformID? platformID = ServerAuthManager.FindAuthData(conn)?.platformId;
			if (platformID.HasValue)
			{
				if (platformID.Value.isSteam)
				{
					UnityEngine.Debug.LogError("THIS SHOULD NOT HAPPEN INSIDE AN EOS GAME!");
				}
				result = new NetworkUserId(platformID.Value.stringID, playerControllerId);
			}
			return result;
		}

		protected override void KickClient(NetworkConnection conn, BaseKickReason reason)
		{
			if (conn is EOSNetworkConnection eOSNetworkConnection)
			{
				eOSNetworkConnection.ignore = true;
			}
		}

		public override void ServerHandleClientDisconnect(NetworkConnection conn)
		{
			OnServerDisconnect(conn);
			conn.InvokeHandlerNoData(33);
			conn.Disconnect();
			conn.Dispose();
			if (conn is EOSNetworkConnection)
			{
				NetworkServer.RemoveExternalConnection(conn.connectionId);
			}
		}

		protected override void UpdateServer()
		{
		}

		public override void OnStartClient(NetworkClient newClient)
		{
			base.OnStartClient(newClient);
			InitP2P();
		}

		public override void OnClientDisconnect(NetworkConnection conn)
		{
			if (conn is EOSNetworkConnection eOSNetworkConnection)
			{
				UnityEngine.Debug.LogFormat("Closing connection with remote ID: {0}", eOSNetworkConnection.RemoteUserID);
			}
			base.OnClientDisconnect(conn);
		}

		protected override AddPlayerMessage CreateClientAddPlayerMessage()
		{
			if (client != null)
			{
				return new AddPlayerMessage
				{
					id = new PlatformID(EOSLoginManager.loggedInProductId),
					steamAuthTicketData = Array.Empty<byte>()
				};
			}
			return new AddPlayerMessage
			{
				id = default(PlatformID),
				steamAuthTicketData = Array.Empty<byte>()
			};
		}

		protected override void UpdateCheckInactiveConnections()
		{
		}

		protected override void StartClient(PlatformID serverID)
		{
			StartClient(serverID.productUserID);
		}

		protected override void PlatformAuth(ref ClientAuthData authData, NetworkConnection conn)
		{
			authData.platformId = new PlatformID(EOSLoginManager.loggedInProductId);
			authData.entitlements = PlatformSystems.entitlementsSystem.BuildEntitlements();
			authData.authTicket = Client.Instance.Auth.GetAuthSessionTicket().Data;
		}

		private void StartClient(ProductUserId remoteUserId)
		{
			if (!NetworkServer.active)
			{
				NetworkManager.networkSceneName = "";
			}
			string text = "";
			if (isNetworkActive)
			{
				text += "isNetworkActive ";
			}
			if (NetworkClient.active)
			{
				text += "NetworkClient.active ";
			}
			if (NetworkServer.active)
			{
				text += "NetworkClient.active ";
			}
			if (NetworkManagerSystem.isLoadingScene)
			{
				text += "isLoadingScene ";
			}
			if (text != "")
			{
				RoR2Application.onNextUpdate += delegate
				{
				};
			}
			EOSNetworkConnection eOSNetworkConnection = new EOSNetworkConnection(EOSLoginManager.loggedInProductId, remoteUserId);
			EOSNetworkClient eOSNetworkClient = new EOSNetworkClient(eOSNetworkConnection);
			eOSNetworkClient.Configure(base.connectionConfig, 1);
			UseExternalClient(eOSNetworkClient);
			eOSNetworkClient.Connect();
			UnityEngine.Debug.LogFormat("Initiating connection to server {0}...", remoteUserId);
			if (!eOSNetworkConnection.SendConnectionRequest())
			{
				UnityEngine.Debug.LogFormat("Failed to send connection request to server {0}.", remoteUserId);
			}
		}

		public override bool IsConnectedToServer(PlatformID serverID)
		{
			if (client == null || !client.connection.isConnected)
			{
				return false;
			}
			if (client.connection is EOSNetworkConnection eOSNetworkConnection)
			{
				return eOSNetworkConnection.RemoteUserID == serverID.productUserID;
			}
			if (client.connection.address == "localServer")
			{
				return serverID == base.serverP2PId;
			}
			return false;
		}

		private void OnConnectionRequested(ref OnIncomingConnectionRequestInfo connectionRequestInfo)
		{
			bool flag = false;
			if (connectionRequestInfo.SocketId.Value.SocketName == socketId.SocketName)
			{
				if (NetworkServer.active)
				{
					flag = !NetworkServer.dontListen && !epicIdBanList.Contains(connectionRequestInfo.RemoteUserId) && !IsServerAtMaxConnections();
				}
				else if (client is EOSNetworkClient eOSNetworkClient && eOSNetworkClient.eosConnection.RemoteUserID == connectionRequestInfo.RemoteUserId)
				{
					flag = true;
				}
			}
			if (flag)
			{
				AcceptConnectionOptions acceptConnectionOptions = default(AcceptConnectionOptions);
				acceptConnectionOptions.LocalUserId = connectionRequestInfo.LocalUserId;
				acceptConnectionOptions.RemoteUserId = connectionRequestInfo.RemoteUserId;
				acceptConnectionOptions.SocketId = socketId;
				AcceptConnectionOptions options = acceptConnectionOptions;
				P2pInterface.AcceptConnection(ref options);
				CreateServerP2PConnectionWithPeer(connectionRequestInfo.RemoteUserId);
			}
		}

		public void CreateServerP2PConnectionWithPeer(ProductUserId peer)
		{
			EOSNetworkConnection eOSNetworkConnection = new EOSNetworkConnection(myUserId, peer);
			eOSNetworkConnection.ForceInitialize(NetworkServer.hostTopology);
			int num = -1;
			ReadOnlyCollection<NetworkConnection> connections = NetworkServer.connections;
			for (int i = 1; i < connections.Count; i++)
			{
				if (connections[i] == null)
				{
					num = i;
					break;
				}
			}
			if (num == -1)
			{
				num = connections.Count;
			}
			eOSNetworkConnection.connectionId = num;
			NetworkServer.AddExternalConnection(eOSNetworkConnection);
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.StartMessage(32);
			networkWriter.FinishMessage();
			eOSNetworkConnection.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
		}

		protected void InitP2P()
		{
			if (P2pInterface == null)
			{
				P2pInterface = EOSPlatformManager.GetPlatformInterface().GetP2PInterface();
				AddNotifyPeerConnectionRequestOptions addNotifyPeerConnectionRequestOptions = default(AddNotifyPeerConnectionRequestOptions);
				addNotifyPeerConnectionRequestOptions.LocalUserId = EOSLoginManager.loggedInProductId;
				addNotifyPeerConnectionRequestOptions.SocketId = socketId;
				AddNotifyPeerConnectionRequestOptions options = addNotifyPeerConnectionRequestOptions;
				P2pInterface.AddNotifyPeerConnectionRequest(ref options, null, OnConnectionRequested);
				AddNotifyPeerConnectionClosedOptions addNotifyPeerConnectionClosedOptions = default(AddNotifyPeerConnectionClosedOptions);
				addNotifyPeerConnectionClosedOptions.LocalUserId = EOSLoginManager.loggedInProductId;
				addNotifyPeerConnectionClosedOptions.SocketId = socketId;
				AddNotifyPeerConnectionClosedOptions options2 = addNotifyPeerConnectionClosedOptions;
				P2pInterface.AddNotifyPeerConnectionClosed(ref options2, null, OnConnectionClosed);
			}
			myUserId = EOSLoginManager.loggedInProductId;
			base.serverP2PId = new PlatformID(myUserId);
		}

		private void OnConnectionClosed(ref OnRemoteConnectionClosedInfo connectionRequestInfo)
		{
			EOSNetworkConnection eOSNetworkConnection = EOSNetworkConnection.Find(myUserId, connectionRequestInfo.RemoteUserId);
			if (client != null && client.connection == eOSNetworkConnection)
			{
				eOSNetworkConnection.InvokeHandlerNoData(33);
				eOSNetworkConnection.Disconnect();
				eOSNetworkConnection.Dispose();
			}
			if (NetworkServer.active && NetworkServer.connections.IndexOf(eOSNetworkConnection) != -1)
			{
				ServerHandleClientDisconnect(eOSNetworkConnection);
			}
		}

		protected override void PlatformClientSetPlayers(ConCommandArgs args)
		{
			if (client != null && client.connection != null)
			{
				ClientSetPlayers(client.connection);
			}
		}

		protected override void PlatformConnectP2P(ConCommandArgs args)
		{
		}

		protected override void PlatformDisconnect(ConCommandArgs args)
		{
			NetworkManagerSystem.singleton.desiredHost = HostDescription.none;
		}

		protected override void PlatformConnect(ConCommandArgs args)
		{
			AddressPortPair argAddressPortPair = args.GetArgAddressPortPair(0);
			if ((bool)NetworkManagerSystem.singleton)
			{
				NetworkManagerSystem.EnsureNetworkManagerNotBusy();
				UnityEngine.Debug.LogFormat("Parsed address={0} port={1}. Setting desired host.", argAddressPortPair.address, argAddressPortPair.port);
				NetworkManagerSystem.singleton.desiredHost = new HostDescription(argAddressPortPair);
			}
		}

		protected override void PlatformHost(ConCommandArgs args)
		{
			if (!NetworkManagerSystem.singleton)
			{
				return;
			}
			bool argBool = args.GetArgBool(0);
			if (PlatformSystems.lobbyManager.isInLobby && !PlatformSystems.lobbyManager.ownsLobby)
			{
				return;
			}
			bool flag = false;
			if (NetworkServer.active)
			{
				flag = true;
			}
			if (!flag)
			{
				int maxPlayers = SvMaxPlayersConVar.instance.intValue;
				if (PlatformSystems.lobbyManager.isInLobby)
				{
					LobbyDetailsCopyInfoOptions options = default(LobbyDetailsCopyInfoOptions);
					maxPlayers = (int)(((PlatformSystems.lobbyManager as EOSLobbyManager).CurrentLobbyDetails.CopyInfo(ref options, out var outLobbyDetailsInfo) == Result.Success) ? outLobbyDetailsInfo.Value.MaxMembers : 0);
				}
				NetworkManagerSystem.singleton.desiredHost = new HostDescription(new HostDescription.HostingParameters
				{
					listen = argBool,
					maxPlayers = maxPlayers
				});
			}
		}

		protected override void PlatformGetP2PSessionState(ConCommandArgs args)
		{
			CheckSteamworks();
			args.GetArgPlatformID(0);
			_ = (bool)NetworkManagerSystem.singleton;
		}

		protected override void PlatformKick(ConCommandArgs args)
		{
			CheckSteamworks();
			PlatformID argPlatformID = args.GetArgPlatformID(0);
			NetworkConnection networkConnection = NetworkManagerSystem.singleton.GetClient(argPlatformID);
			if (networkConnection != null)
			{
				NetworkManagerSystem.singleton.ServerKickClient(networkConnection, new SimpleLocalizedKickReason("KICK_REASON_KICK"));
			}
		}

		protected override void PlatformBan(ConCommandArgs args)
		{
			CheckSteamworks();
			PlatformID argPlatformID = args.GetArgPlatformID(0);
			NetworkConnection networkConnection = NetworkManagerSystem.singleton.GetClient(argPlatformID);
			if (networkConnection != null)
			{
				NetworkManagerSystem.singleton.ServerBanClient(networkConnection);
				NetworkManagerSystem.singleton.ServerKickClient(networkConnection, new SimpleLocalizedKickReason("KICK_REASON_BAN"));
			}
		}

		public static void CheckSteamworks()
		{
			if (Client.Instance == null)
			{
				throw new ConCommandException("Steamworks not available.");
			}
		}

		public override void CreateLocalLobby()
		{
		}
	}
	public abstract class NetworkManagerSystem : NetworkManager
	{
		public enum CanPlayOnlineState
		{
			Pending,
			Yes,
			No
		}

		private class NetLogLevelConVar : BaseConVar
		{
			private static NetLogLevelConVar cvNetLogLevel = new NetLogLevelConVar("net_loglevel", ConVarFlags.Engine, null, "Network log verbosity.");

			public NetLogLevelConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (TextSerialization.TryParseInvariant(newValue, out int result))
				{
					LogFilter.currentLogLevel = result;
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(LogFilter.currentLogLevel);
			}
		}

		private class SvListenConVar : BaseConVar
		{
			private static SvListenConVar cvSvListen = new SvListenConVar("sv_listen", ConVarFlags.Engine, null, "Whether or not the server will accept connections from other players.");

			public SvListenConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (!NetworkServer.active && TextSerialization.TryParseInvariant(newValue, out int result))
				{
					NetworkServer.dontListen = result == 0;
				}
			}

			public override string GetString()
			{
				if (!NetworkServer.dontListen)
				{
					return "1";
				}
				return "0";
			}
		}

		public class SvMaxPlayersConVar : BaseConVar
		{
			public static readonly SvMaxPlayersConVar instance = new SvMaxPlayersConVar("sv_maxplayers", ConVarFlags.Engine, null, "Maximum number of players allowed.");

			public int intValue => NetworkManager.singleton.maxConnections;

			public SvMaxPlayersConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (NetworkServer.active)
				{
					throw new ConCommandException("Cannot change this convar while the server is running.");
				}
				if ((bool)NetworkManager.singleton && TextSerialization.TryParseInvariant(newValue, out int result))
				{
					NetworkManager.singleton.maxConnections = Math.Min(Math.Max(result, 1), RoR2Application.hardMaxPlayers);
				}
			}

			public override string GetString()
			{
				if (!NetworkManager.singleton)
				{
					return "1";
				}
				return TextSerialization.ToStringInvariant(NetworkManager.singleton.maxConnections);
			}
		}

		private class KickMessage : MessageBase
		{
			public BaseKickReason kickReason;

			public KickMessage()
			{
			}

			public KickMessage(BaseKickReason kickReason)
			{
				this.kickReason = kickReason;
			}

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
				string text = kickReason?.GetType().FullName ?? string.Empty;
				writer.Write(text);
				if (!(text == string.Empty))
				{
					kickReason.Serialize(writer);
				}
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
				string typeName = reader.ReadString();
				Type type = null;
				try
				{
					type = Type.GetType(typeName);
				}
				catch
				{
				}
				if (type == null || !typeof(BaseKickReason).IsAssignableFrom(type) || type.IsAbstract)
				{
					kickReason = null;
					return;
				}
				kickReason = (BaseKickReason)Activator.CreateInstance(type);
				kickReason.Deserialize(reader);
			}

			public bool TryGetDisplayTokenAndFormatParams(out string token, out object[] formatArgs)
			{
				if (kickReason == null)
				{
					token = null;
					formatArgs = null;
					return false;
				}
				kickReason.GetDisplayTokenAndFormatParams(out token, out formatArgs);
				return true;
			}
		}

		public abstract class BaseKickReason : MessageBase
		{
			public BaseKickReason()
			{
			}

			public abstract void GetDisplayTokenAndFormatParams(out string token, out object[] formatArgs);
		}

		public class SimpleLocalizedKickReason : BaseKickReason
		{
			public string baseToken;

			public string[] formatArgs;

			public SimpleLocalizedKickReason()
			{
			}

			public SimpleLocalizedKickReason(string baseToken, params string[] formatArgs)
			{
				this.baseToken = baseToken;
				this.formatArgs = formatArgs;
			}

			public override void GetDisplayTokenAndFormatParams(out string token, out object[] formatArgs)
			{
				token = baseToken;
				object[] array = this.formatArgs;
				formatArgs = array;
			}

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(baseToken);
				GeneratedNetworkCode._WriteArrayString_None(writer, formatArgs);
			}

			public override void Deserialize(NetworkReader reader)
			{
				baseToken = reader.ReadString();
				formatArgs = GeneratedNetworkCode._ReadArrayString_None(reader);
			}
		}

		public class ModMismatchKickReason : BaseKickReason
		{
			public string[] serverModList = Array.Empty<string>();

			public ModMismatchKickReason()
			{
			}

			public ModMismatchKickReason(IEnumerable<string> serverModList)
			{
				this.serverModList = serverModList.ToArray();
			}

			public override void GetDisplayTokenAndFormatParams(out string token, out object[] formatArgs)
			{
				IEnumerable<string> networkModList = NetworkModCompatibilityHelper.networkModList;
				IEnumerable<string> values = networkModList.Except(serverModList);
				IEnumerable<string> values2 = serverModList.Except(networkModList);
				token = "KICK_REASON_MOD_MISMATCH";
				object[] array = new string[2]
				{
					string.Join("\n", values),
					string.Join("\n", values2)
				};
				formatArgs = array;
			}

			public override void Serialize(NetworkWriter writer)
			{
				GeneratedNetworkCode._WriteArrayString_None(writer, serverModList);
			}

			public override void Deserialize(NetworkReader reader)
			{
				serverModList = GeneratedNetworkCode._ReadArrayString_None(reader);
			}
		}

		protected class AddPlayerMessage : MessageBase
		{
			public PlatformID id;

			public byte[] steamAuthTicketData;

			public override void Serialize(NetworkWriter writer)
			{
				GeneratedNetworkCode._WritePlatformID_None(writer, id);
				writer.WriteBytesFull(steamAuthTicketData);
			}

			public override void Deserialize(NetworkReader reader)
			{
				id = GeneratedNetworkCode._ReadPlatformID_None(reader);
				steamAuthTicketData = reader.ReadBytesAndSize();
			}
		}

		public class SvHostNameConVar : BaseConVar
		{
			public static readonly SvHostNameConVar instance = new SvHostNameConVar("sv_hostname", ConVarFlags.None, "", "The public name to use for the server if hosting.");

			private string value = "NAME";

			public event Action<string> onValueChanged;

			public SvHostNameConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				value = newValue;
				this.onValueChanged?.Invoke(newValue);
			}

			public override string GetString()
			{
				return value;
			}
		}

		public class SvPortConVar : BaseConVar
		{
			public static readonly SvPortConVar instance = new SvPortConVar("sv_port", ConVarFlags.Engine, null, "The port to use for the server if hosting.");

			public ushort value
			{
				get
				{
					if (!singleton)
					{
						return 0;
					}
					return (ushort)singleton.networkPort;
				}
			}

			public SvPortConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValueString)
			{
				if (NetworkServer.active)
				{
					throw new ConCommandException("Cannot change this convar while the server is running.");
				}
				if (TextSerialization.TryParseInvariant(newValueString, out ushort result))
				{
					singleton.networkPort = result;
				}
			}

			public override string GetString()
			{
				return value.ToString();
			}
		}

		public class SvIPConVar : BaseConVar
		{
			public static readonly SvIPConVar instance = new SvIPConVar("sv_ip", ConVarFlags.Engine, null, "The IP for the server to bind to if hosting.");

			public SvIPConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValueString)
			{
				if (NetworkServer.active)
				{
					throw new ConCommandException("Cannot change this convar while the server is running.");
				}
				singleton.serverBindAddress = newValueString;
			}

			public override string GetString()
			{
				if (!singleton)
				{
					return string.Empty;
				}
				return singleton.serverBindAddress;
			}
		}

		public class SvPasswordConVar : BaseConVar
		{
			public static readonly SvPasswordConVar instance = new SvPasswordConVar("sv_password", ConVarFlags.None, "", "The password to use for the server if hosting.");

			public string value { get; private set; }

			public event Action<string> onValueChanged;

			public SvPasswordConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (newValue == null)
				{
					newValue = "";
				}
				if (!(value == newValue))
				{
					value = newValue;
					this.onValueChanged?.Invoke(value);
				}
			}

			public override string GetString()
			{
				return value;
			}
		}

		protected class AddressablesChangeSceneAsyncOperation : IChangeSceneAsyncOperation
		{
			private static AsyncOperationHandle<SceneInstance>? previousLoadOperation;

			private AsyncOperationHandle<SceneInstance> srcOperation;

			private bool srcOperationIsDone;

			private SceneInstance sceneInstance;

			private bool isActivated;

			private bool _allowSceneActivation;

			public bool isDone { get; private set; }

			public bool allowSceneActivation
			{
				get
				{
					return _allowSceneActivation;
				}
				set
				{
					if (_allowSceneActivation != value)
					{
						_allowSceneActivation = value;
						ActivateIfReady();
					}
				}
			}

			public AddressablesChangeSceneAsyncOperation(object key, LoadSceneMode loadMode, bool activateOnLoad)
			{
				srcOperation = Addressables.LoadSceneAsync(key, loadMode, activateOnLoad);
				previousLoadOperation = srcOperation;
				srcOperation.Completed += delegate(AsyncOperationHandle<SceneInstance> v)
				{
					srcOperationIsDone = true;
					sceneInstance = v.Result;
					ActivateIfReady();
				};
				allowSceneActivation = activateOnLoad;
			}

			private void ActivateIfReady()
			{
				if (srcOperationIsDone && !isActivated)
				{
					sceneInstance.ActivateAsync().completed += delegate
					{
						isDone = true;
					};
				}
			}
		}

		protected static readonly FieldInfo loadingSceneAsyncFieldInfo;

		protected float _unpredictedServerFixedTime;

		protected float _unpredictedServerFixedTimeSmoothed;

		protected float unpredictedServerFixedTimeVelocity;

		protected float _unpredictedServerFrameTime;

		protected float _unpredictedServerFrameTimeSmoothed;

		protected float unpredictedServerFrameTimeVelocity;

		protected static FloatConVar cvNetTimeSmoothRate;

		public float debugServerTime;

		public float debugRTT;

		protected bool isSinglePlayer;

		protected bool actedUponDesiredHost;

		protected float lastDesiredHostSetTime = float.NegativeInfinity;

		protected HostDescription _desiredHost;

		private static bool wasFading;

		protected static readonly string[] sceneWhiteList;

		public static readonly StringConVar cvClPassword;

		protected GameObject serverNetworkSessionInstance;

		protected GameObject serverPauseStopControllerInstance;

		private static NetworkReader DefaultNetworkReader;

		private static readonly FloatConVar svTimeTransmitInterval;

		private float timeTransmitTimer;

		protected bool serverShuttingDown;

		private static readonly Queue<NetworkConnection> clientsReadyDuringLevelTransition;

		public static readonly StringConVar cvSvCustomTags;

		protected static bool isLoadingScene
		{
			get
			{
				IChangeSceneAsyncOperation changeSceneAsyncOperation = (IChangeSceneAsyncOperation)loadingSceneAsyncFieldInfo.GetValue(null);
				if (changeSceneAsyncOperation != null)
				{
					return !changeSceneAsyncOperation.isDone;
				}
				return false;
			}
		}

		public new static NetworkManagerSystem singleton => (NetworkManagerSystem)NetworkManager.singleton;

		public float unpredictedServerFixedTime => _unpredictedServerFixedTime;

		public float unpredictedServerFixedTimeSmoothed => _unpredictedServerFixedTimeSmoothed;

		public float serverFixedTime => unpredictedServerFixedTimeSmoothed + filteredClientRttFixed;

		public float unpredictedServerFrameTime => _unpredictedServerFrameTime;

		public float unpredictedServerFrameTimeSmoothed => _unpredictedServerFrameTimeSmoothed;

		public float serverFrameTime => unpredictedServerFrameTimeSmoothed + filteredClientRttFrame;

		public HostDescription desiredHost
		{
			get
			{
				return _desiredHost;
			}
			set
			{
				if (!_desiredHost.Equals(value))
				{
					_desiredHost = value;
					actedUponDesiredHost = false;
					lastDesiredHostSetTime = Time.unscaledTime;
					UnityEngine.Debug.LogFormat("NetworkManagerSystem.desiredHost={0}", _desiredHost.ToString());
				}
			}
		}

		public bool clientHasConfirmedQuit { get; private set; }

		protected bool clientIsConnecting
		{
			get
			{
				if (client?.connection != null)
				{
					return !client.isConnected;
				}
				return false;
			}
		}

		public float clientRttFixed { get; private set; }

		public float clientRttFrame { get; private set; }

		public float filteredClientRttFixed { get; private set; }

		public float filteredClientRttFrame { get; private set; }

		public bool isHost { get; protected set; }

		public PlatformID clientP2PId { get; protected set; } = PlatformID.nil;


		public PlatformID serverP2PId { get; protected set; } = PlatformID.nil;


		public static event Action onStartGlobal;

		public static event Action<NetworkClient> onStartClientGlobal;

		public static event Action onStopClientGlobal;

		public static event Action<NetworkConnection> onClientConnectGlobal;

		public static event Action<NetworkConnection> onClientDisconnectGlobal;

		public static event Action onStartHostGlobal;

		public static event Action onStopHostGlobal;

		public static event Action onStartServerGlobal;

		public static event Action onStopServerGlobal;

		public static event Action<NetworkConnection> onServerConnectGlobal;

		public static event Action<NetworkConnection> onServerDisconnectGlobal;

		public static event Action<string> onServerSceneChangedGlobal;

		static NetworkManagerSystem()
		{
			cvNetTimeSmoothRate = new FloatConVar("net_time_smooth_rate", ConVarFlags.None, "1.05", "The smoothing rate for the network time.");
			wasFading = false;
			sceneWhiteList = new string[3] { "title", "crystalworld", "logbook" };
			cvClPassword = new StringConVar("cl_password", ConVarFlags.None, "", "The password to use when joining a passworded server.");
			DefaultNetworkReader = new NetworkReader();
			svTimeTransmitInterval = new FloatConVar("sv_time_transmit_interval", ConVarFlags.Cheat, (1f / 60f).ToString(), "How long it takes for the server to issue a time update to clients.");
			clientsReadyDuringLevelTransition = new Queue<NetworkConnection>();
			cvSvCustomTags = new StringConVar("sv_custom_tags", ConVarFlags.None, "", "Comma-delimited custom tags to report to the server browser.");
			loadingSceneAsyncFieldInfo = typeof(NetworkManager).GetField("s_LoadingSceneAsync", BindingFlags.Static | BindingFlags.NonPublic);
			if (loadingSceneAsyncFieldInfo == null)
			{
				UnityEngine.Debug.LogError("NetworkManager.s_LoadingSceneAsync field could not be found! Make sure to provide a proper implementation for this version of Unity.");
			}
		}

		public virtual void Init(NetworkManagerConfiguration configurationComponent)
		{
			base.dontDestroyOnLoad = configurationComponent.DontDestroyOnLoad;
			base.runInBackground = configurationComponent.RunInBackground;
			base.logLevel = configurationComponent.LogLevel;
			base.offlineScene = configurationComponent.OfflineScene;
			base.onlineScene = configurationComponent.OnlineScene;
			base.playerPrefab = configurationComponent.PlayerPrefab;
			base.autoCreatePlayer = configurationComponent.AutoCreatePlayer;
			base.playerSpawnMethod = configurationComponent.PlayerSpawnMethod;
			base.spawnPrefabs.Clear();
			base.spawnPrefabs.AddRange(configurationComponent.SpawnPrefabs);
			base.customConfig = configurationComponent.CustomConfig;
			base.maxConnections = configurationComponent.MaxConnections;
			base.channels.Clear();
			base.channels.AddRange(configurationComponent.QosChannels);
			Run.onRunStartGlobal += ResetRunTime;
		}

		private void ResetRunTime(Run run)
		{
			if (Run.instance != null)
			{
				Run.instance.NetworkfixedTime = 0f;
				Run.instance.time = 0f;
				Run.FixedTimeStamp.Update();
			}
		}

		protected void InitializeTime()
		{
			_unpredictedServerFixedTime = 0f;
			_unpredictedServerFixedTimeSmoothed = 0f;
			unpredictedServerFixedTimeVelocity = 1f;
			_unpredictedServerFrameTime = 0f;
			_unpredictedServerFrameTimeSmoothed = 0f;
			unpredictedServerFrameTimeVelocity = 1f;
		}

		protected void UpdateTime(ref float targetValue, ref float currentValue, ref float velocity, float deltaTime)
		{
			if (!(deltaTime <= 0f))
			{
				targetValue += deltaTime;
				float num = (targetValue - currentValue) / deltaTime;
				float num2 = 1f;
				if (velocity == 0f || Mathf.Abs(num) > num2 * 3f)
				{
					currentValue = targetValue;
					velocity = num2;
				}
				else
				{
					currentValue += velocity * deltaTime;
					velocity = Mathf.MoveTowards(velocity, num, cvNetTimeSmoothRate.value * deltaTime);
				}
			}
		}

		protected static NetworkUser[] GetConnectionNetworkUsers(NetworkConnection conn)
		{
			List<UnityEngine.Networking.PlayerController> playerControllers = conn.playerControllers;
			NetworkUser[] array = new NetworkUser[playerControllers.Count];
			for (int i = 0; i < playerControllers.Count; i++)
			{
				array[i] = playerControllers[i].gameObject.GetComponent<NetworkUser>();
			}
			return array;
		}

		protected abstract void Start();

		protected void OnDestroy()
		{
			typeof(NetworkManager).GetMethod("OnDestroy", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, null);
		}

		public IEnumerator FireOnStartGlobalEvent()
		{
			while (Console.instance == null)
			{
				yield return null;
			}
			NetworkManagerSystem.onStartGlobal?.Invoke();
		}

		protected void FixedUpdate()
		{
			UpdateTime(ref _unpredictedServerFixedTime, ref _unpredictedServerFixedTimeSmoothed, ref unpredictedServerFixedTimeVelocity, Time.fixedDeltaTime);
			FixedUpdateServer();
			FixedUpdateClient();
			debugServerTime = unpredictedServerFixedTime;
			debugRTT = clientRttFrame;
		}

		protected abstract void Update();

		protected abstract void EnsureDesiredHost();

		public abstract void ForceCloseAllConnections();

		public bool IsSinglePlayer()
		{
			return isSinglePlayer;
		}

		public void SetSinglePlayerNetworkState()
		{
			NetworkServer.dontListen = true;
			desiredHost = default(HostDescription);
			isSinglePlayer = true;
		}

		public void ResetDesiredHost()
		{
			actedUponDesiredHost = false;
			singleton.desiredHost = default(HostDescription);
			isSinglePlayer = false;
		}

		public abstract void CreateLocalLobby();

		public virtual IEnumerator<CanPlayOnlineState> CanPlayOnline()
		{
			yield return CanPlayOnlineState.Yes;
		}

		public override void OnStartClient(NetworkClient newClient)
		{
			base.OnStartClient(newClient);
			InitializeTime();
			RegisterPrefabs(ContentManager.bodyPrefabs);
			RegisterPrefabs(ContentManager.masterPrefabs);
			RegisterPrefabs(ContentManager.projectilePrefabs);
			RegisterPrefabs(ContentManager.networkedObjectPrefabs);
			RegisterPrefabs(ContentManager.gameModePrefabs);
			ClientScene.RegisterPrefab(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkSession"));
			ClientScene.RegisterPrefab(LegacyResourcesAPI.Load<GameObject>("Prefabs/Stage"));
			NetworkMessageHandlerAttribute.RegisterClientMessages(newClient);
			NetworkManagerSystem.onStartClientGlobal?.Invoke(newClient);
			static void RegisterPrefabs(GameObject[] prefabs)
			{
				for (int i = 0; i < prefabs.Length; i++)
				{
					ClientScene.RegisterPrefab(prefabs[i]);
				}
			}
		}

		public override void OnStopClient()
		{
			try
			{
				NetworkManagerSystem.onStopClientGlobal?.Invoke();
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			foreach (NetworkClient allClient in NetworkClient.allClients)
			{
				allClient?.connection?.Disconnect();
			}
			ForceCloseAllConnections();
			if (actedUponDesiredHost)
			{
				singleton.desiredHost = HostDescription.none;
			}
			base.OnStopClient();
			OrbStorageUtility.Clear();
		}

		public override void OnClientConnect(NetworkConnection conn)
		{
			base.OnClientConnect(conn);
			clientRttFrame = 0f;
			filteredClientRttFixed = 0f;
			ClientSendAuth(conn);
			ClientSetPlayers(conn);
			NetworkManagerSystem.onClientConnectGlobal?.Invoke(conn);
		}

		public override void OnClientDisconnect(NetworkConnection conn)
		{
			base.OnClientDisconnect(conn);
			NetworkManagerSystem.onClientDisconnectGlobal?.Invoke(conn);
		}

		public void ClientAddPlayer(short playerControllerId, NetworkConnection connection = null)
		{
			foreach (UnityEngine.Networking.PlayerController localPlayer in ClientScene.localPlayers)
			{
				if (localPlayer.playerControllerId == playerControllerId && localPlayer.IsValid && (bool)localPlayer.gameObject)
				{
					UnityEngine.Debug.LogFormat("Player {0} already added, aborting.", playerControllerId);
					return;
				}
			}
			UnityEngine.Debug.LogFormat("Adding local player controller {0} on connection {1}", playerControllerId, connection);
			AddPlayerMessage extraMessage = CreateClientAddPlayerMessage();
			ClientScene.AddPlayer(connection, playerControllerId, extraMessage);
		}

		protected abstract AddPlayerMessage CreateClientAddPlayerMessage();

		protected void UpdateClient()
		{
			UpdateCheckInactiveConnections();
			if (client?.connection != null)
			{
				filteredClientRttFrame = RttManager.GetConnectionFrameSmoothedRtt(client.connection);
				clientRttFrame = RttManager.GetConnectionRTT(client.connection);
			}
			bool flag = string.IsNullOrEmpty(NetworkManager.networkSceneName);
			bool flag2 = (client != null && !ClientScene.ready && !flag) || isLoadingScene;
			if (wasFading != flag2)
			{
				if (flag2)
				{
					FadeToBlackManager.fadeCount++;
				}
				else
				{
					FadeToBlackManager.fadeCount--;
				}
				wasFading = flag2;
			}
		}

		protected abstract void UpdateCheckInactiveConnections();

		protected abstract void StartClient(PlatformID serverID);

		public abstract bool IsConnectedToServer(PlatformID serverID);

		private void FixedUpdateClient()
		{
			if (NetworkClient.active && client != null && client?.connection != null && client.connection.isConnected)
			{
				NetworkConnection connection = client.connection;
				filteredClientRttFixed = RttManager.GetConnectionFixedSmoothedRtt(connection);
				clientRttFixed = RttManager.GetConnectionRTT(connection);
				if (!Util.ConnectionIsLocal(connection))
				{
					RttManager.Ping(connection, QosChannelIndex.ping.intVal);
				}
			}
		}

		public override void OnClientSceneChanged(NetworkConnection conn)
		{
			string text = NetworkManager.networkSceneName;
			List<string> list = new List<string>();
			bool flag = false;
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				string text2 = SceneManager.GetSceneAt(i).name;
				list.Add(text2);
				if (text2 == text)
				{
					flag = true;
				}
			}
			if (flag)
			{
				base.autoCreatePlayer = false;
				base.OnClientSceneChanged(conn);
				ClientSetPlayers(conn);
				FadeToBlackManager.ForceFullBlack();
			}
		}

		private void ClientSendAuth(NetworkConnection conn)
		{
			ClientAuthData data = new ClientAuthData();
			PlatformAuth(ref data, conn);
			data.password = cvClPassword.value;
			data.version = RoR2Application.GetBuildId();
			data.modHash = NetworkModCompatibilityHelper.networkModHash;
			conn.Send(74, data);
		}

		protected abstract void PlatformAuth(ref ClientAuthData data, NetworkConnection conn);

		protected void ClientSetPlayers(NetworkConnection conn)
		{
			ReadOnlyCollection<LocalUser> readOnlyLocalUsersList = LocalUserManager.readOnlyLocalUsersList;
			for (int i = 0; i < readOnlyLocalUsersList.Count; i++)
			{
				if (i == 0 || RoR2Application.isInLocalMultiPlayer)
				{
					UnityEngine.Debug.LogError($"For iteration {i}, out of {readOnlyLocalUsersList.Count}");
					ClientAddPlayer((short)readOnlyLocalUsersList[i].id, conn);
				}
			}
		}

		[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
		private static void ClientInit()
		{
			SceneCatalog.onMostRecentSceneDefChanged += ClientUpdateOfflineScene;
		}

		private static void ClientUpdateOfflineScene(SceneDef sceneDef)
		{
			if ((bool)singleton && sceneDef.isOfflineScene)
			{
				singleton.offlineScene = sceneDef.cachedName;
			}
		}

		protected static void EnsureNetworkManagerNotBusy()
		{
			if (!singleton || (!singleton.serverShuttingDown && !isLoadingScene))
			{
				return;
			}
			throw new ConCommandException("NetworkManager is busy and cannot receive commands.");
		}

		[ConCommand(commandName = "client_set_players", flags = ConVarFlags.None, helpText = "Adds network players for all local players. Debug only.")]
		private static void CCClientSetPlayers(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformClientSetPlayers(args);
			}
		}

		protected abstract void PlatformClientSetPlayers(ConCommandArgs args);

		[ConCommand(commandName = "ping", flags = ConVarFlags.None, helpText = "Prints the current round trip time from this client to the server and back.")]
		private static void CCPing(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				NetworkConnection networkConnection = singleton?.client?.connection;
				if (networkConnection != null)
				{
					UnityEngine.Debug.LogFormat("rtt={0}ms smoothedFrame={1} smoothedFixed={2}", RttManager.GetConnectionRTTInMilliseconds(networkConnection), RttManager.GetConnectionFrameSmoothedRtt(networkConnection), RttManager.GetConnectionFixedSmoothedRtt(networkConnection));
				}
			}
		}

		[ConCommand(commandName = "set_scene", flags = ConVarFlags.None, helpText = "Changes to the named scene.")]
		private static void CCSetScene(ConCommandArgs args)
		{
			string argString = args.GetArgString(0);
			if (!singleton)
			{
				throw new ConCommandException("set_scene failed: NetworkManagerSystem is not available.");
			}
			SceneCatalog.GetSceneDefForCurrentScene();
			SceneDef sceneDefFromSceneName = SceneCatalog.GetSceneDefFromSceneName(argString);
			if (!sceneDefFromSceneName)
			{
				throw new ConCommandException("\"" + argString + "\" is not a valid scene.");
			}
			bool boolValue = Console.CheatsConVar.instance.boolValue;
			if (!NetworkManager.singleton)
			{
				_ = 1;
			}
			else
				_ = NetworkManager.singleton.isNetworkActive;
			if (NetworkManager.singleton.isNetworkActive)
			{
				if (sceneDefFromSceneName.isOfflineScene)
				{
					throw new ConCommandException("Cannot switch to scene \"" + argString + "\": Cannot switch to offline-only scene while in a network session.");
				}
				if (!boolValue)
				{
					throw new ConCommandException("Cannot switch to scene \"" + argString + "\": Cheats must be enabled to switch between online-only scenes.");
				}
			}
			else if (!sceneDefFromSceneName.isOfflineScene)
			{
				throw new ConCommandException("Cannot switch to scene \"" + argString + "\": Cannot switch to online-only scene while not in a network session.");
			}
			if ((bool)PauseStopController.instance && PauseStopController.instance.isPaused)
			{
				PauseStopController.instance.Pause(shouldPause: false);
			}
			if (NetworkServer.active)
			{
				UnityEngine.Debug.LogFormat("Setting server scene to {0}", argString);
				singleton.ServerChangeScene(argString);
				return;
			}
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogFormat("Setting offline scene to {0}", argString);
				singleton.ServerChangeScene(argString);
				return;
			}
			throw new ConCommandException("Cannot change scene while connected to a remote server.");
		}

		[ConCommand(commandName = "scene_list", flags = ConVarFlags.None, helpText = "Prints a list of all available scene names.")]
		private static void CCSceneList(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				string[] array = new string[SceneManager.sceneCountInBuildSettings];
				for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
				{
					array[i] = $"[{i}]={SceneUtility.GetScenePathByBuildIndex(i)}";
				}
			}
		}

		[ConCommand(commandName = "dump_network_ids", flags = ConVarFlags.None, helpText = "Lists the network ids of all currently networked game objects.")]
		private static void CCDumpNetworkIDs(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				List<NetworkIdentity> list = new List<NetworkIdentity>(UnityEngine.Object.FindObjectsOfType<NetworkIdentity>());
				list.Sort((NetworkIdentity lhs, NetworkIdentity rhs) => (int)(lhs.netId.Value - rhs.netId.Value));
				for (int i = 0; i < list.Count; i++)
				{
					UnityEngine.Debug.LogFormat("{0}={1}", list[i].netId.Value, list[i].gameObject.name);
				}
			}
		}

		[ConCommand(commandName = "disconnect", flags = ConVarFlags.None, helpText = "Disconnect from a server or shut down the current server.")]
		private static void CCDisconnect(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformDisconnect(args);
			}
		}

		protected abstract void PlatformDisconnect(ConCommandArgs args);

		protected void Disconnect()
		{
			if (!serverShuttingDown && singleton.isNetworkActive)
			{
				if (NetworkServer.active)
				{
					singleton.RequestServerShutdown();
				}
				else
				{
					singleton.StopClient();
				}
				OrbStorageUtility.Clear();
			}
		}

		[ConCommand(commandName = "connect", flags = ConVarFlags.None, helpText = "Connect to a server.")]
		private static void CCConnect(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformConnect(args);
			}
		}

		protected abstract void PlatformConnect(ConCommandArgs args);

		private static void CCConnectP2P(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformConnect(args);
			}
		}

		protected abstract void PlatformConnectP2P(ConCommandArgs args);

		[ConCommand(commandName = "host", flags = ConVarFlags.None, helpText = "Host a server. First argument is whether or not to listen for incoming connections.")]
		private static void CCHost(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformHost(args);
			}
		}

		protected abstract void PlatformHost(ConCommandArgs args);

		[ConCommand(commandName = "steam_get_p2p_session_state")]
		private static void CCSGetP2PSessionState(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformGetP2PSessionState(args);
			}
		}

		protected abstract void PlatformGetP2PSessionState(ConCommandArgs args);

		[ConCommand(commandName = "kick_steam", flags = ConVarFlags.SenderMustBeServer, helpText = "Kicks the user with the specified steam id from the server.")]
		private static void CCKickSteam(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformKick(args);
			}
		}

		protected abstract void PlatformKick(ConCommandArgs args);

		[ConCommand(commandName = "ban_steam", flags = ConVarFlags.SenderMustBeServer, helpText = "Bans the user with the specified steam id from the server.")]
		private static void CCBan(ConCommandArgs args)
		{
			if ((bool)singleton)
			{
				singleton.PlatformBan(args);
			}
		}

		protected abstract void PlatformBan(ConCommandArgs args);

		public virtual bool IsHost()
		{
			return isHost;
		}

		public override void OnStartHost()
		{
			base.OnStartHost();
			isHost = true;
			NetworkManagerSystem.onStartHostGlobal?.Invoke();
		}

		public override void OnStopHost()
		{
			NetworkManagerSystem.onStopHostGlobal?.Invoke();
			isHost = false;
			base.OnStopHost();
		}

		[NetworkMessageHandler(client = true, server = false, msgType = 67)]
		private static void HandleKick(NetworkMessage netMsg)
		{
			KickMessage kickMessage = netMsg.ReadMessage<KickMessage>();
			UnityEngine.Debug.LogFormat("Received kick message. Reason={0}", kickMessage.kickReason);
			singleton.StopClient();
			kickMessage.TryGetDisplayTokenAndFormatParams(out var token, out var formatArgs);
			DialogBoxManager.DialogBox(new SimpleDialogBox.TokenParamsPair("DISCONNECTED"), new SimpleDialogBox.TokenParamsPair(token ?? string.Empty, formatArgs), CommonLanguageTokens.ok);
		}

		public static void HandleKick(string displayToken)
		{
			singleton.StopClient();
			DialogBoxManager.DialogBox("DISCONNECTED", displayToken, CommonLanguageTokens.ok);
		}

		[NetworkMessageHandler(msgType = 54, client = true)]
		private static void HandleUpdateTime(NetworkMessage netMsg)
		{
			float num = netMsg.reader.ReadSingle();
			singleton._unpredictedServerFixedTime = num;
			float num2 = Time.time - Time.fixedTime;
			singleton._unpredictedServerFrameTime = num + num2;
		}

		[NetworkMessageHandler(msgType = 64, client = true, server = true)]
		private static void HandleTest(NetworkMessage netMsg)
		{
			int num = netMsg.reader.ReadInt32();
			UnityEngine.Debug.LogFormat("Received test packet. value={0}", num);
		}

		public abstract NetworkConnection GetClient(PlatformID clientId);

		public virtual void InitPlatformServer()
		{
		}

		public override void OnStartServer()
		{
			base.OnStartServer();
			NetworkMessageHandlerAttribute.RegisterServerMessages();
			InitializeTime();
			serverNetworkSessionInstance = UnityEngine.Object.Instantiate(RoR2Application.instance.networkSessionPrefab);
			serverPauseStopControllerInstance = UnityEngine.Object.Instantiate(RoR2Application.instance.pauseStopController);
			InitPlatformServer();
			NetworkManagerSystem.onStartServerGlobal?.Invoke();
		}

		public void FireStartServerGlobalEvent()
		{
			NetworkManagerSystem.onStartServerGlobal?.Invoke();
		}

		public override void OnStopServer()
		{
			base.OnStopServer();
			FireStopServerGlobalEvent();
			for (int i = 0; i < NetworkServer.connections.Count; i++)
			{
				NetworkConnection networkConnection = NetworkServer.connections[i];
				if (networkConnection != null)
				{
					OnServerDisconnect(networkConnection);
				}
			}
			UnityEngine.Object.Destroy(serverPauseStopControllerInstance);
			serverPauseStopControllerInstance = null;
			UnityEngine.Object.Destroy(serverNetworkSessionInstance);
			serverNetworkSessionInstance = null;
		}

		public void FireStopServerGlobalEvent()
		{
			NetworkManagerSystem.onStopServerGlobal?.Invoke();
		}

		public override void OnServerConnect(NetworkConnection conn)
		{
			base.OnServerConnect(conn);
		}

		public void FireServerConnectGlobalEvent(NetworkConnection conn)
		{
			NetworkManagerSystem.onServerConnectGlobal?.Invoke(conn);
		}

		public override void OnServerDisconnect(NetworkConnection conn)
		{
			base.OnServerDisconnect(conn);
		}

		public void FireServerDisconnectGlobalEvent(NetworkConnection conn)
		{
			NetworkManagerSystem.onServerDisconnectGlobal?.Invoke(conn);
		}

		public abstract void ServerHandleClientDisconnect(NetworkConnection conn);

		public abstract void ServerBanClient(NetworkConnection conn);

		public void ServerKickClient(NetworkConnection conn, BaseKickReason reason)
		{
			UnityEngine.Debug.LogFormat("Kicking client on connection {0}: Reason {1}", conn.connectionId, reason);
			conn.SendByChannel(67, new KickMessage(reason), QosChannelIndex.defaultReliable.intVal);
			conn.FlushChannels();
			KickClient(conn, reason);
		}

		protected abstract void KickClient(NetworkConnection conn, BaseKickReason reason);

		public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
		{
			OnServerAddPlayer(conn, playerControllerId, null);
		}

		public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader)
		{
			OnServerAddPlayerInternal(conn, playerControllerId, extraMessageReader);
		}

		private void OnServerAddPlayerInternal(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader)
		{
			if (base.playerPrefab == null)
			{
				if (LogFilter.logError)
				{
					UnityEngine.Debug.LogError("The PlayerPrefab is empty on the NetworkManager. Please setup a PlayerPrefab object.");
				}
				return;
			}
			if (base.playerPrefab.GetComponent<NetworkIdentity>() == null)
			{
				if (LogFilter.logError)
				{
					UnityEngine.Debug.LogError("The PlayerPrefab does not have a NetworkIdentity. Please add a NetworkIdentity to the player prefab.");
				}
				return;
			}
			if (playerControllerId < conn.playerControllers.Count && conn.playerControllers[playerControllerId].IsValid && conn.playerControllers[playerControllerId].gameObject != null)
			{
				if (LogFilter.logError)
				{
					UnityEngine.Debug.LogErrorFormat("There is already a player at that playerControllerId for this connection, conn = {0}, playerControllerId = {1}.", conn, playerControllerId);
				}
				return;
			}
			if (NetworkUser.readOnlyInstancesList.Count >= base.maxConnections)
			{
				if (LogFilter.logError)
				{
					UnityEngine.Debug.LogError("Cannot add any more players.)");
				}
				return;
			}
			if (extraMessageReader == null)
			{
				extraMessageReader = DefaultNetworkReader;
			}
			AddPlayerMessage message = extraMessageReader.ReadMessage<AddPlayerMessage>();
			Transform startPosition = GetStartPosition();
			GameObject gameObject = ((!(startPosition != null)) ? UnityEngine.Object.Instantiate(base.playerPrefab, UnityEngine.Vector3.zero, UnityEngine.Quaternion.identity) : UnityEngine.Object.Instantiate(base.playerPrefab, startPosition.position, startPosition.rotation));
			UnityEngine.Debug.LogFormat("NetworkManagerSystem.AddPlayerInternal(conn={0}, playerControllerId={1}, extraMessageReader={2}", conn, playerControllerId, extraMessageReader);
			NetworkUser component = gameObject.GetComponent<NetworkUser>();
			Util.ConnectionIsLocal(conn);
			component.id = AddPlayerIdFromPlatform(conn, message, (byte)playerControllerId);
			Chat.SendPlayerConnectedMessage(component);
			NetworkServer.AddPlayerForConnection(conn, gameObject, playerControllerId);
		}

		protected abstract NetworkUserId AddPlayerIdFromPlatform(NetworkConnection conn, AddPlayerMessage message, byte playerControllerId);

		protected abstract void UpdateServer();

		private void FixedUpdateServer()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			timeTransmitTimer -= Time.fixedDeltaTime;
			if (timeTransmitTimer <= 0f)
			{
				NetworkWriter networkWriter = new NetworkWriter();
				networkWriter.StartMessage(54);
				networkWriter.Write(unpredictedServerFixedTime);
				networkWriter.FinishMessage();
				NetworkServer.SendWriterToReady(null, networkWriter, QosChannelIndex.time.intVal);
				timeTransmitTimer += svTimeTransmitInterval.value;
			}
			foreach (NetworkConnection connection in NetworkServer.connections)
			{
				if (connection != null && !Util.ConnectionIsLocal(connection))
				{
					RttManager.Ping(connection, QosChannelIndex.ping.intVal);
				}
			}
		}

		public override void OnServerSceneChanged(string sceneName)
		{
			base.OnServerSceneChanged(sceneName);
			if ((bool)Run.instance)
			{
				Run.instance.OnServerSceneChanged(sceneName);
			}
			NetworkManagerSystem.onServerSceneChangedGlobal?.Invoke(sceneName);
			while (clientsReadyDuringLevelTransition.Count > 0)
			{
				NetworkConnection networkConnection = clientsReadyDuringLevelTransition.Dequeue();
				try
				{
					if (networkConnection.isConnected)
					{
						OnServerReady(networkConnection);
					}
				}
				catch (Exception ex)
				{
					UnityEngine.Debug.LogErrorFormat("OnServerReady could not be called for client: {0}", ex.Message);
				}
			}
		}

		protected bool IsServerAtMaxConnections()
		{
			ReadOnlyCollection<NetworkConnection> connections = NetworkServer.connections;
			if (connections.Count >= base.maxConnections)
			{
				int num = 0;
				for (int i = 0; i < connections.Count; i++)
				{
					if (connections[i] != null)
					{
						num++;
					}
				}
				return num >= base.maxConnections;
			}
			return false;
		}

		private NetworkUser FindNetworkUserForConnectionServer(NetworkConnection connection)
		{
			ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
			int count = readOnlyInstancesList.Count;
			for (int i = 0; i < count; i++)
			{
				NetworkUser networkUser = readOnlyInstancesList[i];
				if (networkUser.connectionToClient == connection)
				{
					return networkUser;
				}
			}
			return null;
		}

		public int GetConnectingClientCount()
		{
			int num = 0;
			ReadOnlyCollection<NetworkConnection> connections = NetworkServer.connections;
			int count = connections.Count;
			for (int i = 0; i < count; i++)
			{
				NetworkConnection networkConnection = connections[i];
				if (networkConnection != null && !FindNetworkUserForConnectionServer(networkConnection))
				{
					num++;
				}
			}
			return num;
		}

		public void RequestServerShutdown()
		{
			if (!serverShuttingDown)
			{
				serverShuttingDown = true;
				StartCoroutine(ServerShutdownCoroutine());
			}
		}

		private IEnumerator ServerShutdownCoroutine()
		{
			ReadOnlyCollection<NetworkConnection> connections = NetworkServer.connections;
			for (int num = connections.Count - 1; num >= 0; num--)
			{
				NetworkConnection networkConnection = connections[num];
				if (networkConnection != null && !Util.ConnectionIsLocal(networkConnection))
				{
					ServerKickClient(networkConnection, new SimpleLocalizedKickReason("KICK_REASON_SERVERSHUTDOWN"));
				}
			}
			float maxWait = 0.2f;
			for (float t = 0f; t < maxWait; t += Time.unscaledDeltaTime)
			{
				if (CheckConnectionsEmpty())
				{
					break;
				}
				yield return new WaitForEndOfFrame();
			}
			if (client != null)
			{
				StopHost();
			}
			else
			{
				StopServer();
			}
			serverShuttingDown = false;
			static bool CheckConnectionsEmpty()
			{
				foreach (NetworkConnection connection in NetworkServer.connections)
				{
					if (connection != null && !Util.ConnectionIsLocal(connection))
					{
						return false;
					}
				}
				return true;
			}
		}

		private static void ServerHandleReady(NetworkMessage netMsg)
		{
			if (isLoadingScene)
			{
				clientsReadyDuringLevelTransition.Enqueue(netMsg.conn);
			}
			else
			{
				singleton.OnServerReady(netMsg.conn);
			}
		}

		private void RegisterServerOverrideMessages()
		{
			NetworkServer.RegisterHandler(35, ServerHandleReady);
		}

		public override void ServerChangeScene(string newSceneName)
		{
			RegisterServerOverrideMessages();
			base.ServerChangeScene(newSceneName);
		}

		private static bool IsAddressablesKeyValid(string key, Type type)
		{
			foreach (IResourceLocator resourceLocator in Addressables.ResourceLocators)
			{
				if (resourceLocator.Locate(key, typeof(SceneInstance), out var locations) && locations.Count > 0)
				{
					return true;
				}
			}
			return false;
		}

		protected override IChangeSceneAsyncOperation ChangeSceneImplementation(string newSceneName)
		{
			IChangeSceneAsyncOperation changeSceneAsyncOperation = null;
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			try
			{
				SceneDef sceneDef = SceneCatalog.FindSceneDef(newSceneName);
				if ((bool)sceneDef)
				{
					string text = sceneDef.sceneAddress?.AssetGUID;
					if (!string.IsNullOrEmpty(text))
					{
						if (IsAddressablesKeyValid(text, typeof(SceneInstance)))
						{
							changeSceneAsyncOperation = new AddressablesChangeSceneAsyncOperation(text, LoadSceneMode.Single, activateOnLoad: false);
						}
						else
						{
							stringBuilder.AppendLine("Scene address is invalid. sceneName=\"").Append(newSceneName).Append("\" sceneAddress=\"")
								.Append(text)
								.Append("\"")
								.AppendLine();
						}
					}
				}
				else if (IsAddressablesKeyValid(newSceneName, typeof(SceneInstance)))
				{
					changeSceneAsyncOperation = new AddressablesChangeSceneAsyncOperation(newSceneName, LoadSceneMode.Single, activateOnLoad: false);
				}
				if (changeSceneAsyncOperation == null)
				{
					changeSceneAsyncOperation = base.ChangeSceneImplementation(newSceneName);
					if (changeSceneAsyncOperation == null)
					{
						stringBuilder.Append("SceneManager.LoadSceneAsync(\"").Append(newSceneName).Append("\" failed.")
							.AppendLine();
					}
				}
				return changeSceneAsyncOperation;
			}
			finally
			{
				if (changeSceneAsyncOperation == null)
				{
					UnityEngine.Debug.LogError(stringBuilder.ToString());
				}
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			}
		}
	}
	public struct HostDescription : IEquatable<HostDescription>
	{
		public enum HostType
		{
			None,
			Self,
			Steam,
			IPv4,
			Pia,
			PS4,
			EOS,
			Playfab
		}

		public struct HostingParameters : IEquatable<HostingParameters>
		{
			public bool listen;

			public int maxPlayers;

			public bool Equals(HostingParameters other)
			{
				if (listen == other.listen)
				{
					return maxPlayers == other.maxPlayers;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is HostingParameters other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (listen.GetHashCode() * 397) ^ maxPlayers;
			}
		}

		public readonly HostType hostType;

		public readonly PlatformID userID;

		public readonly AddressPortPair addressPortPair;

		public readonly HostingParameters hostingParameters;

		public static readonly HostDescription none = new HostDescription(null);

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		public bool isRemote
		{
			get
			{
				if (hostType != 0)
				{
					return hostType != HostType.Self;
				}
				return false;
			}
		}

		public HostDescription(PlatformID id, HostType type)
		{
			this = default(HostDescription);
			hostType = type;
			userID = id;
		}

		public HostDescription(AddressPortPair addressPortPair)
		{
			this = default(HostDescription);
			hostType = HostType.IPv4;
			this.addressPortPair = addressPortPair;
		}

		public HostDescription(HostingParameters hostingParameters)
		{
			this = default(HostDescription);
			hostType = HostType.Self;
			this.hostingParameters = hostingParameters;
		}

		public bool DescribesCurrentHost()
		{
			switch (hostType)
			{
			case HostType.None:
				return !NetworkManagerSystem.singleton.isNetworkActive;
			case HostType.Self:
				if (NetworkServer.active && hostingParameters.listen != NetworkServer.dontListen)
				{
					return true;
				}
				return false;
			case HostType.Steam:
				if (NetworkManagerSystem.singleton.client?.connection is SteamNetworkConnection steamNetworkConnection && steamNetworkConnection.steamId == userID)
				{
					return true;
				}
				return false;
			case HostType.EOS:
				if (NetworkManagerSystem.singleton.client?.connection is EOSNetworkConnection eOSNetworkConnection && eOSNetworkConnection.RemoteUserID == userID.productUserID)
				{
					return true;
				}
				return false;
			case HostType.IPv4:
			{
				NetworkConnection networkConnection2 = NetworkManagerSystem.singleton.client?.connection;
				if (networkConnection2 != null && networkConnection2.address == addressPortPair.address)
				{
					return true;
				}
				return false;
			}
			case HostType.Pia:
				return false;
			case HostType.Playfab:
			{
				NetworkConnection networkConnection = NetworkManagerSystem.singleton.client?.connection;
				if (networkConnection != null && networkConnection.address == addressPortPair.address)
				{
					return true;
				}
				return false;
			}
			default:
				throw new ArgumentOutOfRangeException();
			}
		}

		private HostDescription(object o)
		{
			this = default(HostDescription);
			hostType = HostType.None;
		}

		public bool Equals(HostDescription other)
		{
			if (hostType == other.hostType && userID.Equals(other.userID) && addressPortPair.Equals(other.addressPortPair))
			{
				return hostingParameters.Equals(other.hostingParameters);
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is HostDescription other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((((((int)hostType * 397) ^ userID.GetHashCode()) * 397) ^ addressPortPair.GetHashCode()) * 397) ^ hostingParameters.GetHashCode();
		}

		public override string ToString()
		{
			sharedStringBuilder.Clear();
			sharedStringBuilder.Append("{ hostType=").Append(hostType);
			switch (hostType)
			{
			case HostType.Self:
				sharedStringBuilder.Append(" listen=").Append(hostingParameters.listen);
				sharedStringBuilder.Append(" maxPlayers=").Append(hostingParameters.maxPlayers);
				break;
			case HostType.Steam:
				sharedStringBuilder.Append(" steamId=").Append(userID);
				break;
			case HostType.IPv4:
				sharedStringBuilder.Append(" address=").Append(addressPortPair.address);
				sharedStringBuilder.Append(" port=").Append(addressPortPair.port);
				break;
			case HostType.EOS:
				sharedStringBuilder.Append(" steamId=").Append(userID.ToString());
				break;
			default:
				throw new ArgumentOutOfRangeException();
			case HostType.None:
			case HostType.Pia:
			case HostType.Playfab:
				break;
			}
			sharedStringBuilder.Append(" }");
			return sharedStringBuilder.ToString();
		}
	}
	public class NetworkManagerSystemSteam : NetworkManagerSystem
	{
		private BaseSteamworks clientSteamworks;

		private BaseSteamworks serverSteamworks;

		protected List<PlatformID> steamIdBanList = new List<PlatformID>();

		private static readonly BoolConVar cvSteamP2PUseSteamServer = new BoolConVar("steam_p2p_use_steam_server", ConVarFlags.None, "0", "Whether or not to use the Steam server interface to receive network traffic. Setting to false will cause the traffic to be handled by the Steam client interface instead. Only takes effect on server startup.");

		protected override void Start()
		{
			foreach (QosType channel in base.channels)
			{
				base.connectionConfig.AddChannel(channel);
			}
			base.connectionConfig.PacketSize = 1200;
			StartCoroutine(FireOnStartGlobalEvent());
		}

		protected override void Update()
		{
			UpdateTime(ref _unpredictedServerFrameTime, ref _unpredictedServerFrameTimeSmoothed, ref unpredictedServerFrameTimeVelocity, Time.deltaTime);
			EnsureDesiredHost();
			UpdateServer();
			UpdateClient();
		}

		protected override void EnsureDesiredHost()
		{
			if ((false | serverShuttingDown | base.clientIsConnecting | (NetworkServer.active && NetworkManagerSystem.isLoadingScene) | (!NetworkClient.active && NetworkManagerSystem.isLoadingScene)) || !SystemInitializerAttribute.hasExecuted)
			{
				return;
			}
			bool isAnyUserSignedIn = LocalUserManager.isAnyUserSignedIn;
			if (base.desiredHost.isRemote && !isAnyUserSignedIn)
			{
				return;
			}
			if (isNetworkActive && !actedUponDesiredHost && !base.desiredHost.DescribesCurrentHost())
			{
				Disconnect();
			}
			else
			{
				if (actedUponDesiredHost)
				{
					return;
				}
				if (base.desiredHost.hostType == HostDescription.HostType.Self)
				{
					if (NetworkServer.active)
					{
						return;
					}
					actedUponDesiredHost = true;
					base.maxConnections = base.desiredHost.hostingParameters.maxPlayers;
					NetworkServer.dontListen = !base.desiredHost.hostingParameters.listen;
					if (!isAnyUserSignedIn)
					{
						StartServer(base.connectionConfig, 4);
					}
					else
					{
						StartHost(base.connectionConfig, 4);
					}
				}
				if (base.desiredHost.hostType == HostDescription.HostType.Steam && Time.unscaledTime - lastDesiredHostSetTime >= 0f)
				{
					actedUponDesiredHost = true;
					StartClient(base.desiredHost.userID);
				}
				if (base.desiredHost.hostType == HostDescription.HostType.IPv4 && Time.unscaledTime - lastDesiredHostSetTime >= 0f)
				{
					actedUponDesiredHost = true;
					UnityEngine.Debug.LogFormat("Attempting connection. ip={0} port={1}", base.desiredHost.addressPortPair.address, base.desiredHost.addressPortPair.port);
					NetworkManagerSystem.singleton.networkAddress = base.desiredHost.addressPortPair.address;
					NetworkManagerSystem.singleton.networkPort = base.desiredHost.addressPortPair.port;
					NetworkManagerSystem.singleton.StartClient();
				}
			}
		}

		public override void ForceCloseAllConnections()
		{
			Facepunch.Steamworks.Networking networking = Client.Instance?.Networking;
			if (networking == null)
			{
				return;
			}
			foreach (NetworkConnection connection in NetworkServer.connections)
			{
				if (connection is SteamNetworkConnection steamNetworkConnection)
				{
					networking.CloseSession(steamNetworkConnection.steamId.ID);
				}
			}
			if (client?.connection is SteamNetworkConnection steamNetworkConnection2)
			{
				networking.CloseSession(steamNetworkConnection2.steamId.ID);
			}
		}

		public override NetworkConnection GetClient(PlatformID clientID)
		{
			if (!NetworkServer.active)
			{
				return null;
			}
			if (clientID.ID == Client.Instance.SteamId && NetworkServer.connections.Count > 0)
			{
				return NetworkServer.connections[0];
			}
			foreach (NetworkConnection connection in NetworkServer.connections)
			{
				if (connection is SteamNetworkConnection { steamId: var steamId } steamNetworkConnection && steamId.value == clientID.value)
				{
					return steamNetworkConnection;
				}
			}
			UnityEngine.Debug.LogError("Client not found");
			return null;
		}

		public override void OnServerConnect(NetworkConnection conn)
		{
			base.OnServerConnect(conn);
			if (NetworkUser.readOnlyInstancesList.Count >= base.maxConnections)
			{
				ServerKickClient(conn, new SimpleLocalizedKickReason("KICK_REASON_SERVERFULL"));
			}
			else
			{
				FireServerConnectGlobalEvent(conn);
			}
		}

		public override void OnServerDisconnect(NetworkConnection conn)
		{
			FireServerDisconnectGlobalEvent(conn);
			if (conn.clientOwnedObjects != null)
			{
				foreach (NetworkInstanceId item in new HashSet<NetworkInstanceId>(conn.clientOwnedObjects))
				{
					GameObject gameObject = NetworkServer.FindLocalObject(item);
					if (gameObject != null && (bool)gameObject.GetComponent<CharacterMaster>())
					{
						NetworkIdentity component = gameObject.GetComponent<NetworkIdentity>();
						if ((bool)component && component.clientAuthorityOwner == conn)
						{
							component.RemoveClientAuthority(conn);
						}
					}
				}
			}
			List<UnityEngine.Networking.PlayerController> playerControllers = conn.playerControllers;
			for (int i = 0; i < playerControllers.Count; i++)
			{
				NetworkUser component2 = playerControllers[i].gameObject.GetComponent<NetworkUser>();
				if ((bool)component2)
				{
					Chat.SendPlayerDisconnectedMessage(component2);
				}
			}
			if (conn is SteamNetworkConnection)
			{
				UnityEngine.Debug.LogFormat("Closing connection with steamId {0}", ((SteamNetworkConnection)conn).steamId);
			}
			base.OnServerDisconnect(conn);
		}

		public override void InitPlatformServer()
		{
			ServerManagerBase<SteamworksServerManager>.StartServer();
			InitP2P();
		}

		public override void OnStopServer()
		{
			FireStopServerGlobalEvent();
			for (int i = 0; i < NetworkServer.connections.Count; i++)
			{
				NetworkConnection networkConnection = NetworkServer.connections[i];
				if (networkConnection != null)
				{
					OnServerDisconnect(networkConnection);
				}
			}
			if ((bool)serverNetworkSessionInstance)
			{
				UnityEngine.Object.Destroy(serverNetworkSessionInstance);
			}
			serverNetworkSessionInstance = null;
			ServerManagerBase<SteamworksServerManager>.StopServer();
		}

		public override void ServerBanClient(NetworkConnection conn)
		{
			if (conn is SteamNetworkConnection steamNetworkConnection)
			{
				steamIdBanList.Add(steamNetworkConnection.steamId);
			}
		}

		protected override NetworkUserId AddPlayerIdFromPlatform(NetworkConnection conn, AddPlayerMessage message, byte playerControllerId)
		{
			NetworkUserId result = NetworkUserId.FromIp(conn.address, playerControllerId);
			PlatformID platformID = ServerAuthManager.FindAuthData(conn)?.platformId ?? PlatformID.nil;
			if (platformID != PlatformID.nil)
			{
				result = NetworkUserId.FromId(platformID.ID, playerControllerId);
			}
			return result;
		}

		protected override void KickClient(NetworkConnection conn, BaseKickReason reason)
		{
			if (conn is SteamNetworkConnection steamNetworkConnection)
			{
				steamNetworkConnection.ignore = true;
			}
		}

		public override void ServerHandleClientDisconnect(NetworkConnection conn)
		{
			OnServerDisconnect(conn);
			conn.InvokeHandlerNoData(33);
			conn.Disconnect();
			conn.Dispose();
			if (conn is SteamNetworkConnection)
			{
				NetworkServer.RemoveExternalConnection(conn.connectionId);
			}
		}

		protected override void UpdateServer()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			ReadOnlyCollection<NetworkConnection> connections = NetworkServer.connections;
			for (int num = connections.Count - 1; num >= 0; num--)
			{
				if (connections[num] is SteamNetworkConnection steamNetworkConnection)
				{
					Facepunch.Steamworks.Networking.P2PSessionState sessionState = default(Facepunch.Steamworks.Networking.P2PSessionState);
					if (Client.Instance.Networking.GetP2PSessionState(steamNetworkConnection.steamId.ID, ref sessionState) && sessionState.Connecting == 0 && sessionState.ConnectionActive == 0)
					{
						ServerHandleClientDisconnect(steamNetworkConnection);
					}
				}
			}
		}

		public override void OnStartClient(NetworkClient newClient)
		{
			base.OnStartClient(newClient);
			InitP2P();
		}

		public override void OnClientConnect(NetworkConnection conn)
		{
			base.OnClientConnect(conn);
		}

		public override void OnClientDisconnect(NetworkConnection conn)
		{
			if (conn is SteamNetworkConnection steamNetworkConnection)
			{
				UnityEngine.Debug.LogFormat("Closing connection with steamId {0}", steamNetworkConnection.steamId);
			}
			base.OnClientDisconnect(conn);
		}

		protected override AddPlayerMessage CreateClientAddPlayerMessage()
		{
			if (Client.Instance != null)
			{
				return new AddPlayerMessage
				{
					id = new PlatformID(Client.Instance.SteamId),
					steamAuthTicketData = Client.Instance.Auth.GetAuthSessionTicket().Data
				};
			}
			return new AddPlayerMessage
			{
				id = default(PlatformID),
				steamAuthTicketData = Array.Empty<byte>()
			};
		}

		protected override void UpdateCheckInactiveConnections()
		{
			if (client?.connection is SteamNetworkConnection)
			{
				Facepunch.Steamworks.Networking.P2PSessionState sessionState = default(Facepunch.Steamworks.Networking.P2PSessionState);
				if (Client.Instance.Networking.GetP2PSessionState(((SteamNetworkConnection)client.connection).steamId.ID, ref sessionState) && sessionState.Connecting == 0 && sessionState.ConnectionActive == 0)
				{
					client.connection.InvokeHandlerNoData(33);
					StopClient();
				}
			}
		}

		protected override void PlatformAuth(ref ClientAuthData authData, NetworkConnection conn)
		{
			authData.platformId = new PlatformID(Client.Instance.SteamId);
			authData.authTicket = Client.Instance.Auth.GetAuthSessionTicket().Data;
			authData.entitlements = PlatformSystems.entitlementsSystem.BuildEntitlements();
		}

		protected override void StartClient(PlatformID serverID)
		{
			if (!NetworkServer.active)
			{
				NetworkManager.networkSceneName = "";
			}
			string text = "";
			if (isNetworkActive)
			{
				text += "isNetworkActive ";
			}
			if (NetworkClient.active)
			{
				text += "NetworkClient.active ";
			}
			if (NetworkServer.active)
			{
				text += "NetworkClient.active ";
			}
			if (NetworkManagerSystem.isLoadingScene)
			{
				text += "isLoadingScene ";
			}
			if (text != "")
			{
				RoR2Application.onNextUpdate += delegate
				{
				};
			}
			SteamNetworkConnection steamNetworkConnection = new SteamNetworkConnection(Client.Instance, serverID);
			SteamNetworkClient steamNetworkClient = new SteamNetworkClient(steamNetworkConnection);
			steamNetworkClient.Configure(base.connectionConfig, 1);
			UseExternalClient(steamNetworkClient);
			steamNetworkClient.Connect();
			UnityEngine.Debug.LogFormat("Initiating connection to server {0}...", serverID.value);
			if (!steamNetworkConnection.SendConnectionRequest())
			{
				UnityEngine.Debug.LogFormat("Failed to send connection request to server {0}.", serverID.value);
			}
		}

		public override bool IsConnectedToServer(PlatformID serverID)
		{
			if (client == null || !client.connection.isConnected || Client.Instance == null)
			{
				return false;
			}
			if (client.connection is SteamNetworkConnection steamNetworkConnection)
			{
				return steamNetworkConnection.steamId == serverID;
			}
			if (client.connection.address == "localServer")
			{
				return serverID == base.serverP2PId;
			}
			return false;
		}

		public static bool IsMemberInSteamLobby(PlatformID steamId)
		{
			return Client.Instance.Lobby.UserIsInCurrentLobby(steamId.ID);
		}

		private static PlatformID GetSteamworksSteamId(BaseSteamworks steamworks)
		{
			if (steamworks is Client client)
			{
				return new PlatformID(client.SteamId);
			}
			if (steamworks is Server server)
			{
				return new PlatformID(server.SteamId);
			}
			return PlatformID.nil;
		}

		protected void InitP2P()
		{
			Facepunch.Steamworks.Networking networking = Server.Instance?.Networking;
			Facepunch.Steamworks.Networking networking2 = Client.Instance?.Networking;
			if (networking != null)
			{
				networking.OnIncomingConnection = OnSteamServerP2PIncomingConnection;
				networking.OnConnectionFailed = OnSteamServerP2PConnectionFailed;
				networking.OnP2PData = OnSteamServerP2PData;
				for (int i = 0; i < base.connectionConfig.ChannelCount; i++)
				{
					networking.SetListenChannel(i, Listen: true);
				}
			}
			if (networking2 != null)
			{
				networking2.OnIncomingConnection = OnSteamClientP2PIncomingConnection;
				networking2.OnConnectionFailed = OnSteamClientP2PConnectionFailed;
				networking2.OnP2PData = OnSteamClientP2PData;
				for (int j = 0; j < base.connectionConfig.ChannelCount; j++)
				{
					networking2.SetListenChannel(j, Listen: true);
				}
			}
			clientSteamworks = Client.Instance;
			serverSteamworks = null;
			if (NetworkServer.active)
			{
				serverSteamworks = (BaseSteamworks)(((object)(cvSteamP2PUseSteamServer.value ? Server.Instance : null)) ?? ((object)Client.Instance));
			}
			base.clientP2PId = GetSteamworksSteamId(clientSteamworks);
			base.serverP2PId = GetSteamworksSteamId(serverSteamworks);
		}

		private bool OnSteamServerP2PIncomingConnection(ulong senderSteamId)
		{
			return OnIncomingP2PConnection(Server.Instance, new PlatformID(senderSteamId));
		}

		private void OnSteamServerP2PConnectionFailed(ulong senderSteamId, Facepunch.Steamworks.Networking.SessionError sessionError)
		{
			OnP2PConnectionFailed(Server.Instance, new PlatformID(senderSteamId), sessionError);
		}

		private void OnSteamServerP2PData(ulong senderSteamId, byte[] data, int dataLength, int channel)
		{
			OnP2PData(Server.Instance, new PlatformID(senderSteamId), data, dataLength, channel);
		}

		private bool OnSteamClientP2PIncomingConnection(ulong senderSteamId)
		{
			return OnIncomingP2PConnection(Client.Instance, new PlatformID(senderSteamId));
		}

		private void OnSteamClientP2PConnectionFailed(ulong senderSteamId, Facepunch.Steamworks.Networking.SessionError sessionError)
		{
			OnP2PConnectionFailed(Client.Instance, new PlatformID(senderSteamId), sessionError);
		}

		private void OnSteamClientP2PData(ulong senderSteamId, byte[] data, int dataLength, int channel)
		{
			OnP2PData(Client.Instance, new PlatformID(senderSteamId), data, dataLength, channel);
		}

		private bool OnIncomingP2PConnection(BaseSteamworks receiver, PlatformID senderSteamId)
		{
			bool flag = false;
			if (receiver == serverSteamworks)
			{
				if (NetworkServer.active)
				{
					flag = !NetworkServer.dontListen && !steamIdBanList.Contains(senderSteamId) && !IsServerAtMaxConnections();
				}
				else if (client is SteamNetworkClient && ((SteamNetworkClient)client).steamConnection.steamId == senderSteamId)
				{
					flag = true;
				}
			}
			UnityEngine.Debug.LogFormat("Incoming Steamworks connection from Steam ID {0}: {1}", senderSteamId, flag ? "accepted" : "rejected");
			if (flag)
			{
				CreateServerP2PConnectionWithPeer(receiver, senderSteamId);
			}
			return flag;
		}

		private void OnP2PConnectionFailed(BaseSteamworks receiver, PlatformID senderSteamId, Facepunch.Steamworks.Networking.SessionError sessionError)
		{
			UnityEngine.Debug.LogFormat("NetworkManagerSystem.OnClientP2PConnectionFailed steamId={0} sessionError={1}", senderSteamId, sessionError);
			SteamNetworkConnection steamNetworkConnection = SteamNetworkConnection.Find(receiver, senderSteamId);
			if (steamNetworkConnection != null)
			{
				if (client != null && client.connection == steamNetworkConnection)
				{
					steamNetworkConnection.InvokeHandlerNoData(33);
					steamNetworkConnection.Disconnect();
					steamNetworkConnection.Dispose();
				}
				if (NetworkServer.active && NetworkServer.connections.IndexOf(steamNetworkConnection) != -1)
				{
					ServerHandleClientDisconnect(steamNetworkConnection);
				}
			}
		}

		private void OnP2PData(BaseSteamworks receiver, PlatformID senderSteamId, byte[] data, int dataLength, int channel)
		{
			if (SteamNetworkConnection.cvNetP2PDebugTransport.value)
			{
				UnityEngine.Debug.LogFormat("Received packet from {0} dataLength={1} channel={2}", senderSteamId, dataLength, channel);
			}
			SteamNetworkConnection steamNetworkConnection = SteamNetworkConnection.Find(receiver, senderSteamId);
			if (steamNetworkConnection != null)
			{
				steamNetworkConnection.TransportReceive(data, dataLength, 0);
				return;
			}
			UnityEngine.Debug.LogFormat("Rejecting data from sender: Not associated with a registered connection. steamid={0} dataLength={1}", senderSteamId, data);
		}

		public void CreateServerP2PConnectionWithPeer(BaseSteamworks steamworks, PlatformID peer)
		{
			SteamNetworkConnection steamNetworkConnection = new SteamNetworkConnection(steamworks, peer);
			steamNetworkConnection.ForceInitialize(NetworkServer.hostTopology);
			int num = -1;
			ReadOnlyCollection<NetworkConnection> connections = NetworkServer.connections;
			for (int i = 1; i < connections.Count; i++)
			{
				if (connections[i] == null)
				{
					num = i;
					break;
				}
			}
			if (num == -1)
			{
				num = connections.Count;
			}
			steamNetworkConnection.connectionId = num;
			NetworkServer.AddExternalConnection(steamNetworkConnection);
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.StartMessage(32);
			networkWriter.FinishMessage();
			steamNetworkConnection.SendWriter(networkWriter, QosChannelIndex.defaultReliable.intVal);
		}

		protected override void PlatformClientSetPlayers(ConCommandArgs args)
		{
			if (client != null && client.connection != null)
			{
				ClientSetPlayers(client.connection);
			}
		}

		protected override void PlatformConnectP2P(ConCommandArgs args)
		{
			CheckSteamworks();
			PlatformID argPlatformID = args.GetArgPlatformID(0);
			if (Client.Instance.Lobby.IsValid && !PlatformSystems.lobbyManager.ownsLobby && argPlatformID != PlatformSystems.lobbyManager.newestLobbyData.serverId)
			{
				UnityEngine.Debug.LogFormat("Cannot connect to server {0}: Server is not the one specified by the current steam lobby.", argPlatformID);
			}
			else if (!(base.clientP2PId == argPlatformID))
			{
				NetworkManagerSystem.singleton.desiredHost = new HostDescription(argPlatformID, HostDescription.HostType.Steam);
			}
		}

		protected override void PlatformDisconnect(ConCommandArgs args)
		{
			NetworkManagerSystem.singleton.desiredHost = HostDescription.none;
		}

		protected override void PlatformConnect(ConCommandArgs args)
		{
			AddressPortPair argAddressPortPair = args.GetArgAddressPortPair(0);
			if ((bool)NetworkManagerSystem.singleton)
			{
				NetworkManagerSystem.EnsureNetworkManagerNotBusy();
				UnityEngine.Debug.LogFormat("Parsed address={0} port={1}. Setting desired host.", argAddressPortPair.address, argAddressPortPair.port);
				NetworkManagerSystem.singleton.desiredHost = new HostDescription(argAddressPortPair);
			}
		}

		protected override void PlatformHost(ConCommandArgs args)
		{
			if (!NetworkManagerSystem.singleton)
			{
				return;
			}
			bool argBool = args.GetArgBool(0);
			if (PlatformSystems.lobbyManager.isInLobby && !PlatformSystems.lobbyManager.ownsLobby)
			{
				return;
			}
			bool flag = false;
			if (NetworkServer.active)
			{
				flag = true;
			}
			if (!flag)
			{
				int maxPlayers = SvMaxPlayersConVar.instance.intValue;
				if (PlatformSystems.lobbyManager.isInLobby)
				{
					maxPlayers = PlatformSystems.lobbyManager.newestLobbyData.totalMaxPlayers;
				}
				NetworkManagerSystem.singleton.desiredHost = new HostDescription(new HostDescription.HostingParameters
				{
					listen = argBool,
					maxPlayers = maxPlayers
				});
			}
		}

		protected override void PlatformGetP2PSessionState(ConCommandArgs args)
		{
			CheckSteamworks();
			PlatformID argPlatformID = args.GetArgPlatformID(0);
			if ((bool)NetworkManagerSystem.singleton)
			{
				Facepunch.Steamworks.Networking.P2PSessionState sessionState = default(Facepunch.Steamworks.Networking.P2PSessionState);
				if (Client.Instance.Networking.GetP2PSessionState(argPlatformID.ID, ref sessionState))
				{
					UnityEngine.Debug.LogFormat("ConnectionActive={0}\nConnecting={1}\nP2PSessionError={2}\nUsingRelay={3}\nBytesQueuedForSend={4}\nPacketsQueuedForSend={5}\nRemoteIP={6}\nRemotePort={7}", sessionState.ConnectionActive, sessionState.Connecting, sessionState.P2PSessionError, sessionState.UsingRelay, sessionState.BytesQueuedForSend, sessionState.PacketsQueuedForSend, sessionState.RemoteIP, sessionState.RemotePort);
				}
				else
				{
					UnityEngine.Debug.LogFormat("Could not get p2p session info for steamId={0}", argPlatformID);
				}
			}
		}

		protected override void PlatformKick(ConCommandArgs args)
		{
			CheckSteamworks();
			PlatformID argPlatformID = args.GetArgPlatformID(0);
			NetworkConnection networkConnection = NetworkManagerSystem.singleton.GetClient(argPlatformID);
			if (networkConnection != null)
			{
				NetworkManagerSystem.singleton.ServerKickClient(networkConnection, new SimpleLocalizedKickReason("KICK_REASON_KICK"));
			}
		}

		protected override void PlatformBan(ConCommandArgs args)
		{
			CheckSteamworks();
			PlatformID argPlatformID = args.GetArgPlatformID(0);
			NetworkConnection networkConnection = NetworkManagerSystem.singleton.GetClient(argPlatformID);
			if (networkConnection != null)
			{
				NetworkManagerSystem.singleton.ServerBanClient(networkConnection);
				NetworkManagerSystem.singleton.ServerKickClient(networkConnection, new SimpleLocalizedKickReason("KICK_REASON_BAN"));
			}
		}

		public static void CheckSteamworks()
		{
			if (Client.Instance == null)
			{
				throw new ConCommandException("Steamworks not available.");
			}
		}

		public override void CreateLocalLobby()
		{
		}
	}
}
namespace RoR2.ExpansionManagement
{
	public enum ExpansionIndex
	{
		None = -1
	}
	public static class ExpansionCatalog
	{
		private static ExpansionDef[] _expansionDefs = Array.Empty<ExpansionDef>();

		public static ReadOnlyArray<ExpansionDef> expansionDefs => _expansionDefs;

		private static void SetExpansions(ExpansionDef[] newExpansionsDefs)
		{
			ArrayUtils.CloneTo(newExpansionsDefs, ref _expansionDefs);
			for (int i = 0; i < _expansionDefs.Length; i++)
			{
				_expansionDefs[i].expansionIndex = (ExpansionIndex)i;
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetExpansions(ContentManager.expansionDefs);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/ExpansionDef")]
	public class ExpansionDef : ScriptableObject
	{
		[SerializeField]
		[HideInInspector]
		public ExpansionIndex expansionIndex;

		[Tooltip("The entitlement required to use this expansion.")]
		public EntitlementDef requiredEntitlement;

		[Tooltip("The token for the user-facing name of this expansion.")]
		public string nameToken;

		[Tooltip("The token for the user-facing description of this expansion.")]
		public string descriptionToken;

		[Tooltip("The icon for this expansion.")]
		[ShowThumbnail]
		public Sprite iconSprite;

		[Tooltip("The icon to display when this expansion is disabled.")]
		[ShowThumbnail]
		public Sprite disabledIconSprite;

		public RuleChoiceDef enabledChoice;

		[Tooltip("This prefab is instantiated and childed to the run")]
		public GameObject runBehaviorPrefab;
	}
	public class ExpansionRequirementComponent : MonoBehaviour
	{
		public ExpansionDef requiredExpansion;

		public bool requireEntitlementIfPlayerControlled;

		public static bool ignoreExpansionDisablingForPlayerControlled = true;

		private void Start()
		{
			CharacterBody component = GetComponent<CharacterBody>();
			if ((bool)component && component.isPlayerControlled && !PlayerCanUseBody(component.master.playerCharacterMasterController))
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		public bool IgnoreExpansionDisabling()
		{
			if (requireEntitlementIfPlayerControlled)
			{
				return ignoreExpansionDisablingForPlayerControlled;
			}
			return false;
		}

		public bool PlayerCanUseBody(PlayerCharacterMasterController playerCharacterMasterController)
		{
			Run instance = Run.instance;
			if (!instance)
			{
				return false;
			}
			if ((bool)requiredExpansion)
			{
				if (!instance.IsExpansionEnabled(requiredExpansion) && !IgnoreExpansionDisabling())
				{
					return false;
				}
				if (requireEntitlementIfPlayerControlled)
				{
					EntitlementDef requiredEntitlement = requiredExpansion.requiredEntitlement;
					if ((bool)requiredEntitlement)
					{
						PlayerCharacterMasterControllerEntitlementTracker component = playerCharacterMasterController.GetComponent<PlayerCharacterMasterControllerEntitlementTracker>();
						if (!component)
						{
							UnityEngine.Debug.LogWarning("Rejecting body because the playerCharacterMasterController doesn't have a sibling PlayerCharacterMasterControllerEntitlementTracker");
							return false;
						}
						if (!component.HasEntitlement(requiredEntitlement))
						{
							UnityEngine.Debug.LogWarning("Rejecting body because the player doesn't have entitlement " + requiredEntitlement.name);
							return false;
						}
					}
				}
			}
			return true;
		}
	}
}
namespace RoR2.Projectile
{
	[RequireComponent(typeof(ProjectileController))]
	public class CleaverProjectile : NetworkBehaviour, IProjectileImpactBehavior
	{
		private enum BoomerangState
		{
			FlyOut,
			Transition,
			FlyBack,
			Stopped
		}

		public float travelSpeed = 40f;

		public float charge;

		public float transitionDuration;

		private float maxFlyStopwatch;

		public GameObject impactSpark;

		public GameObject returnImpactSpark;

		public GameObject crosshairPrefab;

		public bool canHitCharacters;

		public bool canHitWorld;

		public bool returnOnHitWorldOrHover;

		public ProjectileController projectileController;

		[SyncVar]
		private BoomerangState boomerangState;

		private Transform ownerTransform;

		private ProjectileDamage projectileDamage;

		private Rigidbody rigidbody;

		private float stopwatch;

		private float fireAge;

		private float fireFrequency;

		[FormerlySerializedAs("distanceMultiplier")]
		public float travelTime = 2f;

		public UnityEvent onFlyBack;

		private bool setScale;

		private bool recallDamageFired;

		private float stoppedStopwatch = 3f;

		private ChefController chefController;

		private ushort predictionId;

		private bool recalled;

		private bool hasEffectiveAuthority;

		private bool disableOnRcall_ReelingCache;

		public Collider[] disableOnRecall;

		private static int kCmdCmdDestroyAndCleanup;

		public BoomerangState NetworkboomerangState
		{
			get
			{
				return boomerangState;
			}
			[param: In]
			set
			{
				ulong newValueAsUlong = (ulong)value;
				ulong fieldValueAsUlong = (ulong)boomerangState;
				SetSyncVarEnum(value, newValueAsUlong, ref boomerangState, fieldValueAsUlong, 1u);
			}
		}

		private void Awake()
		{
			rigidbody = GetComponent<Rigidbody>();
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			maxFlyStopwatch = travelTime;
		}

		private void Start()
		{
			if ((bool)projectileController)
			{
				predictionId = projectileController.predictionId;
				if ((bool)projectileController.owner)
				{
					ownerTransform = projectileController.owner.transform;
					chefController = projectileController.owner.GetComponent<ChefController>();
					if ((bool)chefController)
					{
						chefController.AddLocalProjectileReference(predictionId, this);
						if (base.hasAuthority && !NetworkServer.active && chefController.TryRetrieveCachedProjectileFireInfo(out var fireProjectileInfo))
						{
							ApplyCachedFireProjectileInfo(fireProjectileInfo);
						}
					}
				}
			}
			hasEffectiveAuthority = Util.HasEffectiveAuthority(chefController.gameObject);
		}

		private void ApplyCachedFireProjectileInfo(FireProjectileInfo fireProjectileInfo)
		{
			ProjectileDamage component = GetComponent<ProjectileDamage>();
			TeamFilter component2 = GetComponent<TeamFilter>();
			ProjectileSimple component3 = GetComponent<ProjectileSimple>();
			if ((bool)component2)
			{
				component2.teamIndex = TeamComponent.GetObjectTeam(fireProjectileInfo.owner);
			}
			if (fireProjectileInfo.useSpeedOverride && (bool)component3)
			{
				component3.desiredForwardSpeed = fireProjectileInfo.speedOverride;
			}
			if ((bool)component)
			{
				component.damage = fireProjectileInfo.damage;
				component.force = fireProjectileInfo.force;
				component.crit = fireProjectileInfo.crit;
				component.damageColorIndex = fireProjectileInfo.damageColorIndex;
				if (fireProjectileInfo.damageTypeOverride.HasValue)
				{
					component.damageType = fireProjectileInfo.damageTypeOverride.Value;
				}
			}
			projectileController.DispatchOnInitialized();
		}

		private void OnEnable()
		{
			recalled = false;
			recallDamageFired = false;
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (!canHitWorld)
			{
				return;
			}
			if (impactInfo.collider.gameObject.layer == LayerIndex.world.intVal)
			{
				if (returnOnHitWorldOrHover)
				{
					NetworkboomerangState = BoomerangState.FlyBack;
				}
				else
				{
					NetworkboomerangState = BoomerangState.Stopped;
				}
			}
			if (boomerangState != BoomerangState.Stopped)
			{
				EffectManager.SimpleImpactEffect(recalled ? returnImpactSpark : impactSpark, impactInfo.estimatedPointOfImpact, -base.transform.forward, transmit: true);
			}
		}

		private bool Reel()
		{
			UnityEngine.Vector3 vector = projectileController.owner.transform.position - base.transform.position;
			_ = vector.normalized;
			float magnitude = vector.magnitude;
			if (!chefController)
			{
				chefController = projectileController.owner.GetComponent<ChefController>();
			}
			return magnitude <= 2f;
		}

		public void FixedUpdate()
		{
			if (!hasEffectiveAuthority)
			{
				return;
			}
			if (!setScale)
			{
				setScale = true;
			}
			if (!projectileController.owner)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			if (!chefController)
			{
				chefController = projectileController.owner.GetComponent<ChefController>();
			}
			recalled = recalled || chefController.recallCleaver || boomerangState == BoomerangState.FlyBack;
			if ((bool)chefController && recalled && boomerangState != BoomerangState.Transition)
			{
				NetworkboomerangState = BoomerangState.FlyBack;
			}
			if (returnOnHitWorldOrHover && boomerangState == BoomerangState.Stopped)
			{
				NetworkboomerangState = BoomerangState.FlyBack;
				recalled = true;
			}
			if (!recalled)
			{
				ToggleThrowOnlyObjects(isReeling: false);
				switch (boomerangState)
				{
				case BoomerangState.FlyOut:
					rigidbody.velocity = travelSpeed * base.transform.forward;
					stopwatch += Time.fixedDeltaTime;
					if (stopwatch >= maxFlyStopwatch)
					{
						stopwatch = 0f;
						NetworkboomerangState = BoomerangState.Stopped;
					}
					break;
				case BoomerangState.Transition:
				{
					stopwatch += Time.fixedDeltaTime;
					float num = stopwatch / transitionDuration;
					UnityEngine.Vector3 vector = CalculatePullDirection();
					rigidbody.velocity = UnityEngine.Vector3.Lerp(travelSpeed * base.transform.forward, travelSpeed * vector, num);
					if (num >= 0.1f)
					{
						NetworkboomerangState = BoomerangState.FlyBack;
						onFlyBack?.Invoke();
					}
					break;
				}
				case BoomerangState.Stopped:
					chefController = projectileController.owner.GetComponent<ChefController>();
					rigidbody.velocity = new UnityEngine.Vector3(0f, 0f, 0f);
					stopwatch += Time.deltaTime;
					if (stopwatch > stoppedStopwatch)
					{
						CallCmdDestroyAndCleanup();
					}
					break;
				case BoomerangState.FlyBack:
					break;
				}
				return;
			}
			ToggleThrowOnlyObjects(isReeling: true);
			if (!recallDamageFired)
			{
				rigidbody.velocity = new UnityEngine.Vector3(0f, 0f, 0f);
				GetComponent<ProjectileOverlapAttack>().ResetOverlapAttack();
				projectileDamage.damage *= 1.5f;
				recallDamageFired = true;
			}
			bool num2 = Reel();
			UnityEngine.Vector3 vector2 = CalculatePullDirection();
			rigidbody.velocity = travelSpeed * vector2;
			if (num2)
			{
				if (chefController != null)
				{
					chefController.NetworkcatchDirtied = true;
				}
				CallCmdDestroyAndCleanup();
			}
		}

		private void ToggleThrowOnlyObjects(bool isReeling)
		{
			if (disableOnRcall_ReelingCache != isReeling)
			{
				int num = disableOnRecall.Length;
				for (int i = 0; i < num; i++)
				{
					disableOnRecall[i].enabled = !isReeling;
				}
				disableOnRcall_ReelingCache = isReeling;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		[Command]
		public void CmdDestroyAndCleanup()
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}

		private UnityEngine.Vector3 CalculatePullDirection()
		{
			if ((bool)projectileController.owner)
			{
				return (projectileController.owner.transform.position - base.transform.position).normalized;
			}
			return base.transform.forward;
		}

		private void OnDestroy()
		{
			if ((bool)chefController)
			{
				chefController.RemoveLocalProjectileReference(predictionId);
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdDestroyAndCleanup(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdDestroyAndCleanup called on client.");
			}
			else
			{
				((CleaverProjectile)obj).CmdDestroyAndCleanup();
			}
		}

		public void CallCmdDestroyAndCleanup()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdDestroyAndCleanup called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdDestroyAndCleanup();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdDestroyAndCleanup);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdDestroyAndCleanup");
		}

		static CleaverProjectile()
		{
			kCmdCmdDestroyAndCleanup = 978502080;
			NetworkBehaviour.RegisterCommandDelegate(typeof(CleaverProjectile), kCmdCmdDestroyAndCleanup, InvokeCmdCmdDestroyAndCleanup);
			NetworkCRC.RegisterBehaviour("CleaverProjectile", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write((int)boomerangState);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write((int)boomerangState);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				boomerangState = (BoomerangState)reader.ReadInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				boomerangState = (BoomerangState)reader.ReadInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(ProjectileTargetComponent))]
	[RequireComponent(typeof(Rigidbody))]
	public class SoulSearchController : MonoBehaviour
	{
		private new Transform transform;

		private Rigidbody rigidbody;

		private TeamFilter teamFilter;

		private HurtBox trackingTarget;

		private ProjectileController projectileController;

		public float maxVelocity;

		public float rollVelocity;

		public float acceleration;

		public float delayTimer;

		public float giveupTimer = 8f;

		public float deathTimer = 10f;

		private float timer;

		private QuaternionPID torquePID;

		public float turbulence;

		public float maxSeekDistance = 40f;

		private void Awake()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
				return;
			}
			transform = base.transform;
			rigidbody = GetComponent<Rigidbody>();
			torquePID = GetComponent<QuaternionPID>();
			teamFilter = GetComponent<TeamFilter>();
			projectileController = GetComponent<ProjectileController>();
		}

		private void FixedUpdate()
		{
			timer += Time.fixedDeltaTime;
			if (!trackingTarget)
			{
				trackingTarget = projectileController.owner.GetComponent<HuntressTracker>().GetTrackingTarget();
			}
			else
			{
				HealthComponent component = trackingTarget.GetComponent<HealthComponent>();
				if ((bool)component && !component.alive)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
			if (timer > deathTimer)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			rigidbody.velocity = transform.forward * maxVelocity;
			if ((bool)trackingTarget && timer >= delayTimer)
			{
				rigidbody.velocity = transform.forward * (maxVelocity + timer * acceleration);
				UnityEngine.Vector3 vector = trackingTarget.transform.position + UnityEngine.Random.insideUnitSphere * turbulence - transform.position;
				if (vector != UnityEngine.Vector3.zero)
				{
					UnityEngine.Quaternion rotation = transform.rotation;
					UnityEngine.Quaternion targetQuat = Util.QuaternionSafeLookRotation(vector);
					torquePID.inputQuat = rotation;
					torquePID.targetQuat = targetQuat;
					rigidbody.angularVelocity = torquePID.UpdatePID();
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class UnseenHandHealingProjectile : MonoBehaviour, IOnDamageInflictedServerReceiver
	{
		public bool addBarrier;

		public bool addHealing;

		public float fractionOfDamage;

		public float barrierPercent;

		private int chakraCount;

		public float chakraIncrease;

		private ProjectileController projectileController;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
		}

		public void OnDamageInflictedServer(DamageReport damageReport)
		{
			if ((bool)projectileController.owner)
			{
				HealthComponent component = projectileController.owner.GetComponent<HealthComponent>();
				CharacterBody component2 = projectileController.owner.GetComponent<CharacterBody>();
				if (component2 != null)
				{
					chakraCount = component2.GetBuffCount(DLC2Content.Buffs.ChakraBuff);
				}
				if (addHealing && (bool)component)
				{
					HealOrb healOrb = new HealOrb();
					healOrb.origin = base.transform.position;
					healOrb.target = component.body.mainHurtBox;
					healOrb.healValue = damageReport.damageDealt * (fractionOfDamage + (float)chakraCount * chakraIncrease);
					healOrb.overrideDuration = 0.3f;
					OrbManager.instance.AddOrb(healOrb);
				}
				if (addBarrier)
				{
					component.AddBarrierAuthority(component2.baseMaxHealth * (barrierPercent + (float)chakraCount * chakraIncrease));
				}
			}
		}
	}
	[RequireComponent(typeof(HealthComponent))]
	public class AssignTeamFilterToTeamComponent : MonoBehaviour
	{
		private void Start()
		{
			if (NetworkServer.active)
			{
				TeamComponent component = GetComponent<TeamComponent>();
				TeamFilter component2 = GetComponent<TeamFilter>();
				if ((bool)component2 && (bool)component)
				{
					component.teamIndex = component2.teamIndex;
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class BoomerangProjectile : NetworkBehaviour, IProjectileImpactBehavior
	{
		private enum BoomerangState
		{
			FlyOut,
			Transition,
			FlyBack,
			NetworkClientCatchup
		}

		public float travelSpeed = 40f;

		public float charge;

		public float transitionDuration;

		private float maxFlyStopwatch;

		public GameObject impactSpark;

		public GameObject crosshairPrefab;

		public bool canHitCharacters;

		public bool canHitWorld;

		private ProjectileController projectileController;

		[SyncVar]
		private BoomerangState boomerangState;

		private Transform ownerTransform;

		private ProjectileDamage projectileDamage;

		private Rigidbody rigidbody;

		private float stopwatch;

		private float fireAge;

		private float fireFrequency;

		public float distanceMultiplier = 2f;

		public UnityEvent onFlyBack;

		[Tooltip("Allows the server and client side boomerangs to idle harmlessly/invisibly for up to 1 second while the rest of the boomerangs from other clients have time to finish their flight.")]
		public bool EnableNetworkClientCatchup;

		private bool setScale;

		private float networkCatchupTimer = -1f;

		private float networkCatchupDuration = 1f;

		public bool isStunAndPierce;

		public BoomerangState NetworkboomerangState
		{
			get
			{
				return boomerangState;
			}
			[param: In]
			set
			{
				ulong newValueAsUlong = (ulong)value;
				ulong fieldValueAsUlong = (ulong)boomerangState;
				SetSyncVarEnum(value, newValueAsUlong, ref boomerangState, fieldValueAsUlong, 1u);
			}
		}

		private void Awake()
		{
			rigidbody = GetComponent<Rigidbody>();
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			if ((bool)projectileController && (bool)projectileController.owner)
			{
				ownerTransform = projectileController.owner.transform;
			}
			maxFlyStopwatch = charge * distanceMultiplier;
		}

		private void Start()
		{
			float num = charge * 7f;
			if (num < 1f)
			{
				num = 1f;
			}
			UnityEngine.Vector3 localScale = new UnityEngine.Vector3(num * base.transform.localScale.x, num * base.transform.localScale.y, num * base.transform.localScale.z);
			base.transform.localScale = localScale;
			base.gameObject.GetComponent<ProjectileController>().ghost.transform.localScale = localScale;
			GetComponent<ProjectileDotZone>().damageCoefficient *= num;
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (canHitWorld)
			{
				NetworkboomerangState = BoomerangState.FlyBack;
				onFlyBack?.Invoke();
				EffectManager.SimpleImpactEffect(impactSpark, impactInfo.estimatedPointOfImpact, -base.transform.forward, transmit: true);
			}
		}

		private bool Reel()
		{
			return (projectileController.owner.transform.position - base.transform.position).magnitude <= 2f;
		}

		public void FixedUpdate()
		{
			bool active = NetworkServer.active;
			if (active)
			{
				if (!setScale)
				{
					setScale = true;
				}
				if (!projectileController.owner)
				{
					UnityEngine.Object.Destroy(base.gameObject);
					return;
				}
			}
			switch (boomerangState)
			{
			case BoomerangState.FlyOut:
				if (active)
				{
					rigidbody.velocity = travelSpeed * base.transform.forward;
					stopwatch += Time.fixedDeltaTime;
					if (stopwatch >= maxFlyStopwatch)
					{
						stopwatch = 0f;
						NetworkboomerangState = BoomerangState.Transition;
					}
				}
				break;
			case BoomerangState.Transition:
				if (active)
				{
					stopwatch += Time.fixedDeltaTime;
					float num = stopwatch / transitionDuration;
					UnityEngine.Vector3 vector = CalculatePullDirection();
					rigidbody.velocity = UnityEngine.Vector3.Lerp(travelSpeed * base.transform.forward, travelSpeed * vector, num);
					if (num >= 1f)
					{
						NetworkboomerangState = BoomerangState.FlyBack;
						onFlyBack?.Invoke();
					}
				}
				break;
			case BoomerangState.FlyBack:
			{
				bool num2 = Reel();
				if (active)
				{
					canHitWorld = false;
					UnityEngine.Vector3 vector2 = CalculatePullDirection();
					rigidbody.velocity = travelSpeed * vector2;
				}
				if (!num2)
				{
					break;
				}
				if (EnableNetworkClientCatchup)
				{
					projectileController.DisconnectFromGhost();
					if (active)
					{
						networkCatchupTimer = networkCatchupDuration;
						NetworkboomerangState = BoomerangState.NetworkClientCatchup;
					}
				}
				else if (active)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
				break;
			}
			case BoomerangState.NetworkClientCatchup:
				if (!active)
				{
					if (Reel())
					{
						projectileController.DisconnectFromGhost();
					}
					break;
				}
				networkCatchupTimer -= Time.fixedDeltaTime;
				if (networkCatchupTimer <= 0f)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
				break;
			}
			UnityEngine.Vector3 CalculatePullDirection()
			{
				if ((bool)projectileController.owner)
				{
					return (projectileController.owner.transform.position - base.transform.position).normalized;
				}
				return base.transform.forward;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write((int)boomerangState);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write((int)boomerangState);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				boomerangState = (BoomerangState)reader.ReadInt32();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				boomerangState = (BoomerangState)reader.ReadInt32();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(Rigidbody))]
	public class DaggerController : MonoBehaviour
	{
		private new Transform transform;

		private Rigidbody rigidbody;

		public Transform target;

		public float acceleration;

		public float delayTimer;

		public float giveupTimer = 8f;

		public float deathTimer = 10f;

		private float timer;

		public float turbulence;

		private bool hasPlayedSound;

		private void Awake()
		{
			transform = base.transform;
			rigidbody = GetComponent<Rigidbody>();
			rigidbody.AddRelativeForce(UnityEngine.Random.insideUnitSphere * 50f);
		}

		private void FixedUpdate()
		{
			timer += Time.fixedDeltaTime;
			if (timer < giveupTimer)
			{
				if ((bool)target)
				{
					UnityEngine.Vector3 vector = target.transform.position - transform.position;
					if (vector != UnityEngine.Vector3.zero)
					{
						transform.rotation = Util.QuaternionSafeLookRotation(vector);
					}
					if (timer >= delayTimer)
					{
						rigidbody.AddForce(transform.forward * acceleration);
						if (!hasPlayedSound)
						{
							Util.PlaySound("Play_item_proc_dagger_fly", base.gameObject);
							hasPlayedSound = true;
						}
					}
				}
			}
			else
			{
				rigidbody.useGravity = true;
			}
			if (!target)
			{
				target = FindTarget();
			}
			else
			{
				HealthComponent component = target.GetComponent<HealthComponent>();
				if ((bool)component && !component.alive)
				{
					target = FindTarget();
				}
			}
			if (timer > deathTimer)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private Transform FindTarget()
		{
			ReadOnlyCollection<TeamComponent> teamMembers = TeamComponent.GetTeamMembers(TeamIndex.Monster);
			float num = 99999f;
			Transform result = null;
			for (int i = 0; i < teamMembers.Count; i++)
			{
				float num2 = UnityEngine.Vector3.SqrMagnitude(teamMembers[i].transform.position - transform.position);
				if (num2 < num)
				{
					num = num2;
					result = teamMembers[i].transform;
				}
			}
			return result;
		}
	}
	[RequireComponent(typeof(ProjectileDamage))]
	[RequireComponent(typeof(HealthComponent))]
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileStickOnImpact))]
	public class DeathProjectile : MonoBehaviour
	{
		private ProjectileStickOnImpact projectileStickOnImpactController;

		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private HealthComponent healthComponent;

		public GameObject OnKillTickEffect;

		public TeamIndex teamIndex;

		public string activeSoundLoopString;

		public string exitSoundString;

		private float duration;

		private float fixedAge;

		public float baseDuration = 8f;

		public float radius = 500f;

		public GameObject rotateObject;

		private bool doneWithRemovalEvents;

		public float removalTime = 1f;

		private bool shouldStopSound;

		private void Awake()
		{
			projectileStickOnImpactController = GetComponent<ProjectileStickOnImpact>();
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			healthComponent = GetComponent<HealthComponent>();
			duration = baseDuration;
			fixedAge = 0f;
		}

		private void FixedUpdate()
		{
			fixedAge += Time.deltaTime;
			if (duration > 0f)
			{
				if (!(fixedAge >= 1f))
				{
					return;
				}
				if (projectileStickOnImpactController.stuck)
				{
					if ((bool)projectileController.owner)
					{
						RotateDoll(UnityEngine.Random.Range(90f, 180f));
						SpawnTickEffect();
						if (NetworkServer.active)
						{
							DamageInfo damageInfo = new DamageInfo
							{
								attacker = projectileController.owner,
								crit = projectileDamage.crit,
								damage = projectileDamage.damage,
								position = base.transform.position,
								procCoefficient = projectileController.procCoefficient,
								damageType = projectileDamage.damageType,
								damageColorIndex = projectileDamage.damageColorIndex
							};
							HealthComponent victim = healthComponent;
							DamageReport damageReport = new DamageReport(damageInfo, victim, damageInfo.damage, healthComponent.combinedHealth);
							GlobalEventManager.instance.OnCharacterDeath(damageReport);
						}
					}
					duration -= 1f;
				}
				fixedAge = 0f;
			}
			else
			{
				if (!doneWithRemovalEvents)
				{
					doneWithRemovalEvents = true;
					rotateObject.GetComponent<ObjectScaleCurve>().enabled = true;
				}
				if (fixedAge >= removalTime)
				{
					Util.PlaySound(exitSoundString, base.gameObject);
					shouldStopSound = false;
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}

		private void OnDisable()
		{
			if (shouldStopSound)
			{
				Util.PlaySound(exitSoundString, base.gameObject);
				shouldStopSound = false;
			}
		}

		public void SpawnTickEffect()
		{
			EffectData effectData = new EffectData
			{
				origin = base.transform.position,
				rotation = UnityEngine.Quaternion.identity
			};
			EffectManager.SpawnEffect(OnKillTickEffect, effectData, transmit: false);
		}

		public void PlayStickSoundLoop()
		{
			Util.PlaySound(activeSoundLoopString, base.gameObject);
			shouldStopSound = true;
		}

		public void RotateDoll(float rotationAmount)
		{
			rotateObject.transform.Rotate(new UnityEngine.Vector3(0f, 0f, rotationAmount));
		}
	}
	[RequireComponent(typeof(ProjectileGhostController))]
	public class EngiMineGhostController : MonoBehaviour
	{
		private ProjectileGhostController projectileGhostController;

		private EntityStateMachine armingStateMachine;

		[Tooltip("Child object which will be enabled if the projectile is armed.")]
		public GameObject stickIndicator;

		private bool cachedArmed;

		private void Awake()
		{
			projectileGhostController = GetComponent<ProjectileGhostController>();
			stickIndicator.SetActive(value: false);
		}

		private void Start()
		{
			Transform authorityTransform = projectileGhostController.authorityTransform;
			if ((bool)authorityTransform)
			{
				armingStateMachine = EntityStateMachine.FindByCustomName(authorityTransform.gameObject, "Arming");
			}
		}

		private bool IsArmed()
		{
			return ((armingStateMachine?.state as BaseMineArmingState)?.damageScale ?? 0f) > 1f;
		}

		private void FixedUpdate()
		{
			bool flag = IsArmed();
			if (flag != cachedArmed)
			{
				cachedArmed = flag;
				stickIndicator.SetActive(flag);
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileTargetComponent))]
	public class GatewayProjectileController : NetworkBehaviour, IInteractable
	{
		private ProjectileController projectileController;

		private ProjectileTargetComponent projectileTargetComponent;

		[SyncVar(hook = "SetLinkedObject")]
		private GameObject linkedObject;

		private GatewayProjectileController linkedGatewayProjectileController;

		private NetworkInstanceId ___linkedObjectNetId;

		public GameObject NetworklinkedObject
		{
			get
			{
				return linkedObject;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					SetLinkedObject(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVarGameObject(value, ref linkedObject, 1u, ref ___linkedObjectNetId);
			}
		}

		public string GetContextString(Interactor activator)
		{
			throw new NotImplementedException();
		}

		public Interactability GetInteractability(Interactor activator)
		{
			if (!linkedObject)
			{
				return Interactability.ConditionsNotMet;
			}
			return Interactability.Available;
		}

		public void OnInteractionBegin(Interactor activator)
		{
			throw new NotImplementedException();
		}

		public bool ShouldIgnoreSpherecastForInteractibility(Interactor activator)
		{
			return false;
		}

		public bool ShouldShowOnScanner()
		{
			return false;
		}

		public bool ShouldProximityHighlight()
		{
			return false;
		}

		private void SetLinkedObject(GameObject newLinkedObject)
		{
			if (linkedObject != newLinkedObject)
			{
				NetworklinkedObject = newLinkedObject;
				linkedGatewayProjectileController = (linkedObject ? linkedObject.GetComponent<GatewayProjectileController>() : null);
				if ((bool)linkedGatewayProjectileController)
				{
					linkedGatewayProjectileController.SetLinkedObject(base.gameObject);
				}
			}
		}

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileTargetComponent = GetComponent<ProjectileTargetComponent>();
		}

		public override void OnStartServer()
		{
			base.OnStartServer();
			if ((bool)projectileTargetComponent.target)
			{
				SetLinkedObject(projectileTargetComponent.target.gameObject);
				return;
			}
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.position = base.transform.position;
			fireProjectileInfo.rotation = base.transform.rotation;
			fireProjectileInfo.target = base.gameObject;
			fireProjectileInfo.owner = projectileController.owner;
			fireProjectileInfo.speedOverride = 0f;
			fireProjectileInfo.projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/GatewayProjectile");
			ProjectileManager.instance.FireProjectile(fireProjectileInfo);
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(linkedObject);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(linkedObject);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___linkedObjectNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				SetLinkedObject(reader.ReadGameObject());
			}
		}

		public override void PreStartClient()
		{
			if (!___linkedObjectNetId.IsEmpty())
			{
				NetworklinkedObject = ClientScene.FindLocalObject(___linkedObjectNetId);
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class GummyCloneProjectile : MonoBehaviour, IProjectileImpactBehavior
	{
		[SerializeField]
		private int damageBoostCount = 10;

		[SerializeField]
		private int hpBoostCount = 10;

		[SerializeField]
		private float maxLifetime = 10f;

		private float stopwatch;

		private bool isAlive = true;

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (isAlive)
			{
				SpawnGummyClone();
				isAlive = false;
			}
		}

		protected void FixedUpdate()
		{
			stopwatch += Time.fixedDeltaTime;
			if (NetworkServer.active && (!isAlive || stopwatch > maxLifetime))
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		public void SpawnGummyClone()
		{
			ProjectileController component = GetComponent<ProjectileController>();
			if (!component || !component.owner)
			{
				return;
			}
			CharacterBody component2 = component.owner.GetComponent<CharacterBody>();
			if (!component2)
			{
				return;
			}
			CharacterMaster characterMaster = component2.master;
			if (!characterMaster || characterMaster.IsDeployableLimited(DeployableSlot.GummyClone))
			{
				return;
			}
			MasterCopySpawnCard masterCopySpawnCard = MasterCopySpawnCard.FromMaster(characterMaster, copyItems: false, copyEquipment: false);
			if (!masterCopySpawnCard)
			{
				return;
			}
			masterCopySpawnCard.GiveItem(DLC1Content.Items.GummyCloneIdentifier);
			masterCopySpawnCard.GiveItem(RoR2Content.Items.BoostDamage, damageBoostCount);
			masterCopySpawnCard.GiveItem(RoR2Content.Items.BoostHp, hpBoostCount);
			Transform spawnOnTarget = base.transform;
			DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule
			{
				spawnOnTarget = spawnOnTarget,
				placementMode = DirectorPlacementRule.PlacementMode.Direct
			};
			DirectorCore.GetMonsterSpawnDistance(DirectorCore.MonsterSpawnDistance.Close, out directorPlacementRule.minDistance, out directorPlacementRule.maxDistance);
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(masterCopySpawnCard, directorPlacementRule, new Xoroshiro128Plus(Run.instance.seed + (ulong)Run.instance.fixedTime));
			directorSpawnRequest.teamIndexOverride = characterMaster.teamIndex;
			directorSpawnRequest.ignoreTeamMemberLimit = true;
			directorSpawnRequest.summonerBodyObject = component2.gameObject;
			directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult result)
			{
				CharacterMaster component3 = result.spawnedInstance.GetComponent<CharacterMaster>();
				Deployable deployable = result.spawnedInstance.AddComponent<Deployable>();
				characterMaster.AddDeployable(deployable, DeployableSlot.GummyClone);
				deployable.onUndeploy = deployable.onUndeploy ?? new UnityEvent();
				deployable.onUndeploy.AddListener(component3.TrueKill);
				GameObject bodyObject = component3.GetBodyObject();
				if ((bool)bodyObject)
				{
					EntityStateMachine[] components = bodyObject.GetComponents<EntityStateMachine>();
					foreach (EntityStateMachine entityStateMachine in components)
					{
						if (entityStateMachine.customName == "Body")
						{
							entityStateMachine.SetState(new GummyCloneSpawnState());
							break;
						}
					}
				}
			});
			DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			UnityEngine.Object.Destroy(masterCopySpawnCard);
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class HookProjectileImpact : NetworkBehaviour, IProjectileImpactBehavior
	{
		private enum HookState
		{
			Flying,
			HitDelay,
			Reel,
			ReelFail
		}

		private ProjectileController projectileController;

		public float reelDelayTime;

		public float reelSpeed = 40f;

		public string attachmentString;

		public float victimPullFactor = 1f;

		public float pullMinimumDistance = 10f;

		public GameObject impactSpark;

		public GameObject impactSuccess;

		[SyncVar]
		private HookState hookState;

		[SyncVar]
		private GameObject victim;

		private Transform ownerTransform;

		private ProjectileDamage projectileDamage;

		private Rigidbody rigidbody;

		public float liveTimer;

		private float delayTimer;

		private float flyTimer;

		private NetworkInstanceId ___victimNetId;

		public HookState NetworkhookState
		{
			get
			{
				return hookState;
			}
			[param: In]
			set
			{
				ulong newValueAsUlong = (ulong)value;
				ulong fieldValueAsUlong = (ulong)hookState;
				SetSyncVarEnum(value, newValueAsUlong, ref hookState, fieldValueAsUlong, 1u);
			}
		}

		public GameObject Networkvictim
		{
			get
			{
				return victim;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref victim, 2u, ref ___victimNetId);
			}
		}

		private void Start()
		{
			rigidbody = GetComponent<Rigidbody>();
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			ownerTransform = projectileController.owner.transform;
			if (!ownerTransform)
			{
				return;
			}
			ModelLocator component = ownerTransform.GetComponent<ModelLocator>();
			if (!component)
			{
				return;
			}
			Transform modelTransform = component.modelTransform;
			if ((bool)modelTransform)
			{
				ChildLocator component2 = modelTransform.GetComponent<ChildLocator>();
				if ((bool)component2)
				{
					ownerTransform = component2.FindChild(attachmentString);
				}
			}
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			EffectManager.SimpleImpactEffect(impactSpark, impactInfo.estimatedPointOfImpact, -base.transform.forward, transmit: true);
			if (hookState != 0)
			{
				return;
			}
			HurtBox component = impactInfo.collider.GetComponent<HurtBox>();
			if ((bool)component)
			{
				HealthComponent healthComponent = component.healthComponent;
				if ((bool)healthComponent)
				{
					TeamIndex teamIndex = projectileController.teamFilter.teamIndex;
					if (!FriendlyFireManager.ShouldDirectHitProceed(healthComponent, teamIndex))
					{
						return;
					}
					Networkvictim = healthComponent.gameObject;
					DamageInfo damageInfo = new DamageInfo();
					if ((bool)projectileDamage)
					{
						damageInfo.damage = projectileDamage.damage;
						damageInfo.crit = projectileDamage.crit;
						damageInfo.attacker = (projectileController.owner ? projectileController.owner.gameObject : null);
						damageInfo.inflictor = base.gameObject;
						damageInfo.position = impactInfo.estimatedPointOfImpact;
						damageInfo.force = projectileDamage.force * base.transform.forward;
						damageInfo.procChainMask = projectileController.procChainMask;
						damageInfo.procCoefficient = projectileController.procCoefficient;
						damageInfo.damageColorIndex = projectileDamage.damageColorIndex;
					}
					healthComponent.TakeDamage(damageInfo);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
					NetworkhookState = HookState.HitDelay;
					EffectManager.SimpleImpactEffect(impactSuccess, impactInfo.estimatedPointOfImpact, -base.transform.forward, transmit: true);
					base.gameObject.layer = LayerIndex.noCollision.intVal;
				}
			}
			if (!victim)
			{
				NetworkhookState = HookState.ReelFail;
			}
		}

		private bool Reel()
		{
			UnityEngine.Vector3 vector = ownerTransform.position - victim.transform.position;
			UnityEngine.Vector3 normalized = vector.normalized;
			float num = vector.magnitude;
			Collider component = projectileController.owner.GetComponent<Collider>();
			Collider component2 = victim.GetComponent<Collider>();
			if ((bool)component && (bool)component2)
			{
				num = Util.EstimateSurfaceDistance(component, component2);
			}
			bool flag = num <= pullMinimumDistance;
			CharacterMotor characterMotor = null;
			Rigidbody rigidbody = null;
			float num2 = -1f;
			characterMotor = projectileController.owner.GetComponent<CharacterMotor>();
			if ((bool)characterMotor)
			{
				num2 = characterMotor.mass;
			}
			else
			{
				rigidbody = projectileController.owner.GetComponent<Rigidbody>();
				if ((bool)rigidbody)
				{
					num2 = rigidbody.mass;
				}
			}
			CharacterMotor characterMotor2 = null;
			Rigidbody rigidbody2 = null;
			float num3 = -1f;
			characterMotor2 = victim.GetComponent<CharacterMotor>();
			if ((bool)characterMotor2)
			{
				num3 = characterMotor2.mass;
			}
			else
			{
				rigidbody2 = victim.GetComponent<Rigidbody>();
				if ((bool)rigidbody2)
				{
					num3 = rigidbody2.mass;
				}
			}
			float num4 = 0f;
			float num5 = 0f;
			if (num2 > 0f && num3 > 0f)
			{
				num4 = 1f - num2 / (num2 + num3);
				num5 = 1f - num4;
			}
			else if (num2 > 0f)
			{
				num4 = 1f;
			}
			else if (num3 > 0f)
			{
				num5 = 1f;
			}
			else
			{
				flag = true;
			}
			if (flag)
			{
				num4 = 0f;
				num5 = 0f;
			}
			UnityEngine.Vector3 velocity = normalized * (num5 * victimPullFactor * reelSpeed);
			if ((bool)characterMotor2)
			{
				characterMotor2.velocity = velocity;
			}
			if ((bool)rigidbody2)
			{
				rigidbody2.velocity = velocity;
			}
			return flag;
		}

		public void FixedUpdate()
		{
			if (NetworkServer.active && !projectileController.owner)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			if ((bool)victim)
			{
				rigidbody.MovePosition(victim.transform.position);
			}
			switch (hookState)
			{
			case HookState.Flying:
				if (NetworkServer.active)
				{
					flyTimer += Time.fixedDeltaTime;
					if (flyTimer >= liveTimer)
					{
						NetworkhookState = HookState.ReelFail;
					}
				}
				break;
			case HookState.HitDelay:
				if (!NetworkServer.active)
				{
					break;
				}
				if ((bool)victim)
				{
					delayTimer += Time.fixedDeltaTime;
					if (delayTimer >= reelDelayTime)
					{
						NetworkhookState = HookState.Reel;
					}
				}
				else
				{
					NetworkhookState = HookState.Reel;
				}
				break;
			case HookState.Reel:
			{
				bool flag = true;
				if ((bool)victim)
				{
					flag = Reel();
				}
				if (NetworkServer.active)
				{
					if (!victim)
					{
						NetworkhookState = HookState.ReelFail;
					}
					if (flag)
					{
						UnityEngine.Object.Destroy(base.gameObject);
					}
				}
				break;
			}
			case HookState.ReelFail:
				if (!NetworkServer.active)
				{
					break;
				}
				if ((bool)rigidbody)
				{
					rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
					rigidbody.isKinematic = true;
				}
				if ((bool)ownerTransform)
				{
					rigidbody.MovePosition(UnityEngine.Vector3.MoveTowards(base.transform.position, ownerTransform.position, reelSpeed * Time.fixedDeltaTime));
					if (base.transform.position == ownerTransform.position)
					{
						UnityEngine.Object.Destroy(base.gameObject);
					}
				}
				break;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write((int)hookState);
				writer.Write(victim);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write((int)hookState);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(victim);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				hookState = (HookState)reader.ReadInt32();
				___victimNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				hookState = (HookState)reader.ReadInt32();
			}
			if (((uint)num & 2u) != 0)
			{
				victim = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___victimNetId.IsEmpty())
			{
				Networkvictim = ClientScene.FindLocalObject(___victimNetId);
			}
		}
	}
	public struct ProjectileImpactInfo
	{
		public Collider collider;

		public UnityEngine.Vector3 estimatedPointOfImpact;

		public UnityEngine.Vector3 estimatedImpactNormal;
	}
	public interface IProjectileImpactBehavior
	{
		void OnProjectileImpact(ProjectileImpactInfo impactInfo);
	}
	[DisallowMultipleComponent]
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileImpactExplosion))]
	[RequireComponent(typeof(ProjectileOwnerOrbiter))]
	public class LunarSunProjectileController : MonoBehaviour
	{
		private ProjectileImpactExplosion explosion;

		public void OnEnable()
		{
			explosion = GetComponent<ProjectileImpactExplosion>();
			if (NetworkServer.active)
			{
				ProjectileController component = GetComponent<ProjectileController>();
				if ((bool)component.owner)
				{
					AcquireOwner(component);
				}
				else
				{
					component.onInitialized += AcquireOwner;
				}
			}
		}

		private void AcquireOwner(ProjectileController controller)
		{
			controller.onInitialized -= AcquireOwner;
			CharacterBody component = controller.owner.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				ProjectileOwnerOrbiter component2 = GetComponent<ProjectileOwnerOrbiter>();
				component.GetComponent<LunarSunBehavior>().InitializeOrbiter(component2, this);
			}
		}

		public void Detonate()
		{
			if ((bool)explosion)
			{
				explosion.Detonate();
			}
		}
	}
	public class MegacrabProjectileController : MonoBehaviour
	{
		public enum MegacrabProjectileType
		{
			White,
			Black,
			Count
		}

		[Header("Cached Properties")]
		public ProjectileController projectileController;

		public ProjectileDamage projectileDamage;

		public Rigidbody projectileRigidbody;

		public MegacrabProjectileType megacrabProjectileType;

		[Header("Black Properties")]
		public AnimationCurve blackForceFalloffCurve;

		public float whiteToBlackTransformationRadius;

		public GameObject whiteToBlackTransformedProjectile;

		[Header("White Properties")]
		public AnimationCurve whiteForceFalloffCurve;

		public float minimumWhiteForceMagnitude;

		public float maximumWhiteForceMagnitude;

		public float whiteMinimumForceToFullyRotate;

		public float whiteScaleSmoothtimeMin = 0.1f;

		public float whiteScaleSmoothtimeMax = 0.1f;

		[Range(0f, 1f)]
		public float whitePoisson;

		public static List<MegacrabProjectileController> whiteProjectileList = new List<MegacrabProjectileController>();

		public static List<MegacrabProjectileController> blackProjectileList = new List<MegacrabProjectileController>();

		private float whiteScaleSmoothtime;

		private UnityEngine.Vector3 whiteScaleVelocity;

		private float whiteRotationVelocity;

		private void OnEnable()
		{
			switch (megacrabProjectileType)
			{
			case MegacrabProjectileType.White:
				whiteProjectileList.Add(this);
				break;
			case MegacrabProjectileType.Black:
				blackProjectileList.Add(this);
				break;
			}
		}

		private void OnDisable()
		{
			switch (megacrabProjectileType)
			{
			case MegacrabProjectileType.White:
				whiteProjectileList.Remove(this);
				break;
			case MegacrabProjectileType.Black:
				blackProjectileList.Remove(this);
				break;
			}
		}

		private void Start()
		{
			whiteScaleSmoothtime = UnityEngine.Random.Range(whiteScaleSmoothtimeMin, whiteScaleSmoothtimeMax);
		}

		private void FixedUpdate()
		{
			UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
			UnityEngine.Vector3 position = base.transform.position;
			switch (megacrabProjectileType)
			{
			case MegacrabProjectileType.White:
			{
				for (int j = 0; j < blackProjectileList.Count; j++)
				{
					UnityEngine.Vector3 vector3 = blackProjectileList[j].transform.position - position;
					float magnitude2 = vector3.magnitude;
					UnityEngine.Vector3 vector4 = whiteForceFalloffCurve.Evaluate(magnitude2) * vector3.normalized;
					zero += vector4;
				}
				UnityEngine.Quaternion rotation = base.transform.rotation;
				UnityEngine.Quaternion target = base.transform.rotation;
				UnityEngine.Vector3 localScale = base.transform.localScale;
				UnityEngine.Vector3 target2 = UnityEngine.Vector3.one;
				if (zero.magnitude > minimumWhiteForceMagnitude)
				{
					UnityEngine.Quaternion b = UnityEngine.Quaternion.LookRotation(zero);
					float num = Mathf.Min(maximumWhiteForceMagnitude, zero.magnitude);
					float num2 = 1f / Mathf.Lerp(num, 1f, whitePoisson);
					target2 = new UnityEngine.Vector3(num2, num2, num);
					target = UnityEngine.Quaternion.Slerp(rotation, b, whiteMinimumForceToFullyRotate);
				}
				base.transform.localScale = UnityEngine.Vector3.SmoothDamp(localScale, target2, ref whiteScaleVelocity, whiteScaleSmoothtime);
				base.transform.rotation = Util.SmoothDampQuaternion(rotation, target, ref whiteRotationVelocity, whiteScaleSmoothtime);
				break;
			}
			case MegacrabProjectileType.Black:
			{
				for (int i = 0; i < whiteProjectileList.Count; i++)
				{
					UnityEngine.Vector3 vector = whiteProjectileList[i].transform.position - position;
					float magnitude = vector.magnitude;
					UnityEngine.Vector3 vector2 = blackForceFalloffCurve.Evaluate(magnitude) * vector.normalized;
					zero += vector2;
				}
				projectileRigidbody.AddForce(zero);
				break;
			}
			}
		}

		public void OnDestroy()
		{
			if (!NetworkServer.active || megacrabProjectileType != MegacrabProjectileType.Black)
			{
				return;
			}
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < whiteProjectileList.Count; i++)
			{
				MegacrabProjectileController megacrabProjectileController = whiteProjectileList[i];
				if ((whiteProjectileList[i].transform.position - position).magnitude <= whiteToBlackTransformationRadius)
				{
					ProjectileExplosion component = megacrabProjectileController.GetComponent<ProjectileExplosion>();
					if (component.GetAlive())
					{
						ProjectileManager.instance.FireProjectile(whiteToBlackTransformedProjectile, megacrabProjectileController.transform.position, UnityEngine.Quaternion.identity, projectileController.owner, projectileDamage.damage, 0f, projectileDamage.crit);
						component.SetAlive(newAlive: false);
					}
				}
			}
		}
	}
	public class MineProximityDetonator : MonoBehaviour
	{
		public TeamFilter myTeamFilter;

		public UnityEvent triggerEvents;

		public void OnTriggerEnter(Collider collider)
		{
			if (!NetworkServer.active || !collider)
			{
				return;
			}
			HurtBox component = collider.GetComponent<HurtBox>();
			if (!component)
			{
				return;
			}
			HealthComponent healthComponent = component.healthComponent;
			if ((bool)healthComponent)
			{
				TeamComponent component2 = healthComponent.GetComponent<TeamComponent>();
				if (!component2 || component2.teamIndex != myTeamFilter.teamIndex)
				{
					triggerEvents?.Invoke();
				}
			}
		}
	}
	[RequireComponent(typeof(Rigidbody))]
	[RequireComponent(typeof(ProjectileTargetComponent))]
	public class MissileController : MonoBehaviour
	{
		private new Transform transform;

		private Rigidbody rigidbody;

		private TeamFilter teamFilter;

		private ProjectileTargetComponent targetComponent;

		public float maxVelocity;

		public float rollVelocity;

		public float acceleration;

		public float delayTimer;

		public float giveupTimer = 8f;

		public float deathTimer = 10f;

		private float timer;

		private QuaternionPID torquePID;

		public float turbulence;

		public float maxSeekDistance = 40f;

		private BullseyeSearch search = new BullseyeSearch();

		private void Awake()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
				return;
			}
			transform = base.transform;
			rigidbody = GetComponent<Rigidbody>();
			torquePID = GetComponent<QuaternionPID>();
			teamFilter = GetComponent<TeamFilter>();
			targetComponent = GetComponent<ProjectileTargetComponent>();
		}

		private void FixedUpdate()
		{
			timer += Time.deltaTime;
			if (timer < giveupTimer)
			{
				rigidbody.velocity = transform.forward * maxVelocity;
				if ((bool)targetComponent.target && timer >= delayTimer)
				{
					rigidbody.velocity = transform.forward * (maxVelocity + timer * acceleration);
					UnityEngine.Vector3 vector = targetComponent.target.position + UnityEngine.Random.insideUnitSphere * turbulence - transform.position;
					if (vector != UnityEngine.Vector3.zero)
					{
						UnityEngine.Quaternion rotation = transform.rotation;
						UnityEngine.Quaternion targetQuat = Util.QuaternionSafeLookRotation(vector);
						torquePID.inputQuat = rotation;
						torquePID.targetQuat = targetQuat;
						rigidbody.angularVelocity = torquePID.UpdatePID();
					}
				}
			}
			if (!targetComponent.target)
			{
				targetComponent.target = FindTarget();
			}
			else
			{
				HealthComponent component = targetComponent.target.GetComponent<HealthComponent>();
				if ((bool)component && !component.alive)
				{
					targetComponent.target = FindTarget();
				}
			}
			if (timer > deathTimer)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private Transform FindTarget()
		{
			search.searchOrigin = transform.position;
			search.searchDirection = transform.forward;
			search.teamMaskFilter.RemoveTeam(teamFilter.teamIndex);
			search.RefreshCandidates();
			return search.GetResults().FirstOrDefault()?.transform;
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileCallOnOwnerNearby : MonoBehaviour
	{
		[Flags]
		public enum Filter
		{
			None = 0,
			Server = 1,
			Client = 2
		}

		private enum State
		{
			Outside,
			Inside
		}

		public Filter filter;

		public float radius;

		public UnityEvent onOwnerEnter;

		public UnityEvent onOwnerExit;

		private State state;

		private bool ownerInRadius;

		private ProjectileController projectileController;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			Filter filter = Filter.None;
			if (NetworkServer.active)
			{
				filter |= Filter.Server;
			}
			if (NetworkClient.active)
			{
				filter |= Filter.Client;
			}
			if ((this.filter & filter) == 0)
			{
				base.enabled = false;
			}
		}

		private void OnDisable()
		{
			SetState(State.Outside);
		}

		private void SetState(State newState)
		{
			if (state != newState)
			{
				state = newState;
				if (state == State.Inside)
				{
					onOwnerEnter?.Invoke();
				}
				else
				{
					onOwnerExit?.Invoke();
				}
			}
		}

		private void FixedUpdate()
		{
			State state = State.Outside;
			if ((bool)projectileController.owner)
			{
				float num = radius * radius;
				if ((base.transform.position - projectileController.owner.transform.position).sqrMagnitude < num)
				{
					state = State.Inside;
				}
			}
			SetState(state);
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(CharacterController))]
	public class ProjectileCharacterController : MonoBehaviour
	{
		private UnityEngine.Vector3 downVector;

		public float velocity;

		public float lifetime = 5f;

		private float timer;

		private ProjectileController projectileController;

		private CharacterController characterController;

		private void Awake()
		{
			downVector = UnityEngine.Vector3.down * 3f;
			projectileController = GetComponent<ProjectileController>();
			characterController = GetComponent<CharacterController>();
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active || projectileController.isPrediction)
			{
				characterController.Move((base.transform.forward + downVector) * (velocity * Time.fixedDeltaTime));
			}
			if (NetworkServer.active)
			{
				timer += Time.fixedDeltaTime;
				if (timer > lifetime)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	public class ProjectileController : NetworkBehaviour
	{
		[HideInInspector]
		[Tooltip("This is assigned to the prefab automatically by ProjectileCatalog at runtime. Do not set this value manually.")]
		public int catalogIndex = -1;

		[Tooltip("The prefab to instantiate as the visual representation of this projectile. The prefab must have a ProjectileGhostController attached.")]
		public GameObject ghostPrefab;

		[Tooltip("The transform for the ghost to follow. If null, the transform of this object will be used instead.")]
		public Transform ghostTransformAnchor;

		[Tooltip("The sound to play on Start(). Use this field to ensure the sound only plays once when prediction creates two instances.")]
		public string startSound;

		[Tooltip("Prevents this projectile from being deleted by gameplay events, like Captain's defense matrix.")]
		public bool cannotBeDeleted;

		[Tooltip("Check this if you want collision events to only run on the local authority (which may be a client instead of the host). 99% of projectiles should have this set to false.")]
		public bool authorityHandlesCollisionEvents;

		[SerializeField]
		[Tooltip("The sound loop to play while this object exists. Use this field to ensure the sound only plays once when prediction creates two instances.")]
		private LoopSoundDef flightSoundLoop;

		protected Rigidbody rigidbody;

		public bool canImpactOnTrigger;

		public bool allowPrediction = true;

		[NonSerialized]
		[SyncVar]
		public ushort predictionId;

		[SyncVar]
		[HideInInspector]
		public GameObject owner;

		[HideInInspector]
		public bool localCollisionHappened;

		public float procCoefficient = 1f;

		private Collider[] myColliders;

		protected EffectManagerHelper _efhGhost;

		public bool CheckChildrenForCollidersAndIncludeDisabled;

		private NetworkInstanceId ___ownerNetId;

		public TeamFilter teamFilter { get; private set; }

		public ProjectileGhostController ghost { get; set; }

		public bool isPrediction { get; set; }

		public bool shouldPlaySounds { get; set; }

		public ProcChainMask procChainMask { get; set; }

		public NetworkConnection clientAuthorityOwner { get; private set; }

		public ushort NetworkpredictionId
		{
			get
			{
				return predictionId;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref predictionId, 1u);
			}
		}

		public GameObject Networkowner
		{
			get
			{
				return owner;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref owner, 2u, ref ___ownerNetId);
			}
		}

		public event Action<ProjectileController> onInitialized;

		private void Awake()
		{
			rigidbody = GetComponent<Rigidbody>();
			teamFilter = GetComponent<TeamFilter>();
			if (CheckChildrenForCollidersAndIncludeDisabled)
			{
				myColliders = GetComponentsInChildren<Collider>(includeInactive: true);
			}
			else
			{
				myColliders = GetComponents<Collider>();
			}
			for (int i = 0; i < myColliders.Length; i++)
			{
				myColliders[i].enabled = false;
			}
		}

		private void Start()
		{
			for (int i = 0; i < myColliders.Length; i++)
			{
				myColliders[i].enabled = true;
			}
			IgnoreCollisionsWithOwner(shouldIgnore: true);
			if (!isPrediction && !NetworkServer.active)
			{
				ProjectileManager.instance.OnClientProjectileReceived(this);
			}
			GameObject gameObject = ProjectileGhostReplacementManager.FindProjectileGhostPrefab(this);
			shouldPlaySounds = false;
			if (isPrediction || !allowPrediction || !base.hasAuthority)
			{
				shouldPlaySounds = true;
				if ((bool)gameObject)
				{
					Transform transform = base.transform;
					if ((bool)ghostTransformAnchor)
					{
						transform = ghostTransformAnchor;
					}
					if (!EffectManager.ShouldUsePooledEffect(gameObject))
					{
						ghost = UnityEngine.Object.Instantiate(gameObject, transform.position, transform.rotation).GetComponent<ProjectileGhostController>();
					}
					else
					{
						_efhGhost = EffectManager.GetAndActivatePooledEffect(gameObject, transform.position, transform.rotation);
						ghost = _efhGhost.gameObject.GetComponent<ProjectileGhostController>();
					}
					if (isPrediction)
					{
						ghost.predictionTransform = transform;
					}
					else
					{
						ghost.authorityTransform = transform;
					}
					ghost.enabled = true;
				}
			}
			clientAuthorityOwner = GetComponent<NetworkIdentity>().clientAuthorityOwner;
			if (shouldPlaySounds)
			{
				PointSoundManager.EmitSoundLocal((AkEventIdArg)startSound, base.transform.position);
				if ((bool)flightSoundLoop)
				{
					Util.PlaySound(flightSoundLoop.startSoundName, base.gameObject);
				}
			}
		}

		private void OnDestroy()
		{
			if (NetworkServer.active && ProjectileManager.instance != null)
			{
				ProjectileManager.instance.OnServerProjectileDestroyed(this);
			}
			if (shouldPlaySounds && (bool)flightSoundLoop)
			{
				Util.PlaySound(flightSoundLoop.stopSoundName, base.gameObject);
			}
			DisconnectFromGhost();
		}

		public void DisconnectFromGhost()
		{
			if (!ghost || (isPrediction && (bool)ghost.authorityTransform))
			{
				return;
			}
			RunGhostParentProjectileDestroyedMethod();
			if (!EffectManager.UsePools)
			{
				UnityEngine.Object.Destroy(ghost.gameObject);
			}
			else
			{
				if (!isPrediction && _efhGhost == null)
				{
					_efhGhost = ghost.emh;
				}
				if (_efhGhost != null && _efhGhost.OwningPool != null)
				{
					if (!_efhGhost.HasDestroyOnTimer && !_efhGhost.HasAnimateShaderAlphas)
					{
						_efhGhost.OwningPool.ReturnObject(_efhGhost);
					}
				}
				else
				{
					if (_efhGhost != null)
					{
						UnityEngine.Debug.LogFormat("efhGhost has no owning pool {0} {1}", _efhGhost.gameObject.name, _efhGhost.gameObject.GetInstanceID());
					}
					UnityEngine.Object.Destroy(ghost.gameObject);
				}
			}
			_efhGhost = null;
			ghost = null;
		}

		public void RunGhostParentProjectileDestroyedMethod()
		{
			if ((bool)ghost)
			{
				ghost.OnParentProjectileDestroyed();
			}
		}

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			IgnoreCollisionsWithOwner(shouldIgnore: true);
		}

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		public void IgnoreCollisionsWithOwner(bool shouldIgnore)
		{
			if (!owner)
			{
				return;
			}
			ModelLocator component = owner.GetComponent<ModelLocator>();
			if (!component)
			{
				return;
			}
			Transform modelTransform = component.modelTransform;
			if (!modelTransform)
			{
				return;
			}
			HurtBoxGroup component2 = modelTransform.GetComponent<HurtBoxGroup>();
			if (!component2)
			{
				return;
			}
			HurtBox[] hurtBoxes = component2.hurtBoxes;
			for (int i = 0; i < hurtBoxes.Length; i++)
			{
				List<Collider> gameObjectComponents = GetComponentsCache<Collider>.GetGameObjectComponents(hurtBoxes[i].gameObject);
				int j = 0;
				for (int count = gameObjectComponents.Count; j < count; j++)
				{
					Collider collider = gameObjectComponents[j];
					for (int k = 0; k < myColliders.Length; k++)
					{
						Collider collider2 = myColliders[k];
						Physics.IgnoreCollision(collider, collider2, shouldIgnore);
					}
				}
				GetComponentsCache<Collider>.ReturnBuffer(gameObjectComponents);
			}
		}

		private static UnityEngine.Vector3 EstimateContactPoint(ContactPoint[] contacts, Collider collider)
		{
			if (contacts.Length == 0)
			{
				return collider.transform.position;
			}
			return contacts[0].point;
		}

		private static UnityEngine.Vector3 EstimateContactNormal(ContactPoint[] contacts)
		{
			if (contacts.Length == 0)
			{
				return UnityEngine.Vector3.zero;
			}
			return contacts[0].normal;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public bool CanProcessCollisionEvents()
		{
			if ((authorityHandlesCollisionEvents || !NetworkServer.active) && (!authorityHandlesCollisionEvents || !Util.HasEffectiveAuthority(base.gameObject)))
			{
				return isPrediction;
			}
			return true;
		}

		public void OnCollisionEnter(Collision collision)
		{
			localCollisionHappened = true;
			if (CanProcessCollisionEvents())
			{
				ContactPoint[] contacts = collision.contacts;
				ProjectileImpactInfo projectileImpactInfo = default(ProjectileImpactInfo);
				projectileImpactInfo.collider = collision.collider;
				projectileImpactInfo.estimatedPointOfImpact = EstimateContactPoint(contacts, collision.collider);
				projectileImpactInfo.estimatedImpactNormal = EstimateContactNormal(contacts);
				ProjectileImpactInfo impactInfo = projectileImpactInfo;
				IProjectileImpactBehavior[] components = GetComponents<IProjectileImpactBehavior>();
				for (int i = 0; i < components.Length; i++)
				{
					components[i].OnProjectileImpact(impactInfo);
				}
			}
		}

		public void DispatchOnInitialized()
		{
			this.onInitialized?.Invoke(this);
		}

		private void OnValidate()
		{
			if (!Application.IsPlaying(this))
			{
				bool flag = GetComponent<NetworkIdentity>().localPlayerAuthority;
				if (allowPrediction && !flag)
				{
					UnityEngine.Debug.LogWarningFormat(base.gameObject, "ProjectileController: {0} allows predictions, so it should have localPlayerAuthority=true", base.gameObject);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.WritePackedUInt32(predictionId);
				writer.Write(owner);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32(predictionId);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(owner);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				predictionId = (ushort)reader.ReadPackedUInt32();
				___ownerNetId = reader.ReadNetworkId();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				predictionId = (ushort)reader.ReadPackedUInt32();
			}
			if (((uint)num & 2u) != 0)
			{
				owner = reader.ReadGameObject();
			}
		}

		public override void PreStartClient()
		{
			if (!___ownerNetId.IsEmpty())
			{
				Networkowner = ClientScene.FindLocalObject(___ownerNetId);
			}
		}
	}
	[RequireComponent(typeof(TeamFilter))]
	public class ProjectileControllerTrigger : ProjectileController
	{
		public void OnTriggerEnter(Collider collider)
		{
			if (NetworkServer.active && canImpactOnTrigger)
			{
				UnityEngine.Vector3 vector = UnityEngine.Vector3.zero;
				if ((bool)rigidbody)
				{
					vector = rigidbody.velocity;
				}
				ProjectileImpactInfo projectileImpactInfo = default(ProjectileImpactInfo);
				projectileImpactInfo.collider = collider;
				projectileImpactInfo.estimatedPointOfImpact = base.transform.position;
				projectileImpactInfo.estimatedImpactNormal = -vector.normalized;
				ProjectileImpactInfo impactInfo = projectileImpactInfo;
				IProjectileImpactBehavior[] components = GetComponents<IProjectileImpactBehavior>();
				for (int i = 0; i < components.Length; i++)
				{
					components[i].OnProjectileImpact(impactInfo);
				}
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool flag = base.OnSerialize(writer, forceAll);
			bool flag2 = default(bool);
			return flag2 || flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			base.OnDeserialize(reader, initialState);
		}

		public override void PreStartClient()
		{
			base.PreStartClient();
		}
	}
	public class ProjectileDamage : MonoBehaviour
	{
		[HideInInspector]
		public float damage;

		[HideInInspector]
		public bool crit;

		[HideInInspector]
		public float force;

		[HideInInspector]
		public DamageColorIndex damageColorIndex;

		public DamageTypeCombo damageType;

		[Tooltip("If true, we cap the maximum stacks for this attacker")]
		public bool useDotMaxStacksFromAttacker;

		[Tooltip("The number of maximum stacks (if we're capping)")]
		public uint dotMaxStacksFromAttacker = uint.MaxValue;

		public void SetDamageTypeViaInt(int newDamageType)
		{
			damageType = new DamageTypeCombo
			{
				damageType = (DamageType)newDamageType
			};
		}
	}
	[RequireComponent(typeof(CharacterController))]
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileDamage))]
	public class ProjectileDamageTrail : MonoBehaviour
	{
		public GameObject trailPrefab;

		public float damageToTrailDpsFactor = 1f;

		public float trailLifetimeAfterExpiration = 1f;

		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private GameObject currentTrailObject;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
		}

		private void FixedUpdate()
		{
			if (!currentTrailObject)
			{
				currentTrailObject = UnityEngine.Object.Instantiate(trailPrefab, base.transform.position, base.transform.rotation);
				DamageTrail component = currentTrailObject.GetComponent<DamageTrail>();
				component.damagePerSecond = projectileDamage.damage * damageToTrailDpsFactor;
				component.owner = projectileController.owner;
			}
			else
			{
				currentTrailObject.transform.position = base.transform.position;
			}
		}

		private void OnDestroy()
		{
			DiscontinueTrail();
		}

		private void DiscontinueTrail()
		{
			if ((bool)currentTrailObject)
			{
				currentTrailObject.AddComponent<DestroyOnTimer>().duration = trailLifetimeAfterExpiration;
				currentTrailObject.GetComponent<DamageTrail>().active = false;
				currentTrailObject = null;
			}
		}
	}
	[RequireComponent(typeof(Deployable))]
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileDeployToOwner : MonoBehaviour
	{
		public DeployableSlot deployableSlot;

		private void Start()
		{
			if (NetworkServer.active)
			{
				DeployToOwner();
			}
		}

		private void DeployToOwner()
		{
			GameObject owner = GetComponent<ProjectileController>().owner;
			if (!owner)
			{
				return;
			}
			CharacterBody component = owner.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				CharacterMaster master = component.master;
				if ((bool)master)
				{
					master.AddDeployable(GetComponent<Deployable>(), deployableSlot);
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileTargetComponent))]
	[RequireComponent(typeof(TeamFilter))]
	public class ProjectileDirectionalTargetFinder : MonoBehaviour
	{
		[Tooltip("How far ahead the projectile should look to find a target.")]
		public float lookRange;

		[Range(0f, 180f)]
		[Tooltip("How wide the cone of vision for this projectile is in degrees. Limit is 180.")]
		public float lookCone;

		[Tooltip("How long before searching for a target.")]
		public float targetSearchInterval = 0.5f;

		[Tooltip("Will not search for new targets once it has one.")]
		public bool onlySearchIfNoTarget;

		[Tooltip("Allows the target to be lost if it's outside the acceptable range.")]
		public bool allowTargetLoss;

		[Tooltip("If set, targets can only be found when there is a free line of sight.")]
		public bool testLoS;

		[Tooltip("Whether or not airborne characters should be ignored.")]
		public bool ignoreAir;

		[Tooltip("The difference in altitude at which a result will be ignored.")]
		[FormerlySerializedAs("altitudeTolerance")]
		public float flierAltitudeTolerance = float.PositiveInfinity;

		public UnityEvent onNewTargetFound;

		[FormerlySerializedAs("ontargetLost")]
		public UnityEvent onTargetLost;

		private new Transform transform;

		private TeamFilter teamFilter;

		private ProjectileTargetComponent targetComponent;

		private float searchTimer;

		private bool hasTarget;

		private bool hadTargetLastUpdate;

		private BullseyeSearch bullseyeSearch;

		private HurtBox lastFoundHurtBox;

		private Transform lastFoundTransform;

		private void Start()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
				return;
			}
			bullseyeSearch = new BullseyeSearch();
			teamFilter = GetComponent<TeamFilter>();
			targetComponent = GetComponent<ProjectileTargetComponent>();
			transform = base.transform;
			searchTimer = 0f;
		}

		private void FixedUpdate()
		{
			searchTimer -= Time.fixedDeltaTime;
			if (!(searchTimer <= 0f))
			{
				return;
			}
			searchTimer += targetSearchInterval;
			if (allowTargetLoss && (object)targetComponent.target != null && (object)lastFoundTransform == targetComponent.target && !PassesFilters(lastFoundHurtBox))
			{
				SetTarget(null);
			}
			if (!onlySearchIfNoTarget || targetComponent.target == null)
			{
				SearchForTarget();
			}
			hasTarget = targetComponent.target != null;
			if (hadTargetLastUpdate != hasTarget)
			{
				if (hasTarget)
				{
					onNewTargetFound?.Invoke();
				}
				else
				{
					onTargetLost?.Invoke();
				}
			}
			hadTargetLastUpdate = hasTarget;
		}

		private bool PassesFilters(HurtBox result)
		{
			CharacterBody body = result.healthComponent.body;
			if (!body || (ignoreAir && body.isFlying))
			{
				return false;
			}
			if (body.isFlying && !float.IsInfinity(flierAltitudeTolerance) && flierAltitudeTolerance < Mathf.Abs(result.transform.position.y - transform.position.y))
			{
				return false;
			}
			return true;
		}

		private void SearchForTarget()
		{
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			bullseyeSearch.teamMaskFilter.RemoveTeam(teamFilter.teamIndex);
			bullseyeSearch.filterByLoS = testLoS;
			bullseyeSearch.searchOrigin = transform.position;
			bullseyeSearch.searchDirection = transform.forward;
			bullseyeSearch.maxDistanceFilter = lookRange;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.DistanceAndAngle;
			bullseyeSearch.maxAngleFilter = lookCone;
			bullseyeSearch.RefreshCandidates();
			IEnumerable<HurtBox> source = bullseyeSearch.GetResults().Where(PassesFilters);
			SetTarget(source.FirstOrDefault());
		}

		private void SetTarget(HurtBox hurtBox)
		{
			lastFoundHurtBox = hurtBox;
			lastFoundTransform = hurtBox?.transform;
			targetComponent.target = lastFoundTransform;
		}

		private void OnDrawGizmosSelected()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			Transform transform = base.transform;
			UnityEngine.Vector3 position = transform.position;
			Gizmos.DrawWireSphere(position, lookRange);
			Gizmos.DrawRay(position, transform.forward * lookRange);
			Gizmos.DrawFrustum(position, lookCone * 2f, lookRange, 0f, 1f);
			if (!float.IsInfinity(flierAltitudeTolerance))
			{
				Gizmos.DrawWireCube(position, new UnityEngine.Vector3(lookRange * 2f, flierAltitudeTolerance * 2f, lookRange * 2f));
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(HitBoxGroup))]
	public class ProjectileDotZone : MonoBehaviour, IProjectileImpactBehavior
	{
		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		public float damageCoefficient;

		public AttackerFiltering attackerFiltering = AttackerFiltering.NeverHitSelf;

		public GameObject impactEffect;

		public UnityEngine.Vector3 forceVector;

		public float overlapProcCoefficient = 1f;

		[Tooltip("The frequency (1/time) at which the overlap attack is tested. Higher values are more accurate but more expensive.")]
		public float fireFrequency = 1f;

		[Tooltip("The frequency  (1/time) at which the overlap attack is reset. Higher values means more frequent ticks of damage.")]
		public float resetFrequency = 20f;

		public float lifetime = 30f;

		[Tooltip("The event that runs at the start.")]
		public UnityEvent onBegin;

		[Tooltip("The event that runs at the start.")]
		public UnityEvent onEnd;

		private OverlapAttack attack;

		private float fireStopwatch;

		private float resetStopwatch;

		private float totalStopwatch;

		public string soundLoopString = "";

		public string soundLoopStopString = "";

		private void Start()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			ResetOverlap();
			onBegin.Invoke();
			if (!string.IsNullOrEmpty(soundLoopString))
			{
				Util.PlaySound(soundLoopString, base.gameObject);
			}
		}

		private void ResetOverlap()
		{
			attack = new OverlapAttack();
			attack.procChainMask = projectileController.procChainMask;
			attack.procCoefficient = projectileController.procCoefficient * overlapProcCoefficient;
			attack.attacker = projectileController.owner;
			attack.inflictor = base.gameObject;
			attack.teamIndex = projectileController.teamFilter.teamIndex;
			attack.attackerFiltering = attackerFiltering;
			attack.damage = damageCoefficient * projectileDamage.damage;
			attack.forceVector = forceVector + projectileDamage.force * base.transform.forward;
			attack.hitEffectPrefab = impactEffect;
			attack.isCrit = projectileDamage.crit;
			attack.damageColorIndex = projectileDamage.damageColorIndex;
			attack.damageType = projectileDamage.damageType;
			attack.hitBoxGroup = GetComponent<HitBoxGroup>();
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
		}

		public void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			totalStopwatch += Time.fixedDeltaTime;
			resetStopwatch += Time.fixedDeltaTime;
			fireStopwatch += Time.fixedDeltaTime;
			if (resetStopwatch >= 1f / resetFrequency)
			{
				ResetOverlap();
				resetStopwatch -= 1f / resetFrequency;
			}
			if (fireStopwatch >= 1f / fireFrequency)
			{
				attack.Fire();
				fireStopwatch -= 1f / fireFrequency;
			}
			if (lifetime > 0f && totalStopwatch >= lifetime)
			{
				onEnd.Invoke();
				if (!string.IsNullOrEmpty(soundLoopStopString))
				{
					Util.PlaySound(soundLoopStopString, base.gameObject);
				}
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileExplosion : MonoBehaviour
	{
		protected ProjectileController projectileController;

		protected ProjectileDamage projectileDamage;

		protected bool alive = true;

		[Header("Main Properties")]
		public BlastAttack.FalloffModel falloffModel = BlastAttack.FalloffModel.Linear;

		public float blastRadius;

		[Tooltip("The percentage of the damage, proc coefficient, and force of the initial projectile. Ranges from 0-1")]
		public float blastDamageCoefficient;

		public float blastProcCoefficient = 1f;

		public AttackerFiltering blastAttackerFiltering;

		public UnityEngine.Vector3 bonusBlastForce;

		public bool canRejectForce = true;

		public HealthComponent projectileHealthComponent;

		public GameObject explosionEffect;

		[Obsolete("This sound will not play over the network. Provide the sound via the prefab referenced by explosionEffect instead.", false)]
		[ShowFieldObsolete]
		[Tooltip("This sound will not play over the network. Provide the sound via the prefab referenced by explosionEffect instead.")]
		public string explosionSoundString;

		[Header("Child Properties")]
		[Tooltip("Does this projectile release children on death?")]
		public bool fireChildren;

		public GameObject childrenProjectilePrefab;

		public int childrenCount;

		[Tooltip("What percentage of our damage does the children get?")]
		public float childrenDamageCoefficient;

		[ShowFieldObsolete]
		[Tooltip("How to randomize the orientation of children")]
		public UnityEngine.Vector3 minAngleOffset;

		[ShowFieldObsolete]
		public UnityEngine.Vector3 maxAngleOffset;

		public float minRollDegrees;

		public float rangeRollDegrees;

		public float minPitchDegrees;

		public float rangePitchDegrees;

		[Tooltip("useLocalSpaceForChildren is unused by ProjectileImpactExplosion")]
		public bool useLocalSpaceForChildren;

		[Tooltip("If true, applies a DoT given the following properties")]
		[Header("DoT Properties")]
		public bool applyDot;

		public DotController.DotIndex dotIndex = DotController.DotIndex.None;

		[Tooltip("Duration in seconds of the DoT.  Unused if calculateTotalDamage is true.")]
		public float dotDuration;

		[Tooltip("Multiplier on the per-tick damage")]
		public float dotDamageMultiplier = 1f;

		[Tooltip("If true, we cap the numer of DoT stacks for this attacker.")]
		public bool applyMaxStacksFromAttacker;

		[Tooltip("The maximum number of stacks that we can apply for this attacker")]
		public uint maxStacksFromAttacker = uint.MaxValue;

		[Tooltip("If true, we disregard the duration and instead specify the total damage.")]
		public bool calculateTotalDamage;

		[Tooltip("totalDamage = totalDamageMultiplier * attacker's damage")]
		public float totalDamageMultiplier;

		protected virtual void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
		}

		public void Detonate()
		{
			if (NetworkServer.active)
			{
				DetonateServer();
			}
			UnityEngine.Object.Destroy(base.gameObject);
		}

		protected void DetonateServer()
		{
			if ((bool)explosionEffect)
			{
				EffectManager.SpawnEffect(explosionEffect, new EffectData
				{
					origin = base.transform.position,
					scale = blastRadius
				}, transmit: true);
			}
			if ((bool)projectileDamage)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.position = base.transform.position;
				blastAttack.baseDamage = projectileDamage.damage * blastDamageCoefficient;
				blastAttack.baseForce = projectileDamage.force * blastDamageCoefficient;
				blastAttack.radius = blastRadius;
				blastAttack.attacker = (projectileController.owner ? projectileController.owner.gameObject : null);
				blastAttack.inflictor = base.gameObject;
				blastAttack.teamIndex = projectileController.teamFilter.teamIndex;
				blastAttack.crit = projectileDamage.crit;
				blastAttack.procChainMask = projectileController.procChainMask;
				blastAttack.procCoefficient = projectileController.procCoefficient * blastProcCoefficient;
				blastAttack.bonusForce = bonusBlastForce;
				blastAttack.falloffModel = falloffModel;
				blastAttack.damageColorIndex = projectileDamage.damageColorIndex;
				blastAttack.damageType = projectileDamage.damageType;
				blastAttack.attackerFiltering = blastAttackerFiltering;
				blastAttack.canRejectForce = canRejectForce;
				BlastAttack.Result result = blastAttack.Fire();
				OnBlastAttackResult(blastAttack, result);
			}
			if (explosionSoundString.Length > 0)
			{
				Util.PlaySound(explosionSoundString, base.gameObject);
			}
			if (fireChildren)
			{
				for (int i = 0; i < childrenCount; i++)
				{
					FireChild();
				}
			}
		}

		protected UnityEngine.Quaternion GetRandomChildRollPitch()
		{
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.AngleAxis(minRollDegrees + UnityEngine.Random.Range(0f, rangeRollDegrees), UnityEngine.Vector3.forward);
			UnityEngine.Quaternion quaternion2 = UnityEngine.Quaternion.AngleAxis(minPitchDegrees + UnityEngine.Random.Range(0f, rangePitchDegrees), UnityEngine.Vector3.left);
			return quaternion * quaternion2;
		}

		protected virtual UnityEngine.Quaternion GetRandomDirectionForChild()
		{
			UnityEngine.Quaternion randomChildRollPitch = GetRandomChildRollPitch();
			if (useLocalSpaceForChildren)
			{
				return base.transform.rotation * randomChildRollPitch;
			}
			return randomChildRollPitch;
		}

		protected void FireChild()
		{
			UnityEngine.Quaternion randomDirectionForChild = GetRandomDirectionForChild();
			GameObject obj = UnityEngine.Object.Instantiate(childrenProjectilePrefab, base.transform.position, randomDirectionForChild);
			ProjectileController component = obj.GetComponent<ProjectileController>();
			if ((bool)component)
			{
				component.procChainMask = projectileController.procChainMask;
				component.procCoefficient = projectileController.procCoefficient;
				component.Networkowner = projectileController.owner;
			}
			obj.GetComponent<TeamFilter>().teamIndex = GetComponent<TeamFilter>().teamIndex;
			ProjectileDamage component2 = obj.GetComponent<ProjectileDamage>();
			if ((bool)component2)
			{
				component2.damage = projectileDamage.damage * childrenDamageCoefficient;
				component2.crit = projectileDamage.crit;
				component2.force = projectileDamage.force;
				component2.damageColorIndex = projectileDamage.damageColorIndex;
			}
			NetworkServer.Spawn(obj);
		}

		public void SetExplosionRadius(float newRadius)
		{
			blastRadius = newRadius;
		}

		public void SetAlive(bool newAlive)
		{
			alive = newAlive;
		}

		public bool GetAlive()
		{
			if (!NetworkServer.active)
			{
				return false;
			}
			return alive;
		}

		protected virtual void OnValidate()
		{
			if (!Application.IsPlaying(this) && !string.IsNullOrEmpty(explosionSoundString))
			{
				UnityEngine.Debug.LogWarningFormat(base.gameObject, "{0} ProjectileImpactExplosion component supplies a value in the explosionSoundString field. This will not play correctly over the network. Please move the sound to the explosion effect.", Util.GetGameObjectHierarchyName(base.gameObject));
			}
		}

		protected virtual void OnBlastAttackResult(BlastAttack blastAttack, BlastAttack.Result result)
		{
			if (!applyDot)
			{
				return;
			}
			CharacterBody characterBody = blastAttack.attacker?.GetComponent<CharacterBody>();
			BlastAttack.HitPoint[] hitPoints = result.hitPoints;
			for (int i = 0; i < hitPoints.Length; i++)
			{
				BlastAttack.HitPoint hitPoint = hitPoints[i];
				if ((bool)hitPoint.hurtBox && (bool)hitPoint.hurtBox.healthComponent)
				{
					InflictDotInfo inflictDotInfo = default(InflictDotInfo);
					inflictDotInfo.victimObject = hitPoint.hurtBox.healthComponent.gameObject;
					inflictDotInfo.attackerObject = blastAttack.attacker;
					inflictDotInfo.dotIndex = dotIndex;
					inflictDotInfo.damageMultiplier = dotDamageMultiplier;
					InflictDotInfo dotInfo = inflictDotInfo;
					if (calculateTotalDamage && (bool)characterBody)
					{
						dotInfo.totalDamage = characterBody.damage * totalDamageMultiplier;
					}
					else
					{
						dotInfo.duration = dotDuration;
					}
					if (applyMaxStacksFromAttacker)
					{
						dotInfo.maxStacksFromAttacker = maxStacksFromAttacker;
					}
					if ((bool)characterBody && (bool)characterBody.inventory)
					{
						StrengthenBurnUtils.CheckDotForUpgrade(characterBody.inventory, ref dotInfo);
					}
					DotController.InflictDot(ref dotInfo);
				}
			}
		}
	}
	public class ProjectileFireChildren : MonoBehaviour
	{
		public float duration = 5f;

		public int count = 5;

		public GameObject childProjectilePrefab;

		private float timer;

		private float nextSpawnTimer;

		public float childDamageCoefficient = 1f;

		public float childProcCoefficient = 1f;

		private ProjectileDamage projectileDamage;

		private ProjectileController projectileController;

		public bool ignoreParentForChainController;

		private void Start()
		{
			projectileDamage = GetComponent<ProjectileDamage>();
			projectileController = GetComponent<ProjectileController>();
		}

		private void Update()
		{
			timer += Time.deltaTime;
			nextSpawnTimer += Time.deltaTime;
			if (timer >= duration)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			if (nextSpawnTimer >= duration / (float)count)
			{
				nextSpawnTimer -= duration / (float)count;
				GameObject obj = UnityEngine.Object.Instantiate(childProjectilePrefab, base.transform.position, Util.QuaternionSafeLookRotation(base.transform.forward));
				ProjectileController component = obj.GetComponent<ProjectileController>();
				if ((bool)component)
				{
					component.procChainMask = projectileController.procChainMask;
					component.procCoefficient = projectileController.procCoefficient * childProcCoefficient;
					component.Networkowner = projectileController.owner;
				}
				obj.GetComponent<TeamFilter>().teamIndex = GetComponent<TeamFilter>().teamIndex;
				ProjectileDamage component2 = obj.GetComponent<ProjectileDamage>();
				if ((bool)component2)
				{
					component2.damage = projectileDamage.damage * childDamageCoefficient;
					component2.crit = projectileDamage.crit;
					component2.force = projectileDamage.force;
					component2.damageColorIndex = projectileDamage.damageColorIndex;
				}
				NetworkServer.Spawn(obj);
			}
		}
	}
	public class ProjectileFireEffects : MonoBehaviour
	{
		public float duration = 5f;

		public int count = 5;

		public GameObject effectPrefab;

		public UnityEngine.Vector3 randomOffset;

		private float timer;

		private float nextSpawnTimer;

		private void Update()
		{
			timer += Time.deltaTime;
			nextSpawnTimer += Time.deltaTime;
			if (timer >= duration)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			if (nextSpawnTimer >= duration / (float)count)
			{
				nextSpawnTimer -= duration / (float)count;
				if ((bool)effectPrefab)
				{
					UnityEngine.Vector3 vector = new UnityEngine.Vector3(UnityEngine.Random.Range(0f - randomOffset.x, randomOffset.x), UnityEngine.Random.Range(0f - randomOffset.y, randomOffset.y), UnityEngine.Random.Range(0f - randomOffset.z, randomOffset.z));
					EffectManager.SimpleImpactEffect(effectPrefab, base.transform.position + vector, UnityEngine.Vector3.forward, transmit: true);
				}
			}
		}
	}
	[Obsolete("This component is deprecated and will likely be removed from future releases.", false)]
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(TeamFilter))]
	public class ProjectileFunballBehavior : NetworkBehaviour
	{
		[Tooltip("The effect to use for the explosion.")]
		public GameObject explosionPrefab;

		[Tooltip("How many seconds until detonation.")]
		public float duration;

		[Tooltip("Radius of blast in meters.")]
		public float blastRadius = 1f;

		[Tooltip("Maximum damage of blast.")]
		public float blastDamage = 1f;

		[Tooltip("Force of blast.")]
		public float blastForce = 1f;

		private ProjectileController projectileController;

		[SyncVar]
		private float timer;

		private bool fuseStarted;

		public float Networktimer
		{
			get
			{
				return timer;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref timer, 1u);
			}
		}

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
		}

		private void Start()
		{
			Networktimer = -1f;
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active && fuseStarted)
			{
				Networktimer = timer + Time.fixedDeltaTime;
				if (timer >= duration)
				{
					EffectManager.SpawnEffect(explosionPrefab, new EffectData
					{
						origin = base.transform.position,
						scale = blastRadius
					}, transmit: true);
					BlastAttack blastAttack = new BlastAttack();
					blastAttack.attacker = projectileController.owner;
					blastAttack.inflictor = base.gameObject;
					blastAttack.teamIndex = projectileController.teamFilter.teamIndex;
					blastAttack.position = base.transform.position;
					blastAttack.procChainMask = projectileController.procChainMask;
					blastAttack.procCoefficient = projectileController.procCoefficient;
					blastAttack.radius = blastRadius;
					blastAttack.baseDamage = blastDamage;
					blastAttack.baseForce = blastForce;
					blastAttack.bonusForce = UnityEngine.Vector3.zero;
					blastAttack.crit = false;
					blastAttack.damageType = DamageType.Generic;
					blastAttack.Fire();
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}

		private void OnCollisionEnter(Collision collision)
		{
			fuseStarted = true;
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(timer);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(timer);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				timer = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				timer = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileFuse : MonoBehaviour
	{
		public float fuse;

		public UnityEvent onFuse;

		private void Awake()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
			}
		}

		private void FixedUpdate()
		{
			fuse -= Time.fixedDeltaTime;
			if (fuse <= 0f)
			{
				base.enabled = false;
				onFuse.Invoke();
			}
		}
	}
	public class ProjectileGhostCluster : MonoBehaviour
	{
		public GameObject ghostClusterPrefab;

		public int clusterCount;

		public bool distributeEvenly;

		public float clusterDistance;

		private void Start()
		{
			float num = 1f / (Mathf.Log(clusterCount, 4f) + 1f);
			UnityEngine.Vector3 position = base.transform.position;
			for (int i = 0; i < clusterCount; i++)
			{
				GameObject obj = UnityEngine.Object.Instantiate(position: position + ((!distributeEvenly) ? (UnityEngine.Random.insideUnitSphere * clusterDistance) : UnityEngine.Vector3.zero), original: ghostClusterPrefab, rotation: UnityEngine.Quaternion.identity, parent: base.transform);
				obj.transform.localScale = UnityEngine.Vector3.one / (Mathf.Log(clusterCount, 4f) + 1f);
				TrailRenderer component = obj.GetComponent<TrailRenderer>();
				if ((bool)component)
				{
					component.widthMultiplier *= num;
				}
			}
		}

		private void Update()
		{
		}
	}
	public class ProjectileGhostController : MonoBehaviour
	{
		private new Transform transform;

		[HideInInspector]
		public EffectManagerHelper emh;

		private float migration = 1f;

		[Tooltip("Sets the ghost's scale to match the base projectile.")]
		public bool inheritScaleFromProjectile;

		[Tooltip("When my local projectile 'parent' is destroyed, run these.")]
		public UnityEvent ParentProjectileDestroyedEvent;

		private bool alreadyRunParentProjectileDestroyedEvent;

		public Transform authorityTransform { get; set; }

		public Transform predictionTransform { get; set; }

		private void Awake()
		{
			transform = base.transform;
		}

		private void Start()
		{
			if (TryGetComponent<EffectManagerHelper>(out var component))
			{
				emh = component;
			}
		}

		private void OnEnable()
		{
			alreadyRunParentProjectileDestroyedEvent = false;
		}

		private void FixedUpdate()
		{
			if ((bool)authorityTransform ^ (bool)predictionTransform)
			{
				CopyTransform(authorityTransform ? authorityTransform : predictionTransform);
			}
			else if ((bool)authorityTransform)
			{
				LerpTransform(predictionTransform, authorityTransform, migration);
				if (migration == 1f)
				{
					predictionTransform = null;
				}
			}
			else if ((bool)emh && emh.OwningPool != null)
			{
				if (!emh.DontAllowProjectilesToPrematurelyPool)
				{
					emh.OwningPool.ReturnObject(emh);
				}
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void LerpTransform(Transform a, Transform b, float t)
		{
			transform.position = UnityEngine.Vector3.LerpUnclamped(a.position, b.position, t);
			transform.rotation = UnityEngine.Quaternion.SlerpUnclamped(a.rotation, b.rotation, t);
			if (inheritScaleFromProjectile)
			{
				transform.localScale = UnityEngine.Vector3.Lerp(a.localScale, b.localScale, t);
			}
		}

		private void CopyTransform(Transform src)
		{
			transform.position = src.position;
			transform.rotation = src.rotation;
			if (inheritScaleFromProjectile)
			{
				transform.localScale = src.localScale;
			}
		}

		public void OnParentProjectileDestroyed()
		{
			if (!alreadyRunParentProjectileDestroyedEvent)
			{
				ParentProjectileDestroyedEvent.Invoke();
				alreadyRunParentProjectileDestroyedEvent = true;
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileSimple))]
	[RequireComponent(typeof(EntityStateMachine))]
	[RequireComponent(typeof(ProjectileStickOnImpact))]
	public class ProjectileGrappleController : MonoBehaviour
	{
		private struct OwnerInfo
		{
			public readonly GameObject gameObject;

			public readonly CharacterBody characterBody;

			public readonly CharacterMotor characterMotor;

			public readonly Rigidbody rigidbody;

			public readonly EntityStateMachine stateMachine;

			public readonly bool hasEffectiveAuthority;

			public OwnerInfo(GameObject ownerGameObject)
			{
				this = default(OwnerInfo);
				gameObject = ownerGameObject;
				if (!gameObject)
				{
					return;
				}
				characterBody = gameObject.GetComponent<CharacterBody>();
				characterMotor = gameObject.GetComponent<CharacterMotor>();
				rigidbody = gameObject.GetComponent<Rigidbody>();
				hasEffectiveAuthority = Util.HasEffectiveAuthority(gameObject);
				EntityStateMachine[] components = gameObject.GetComponents<EntityStateMachine>();
				for (int i = 0; i < components.Length; i++)
				{
					if (components[i].customName == "Hook")
					{
						stateMachine = components[i];
						break;
					}
				}
			}
		}

		private class BaseState : EntityStates.BaseState
		{
			protected ProjectileGrappleController grappleController;

			protected UnityEngine.Vector3 aimOrigin;

			protected UnityEngine.Vector3 position;

			protected bool ownerValid { get; private set; }

			protected ref OwnerInfo owner => ref grappleController.owner;

			private void UpdatePositions()
			{
				aimOrigin = grappleController.owner.characterBody.aimOrigin;
				position = base.transform.position + base.transform.up * grappleController.normalOffset;
			}

			public override void OnEnter()
			{
				base.OnEnter();
				grappleController = GetComponent<ProjectileGrappleController>();
				ownerValid = (bool)grappleController && (bool)grappleController.owner.gameObject;
				if (ownerValid)
				{
					UpdatePositions();
				}
			}

			public override void FixedUpdate()
			{
				base.FixedUpdate();
				if (ownerValid)
				{
					ownerValid &= grappleController.owner.gameObject;
					if (ownerValid)
					{
						UpdatePositions();
						FixedUpdateBehavior();
					}
				}
				if (NetworkServer.active && !ownerValid)
				{
					ownerValid = false;
					EntityState.Destroy(base.gameObject);
				}
			}

			protected virtual void FixedUpdateBehavior()
			{
				if (base.isAuthority && !grappleController.OwnerIsInFiringState())
				{
					outer.SetNextState(new ReturnState());
				}
			}

			protected Ray GetOwnerAimRay()
			{
				if (!owner.characterBody)
				{
					return default(Ray);
				}
				return owner.characterBody.inputBank.GetAimRay();
			}
		}

		private class FlyState : BaseState
		{
			private float duration;

			public override void OnEnter()
			{
				base.OnEnter();
				duration = grappleController.maxTravelDistance / grappleController.GetComponent<ProjectileSimple>().velocity;
			}

			protected override void FixedUpdateBehavior()
			{
				base.FixedUpdateBehavior();
				if (!base.isAuthority)
				{
					return;
				}
				if (grappleController.projectileStickOnImpactController.stuck)
				{
					EntityState entityState = null;
					if ((bool)grappleController.projectileStickOnImpactController.stuckBody)
					{
						Rigidbody component = grappleController.projectileStickOnImpactController.stuckBody.GetComponent<Rigidbody>();
						if ((bool)component && component.mass < grappleController.yankMassLimit)
						{
							CharacterBody component2 = component.GetComponent<CharacterBody>();
							if (!component2 || !component2.isPlayerControlled || component2.teamComponent.teamIndex != base.projectileController.teamFilter.teamIndex || FriendlyFireManager.ShouldDirectHitProceed(component2.healthComponent, base.projectileController.teamFilter.teamIndex))
							{
								entityState = new YankState();
							}
						}
					}
					if (entityState == null)
					{
						entityState = new GripState();
					}
					DeductOwnerStock();
					outer.SetNextState(entityState);
				}
				else if (duration <= base.fixedAge)
				{
					outer.SetNextState(new ReturnState());
				}
			}

			private void DeductOwnerStock()
			{
				if (!base.ownerValid || !base.owner.hasEffectiveAuthority)
				{
					return;
				}
				SkillLocator component = base.owner.gameObject.GetComponent<SkillLocator>();
				if ((bool)component)
				{
					GenericSkill secondary = component.secondary;
					if ((bool)secondary)
					{
						secondary.DeductStock(1);
					}
				}
			}
		}

		private class BaseGripState : BaseState
		{
			protected float currentDistance;

			public override void OnEnter()
			{
				base.OnEnter();
				currentDistance = UnityEngine.Vector3.Distance(aimOrigin, position);
			}

			protected override void FixedUpdateBehavior()
			{
				base.FixedUpdateBehavior();
				currentDistance = UnityEngine.Vector3.Distance(aimOrigin, position);
				if (base.isAuthority)
				{
					bool flag = !grappleController.projectileStickOnImpactController.stuck;
					bool flag2 = currentDistance < grappleController.nearBreakDistance;
					bool flag3 = !grappleController.OwnerIsInFiringState();
					if (!base.owner.stateMachine || !((base.owner.stateMachine.state as BaseSkillState)?.IsKeyDownAuthority() ?? false) || flag3 || flag2 || flag)
					{
						outer.SetNextState(new ReturnState());
					}
				}
			}
		}

		private class GripState : BaseGripState
		{
			private float lastDistance;

			private void DeductStockIfStruckNonPylon()
			{
				GameObject victim = grappleController.projectileStickOnImpactController.victim;
				if ((bool)victim)
				{
					GameObject gameObject = victim;
					EntityLocator component = gameObject.GetComponent<EntityLocator>();
					if ((bool)component)
					{
						gameObject = component.entity;
					}
					_ = (bool)gameObject.GetComponent<ProjectileController>();
				}
			}

			public override void OnEnter()
			{
				base.OnEnter();
				lastDistance = UnityEngine.Vector3.Distance(aimOrigin, position);
				if (base.ownerValid)
				{
					grappleController.didStick = true;
					if ((bool)base.owner.characterMotor)
					{
						UnityEngine.Vector3 direction = GetOwnerAimRay().direction;
						UnityEngine.Vector3 velocity = base.owner.characterMotor.velocity;
						velocity = ((UnityEngine.Vector3.Dot(velocity, direction) < 0f) ? UnityEngine.Vector3.zero : UnityEngine.Vector3.Project(velocity, direction));
						velocity += direction * grappleController.initialLookImpulse;
						velocity += base.owner.characterMotor.moveDirection * grappleController.initiallMoveImpulse;
						base.owner.characterMotor.velocity = velocity;
					}
				}
			}

			protected override void FixedUpdateBehavior()
			{
				base.FixedUpdateBehavior();
				float num = grappleController.acceleration;
				if (currentDistance > lastDistance)
				{
					num *= grappleController.escapeForceMultiplier;
				}
				lastDistance = currentDistance;
				if (base.owner.hasEffectiveAuthority && (bool)base.owner.characterMotor && (bool)base.owner.characterBody)
				{
					Ray ownerAimRay = GetOwnerAimRay();
					UnityEngine.Vector3 normalized = (base.transform.position - base.owner.characterBody.aimOrigin).normalized;
					UnityEngine.Vector3 vector = normalized * num;
					float time = Mathf.Clamp01(base.fixedAge / grappleController.lookAccelerationRampUpDuration);
					float num2 = grappleController.lookAccelerationRampUpCurve.Evaluate(time);
					float num3 = Util.Remap(UnityEngine.Vector3.Dot(ownerAimRay.direction, normalized), -1f, 1f, 1f, 0f);
					vector += ownerAimRay.direction * (grappleController.lookAcceleration * num2 * num3);
					vector += base.owner.characterMotor.moveDirection * grappleController.moveAcceleration;
					base.owner.characterMotor.ApplyForce(vector * (base.owner.characterMotor.mass * Time.fixedDeltaTime), alwaysApply: true, disableAirControlUntilCollision: true);
				}
			}
		}

		private class YankState : BaseGripState
		{
			public static float yankSpeed;

			public static float delayBeforeYanking;

			public static float hoverTimeLimit = 0.5f;

			private CharacterBody stuckBody;

			public override void OnEnter()
			{
				base.OnEnter();
				stuckBody = grappleController.projectileStickOnImpactController.stuckBody;
			}

			protected override void FixedUpdateBehavior()
			{
				base.FixedUpdateBehavior();
				if (!stuckBody)
				{
					return;
				}
				if (Util.HasEffectiveAuthority(stuckBody.gameObject))
				{
					UnityEngine.Vector3 vector = aimOrigin - position;
					IDisplacementReceiver component = stuckBody.GetComponent<IDisplacementReceiver>();
					if ((bool)(Component)component && base.fixedAge >= delayBeforeYanking)
					{
						component.AddDisplacement(vector * (yankSpeed * Time.fixedDeltaTime));
					}
				}
				if (base.owner.hasEffectiveAuthority && (bool)base.owner.characterMotor && base.fixedAge < hoverTimeLimit)
				{
					UnityEngine.Vector3 velocity = base.owner.characterMotor.velocity;
					if (velocity.y < 0f)
					{
						velocity.y = 0f;
						base.owner.characterMotor.velocity = velocity;
					}
				}
			}
		}

		private class ReturnState : BaseState
		{
			private float returnSpeedAcceleration = 240f;

			private float returnSpeed;

			public override void OnEnter()
			{
				base.OnEnter();
				if (base.ownerValid)
				{
					returnSpeed = grappleController.projectileSimple.velocity;
					returnSpeedAcceleration = returnSpeed * 2f;
				}
				if (NetworkServer.active && (bool)grappleController)
				{
					grappleController.projectileStickOnImpactController.Detach();
					grappleController.projectileStickOnImpactController.ignoreCharacters = true;
					grappleController.projectileStickOnImpactController.ignoreWorld = true;
				}
				Collider component = GetComponent<Collider>();
				if ((bool)component)
				{
					component.enabled = false;
				}
			}

			protected override void FixedUpdateBehavior()
			{
				base.FixedUpdateBehavior();
				if (!base.rigidbody)
				{
					return;
				}
				returnSpeed += returnSpeedAcceleration * Time.fixedDeltaTime;
				base.rigidbody.velocity = (aimOrigin - position).normalized * returnSpeed;
				if (NetworkServer.active)
				{
					UnityEngine.Vector3 endPosition = position + base.rigidbody.velocity * Time.fixedDeltaTime;
					if (HGMath.Overshoots(position, endPosition, aimOrigin))
					{
						EntityState.Destroy(base.gameObject);
					}
				}
			}
		}

		private ProjectileController projectileController;

		private ProjectileStickOnImpact projectileStickOnImpactController;

		private ProjectileSimple projectileSimple;

		public SerializableEntityStateType ownerHookStateType;

		public float acceleration;

		public float lookAcceleration = 4f;

		public float lookAccelerationRampUpDuration = 0.25f;

		public float initialLookImpulse = 5f;

		public float initiallMoveImpulse = 5f;

		public float moveAcceleration = 4f;

		public string enterSoundString;

		public string exitSoundString;

		public string hookDistanceRTPCstring;

		public float minHookDistancePitchModifier;

		public float maxHookDistancePitchModifier;

		public AnimationCurve lookAccelerationRampUpCurve;

		public Transform ropeEndTransform;

		public string muzzleStringOnBody = "MuzzleLeft";

		[Tooltip("The minimum distance the hook can be from the target before it detaches.")]
		public float nearBreakDistance;

		[Tooltip("The maximum distance this hook can travel.")]
		public float maxTravelDistance;

		public float escapeForceMultiplier = 2f;

		public float normalOffset = 1f;

		public float yankMassLimit;

		private Type resolvedOwnerHookStateType;

		private OwnerInfo owner;

		private bool didStick;

		private uint soundID;

		private void Awake()
		{
			projectileStickOnImpactController = GetComponent<ProjectileStickOnImpact>();
			projectileController = GetComponent<ProjectileController>();
			projectileSimple = GetComponent<ProjectileSimple>();
			resolvedOwnerHookStateType = ownerHookStateType.stateType;
			if ((bool)ropeEndTransform)
			{
				soundID = Util.PlaySound(enterSoundString, ropeEndTransform.gameObject);
			}
		}

		private void FixedUpdate()
		{
			if ((bool)ropeEndTransform)
			{
				float in_value = Util.Remap((ropeEndTransform.transform.position - base.transform.position).magnitude, minHookDistancePitchModifier, maxHookDistancePitchModifier, 0f, 100f);
				AkSoundEngine.SetRTPCValueByPlayingID(hookDistanceRTPCstring, in_value, soundID);
			}
		}

		private void AssignHookReferenceToBodyStateMachine()
		{
			if ((bool)owner.stateMachine && owner.stateMachine.state is FireHook fireHook)
			{
				fireHook.SetHookReference(base.gameObject);
			}
			Transform modelTransform = owner.gameObject.GetComponent<ModelLocator>().modelTransform;
			if (!modelTransform)
			{
				return;
			}
			ChildLocator component = modelTransform.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				Transform transform = component.FindChild(muzzleStringOnBody);
				if ((bool)transform)
				{
					ropeEndTransform.SetParent(transform, worldPositionStays: false);
				}
			}
		}

		private void Start()
		{
			owner = new OwnerInfo(projectileController.owner);
			AssignHookReferenceToBodyStateMachine();
		}

		private void OnDestroy()
		{
			if ((bool)ropeEndTransform)
			{
				Util.PlaySound(exitSoundString, ropeEndTransform.gameObject);
				UnityEngine.Object.Destroy(ropeEndTransform.gameObject);
			}
			else
			{
				AkSoundEngine.StopPlayingID(soundID);
			}
		}

		private bool OwnerIsInFiringState()
		{
			if ((bool)owner.stateMachine)
			{
				return owner.stateMachine.state.GetType() == resolvedOwnerHookStateType;
			}
			return false;
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileImpactEventCaller : MonoBehaviour, IProjectileImpactBehavior
	{
		public ProjectileImpactEvent impactEvent;

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			impactEvent?.Invoke(impactInfo);
		}
	}
	[Serializable]
	public class ProjectileImpactEvent : UnityEvent<ProjectileImpactInfo>
	{
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileImpactExplosion : ProjectileExplosion, IProjectileImpactBehavior
	{
		public enum TransformSpace
		{
			World,
			Local,
			Normal
		}

		private UnityEngine.Vector3 impactNormal = UnityEngine.Vector3.up;

		[Header("Impact & Lifetime Properties")]
		public GameObject impactEffect;

		[ShowFieldObsolete]
		[Tooltip("This sound will not play over the network. Use lifetimeExpiredSound instead.")]
		[HideInInspector]
		[Obsolete("This sound will not play over the network. Use lifetimeExpiredSound instead.", false)]
		public string lifetimeExpiredSoundString;

		public NetworkSoundEventDef lifetimeExpiredSound;

		public float offsetForLifetimeExpiredSound;

		public bool destroyOnEnemy = true;

		public bool destroyOnWorld;

		public bool impactOnWorld = true;

		public bool timerAfterImpact;

		public float lifetime;

		public float lifetimeAfterImpact;

		public float lifetimeRandomOffset;

		private float stopwatch;

		public uint minimumPhysicsStepsToKeepAliveAfterImpact;

		private float stopwatchAfterImpact;

		private bool hasImpact;

		private bool hasPlayedLifetimeExpiredSound;

		public TransformSpace transformSpace;

		public bool explodeOnLifeTimeExpiration;

		protected override void Awake()
		{
			base.Awake();
			lifetime += UnityEngine.Random.Range(0f, lifetimeRandomOffset);
		}

		protected void FixedUpdate()
		{
			stopwatch += Time.fixedDeltaTime;
			if (!NetworkServer.active && !projectileController.isPrediction)
			{
				return;
			}
			if (explodeOnLifeTimeExpiration && alive && stopwatch >= lifetime)
			{
				explosionEffect = impactEffect ?? explosionEffect;
				Detonate();
			}
			if (timerAfterImpact && hasImpact)
			{
				stopwatchAfterImpact += Time.fixedDeltaTime;
			}
			bool num = stopwatch >= lifetime;
			bool flag = timerAfterImpact && stopwatchAfterImpact > lifetimeAfterImpact;
			bool flag2 = (bool)projectileHealthComponent && !projectileHealthComponent.alive;
			if (num || flag || flag2)
			{
				alive = false;
			}
			if (timerAfterImpact && hasImpact && minimumPhysicsStepsToKeepAliveAfterImpact != 0)
			{
				minimumPhysicsStepsToKeepAliveAfterImpact--;
				alive = true;
			}
			if (alive && !hasPlayedLifetimeExpiredSound)
			{
				bool flag3 = stopwatch > lifetime - offsetForLifetimeExpiredSound;
				if (timerAfterImpact)
				{
					flag3 |= stopwatchAfterImpact > lifetimeAfterImpact - offsetForLifetimeExpiredSound;
				}
				if (flag3)
				{
					hasPlayedLifetimeExpiredSound = true;
					if (NetworkServer.active && (bool)lifetimeExpiredSound)
					{
						PointSoundManager.EmitSoundServer(lifetimeExpiredSound.index, base.transform.position);
					}
				}
			}
			if (!alive)
			{
				explosionEffect = impactEffect ?? explosionEffect;
				Detonate();
			}
		}

		protected override UnityEngine.Quaternion GetRandomDirectionForChild()
		{
			UnityEngine.Quaternion randomChildRollPitch = GetRandomChildRollPitch();
			return transformSpace switch
			{
				TransformSpace.Local => base.transform.rotation * randomChildRollPitch, 
				TransformSpace.Normal => UnityEngine.Quaternion.FromToRotation(UnityEngine.Vector3.forward, impactNormal) * randomChildRollPitch, 
				_ => randomChildRollPitch, 
			};
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (!alive)
			{
				return;
			}
			Collider collider = impactInfo.collider;
			impactNormal = impactInfo.estimatedImpactNormal;
			if (!collider)
			{
				return;
			}
			DamageInfo damageInfo = new DamageInfo();
			if ((bool)projectileDamage)
			{
				damageInfo.damage = projectileDamage.damage;
				damageInfo.crit = projectileDamage.crit;
				damageInfo.attacker = (projectileController.owner ? projectileController.owner.gameObject : null);
				damageInfo.inflictor = base.gameObject;
				damageInfo.position = impactInfo.estimatedPointOfImpact;
				damageInfo.force = projectileDamage.force * base.transform.forward;
				damageInfo.procChainMask = projectileController.procChainMask;
				damageInfo.procCoefficient = projectileController.procCoefficient;
			}
			HurtBox component = collider.GetComponent<HurtBox>();
			if ((bool)component)
			{
				if (destroyOnEnemy)
				{
					HealthComponent healthComponent = component.healthComponent;
					if ((bool)healthComponent)
					{
						if (healthComponent.gameObject == projectileController.owner || ((bool)projectileHealthComponent && healthComponent == projectileHealthComponent))
						{
							return;
						}
						alive = false;
					}
				}
			}
			else if (destroyOnWorld)
			{
				alive = false;
			}
			hasImpact = (bool)component || impactOnWorld;
			if (NetworkServer.active && hasImpact)
			{
				GlobalEventManager.instance.OnHitAll(damageInfo, collider.gameObject);
			}
		}

		protected override void OnValidate()
		{
			if (!Application.IsPlaying(this))
			{
				base.OnValidate();
				if (!string.IsNullOrEmpty(lifetimeExpiredSoundString))
				{
					UnityEngine.Debug.LogWarningFormat(base.gameObject, "{0} ProjectileImpactExplosion component supplies a value in the lifetimeExpiredSoundString field. This will not play correctly over the network. Please use lifetimeExpiredSound instead.", Util.GetGameObjectHierarchyName(base.gameObject));
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileImpaleOnEnemy : MonoBehaviour, IProjectileImpactBehavior
	{
		private bool alive = true;

		public GameObject impalePrefab;

		private Rigidbody rigidbody;

		private void Awake()
		{
			rigidbody = GetComponent<Rigidbody>();
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (!alive)
			{
				return;
			}
			Collider collider = impactInfo.collider;
			if (!collider)
			{
				return;
			}
			HurtBox component = collider.GetComponent<HurtBox>();
			if ((bool)component)
			{
				_ = base.transform.position;
				UnityEngine.Vector3 estimatedPointOfImpact = impactInfo.estimatedPointOfImpact;
				_ = UnityEngine.Quaternion.identity;
				if ((bool)rigidbody)
				{
					Util.QuaternionSafeLookRotation(rigidbody.velocity);
				}
				GameObject obj = UnityEngine.Object.Instantiate(impalePrefab, component.transform);
				obj.transform.position = estimatedPointOfImpact;
				obj.transform.rotation = base.transform.rotation;
			}
		}
	}
	public class ProjectileInflictTimedBuff : MonoBehaviour, IOnDamageInflictedServerReceiver
	{
		public BuffDef buffDef;

		public float duration;

		public void OnDamageInflictedServer(DamageReport damageReport)
		{
			CharacterBody victimBody = damageReport.victimBody;
			if ((bool)victimBody)
			{
				victimBody.AddTimedBuff(buffDef.buffIndex, duration);
			}
		}

		private void OnValidate()
		{
			if (!buffDef)
			{
				UnityEngine.Debug.LogWarningFormat(this, "ProjectileInflictTimedBuff {0} has no buff specified.", this);
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileInstantiateDeployable : MonoBehaviour
	{
		[Tooltip("The deployable slot to use.")]
		[SerializeField]
		private DeployableSlot deployableSlot;

		[Tooltip("The prefab to instantiate.")]
		[SerializeField]
		private GameObject prefab;

		[Tooltip("The object upon which the prefab will be positioned.")]
		[SerializeField]
		private Transform targetTransform;

		[SerializeField]
		[Tooltip("The transform upon which to instantiate the prefab.")]
		private bool copyTargetRotation;

		[Tooltip("Whether or not to parent the instantiated prefab to the specified transform.")]
		[SerializeField]
		private bool parentToTarget;

		[SerializeField]
		[Tooltip("Whether or not to instantiate this prefab. If so, this will only run on the server, and will be spawned over the network.")]
		private bool instantiateOnStart = true;

		public void Start()
		{
			if (instantiateOnStart)
			{
				InstantiateDeployable();
			}
		}

		public void InstantiateDeployable()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			GameObject owner = GetComponent<ProjectileController>().owner;
			if (!owner)
			{
				return;
			}
			CharacterBody component = owner.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				CharacterMaster master = component.master;
				if ((bool)master)
				{
					UnityEngine.Vector3 position = (targetTransform ? targetTransform.position : UnityEngine.Vector3.zero);
					UnityEngine.Quaternion rotation = (copyTargetRotation ? targetTransform.rotation : UnityEngine.Quaternion.identity);
					Transform parent = (parentToTarget ? targetTransform : null);
					GameObject gameObject = UnityEngine.Object.Instantiate(prefab, position, rotation, parent);
					NetworkServer.Spawn(gameObject);
					master.AddDeployable(gameObject.GetComponent<Deployable>(), deployableSlot);
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileDamage))]
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileIntervalOverlapAttack : MonoBehaviour
	{
		public HitBoxGroup hitBoxGroup;

		public float interval;

		public float damageCoefficient = 1f;

		private float countdown;

		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
		}

		private void Start()
		{
			countdown = 0f;
		}

		private void FixedUpdate()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			countdown -= Time.fixedDeltaTime;
			if (countdown <= 0f)
			{
				countdown += interval;
				if ((bool)hitBoxGroup)
				{
					OverlapAttack overlapAttack = new OverlapAttack();
					overlapAttack.attacker = projectileController.owner;
					overlapAttack.inflictor = base.gameObject;
					overlapAttack.teamIndex = projectileController.teamFilter.teamIndex;
					overlapAttack.damage = projectileDamage.damage * damageCoefficient;
					overlapAttack.hitBoxGroup = hitBoxGroup;
					overlapAttack.isCrit = projectileDamage.crit;
					overlapAttack.procCoefficient = 0f;
					overlapAttack.damageType = projectileDamage.damageType;
					overlapAttack.Fire();
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileDamage))]
	public class ProjectileMageFirewallController : MonoBehaviour, IProjectileImpactBehavior
	{
		public GameObject walkerPrefab;

		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private bool consumed;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
		}

		void IProjectileImpactBehavior.OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (!consumed)
			{
				consumed = true;
				CreateWalkers();
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private void CreateWalkers()
		{
			UnityEngine.Vector3 forward = base.transform.forward;
			forward.y = 0f;
			forward.Normalize();
			UnityEngine.Vector3 vector = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, forward);
			ProjectileManager.instance.FireProjectile(walkerPrefab, base.transform.position + UnityEngine.Vector3.up, Util.QuaternionSafeLookRotation(vector), projectileController.owner, projectileDamage.damage, projectileDamage.force, projectileDamage.crit, projectileDamage.damageColorIndex);
			ProjectileManager.instance.FireProjectile(walkerPrefab, base.transform.position + UnityEngine.Vector3.up, Util.QuaternionSafeLookRotation(-vector), projectileController.owner, projectileDamage.damage, projectileDamage.force, projectileDamage.crit, projectileDamage.damageColorIndex);
		}
	}
	[RequireComponent(typeof(ProjectileDamage))]
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileMageFirewallWalkerController : MonoBehaviour
	{
		public int totalProjectiles;

		private int _projectileCounter;

		public float dropInterval = 0.15f;

		public GameObject firePillarPrefab;

		public float pillarAngle = 45f;

		public bool curveToCenter = true;

		private float moveSign;

		[Tooltip("Some consoles/etc run a different FixedUpdate timestep. This allows you to run an independent coroutine to get the timing right.")]
		[SerializeField]
		private bool DontUseFixedUpdateForProjectileSpawning;

		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private UnityEngine.Vector3 lastCenterPosition;

		private float timer;

		private UnityEngine.Vector3 currentPillarVector = UnityEngine.Vector3.up;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			lastCenterPosition = base.transform.position;
			timer = dropInterval / 2f;
			moveSign = 1f;
		}

		private void Start()
		{
			if ((bool)projectileController.owner)
			{
				UnityEngine.Vector3 position = projectileController.owner.transform.position;
				UnityEngine.Vector3 rhs = base.transform.position - position;
				rhs.y = 0f;
				if (rhs.x != 0f && rhs.z != 0f)
				{
					moveSign = Mathf.Sign(UnityEngine.Vector3.Dot(base.transform.right, rhs));
				}
			}
			UpdateDirections();
			_projectileCounter = totalProjectiles;
			if (DontUseFixedUpdateForProjectileSpawning)
			{
				StartCoroutine(ProcessProjectilesLoop());
			}
		}

		private void UpdateDirections()
		{
			if (curveToCenter)
			{
				UnityEngine.Vector3 vector = base.transform.position - lastCenterPosition;
				vector.y = 0f;
				if (vector.x != 0f && vector.z != 0f)
				{
					vector.Normalize();
					UnityEngine.Vector3 vector2 = UnityEngine.Vector3.Cross(UnityEngine.Vector3.up, vector);
					base.transform.forward = vector2 * moveSign;
					currentPillarVector = UnityEngine.Quaternion.AngleAxis(pillarAngle, vector2) * UnityEngine.Vector3.Cross(vector, vector2);
				}
			}
		}

		private IEnumerator ProcessProjectilesLoop()
		{
			yield return new WaitForSeconds(dropInterval / 2f);
			while (base.gameObject.activeSelf)
			{
				HandleProjectileGeneration();
				yield return new WaitForSeconds(dropInterval);
			}
		}

		private void FixedUpdate()
		{
			if (!DontUseFixedUpdateForProjectileSpawning)
			{
				HandleProjectileGeneration();
			}
		}

		private void HandleProjectileGeneration()
		{
			if ((bool)projectileController.owner)
			{
				lastCenterPosition = projectileController.owner.transform.position;
			}
			if (_projectileCounter <= 0)
			{
				return;
			}
			UpdateDirections();
			if (!NetworkServer.active)
			{
				return;
			}
			timer -= Time.fixedDeltaTime;
			if (timer <= 0f || DontUseFixedUpdateForProjectileSpawning)
			{
				timer = dropInterval;
				_projectileCounter--;
				if ((bool)firePillarPrefab)
				{
					ProjectileManager.instance.FireProjectile(firePillarPrefab, base.transform.position, Util.QuaternionSafeLookRotation(currentPillarVector), projectileController.owner, projectileDamage.damage, projectileDamage.force, projectileDamage.crit, projectileDamage.damageColorIndex);
				}
			}
		}
	}
	public struct FireProjectileInfo
	{
		public GameObject projectilePrefab;

		public UnityEngine.Vector3 position;

		public UnityEngine.Quaternion rotation;

		public GameObject owner;

		public GameObject target;

		public bool useSpeedOverride;

		private float _speedOverride;

		public bool useFuseOverride;

		private float _fuseOverride;

		public float damage;

		public float force;

		public bool crit;

		public DamageColorIndex damageColorIndex;

		public ProcChainMask procChainMask;

		public DamageTypeCombo? damageTypeOverride;

		public float speedOverride
		{
			get
			{
				if (!useSpeedOverride)
				{
					return -1f;
				}
				return _speedOverride;
			}
			set
			{
				useSpeedOverride = value != -1f;
				_speedOverride = value;
			}
		}

		public float fuseOverride
		{
			get
			{
				if (!useFuseOverride)
				{
					return -1f;
				}
				return _fuseOverride;
			}
			set
			{
				useFuseOverride = value != -1f;
				_fuseOverride = value;
			}
		}
	}
	public class ProjectileManager : MonoBehaviour
	{
		private struct ProjectileQueueItem
		{
			public FireProjectileInfo fireProjectileInfo;

			public NetworkConnection clientAuthorityOwner;

			public NetworkClient localNetworkClient;

			public ushort predictionId;

			public double fireSendTime;

			public int timeCachedFrameStamp;

			public UnityEngine.Vector3 positionOffset;

			public bool ownerStartedAsNull;

			public ProjectileQueueItem(FireProjectileInfo fireProjectileInfo, int currentFrame, NetworkConnection clientAuthorityOwner = null, ushort predictionId = 0, double fireSendTime = 0.0)
			{
				this.fireProjectileInfo = fireProjectileInfo;
				ownerStartedAsNull = fireProjectileInfo.owner == null;
				timeCachedFrameStamp = currentFrame;
				this.clientAuthorityOwner = clientAuthorityOwner;
				this.predictionId = predictionId;
				this.fireSendTime = fireSendTime;
				localNetworkClient = null;
				if (!ownerStartedAsNull && fireProjectileInfo.owner.TryGetComponent<CharacterBody>(out var component))
				{
					positionOffset = component.corePosition - fireProjectileInfo.position;
				}
				else
				{
					positionOffset = UnityEngine.Vector3.zero;
				}
			}

			public ProjectileQueueItem(FireProjectileInfo fireProjectileInfo, NetworkClient serverClient = null, double fireSendTime = 0.0)
			{
				this.fireProjectileInfo = fireProjectileInfo;
				ownerStartedAsNull = fireProjectileInfo.owner == null;
				timeCachedFrameStamp = 0;
				clientAuthorityOwner = null;
				predictionId = 0;
				this.fireSendTime = fireSendTime;
				localNetworkClient = serverClient;
				if (!ownerStartedAsNull && fireProjectileInfo.owner.TryGetComponent<CharacterBody>(out var component))
				{
					positionOffset = component.corePosition - fireProjectileInfo.position;
				}
				else
				{
					positionOffset = UnityEngine.Vector3.zero;
				}
			}

			public void TryAdjustingFiringPosition()
			{
				if (!ownerStartedAsNull && !(fireProjectileInfo.owner == null) && fireProjectileInfo.owner.TryGetComponent<CharacterBody>(out var component))
				{
					fireProjectileInfo.position = component.corePosition + positionOffset;
				}
			}
		}

		private class PlayerFireProjectileMessage : MessageBase
		{
			public double sendTime;

			public uint prefabIndexPlusOne;

			public UnityEngine.Vector3 position;

			public UnityEngine.Quaternion rotation;

			public GameObject owner;

			public HurtBoxReference target;

			public float damage;

			public float force;

			public bool crit;

			public ushort predictionId;

			public DamageColorIndex damageColorIndex;

			public float speedOverride;

			public float fuseOverride;

			public bool useDamageTypeOverride;

			public DamageTypeCombo damageTypeOverride;

			public override void Serialize(NetworkWriter writer)
			{
				writer.Write(sendTime);
				writer.WritePackedUInt32(prefabIndexPlusOne);
				writer.Write(position);
				writer.Write(rotation);
				writer.Write(owner);
				GeneratedNetworkCode._WriteHurtBoxReference_None(writer, target);
				writer.Write(damage);
				writer.Write(force);
				writer.Write(crit);
				writer.WritePackedUInt32(predictionId);
				writer.Write((int)damageColorIndex);
				writer.Write(speedOverride);
				writer.Write(fuseOverride);
				writer.Write(useDamageTypeOverride);
				GeneratedNetworkCode._WriteDamageTypeCombo_None(writer, damageTypeOverride);
			}

			public override void Deserialize(NetworkReader reader)
			{
				sendTime = reader.ReadDouble();
				prefabIndexPlusOne = reader.ReadPackedUInt32();
				position = reader.ReadVector3();
				rotation = reader.ReadQuaternion();
				owner = reader.ReadGameObject();
				target = GeneratedNetworkCode._ReadHurtBoxReference_None(reader);
				damage = reader.ReadSingle();
				force = reader.ReadSingle();
				crit = reader.ReadBoolean();
				predictionId = (ushort)reader.ReadPackedUInt32();
				damageColorIndex = (DamageColorIndex)reader.ReadInt32();
				speedOverride = reader.ReadSingle();
				fuseOverride = reader.ReadSingle();
				useDamageTypeOverride = reader.ReadBoolean();
				damageTypeOverride = GeneratedNetworkCode._ReadDamageTypeCombo_None(reader);
			}
		}

		private class ReleasePredictionIdMessage : MessageBase
		{
			public ushort predictionId;

			public override void Serialize(NetworkWriter writer)
			{
				writer.WritePackedUInt32(predictionId);
			}

			public override void Deserialize(NetworkReader reader)
			{
				predictionId = (ushort)reader.ReadPackedUInt32();
			}
		}

		private class PredictionManager
		{
			private Dictionary<ushort, ProjectileController> predictions = new Dictionary<ushort, ProjectileController>();

			public ProjectileController FindPredictedProjectileController(ushort predictionId)
			{
				return predictions[predictionId];
			}

			public void OnAuthorityProjectileReceived(ProjectileController authoritativeProjectile)
			{
				if (authoritativeProjectile.hasAuthority && authoritativeProjectile.predictionId != 0 && predictions.TryGetValue(authoritativeProjectile.predictionId, out var value))
				{
					authoritativeProjectile.ghost = value.ghost;
					if ((bool)authoritativeProjectile.ghost)
					{
						authoritativeProjectile.ghost.authorityTransform = authoritativeProjectile.transform;
					}
					authoritativeProjectile.DispatchOnInitialized();
				}
			}

			public void ReleasePredictionId(ushort predictionId)
			{
				ProjectileController projectileController = predictions[predictionId];
				predictions.Remove(predictionId);
				if ((bool)projectileController && (bool)projectileController.gameObject)
				{
					UnityEngine.Object.Destroy(projectileController.gameObject);
				}
			}

			public void RegisterPrediction(ProjectileController predictedProjectile)
			{
				predictedProjectile.NetworkpredictionId = RequestPredictionId();
				predictions[predictedProjectile.predictionId] = predictedProjectile;
				predictedProjectile.isPrediction = true;
			}

			private ushort RequestPredictionId()
			{
				for (ushort num = 1; num < 32767; num++)
				{
					if (!predictions.ContainsKey(num))
					{
						return num;
					}
				}
				return 0;
			}
		}

		private PredictionManager predictionManager;

		private static Queue<ProjectileQueueItem> queuedProjectiles = new Queue<ProjectileQueueItem>(150);

		private static int _projectileCurrentFrame;

		private static int totalProjectilesFiredThisFrame;

		private static int maximumProjectilesFiredPerFrame = 20;

		private static int totalQueuedProjectilesAllowedPerFrame = 5;

		private static double projectileExpirationLifetime = 5.0;

		private PlayerFireProjectileMessage fireMsg = new PlayerFireProjectileMessage();

		private ReleasePredictionIdMessage releasePredictionIdMsg = new ReleasePredictionIdMessage();

		public static ProjectileManager instance { get; private set; }

		private static int projectileCurrentFrame
		{
			get
			{
				return _projectileCurrentFrame;
			}
			set
			{
				if (value > _projectileCurrentFrame)
				{
					_projectileCurrentFrame = value;
					totalProjectilesFiredThisFrame = 0;
				}
			}
		}

		private static void CacheProjectileForNextFrameServer(FireProjectileInfo fireProjectileInfo, NetworkConnection clientAuthorityOwner = null, ushort predictionId = 0, double fastForwardTime = 0.0)
		{
			ProjectileQueueItem item = new ProjectileQueueItem(fireProjectileInfo, projectileCurrentFrame, clientAuthorityOwner, predictionId, (double)Run.instance.time - fastForwardTime);
			queuedProjectiles.Enqueue(item);
		}

		private static void CacheProjectileForNextFrameClient(FireProjectileInfo fireProjectileInfo, NetworkClient client = null, double fireTime = 0.0)
		{
			ProjectileQueueItem item = new ProjectileQueueItem(fireProjectileInfo, client, fireTime);
			queuedProjectiles.Enqueue(item);
		}

		private static bool CanAffordToFireProjectile()
		{
			return totalProjectilesFiredThisFrame < maximumProjectilesFiredPerFrame;
		}

		private bool ShouldSkipFiringProjectile(double currentRunTime, ProjectileQueueItem nextItem)
		{
			if (!(currentRunTime - nextItem.fireSendTime > projectileExpirationLifetime))
			{
				if (!nextItem.ownerStartedAsNull)
				{
					return nextItem.fireProjectileInfo.owner == null;
				}
				return false;
			}
			return true;
		}

		private void ClientFireQueuedProjectiles()
		{
			double currentRunTime = Run.instance.time;
			int num = 0;
			int num2 = 0;
			num2 = 0;
			while (totalProjectilesFiredThisFrame < maximumProjectilesFiredPerFrame && queuedProjectiles.Count > 0 && num2 < totalQueuedProjectilesAllowedPerFrame)
			{
				ProjectileQueueItem nextItem = queuedProjectiles.Dequeue();
				if (ShouldSkipFiringProjectile(currentRunTime, nextItem))
				{
					num++;
					num2--;
				}
				else
				{
					nextItem.TryAdjustingFiringPosition();
					FireProjectileClient(nextItem.fireProjectileInfo, nextItem.localNetworkClient, nextItem.fireSendTime);
				}
				num2++;
			}
			_ = 0;
			_ = 0;
		}

		private void ServerFireQueuedProjectiles()
		{
			double num = Run.instance.time;
			int num2 = 0;
			int num3 = 0;
			num3 = 0;
			while (totalProjectilesFiredThisFrame < maximumProjectilesFiredPerFrame && queuedProjectiles.Count > 0 && num3 < totalQueuedProjectilesAllowedPerFrame)
			{
				ProjectileQueueItem nextItem = queuedProjectiles.Dequeue();
				if (ShouldSkipFiringProjectile(num, nextItem))
				{
					num2++;
					num3--;
				}
				else
				{
					nextItem.TryAdjustingFiringPosition();
					FireProjectileServer(nextItem.fireProjectileInfo, nextItem.clientAuthorityOwner, nextItem.predictionId, num - nextItem.fireSendTime);
				}
				num3++;
			}
			_ = 0;
			_ = 0;
		}

		private void Awake()
		{
			predictionManager = new PredictionManager();
		}

		private void OnEnable()
		{
			instance = SingletonHelper.Assign(instance, this);
		}

		private void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		[NetworkMessageHandler(msgType = 49, server = true)]
		private static void HandlePlayerFireProjectile(NetworkMessage netMsg)
		{
			if ((bool)instance)
			{
				instance.HandlePlayerFireProjectileInternal(netMsg);
			}
		}

		[NetworkMessageHandler(msgType = 50, client = true)]
		private static void HandleReleaseProjectilePredictionId(NetworkMessage netMsg)
		{
			if ((bool)instance)
			{
				instance.HandleReleaseProjectilePredictionIdInternal(netMsg);
			}
		}

		public void FireProjectile(GameObject prefab, UnityEngine.Vector3 position, UnityEngine.Quaternion rotation, GameObject owner, float damage, float force, bool crit, DamageColorIndex damageColorIndex = DamageColorIndex.Default, GameObject target = null, float speedOverride = -1f)
		{
			FireProjectileInfo fireProjectileInfo = default(FireProjectileInfo);
			fireProjectileInfo.projectilePrefab = prefab;
			fireProjectileInfo.position = position;
			fireProjectileInfo.rotation = rotation;
			fireProjectileInfo.owner = owner;
			fireProjectileInfo.damage = damage;
			fireProjectileInfo.force = force;
			fireProjectileInfo.crit = crit;
			fireProjectileInfo.damageColorIndex = damageColorIndex;
			fireProjectileInfo.target = target;
			fireProjectileInfo.speedOverride = speedOverride;
			fireProjectileInfo.fuseOverride = -1f;
			fireProjectileInfo.damageTypeOverride = null;
			FireProjectileInfo fireProjectileInfo2 = fireProjectileInfo;
			FireProjectile(fireProjectileInfo2);
		}

		public void FireProjectile(FireProjectileInfo fireProjectileInfo)
		{
			if (NetworkServer.active)
			{
				FireProjectileServer(fireProjectileInfo, null, 0);
			}
			else
			{
				FireProjectileClient(fireProjectileInfo, NetworkManager.singleton.client);
			}
		}

		private void FireProjectileClient(FireProjectileInfo fireProjectileInfo, NetworkClient client, double fireTime = -1.0)
		{
			if (fireTime == -1.0)
			{
				fireTime = Run.instance.time;
			}
			int projectileIndex = ProjectileCatalog.GetProjectileIndex(fireProjectileInfo.projectilePrefab);
			if (projectileIndex == -1)
			{
				UnityEngine.Debug.LogErrorFormat(fireProjectileInfo.projectilePrefab, "Prefab {0} is not a registered projectile prefab.", fireProjectileInfo.projectilePrefab);
				return;
			}
			bool allowPrediction = ProjectileCatalog.GetProjectilePrefabProjectileControllerComponent(projectileIndex).allowPrediction;
			ushort predictionId = 0;
			if (allowPrediction)
			{
				ProjectileController component = UnityEngine.Object.Instantiate(fireProjectileInfo.projectilePrefab, fireProjectileInfo.position, fireProjectileInfo.rotation).GetComponent<ProjectileController>();
				InitializeProjectile(component, fireProjectileInfo);
				predictionManager.RegisterPrediction(component);
				predictionId = component.predictionId;
			}
			fireMsg.sendTime = fireTime;
			fireMsg.prefabIndexPlusOne = Util.IntToUintPlusOne(projectileIndex);
			fireMsg.position = fireProjectileInfo.position;
			fireMsg.rotation = fireProjectileInfo.rotation;
			fireMsg.owner = fireProjectileInfo.owner;
			fireMsg.predictionId = predictionId;
			fireMsg.damage = fireProjectileInfo.damage;
			fireMsg.force = fireProjectileInfo.force;
			fireMsg.crit = fireProjectileInfo.crit;
			fireMsg.damageColorIndex = fireProjectileInfo.damageColorIndex;
			fireMsg.speedOverride = fireProjectileInfo.speedOverride;
			fireMsg.fuseOverride = fireProjectileInfo.fuseOverride;
			fireMsg.useDamageTypeOverride = fireProjectileInfo.damageTypeOverride.HasValue;
			fireMsg.damageTypeOverride = fireProjectileInfo.damageTypeOverride ?? ((DamageTypeCombo)DamageType.Generic);
			if ((bool)fireProjectileInfo.target)
			{
				HurtBox component2 = fireProjectileInfo.target.GetComponent<HurtBox>();
				fireMsg.target = (component2 ? HurtBoxReference.FromHurtBox(component2) : HurtBoxReference.FromRootObject(fireProjectileInfo.target));
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.StartMessage(49);
			networkWriter.Write(fireMsg);
			networkWriter.FinishMessage();
			client.SendWriter(networkWriter, 0);
		}

		private static void InitializeProjectile(ProjectileController projectileController, FireProjectileInfo fireProjectileInfo)
		{
			GameObject gameObject = projectileController.gameObject;
			ProjectileDamage component = gameObject.GetComponent<ProjectileDamage>();
			TeamFilter component2 = gameObject.GetComponent<TeamFilter>();
			ProjectileNetworkTransform component3 = gameObject.GetComponent<ProjectileNetworkTransform>();
			ProjectileTargetComponent component4 = gameObject.GetComponent<ProjectileTargetComponent>();
			ProjectileSimple component5 = gameObject.GetComponent<ProjectileSimple>();
			projectileController.Networkowner = fireProjectileInfo.owner;
			projectileController.procChainMask = fireProjectileInfo.procChainMask;
			if ((bool)component2)
			{
				component2.teamIndex = TeamComponent.GetObjectTeam(fireProjectileInfo.owner);
			}
			if ((bool)component3)
			{
				component3.SetValuesFromTransform();
			}
			if ((bool)component4 && (bool)fireProjectileInfo.target)
			{
				CharacterBody component6 = fireProjectileInfo.target.GetComponent<CharacterBody>();
				component4.target = (component6 ? component6.coreTransform : fireProjectileInfo.target.transform);
			}
			if (fireProjectileInfo.useSpeedOverride && (bool)component5)
			{
				component5.desiredForwardSpeed = fireProjectileInfo.speedOverride;
			}
			if (fireProjectileInfo.useFuseOverride)
			{
				ProjectileImpactExplosion component7 = gameObject.GetComponent<ProjectileImpactExplosion>();
				if ((bool)component7)
				{
					component7.lifetime = fireProjectileInfo.fuseOverride;
				}
				ProjectileFuse component8 = gameObject.GetComponent<ProjectileFuse>();
				if ((bool)component8)
				{
					component8.fuse = fireProjectileInfo.fuseOverride;
				}
			}
			if ((bool)component)
			{
				component.damage = fireProjectileInfo.damage;
				component.force = fireProjectileInfo.force;
				component.crit = fireProjectileInfo.crit;
				component.damageColorIndex = fireProjectileInfo.damageColorIndex;
				if (fireProjectileInfo.damageTypeOverride.HasValue)
				{
					component.damageType = fireProjectileInfo.damageTypeOverride.Value;
				}
			}
			projectileController.DispatchOnInitialized();
		}

		private void FireProjectileServer(FireProjectileInfo fireProjectileInfo, NetworkConnection clientAuthorityOwner = null, ushort predictionId = 0, double fastForwardTime = 0.0)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(fireProjectileInfo.projectilePrefab, fireProjectileInfo.position, fireProjectileInfo.rotation);
			ProjectileController component = gameObject.GetComponent<ProjectileController>();
			component.NetworkpredictionId = predictionId;
			InitializeProjectile(component, fireProjectileInfo);
			NetworkIdentity component2 = gameObject.GetComponent<NetworkIdentity>();
			if (clientAuthorityOwner != null && component2.localPlayerAuthority)
			{
				NetworkServer.SpawnWithClientAuthority(gameObject, clientAuthorityOwner);
			}
			else
			{
				NetworkServer.Spawn(gameObject);
			}
		}

		public void OnServerProjectileDestroyed(ProjectileController projectile)
		{
			if (projectile.predictionId != 0)
			{
				NetworkConnection clientAuthorityOwner = projectile.clientAuthorityOwner;
				if (clientAuthorityOwner != null)
				{
					ReleasePredictionId(clientAuthorityOwner, projectile.predictionId);
				}
			}
		}

		public void OnClientProjectileReceived(ProjectileController projectile)
		{
			if (projectile.predictionId != 0 && projectile.hasAuthority)
			{
				predictionManager.OnAuthorityProjectileReceived(projectile);
			}
		}

		private void ReleasePredictionId(NetworkConnection owner, ushort predictionId)
		{
			releasePredictionIdMsg.predictionId = predictionId;
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.StartMessage(50);
			networkWriter.Write(releasePredictionIdMsg);
			networkWriter.FinishMessage();
			owner.SendWriter(networkWriter, 0);
		}

		private void HandlePlayerFireProjectileInternal(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(fireMsg);
			GameObject projectilePrefab = ProjectileCatalog.GetProjectilePrefab(Util.UintToIntMinusOne(fireMsg.prefabIndexPlusOne));
			if (projectilePrefab == null)
			{
				ReleasePredictionId(netMsg.conn, fireMsg.predictionId);
				return;
			}
			FireProjectileServer(new FireProjectileInfo
			{
				projectilePrefab = projectilePrefab,
				position = fireMsg.position,
				rotation = fireMsg.rotation,
				owner = fireMsg.owner,
				damage = fireMsg.damage,
				force = fireMsg.force,
				crit = fireMsg.crit,
				target = fireMsg.target.ResolveGameObject(),
				damageColorIndex = fireMsg.damageColorIndex,
				speedOverride = fireMsg.speedOverride,
				fuseOverride = fireMsg.fuseOverride,
				damageTypeOverride = (fireMsg.useDamageTypeOverride ? new DamageTypeCombo?(fireMsg.damageTypeOverride) : null)
			}, netMsg.conn, fireMsg.predictionId, (double)Run.instance.time - fireMsg.sendTime);
		}

		private void HandleReleaseProjectilePredictionIdInternal(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(releasePredictionIdMsg);
			predictionManager.ReleasePredictionId(releasePredictionIdMsg.predictionId);
		}
	}
	public class ProjectileNetworkTransform : NetworkBehaviour
	{
		private ProjectileController projectileController;

		private new Transform transform;

		private Rigidbody rb;

		private InterpolatedTransform interpolatedTransform;

		[Tooltip("The delay in seconds between position network updates.")]
		public float positionTransmitInterval = 1f / 30f;

		[Tooltip("The number of packets of buffers to have.")]
		public float interpolationFactor = 1f;

		public bool allowClientsideCollision;

		public bool checkForLocalPlayerAuthority;

		public int singletonArrayIndex = -1;

		private bool hasEffectiveAuthority;

		[SyncVar(hook = "OnSyncPosition")]
		public UnityEngine.Vector3 serverPosition;

		[SyncVar(hook = "OnSyncRotation")]
		public UnityEngine.Quaternion serverRotation;

		private NetworkLerpedVector3 interpolatedPosition;

		private NetworkLerpedQuaternion interpolatedRotation;

		private bool needsUpdate = true;

		private static int kCmdCmdSetPositionAndRotationFromClient;

		private bool isPrediction
		{
			get
			{
				if (!projectileController)
				{
					return false;
				}
				return projectileController.isPrediction;
			}
		}

		public UnityEngine.Vector3 NetworkserverPosition
		{
			get
			{
				return serverPosition;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncPosition(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref serverPosition, 1u);
			}
		}

		public UnityEngine.Quaternion NetworkserverRotation
		{
			get
			{
				return serverRotation;
			}
			[param: In]
			set
			{
				if (NetworkServer.localClientActive && !base.syncVarHookGuard)
				{
					base.syncVarHookGuard = true;
					OnSyncRotation(value);
					base.syncVarHookGuard = false;
				}
				SetSyncVar(value, ref serverRotation, 2u);
			}
		}

		public void SetValuesFromTransform()
		{
			NetworkserverPosition = transform.position;
			NetworkserverRotation = transform.rotation;
			if (singletonArrayIndex != -1)
			{
				UnityEngine.Debug.LogError("SetValuesFromTransform called without being registered!");
			}
			needsUpdate = true;
		}

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			interpolatedTransform = GetComponent<InterpolatedTransform>();
			transform = base.transform;
			NetworkserverPosition = transform.position;
			NetworkserverRotation = transform.rotation;
			rb = GetComponent<Rigidbody>();
		}

		private void Start()
		{
			interpolatedPosition.interpDelay = GetNetworkSendInterval() * interpolationFactor;
			interpolatedPosition.SetValueImmediate(serverPosition);
			interpolatedRotation.SetValueImmediate(serverRotation);
			if (isPrediction)
			{
				base.enabled = false;
			}
			CheckAuthority();
		}

		private void CheckAuthority()
		{
			if (checkForLocalPlayerAuthority)
			{
				hasEffectiveAuthority = Util.HasEffectiveAuthority(base.gameObject);
			}
			else
			{
				hasEffectiveAuthority = NetworkServer.active;
			}
			if ((bool)rb && !isPrediction && !hasEffectiveAuthority)
			{
				rb.collisionDetectionMode = CollisionDetectionMode.Discrete;
				rb.detectCollisions = allowClientsideCollision;
				rb.isKinematic = true;
			}
			base.OnStartAuthority();
		}

		private void OnSyncPosition(UnityEngine.Vector3 newPosition)
		{
			interpolatedPosition.PushValue(newPosition);
			NetworkserverPosition = newPosition;
		}

		[Command]
		private void CmdSetPositionAndRotationFromClient(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			NetworkserverPosition = position;
			NetworkserverRotation = rotation;
		}

		private void OnSyncRotation(UnityEngine.Quaternion newRotation)
		{
			interpolatedRotation.PushValue(newRotation);
			NetworkserverRotation = newRotation;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public override float GetNetworkSendInterval()
		{
			return positionTransmitInterval;
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.deltaTime);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private bool NeedsUpdate()
		{
			if (needsUpdate)
			{
				return true;
			}
			if (!(serverPosition != transform.position))
			{
				return serverRotation != transform.rotation;
			}
			return true;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void CheckForUpdateAndPushUpdatesIfNeeded()
		{
			if (NeedsUpdate())
			{
				interpolatedPosition.interpDelay = GetNetworkSendInterval() * interpolationFactor;
				Transform obj = transform;
				UnityEngine.Vector3 position = obj.position;
				UnityEngine.Quaternion rotation = obj.rotation;
				NetworkserverPosition = position;
				NetworkserverRotation = rotation;
				interpolatedPosition.SetValueImmediate(position);
				interpolatedRotation.SetValueImmediate(rotation);
				needsUpdate = false;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void CheckForUpdateAndPushUpdatesIfNeededWithCommand()
		{
			if (NeedsUpdate())
			{
				interpolatedPosition.interpDelay = GetNetworkSendInterval() * interpolationFactor;
				Transform obj = transform;
				UnityEngine.Vector3 position = obj.position;
				UnityEngine.Quaternion rotation = obj.rotation;
				CallCmdSetPositionAndRotationFromClient(position, rotation);
				interpolatedPosition.SetValueImmediate(position);
				interpolatedRotation.SetValueImmediate(rotation);
				needsUpdate = false;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void Interpolate()
		{
			UnityEngine.Vector3 currentValue = interpolatedPosition.GetCurrentValue(hasAuthority: false);
			UnityEngine.Quaternion currentValue2 = interpolatedRotation.GetCurrentValue(hasAuthority: false);
			ApplyPositionAndRotation(currentValue, currentValue2);
		}

		private void MyFixedUpdate(float deltaTime)
		{
			if (checkForLocalPlayerAuthority)
			{
				if (hasEffectiveAuthority)
				{
					CheckForUpdateAndPushUpdatesIfNeededWithCommand();
				}
				else
				{
					Interpolate();
				}
			}
			else if (base.isServer)
			{
				CheckForUpdateAndPushUpdatesIfNeeded();
			}
			else
			{
				Interpolate();
			}
		}

		private void ApplyPositionAndRotation(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			if ((bool)rb && !interpolatedTransform)
			{
				rb.MovePosition(position);
				rb.MoveRotation(rotation);
			}
			else
			{
				transform.position = position;
				transform.rotation = rotation;
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdSetPositionAndRotationFromClient(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetPositionAndRotationFromClient called on client.");
			}
			else
			{
				((ProjectileNetworkTransform)obj).CmdSetPositionAndRotationFromClient(reader.ReadVector3(), reader.ReadQuaternion());
			}
		}

		public void CallCmdSetPositionAndRotationFromClient(UnityEngine.Vector3 position, UnityEngine.Quaternion rotation)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetPositionAndRotationFromClient called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetPositionAndRotationFromClient(position, rotation);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetPositionAndRotationFromClient);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.Write(position);
			networkWriter.Write(rotation);
			SendCommandInternal(networkWriter, 0, "CmdSetPositionAndRotationFromClient");
		}

		static ProjectileNetworkTransform()
		{
			kCmdCmdSetPositionAndRotationFromClient = -895512346;
			NetworkBehaviour.RegisterCommandDelegate(typeof(ProjectileNetworkTransform), kCmdCmdSetPositionAndRotationFromClient, InvokeCmdCmdSetPositionAndRotationFromClient);
			NetworkCRC.RegisterBehaviour("ProjectileNetworkTransform", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(serverPosition);
				writer.Write(serverRotation);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(serverPosition);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(serverRotation);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				serverPosition = reader.ReadVector3();
				serverRotation = reader.ReadQuaternion();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				OnSyncPosition(reader.ReadVector3());
			}
			if (((uint)num & 2u) != 0)
			{
				OnSyncRotation(reader.ReadQuaternion());
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(ProjectileDamage))]
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(HitBoxGroup))]
	public class ProjectileOverlapAttack : MonoBehaviour, IProjectileImpactBehavior
	{
		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		public float damageCoefficient;

		public GameObject impactEffect;

		public UnityEngine.Vector3 forceVector;

		public float overlapProcCoefficient = 1f;

		public int maximumOverlapTargets = 100;

		public UnityEvent onServerHit;

		private OverlapAttack attack;

		public float fireFrequency = 60f;

		[Tooltip("If non-negative, the attack clears its hit memory at the specified interval.")]
		public float resetInterval = -1f;

		private float resetTimer;

		public bool requireDelayOnePhysicsFrame;

		[Header("Velocity Scaling")]
		public bool ScaleWithVelocity;

		public Rigidbody ScaleVelocitySource;

		private UnityEngine.Vector3[] HitboxOriginalScales;

		private Transform[] HitboxTransforms;

		public UnityEngine.Vector3 ScaleWithVelocityAxis = new UnityEngine.Vector3(0f, 0f, 1f);

		private float fireTimer;

		private void Start()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			attack = new OverlapAttack();
			attack.procChainMask = projectileController.procChainMask;
			attack.procCoefficient = projectileController.procCoefficient * overlapProcCoefficient;
			attack.attacker = projectileController.owner;
			attack.inflictor = base.gameObject;
			attack.teamIndex = projectileController.teamFilter.teamIndex;
			attack.damage = damageCoefficient * projectileDamage.damage;
			attack.forceVector = forceVector + projectileDamage.force * base.transform.forward;
			attack.hitEffectPrefab = impactEffect;
			attack.isCrit = projectileDamage.crit;
			attack.damageColorIndex = projectileDamage.damageColorIndex;
			attack.damageType = projectileDamage.damageType;
			attack.procChainMask = projectileController.procChainMask;
			attack.maximumOverlapTargets = maximumOverlapTargets;
			attack.hitBoxGroup = GetComponent<HitBoxGroup>();
			int num = attack.hitBoxGroup.hitBoxes.Length;
			HitboxOriginalScales = new UnityEngine.Vector3[num];
			HitboxTransforms = new Transform[num];
			for (int i = 0; i < num; i++)
			{
				HitboxTransforms[i] = attack.hitBoxGroup.hitBoxes[i].transform;
				HitboxOriginalScales[i] = HitboxTransforms[i].localScale;
			}
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.fixedDeltaTime);
		}

		public void MyFixedUpdate(float deltaTime)
		{
			if (!((!(projectileController != null)) ? NetworkServer.active : projectileController.CanProcessCollisionEvents()))
			{
				return;
			}
			if (resetInterval >= 0f)
			{
				resetTimer -= deltaTime;
				if (resetTimer <= 0f)
				{
					resetTimer = resetInterval;
					ResetOverlapAttack();
				}
			}
			fireTimer -= deltaTime;
			if (!(fireTimer <= 0f))
			{
				return;
			}
			if (ScaleWithVelocity)
			{
				float num = 1f / fireFrequency - fireTimer;
				if (num > 0f)
				{
					float num2 = num * ScaleVelocitySource.velocity.magnitude;
					UnityEngine.Vector3 rhs = ScaleWithVelocityAxis * num2;
					int num3 = HitboxTransforms.Length;
					for (int i = 0; i < num3; i++)
					{
						HitboxTransforms[i].localScale = UnityEngine.Vector3.Max(HitboxOriginalScales[i], rhs);
					}
				}
			}
			fireTimer = 1f / fireFrequency;
			attack.damage = damageCoefficient * projectileDamage.damage;
			if (attack.Fire())
			{
				onServerHit?.Invoke();
			}
		}

		public void ResetOverlapAttack()
		{
			attack.damageType = projectileDamage.damageType;
			attack.ResetIgnoredHealthComponents();
		}

		public void SetDamageCoefficient(float newDamageCoefficient)
		{
			damageCoefficient = newDamageCoefficient;
		}

		public void AddToDamageCoefficient(float bonusDamageCoefficient)
		{
			damageCoefficient += bonusDamageCoefficient;
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileOverlapAttack))]
	public class ProjectileOverlapLimitHits : NetworkBehaviour
	{
		[Tooltip("How many hits this projectile can make before it will destroy itself.")]
		[SerializeField]
		public int hitLimit;

		[Tooltip("Announce in the console when the hit limit has been reached")]
		[SerializeField]
		private bool debugMessages;

		private ProjectileOverlapAttack projectileOverlapAttack;

		[Tooltip("Run when the projectile has one hit remaining.")]
		[SerializeField]
		public UnityEvent OnOneHitRemaining;

		private int hitCount;

		private static int kCmdCmdLastHit;

		private static int kRpcRpcLastHit;

		private void Awake()
		{
			projectileOverlapAttack = GetComponent<ProjectileOverlapAttack>();
			_ = projectileOverlapAttack == null;
		}

		private void OnEnable()
		{
			projectileOverlapAttack.onServerHit.AddListener(CountOverlapHits);
		}

		private void CountOverlapHits()
		{
			hitCount++;
			if (hitCount == hitLimit - 1)
			{
				HandleNetworkedLastHit();
			}
			if (hitCount >= hitLimit)
			{
				DestroyProjectile();
			}
		}

		private void HandleNetworkedLastHit()
		{
			if (NetworkServer.active)
			{
				CallRpcLastHit();
			}
			else
			{
				CallCmdLastHit();
			}
		}

		[Command]
		private void CmdLastHit()
		{
			CallRpcLastHit();
		}

		[ClientRpc]
		private void RpcLastHit()
		{
			OnOneHitRemaining?.Invoke();
		}

		public bool IsLastHit()
		{
			return hitCount == hitLimit - 1;
		}

		private void DestroyProjectile()
		{
			if (NetworkServer.active)
			{
				_ = debugMessages;
				EffectManagerHelper component = GetComponent<EffectManagerHelper>();
				if ((bool)component && component.OwningPool != null)
				{
					component.OwningPool.ReturnObject(component);
				}
				else
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}

		private void OnDisable()
		{
			if (NetworkServer.active)
			{
				projectileOverlapAttack.onServerHit.RemoveListener(CountOverlapHits);
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdLastHit(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdLastHit called on client.");
			}
			else
			{
				((ProjectileOverlapLimitHits)obj).CmdLastHit();
			}
		}

		public void CallCmdLastHit()
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdLastHit called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdLastHit();
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdLastHit);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendCommandInternal(networkWriter, 0, "CmdLastHit");
		}

		protected static void InvokeRpcRpcLastHit(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcLastHit called on server.");
			}
			else
			{
				((ProjectileOverlapLimitHits)obj).RpcLastHit();
			}
		}

		public void CallRpcLastHit()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcLastHit called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcLastHit);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			SendRPCInternal(networkWriter, 0, "RpcLastHit");
		}

		static ProjectileOverlapLimitHits()
		{
			kCmdCmdLastHit = 809020640;
			NetworkBehaviour.RegisterCommandDelegate(typeof(ProjectileOverlapLimitHits), kCmdCmdLastHit, InvokeCmdCmdLastHit);
			kRpcRpcLastHit = -716657590;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ProjectileOverlapLimitHits), kRpcRpcLastHit, InvokeRpcRpcLastHit);
			NetworkCRC.RegisterBehaviour("ProjectileOverlapLimitHits", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[DisallowMultipleComponent]
	public class ProjectileOwnerOrbiter : NetworkBehaviour
	{
		[SyncVar]
		[SerializeField]
		private UnityEngine.Vector3 offset;

		[SyncVar]
		[SerializeField]
		private float initialDegreesFromOwnerForward;

		[SerializeField]
		[SyncVar]
		private float degreesPerSecond;

		[SyncVar]
		[SerializeField]
		public float radius;

		[SyncVar]
		[SerializeField]
		private UnityEngine.Vector3 planeNormal = UnityEngine.Vector3.up;

		private Transform ownerTransform;

		private Rigidbody rigidBody;

		private bool resetOnAcquireOwner = true;

		[SyncVar]
		private UnityEngine.Vector3 initialRadialDirection;

		[SyncVar]
		private float initialRunTime;

		public UnityEngine.Vector3 Networkoffset
		{
			get
			{
				return offset;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref offset, 1u);
			}
		}

		public float NetworkinitialDegreesFromOwnerForward
		{
			get
			{
				return initialDegreesFromOwnerForward;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref initialDegreesFromOwnerForward, 2u);
			}
		}

		public float NetworkdegreesPerSecond
		{
			get
			{
				return degreesPerSecond;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref degreesPerSecond, 4u);
			}
		}

		public float Networkradius
		{
			get
			{
				return radius;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref radius, 8u);
			}
		}

		public UnityEngine.Vector3 NetworkplaneNormal
		{
			get
			{
				return planeNormal;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref planeNormal, 16u);
			}
		}

		public UnityEngine.Vector3 NetworkinitialRadialDirection
		{
			get
			{
				return initialRadialDirection;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref initialRadialDirection, 32u);
			}
		}

		public float NetworkinitialRunTime
		{
			get
			{
				return initialRunTime;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref initialRunTime, 64u);
			}
		}

		public void Initialize(UnityEngine.Vector3 planeNormal, float radius, float degreesPerSecond, float initialDegreesFromOwnerForward)
		{
			NetworkplaneNormal = planeNormal;
			Networkradius = radius;
			NetworkdegreesPerSecond = degreesPerSecond;
			NetworkinitialDegreesFromOwnerForward = initialDegreesFromOwnerForward;
			ResetState();
		}

		private void OnEnable()
		{
			rigidBody = GetComponent<Rigidbody>();
			ProjectileController component = GetComponent<ProjectileController>();
			if ((bool)component.owner)
			{
				AcquireOwner(component);
			}
			else
			{
				component.onInitialized += AcquireOwner;
			}
		}

		public void FixedUpdate()
		{
			UpdatePosition(doSnap: false);
		}

		private void ResetState()
		{
			NetworkinitialRunTime = Time.fixedTime;
			planeNormal.Normalize();
			if ((bool)ownerTransform)
			{
				NetworkinitialRadialDirection = UnityEngine.Quaternion.AngleAxis(initialDegreesFromOwnerForward, planeNormal) * ownerTransform.forward;
				resetOnAcquireOwner = false;
			}
			UpdatePosition(doSnap: true);
		}

		private void UpdatePosition(bool doSnap)
		{
			if ((bool)ownerTransform)
			{
				float angle = (Time.fixedTime - initialRunTime) * degreesPerSecond;
				UnityEngine.Vector3 position = ownerTransform.position + offset + UnityEngine.Quaternion.AngleAxis(angle, planeNormal) * initialRadialDirection * radius;
				if (!rigidBody || doSnap)
				{
					base.transform.position = position;
				}
				else if ((bool)rigidBody)
				{
					rigidBody.MovePosition(position);
				}
			}
		}

		public void SetInitialDegreesFromOwnerForward(float degrees)
		{
			NetworkinitialDegreesFromOwnerForward = degrees;
			if ((bool)ownerTransform)
			{
				NetworkinitialRadialDirection = UnityEngine.Quaternion.AngleAxis(initialDegreesFromOwnerForward, planeNormal) * ownerTransform.forward;
			}
		}

		public float GetInitialRunTime()
		{
			return initialRunTime;
		}

		public void SetInitialRunTime(float _time)
		{
			NetworkinitialRunTime = Mathf.Max(_time, 0f);
		}

		private void AcquireOwner(ProjectileController controller)
		{
			ownerTransform = controller.owner.transform;
			controller.onInitialized -= AcquireOwner;
			if (resetOnAcquireOwner)
			{
				resetOnAcquireOwner = false;
				ResetState();
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(offset);
				writer.Write(initialDegreesFromOwnerForward);
				writer.Write(degreesPerSecond);
				writer.Write(radius);
				writer.Write(planeNormal);
				writer.Write(initialRadialDirection);
				writer.Write(initialRunTime);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(offset);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(initialDegreesFromOwnerForward);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(degreesPerSecond);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(radius);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(planeNormal);
			}
			if ((base.syncVarDirtyBits & 0x20u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(initialRadialDirection);
			}
			if ((base.syncVarDirtyBits & 0x40u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(initialRunTime);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				offset = reader.ReadVector3();
				initialDegreesFromOwnerForward = reader.ReadSingle();
				degreesPerSecond = reader.ReadSingle();
				radius = reader.ReadSingle();
				planeNormal = reader.ReadVector3();
				initialRadialDirection = reader.ReadVector3();
				initialRunTime = reader.ReadSingle();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				offset = reader.ReadVector3();
			}
			if (((uint)num & 2u) != 0)
			{
				initialDegreesFromOwnerForward = reader.ReadSingle();
			}
			if (((uint)num & 4u) != 0)
			{
				degreesPerSecond = reader.ReadSingle();
			}
			if (((uint)num & 8u) != 0)
			{
				radius = reader.ReadSingle();
			}
			if (((uint)num & 0x10u) != 0)
			{
				planeNormal = reader.ReadVector3();
			}
			if (((uint)num & 0x20u) != 0)
			{
				initialRadialDirection = reader.ReadVector3();
			}
			if (((uint)num & 0x40u) != 0)
			{
				initialRunTime = reader.ReadSingle();
			}
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(ProjectileDamage))]
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileParentTether : MonoBehaviour
	{
		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private TeamIndex myTeamIndex;

		public float attackInterval = 1f;

		public float maxTetherRange = 20f;

		public float procCoefficient = 0.1f;

		public float damageCoefficient = 1f;

		public float raycastRadius;

		public float lifetime;

		public GameObject impactEffect;

		public GameObject tetherEffectPrefab;

		public ProjectileStickOnImpact stickOnImpact;

		private GameObject tetherEffectInstance;

		private GameObject tetherEffectInstanceEnd;

		private float attackTimer;

		private float lifetimeStopwatch;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			attackTimer = 0f;
			UpdateTetherGraphic();
		}

		private void UpdateTetherGraphic()
		{
			if (ShouldIFire())
			{
				if ((bool)tetherEffectPrefab && !tetherEffectInstance)
				{
					tetherEffectInstance = UnityEngine.Object.Instantiate(tetherEffectPrefab, base.transform.position, base.transform.rotation);
					tetherEffectInstance.transform.parent = base.transform;
					ChildLocator component = tetherEffectInstance.GetComponent<ChildLocator>();
					tetherEffectInstanceEnd = component.FindChild("LaserEnd").gameObject;
				}
				if ((bool)tetherEffectInstance)
				{
					Ray aimRay = GetAimRay();
					tetherEffectInstance.transform.rotation = Util.QuaternionSafeLookRotation(aimRay.direction);
					tetherEffectInstanceEnd.transform.position = aimRay.origin + aimRay.direction * GetRayDistance();
				}
			}
		}

		private float GetRayDistance()
		{
			if ((bool)projectileController.owner)
			{
				return (projectileController.owner.transform.position - base.transform.position).magnitude;
			}
			return 0f;
		}

		private Ray GetAimRay()
		{
			Ray result = default(Ray);
			result.origin = base.transform.position;
			result.direction = projectileController.owner.transform.position - result.origin;
			return result;
		}

		private bool ShouldIFire()
		{
			if ((bool)stickOnImpact)
			{
				return stickOnImpact.stuck;
			}
			return true;
		}

		private void Update()
		{
			UpdateTetherGraphic();
		}

		private void FixedUpdate()
		{
			if (ShouldIFire())
			{
				lifetimeStopwatch += Time.fixedDeltaTime;
			}
			if (lifetimeStopwatch > lifetime)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			if (!projectileController.owner.transform || !ShouldIFire())
			{
				return;
			}
			myTeamIndex = (projectileController.teamFilter ? projectileController.teamFilter.teamIndex : TeamIndex.Neutral);
			attackTimer -= Time.fixedDeltaTime;
			if (attackTimer <= 0f)
			{
				Ray aimRay = GetAimRay();
				attackTimer = attackInterval;
				if (aimRay.direction.magnitude < maxTetherRange && NetworkServer.active)
				{
					BulletAttack bulletAttack = new BulletAttack();
					bulletAttack.owner = projectileController.owner;
					bulletAttack.origin = aimRay.origin;
					bulletAttack.aimVector = aimRay.direction;
					bulletAttack.minSpread = 0f;
					bulletAttack.damage = damageCoefficient * projectileDamage.damage;
					bulletAttack.force = 0f;
					bulletAttack.hitEffectPrefab = impactEffect;
					bulletAttack.isCrit = projectileDamage.crit;
					bulletAttack.radius = raycastRadius;
					bulletAttack.falloffModel = BulletAttack.FalloffModel.None;
					bulletAttack.stopperMask = 0;
					bulletAttack.hitMask = LayerIndex.entityPrecise.mask;
					bulletAttack.procCoefficient = procCoefficient;
					bulletAttack.maxDistance = GetRayDistance();
					bulletAttack.Fire();
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileDamage))]
	public class ProjectileProximityBeamController : MonoBehaviour
	{
		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private List<HealthComponent> previousTargets;

		private TeamFilter teamFilter;

		public int attackFireCount = 1;

		public float attackInterval = 1f;

		public float listClearInterval = 3f;

		public float attackRange = 20f;

		[Range(0f, 180f)]
		public float minAngleFilter;

		[Range(0f, 180f)]
		public float maxAngleFilter = 180f;

		public float procCoefficient = 0.1f;

		public float damageCoefficient = 1f;

		public int bounces;

		public bool inheritDamageType;

		public LightningOrb.LightningType lightningType = LightningOrb.LightningType.BFG;

		private float attackTimer;

		private float listClearTimer;

		private BullseyeSearch search;

		private TeamIndex myTeamIndex
		{
			get
			{
				if (!teamFilter)
				{
					return TeamIndex.Neutral;
				}
				return teamFilter.teamIndex;
			}
		}

		private void Awake()
		{
			if (NetworkServer.active)
			{
				projectileController = GetComponent<ProjectileController>();
				teamFilter = projectileController.teamFilter;
				projectileDamage = GetComponent<ProjectileDamage>();
				attackTimer = 0f;
				previousTargets = new List<HealthComponent>();
				search = new BullseyeSearch();
			}
			else
			{
				base.enabled = false;
			}
		}

		private void ClearList()
		{
			previousTargets.Clear();
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				UpdateServer();
			}
			else
			{
				base.enabled = false;
			}
		}

		private void UpdateServer()
		{
			listClearTimer -= Time.fixedDeltaTime;
			if (listClearTimer <= 0f)
			{
				ClearList();
				listClearTimer = listClearInterval;
			}
			attackTimer -= Time.fixedDeltaTime;
			if (!(attackTimer <= 0f))
			{
				return;
			}
			attackTimer += attackInterval;
			UnityEngine.Vector3 position = base.transform.position;
			UnityEngine.Vector3 forward = base.transform.forward;
			for (int i = 0; i < attackFireCount; i++)
			{
				HurtBox hurtBox = FindNextTarget(position, forward);
				if ((bool)hurtBox)
				{
					previousTargets.Add(hurtBox.healthComponent);
					LightningOrb lightningOrb = new LightningOrb();
					lightningOrb.bouncedObjects = new List<HealthComponent>();
					lightningOrb.attacker = projectileController.owner;
					lightningOrb.inflictor = base.gameObject;
					lightningOrb.teamIndex = myTeamIndex;
					lightningOrb.damageValue = projectileDamage.damage * damageCoefficient;
					lightningOrb.isCrit = projectileDamage.crit;
					lightningOrb.origin = position;
					lightningOrb.bouncesRemaining = bounces;
					lightningOrb.lightningType = lightningType;
					lightningOrb.procCoefficient = procCoefficient;
					lightningOrb.target = hurtBox;
					lightningOrb.damageColorIndex = projectileDamage.damageColorIndex;
					if (inheritDamageType)
					{
						lightningOrb.damageType = projectileDamage.damageType;
					}
					OrbManager.instance.AddOrb(lightningOrb);
				}
			}
		}

		public HurtBox FindNextTarget(UnityEngine.Vector3 position, UnityEngine.Vector3 forward)
		{
			search.searchOrigin = position;
			search.searchDirection = forward;
			search.sortMode = BullseyeSearch.SortMode.Distance;
			search.teamMaskFilter = TeamMask.allButNeutral;
			search.teamMaskFilter.RemoveTeam(myTeamIndex);
			search.filterByLoS = false;
			search.minAngleFilter = minAngleFilter;
			search.maxAngleFilter = maxAngleFilter;
			search.maxDistanceFilter = attackRange;
			search.RefreshCandidates();
			return search.GetResults().FirstOrDefault((HurtBox hurtBox) => !previousTargets.Contains(hurtBox.healthComponent));
		}
	}
	public class ProjectileSimple : MonoBehaviour
	{
		[Header("Lifetime")]
		public float lifetime = 5f;

		public GameObject lifetimeExpiredEffect;

		[FormerlySerializedAs("velocity")]
		[Header("Velocity")]
		public float desiredForwardSpeed;

		public bool updateAfterFiring;

		public bool enableVelocityOverLifetime;

		public AnimationCurve velocityOverLifetime;

		[Header("Oscillation")]
		public bool oscillate;

		public float oscillateMagnitude = 20f;

		public float oscillateSpeed;

		private float deltaHeight;

		private float oscillationStopwatch;

		private float stopwatch;

		private Rigidbody rigidbody;

		private new Transform transform;

		[Obsolete("Use 'desiredForwardSpeed' instead.", false)]
		public float velocity
		{
			get
			{
				return desiredForwardSpeed;
			}
			set
			{
				desiredForwardSpeed = value;
			}
		}

		protected void Awake()
		{
			transform = base.transform;
			rigidbody = GetComponent<Rigidbody>();
		}

		protected void OnEnable()
		{
			SetForwardSpeed(desiredForwardSpeed);
		}

		protected void Start()
		{
			SetForwardSpeed(desiredForwardSpeed);
		}

		protected void OnDisable()
		{
			SetForwardSpeed(0f);
		}

		protected void FixedUpdate()
		{
			if (oscillate)
			{
				deltaHeight = Mathf.Sin(oscillationStopwatch * oscillateSpeed);
			}
			if (updateAfterFiring || enableVelocityOverLifetime)
			{
				SetForwardSpeed(desiredForwardSpeed);
			}
			oscillationStopwatch += Time.deltaTime;
			stopwatch += Time.deltaTime;
			if (NetworkServer.active && stopwatch > lifetime)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				if ((bool)lifetimeExpiredEffect && NetworkServer.active)
				{
					EffectManager.SimpleEffect(lifetimeExpiredEffect, transform.position, transform.rotation, transmit: true);
				}
			}
		}

		public void SetLifetime(float newLifetime)
		{
			lifetime = newLifetime;
			stopwatch = 0f;
		}

		protected void SetForwardSpeed(float speed)
		{
			if ((bool)rigidbody)
			{
				if (enableVelocityOverLifetime)
				{
					rigidbody.velocity = speed * velocityOverLifetime.Evaluate(stopwatch / lifetime) * transform.forward;
				}
				else
				{
					rigidbody.velocity = transform.forward * speed + transform.right * (deltaHeight * oscillateMagnitude);
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileSingleTargetImpact : MonoBehaviour, IProjectileImpactBehavior
	{
		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private bool alive = true;

		public bool destroyWhenNotAlive = true;

		public bool destroyOnWorld;

		public GameObject impactEffect;

		public string hitSoundString;

		public string enemyHitSoundString;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (!alive)
			{
				return;
			}
			Collider collider = impactInfo.collider;
			if ((bool)collider)
			{
				DamageInfo damageInfo = new DamageInfo();
				if ((bool)projectileDamage)
				{
					damageInfo.damage = projectileDamage.damage;
					damageInfo.crit = projectileDamage.crit;
					damageInfo.attacker = projectileController.owner;
					damageInfo.inflictor = base.gameObject;
					damageInfo.position = impactInfo.estimatedPointOfImpact;
					damageInfo.force = projectileDamage.force * base.transform.forward;
					damageInfo.procChainMask = projectileController.procChainMask;
					damageInfo.procCoefficient = projectileController.procCoefficient;
					damageInfo.damageColorIndex = projectileDamage.damageColorIndex;
					damageInfo.damageType = projectileDamage.damageType;
				}
				HurtBox component = collider.GetComponent<HurtBox>();
				if ((bool)component)
				{
					HealthComponent healthComponent = component.healthComponent;
					if ((bool)healthComponent)
					{
						if (healthComponent.gameObject == projectileController.owner)
						{
							return;
						}
						if (FriendlyFireManager.ShouldDirectHitProceed(healthComponent, projectileController.teamFilter.teamIndex))
						{
							Util.PlaySound(enemyHitSoundString, base.gameObject);
							if (NetworkServer.active)
							{
								damageInfo.ModifyDamageInfo(component.damageModifier);
								healthComponent.TakeDamage(damageInfo);
								GlobalEventManager.instance.OnHitEnemy(damageInfo, component.healthComponent.gameObject);
							}
						}
						alive = false;
					}
				}
				else if (destroyOnWorld)
				{
					alive = false;
				}
				damageInfo.position = base.transform.position;
				if (NetworkServer.active)
				{
					GlobalEventManager.instance.OnHitAll(damageInfo, collider.gameObject);
				}
			}
			if (!alive)
			{
				if (NetworkServer.active && (bool)impactEffect)
				{
					EffectManager.SimpleImpactEffect(impactEffect, impactInfo.estimatedPointOfImpact, -base.transform.forward, !projectileController.isPrediction);
				}
				Util.PlaySound(hitSoundString, base.gameObject);
				if (destroyWhenNotAlive)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileSpawnMaster : MonoBehaviour, IProjectileImpactBehavior
	{
		[SerializeField]
		private float maxLifetime = 10f;

		[SerializeField]
		private CharacterSpawnCard spawnCard;

		[SerializeField]
		public DeployableSlot deployableSlot = DeployableSlot.None;

		private float stopwatch;

		private bool isAlive = true;

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (isAlive)
			{
				SpawnMaster();
				isAlive = false;
			}
		}

		protected void FixedUpdate()
		{
			stopwatch += Time.fixedDeltaTime;
			if (NetworkServer.active && (!isAlive || stopwatch > maxLifetime))
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		public void SpawnMaster()
		{
			ProjectileController component = GetComponent<ProjectileController>();
			if (!component || !component.owner)
			{
				return;
			}
			CharacterBody component2 = component.owner.GetComponent<CharacterBody>();
			if (!component2 || !component2.master || !spawnCard)
			{
				return;
			}
			CharacterMaster characterMaster = component2.master;
			if (!characterMaster || (deployableSlot != DeployableSlot.None && characterMaster.IsDeployableLimited(deployableSlot)))
			{
				return;
			}
			Transform spawnOnTarget = base.transform;
			DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule
			{
				spawnOnTarget = spawnOnTarget,
				placementMode = DirectorPlacementRule.PlacementMode.Direct
			};
			DirectorCore.GetMonsterSpawnDistance(DirectorCore.MonsterSpawnDistance.Close, out directorPlacementRule.minDistance, out directorPlacementRule.maxDistance);
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, directorPlacementRule, new Xoroshiro128Plus(Run.instance.seed + (ulong)Run.instance.fixedTime));
			directorSpawnRequest.teamIndexOverride = characterMaster.teamIndex;
			directorSpawnRequest.ignoreTeamMemberLimit = false;
			directorSpawnRequest.summonerBodyObject = component.owner;
			if (deployableSlot != DeployableSlot.None)
			{
				directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult result)
				{
					if (result.success && (bool)result.spawnedInstance)
					{
						result.spawnedInstance.GetComponent<CharacterMaster>();
						Deployable deployable = result.spawnedInstance.AddComponent<Deployable>();
						characterMaster.AddDeployable(deployable, deployableSlot);
					}
				});
			}
			DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
		}
	}
	[RequireComponent(typeof(ProjectileTargetComponent))]
	[RequireComponent(typeof(TeamFilter))]
	public class ProjectileSphereTargetFinder : MonoBehaviour
	{
		[Tooltip("How far ahead the projectile should look to find a target.")]
		public float lookRange;

		[Tooltip("How long before searching for a target.")]
		public float targetSearchInterval = 0.5f;

		[Tooltip("Will not search for new targets once it has one.")]
		public bool onlySearchIfNoTarget;

		[Tooltip("Allows the target to be lost if it's outside the acceptable range.")]
		public bool allowTargetLoss;

		[Tooltip("If set, targets can only be found when there is a free line of sight.")]
		public bool testLoS;

		[Tooltip("Whether or not airborne characters should be ignored.")]
		public bool ignoreAir;

		[Tooltip("The difference in altitude at which a result will be ignored.")]
		[FormerlySerializedAs("altitudeTolerance")]
		public float flierAltitudeTolerance = float.PositiveInfinity;

		public UnityEvent onNewTargetFound;

		public UnityEvent onTargetLost;

		private new Transform transform;

		private TeamFilter teamFilter;

		private ProjectileTargetComponent targetComponent;

		private float searchTimer;

		private SphereSearch sphereSearch;

		private bool hasTarget;

		private bool hadTargetLastUpdate;

		private HurtBox lastFoundHurtBox;

		private Transform lastFoundTransform;

		private static readonly List<HurtBox> foundHurtBoxes = new List<HurtBox>();

		private void Start()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
				return;
			}
			transform = base.transform;
			teamFilter = GetComponent<TeamFilter>();
			targetComponent = GetComponent<ProjectileTargetComponent>();
			sphereSearch = new SphereSearch();
			searchTimer = 0f;
		}

		private void FixedUpdate()
		{
			searchTimer -= Time.fixedDeltaTime;
			if (!(searchTimer <= 0f))
			{
				return;
			}
			searchTimer += targetSearchInterval;
			if (allowTargetLoss && (object)targetComponent.target != null && (object)lastFoundTransform == targetComponent.target && !PassesFilters(lastFoundHurtBox))
			{
				SetTarget(null);
			}
			if (!onlySearchIfNoTarget || targetComponent.target == null)
			{
				SearchForTarget();
			}
			hasTarget = targetComponent.target != null;
			if (hadTargetLastUpdate != hasTarget)
			{
				if (hasTarget)
				{
					onNewTargetFound?.Invoke();
				}
				else
				{
					onTargetLost?.Invoke();
				}
			}
			hadTargetLastUpdate = hasTarget;
		}

		private bool PassesFilters(HurtBox result)
		{
			CharacterBody body = result.healthComponent.body;
			if (!body || (ignoreAir && body.isFlying))
			{
				return false;
			}
			if (body.isFlying && !float.IsInfinity(flierAltitudeTolerance) && flierAltitudeTolerance < Mathf.Abs(result.transform.position.y - transform.position.y))
			{
				return false;
			}
			return true;
		}

		private void SearchForTarget()
		{
			sphereSearch.origin = transform.position;
			sphereSearch.radius = lookRange;
			sphereSearch.mask = LayerIndex.entityPrecise.mask;
			sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
			sphereSearch.RefreshCandidates();
			sphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamFilter.teamIndex));
			sphereSearch.OrderCandidatesByDistance();
			sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
			sphereSearch.GetHurtBoxes(foundHurtBoxes);
			HurtBox target = null;
			if (foundHurtBoxes.Count > 0)
			{
				int i = 0;
				for (int count = foundHurtBoxes.Count; i < count; i++)
				{
					if (PassesFilters(foundHurtBoxes[i]))
					{
						target = foundHurtBoxes[i];
						break;
					}
				}
				foundHurtBoxes.Clear();
			}
			SetTarget(target);
		}

		private void SetTarget(HurtBox hurtBox)
		{
			lastFoundHurtBox = hurtBox;
			lastFoundTransform = hurtBox?.transform;
			targetComponent.target = lastFoundTransform;
		}

		private void OnDrawGizmosSelected()
		{
			Gizmos.color = UnityEngine.Color.yellow;
			UnityEngine.Vector3 position = base.transform.position;
			Gizmos.DrawWireSphere(position, lookRange);
			if (!float.IsInfinity(flierAltitudeTolerance))
			{
				Gizmos.DrawWireCube(position, new UnityEngine.Vector3(lookRange * 2f, flierAltitudeTolerance * 2f, lookRange * 2f));
			}
		}
	}
	[RequireComponent(typeof(Rigidbody))]
	[RequireComponent(typeof(ProjectileController))]
	[DefaultExecutionOrder(-1)]
	[RequireComponent(typeof(ProjectileNetworkTransform))]
	public class ProjectileStickOnImpact : NetworkBehaviour, IProjectileImpactBehavior
	{
		public string stickSoundString;

		public ParticleSystem[] stickParticleSystem;

		public bool ignoreCharacters;

		public bool ignoreWorld;

		public bool alignNormals = true;

		public UnityEvent stickEvent;

		private ProjectileController projectileController;

		private Rigidbody rigidbody;

		private bool wasEverEnabled;

		private GameObject _victim;

		[SyncVar]
		private GameObject syncVictim;

		[SyncVar]
		private sbyte hitHurtboxIndex = -1;

		[SyncVar]
		private UnityEngine.Vector3 localPosition;

		[SyncVar]
		private UnityEngine.Quaternion localRotation;

		[SyncVar]
		private bool runStickEvent;

		private bool alreadyRanStickEvent;

		private NetworkInstanceId ___syncVictimNetId;

		public Transform stuckTransform { get; private set; }

		public CharacterBody stuckBody { get; private set; }

		public GameObject victim
		{
			get
			{
				return _victim;
			}
			private set
			{
				_victim = value;
				NetworksyncVictim = value;
			}
		}

		public bool stuck => hitHurtboxIndex != -1;

		public GameObject NetworksyncVictim
		{
			get
			{
				return syncVictim;
			}
			[param: In]
			set
			{
				SetSyncVarGameObject(value, ref syncVictim, 1u, ref ___syncVictimNetId);
			}
		}

		public sbyte NetworkhitHurtboxIndex
		{
			get
			{
				return hitHurtboxIndex;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref hitHurtboxIndex, 2u);
			}
		}

		public UnityEngine.Vector3 NetworklocalPosition
		{
			get
			{
				return localPosition;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref localPosition, 4u);
			}
		}

		public UnityEngine.Quaternion NetworklocalRotation
		{
			get
			{
				return localRotation;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref localRotation, 8u);
			}
		}

		public bool NetworkrunStickEvent
		{
			get
			{
				return runStickEvent;
			}
			[param: In]
			set
			{
				SetSyncVar(value, ref runStickEvent, 16u);
			}
		}

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
			rigidbody = GetComponent<Rigidbody>();
		}

		private void OnEnable()
		{
			if (wasEverEnabled)
			{
				Collider component = GetComponent<Collider>();
				component.enabled = false;
				component.enabled = true;
			}
			wasEverEnabled = true;
		}

		private void OnDisable()
		{
			if (NetworkServer.active)
			{
				Detach();
			}
		}

		[Server]
		public void Detach()
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.Projectile.ProjectileStickOnImpact::Detach()' called on client");
				return;
			}
			victim = null;
			stuckTransform = null;
			NetworkhitHurtboxIndex = -1;
			UpdateSticking();
		}

		public void OnProjectileImpact(ProjectileImpactInfo impactInfo)
		{
			if (base.enabled)
			{
				TrySticking(impactInfo.collider, impactInfo.estimatedImpactNormal);
			}
		}

		private bool TrySticking(Collider hitCollider, UnityEngine.Vector3 impactNormal)
		{
			if ((bool)victim)
			{
				return false;
			}
			GameObject gameObject = null;
			sbyte networkhitHurtboxIndex = -1;
			HurtBox component = hitCollider.GetComponent<HurtBox>();
			if ((bool)component)
			{
				HealthComponent healthComponent = component.healthComponent;
				if ((bool)healthComponent)
				{
					gameObject = healthComponent.gameObject;
				}
				networkhitHurtboxIndex = (sbyte)component.indexInGroup;
			}
			if (!gameObject && !ignoreWorld)
			{
				gameObject = hitCollider.gameObject;
				networkhitHurtboxIndex = -2;
			}
			if (gameObject == projectileController.owner || (ignoreCharacters && (bool)component))
			{
				gameObject = null;
				networkhitHurtboxIndex = -1;
			}
			if ((bool)gameObject)
			{
				NetworkrunStickEvent = true;
				ParticleSystem[] array = stickParticleSystem;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].Play();
				}
				if (stickSoundString.Length > 0)
				{
					Util.PlaySound(stickSoundString, base.gameObject);
				}
				if (alignNormals && impactNormal != UnityEngine.Vector3.zero)
				{
					base.transform.rotation = Util.QuaternionSafeLookRotation(impactNormal, base.transform.up);
				}
				Transform transform = hitCollider.transform;
				NetworklocalPosition = transform.InverseTransformPoint(base.transform.position);
				NetworklocalRotation = UnityEngine.Quaternion.Inverse(transform.rotation) * base.transform.rotation;
				victim = gameObject;
				NetworkhitHurtboxIndex = networkhitHurtboxIndex;
				return true;
			}
			return false;
		}

		private void FixedUpdate()
		{
			MyFixedUpdate(Time.deltaTime);
		}

		private void UpdateSticking()
		{
			bool flag = stuckTransform;
			if (flag)
			{
				base.transform.SetPositionAndRotation(stuckTransform.TransformPoint(localPosition), alignNormals ? (stuckTransform.rotation * localRotation) : base.transform.rotation);
			}
			else
			{
				GameObject gameObject = (NetworkServer.active ? victim : syncVictim);
				if ((bool)gameObject)
				{
					stuckTransform = gameObject.transform;
					flag = true;
					if (hitHurtboxIndex >= 0)
					{
						stuckBody = stuckTransform.GetComponent<CharacterBody>();
						if ((bool)stuckBody && hitHurtboxIndex < stuckBody.hurtBoxGroup.hurtBoxes.Length && stuckBody.hurtBoxGroup.hurtBoxes[hitHurtboxIndex] != null)
						{
							stuckTransform = stuckBody.hurtBoxGroup.hurtBoxes[hitHurtboxIndex].transform;
						}
						ModelLocator component = syncVictim.GetComponent<ModelLocator>();
						if ((bool)component)
						{
							Transform modelTransform = component.modelTransform;
							if ((bool)modelTransform)
							{
								HurtBoxGroup component2 = modelTransform.GetComponent<HurtBoxGroup>();
								if ((bool)component2)
								{
									HurtBox hurtBox = component2.hurtBoxes[hitHurtboxIndex];
									if ((bool)hurtBox)
									{
										stuckTransform = hurtBox.transform;
									}
								}
							}
						}
					}
				}
				else if (hitHurtboxIndex == -2 && !NetworkServer.active)
				{
					flag = true;
				}
			}
			if (!NetworkServer.active)
			{
				return;
			}
			if (rigidbody.isKinematic != flag)
			{
				if (flag)
				{
					rigidbody.detectCollisions = false;
					rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
					rigidbody.isKinematic = true;
				}
				else
				{
					rigidbody.detectCollisions = true;
					rigidbody.isKinematic = false;
					rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
				}
			}
			if (!flag)
			{
				NetworkhitHurtboxIndex = -1;
			}
		}

		public void MyFixedUpdate(float deltaTime)
		{
			UpdateSticking();
			if (!alreadyRanStickEvent && runStickEvent)
			{
				stickEvent.Invoke();
				alreadyRanStickEvent = true;
			}
		}

		private void UNetVersion()
		{
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			if (forceAll)
			{
				writer.Write(syncVictim);
				writer.WritePackedUInt32((uint)hitHurtboxIndex);
				writer.Write(localPosition);
				writer.Write(localRotation);
				writer.Write(runStickEvent);
				return true;
			}
			bool flag = false;
			if ((base.syncVarDirtyBits & (true ? 1u : 0u)) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(syncVictim);
			}
			if ((base.syncVarDirtyBits & 2u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.WritePackedUInt32((uint)hitHurtboxIndex);
			}
			if ((base.syncVarDirtyBits & 4u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(localPosition);
			}
			if ((base.syncVarDirtyBits & 8u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(localRotation);
			}
			if ((base.syncVarDirtyBits & 0x10u) != 0)
			{
				if (!flag)
				{
					writer.WritePackedUInt32(base.syncVarDirtyBits);
					flag = true;
				}
				writer.Write(runStickEvent);
			}
			if (!flag)
			{
				writer.WritePackedUInt32(base.syncVarDirtyBits);
			}
			return flag;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
			if (initialState)
			{
				___syncVictimNetId = reader.ReadNetworkId();
				hitHurtboxIndex = (sbyte)reader.ReadPackedUInt32();
				localPosition = reader.ReadVector3();
				localRotation = reader.ReadQuaternion();
				runStickEvent = reader.ReadBoolean();
				return;
			}
			int num = (int)reader.ReadPackedUInt32();
			if (((uint)num & (true ? 1u : 0u)) != 0)
			{
				syncVictim = reader.ReadGameObject();
			}
			if (((uint)num & 2u) != 0)
			{
				hitHurtboxIndex = (sbyte)reader.ReadPackedUInt32();
			}
			if (((uint)num & 4u) != 0)
			{
				localPosition = reader.ReadVector3();
			}
			if (((uint)num & 8u) != 0)
			{
				localRotation = reader.ReadQuaternion();
			}
			if (((uint)num & 0x10u) != 0)
			{
				runStickEvent = reader.ReadBoolean();
			}
		}

		public override void PreStartClient()
		{
			if (!___syncVictimNetId.IsEmpty())
			{
				NetworksyncVictim = ClientScene.FindLocalObject(___syncVictimNetId);
			}
		}
	}
	public class ProjectileTargetComponent : MonoBehaviour
	{
		public Transform target { get; set; }

		private void FixedUpdate()
		{
			if ((bool)target && !target.gameObject.activeSelf)
			{
				target = null;
			}
		}
	}
	[RequireComponent(typeof(Collider))]
	public class SlowDownProjectiles : MonoBehaviour
	{
		private struct SlowDownProjectileInfo
		{
			public Rigidbody rb;

			public UnityEngine.Vector3 previousVelocity;
		}

		public TeamFilter teamFilter;

		public float slowDownCoefficient;

		private List<SlowDownProjectileInfo> slowDownProjectileInfos;

		private void Start()
		{
			slowDownProjectileInfos = new List<SlowDownProjectileInfo>();
		}

		private void Update()
		{
		}

		private void OnTriggerEnter(Collider other)
		{
			TeamFilter component = other.GetComponent<TeamFilter>();
			Rigidbody component2 = other.GetComponent<Rigidbody>();
			if ((bool)component2 && component.teamIndex != teamFilter.teamIndex)
			{
				slowDownProjectileInfos.Add(new SlowDownProjectileInfo
				{
					rb = component2,
					previousVelocity = component2.velocity
				});
			}
		}

		private void OnTriggerExit(Collider other)
		{
			TeamFilter component = other.GetComponent<TeamFilter>();
			Rigidbody component2 = other.GetComponent<Rigidbody>();
			if ((bool)component2 && component.teamIndex != teamFilter.teamIndex)
			{
				RemoveFromSlowDownProjectileInfos(component2);
			}
		}

		private void RemoveFromSlowDownProjectileInfos(Rigidbody rb)
		{
			for (int i = 0; i < slowDownProjectileInfos.Count; i++)
			{
				if (slowDownProjectileInfos[i].rb == rb)
				{
					slowDownProjectileInfos.RemoveAt(i);
					break;
				}
			}
		}

		private void FixedUpdate()
		{
			for (int i = 0; i < slowDownProjectileInfos.Count; i++)
			{
				SlowDownProjectileInfo value = slowDownProjectileInfos[i];
				Rigidbody rb = value.rb;
				UnityEngine.Vector3 previousVelocity = value.previousVelocity;
				if ((bool)rb)
				{
					rb.MovePosition(rb.position - UnityEngine.Vector3.Lerp(previousVelocity, UnityEngine.Vector3.zero, slowDownCoefficient) * Time.fixedDeltaTime);
					value.previousVelocity = rb.velocity;
					slowDownProjectileInfos[i] = value;
				}
				else
				{
					RemoveFromSlowDownProjectileInfos(rb);
				}
			}
		}
	}
	[RequireComponent(typeof(HealthComponent))]
	[RequireComponent(typeof(ProjectileController))]
	[RequireComponent(typeof(ProjectileDamage))]
	public class ProjectileGrantOnKillOnDestroy : MonoBehaviour
	{
		private ProjectileController projectileController;

		private ProjectileDamage projectileDamage;

		private HealthComponent healthComponent;

		private void OnDestroy()
		{
			healthComponent = GetComponent<HealthComponent>();
			projectileController = GetComponent<ProjectileController>();
			projectileDamage = GetComponent<ProjectileDamage>();
			if (NetworkServer.active && (bool)projectileController.owner)
			{
				DamageInfo damageInfo = new DamageInfo
				{
					attacker = projectileController.owner,
					crit = projectileDamage.crit,
					damage = projectileDamage.damage,
					position = base.transform.position,
					procCoefficient = projectileController.procCoefficient,
					damageType = projectileDamage.damageType,
					damageColorIndex = projectileDamage.damageColorIndex
				};
				HealthComponent victim = healthComponent;
				DamageReport damageReport = new DamageReport(damageInfo, victim, damageInfo.damage, healthComponent.combinedHealth);
				GlobalEventManager.instance.OnCharacterDeath(damageReport);
			}
		}
	}
	[RequireComponent(typeof(ProjectileController))]
	public class ProjectileHealOwnerOnDamageInflicted : MonoBehaviour, IOnDamageInflictedServerReceiver
	{
		public float fractionOfDamage;

		private ProjectileController projectileController;

		private void Awake()
		{
			projectileController = GetComponent<ProjectileController>();
		}

		public void OnDamageInflictedServer(DamageReport damageReport)
		{
			if ((bool)projectileController.owner)
			{
				HealthComponent component = projectileController.owner.GetComponent<HealthComponent>();
				if ((bool)component)
				{
					HealOrb healOrb = new HealOrb();
					healOrb.origin = base.transform.position;
					healOrb.target = component.body.mainHurtBox;
					healOrb.healValue = damageReport.damageDealt * fractionOfDamage;
					healOrb.overrideDuration = 0.3f;
					OrbManager.instance.AddOrb(healOrb);
				}
			}
		}
	}
	[RequireComponent(typeof(ProjectileTargetComponent))]
	public class ProjectileSteerTowardTarget : MonoBehaviour
	{
		[Tooltip("Constrains rotation to the Y axis only.")]
		public bool yAxisOnly;

		[Tooltip("How fast to rotate in degrees per second. Rotation is linear.")]
		public float rotationSpeed;

		private new Transform transform;

		private ProjectileTargetComponent targetComponent;

		private void Start()
		{
			if (!NetworkServer.active)
			{
				base.enabled = false;
				return;
			}
			transform = base.transform;
			targetComponent = GetComponent<ProjectileTargetComponent>();
		}

		private void FixedUpdate()
		{
			if ((bool)targetComponent.target)
			{
				UnityEngine.Vector3 vector = targetComponent.target.transform.position - transform.position;
				if (yAxisOnly)
				{
					vector.y = 0f;
				}
				if (vector != UnityEngine.Vector3.zero)
				{
					transform.forward = UnityEngine.Vector3.RotateTowards(transform.forward, vector, rotationSpeed * (MathF.PI / 180f) * Time.fixedDeltaTime, 0f);
				}
			}
		}
	}
}
namespace RoR2.EntityLogic
{
	public class BoolEventSplitter : MonoBehaviour
	{
		public UnityEvent trueEvent;

		public UnityEvent falseEvent;

		public void CallEvent(bool value)
		{
			(value ? trueEvent : falseEvent)?.Invoke();
		}
	}
	public class Counter : MonoBehaviour
	{
		public int value;

		public int threshold;

		public UnityEvent onTrigger;

		public void Add(int valueToAdd)
		{
			value += valueToAdd;
			if (value >= threshold)
			{
				onTrigger.Invoke();
			}
		}

		public void SetValue(int newValue)
		{
			value = newValue;
		}
	}
	public class DelayedEvent : MonoBehaviour
	{
		public enum TimeStepType
		{
			Time,
			UnscaledTime,
			FixedTime
		}

		public UnityEvent action;

		public TimeStepType timeStepType;

		public void CallDelayed(float timer)
		{
			TimerQueue timerQueue = null;
			switch (timeStepType)
			{
			case TimeStepType.Time:
				timerQueue = RoR2Application.timeTimers;
				break;
			case TimeStepType.UnscaledTime:
				timerQueue = RoR2Application.unscaledTimeTimers;
				break;
			case TimeStepType.FixedTime:
				timerQueue = RoR2Application.fixedTimeTimers;
				break;
			}
			timerQueue?.CreateTimer(timer, Call);
		}

		public void CallDelayedIfActiveAndEnabled(float timer)
		{
			if (base.isActiveAndEnabled)
			{
				CallDelayed(timer);
			}
		}

		private void Call()
		{
			if ((bool)this && base.enabled)
			{
				action.Invoke();
			}
		}
	}
	public class Repeat : MonoBehaviour
	{
		public UnityEvent repeatedEvent;

		public void CallRepeat(int repeatNumber)
		{
			while (repeatNumber > 0)
			{
				repeatNumber--;
				repeatedEvent?.Invoke();
			}
		}
	}
	public class TeleporterEventRelay : MonoBehaviour
	{
		public UnityEvent onTeleporterBeginCharging;

		public UnityEvent onTeleporterCharged;

		public UnityEvent onTeleporterFinish;

		private TeleporterInteraction.ActivationState recordedActivationState;

		public void OnEnable()
		{
			TeleporterInteraction.onTeleporterBeginChargingGlobal += CheckTeleporterBeginCharging;
			TeleporterInteraction.onTeleporterChargedGlobal += CheckTeleporterCharged;
			TeleporterInteraction.onTeleporterFinishGlobal += CheckTeleporterFinish;
			CheckTeleporterBeginCharging(TeleporterInteraction.instance);
			CheckTeleporterCharged(TeleporterInteraction.instance);
			CheckTeleporterFinish(TeleporterInteraction.instance);
		}

		public void OnDisable()
		{
			TeleporterInteraction.onTeleporterBeginChargingGlobal -= CheckTeleporterBeginCharging;
			TeleporterInteraction.onTeleporterChargedGlobal -= CheckTeleporterCharged;
			TeleporterInteraction.onTeleporterFinishGlobal -= CheckTeleporterFinish;
		}

		private void CheckTeleporterBeginCharging(TeleporterInteraction teleporter)
		{
			if ((bool)teleporter && teleporter.activationState >= TeleporterInteraction.ActivationState.Charging && recordedActivationState < TeleporterInteraction.ActivationState.Charging)
			{
				onTeleporterBeginCharging?.Invoke();
				recordedActivationState = TeleporterInteraction.ActivationState.Charging;
			}
		}

		private void CheckTeleporterCharged(TeleporterInteraction teleporter)
		{
			if ((bool)teleporter && teleporter.activationState >= TeleporterInteraction.ActivationState.Charged && recordedActivationState < TeleporterInteraction.ActivationState.Charged)
			{
				onTeleporterCharged?.Invoke();
				recordedActivationState = TeleporterInteraction.ActivationState.Charged;
			}
		}

		private void CheckTeleporterFinish(TeleporterInteraction teleporter)
		{
			if ((bool)teleporter && teleporter.activationState >= TeleporterInteraction.ActivationState.Finished && recordedActivationState < TeleporterInteraction.ActivationState.Finished)
			{
				onTeleporterFinish?.Invoke();
				recordedActivationState = TeleporterInteraction.ActivationState.Finished;
			}
		}
	}
	public class Timer : MonoBehaviour
	{
		public enum TimeStepType
		{
			Time,
			UnscaledTime,
			FixedTime
		}

		[SerializeField]
		private float _duration;

		[SerializeField]
		private TimeStepType _timeStepType = TimeStepType.FixedTime;

		public bool resetTimerOnEnable = true;

		public bool playTimerOnEnable = true;

		public bool loop;

		public UnityEvent action;

		private float stopwatch;

		private bool timerRunning;

		public float duration
		{
			get
			{
				return _duration;
			}
			set
			{
				_duration = value;
			}
		}

		public TimeStepType timeStepType
		{
			get
			{
				return _timeStepType;
			}
			set
			{
				_timeStepType = value;
			}
		}

		private void OnEnable()
		{
			if (resetTimerOnEnable)
			{
				RewindTimerToBeginning();
			}
			if (playTimerOnEnable)
			{
				PlayTimer();
			}
		}

		private void Update()
		{
			if (timerRunning)
			{
				if (timeStepType == TimeStepType.Time)
				{
					RunTimer(Time.deltaTime);
				}
				else if (timeStepType == TimeStepType.UnscaledTime)
				{
					RunTimer(Time.unscaledDeltaTime);
				}
			}
		}

		private void FixedUpdate()
		{
			if (timerRunning && timeStepType == TimeStepType.FixedTime)
			{
				RunTimer(Time.fixedDeltaTime);
			}
		}

		public void RewindTimerToBeginning()
		{
			stopwatch = 0f;
		}

		public void SkipTimerToEnd()
		{
			stopwatch = duration;
		}

		public void SetTimerPlaying(bool newTimerRunning)
		{
			timerRunning = newTimerRunning;
		}

		public void PlayTimer()
		{
			SetTimerPlaying(newTimerRunning: true);
		}

		public void PauseTimer()
		{
			SetTimerPlaying(newTimerRunning: false);
		}

		public void CancelTimer()
		{
			PauseTimer();
			RewindTimerToBeginning();
		}

		public void PlayTimerFromBeginning()
		{
			RewindTimerToBeginning();
			PlayTimer();
		}

		private void RunTimer(float deltaTime)
		{
			stopwatch += deltaTime;
			if (stopwatch >= duration)
			{
				stopwatch = 0f;
				try
				{
					action?.Invoke();
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
				if (!loop)
				{
					timerRunning = false;
				}
			}
		}
	}
	public class UpdateEvent : MonoBehaviour
	{
		[Tooltip("Don't call the action until at least this many updates have fired")]
		[SerializeField]
		private int updateSkipCount;

		[Tooltip("Don't call the action after this many updates have fired.  If negative, ignore.")]
		[SerializeField]
		private int maxInvokeCount = -1;

		[SerializeField]
		private UnityEvent action;

		private int invokeCount;

		private int updateCount;

		private void Update()
		{
			if (updateSkipCount < updateCount && (maxInvokeCount < 0 || invokeCount < maxInvokeCount))
			{
				action?.Invoke();
				invokeCount++;
			}
			updateCount++;
		}
	}
}
namespace RoR2.EntitlementManagement
{
	public abstract class BaseUserEntitlementTracker<TUser> : IDisposable where TUser : class
	{
		private Dictionary<TUser, List<EntitlementDef>> userToEntitlements = new Dictionary<TUser, List<EntitlementDef>>();

		private IUserEntitlementResolver<TUser>[] entitlementResolvers;

		private bool disposed;

		public static Action OnUserEntitlementsUpdated;

		public static Action OnAllUserEntitlementsUpdated;

		protected abstract void SubscribeToUserDiscovered();

		protected abstract void SubscribeToUserLost();

		protected abstract void UnsubscribeFromUserDiscovered();

		protected abstract void UnsubscribeFromUserLost();

		protected abstract IList<TUser> GetCurrentUsers();

		public BaseUserEntitlementTracker(IUserEntitlementResolver<TUser>[] entitlementResolvers)
		{
			this.entitlementResolvers = ArrayUtils.Clone(entitlementResolvers);
			SubscribeToUserDiscovered();
			SubscribeToUserLost();
			for (int i = 0; i < entitlementResolvers.Length; i++)
			{
				entitlementResolvers[i].onEntitlementsChanged += UpdateAllUserEntitlements;
			}
			IList<TUser> currentUsers = GetCurrentUsers();
			for (int j = 0; j < currentUsers.Count; j++)
			{
				OnUserDiscovered(currentUsers[j]);
			}
		}

		public virtual void Dispose()
		{
			disposed = true;
			for (int num = entitlementResolvers.Length - 1; num >= 0; num--)
			{
				entitlementResolvers[num].onEntitlementsChanged -= UpdateAllUserEntitlements;
			}
			UnsubscribeFromUserLost();
			UnsubscribeFromUserDiscovered();
			IList<TUser> currentUsers = GetCurrentUsers();
			for (int i = 0; i < currentUsers.Count; i++)
			{
				OnUserLost(currentUsers[i]);
			}
		}

		protected virtual void OnUserDiscovered(TUser user)
		{
			try
			{
				List<EntitlementDef> value = new List<EntitlementDef>();
				userToEntitlements.Add(user, value);
				UpdateUserEntitlements(user);
			}
			catch (Exception message)
			{
				LogError(message);
			}
		}

		protected virtual void OnUserLost(TUser user)
		{
			try
			{
				userToEntitlements.Remove(user);
			}
			catch (Exception message)
			{
				LogError(message);
			}
		}

		public void UpdateAllUserEntitlements()
		{
			IList<TUser> currentUsers = GetCurrentUsers();
			for (int i = 0; i < currentUsers.Count; i++)
			{
				UpdateUserEntitlements(currentUsers[i]);
			}
			OnAllUserEntitlementsUpdated?.Invoke();
		}

		protected void UpdateUserEntitlements(TUser user)
		{
			if (!userToEntitlements.TryGetValue(user, out var value))
			{
				return;
			}
			value.Clear();
			IUserEntitlementResolver<TUser>[] array = entitlementResolvers;
			foreach (IUserEntitlementResolver<TUser> userEntitlementResolver in array)
			{
				foreach (EntitlementDef entitlementDef in EntitlementCatalog.entitlementDefs)
				{
					if (!value.Contains(entitlementDef) && userEntitlementResolver.CheckUserHasEntitlement(user, entitlementDef))
					{
						value.Add(entitlementDef);
					}
				}
			}
			OnUserEntitlementsUpdated?.Invoke();
		}

		public bool UserHasEntitlement([NotNull] TUser user, [NotNull] EntitlementDef entitlementDef)
		{
			if (!entitlementDef)
			{
				throw new ArgumentNullException("entitlementDef");
			}
			if (user == null || !userToEntitlements.TryGetValue(user, out var value))
			{
				return false;
			}
			return value.Contains(entitlementDef);
		}

		public bool AnyUserHasEntitlement([NotNull] EntitlementDef entitlementDef)
		{
			IList<TUser> currentUsers = GetCurrentUsers();
			for (int i = 0; i < currentUsers.Count; i++)
			{
				if (UserHasEntitlement(currentUsers[i], entitlementDef))
				{
					return true;
				}
			}
			return false;
		}

		public bool UserHasEntitlementForUnlockable([NotNull] TUser user, UnlockableDef unlockableDef)
		{
			if (!unlockableDef)
			{
				return true;
			}
			if (user == null || !userToEntitlements.TryGetValue(user, out var value))
			{
				return false;
			}
			ExpansionDef expansionDefForUnlockable = UnlockableCatalog.GetExpansionDefForUnlockable(unlockableDef.index);
			if (!expansionDefForUnlockable)
			{
				return true;
			}
			EntitlementDef requiredEntitlement = expansionDefForUnlockable.requiredEntitlement;
			return value.Contains(requiredEntitlement);
		}

		protected static void LogError(object message)
		{
			RoR2Application.onNextUpdate += delegate
			{
				UnityEngine.Debug.LogError(message);
			};
		}
	}
	public class EgsEntitlementResolver : IUserEntitementsResolverNetworkAndLocal, IUserEntitlementResolver<NetworkUser>, IUserEntitlementResolver<LocalUser>, IPlatformShopLauncher
	{
		private const string DevAudienceEntitlementName = "8fc64849a03741faaf51824d6e727cc1";

		private static EcomInterface EOS_Ecom;

		private List<string> ownedEntitlementIDs = new List<string>();

		private static event Action onDlcInstalled;

		public event Action OnPlatformShopClosed;

		event Action IUserEntitlementResolver<LocalUser>.onEntitlementsChanged
		{
			add
			{
				onDlcInstalled += value;
			}
			remove
			{
				onDlcInstalled -= value;
			}
		}

		event Action IUserEntitlementResolver<NetworkUser>.onEntitlementsChanged
		{
			add
			{
				onDlcInstalled += value;
			}
			remove
			{
				onDlcInstalled -= value;
			}
		}

		public EgsEntitlementResolver()
		{
			if (EOS_Ecom == null)
			{
				EOS_Ecom = EOSPlatformManager.GetPlatformInterface().GetEcomInterface();
			}
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(GetEGSEntitlements));
		}

		private void GetEGSEntitlements(EpicAccountId accountId)
		{
			GetEGSEntitlements();
		}

		private void GetEGSEntitlements()
		{
			if (EOSLoginManager.loggedInAuthId != null)
			{
				QueryOwnershipOptions options = default(QueryOwnershipOptions);
				options.LocalUserId = EOSLoginManager.loggedInAuthId;
				options.CatalogItemIds = EntitlementCatalog.entitlementDefs.Select((EntitlementDef x) => new Utf8String(x.eosItemId)).ToArray();
				EOS_Ecom.QueryOwnership(ref options, null, HandleQueryOwnershipCallback);
			}
			else
			{
				EOSLoginManager.OnAuthLoggedIn += GetEGSEntitlements;
			}
		}

		private void HandleQueryOwnershipCallback(ref QueryOwnershipCallbackInfo data)
		{
			if (data.GetResultCode() == Result.Success)
			{
				ownedEntitlementIDs.Clear();
				for (int i = 0; i < data.ItemOwnership.Length; i++)
				{
					if (data.ItemOwnership[i].OwnershipStatus == OwnershipStatus.Owned)
					{
						ownedEntitlementIDs.Add(data.ItemOwnership[i].Id);
					}
				}
			}
			EgsEntitlementResolver.onDlcInstalled();
		}

		bool IUserEntitlementResolver<LocalUser>.CheckUserHasEntitlement([NotNull] LocalUser localUser, [NotNull] EntitlementDef entitlementDef)
		{
			return CheckLocalUserHasEntitlement(entitlementDef);
		}

		private bool CheckLocalUserHasEntitlement(EntitlementDef entitlementDef)
		{
			for (int i = 0; i < ownedEntitlementIDs.Count; i++)
			{
				if (ownedEntitlementIDs[i] == entitlementDef.eosItemId)
				{
					return true;
				}
			}
			return false;
		}

		bool IUserEntitlementResolver<NetworkUser>.CheckUserHasEntitlement([NotNull] NetworkUser networkUser, [NotNull] EntitlementDef entitlementDef)
		{
			if (!networkUser)
			{
				return false;
			}
			if (networkUser.isLocalPlayer)
			{
				return CheckLocalUserHasEntitlement(entitlementDef);
			}
			ClientAuthData clientAuthData = ServerAuthManager.FindAuthData(networkUser.connectionToClient);
			if (clientAuthData == null)
			{
				return false;
			}
			PlatformID platformId = clientAuthData.platformId;
			if (!platformId.isValid)
			{
				return false;
			}
			return EntitlementAbstractions.VerifyRemoteUser(clientAuthData, entitlementDef);
		}

		public string[] BuildEntitlements()
		{
			string[] array = new string[ownedEntitlementIDs.Count];
			int num = array.Length;
			for (int i = 0; i < num; i++)
			{
				EntitlementDef[] entitlementDefs = ContentManager.entitlementDefs;
				foreach (EntitlementDef entitlementDef in entitlementDefs)
				{
					if (entitlementDef.eosItemId == ownedEntitlementIDs[i] || "8fc64849a03741faaf51824d6e727cc1" == ownedEntitlementIDs[i])
					{
						array[i] = entitlementDef.name;
						break;
					}
				}
			}
			return array;
		}

		public void LaunchPlatformShop(EntitlementDef entitlementDef)
		{
			throw new NotImplementedException();
		}

		public void LaunchPlatformShopAllProducts()
		{
			throw new NotImplementedException();
		}
	}
	public enum EntitlementIndex
	{
		None = -1
	}
	public static class EntitlementCatalog
	{
		private static EntitlementDef[] _entitlementDefs = Array.Empty<EntitlementDef>();

		private static Dictionary<string, EntitlementIndex> nameToIndex = new Dictionary<string, EntitlementIndex>();

		private static string[] indexToName = Array.Empty<string>();

		public static ReadOnlyArray<EntitlementDef> entitlementDefs => _entitlementDefs;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetEntitlementDefs(ContentManager.entitlementDefs);
		}

		private static void SetEntitlementDefs(EntitlementDef[] newEntitlementDefs)
		{
			_entitlementDefs = ArrayUtils.Clone(newEntitlementDefs);
			nameToIndex.Clear();
			Array.Resize(ref indexToName, newEntitlementDefs.Length);
			for (int i = 0; i < entitlementDefs.Length; i++)
			{
				_entitlementDefs[i].entitlementIndex = (EntitlementIndex)i;
				string name = _entitlementDefs[i].name;
				nameToIndex[name] = (EntitlementIndex)i;
				indexToName[i] = name;
			}
		}

		public static EntitlementIndex FindEntitlementIndex([NotNull] string entitlementName)
		{
			if (nameToIndex.TryGetValue(entitlementName, out var value))
			{
				return value;
			}
			return EntitlementIndex.None;
		}

		public static EntitlementDef GetEntitlementDef(EntitlementIndex entitlementIndex)
		{
			return ArrayUtils.GetSafe(_entitlementDefs, (int)entitlementIndex);
		}

		[ConCommand(commandName = "entitlements_list", flags = ConVarFlags.None, helpText = "Displays all registered entitlements.")]
		private static void CCEntitlementsList(ConCommandArgs args)
		{
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			for (int i = 0; i < indexToName.Length; i++)
			{
				stringBuilder.AppendLine(indexToName[i]);
			}
			args.Log(stringBuilder.ToString());
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}
	}
	public static class ConCommandArgExtensions
	{
		public static EntitlementIndex? TryGetArgEntitlementIndex(this ConCommandArgs args, int index)
		{
			string text = args.TryGetArgString(index);
			if (text != null)
			{
				EntitlementIndex entitlementIndex = EntitlementCatalog.FindEntitlementIndex(text);
				if (entitlementIndex != EntitlementIndex.None || text.Equals("None", StringComparison.Ordinal))
				{
					return entitlementIndex;
				}
			}
			return null;
		}

		public static EntitlementIndex GetArgEntitlementIndex(this ConCommandArgs args, int index)
		{
			return args.TryGetArgEntitlementIndex(index) ?? throw new ConCommandException("No EntitlementIndex is defined for an entitlement named '" + args.TryGetArgString(index) + "'. Use the \"entitlement_list\" command to get a list of all valid entitlements.");
		}
	}
	[CreateAssetMenu(menuName = "RoR2/EntitlementDef")]
	public class EntitlementDef : ScriptableObject
	{
		[HideInInspector]
		[SerializeField]
		public EntitlementIndex entitlementIndex = EntitlementIndex.None;

		[Tooltip("The localization token of the display name.")]
		public string nameToken;

		[Header("PC")]
		public uint steamAppId;

		[Tooltip("This is an EOS Item Id, not Offer Id.")]
		public string eosItemId;

		[Header("XBox")]
		public string GamecoreID;

		[Header("Playstation")]
		public string SonyID;

		[Header("Nintendo")]
		public ulong switchNsUid;

		[Tooltip("Nintendo DLC is an index. ie first DLC is 0, etc")]
		public uint switchDLCIndex;

		private void OnDisable()
		{
			entitlementIndex = EntitlementIndex.None;
		}
	}
	public static class EntitlementManager
	{
		private static IUserEntitlementResolver<LocalUser>[] localUserEntitlementResolvers = Array.Empty<IUserEntitlementResolver<LocalUser>>();

		private static IUserEntitlementResolver<NetworkUser>[] networkUserEntitlementResolvers = Array.Empty<IUserEntitlementResolver<NetworkUser>>();

		private static bool isLoaded = true;

		private static bool collectLocalUserEntitlementResolversLocked = false;

		private static bool collectNetworkUserEntitlementResolversLocked;

		public static LocalUserEntitlementTracker localUserEntitlementTracker { get; private set; }

		public static NetworkUserServerEntitlementTracker networkUserEntitlementTracker { get; private set; }

		private static event Action<Action<IUserEntitlementResolver<LocalUser>>> _collectLocalUserEntitlementResolvers;

		public static event Action<Action<IUserEntitlementResolver<LocalUser>>> collectLocalUserEntitlementResolvers
		{
			add
			{
				if (collectLocalUserEntitlementResolversLocked)
				{
					throw new InvalidOperationException("collectLocalUserEntitlementResolvers has already been invoked. It is too late to add additional subscribers.");
				}
				_collectLocalUserEntitlementResolvers += value;
			}
			remove
			{
				_collectLocalUserEntitlementResolvers -= value;
			}
		}

		private static event Action<Action<IUserEntitlementResolver<NetworkUser>>> _collectNetworkUserEntitlementResolvers;

		public static event Action<Action<IUserEntitlementResolver<NetworkUser>>> collectNetworkUserEntitlementResolvers
		{
			add
			{
				if (collectNetworkUserEntitlementResolversLocked)
				{
					throw new InvalidOperationException("collectNetworkUserEntitlementResolvers has already been invoked. It is too late to add additional subscribers.");
				}
				_collectNetworkUserEntitlementResolvers += value;
			}
			remove
			{
				_collectNetworkUserEntitlementResolvers -= value;
			}
		}

		public static event Action onEntitlementsUpdated;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			List<IUserEntitlementResolver<LocalUser>> list = new List<IUserEntitlementResolver<LocalUser>>();
			collectLocalUserEntitlementResolversLocked = true;
			EntitlementManager._collectLocalUserEntitlementResolvers?.Invoke(list.Add);
			EntitlementManager._collectLocalUserEntitlementResolvers = null;
			List<IUserEntitlementResolver<NetworkUser>> list2 = new List<IUserEntitlementResolver<NetworkUser>>();
			collectNetworkUserEntitlementResolversLocked = true;
			EntitlementManager._collectNetworkUserEntitlementResolvers?.Invoke(list2.Add);
			EntitlementManager._collectNetworkUserEntitlementResolvers = null;
			localUserEntitlementResolvers = list.ToArray();
			networkUserEntitlementResolvers = list2.ToArray();
			localUserEntitlementTracker = new LocalUserEntitlementTracker(localUserEntitlementResolvers);
			networkUserEntitlementTracker = new NetworkUserServerEntitlementTracker(networkUserEntitlementResolvers);
		}

		public static void NotifyEntitlementsUpdated()
		{
			EntitlementManager.onEntitlementsUpdated?.Invoke();
		}

		[ConCommand(commandName = "entitlement_check_local", flags = ConVarFlags.None, helpText = "Displays the availability of all entitlements for the sender.")]
		private static void CCEntitlementCheckLocal(ConCommandArgs args)
		{
			LocalUser senderLocalUser = args.GetSenderLocalUser();
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			foreach (EntitlementDef entitlementDef in EntitlementCatalog.entitlementDefs)
			{
				stringBuilder.Append(entitlementDef.name).Append("=").Append(localUserEntitlementTracker.UserHasEntitlement(senderLocalUser, entitlementDef))
					.AppendLine();
			}
			args.Log(stringBuilder.ToString());
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
		}

		[ConCommand(commandName = "entitlement_force_refresh", flags = ConVarFlags.None, helpText = "Forces the entitlement trackers to refresh.")]
		private static void CCEntitlementForceRefresh(ConCommandArgs args)
		{
			localUserEntitlementTracker.UpdateAllUserEntitlements();
			networkUserEntitlementTracker.UpdateAllUserEntitlements();
			NotifyEntitlementsUpdated();
		}

		public static void UpdateLocalUsersEntitlements()
		{
			localUserEntitlementTracker.UpdateAllUserEntitlements();
			NotifyEntitlementsUpdated();
		}
	}
	public interface IPlatformShopLauncher
	{
		event Action OnPlatformShopClosed;

		void LaunchPlatformShop(EntitlementDef entitlementDef);

		void LaunchPlatformShopAllProducts();
	}
	public interface IUserEntitlementResolver<TUser> where TUser : class
	{
		event Action onEntitlementsChanged;

		bool CheckUserHasEntitlement([NotNull] TUser user, [NotNull] EntitlementDef entitlementDef);
	}
	public class LocalUserEntitlementTracker : BaseUserEntitlementTracker<LocalUser>, IDisposable
	{
		protected override void SubscribeToUserDiscovered()
		{
			LocalUserManager.onUserSignIn += OnUserDiscovered;
		}

		protected override void SubscribeToUserLost()
		{
			LocalUserManager.onUserSignOut += OnUserLost;
		}

		protected override void UnsubscribeFromUserDiscovered()
		{
			LocalUserManager.onUserSignIn -= OnUserDiscovered;
		}

		protected override void UnsubscribeFromUserLost()
		{
			LocalUserManager.onUserSignOut -= OnUserLost;
		}

		protected override IList<LocalUser> GetCurrentUsers()
		{
			return LocalUserManager.readOnlyLocalUsersList;
		}

		public LocalUserEntitlementTracker([NotNull] IUserEntitlementResolver<LocalUser>[] entitlementResolvers)
			: base(entitlementResolvers)
		{
		}
	}
	public class NetworkUserServerEntitlementTracker : BaseUserEntitlementTracker<NetworkUser>, IDisposable
	{
		protected override void SubscribeToUserDiscovered()
		{
			NetworkUser.onNetworkUserDiscovered += OnUserDiscovered;
		}

		protected override void SubscribeToUserLost()
		{
			NetworkUser.onNetworkUserLost += OnUserLost;
		}

		protected override void UnsubscribeFromUserDiscovered()
		{
			NetworkUser.onNetworkUserDiscovered -= OnUserDiscovered;
		}

		protected override void UnsubscribeFromUserLost()
		{
			NetworkUser.onNetworkUserLost -= OnUserLost;
		}

		protected override IList<NetworkUser> GetCurrentUsers()
		{
			return NetworkUser.readOnlyInstancesList;
		}

		public NetworkUserServerEntitlementTracker(IUserEntitlementResolver<NetworkUser>[] entitlementResolvers)
			: base(entitlementResolvers)
		{
			NetworkUser.onPostNetworkUserStart += OnPostNetworkUserStart;
		}

		private void OnPostNetworkUserStart(NetworkUser networkUser)
		{
			if (NetworkServer.active)
			{
				UpdateUserEntitlements(networkUser);
			}
		}
	}
	public class SteamworksEntitlementResolver : IUserEntitementsResolverNetworkAndLocal, IUserEntitlementResolver<NetworkUser>, IUserEntitlementResolver<LocalUser>, IPlatformShopLauncher
	{
		private static event Action onDlcInstalled;

		public event Action OnPlatformShopClosed;

		event Action IUserEntitlementResolver<LocalUser>.onEntitlementsChanged
		{
			add
			{
				onDlcInstalled += value;
			}
			remove
			{
				onDlcInstalled -= value;
			}
		}

		event Action IUserEntitlementResolver<NetworkUser>.onEntitlementsChanged
		{
			add
			{
			}
			remove
			{
			}
		}

		private static void OnDlcInstalled(uint appId)
		{
			SteamworksEntitlementResolver.onDlcInstalled?.Invoke();
		}

		bool IUserEntitlementResolver<LocalUser>.CheckUserHasEntitlement([NotNull] LocalUser localUser, [NotNull] EntitlementDef entitlementDef)
		{
			return EntitlementAbstractions.VerifyLocalSteamUser(entitlementDef);
		}

		bool IUserEntitlementResolver<NetworkUser>.CheckUserHasEntitlement([NotNull] NetworkUser networkUser, [NotNull] EntitlementDef entitlementDef)
		{
			if (!networkUser)
			{
				return false;
			}
			if (networkUser.isLocalPlayer)
			{
				return EntitlementAbstractions.VerifyLocalSteamUser(entitlementDef);
			}
			ClientAuthData clientAuthData = ServerAuthManager.FindAuthData(networkUser.connectionToClient);
			if (clientAuthData == null)
			{
				return false;
			}
			PlatformID platformId = clientAuthData.platformId;
			if (!platformId.isValid)
			{
				return false;
			}
			return EntitlementAbstractions.VerifyRemoteUser(clientAuthData, entitlementDef);
		}

		public SteamworksEntitlementResolver()
		{
			EntitlementManager.collectLocalUserEntitlementResolvers += delegate(Action<IUserEntitlementResolver<LocalUser>> add)
			{
				add(this);
			};
			EntitlementManager.collectNetworkUserEntitlementResolvers += delegate(Action<IUserEntitlementResolver<NetworkUser>> add)
			{
				add(this);
			};
			SteamworksClientManager.onLoaded += delegate
			{
				SteamworksClientManager.instance.steamworksClient.App.OnDlcInstalled += OnDlcInstalled;
			};
		}

		public string[] BuildEntitlements()
		{
			List<string> list = new List<string>();
			EntitlementDef[] entitlementDefs = ContentManager.entitlementDefs;
			foreach (EntitlementDef entitlementDef in entitlementDefs)
			{
				if (Client.Instance.App.IsDlcInstalled(entitlementDef.steamAppId))
				{
					list.Add(entitlementDef.name);
				}
			}
			return list.ToArray();
		}

		public void LaunchPlatformShop(EntitlementDef entitlementDef)
		{
			throw new NotImplementedException();
		}

		public void LaunchPlatformShopAllProducts()
		{
			throw new NotImplementedException();
		}
	}
	public static class EntitlementAbstractions
	{
		public enum LoggedInPlatform
		{
			NONE_ERROR,
			STEAMWORKS,
			EPIC_ONLINE_SERVICES
		}

		public static LoggedInPlatform loggedInPlatform;

		public static bool VerifyLocalSteamUser(EntitlementDef entitlementDef)
		{
			return Client.Instance.App.IsDlcInstalled(entitlementDef.steamAppId);
		}

		public static bool VerifyRemoteUser(ClientAuthData authData, EntitlementDef entitlementDef)
		{
			for (int i = 0; i < authData.entitlements.Length; i++)
			{
				if (authData.entitlements[i].Equals(entitlementDef.name))
				{
					return true;
				}
			}
			return false;
		}

		public static void OpenShopPage(EntitlementDef entitlementDef)
		{
		}
	}
}
namespace RoR2.DirectionalSearch
{
	public class BaseDirectionalSearch<TSource, TSelector, TCandidateFilter> where TSource : class where TSelector : IGenericWorldSearchSelector<TSource> where TCandidateFilter : IGenericDirectionalSearchFilter<TSource>
	{
		private struct CandidateInfo
		{
			public TSource source;

			public UnityEngine.Vector3 position;

			public UnityEngine.Vector3 diff;

			public float distance;

			public float dot;

			public GameObject entity;
		}

		public UnityEngine.Vector3 searchOrigin;

		public UnityEngine.Vector3 searchDirection;

		private float minThetaDot = -1f;

		private float maxThetaDot = 1f;

		public float minDistanceFilter;

		public float maxDistanceFilter = float.PositiveInfinity;

		public SortMode sortMode = SortMode.Distance;

		public bool filterByLoS = true;

		public bool filterByDistinctEntity;

		private CandidateInfo[] candidateInfoList = Array.Empty<CandidateInfo>();

		private int candidateCount;

		protected TSelector selector;

		protected TCandidateFilter candidateFilter;

		public float minAngleFilter
		{
			set
			{
				maxThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f));
			}
		}

		public float maxAngleFilter
		{
			set
			{
				minThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f));
			}
		}

		public BaseDirectionalSearch(TSelector selector, TCandidateFilter candidateFilter)
		{
			this.selector = selector;
			this.candidateFilter = candidateFilter;
		}

		public TSource SearchCandidatesForSingleTarget<TSourceEnumerable>(TSourceEnumerable sourceEnumerable) where TSourceEnumerable : IEnumerable<TSource>
		{
			ArrayUtils.Clear(candidateInfoList, ref candidateCount);
			float num = minDistanceFilter * minDistanceFilter;
			float num2 = maxDistanceFilter * maxDistanceFilter;
			foreach (TSource item in sourceEnumerable)
			{
				CandidateInfo candidateInfo = default(CandidateInfo);
				candidateInfo.source = item;
				CandidateInfo value = candidateInfo;
				Transform transform = selector.GetTransform(item);
				if (!transform)
				{
					continue;
				}
				value.position = transform.position;
				value.diff = value.position - searchOrigin;
				float sqrMagnitude = value.diff.sqrMagnitude;
				if (!(sqrMagnitude < num) && !(sqrMagnitude > num2))
				{
					value.distance = Mathf.Sqrt(sqrMagnitude);
					value.dot = ((value.distance == 0f) ? 0f : UnityEngine.Vector3.Dot(searchDirection, value.diff / value.distance));
					if (!(value.dot < minThetaDot) && !(value.dot > maxThetaDot))
					{
						value.entity = selector.GetRootObject(item);
						ArrayUtils.ArrayAppend(ref candidateInfoList, ref candidateCount, in value);
					}
				}
			}
			for (int num3 = candidateCount - 1; num3 >= 0; num3--)
			{
				if (!candidateFilter.PassesFilter(candidateInfoList[num3].source))
				{
					ArrayUtils.ArrayRemoveAt(candidateInfoList, ref candidateCount, num3);
				}
			}
			Array.Sort(candidateInfoList, GetSorter());
			if (filterByDistinctEntity)
			{
				for (int num4 = candidateCount - 1; num4 >= 0; num4--)
				{
					ref CandidateInfo reference = ref candidateInfoList[num4];
					for (int i = 0; i < num4; i++)
					{
						ref CandidateInfo reference2 = ref candidateInfoList[i];
						if (reference.entity == reference2.entity)
						{
							ArrayUtils.ArrayRemoveAt(candidateInfoList, ref candidateCount, num4);
							break;
						}
					}
				}
			}
			TSource result = null;
			if (filterByLoS)
			{
				for (int j = 0; j < candidateCount; j++)
				{
					if (!Physics.Linecast(searchOrigin, candidateInfoList[j].position, out var _, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
					{
						result = candidateInfoList[j].source;
						break;
					}
				}
			}
			else if (candidateCount > 0)
			{
				result = candidateInfoList[0].source;
			}
			ArrayUtils.Clear(candidateInfoList, ref candidateCount);
			return result;
		}

		private static int DistanceToInversePriority(CandidateInfo a, CandidateInfo b)
		{
			return a.distance.CompareTo(b.distance);
		}

		private static int AngleToInversePriority(CandidateInfo a, CandidateInfo b)
		{
			return (0f - a.dot).CompareTo(0f - b.dot);
		}

		private static int DistanceAndAngleToInversePriority(CandidateInfo a, CandidateInfo b)
		{
			return ((0f - a.dot) * a.distance).CompareTo((0f - b.dot) * b.distance);
		}

		private Comparison<CandidateInfo> GetSorter()
		{
			return sortMode switch
			{
				SortMode.Distance => DistanceToInversePriority, 
				SortMode.Angle => AngleToInversePriority, 
				SortMode.DistanceAndAngle => DistanceAndAngleToInversePriority, 
				_ => null, 
			};
		}
	}
	public enum SortMode
	{
		None,
		Distance,
		Angle,
		DistanceAndAngle
	}
	public interface IGenericWorldSearchSelector<TSource>
	{
		Transform GetTransform(TSource source);

		GameObject GetRootObject(TSource source);
	}
	public interface IGenericDirectionalSearchFilter<TSource>
	{
		bool PassesFilter(TSource candidateInfo);
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct PickupSearchSelector : IGenericWorldSearchSelector<GenericPickupController>
	{
		public Transform GetTransform(GenericPickupController source)
		{
			return source.pickupDisplay.transform;
		}

		public GameObject GetRootObject(GenericPickupController source)
		{
			return source.gameObject;
		}
	}
	public struct PickupSearchFilter : IGenericDirectionalSearchFilter<GenericPickupController>
	{
		public bool requireTransmutable;

		public bool PassesFilter(GenericPickupController genericPickupController)
		{
			if (requireTransmutable)
			{
				return PickupTransmutationManager.GetAvailableGroupFromPickupIndex(genericPickupController.pickupIndex) != null;
			}
			return true;
		}
	}
	public class PickupSearch : BaseDirectionalSearch<GenericPickupController, PickupSearchSelector, PickupSearchFilter>
	{
		public bool requireTransmutable
		{
			get
			{
				return candidateFilter.requireTransmutable;
			}
			set
			{
				candidateFilter.requireTransmutable = value;
			}
		}

		public PickupSearch()
			: base(default(PickupSearchSelector), default(PickupSearchFilter))
		{
		}

		public PickupSearch(PickupSearchSelector selector, PickupSearchFilter candidateFilter)
			: base(selector, candidateFilter)
		{
		}
	}
}
namespace RoR2.ConVar
{
	public abstract class BaseConVar
	{
		public string name;

		public ConVarFlags flags;

		public string defaultValue;

		public string helpText;

		protected BaseConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
		{
			if (name == null)
			{
				throw new ArgumentNullException("name");
			}
			this.name = name;
			this.flags = flags;
			this.defaultValue = defaultValue;
			if (helpText == null)
			{
				throw new ArgumentNullException("helpText");
			}
			this.helpText = helpText;
		}

		public void AttemptSetString(string newValue)
		{
			try
			{
				SetString(newValue);
			}
			catch (ConCommandException ex)
			{
				UnityEngine.Debug.LogFormat("Could not set value of ConVar \"{0}\" to \"{1}\": {2}", name, newValue, ex.Message);
			}
		}

		public abstract void SetString(string newValue);

		public abstract string GetString();

		protected static void GetEnumValue<T>(string str, ref T dest) where T : struct, Enum
		{
			if (Enum.TryParse<T>(str, out var result))
			{
				dest = result;
				return;
			}
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			stringBuilder.Append("Provided value \"").Append(str).Append("\"")
				.Append(" is not a recognized option. Recognized options: { ");
			bool flag = false;
			string[] names = Enum.GetNames(typeof(T));
			foreach (string value in names)
			{
				if (flag)
				{
					stringBuilder.Append(", ");
				}
				else
				{
					flag = true;
				}
				stringBuilder.Append("\"").Append(value).Append("\"");
			}
			stringBuilder.Append(" }");
			string message = stringBuilder.ToString();
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			throw new ConCommandException(message);
		}

		protected static int ParseIntInvariant(string str)
		{
			if (TextSerialization.TryParseInvariant(str, out int result))
			{
				return result;
			}
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			stringBuilder.Append("Provided value \"").Append(str).Append("\"")
				.Append(" is not a valid number.");
			string message = stringBuilder.ToString();
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			throw new ConCommandException(message);
		}

		protected static float ParseFloatInvariant(string str)
		{
			if (TextSerialization.TryParseInvariant(str, out float result))
			{
				return result;
			}
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			stringBuilder.Append("Provided value \"").Append(str).Append("\"")
				.Append(" is not a valid number.");
			string message = stringBuilder.ToString();
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			throw new ConCommandException(message);
		}

		protected static bool ParseBoolInvariant(string str)
		{
			if (TextSerialization.TryParseInvariant(str, out int result))
			{
				switch (result)
				{
				case 0:
					return false;
				case 1:
					return true;
				}
			}
			StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
			stringBuilder.Append("Provided value \"").Append(str).Append("\"")
				.Append(" was neither \"0\" nor \"1\".");
			string message = stringBuilder.ToString();
			HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			throw new ConCommandException(message);
		}
	}
	public class PlayerPrefsIntConVar : BaseConVar
	{
		private int? defaultValueInt;

		public int value
		{
			get
			{
				if (!defaultValueInt.HasValue && int.TryParse(defaultValue, out var result))
				{
					defaultValueInt = result;
				}
				if (defaultValueInt.HasValue)
				{
					return PlayerPrefs.GetInt(name, defaultValueInt.Value);
				}
				return PlayerPrefs.GetInt(name);
			}
			set
			{
				PlayerPrefs.SetInt(name, value);
				PlayerPrefs.Save();
			}
		}

		public PlayerPrefsIntConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
			: base(name, flags, defaultValue, helpText)
		{
		}

		public override void SetString(string newValue)
		{
			if (TextSerialization.TryParseInvariant(newValue, out int result))
			{
				value = result;
			}
		}

		public override string GetString()
		{
			return TextSerialization.ToStringInvariant(value);
		}
	}
	public class BoolConVar : BaseConVar
	{
		public bool value { get; protected set; }

		public BoolConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
			: base(name, flags, defaultValue, helpText)
		{
		}

		public void SetBool(bool newValue)
		{
			value = newValue;
		}

		public override void SetString(string newValue)
		{
			if (TextSerialization.TryParseInvariant(newValue, out int result))
			{
				value = result != 0;
			}
		}

		public override string GetString()
		{
			if (!value)
			{
				return "0";
			}
			return "1";
		}
	}
	public class IntConVar : BaseConVar
	{
		public int value { get; protected set; }

		public IntConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
			: base(name, flags, defaultValue, helpText)
		{
		}

		public override void SetString(string newValue)
		{
			if (TextSerialization.TryParseInvariant(newValue, out int result))
			{
				value = result;
			}
		}

		public override string GetString()
		{
			return TextSerialization.ToStringInvariant(value);
		}
	}
	public class FloatConVar : BaseConVar
	{
		public float value { get; protected set; }

		public FloatConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
			: base(name, flags, defaultValue, helpText)
		{
		}

		public override void SetString(string newValue)
		{
			if (TextSerialization.TryParseInvariant(newValue, out float result) && !float.IsNaN(result) && !float.IsInfinity(result))
			{
				value = result;
			}
		}

		public override string GetString()
		{
			return TextSerialization.ToStringInvariant(value);
		}
	}
	public class StringConVar : BaseConVar
	{
		public string value { get; protected set; }

		public StringConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
			: base(name, flags, defaultValue, helpText)
		{
		}

		public override void SetString(string newValue)
		{
			value = newValue;
		}

		public override string GetString()
		{
			return value;
		}
	}
	public abstract class ToggleVirtualConVar : BaseConVar
	{
		private bool _enabled;

		private static readonly List<ToggleVirtualConVar> enabledInstances;

		public bool enabled
		{
			get
			{
				return _enabled;
			}
			protected set
			{
				if (_enabled != value)
				{
					_enabled = value;
					if (_enabled)
					{
						enabledInstances.Add(this);
						OnEnable();
					}
					else
					{
						enabledInstances.Remove(this);
						OnDisable();
					}
				}
			}
		}

		public bool value => enabled;

		static ToggleVirtualConVar()
		{
			enabledInstances = new List<ToggleVirtualConVar>();
			RoR2Application.onShutDown = (Action)Delegate.Combine(RoR2Application.onShutDown, new Action(OnApplicationShutDown));
		}

		public ToggleVirtualConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
			: base(name, flags, defaultValue, helpText)
		{
		}

		protected abstract void OnEnable();

		protected abstract void OnDisable();

		public override void SetString(string newValue)
		{
			enabled = BaseConVar.ParseBoolInvariant(newValue);
		}

		public override string GetString()
		{
			if (!enabled)
			{
				return "0";
			}
			return "1";
		}

		private static void OnApplicationShutDown()
		{
			while (enabledInstances.Count > 0)
			{
				enabledInstances[enabledInstances.Count - 1].enabled = false;
			}
		}
	}
	public sealed class ToggleDelegateConVar : ToggleVirtualConVar
	{
		private readonly Action onEnable;

		private readonly Action onDisable;

		public ToggleDelegateConVar(string name, ConVarFlags flags, string defaultValue, string helpText, Action onEnable, Action onDisable)
			: base(name, flags, defaultValue, helpText)
		{
			this.onEnable = onEnable;
			this.onDisable = onDisable;
		}

		protected override void OnEnable()
		{
			onEnable?.Invoke();
		}

		protected override void OnDisable()
		{
			onDisable?.Invoke();
		}
	}
}
namespace RoR2.ContentManagement
{
	public class AddressablesDirectory : IAssetRepository
	{
		public class AddressablesLoadAsyncOperationWrapper<TAsset> : BaseAsyncOperation<TAsset[]> where TAsset : UnityEngine.Object
		{
			private AsyncOperationHandle<TAsset>[] handles;

			private int completionCount;

			private List<TAsset> results = new List<TAsset>();

			public override float progress
			{
				get
				{
					float num = 0f;
					if (handles.Length == 0)
					{
						return 0f;
					}
					float num2 = 1f / (float)handles.Length;
					for (int i = 0; i < handles.Length; i++)
					{
						num += handles[i].PercentComplete * num2;
					}
					return num;
				}
			}

			public AddressablesLoadAsyncOperationWrapper(IReadOnlyList<AsyncOperationHandle<TAsset>> handles)
			{
				if (handles.Count == 0)
				{
					this.handles = Array.Empty<AsyncOperationHandle<TAsset>>();
					Complete(Array.Empty<TAsset>());
					return;
				}
				results = new List<TAsset>(handles.Count);
				this.handles = new AsyncOperationHandle<TAsset>[handles.Count];
				Action<AsyncOperationHandle<TAsset>> value = OnChildOperationCompleted;
				for (int i = 0; i < handles.Count; i++)
				{
					this.handles[i] = handles[i];
					AsyncOperationHandle<TAsset> asyncOperationHandle = handles[i];
					asyncOperationHandle.Completed += value;
				}
			}

			private void OnChildOperationCompleted(AsyncOperationHandle<TAsset> handle)
			{
				if ((bool)handle.Result)
				{
					results.Add(handle.Result);
				}
				completionCount++;
				if (completionCount == handles.Length)
				{
					Complete(results.ToArray());
				}
			}
		}

		private string baseDirectory;

		private FilePathTree folderTree;

		private IResourceLocator[] resourceLocators = Array.Empty<IResourceLocator>();

		public AddressablesDirectory(string baseDirectory, IEnumerable<IResourceLocator> resourceLocators)
		{
			baseDirectory = baseDirectory ?? string.Empty;
			if (baseDirectory.Length > 0 && !baseDirectory.EndsWith("/"))
			{
				throw new ArgumentException("'baseDirectory' must be empty or end with '/'. baseDirectory=\"" + baseDirectory + "\"");
			}
			this.baseDirectory = baseDirectory;
			this.resourceLocators = resourceLocators.ToArray();
			List<string> list = new List<string>();
			IResourceLocator[] array = this.resourceLocators;
			for (int i = 0; i < array.Length; i++)
			{
				foreach (object key in array[i].Keys)
				{
					if (key is string text && text.StartsWith(baseDirectory))
					{
						list.Add(text);
					}
				}
			}
			folderTree = FilePathTree.Create(list);
		}

		public BaseAsyncOperation<TAsset[]> LoadAllAsync<TAsset>(string folderPath) where TAsset : UnityEngine.Object
		{
			List<string> list = new List<string>();
			string folderPath2 = baseDirectory + folderPath;
			folderTree.GetEntriesInFolder(folderPath2, list);
			_ = list.Count;
			return IssueLoadOperationAsGroup<TAsset>(list);
		}

		private BaseAsyncOperation<TAsset[]> IssueLoadOperationAsGroup<TAsset>(List<string> entriesToLoad) where TAsset : UnityEngine.Object
		{
			List<IResourceLocation> locations = FilterPathsByType<TAsset>(entriesToLoad);
			List<TAsset> results = new List<TAsset>();
			AsyncOperationHandle<IList<TAsset>> loadOperationHandle = Addressables.LoadAssetsAsync(locations, delegate(TAsset result)
			{
				results.Add(result);
			});
			ScriptedAsyncOperation<TAsset[]> resultOperation = new ScriptedAsyncOperation<TAsset[]>(() => loadOperationHandle.PercentComplete);
			loadOperationHandle.Completed += delegate
			{
				resultOperation.Complete(results.ToArray());
			};
			return resultOperation;
		}

		private BaseAsyncOperation<TAsset[]> IssueLoadOperationsIndividually<TAsset>(List<string> entriesToLoad) where TAsset : UnityEngine.Object
		{
			List<IResourceLocation> list = FilterPathsByType<TAsset>(entriesToLoad);
			AsyncOperationHandle<TAsset>[] array = new AsyncOperationHandle<TAsset>[list.Count];
			for (int i = 0; i < list.Count; i++)
			{
				AsyncOperationHandle<TAsset> asyncOperationHandle = Addressables.LoadAssetAsync<TAsset>(list[i]);
				array[i] = asyncOperationHandle;
			}
			return new AddressablesLoadAsyncOperationWrapper<TAsset>(array);
		}

		private List<IResourceLocation> FilterPathsByType<TAsset>(List<string> paths)
		{
			Type typeFromHandle = typeof(TAsset);
			bool[] array = new bool[paths.Count];
			List<IResourceLocation> list = new List<IResourceLocation>();
			IResourceLocator[] array2 = resourceLocators;
			foreach (IResourceLocator resourceLocator in array2)
			{
				for (int j = 0; j < paths.Count; j++)
				{
					if (array[j] || !resourceLocator.Locate(paths[j], null, out var locations))
					{
						continue;
					}
					for (int k = 0; k < locations.Count; k++)
					{
						IResourceLocation resourceLocation = locations[k];
						if (typeFromHandle.IsAssignableFrom(resourceLocation.ResourceType))
						{
							list.Add(resourceLocation);
							array[j] = true;
							break;
						}
					}
				}
			}
			return list;
		}
	}
	public static class AddressablesLabels
	{
		public static readonly string characterBody = "CharacterBody";

		public static readonly string characterMaster = "CharacterMaster";

		public static readonly string projectile = "Projectile";

		public static readonly string gameMode = "GameMode";

		public static readonly string networkedObject = "NetworkedObject";

		public static readonly string effect = "Effect";

		public static readonly string skillFamily = "SkillFamily";

		public static readonly string skillDef = "SkillDef";

		public static readonly string unlockableDef = "UnlockableDef";

		public static readonly string surfaceDef = "SurfaceDef";

		public static readonly string sceneDef = "SceneDef";

		public static readonly string networkSoundEventDef = "NetworkSoundEventDef";

		public static readonly string musicTrackDef = "MusicTrackDef";

		public static readonly string gameEndingDef = "GameEndingDef";

		public static readonly string itemDef = "ItemDef";

		public static readonly string itemTierDef = "ItemTierDef";

		public static readonly string equipmentDef = "EquipmentDef";

		public static readonly string buffDef = "BuffDef";

		public static readonly string eliteDef = "EliteDef";

		public static readonly string survivorDef = "SurvivorDef";

		public static readonly string artifactDef = "ArtifactDef";

		public static readonly string entityStateConfiguration = "EntityStateConfiguration";

		public static readonly string expansionDef = "ExpansionDef";

		public static readonly string entitlementDef = "EntitlementDef";

		public static readonly string itemRelationshipType = "ItemRelationshipType";

		public static readonly string itemRelationshipProvider = "ItemRelationshipProvider";

		public static readonly string miscPickupDef = "MiscPickupDef";

		public static readonly IReadOnlyDictionary<Type, string> componentTypeLabels = new Dictionary<Type, string>
		{
			[typeof(CharacterBody)] = characterBody,
			[typeof(CharacterMaster)] = characterMaster,
			[typeof(ProjectileController)] = projectile,
			[typeof(Run)] = gameMode,
			[typeof(NetworkIdentity)] = networkedObject,
			[typeof(EffectComponent)] = effect
		};

		public static readonly IReadOnlyDictionary<Type, string> assetTypeLabels = new Dictionary<Type, string>
		{
			[typeof(SkillFamily)] = skillFamily,
			[typeof(SkillDef)] = skillDef,
			[typeof(UnlockableDef)] = unlockableDef,
			[typeof(SurfaceDef)] = surfaceDef,
			[typeof(SceneDef)] = sceneDef,
			[typeof(NetworkSoundEventDef)] = networkSoundEventDef,
			[typeof(MusicTrackDef)] = musicTrackDef,
			[typeof(GameEndingDef)] = gameEndingDef,
			[typeof(ItemDef)] = itemDef,
			[typeof(ItemTierDef)] = itemTierDef,
			[typeof(EquipmentDef)] = equipmentDef,
			[typeof(BuffDef)] = buffDef,
			[typeof(EliteDef)] = eliteDef,
			[typeof(SurvivorDef)] = survivorDef,
			[typeof(ArtifactDef)] = artifactDef,
			[typeof(EntityStateConfiguration)] = entityStateConfiguration,
			[typeof(ExpansionDef)] = expansionDef,
			[typeof(EntitlementDef)] = entitlementDef,
			[typeof(ItemRelationshipProvider)] = itemRelationshipProvider,
			[typeof(ItemRelationshipType)] = itemRelationshipType,
			[typeof(MiscPickupDef)] = miscPickupDef
		};
	}
	public class AddressablesLoadHelper
	{
		private class Operation
		{
			public float weight;

			public IEnumerator coroutine;

			public float progress;
		}

		public class AddressablesLoadAsyncOperationWrapper<TAsset> : BaseAsyncOperation<TAsset[]> where TAsset : UnityEngine.Object
		{
			private AsyncOperationHandle<IList<TAsset>>[] handles;

			private int completionCount;

			public override float progress => 0f;

			public AddressablesLoadAsyncOperationWrapper(IReadOnlyList<AsyncOperationHandle<IList<TAsset>>> handles)
			{
				if (handles.Count == 0)
				{
					this.handles = Array.Empty<AsyncOperationHandle<IList<TAsset>>>();
					Complete(Array.Empty<TAsset>());
					return;
				}
				Action<AsyncOperationHandle<IList<TAsset>>> value = OnChildOperationCompleted;
				this.handles = new AsyncOperationHandle<IList<TAsset>>[handles.Count];
				for (int i = 0; i < handles.Count; i++)
				{
					this.handles[i] = handles[i];
					AsyncOperationHandle<IList<TAsset>> asyncOperationHandle = handles[i];
					asyncOperationHandle.Completed += value;
				}
			}

			private void OnChildOperationCompleted(AsyncOperationHandle<IList<TAsset>> completedOperationHandle)
			{
				completionCount++;
				if (completionCount != handles.Length)
				{
					return;
				}
				List<TAsset> list = new List<TAsset>();
				AsyncOperationHandle<IList<TAsset>>[] array = handles;
				for (int i = 0; i < array.Length; i++)
				{
					AsyncOperationHandle<IList<TAsset>> asyncOperationHandle = array[i];
					if (asyncOperationHandle.Result != null)
					{
						list.AddRange(asyncOperationHandle.Result);
					}
				}
				Complete(list.ToArray());
			}
		}

		private readonly IResourceLocator[] resourceLocators = Array.Empty<IResourceLocator>();

		private readonly object[] requiredKeys = Array.Empty<object>();

		public int maxConcurrentOperations = 2;

		public float timeoutDuration = float.PositiveInfinity;

		private const int loadOperationsStartedMax = 28;

		private int loadOperationsStartedCount;

		private readonly List<Operation> allOperations = new List<Operation>();

		private readonly Queue<Operation> pendingLoadOperations = new Queue<Operation>();

		private readonly List<Operation> runningLoadOperations = new List<Operation>();

		private readonly List<Operation> allGenericOperations = new List<Operation>();

		public ReadableProgress<float> progress { get; private set; }

		public IEnumerator coroutine { get; private set; }

		private float loadOperationsStartedProgress01 => Mathf.Clamp01((float)loadOperationsStartedCount / 28f);

		public AddressablesLoadHelper(IReadOnlyList<IResourceLocator> resourceLocators, object[] requiredKeys = null)
		{
			ArrayUtils.CloneTo(resourceLocators, ref this.resourceLocators);
			if (requiredKeys != null)
			{
				ArrayUtils.CloneTo(requiredKeys, ref this.requiredKeys);
			}
			progress = new ReadableProgress<float>();
			coroutine = Coroutine(progress);
		}

		public AddressablesLoadHelper(IResourceLocator resourceLocator, object[] requiredKeys = null)
			: this(new IResourceLocator[1] { resourceLocator }, requiredKeys)
		{
		}

		public static AddressablesLoadHelper CreateUsingDefaultResourceLocator(object[] requiredKeys = null)
		{
			return new AddressablesLoadHelper(Addressables.ResourceLocators.First(), requiredKeys);
		}

		public static AddressablesLoadHelper CreateUsingDefaultResourceLocator(object requiredKey)
		{
			return CreateUsingDefaultResourceLocator(new object[1] { requiredKey });
		}

		public IEnumerator AddContentPackLoadOperationWithYields(ContentPack contentPack)
		{
			yield return FindLocationsThenAddLoadOperation<GameObject>(AddressablesLabels.characterBody, contentPack.bodyPrefabs.Add);
			yield return FindLocationsThenAddLoadOperation<GameObject>(AddressablesLabels.characterMaster, contentPack.masterPrefabs.Add);
			yield return FindLocationsThenAddLoadOperation<GameObject>(AddressablesLabels.projectile, contentPack.projectilePrefabs.Add);
			yield return FindLocationsThenAddLoadOperation<GameObject>(AddressablesLabels.gameMode, contentPack.gameModePrefabs.Add);
			yield return FindLocationsThenAddLoadOperation<GameObject>(AddressablesLabels.networkedObject, contentPack.networkedObjectPrefabs.Add);
			yield return FindLocationsThenAddLoadOperation<SkillFamily>(AddressablesLabels.skillFamily, contentPack.skillFamilies.Add);
			yield return FindLocationsThenAddLoadOperation<SkillDef>(AddressablesLabels.skillDef, contentPack.skillDefs.Add);
			yield return FindLocationsThenAddLoadOperation<UnlockableDef>(AddressablesLabels.unlockableDef, contentPack.unlockableDefs.Add);
			yield return FindLocationsThenAddLoadOperation<SurfaceDef>(AddressablesLabels.surfaceDef, contentPack.surfaceDefs.Add);
			yield return FindLocationsThenAddLoadOperation<SceneDef>(AddressablesLabels.sceneDef, contentPack.sceneDefs.Add);
			yield return FindLocationsThenAddLoadOperation<NetworkSoundEventDef>(AddressablesLabels.networkSoundEventDef, contentPack.networkSoundEventDefs.Add);
			yield return FindLocationsThenAddLoadOperation<MusicTrackDef>(AddressablesLabels.musicTrackDef, contentPack.musicTrackDefs.Add);
			yield return FindLocationsThenAddLoadOperation<GameEndingDef>(AddressablesLabels.gameEndingDef, contentPack.gameEndingDefs.Add);
			yield return FindLocationsThenAddLoadOperation<ItemDef>(AddressablesLabels.itemDef, contentPack.itemDefs.Add);
			yield return FindLocationsThenAddLoadOperation<ItemTierDef>(AddressablesLabels.itemTierDef, contentPack.itemTierDefs.Add);
			yield return FindLocationsThenAddLoadOperation<ItemRelationshipProvider>(AddressablesLabels.itemRelationshipProvider, contentPack.itemRelationshipProviders.Add);
			yield return FindLocationsThenAddLoadOperation<ItemRelationshipType>(AddressablesLabels.itemRelationshipType, contentPack.itemRelationshipTypes.Add);
			yield return FindLocationsThenAddLoadOperation<EquipmentDef>(AddressablesLabels.equipmentDef, contentPack.equipmentDefs.Add);
			yield return FindLocationsThenAddLoadOperation<MiscPickupDef>(AddressablesLabels.miscPickupDef, contentPack.miscPickupDefs.Add);
			yield return FindLocationsThenAddLoadOperation<BuffDef>(AddressablesLabels.buffDef, contentPack.buffDefs.Add);
			yield return FindLocationsThenAddLoadOperation<EliteDef>(AddressablesLabels.eliteDef, contentPack.eliteDefs.Add);
			yield return FindLocationsThenAddLoadOperation<SurvivorDef>(AddressablesLabels.survivorDef, contentPack.survivorDefs.Add);
			yield return FindLocationsThenAddLoadOperation<ArtifactDef>(AddressablesLabels.artifactDef, contentPack.artifactDefs.Add);
			yield return FindLocationsThenAddLoadOperation(AddressablesLabels.effect, contentPack.effectDefs.Add, (GameObject asset) => new EffectDef(asset));
			yield return FindLocationsThenAddLoadOperation<EntityStateConfiguration>(AddressablesLabels.entityStateConfiguration, contentPack.entityStateConfigurations.Add);
			yield return FindLocationsThenAddLoadOperation<ExpansionDef>(AddressablesLabels.expansionDef, contentPack.expansionDefs.Add);
			yield return FindLocationsThenAddLoadOperation<EntitlementDef>(AddressablesLabels.entitlementDef, contentPack.entitlementDefs.Add);
			loadOperationsStartedCount = 28;
			AddGenericOperation(AddEntityStateTypes(), 0.05f);
			yield return null;
			IEnumerator AddEntityStateTypes()
			{
				contentPack.entityStateTypes.Add((from v in contentPack.entityStateConfigurations
					select (Type)v.targetType into v
					where v != null
					select v).ToArray());
				yield return null;
			}
		}

		public IEnumerator FindLocationsThenAddLoadOperation<TAssetSrc>(string key, Action<TAssetSrc[]> onComplete, float weight = 1f) where TAssetSrc : UnityEngine.Object
		{
			return FindLocationsThenAddLoadOperation<TAssetSrc, TAssetSrc>(key, onComplete, null, weight);
		}

		public IEnumerator FindLocationsThenAddLoadOperation<TAssetSrc, TAssetDest>(string key, Action<TAssetDest[]> onComplete, Func<TAssetSrc, TAssetDest> selector = null, float weight = 1f) where TAssetSrc : UnityEngine.Object
		{
			List<object> list = new List<object>();
			ListUtils.AddRange(list, requiredKeys);
			list.Add(key);
			AsyncOperationHandle<IList<IResourceLocation>> locationAsyncOperationHandle = Addressables.LoadResourceLocationsAsync((IEnumerable)list, Addressables.MergeMode.Intersection, (Type)null);
			while (!locationAsyncOperationHandle.IsDone)
			{
				yield return null;
			}
			IList<IResourceLocation> result = locationAsyncOperationHandle.Result;
			AddLoadOperation(result, onComplete, selector, weight);
			loadOperationsStartedCount++;
		}

		public void AddLoadOperation<TAssetSrc>(IList<IResourceLocation> locations, Action<TAssetSrc[]> onComplete, float weight = 1f) where TAssetSrc : UnityEngine.Object
		{
			AddLoadOperation<TAssetSrc, TAssetSrc>(locations, onComplete, null, weight);
		}

		public void AddLoadOperation<TAssetSrc, TAssetDest>(IList<IResourceLocation> locations, Action<TAssetDest[]> onComplete, Func<TAssetSrc, TAssetDest> selector = null, float weight = 1f) where TAssetSrc : UnityEngine.Object
		{
			Operation loadOperation = new Operation
			{
				weight = weight
			};
			loadOperation.coroutine = Coroutine();
			allOperations.Add(loadOperation);
			pendingLoadOperations.Enqueue(loadOperation);
			IEnumerator Coroutine()
			{
				yield return null;
				List<AsyncOperationHandle<IList<TAssetSrc>>> underlyingLoadOperations = new List<AsyncOperationHandle<IList<TAssetSrc>>>(resourceLocators.Length);
				int j = 0;
				while (j < resourceLocators.Length)
				{
					Action<AsyncOperationHandle, Exception> oldResourceManagerExceptionHandler = ResourceManager.ExceptionHandler;
					ResourceManager.ExceptionHandler = ResourceManagerExceptionHandler;
					try
					{
						List<IResourceLocation> locationsList = locations as List<IResourceLocation>;
						int sliceStart = 0;
						int arrayLength = locations.Count;
						do
						{
							int count = Mathf.Min(5, arrayLength - sliceStart);
							AsyncOperationHandle<IList<TAssetSrc>> item = Addressables.LoadAssetsAsync<TAssetSrc>(locationsList.GetRange(sliceStart, count), null);
							underlyingLoadOperations.Add(item);
							sliceStart += 5;
							yield return null;
						}
						while (sliceStart < arrayLength);
						Addressables.Release(locations);
					}
					finally
					{
						ResourceManager.ExceptionHandler = oldResourceManagerExceptionHandler;
					}
					int num = j + 1;
					j = num;
					void ResourceManagerExceptionHandler(AsyncOperationHandle operationHandle, Exception exception)
					{
						if (!(exception is InvalidKeyException))
						{
							oldResourceManagerExceptionHandler?.Invoke(operationHandle, exception);
						}
					}
				}
				AddressablesLoadAsyncOperationWrapper<TAssetSrc> combinedLoadOperation = new AddressablesLoadAsyncOperationWrapper<TAssetSrc>(underlyingLoadOperations);
				Stopwatch stopwatch = new Stopwatch();
				stopwatch.Start();
				while (!combinedLoadOperation.isDone)
				{
					loadOperation.progress = combinedLoadOperation.progress;
					float num2 = (float)stopwatch.Elapsed.TotalSeconds;
					if (num2 > timeoutDuration)
					{
						throw new Exception($"Loading exceeded timeout. elapsedSeconds={num2} timeoutDuration={timeoutDuration}");
					}
					yield return null;
				}
				TAssetSrc[] loadedAssets = combinedLoadOperation.result.Where((TAssetSrc asset) => asset).ToArray();
				loadOperation.progress = 0.97f;
				yield return null;
				if (onComplete != null)
				{
					TAssetDest[] convertedAssets;
					if (selector == null)
					{
						if (!(typeof(TAssetSrc) == typeof(TAssetDest)))
						{
							throw new ArgumentNullException("selector", "Converter must be provided when TAssetSrc and TAssetDest differ.");
						}
						convertedAssets = (TAssetDest[])(object)loadedAssets;
					}
					else
					{
						convertedAssets = new TAssetDest[loadedAssets.Length];
						j = 0;
						while (j < loadedAssets.Length)
						{
							yield return null;
							convertedAssets[j] = selector(loadedAssets[j]);
							int num = j + 1;
							j = num;
						}
					}
					yield return null;
					string[] assetNames = new string[loadedAssets.Length];
					for (int k = 0; k < loadedAssets.Length; k++)
					{
						assetNames[k] = loadedAssets[k].name;
					}
					yield return null;
					Array.Sort(assetNames, convertedAssets, StringComparer.Ordinal);
					onComplete?.Invoke(convertedAssets);
				}
				loadOperation.progress = 1f;
			}
		}

		public void AddGenericOperation(IEnumerator coroutine, float weight = 1f)
		{
			Operation item = new Operation
			{
				weight = weight,
				coroutine = coroutine
			};
			allOperations.Add(item);
			allGenericOperations.Add(item);
		}

		public void AddGenericOperation(IEnumerable coroutineProvider, float weight = 1f)
		{
			AddGenericOperation(coroutineProvider.GetEnumerator(), weight);
		}

		public void AddGenericOperation(Func<IEnumerator> coroutineMethod, float weight = 1f)
		{
			AddGenericOperation(coroutineMethod(), weight);
		}

		public void AddGenericOperation(Action action, float weight = 1f)
		{
			AddGenericOperation(Coroutine(), weight);
			IEnumerator Coroutine()
			{
				action();
				yield return null;
			}
		}

		private IEnumerator Coroutine(IProgress<float> progressReceiver)
		{
			while (pendingLoadOperations.Count > 0 || runningLoadOperations.Count > 0)
			{
				while (pendingLoadOperations.Count > 0 && runningLoadOperations.Count < maxConcurrentOperations)
				{
					runningLoadOperations.Add(pendingLoadOperations.Dequeue());
				}
				int i = 0;
				while (i < runningLoadOperations.Count)
				{
					Operation operation = runningLoadOperations[i];
					int num;
					if (operation.coroutine.MoveNext())
					{
						UpdateProgress();
						yield return operation.coroutine.Current;
					}
					else
					{
						runningLoadOperations.RemoveAt(i);
						num = i - 1;
						i = num;
					}
					num = i + 1;
					i = num;
				}
			}
			foreach (Operation genericOperation in allGenericOperations)
			{
				while (genericOperation.coroutine.MoveNext())
				{
					UpdateProgress();
					yield return genericOperation.coroutine.Current;
				}
			}
			progressReceiver.Report(1f);
			void UpdateProgress()
			{
				float num2 = 0f;
				float num3 = 0f;
				for (int j = 0; j < allOperations.Count; j++)
				{
					Operation operation2 = allOperations[j];
					num2 += operation2.weight;
					num3 += operation2.progress * operation2.weight;
				}
				if (num2 == 0f)
				{
					num2 = 1f;
					num3 = 0.5f;
				}
				float num4 = loadOperationsStartedProgress01;
				float num5 = num3 / num2;
				progressReceiver.Report(num4 * 0.25f + num5 * 0.75f);
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/ContentAssetRefResolver")]
	public class ContentAssetRefResolver : ScriptableObject
	{
		[Serializable]
		public struct FieldAssignmentInfo
		{
			public UnityEngine.Object targetObject;

			public string fieldPath;

			public ContentAssetPath contentAssetPath;
		}

		[Serializable]
		public struct ContentAssetPath
		{
			public string contentPackIdentifier;

			public string collectionName;

			public string assetName;
		}

		public bool applyOnEnable = true;

		public FieldAssignmentInfo[] fieldAssignmentInfos;

		private static bool contentPacksLoaded;

		private static Queue<ContentAssetRefResolver> pendingResolutions;

		private static ReadOnlyArray<ReadOnlyContentPack> loadedContentPacks;

		[ContextMenu("Run Test")]
		public void Apply()
		{
			for (int i = 0; i < fieldAssignmentInfos.Length; i++)
			{
				ApplyFieldAssignmentInfo(in fieldAssignmentInfos[i]);
			}
		}

		private object FindContentAsset(in ContentAssetPath contentAssetPath)
		{
			for (int i = 0; i < loadedContentPacks.Length; i++)
			{
				if (loadedContentPacks[i].identifier.Equals(contentAssetPath.contentPackIdentifier, StringComparison.Ordinal))
				{
					ReadOnlyContentPack readOnlyContentPack = loadedContentPacks[i];
					readOnlyContentPack.FindAsset(contentAssetPath.collectionName, contentAssetPath.assetName, out var result);
					return result;
				}
			}
			return null;
		}

		static ContentAssetRefResolver()
		{
			contentPacksLoaded = false;
			pendingResolutions = new Queue<ContentAssetRefResolver>();
			loadedContentPacks = Array.Empty<ReadOnlyContentPack>();
			ContentManager.onContentPacksAssigned += OnContentPacksLoaded;
		}

		private static void OnContentPacksLoaded(ReadOnlyArray<ReadOnlyContentPack> newLoadedContentPacks)
		{
			loadedContentPacks = newLoadedContentPacks;
			contentPacksLoaded = true;
			ApplyQueued();
		}

		private static void ApplyQueued()
		{
			while (pendingResolutions.Count > 0)
			{
				ContentAssetRefResolver contentAssetRefResolver = pendingResolutions.Dequeue();
				try
				{
					contentAssetRefResolver.Apply();
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
			}
		}

		private void OnEnable()
		{
			if (applyOnEnable)
			{
				if (contentPacksLoaded)
				{
					Apply();
				}
				else
				{
					pendingResolutions.Enqueue(this);
				}
			}
		}

		private bool ApplyFieldAssignmentInfo(in FieldAssignmentInfo fieldAssignmentInfo)
		{
			object obj2 = fieldAssignmentInfo.targetObject;
			string fieldPath = fieldAssignmentInfo.fieldPath;
			UnityEngine.Object valueToAssign = FindContentAsset(in fieldAssignmentInfo.contentAssetPath) as UnityEngine.Object;
			int currentReadPos = 0;
			try
			{
				if (obj2 == null)
				{
					throw new NullReferenceException("targetObject is null");
				}
				ProcessObject(ref obj2);
				return true;
			}
			catch (Exception ex)
			{
				UnityEngine.Debug.LogError($"Could not assign {obj2}.{fieldPath}={valueToAssign}: {ex}");
				return false;
			}
			void HandleInnerValue(ref object innerValue)
			{
				if (currentReadPos < fieldPath.Length)
				{
					if (innerValue == null)
					{
						throw new Exception(fieldPath.Substring(0, currentReadPos) + " is null.");
					}
					if (innerValue is UnityEngine.Object)
					{
						throw new Exception("Assignment cannot propagate through UnityEngine.Object.");
					}
					ProcessObject(ref innerValue);
				}
				else
				{
					innerValue = valueToAssign;
				}
			}
			static bool IsIdentifierChar(char c)
			{
				if (!char.IsLetterOrDigit(c))
				{
					return c == '_';
				}
				return true;
			}
			void ProcessObject(ref object obj)
			{
				Type type = obj.GetType();
				if (obj is IList list)
				{
					int index = TakeArrayIndex();
					object innerValue2 = list[index];
					HandleInnerValue(ref innerValue2);
					list[index] = innerValue2;
				}
				else
				{
					string text2 = TakeIdentifier();
					FieldInfo field = type.GetField(text2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (field == null)
					{
						throw new Exception("Field \"" + type.Name + "." + text2 + "\" could not be found.");
					}
					object innerValue3 = field.GetValue(obj);
					HandleInnerValue(ref innerValue3);
					field.SetValue(obj, innerValue3);
				}
			}
			int TakeArrayIndex()
			{
				char c4 = fieldPath[currentReadPos];
				if (c4 != '[')
				{
					throw new FormatException($"Expected char '[' but got '{c4}'.");
				}
				int num5 = currentReadPos + 1;
				currentReadPos = num5;
				int num6 = TakeInt();
				if (num6 < 0)
				{
					throw new FormatException($"Array index {num6} cannot be negative.");
				}
				char c5 = fieldPath[currentReadPos];
				if (c5 != ']')
				{
					throw new FormatException($"Expected char ']' but got '{c5}'.");
				}
				num5 = currentReadPos + 1;
				currentReadPos = num5;
				return num6;
			}
			string TakeIdentifier()
			{
				int num = currentReadPos;
				string text = null;
				char c2 = fieldPath[currentReadPos];
				if (c2 == '.')
				{
					num++;
					int num2 = currentReadPos + 1;
					currentReadPos = num2;
				}
				else if (currentReadPos != 0)
				{
					throw new Exception($"Expected '.' at {num}, but encountered '{c2}'");
				}
				while (currentReadPos < fieldPath.Length && IsIdentifierChar(fieldPath[currentReadPos]))
				{
					int num2 = currentReadPos + 1;
					currentReadPos = num2;
				}
				text = fieldPath.Substring(num, currentReadPos - num);
				if (text == null)
				{
					throw new FormatException($"Expected identifier at {num}, but encountered end of string.");
				}
				if (text.Length == 0)
				{
					throw new FormatException($"Expected identifier at {num}, but encountered no valid characters (a-zA-Z0-9_).");
				}
				if (char.IsDigit(text[0]))
				{
					throw new FormatException($"Expected identifier at {num}, but an identifier cannot begin with a digit. digit={text[0]} substring={text}");
				}
				return text;
			}
			int TakeInt()
			{
				int num3 = currentReadPos;
				if (num3 >= fieldPath.Length)
				{
					throw new FormatException($"Expected integer at {num3}, but encountered end of string.");
				}
				char c3 = fieldPath[currentReadPos];
				if (c3 != '-' && !char.IsDigit(c3))
				{
					throw new FormatException($"Expected integer at {num3}, but an integer cannot begin with character '{c3}'");
				}
				if (c3 == '-')
				{
					int num4 = currentReadPos + 1;
					currentReadPos = num4;
				}
				while (currentReadPos < fieldPath.Length)
				{
					if (!char.IsDigit(fieldPath[currentReadPos]) || currentReadPos == fieldPath.Length - 1)
					{
						fieldPath.Substring(num3, currentReadPos + 1 - num3);
						break;
					}
					int num4 = currentReadPos + 1;
					currentReadPos = num4;
				}
				string obj3 = fieldPath.Substring(num3, currentReadPos - num3) ?? throw new FormatException($"Expected integer at {num3}, but encountered end of string.");
				if (obj3.Length == 0)
				{
					throw new FormatException($"Expected integer at {num3}, but encountered no valid characters (-0-9).");
				}
				return int.Parse(obj3);
			}
		}
	}
	public class ContentLoadHelper
	{
		public delegate ref T GetRefDelegate<T>();

		public delegate void AcceptResultDelegate<T>(T result);

		public IAssetRepository assetRepository;

		public ReadableProgress<float> progress;

		public ParallelProgressCoroutine coroutine;

		public ContentLoadHelper()
		{
			progress = new ReadableProgress<float>();
			coroutine = new ParallelProgressCoroutine(progress);
		}

		public void DispatchLoadConvert<TAssetSrc, TAssetDest>(string folderPath, Action<TAssetDest[]> onComplete, Func<TAssetSrc, TAssetDest> selector = null) where TAssetSrc : UnityEngine.Object
		{
			ReadableProgress<float> progressReceiver = new ReadableProgress<float>();
			coroutine.Add(Coroutine(), progressReceiver);
			IEnumerator Coroutine()
			{
				BaseAsyncOperation<TAssetSrc[]> loadFolderOperation = assetRepository.LoadAllAsync<TAssetSrc>(folderPath);
				while (!loadFolderOperation.isDone)
				{
					progressReceiver.Report(Util.Remap(progressReceiver.value, 0f, 1f, 0f, 0.95f));
					yield return null;
				}
				TAssetSrc[] loadedAssets = loadFolderOperation.result.Where((TAssetSrc asset) => asset).ToArray();
				progressReceiver.Report(0.97f);
				yield return null;
				if (onComplete != null)
				{
					TAssetDest[] convertedAssets;
					if (selector == null)
					{
						if (!(typeof(TAssetSrc) == typeof(TAssetDest)))
						{
							throw new ArgumentNullException("selector", "Converter must be provided when TAssetSrc and TAssetDest differ.");
						}
						convertedAssets = (TAssetDest[])(object)loadedAssets;
					}
					else
					{
						convertedAssets = new TAssetDest[loadedAssets.Length];
						int i = 0;
						while (i < loadedAssets.Length)
						{
							yield return null;
							convertedAssets[i] = selector(loadedAssets[i]);
							int num = i + 1;
							i = num;
						}
					}
					yield return null;
					string[] assetNames = new string[loadedAssets.Length];
					for (int j = 0; j < loadedAssets.Length; j++)
					{
						assetNames[j] = loadedAssets[j].name;
					}
					yield return null;
					Array.Sort(assetNames, convertedAssets, StringComparer.Ordinal);
					onComplete?.Invoke(convertedAssets);
				}
				progressReceiver.Report(1f);
			}
		}

		public void DispatchLoad<TAsset>(string folderPath, Action<TAsset[]> onComplete) where TAsset : UnityEngine.Object
		{
			DispatchLoadConvert<TAsset, TAsset>(folderPath, onComplete);
		}

		public static void PopulateTypeFields<TAsset>(Type typeToPopulate, NamedAssetCollection<TAsset> assets, Func<string, string> fieldNameToAssetNameConverter = null) where TAsset : UnityEngine.Object
		{
			string[] array = new string[assets.Length];
			for (int i = 0; i < assets.Length; i++)
			{
				array[i] = assets.GetAssetName(assets[i]);
			}
			FieldInfo[] fields = typeToPopulate.GetFields(BindingFlags.Static | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.FieldType == typeof(TAsset))
				{
					TargetAssetNameAttribute customAttribute = CustomAttributeExtensions.GetCustomAttribute<TargetAssetNameAttribute>(fieldInfo);
					string text = ((customAttribute != null) ? customAttribute.targetAssetName : ((fieldNameToAssetNameConverter == null) ? fieldInfo.Name : fieldNameToAssetNameConverter(fieldInfo.Name)));
					TAsset val = assets.Find(text);
					if ((object)val != null)
					{
						fieldInfo.SetValue(null, val);
						continue;
					}
					UnityEngine.Debug.LogWarning("Failed to assign " + fieldInfo.DeclaringType.Name + "." + fieldInfo.Name + ": Asset \"" + text + "\" not found.");
				}
			}
		}
	}
	public static class ContentManager
	{
		private class ContentPackLoader
		{
			private delegate IEnumerator PerContentPackAction(ref ContentPackLoadInfo contentPackLoadInfo, ReadOnlyArray<ContentPackLoadInfo> readOnlyPeers, IProgress<float> progressReceiver);

			private ContentPackLoadInfo[] contentPackLoadInfos;

			public List<ReadOnlyContentPack> output = new List<ReadOnlyContentPack>();

			public ContentPackLoader(List<IContentPackProvider> contentPackProviders)
			{
				contentPackLoadInfos = new ContentPackLoadInfo[contentPackProviders.Count];
				for (int i = 0; i < contentPackProviders.Count; i++)
				{
					string identifier = contentPackProviders[i].identifier;
					contentPackLoadInfos[i] = new ContentPackLoadInfo
					{
						index = i,
						contentPackProviderIdentifier = identifier,
						contentPackProvider = contentPackProviders[i],
						previousContentPack = new ContentPack
						{
							identifier = identifier
						},
						retries = 0
					};
				}
			}

			private IEnumerator DoPerContentPackProviderCoroutine(IProgress<float> progressReceiver, PerContentPackAction action)
			{
				ReadOnlyArray<ContentPackLoadInfo> readOnlyPeers = ArrayUtils.Clone(contentPackLoadInfos);
				ParallelProgressCoroutine parallelProgressCoroutine = new ParallelProgressCoroutine(progressReceiver);
				for (int i = 0; i < contentPackLoadInfos.Length; i++)
				{
					ReadableProgress<float> readableProgress = new ReadableProgress<float>();
					IEnumerator coroutine = action(ref contentPackLoadInfos[i], readOnlyPeers, readableProgress);
					parallelProgressCoroutine.Add(coroutine, readableProgress);
				}
				return parallelProgressCoroutine;
			}

			public IEnumerator InitialLoad(IProgress<float> progressReceiver)
			{
				yield return DoPerContentPackProviderCoroutine(progressReceiver, StartLoadCoroutine);
				static IEnumerator StartLoadCoroutine(ref ContentPackLoadInfo loadInfo, ReadOnlyArray<ContentPackLoadInfo> readOnlyPeers, IProgress<float> providedProgressReceiver)
				{
					LoadStaticContentAsyncArgs args = new LoadStaticContentAsyncArgs(providedProgressReceiver, readOnlyPeers);
					return loadInfo.contentPackProvider.LoadStaticContentAsync(args);
				}
			}

			public IEnumerator StepGenerateContentPacks(IProgress<float> progressReceiver, IProgress<bool> completionReceiver, int retriesRemaining)
			{
				ContentPack[] newContentPacks = new ContentPack[contentPackLoadInfos.Length];
				for (int i = 0; i < newContentPacks.Length; i++)
				{
					newContentPacks[i] = new ContentPack
					{
						identifier = contentPackLoadInfos[i].contentPackProviderIdentifier
					};
				}
				yield return DoPerContentPackProviderCoroutine(progressReceiver, StartGeneratorCoroutine);
				bool flag = true;
				for (int j = 0; j < contentPackLoadInfos.Length; j++)
				{
					ContentPack contentPack = newContentPacks[j];
					contentPack.identifier = contentPackLoadInfos[j].contentPackProviderIdentifier;
					if (!contentPackLoadInfos[j].previousContentPack.Equals(contentPack))
					{
						flag = false;
						contentPackLoadInfos[j].retries++;
						contentPackLoadInfos[j].previousContentPack = contentPack;
					}
				}
				if (flag)
				{
					completionReceiver.Report(value: true);
				}
				IEnumerator StartGeneratorCoroutine(ref ContentPackLoadInfo loadInfo, ReadOnlyArray<ContentPackLoadInfo> readOnlyPeers, IProgress<float> providedProgressReceiver)
				{
					ContentPack contentPack2 = newContentPacks[loadInfo.index];
					GetContentPackAsyncArgs args = new GetContentPackAsyncArgs(providedProgressReceiver, contentPack2, readOnlyPeers, retriesRemaining);
					return loadInfo.contentPackProvider.GenerateContentPackAsync(args);
				}
			}

			public IEnumerator LoadContentPacks(IProgress<float> progressReceiver)
			{
				int maxRetries = 10;
				bool complete = false;
				ReadableProgress<bool> completionReceiver = new ReadableProgress<bool>(delegate(bool result)
				{
					complete = result;
				});
				int i = 0;
				while (i < maxRetries)
				{
					yield return StepGenerateContentPacks(progressReceiver, completionReceiver, maxRetries - i - 1);
					if (complete)
					{
						break;
					}
					int num = i + 1;
					i = num;
				}
				for (int j = 0; j < contentPackLoadInfos.Length; j++)
				{
					output.Add(contentPackLoadInfos[j].previousContentPack);
				}
			}

			public IEnumerator RunCleanup(IProgress<float> progressReceiver)
			{
				yield return DoPerContentPackProviderCoroutine(progressReceiver, StartFinalizeCoroutine);
				IEnumerator StartFinalizeCoroutine(ref ContentPackLoadInfo loadInfo, ReadOnlyArray<ContentPackLoadInfo> readOnlyPeers, IProgress<float> providedProgressReceiver)
				{
					FinalizeAsyncArgs args = new FinalizeAsyncArgs(providedProgressReceiver, readOnlyPeers, contentPackLoadInfos[loadInfo.index].previousContentPack);
					return loadInfo.contentPackProvider.FinalizeAsync(args);
				}
			}
		}

		public delegate void AddContentPackProviderDelegate(IContentPackProvider contentPackProvider);

		public delegate void CollectContentPackProvidersDelegate(AddContentPackProviderDelegate addContentPackProvider);

		private static ContentPack[] contentPacks;

		public static ItemDef[] _itemDefs;

		public static ItemTierDef[] _itemTierDefs;

		private static ItemRelationshipProvider[] _itemRelationshipProviders;

		private static ItemRelationshipType[] _itemRelationshipTypes;

		public static EquipmentDef[] _equipmentDefs;

		public static BuffDef[] _buffDefs;

		public static EliteDef[] _eliteDefs;

		public static UnlockableDef[] _unlockableDefs;

		public static SurvivorDef[] _survivorDefs;

		public static GameObject[] _bodyPrefabs;

		public static GameObject[] _masterPrefabs;

		public static ArtifactDef[] _artifactDefs;

		public static EffectDef[] _effectDefs;

		public static SkillDef[] _skillDefs;

		public static SkillFamily[] _skillFamilies;

		public static SurfaceDef[] _surfaceDefs;

		public static SceneDef[] _sceneDefs;

		public static GameObject[] _projectilePrefabs;

		public static NetworkSoundEventDef[] _networkSoundEventDefs;

		public static MusicTrackDef[] _musicTrackDefs;

		public static GameObject[] _networkedObjectPrefabs;

		public static GameObject[] _gameModePrefabs;

		public static GameEndingDef[] _gameEndingDefs;

		public static EntityStateConfiguration[] _entityStateConfigurations;

		public static Type[] _entityStateTypes;

		public static ExpansionDef[] _expansionDefs;

		public static EntitlementDef[] _entitlementDefs;

		private static MiscPickupDef[] _miscPickupDefs;

		public static ItemDef[] itemDefs => _itemDefs;

		public static ItemTierDef[] itemTierDefs => _itemTierDefs;

		public static ItemRelationshipProvider[] itemRelationshipProviders => _itemRelationshipProviders;

		public static ItemRelationshipType[] itemRelationshipTypes => _itemRelationshipTypes;

		public static EquipmentDef[] equipmentDefs => _equipmentDefs;

		public static BuffDef[] buffDefs => _buffDefs;

		public static EliteDef[] eliteDefs => _eliteDefs;

		public static UnlockableDef[] unlockableDefs => _unlockableDefs;

		public static SurvivorDef[] survivorDefs => _survivorDefs;

		public static GameObject[] bodyPrefabs => _bodyPrefabs;

		public static GameObject[] masterPrefabs => _masterPrefabs;

		public static ArtifactDef[] artifactDefs => _artifactDefs;

		public static EffectDef[] effectDefs => _effectDefs;

		public static SkillDef[] skillDefs => _skillDefs;

		public static SkillFamily[] skillFamilies => _skillFamilies;

		public static SurfaceDef[] surfaceDefs => _surfaceDefs;

		public static SceneDef[] sceneDefs => _sceneDefs;

		public static GameObject[] projectilePrefabs => _projectilePrefabs;

		public static NetworkSoundEventDef[] networkSoundEventDefs => _networkSoundEventDefs;

		public static MusicTrackDef[] musicTrackDefs => _musicTrackDefs;

		public static GameObject[] networkedObjectPrefabs => _networkedObjectPrefabs;

		public static GameObject[] gameModePrefabs => _gameModePrefabs;

		public static GameEndingDef[] gameEndingDefs => _gameEndingDefs;

		public static EntityStateConfiguration[] entityStateConfigurations => _entityStateConfigurations;

		public static Type[] entityStateTypes => _entityStateTypes;

		public static ExpansionDef[] expansionDefs => _expansionDefs;

		public static EntitlementDef[] entitlementDefs => _entitlementDefs;

		public static MiscPickupDef[] miscPickupDefs => _miscPickupDefs;

		public static ReadOnlyArray<ReadOnlyContentPack> allLoadedContentPacks { get; private set; } = Array.Empty<ReadOnlyContentPack>();


		public static event CollectContentPackProvidersDelegate collectContentPackProviders;

		public static event Action<ReadOnlyArray<ReadOnlyContentPack>> onContentPacksAssigned;

		public static IEnumerator LoadContentPacks(IProgress<float> progressReceiver)
		{
			List<IContentPackProvider> contentPackProviders = new List<IContentPackProvider>();
			ContentManager.collectContentPackProviders?.Invoke(AddContentPackProvider);
			ContentManager.collectContentPackProviders = null;
			ContentPackLoader loader = new ContentPackLoader(contentPackProviders);
			yield return loader.InitialLoad(new ReadableProgress<float>(delegate(float newValue)
			{
				progressReceiver.Report(Util.Remap(newValue, 0f, 1f, 0f, 0.8f));
			}));
			yield return loader.LoadContentPacks(new ReadableProgress<float>(delegate(float newValue)
			{
				progressReceiver.Report(Util.Remap(newValue, 0f, 1f, 0.8f, 0.95f));
			}));
			yield return loader.RunCleanup(new ReadableProgress<float>(delegate(float newValue)
			{
				progressReceiver.Report(Util.Remap(newValue, 0f, 1f, 0.95f, 1f));
			}));
			yield return SetContentPacks(loader.output);
			void AddContentPackProvider(IContentPackProvider contentPackProvider)
			{
				contentPackProviders.Add(contentPackProvider);
			}
		}

		private static IEnumerator SetContentPacks(List<ReadOnlyContentPack> newContentPacks)
		{
			allLoadedContentPacks = newContentPacks.ToArray();
			SetAssets<ItemDef>(ref _itemDefs, (ReadOnlyContentPack contentPack) => contentPack.itemDefs);
			SetAssets<ItemTierDef>(ref _itemTierDefs, (ReadOnlyContentPack contentPack) => contentPack.itemTierDefs);
			SetAssets<ItemRelationshipProvider>(ref _itemRelationshipProviders, (ReadOnlyContentPack contentPack) => contentPack.itemRelationshipProviders);
			SetAssets<ItemRelationshipType>(ref _itemRelationshipTypes, (ReadOnlyContentPack contentPack) => contentPack.itemRelationshipTypes);
			SetAssets<EquipmentDef>(ref _equipmentDefs, (ReadOnlyContentPack contentPack) => contentPack.equipmentDefs);
			SetAssets<BuffDef>(ref _buffDefs, (ReadOnlyContentPack contentPack) => contentPack.buffDefs);
			SetAssets<EliteDef>(ref _eliteDefs, (ReadOnlyContentPack contentPack) => contentPack.eliteDefs);
			SetAssets<UnlockableDef>(ref _unlockableDefs, (ReadOnlyContentPack contentPack) => contentPack.unlockableDefs);
			yield return 0;
			SetAssets<SurvivorDef>(ref _survivorDefs, (ReadOnlyContentPack contentPack) => contentPack.survivorDefs);
			SetAssets<GameObject>(ref _bodyPrefabs, (ReadOnlyContentPack contentPack) => contentPack.bodyPrefabs);
			SetAssets<GameObject>(ref _masterPrefabs, (ReadOnlyContentPack contentPack) => contentPack.masterPrefabs);
			SetAssets<ArtifactDef>(ref _artifactDefs, (ReadOnlyContentPack contentPack) => contentPack.artifactDefs);
			yield return 0;
			SetAssets<EffectDef>(ref _effectDefs, (ReadOnlyContentPack contentPack) => contentPack.effectDefs);
			SetAssets<SkillDef>(ref _skillDefs, (ReadOnlyContentPack contentPack) => contentPack.skillDefs);
			SetAssets<SkillFamily>(ref _skillFamilies, (ReadOnlyContentPack contentPack) => contentPack.skillFamilies);
			SetAssets<SurfaceDef>(ref _surfaceDefs, (ReadOnlyContentPack contentPack) => contentPack.surfaceDefs);
			SetAssets<SceneDef>(ref _sceneDefs, (ReadOnlyContentPack contentPack) => contentPack.sceneDefs);
			SetAssets<GameObject>(ref _projectilePrefabs, (ReadOnlyContentPack contentPack) => contentPack.projectilePrefabs);
			yield return 0;
			SetAssets<NetworkSoundEventDef>(ref _networkSoundEventDefs, (ReadOnlyContentPack contentPack) => contentPack.networkSoundEventDefs);
			SetAssets<MusicTrackDef>(ref _musicTrackDefs, (ReadOnlyContentPack contentPack) => contentPack.musicTrackDefs);
			SetAssets<GameObject>(ref _networkedObjectPrefabs, (ReadOnlyContentPack contentPack) => contentPack.networkedObjectPrefabs);
			SetAssets<GameObject>(ref _gameModePrefabs, (ReadOnlyContentPack contentPack) => contentPack.gameModePrefabs);
			SetAssets<GameEndingDef>(ref _gameEndingDefs, (ReadOnlyContentPack contentPack) => contentPack.gameEndingDefs);
			SetAssets<Type>(ref _entityStateTypes, (ReadOnlyContentPack contentPack) => contentPack.entityStateTypes);
			yield return 0;
			SetAssets<EntityStateConfiguration>(ref _entityStateConfigurations, (ReadOnlyContentPack contentPack) => contentPack.entityStateConfigurations);
			SetAssets<ExpansionDef>(ref _expansionDefs, (ReadOnlyContentPack contentPack) => contentPack.expansionDefs);
			SetAssets<EntitlementDef>(ref _entitlementDefs, (ReadOnlyContentPack contentPack) => contentPack.entitlementDefs);
			SetAssets<MiscPickupDef>(ref _miscPickupDefs, (ReadOnlyContentPack contentPack) => contentPack.miscPickupDefs);
			yield return 0;
			ContentManager.onContentPacksAssigned?.Invoke(allLoadedContentPacks);
			void SetAssets<T>(ref T[] field, Func<ReadOnlyContentPack, IEnumerable<T>> selector)
			{
				field = newContentPacks.SelectMany(selector).ToArray();
			}
		}

		public static ReadOnlyContentPack? FindContentPack(string contentPackIdentifier)
		{
			int num = 0;
			while (true)
			{
				int num2 = num;
				ReadOnlyArray<ReadOnlyContentPack> readOnlyArray = allLoadedContentPacks;
				if (num2 >= readOnlyArray.Length)
				{
					break;
				}
				readOnlyArray = allLoadedContentPacks;
				ref readonly ReadOnlyContentPack reference = ref readOnlyArray[num];
				if (string.Equals(reference.identifier, contentPackIdentifier, StringComparison.Ordinal))
				{
					return reference;
				}
				num++;
			}
			return null;
		}
	}
	public sealed class ContentPack
	{
		[NotNull]
		private string _identifier = "UNIDENTIFIED";

		private static Func<GameObject, string> getGameObjectName = (GameObject obj) => obj.name;

		private static Func<Component, string> getComponentName = (Component obj) => obj.gameObject.name;

		private static Func<ScriptableObject, string> getScriptableObjectName = (ScriptableObject obj) => obj.name;

		private static Func<EffectDef, string> getEffectDefName = (EffectDef obj) => obj.prefabName;

		private static Func<Type, string> getTypeName = (Type obj) => obj.FullName;

		[NotNull]
		public NamedAssetCollection<GameObject> bodyPrefabs = new NamedAssetCollection<GameObject>(getGameObjectName);

		[NotNull]
		public NamedAssetCollection<GameObject> masterPrefabs = new NamedAssetCollection<GameObject>(getGameObjectName);

		[NotNull]
		public NamedAssetCollection<GameObject> projectilePrefabs = new NamedAssetCollection<GameObject>(getGameObjectName);

		[NotNull]
		public NamedAssetCollection<GameObject> gameModePrefabs = new NamedAssetCollection<GameObject>(getGameObjectName);

		[NotNull]
		public NamedAssetCollection<GameObject> networkedObjectPrefabs = new NamedAssetCollection<GameObject>(getGameObjectName);

		[NotNull]
		public NamedAssetCollection<SkillDef> skillDefs = new NamedAssetCollection<SkillDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<SkillFamily> skillFamilies = new NamedAssetCollection<SkillFamily>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<SceneDef> sceneDefs = new NamedAssetCollection<SceneDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<ItemDef> itemDefs = new NamedAssetCollection<ItemDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<ItemTierDef> itemTierDefs = new NamedAssetCollection<ItemTierDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<ItemRelationshipProvider> itemRelationshipProviders = new NamedAssetCollection<ItemRelationshipProvider>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<ItemRelationshipType> itemRelationshipTypes = new NamedAssetCollection<ItemRelationshipType>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<EquipmentDef> equipmentDefs = new NamedAssetCollection<EquipmentDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<BuffDef> buffDefs = new NamedAssetCollection<BuffDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<EliteDef> eliteDefs = new NamedAssetCollection<EliteDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<UnlockableDef> unlockableDefs = new NamedAssetCollection<UnlockableDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<SurvivorDef> survivorDefs = new NamedAssetCollection<SurvivorDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<ArtifactDef> artifactDefs = new NamedAssetCollection<ArtifactDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<EffectDef> effectDefs = new NamedAssetCollection<EffectDef>(getEffectDefName);

		[NotNull]
		public NamedAssetCollection<SurfaceDef> surfaceDefs = new NamedAssetCollection<SurfaceDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<NetworkSoundEventDef> networkSoundEventDefs = new NamedAssetCollection<NetworkSoundEventDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<MusicTrackDef> musicTrackDefs = new NamedAssetCollection<MusicTrackDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<GameEndingDef> gameEndingDefs = new NamedAssetCollection<GameEndingDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<EntityStateConfiguration> entityStateConfigurations = new NamedAssetCollection<EntityStateConfiguration>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<ExpansionDef> expansionDefs = new NamedAssetCollection<ExpansionDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<EntitlementDef> entitlementDefs = new NamedAssetCollection<EntitlementDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<MiscPickupDef> miscPickupDefs = new NamedAssetCollection<MiscPickupDef>(getScriptableObjectName);

		[NotNull]
		public NamedAssetCollection<Type> entityStateTypes = new NamedAssetCollection<Type>(getTypeName);

		private object[] assetCollections;

		[NotNull]
		public string identifier
		{
			get
			{
				return _identifier;
			}
			internal set
			{
				_identifier = value ?? throw new ArgumentNullException("'identifier' cannot be null.");
			}
		}

		public ContentPack()
		{
			assetCollections = new object[28]
			{
				bodyPrefabs, masterPrefabs, projectilePrefabs, gameModePrefabs, networkedObjectPrefabs, skillDefs, skillFamilies, sceneDefs, itemDefs, itemTierDefs,
				itemRelationshipProviders, itemRelationshipTypes, equipmentDefs, buffDefs, eliteDefs, unlockableDefs, survivorDefs, artifactDefs, effectDefs, surfaceDefs,
				networkSoundEventDefs, musicTrackDefs, gameEndingDefs, entityStateConfigurations, expansionDefs, entitlementDefs, miscPickupDefs, entityStateTypes
			};
		}

		public bool ValueEquals(ContentPack other)
		{
			return ValueEquals(this, other);
		}

		public static void Copy([NotNull] ContentPack src, [NotNull] ContentPack dest)
		{
			src = src ?? throw new ArgumentNullException("src");
			dest = dest ?? throw new ArgumentNullException("dest");
			dest.identifier = src.identifier;
			src.bodyPrefabs.CopyTo(dest.bodyPrefabs);
			src.masterPrefabs.CopyTo(dest.masterPrefabs);
			src.projectilePrefabs.CopyTo(dest.projectilePrefabs);
			src.gameModePrefabs.CopyTo(dest.gameModePrefabs);
			src.networkedObjectPrefabs.CopyTo(dest.networkedObjectPrefabs);
			src.skillDefs.CopyTo(dest.skillDefs);
			src.skillFamilies.CopyTo(dest.skillFamilies);
			src.sceneDefs.CopyTo(dest.sceneDefs);
			src.itemDefs.CopyTo(dest.itemDefs);
			src.itemTierDefs.CopyTo(dest.itemTierDefs);
			src.itemRelationshipProviders.CopyTo(dest.itemRelationshipProviders);
			src.equipmentDefs.CopyTo(dest.equipmentDefs);
			src.buffDefs.CopyTo(dest.buffDefs);
			src.eliteDefs.CopyTo(dest.eliteDefs);
			src.unlockableDefs.CopyTo(dest.unlockableDefs);
			src.survivorDefs.CopyTo(dest.survivorDefs);
			src.artifactDefs.CopyTo(dest.artifactDefs);
			src.effectDefs.CopyTo(dest.effectDefs);
			src.surfaceDefs.CopyTo(dest.surfaceDefs);
			src.networkSoundEventDefs.CopyTo(dest.networkSoundEventDefs);
			src.musicTrackDefs.CopyTo(dest.musicTrackDefs);
			src.gameEndingDefs.CopyTo(dest.gameEndingDefs);
			src.entityStateConfigurations.CopyTo(dest.entityStateConfigurations);
			src.expansionDefs.CopyTo(dest.expansionDefs);
			src.entitlementDefs.CopyTo(dest.entitlementDefs);
			src.miscPickupDefs.CopyTo(dest.miscPickupDefs);
			src.entityStateTypes.CopyTo(dest.entityStateTypes);
		}

		public static bool ValueEquals([CanBeNull] ContentPack a, [CanBeNull] ContentPack b)
		{
			if (a == null != (b == null))
			{
				return false;
			}
			if (a == null)
			{
				return true;
			}
			if (!a.identifier.Equals(b.identifier, StringComparison.Ordinal))
			{
				return false;
			}
			if (a.bodyPrefabs.Equals(b.bodyPrefabs) && a.masterPrefabs.Equals(b.masterPrefabs) && a.projectilePrefabs.Equals(b.projectilePrefabs) && a.gameModePrefabs.Equals(b.gameModePrefabs) && a.networkedObjectPrefabs.Equals(b.networkedObjectPrefabs) && a.skillDefs.Equals(b.skillDefs) && a.skillFamilies.Equals(b.skillFamilies) && a.sceneDefs.Equals(b.sceneDefs) && a.itemDefs.Equals(b.itemDefs) && a.itemTierDefs.Equals(b.itemTierDefs) && a.itemRelationshipProviders.Equals(b.itemRelationshipProviders) && a.equipmentDefs.Equals(b.equipmentDefs) && a.buffDefs.Equals(b.buffDefs) && a.eliteDefs.Equals(b.eliteDefs) && a.unlockableDefs.Equals(b.unlockableDefs) && a.survivorDefs.Equals(b.survivorDefs) && a.artifactDefs.Equals(b.artifactDefs) && a.effectDefs.Equals(b.effectDefs) && a.surfaceDefs.Equals(b.surfaceDefs) && a.networkSoundEventDefs.Equals(b.networkSoundEventDefs) && a.musicTrackDefs.Equals(b.musicTrackDefs) && a.gameEndingDefs.Equals(b.gameEndingDefs) && a.entityStateConfigurations.Equals(b.entityStateConfigurations) && a.entityStateTypes.Equals(b.entityStateTypes) && a.expansionDefs.Equals(b.expansionDefs) && a.entitlementDefs.Equals(b.entitlementDefs))
			{
				return a.miscPickupDefs.Equals(b.miscPickupDefs);
			}
			return false;
		}

		private NamedAssetCollection FindAssetCollection(string collectionName)
		{
			return collectionName switch
			{
				"bodyPrefabs" => bodyPrefabs, 
				"masterPrefabs" => masterPrefabs, 
				"projectilePrefabs" => projectilePrefabs, 
				"gameModePrefabs" => gameModePrefabs, 
				"networkedObjectPrefabs" => networkedObjectPrefabs, 
				"skillDefs" => skillDefs, 
				"skillFamilies" => skillFamilies, 
				"sceneDefs" => sceneDefs, 
				"itemDefs" => itemDefs, 
				"itemTierDefs" => itemTierDefs, 
				"itemRelationshipProviders" => itemRelationshipProviders, 
				"itemRelationshipTypes" => itemRelationshipTypes, 
				"equipmentDefs" => equipmentDefs, 
				"buffDefs" => buffDefs, 
				"eliteDefs" => eliteDefs, 
				"unlockableDefs" => unlockableDefs, 
				"survivorDefs" => survivorDefs, 
				"artifactDefs" => artifactDefs, 
				"effectDefs" => effectDefs, 
				"surfaceDefs" => surfaceDefs, 
				"networkSoundEventDefs" => networkSoundEventDefs, 
				"musicTrackDefs" => musicTrackDefs, 
				"gameEndingDefs" => gameEndingDefs, 
				"entityStateConfigurations" => entityStateConfigurations, 
				"expansionDefs" => expansionDefs, 
				"entitlementDefs" => entitlementDefs, 
				"miscPickupDefs" => miscPickupDefs, 
				_ => null, 
			};
		}

		public bool FindAsset(string collectionName, string assetName, out object result)
		{
			NamedAssetCollection namedAssetCollection = FindAssetCollection(collectionName);
			if (namedAssetCollection != null)
			{
				return namedAssetCollection.Find(assetName, out result);
			}
			result = null;
			return false;
		}
	}
	public readonly struct ReadOnlyContentPack
	{
		private readonly ContentPack src;

		public bool isValid => src != null;

		public string identifier => src.identifier;

		public ReadOnlyNamedAssetCollection<GameObject> bodyPrefabs => src.bodyPrefabs;

		public ReadOnlyNamedAssetCollection<GameObject> masterPrefabs => src.masterPrefabs;

		public ReadOnlyNamedAssetCollection<GameObject> projectilePrefabs => src.projectilePrefabs;

		public ReadOnlyNamedAssetCollection<GameObject> gameModePrefabs => src.gameModePrefabs;

		public ReadOnlyNamedAssetCollection<GameObject> networkedObjectPrefabs => src.networkedObjectPrefabs;

		public ReadOnlyNamedAssetCollection<SkillDef> skillDefs => src.skillDefs;

		public ReadOnlyNamedAssetCollection<SkillFamily> skillFamilies => src.skillFamilies;

		public ReadOnlyNamedAssetCollection<SceneDef> sceneDefs => src.sceneDefs;

		public ReadOnlyNamedAssetCollection<ItemDef> itemDefs => src.itemDefs;

		public ReadOnlyNamedAssetCollection<ItemTierDef> itemTierDefs => src.itemTierDefs;

		public ReadOnlyNamedAssetCollection<ItemRelationshipProvider> itemRelationshipProviders => src.itemRelationshipProviders;

		public ReadOnlyNamedAssetCollection<ItemRelationshipType> itemRelationshipTypes => src.itemRelationshipTypes;

		public ReadOnlyNamedAssetCollection<EquipmentDef> equipmentDefs => src.equipmentDefs;

		public ReadOnlyNamedAssetCollection<BuffDef> buffDefs => src.buffDefs;

		public ReadOnlyNamedAssetCollection<EliteDef> eliteDefs => src.eliteDefs;

		public ReadOnlyNamedAssetCollection<UnlockableDef> unlockableDefs => src.unlockableDefs;

		public ReadOnlyNamedAssetCollection<SurvivorDef> survivorDefs => src.survivorDefs;

		public ReadOnlyNamedAssetCollection<ArtifactDef> artifactDefs => src.artifactDefs;

		public ReadOnlyNamedAssetCollection<EffectDef> effectDefs => src.effectDefs;

		public ReadOnlyNamedAssetCollection<SurfaceDef> surfaceDefs => src.surfaceDefs;

		public ReadOnlyNamedAssetCollection<NetworkSoundEventDef> networkSoundEventDefs => src.networkSoundEventDefs;

		public ReadOnlyNamedAssetCollection<MusicTrackDef> musicTrackDefs => src.musicTrackDefs;

		public ReadOnlyNamedAssetCollection<GameEndingDef> gameEndingDefs => src.gameEndingDefs;

		public ReadOnlyNamedAssetCollection<EntityStateConfiguration> entityStateConfigurations => src.entityStateConfigurations;

		public ReadOnlyNamedAssetCollection<ExpansionDef> expansionDefs => src.expansionDefs;

		public ReadOnlyNamedAssetCollection<EntitlementDef> entitlementDefs => src.entitlementDefs;

		public ReadOnlyNamedAssetCollection<MiscPickupDef> miscPickupDefs => src.miscPickupDefs;

		public ReadOnlyNamedAssetCollection<Type> entityStateTypes => src.entityStateTypes;

		public ReadOnlyContentPack([NotNull] ContentPack src)
		{
			this.src = src ?? throw new ArgumentNullException("src");
		}

		public bool ValueEquals(in ReadOnlyContentPack other)
		{
			return src.ValueEquals(other.src);
		}

		public static implicit operator ReadOnlyContentPack([NotNull] ContentPack contentPack)
		{
			return new ReadOnlyContentPack(contentPack);
		}

		public bool FindAsset(string collectionName, string assetName, out object result)
		{
			return src.FindAsset(collectionName, assetName, out result);
		}
	}
	public interface IContentPackProvider
	{
		string identifier { get; }

		IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args);

		IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args);

		IEnumerator FinalizeAsync(FinalizeAsyncArgs args);
	}
	public struct ContentPackLoadInfo
	{
		public int index;

		public string contentPackProviderIdentifier;

		public IContentPackProvider contentPackProvider;

		public ReadOnlyContentPack previousContentPack;

		public int retries;
	}
	public class LoadStaticContentAsyncArgs
	{
		private readonly IProgress<float> progressReceiver;

		public readonly ReadOnlyArray<ContentPackLoadInfo> peerLoadInfos;

		public LoadStaticContentAsyncArgs(IProgress<float> progressReceiver, ReadOnlyArray<ContentPackLoadInfo> peerLoadInfos)
		{
			this.progressReceiver = progressReceiver;
			this.peerLoadInfos = peerLoadInfos;
		}

		public void ReportProgress(float progress)
		{
			progressReceiver.Report(progress);
		}
	}
	public class GetContentPackAsyncArgs
	{
		private readonly IProgress<float> progressReceiver;

		public readonly ReadOnlyArray<ContentPackLoadInfo> peerLoadInfos;

		public readonly ContentPack output;

		public readonly int retriesRemaining;

		public GetContentPackAsyncArgs(IProgress<float> progressReceiver, ContentPack output, ReadOnlyArray<ContentPackLoadInfo> peerLoadInfos, int retriesRemaining)
		{
			this.progressReceiver = progressReceiver;
			this.output = output;
			this.peerLoadInfos = peerLoadInfos;
			this.retriesRemaining = retriesRemaining;
		}

		public void ReportProgress(float progress)
		{
			progressReceiver.Report(progress);
		}
	}
	public class FinalizeAsyncArgs
	{
		private readonly IProgress<float> progressReceiver;

		public readonly ReadOnlyArray<ContentPackLoadInfo> peerLoadInfos;

		public readonly ReadOnlyContentPack finalContentPack;

		public FinalizeAsyncArgs(IProgress<float> progressReceiver, ReadOnlyArray<ContentPackLoadInfo> peerLoadInfos, ReadOnlyContentPack finalContentPack)
		{
			this.progressReceiver = progressReceiver;
		}

		public void ReportProgress(float progress)
		{
			progressReceiver.Report(progress);
		}
	}
	public abstract class NamedAssetCollection
	{
		[CanBeNull]
		public abstract bool Find([NotNull] string assetName, out object result);
	}
	public class NamedAssetCollection<TAsset> : NamedAssetCollection, IEquatable<NamedAssetCollection<TAsset>>, IEnumerable<TAsset>, IEnumerable
	{
		private struct AssetInfo : IComparable<AssetInfo>, IEquatable<AssetInfo>
		{
			public TAsset asset;

			public string assetName;

			public int CompareTo(AssetInfo other)
			{
				return string.Compare(assetName, other.assetName, StringComparison.OrdinalIgnoreCase);
			}

			public bool Equals(AssetInfo other)
			{
				if (object.Equals(asset, other.asset))
				{
					return string.Equals(assetName, other.assetName, StringComparison.Ordinal);
				}
				return false;
			}
		}

		public struct AssetEnumerator : IEnumerator<TAsset>, IEnumerator, IDisposable
		{
			private int i;

			private NamedAssetCollection<TAsset> src;

			public TAsset Current => src.assetInfos[i].asset;

			object IEnumerator.Current => Current;

			public AssetEnumerator(NamedAssetCollection<TAsset> src)
			{
				this.src = src;
				i = -1;
			}

			public void Dispose()
			{
			}

			public bool MoveNext()
			{
				i++;
				return i < src.Length;
			}

			public void Reset()
			{
				i = -1;
			}
		}

		private Dictionary<TAsset, string> assetToName = new Dictionary<TAsset, string>();

		private Dictionary<string, TAsset> nameToAsset = new Dictionary<string, TAsset>();

		private AssetInfo[] assetInfos = Array.Empty<AssetInfo>();

		private Func<TAsset, string> nameProvider;

		public int Length => assetInfos.Length;

		public int Count => Length;

		public bool IsReadOnly => false;

		public TAsset this[int i] => assetInfos[i].asset;

		public NamedAssetCollection([NotNull] Func<TAsset, string> nameProvider)
		{
			this.nameProvider = nameProvider;
		}

		public void Add([NotNull] TAsset[] newAssets)
		{
			string[] array = new string[newAssets.Length];
			for (int i = 0; i < newAssets.Length; i++)
			{
				array[i] = nameProvider(newAssets[i]);
			}
			for (int j = 0; j < newAssets.Length; j++)
			{
				TAsset val = newAssets[j];
				string text = array[j];
				if (assetToName.ContainsKey(val))
				{
					throw new ArgumentException($"Asset {val} is already registered!");
				}
				if (nameToAsset.ContainsKey(text))
				{
					throw new ArgumentException("Asset name " + text + " is already registered!");
				}
			}
			int num = assetInfos.Length;
			int newSize = num + newAssets.Length;
			Array.Resize(ref assetInfos, newSize);
			for (int k = 0; k < newAssets.Length; k++)
			{
				TAsset val2 = newAssets[k];
				string text2 = array[k];
				assetInfos[num + k] = new AssetInfo
				{
					asset = val2,
					assetName = text2
				};
				nameToAsset[text2] = val2;
				assetToName[val2] = text2;
			}
			Array.Sort(assetInfos);
		}

		[CanBeNull]
		public TAsset Find([NotNull] string assetName)
		{
			if (!nameToAsset.TryGetValue(assetName, out var value))
			{
				return default(TAsset);
			}
			return value;
		}

		[CanBeNull]
		public override bool Find([NotNull] string assetName, out object result)
		{
			TAsset value;
			bool result2 = nameToAsset.TryGetValue(assetName, out value);
			result = value;
			return result2;
		}

		[CanBeNull]
		public string GetAssetName([NotNull] TAsset asset)
		{
			if (!assetToName.TryGetValue(asset, out var value))
			{
				return null;
			}
			return value;
		}

		public bool Contains([NotNull] TAsset asset)
		{
			return assetToName.ContainsKey(asset);
		}

		public void Clear()
		{
			assetToName.Clear();
			nameToAsset.Clear();
			assetInfos = Array.Empty<AssetInfo>();
		}

		public override bool Equals(object obj)
		{
			if (!(obj is NamedAssetCollection<TAsset> other))
			{
				return false;
			}
			return Equals(other);
		}

		public bool Equals(NamedAssetCollection<TAsset> other)
		{
			if (this == other)
			{
				return true;
			}
			if (assetInfos.Length != other.assetInfos.Length)
			{
				return false;
			}
			int i = 0;
			for (int num = assetInfos.Length; i < num; i++)
			{
				if (!assetInfos[i].Equals(other.assetInfos[i]))
				{
					return false;
				}
			}
			return true;
		}

		public override int GetHashCode()
		{
			return base.GetHashCode();
		}

		public static void Copy(NamedAssetCollection<TAsset> src, NamedAssetCollection<TAsset> dest)
		{
			dest.assetInfos = ArrayUtils.Clone(src.assetInfos);
			dest.assetToName = new Dictionary<TAsset, string>(src.assetToName);
			dest.nameToAsset = new Dictionary<string, TAsset>(src.nameToAsset);
			dest.nameProvider = src.nameProvider;
		}

		public void CopyTo(NamedAssetCollection<TAsset> dest)
		{
			Copy(this, dest);
		}

		public AssetEnumerator GetEnumerator()
		{
			return new AssetEnumerator(this);
		}

		IEnumerator<TAsset> IEnumerable<TAsset>.GetEnumerator()
		{
			return GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
	public readonly struct ReadOnlyNamedAssetCollection<TAsset> : IEnumerable<TAsset>, IEnumerable, IEquatable<ReadOnlyNamedAssetCollection<TAsset>>
	{
		private readonly NamedAssetCollection<TAsset> src;

		public int Length => src.Length;

		public ReadOnlyNamedAssetCollection(NamedAssetCollection<TAsset> src)
		{
			this.src = src;
		}

		public TAsset Find(string assetName)
		{
			return src.Find(assetName);
		}

		public bool Find(string assetName, out object result)
		{
			return src.Find(assetName, out result);
		}

		public string GetAssetName(TAsset asset)
		{
			return src.GetAssetName(asset);
		}

		public bool Contains([NotNull] TAsset asset)
		{
			return src.Contains(asset);
		}

		public static void Copy(ReadOnlyNamedAssetCollection<TAsset> src, NamedAssetCollection<TAsset> dest)
		{
			NamedAssetCollection<TAsset>.Copy(src.src, dest);
		}

		public void CopyTo(NamedAssetCollection<TAsset> dest)
		{
			src.CopyTo(dest);
		}

		public override bool Equals(object obj)
		{
			if (obj is NamedAssetCollection<TAsset> namedAssetCollection)
			{
				return Equals(namedAssetCollection);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return src.GetHashCode();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		public NamedAssetCollection<TAsset>.AssetEnumerator GetEnumerator()
		{
			return src.GetEnumerator();
		}

		IEnumerator<TAsset> IEnumerable<TAsset>.GetEnumerator()
		{
			return GetEnumerator();
		}

		public bool Equals(ReadOnlyNamedAssetCollection<TAsset> other)
		{
			return src.Equals(other.src);
		}

		public static implicit operator ReadOnlyNamedAssetCollection<TAsset>(NamedAssetCollection<TAsset> src)
		{
			return new ReadOnlyNamedAssetCollection<TAsset>(src);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SerializableContentPack")]
	public class SerializableContentPack : ScriptableObject
	{
		public GameObject[] bodyPrefabs = Array.Empty<GameObject>();

		public GameObject[] masterPrefabs = Array.Empty<GameObject>();

		public GameObject[] projectilePrefabs = Array.Empty<GameObject>();

		public GameObject[] gameModePrefabs = Array.Empty<GameObject>();

		public GameObject[] networkedObjectPrefabs = Array.Empty<GameObject>();

		public SkillDef[] skillDefs = Array.Empty<SkillDef>();

		public SkillFamily[] skillFamilies = Array.Empty<SkillFamily>();

		public SceneDef[] sceneDefs = Array.Empty<SceneDef>();

		public ItemDef[] itemDefs = Array.Empty<ItemDef>();

		public EquipmentDef[] equipmentDefs = Array.Empty<EquipmentDef>();

		public BuffDef[] buffDefs = Array.Empty<BuffDef>();

		public EliteDef[] eliteDefs = Array.Empty<EliteDef>();

		public UnlockableDef[] unlockableDefs = Array.Empty<UnlockableDef>();

		public SurvivorDef[] survivorDefs = Array.Empty<SurvivorDef>();

		public ArtifactDef[] artifactDefs = Array.Empty<ArtifactDef>();

		public GameObject[] effectDefs = Array.Empty<GameObject>();

		public SurfaceDef[] surfaceDefs = Array.Empty<SurfaceDef>();

		public NetworkSoundEventDef[] networkSoundEventDefs = Array.Empty<NetworkSoundEventDef>();

		public MusicTrackDef[] musicTrackDefs = Array.Empty<MusicTrackDef>();

		public GameEndingDef[] gameEndingDefs = Array.Empty<GameEndingDef>();

		public EntityStateConfiguration[] entityStateConfigurations = Array.Empty<EntityStateConfiguration>();

		public SerializableEntityStateType[] entityStateTypes = Array.Empty<SerializableEntityStateType>();

		public ContentPack CreateV1_1_1_4_ContentPack()
		{
			ContentPack contentPack = new ContentPack();
			contentPack.bodyPrefabs.Add(bodyPrefabs);
			contentPack.masterPrefabs.Add(masterPrefabs);
			contentPack.projectilePrefabs.Add(projectilePrefabs);
			contentPack.gameModePrefabs.Add(gameModePrefabs);
			contentPack.networkedObjectPrefabs.Add(networkedObjectPrefabs);
			contentPack.skillDefs.Add(skillDefs);
			contentPack.skillFamilies.Add(skillFamilies);
			contentPack.sceneDefs.Add(sceneDefs);
			contentPack.itemDefs.Add(itemDefs);
			contentPack.equipmentDefs.Add(equipmentDefs);
			contentPack.buffDefs.Add(buffDefs);
			contentPack.eliteDefs.Add(eliteDefs);
			contentPack.unlockableDefs.Add(unlockableDefs);
			contentPack.survivorDefs.Add(survivorDefs);
			contentPack.artifactDefs.Add(artifactDefs);
			contentPack.effectDefs.Add(effectDefs.Select((GameObject asset) => new EffectDef(asset)).ToArray());
			contentPack.surfaceDefs.Add(surfaceDefs);
			contentPack.networkSoundEventDefs.Add(networkSoundEventDefs);
			contentPack.musicTrackDefs.Add(musicTrackDefs);
			contentPack.gameEndingDefs.Add(gameEndingDefs);
			contentPack.entityStateConfigurations.Add(entityStateConfigurations);
			List<Type> list = new List<Type>();
			for (int i = 0; i < entityStateTypes.Length; i++)
			{
				Type stateType = entityStateTypes[i].stateType;
				if (stateType != null)
				{
					list.Add(stateType);
					continue;
				}
				UnityEngine.Debug.LogWarning("SerializableContentPack \"" + base.name + "\" could not resolve type with name \"" + entityStateTypes[i].typeName + "\". The type will not be available in the content pack.");
			}
			contentPack.entityStateTypes.Add(list.ToArray());
			return contentPack;
		}

		public virtual ContentPack CreateContentPack()
		{
			return CreateV1_1_1_4_ContentPack();
		}
	}
	public class SimpleContentPackProvider : IContentPackProvider
	{
		public delegate IEnumerator LoadStaticContentAsyncDelegate(LoadStaticContentAsyncArgs args);

		public delegate IEnumerator GenerateContentPackAsyncDelegate(GetContentPackAsyncArgs args);

		public delegate IEnumerator FinalizeAsyncDelegate(FinalizeAsyncArgs args);

		public string identifier { get; set; }

		public LoadStaticContentAsyncDelegate loadStaticContentImplementation { get; set; }

		public GenerateContentPackAsyncDelegate generateContentPackAsyncImplementation { get; set; }

		public FinalizeAsyncDelegate finalizeAsyncImplementation { get; set; }

		public IEnumerator LoadStaticContentAsync(LoadStaticContentAsyncArgs args)
		{
			return loadStaticContentImplementation?.Invoke(args);
		}

		public IEnumerator GenerateContentPackAsync(GetContentPackAsyncArgs args)
		{
			return generateContentPackAsyncImplementation?.Invoke(args);
		}

		public IEnumerator FinalizeAsync(FinalizeAsyncArgs args)
		{
			return finalizeAsyncImplementation?.Invoke(args);
		}
	}
	public class TargetAssetNameAttribute : System.Attribute
	{
		public readonly string targetAssetName;

		public TargetAssetNameAttribute(string targetAssetName)
		{
			this.targetAssetName = targetAssetName;
		}
	}
}
namespace RoR2.Orbs
{
	public class OrbPool : GenericPool<Orb>
	{
		protected Type _OrbType;

		protected static bool _VerboseLogging = false;

		protected static Dictionary<Type, OrbPool> _OrbPoolMap = new Dictionary<Type, OrbPool>();

		protected static bool _UsePools = true;

		public static bool VerboseLogging => _VerboseLogging;

		public static bool UsePools => _UsePools;

		public static void ToggleVerboseLogging()
		{
			_VerboseLogging = !_VerboseLogging;
			UnityEngine.Debug.LogFormat("Orb pooling {0}", _VerboseLogging ? "ENABLED" : "DISABLED");
		}

		public void Initialize(Type inOrbType, int inMaxSize, int inStartSize)
		{
			_OrbType = inOrbType;
			base.PoolName = _OrbType.ToString();
			base.Initialize(inMaxSize, inStartSize);
		}

		protected override Orb CreateNewObject(bool inPoolEntry = true)
		{
			if (_OrbType != null)
			{
				Orb orb = Activator.CreateInstance(_OrbType) as Orb;
				orb.instanceID = _Pool.Count + _InUse.Count;
				if (VerboseLogging)
				{
					UnityEngine.Debug.LogFormat("OrbPool: {0} created instance {1} ({2})...", base.PoolName, _OrbType.ToString(), orb.instanceID);
				}
				return orb;
			}
			UnityEngine.Debug.LogError("OrbPool: No type set!");
			return null;
		}

		protected override void DestroyObject(Orb inObject)
		{
		}

		public void DumpPool(StringBuilder inDumpSB = null)
		{
			StringBuilder obj = inDumpSB ?? new StringBuilder();
			obj.AppendFormat("OrbPool {0}\n", base.PoolName);
			obj.AppendFormat("\t Pool Count: {0}\n", _Pool.Count);
			obj.AppendFormat("\tInUse Count: {0}\n", _InUse.Count);
		}

		public static void TogglePooling()
		{
			_UsePools = !_UsePools;
			UnityEngine.Debug.LogFormat("Orb pooling is {0}", _UsePools ? "ENABLED" : "DISABLED");
		}

		protected static void CreatePoolIfNotPresent(Type inOrbType)
		{
			if (!_OrbPoolMap.ContainsKey(inOrbType))
			{
				OrbPool orbPool = new OrbPool();
				orbPool.AlwaysGrowable = true;
				orbPool.Initialize(inOrbType, 1, 1);
				_OrbPoolMap.Add(inOrbType, orbPool);
			}
		}

		public static Orb GetPooledOrb(Type inOrbType)
		{
			CreatePoolIfNotPresent(inOrbType);
			OrbPool orbPool = _OrbPoolMap[inOrbType];
			Orb @object = orbPool.GetObject();
			if (@object != null)
			{
				@object.SetOwningPool(orbPool);
				@object.Reset();
			}
			return @object;
		}

		public static void ClearAllPools()
		{
			UnityEngine.Debug.LogWarning("OrbPool: Clearing all pools");
			foreach (OrbPool value in _OrbPoolMap.Values)
			{
				value.Reset();
			}
			_OrbPoolMap.Clear();
		}

		public static void DumpPools()
		{
		}
	}
	public class GenericDamageOrb : Orb
	{
		public float speed = 60f;

		public float damageValue;

		public GameObject attacker;

		public TeamIndex teamIndex;

		public bool isCrit;

		public float scale;

		public ProcChainMask procChainMask;

		public float procCoefficient = 0.2f;

		public DamageColorIndex damageColorIndex;

		public DamageTypeCombo damageType;

		public override void Begin()
		{
			base.duration = base.distanceToTarget / speed;
			if ((bool)GetOrbEffect())
			{
				EffectData effectData = new EffectData
				{
					scale = scale,
					origin = origin,
					genericFloat = base.duration
				};
				effectData.SetHurtBoxReference(target);
				EffectManager.SpawnEffect(GetOrbEffect(), effectData, transmit: true);
			}
		}

		protected virtual GameObject GetOrbEffect()
		{
			return null;
		}

		public override void OnArrival()
		{
			if ((bool)target)
			{
				HealthComponent healthComponent = target.healthComponent;
				if ((bool)healthComponent)
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = damageValue;
					damageInfo.attacker = attacker;
					damageInfo.inflictor = null;
					damageInfo.force = UnityEngine.Vector3.zero;
					damageInfo.crit = isCrit;
					damageInfo.procChainMask = procChainMask;
					damageInfo.procCoefficient = procCoefficient;
					damageInfo.position = target.transform.position;
					damageInfo.damageColorIndex = damageColorIndex;
					damageInfo.damageType = damageType;
					healthComponent.TakeDamage(damageInfo);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
					GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
				}
			}
		}
	}
	public class HuntressArrowOrb : GenericDamageOrb
	{
		public override void Begin()
		{
			speed = 120f;
			base.Begin();
		}

		protected override GameObject GetOrbEffect()
		{
			return OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/ArrowOrbEffect");
		}
	}
	public class HuntressFlurryArrowOrb : HuntressArrowOrb
	{
		public override void Begin()
		{
			base.Begin();
			speed = 80f;
		}

		protected override GameObject GetOrbEffect()
		{
			if (isCrit)
			{
				return OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/FlurryArrowCritOrbEffect");
			}
			return OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/FlurryArrowOrbEffect");
		}
	}
	public class BeetleWardOrb : Orb
	{
		public float speed;

		public override void Begin()
		{
			base.duration = base.distanceToTarget / speed;
			EffectData effectData = new EffectData
			{
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/BeetleWardOrbEffect"), effectData, transmit: true);
		}

		public override void OnArrival()
		{
			if ((bool)target)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(OrbStorageUtility.Get("Prefabs/NetworkedObjects/BeetleWard"), target.transform.position, UnityEngine.Quaternion.identity);
				gameObject.GetComponent<TeamFilter>().teamIndex = target.teamIndex;
				NetworkServer.Spawn(gameObject);
			}
		}
	}
	public class BounceOrb : Orb
	{
		private const float speed = 70f;

		public float damageValue;

		public GameObject attacker;

		public TeamIndex teamIndex;

		public List<HealthComponent> bouncedObjects;

		public bool isCrit;

		public float scale;

		public ProcChainMask procChainMask;

		public float procCoefficient = 0.2f;

		public DamageColorIndex damageColorIndex;

		public override void Begin()
		{
			base.duration = base.distanceToTarget / 70f;
			EffectData effectData = new EffectData
			{
				scale = scale,
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/BounceOrbEffect"), effectData, transmit: true);
		}

		public override void OnArrival()
		{
			if ((bool)target)
			{
				HealthComponent healthComponent = target.healthComponent;
				if ((bool)healthComponent)
				{
					UnityEngine.Vector3 position = target.transform.position;
					GameObject gameObject = healthComponent.gameObject;
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = damageValue;
					damageInfo.attacker = attacker;
					damageInfo.inflictor = null;
					damageInfo.force = (position - origin).normalized * -1000f;
					damageInfo.crit = isCrit;
					damageInfo.procChainMask = procChainMask;
					damageInfo.procCoefficient = procCoefficient;
					damageInfo.position = position;
					damageInfo.damageColorIndex = damageColorIndex;
					healthComponent.TakeDamage(damageInfo);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, gameObject);
					GlobalEventManager.instance.OnHitAll(damageInfo, gameObject);
				}
			}
		}

		public static void SearchForTargets([NotNull] BullseyeSearch search, TeamIndex teamIndex, UnityEngine.Vector3 position, float range, int maxTargets, [NotNull] List<HurtBox> dest, [NotNull] List<HealthComponent> exclusions)
		{
			search.searchOrigin = position;
			search.searchDirection = UnityEngine.Vector3.zero;
			search.teamMaskFilter = TeamMask.GetEnemyTeams(teamIndex);
			search.filterByLoS = false;
			search.sortMode = BullseyeSearch.SortMode.None;
			search.maxDistanceFilter = range;
			search.RefreshCandidates();
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			foreach (HurtBox result in search.GetResults())
			{
				list.Add(result);
			}
			Util.ShuffleList(list);
			int i = 0;
			for (int count = list.Count; i < count; i++)
			{
				HurtBox hurtBox = list[i];
				if ((bool)hurtBox.healthComponent && !exclusions.Contains(hurtBox.healthComponent))
				{
					if (exclusions.Count >= maxTargets)
					{
						break;
					}
					exclusions.Add(hurtBox.healthComponent);
					dest.Add(hurtBox);
				}
			}
			CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}
	}
	public class ChainGunOrb : GenericDamageOrb
	{
		private GameObject orbEffectPrefab;

		public int bouncesRemaining;

		public float bounceRange = 20f;

		public float damageCoefficientPerBounce = 1f;

		public int targetsToFindPerBounce = 1;

		public bool canBounceOnSameTarget;

		private List<HealthComponent> bouncedObjects;

		private BullseyeSearch search;

		public ChainGunOrb(GameObject orbEffectObject)
		{
			orbEffectPrefab = orbEffectObject;
			bouncedObjects = new List<HealthComponent>();
		}

		protected override GameObject GetOrbEffect()
		{
			return orbEffectPrefab;
		}

		public override void OnArrival()
		{
			if (!target)
			{
				return;
			}
			HealthComponent healthComponent = target.healthComponent;
			if ((bool)healthComponent)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = damageValue;
				damageInfo.attacker = attacker;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.crit = isCrit;
				damageInfo.procChainMask = procChainMask;
				damageInfo.procCoefficient = procCoefficient;
				damageInfo.position = target.transform.position;
				damageInfo.damageColorIndex = damageColorIndex;
				damageInfo.damageType = damageType;
				healthComponent.TakeDamage(damageInfo);
				GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
				GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
			}
			if (bouncesRemaining <= 0)
			{
				return;
			}
			for (int i = 0; i < targetsToFindPerBounce; i++)
			{
				if (bouncedObjects != null)
				{
					if (canBounceOnSameTarget)
					{
						bouncedObjects.Clear();
					}
					bouncedObjects.Add(target.healthComponent);
				}
				HurtBox hurtBox = PickNextTarget(target.transform.position);
				if ((bool)hurtBox)
				{
					ChainGunOrb chainGunOrb = new ChainGunOrb(orbEffectPrefab);
					chainGunOrb.search = search;
					chainGunOrb.origin = target.transform.position;
					chainGunOrb.target = hurtBox;
					chainGunOrb.attacker = attacker;
					chainGunOrb.teamIndex = teamIndex;
					chainGunOrb.damageValue = damageValue * damageCoefficientPerBounce;
					chainGunOrb.bouncesRemaining = bouncesRemaining - 1;
					chainGunOrb.isCrit = isCrit;
					chainGunOrb.bouncedObjects = bouncedObjects;
					chainGunOrb.procChainMask = procChainMask;
					chainGunOrb.procCoefficient = procCoefficient;
					chainGunOrb.damageColorIndex = damageColorIndex;
					chainGunOrb.damageCoefficientPerBounce = damageCoefficientPerBounce;
					chainGunOrb.speed = speed;
					chainGunOrb.bounceRange = bounceRange;
					chainGunOrb.damageType = damageType;
					OrbManager.instance.AddOrb(chainGunOrb);
				}
			}
		}

		public HurtBox PickNextTarget(UnityEngine.Vector3 position)
		{
			if (search == null)
			{
				search = new BullseyeSearch();
			}
			search.searchOrigin = position;
			search.searchDirection = UnityEngine.Vector3.zero;
			search.teamMaskFilter = TeamMask.allButNeutral;
			search.teamMaskFilter.RemoveTeam(teamIndex);
			search.filterByLoS = false;
			search.sortMode = BullseyeSearch.SortMode.Distance;
			search.maxDistanceFilter = bounceRange;
			search.RefreshCandidates();
			HurtBox hurtBox = (from v in search.GetResults()
				where !bouncedObjects.Contains(v.healthComponent)
				select v).FirstOrDefault();
			if ((bool)hurtBox)
			{
				bouncedObjects.Add(hurtBox.healthComponent);
			}
			return hurtBox;
		}
	}
	public class DamageOrb : Orb
	{
		public enum DamageOrbType
		{
			ClayGooOrb
		}

		private float speed = 60f;

		public float damageValue;

		public GameObject attacker;

		public TeamIndex teamIndex;

		public bool isCrit;

		public ProcChainMask procChainMask;

		public float procCoefficient = 0.2f;

		public DamageColorIndex damageColorIndex;

		public DamageOrbType damageOrbType;

		private DamageTypeCombo orbDamageType = DamageType.Generic;

		public override void Begin()
		{
			GameObject effectPrefab = null;
			if (damageOrbType == DamageOrbType.ClayGooOrb)
			{
				speed = 5f;
				effectPrefab = OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/ClayGooOrbEffect");
				orbDamageType = DamageType.ClayGoo;
			}
			base.duration = base.distanceToTarget / speed;
			EffectData effectData = new EffectData
			{
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
		}

		public override void OnArrival()
		{
			if (!target)
			{
				return;
			}
			HealthComponent healthComponent = target.healthComponent;
			if (!healthComponent)
			{
				return;
			}
			if (damageOrbType == DamageOrbType.ClayGooOrb)
			{
				CharacterBody component = healthComponent.GetComponent<CharacterBody>();
				if ((bool)component && (component.bodyFlags & CharacterBody.BodyFlags.ImmuneToGoo) != 0)
				{
					healthComponent.Heal(damageValue, default(ProcChainMask));
					return;
				}
			}
			DamageInfo damageInfo = new DamageInfo();
			damageInfo.damage = damageValue;
			damageInfo.attacker = attacker;
			damageInfo.inflictor = null;
			damageInfo.force = UnityEngine.Vector3.zero;
			damageInfo.crit = isCrit;
			damageInfo.procChainMask = procChainMask;
			damageInfo.procCoefficient = procCoefficient;
			damageInfo.position = target.transform.position;
			damageInfo.damageColorIndex = damageColorIndex;
			damageInfo.damageType = orbDamageType;
			healthComponent.TakeDamage(damageInfo);
			GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
			GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
		}
	}
	public class DelayedHitOrb : GenericDamageOrb
	{
		public float delay;

		public GameObject delayedEffectPrefab;

		public GameObject orbEffect;

		public override void Begin()
		{
			base.Begin();
			base.duration = delay;
		}

		protected override GameObject GetOrbEffect()
		{
			return orbEffect;
		}

		public override void OnArrival()
		{
			if ((bool)target && (bool)target.transform)
			{
				EffectManager.SpawnEffect(delayedEffectPrefab, new EffectData
				{
					origin = target.transform.position
				}, transmit: true);
				base.OnArrival();
			}
		}
	}
	public class DevilOrb : Orb
	{
		public enum EffectType
		{
			Skull,
			Wisp
		}

		private const float speed = 30f;

		public float damageValue;

		public GameObject attacker;

		public TeamIndex teamIndex;

		public bool isCrit;

		public float scale;

		public ProcChainMask procChainMask;

		public float procCoefficient = 0.2f;

		public DamageColorIndex damageColorIndex;

		public EffectType effectType;

		public override void Begin()
		{
			base.duration = base.distanceToTarget / 30f;
			EffectData effectData = new EffectData
			{
				scale = scale,
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			GameObject effectPrefab = null;
			switch (effectType)
			{
			case EffectType.Skull:
				effectPrefab = OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/DevilOrbEffect");
				break;
			case EffectType.Wisp:
				effectPrefab = OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/WispOrbEffect");
				break;
			}
			EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
		}

		public override void OnArrival()
		{
			if ((bool)target)
			{
				HealthComponent healthComponent = target.healthComponent;
				if ((bool)healthComponent)
				{
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = damageValue;
					damageInfo.attacker = attacker;
					damageInfo.inflictor = null;
					damageInfo.force = UnityEngine.Vector3.zero;
					damageInfo.crit = isCrit;
					damageInfo.procChainMask = procChainMask;
					damageInfo.procCoefficient = procCoefficient;
					damageInfo.position = target.transform.position;
					damageInfo.damageColorIndex = damageColorIndex;
					healthComponent.TakeDamage(damageInfo);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
					GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
				}
			}
		}

		public HurtBox PickNextTarget(UnityEngine.Vector3 position, float range)
		{
			BullseyeSearch bullseyeSearch = new BullseyeSearch();
			bullseyeSearch.searchOrigin = position;
			bullseyeSearch.searchDirection = UnityEngine.Vector3.zero;
			bullseyeSearch.teamMaskFilter = TeamMask.allButNeutral;
			bullseyeSearch.teamMaskFilter.RemoveTeam(teamIndex);
			bullseyeSearch.filterByLoS = false;
			bullseyeSearch.sortMode = BullseyeSearch.SortMode.Distance;
			bullseyeSearch.maxDistanceFilter = range;
			bullseyeSearch.RefreshCandidates();
			List<HurtBox> list = bullseyeSearch.GetResults().ToList();
			if (list.Count <= 0)
			{
				return null;
			}
			return list[UnityEngine.Random.Range(0, list.Count)];
		}
	}
	public class GoldOrb : Orb
	{
		public uint goldAmount;

		public bool scaleOrb = true;

		public float overrideDuration = 0.6f;

		public override void Begin()
		{
			if ((bool)target)
			{
				base.duration = overrideDuration;
				float scale = (scaleOrb ? Mathf.Min((float)goldAmount / Run.instance.difficultyCoefficient, 1f) : 1f);
				EffectData effectData = new EffectData
				{
					scale = scale,
					origin = origin,
					genericFloat = base.duration
				};
				effectData.SetHurtBoxReference(target);
				EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/GoldOrbEffect"), effectData, transmit: true);
			}
		}

		public override void OnArrival()
		{
			if ((bool)target && (bool)target.healthComponent && (bool)target.healthComponent.body && (bool)target.healthComponent.body.master)
			{
				target.healthComponent.body.master.GiveMoney(goldAmount);
			}
		}
	}
	public class HauntOrb : Orb
	{
		public float timeToArrive;

		public float scale;

		public override void Begin()
		{
			base.duration = timeToArrive + UnityEngine.Random.Range(0f, 0.4f);
			EffectData effectData = new EffectData
			{
				scale = scale,
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/HauntOrbEffect"), effectData, transmit: true);
		}

		public override void OnArrival()
		{
			if ((bool)target)
			{
				HealthComponent healthComponent = target.healthComponent;
				if ((bool)healthComponent && (bool)healthComponent.body)
				{
					healthComponent.body.AddTimedBuff(RoR2Content.Buffs.AffixHaunted, 15f);
				}
			}
		}
	}
	public class HealOrb : Orb
	{
		public float healValue;

		public bool scaleOrb = true;

		public float overrideDuration = 0.3f;

		public override void Begin()
		{
			if ((bool)target)
			{
				base.duration = overrideDuration;
				float scale = (scaleOrb ? Mathf.Min(healValue / target.healthComponent.fullHealth, 1f) : 1f);
				EffectData effectData = new EffectData
				{
					scale = scale,
					origin = origin,
					genericFloat = base.duration
				};
				effectData.SetHurtBoxReference(target);
				EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/HealthOrbEffect"), effectData, transmit: true);
			}
		}

		public override void OnArrival()
		{
			if ((bool)target)
			{
				HealthComponent healthComponent = target.healthComponent;
				if ((bool)healthComponent)
				{
					healthComponent.Heal(healValue, default(ProcChainMask));
				}
			}
		}
	}
	public class InfusionOrb : Orb
	{
		private const float speed = 30f;

		public int maxHpValue;

		private Inventory targetInventory;

		public override void Begin()
		{
			base.duration = base.distanceToTarget / 30f;
			EffectData effectData = new EffectData
			{
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/InfusionOrbEffect"), effectData, transmit: true);
			CharacterBody characterBody = target.GetComponent<HurtBox>()?.healthComponent.GetComponent<CharacterBody>();
			if ((bool)characterBody)
			{
				targetInventory = characterBody.inventory;
			}
		}

		public override void OnArrival()
		{
			if ((bool)targetInventory)
			{
				targetInventory.AddInfusionBonus((uint)maxHpValue);
			}
		}
	}
	public interface IOrbFixedUpdateBehavior
	{
		void FixedUpdate();
	}
	[RequireComponent(typeof(EffectComponent))]
	public class ItemTakenOrbEffect : MonoBehaviour
	{
		public TrailRenderer trailToColor;

		public ParticleSystem[] particlesToColor;

		public SpriteRenderer[] spritesToColor;

		public SpriteRenderer iconSpriteRenderer;

		private void OnEnable()
		{
			StartCoroutine(DelayedUpdateSprite());
		}

		private IEnumerator DelayedUpdateSprite()
		{
			yield return 0;
			ItemDef itemDef = ItemCatalog.GetItemDef((ItemIndex)Util.UintToIntMinusOne(GetComponent<EffectComponent>().effectData.genericUInt));
			ColorCatalog.ColorIndex colorIndex = ColorCatalog.ColorIndex.Error;
			Sprite sprite = null;
			if (itemDef != null)
			{
				colorIndex = itemDef.colorIndex;
				sprite = itemDef.pickupIconSprite;
			}
			UnityEngine.Color color = ColorCatalog.GetColor(colorIndex);
			if (trailToColor != null)
			{
				trailToColor.startColor *= color;
				trailToColor.endColor *= color;
			}
			for (int i = 0; i < particlesToColor.Length; i++)
			{
				ParticleSystem obj = particlesToColor[i];
				ParticleSystem.MainModule main = obj.main;
				main.startColor = color;
				obj.Play();
			}
			for (int j = 0; j < spritesToColor.Length; j++)
			{
				spritesToColor[j].color = color;
			}
			iconSpriteRenderer.sprite = sprite;
		}
	}
	public class ItemTransferOrb : Orb
	{
		public ItemIndex itemIndex;

		public int stack;

		public Inventory inventoryToGrantTo;

		public Action<ItemTransferOrb> onArrival = DefaultOnArrivalBehavior;

		public NetworkIdentity orbEffectTargetObjectOverride;

		public float travelDuration = 1f;

		private static GameObject orbEffectPrefab;

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/Effects/OrbEffects/ItemTransferOrbEffect");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				orbEffectPrefab = x.Result;
			};
		}

		public override void Begin()
		{
			base.duration = travelDuration;
			if ((bool)target || (bool)orbEffectTargetObjectOverride)
			{
				EffectData effectData = new EffectData
				{
					origin = origin,
					genericFloat = base.duration,
					genericUInt = Util.IntToUintPlusOne((int)itemIndex)
				};
				if ((bool)orbEffectTargetObjectOverride)
				{
					effectData.SetNetworkedObjectReference(orbEffectTargetObjectOverride.gameObject);
				}
				else
				{
					effectData.SetHurtBoxReference(target);
				}
				EffectManager.SpawnEffect(orbEffectPrefab, effectData, transmit: true);
			}
		}

		public override void OnArrival()
		{
			onArrival?.Invoke(this);
		}

		public static void DefaultOnArrivalBehavior(ItemTransferOrb orb)
		{
			if ((bool)orb.inventoryToGrantTo)
			{
				orb.inventoryToGrantTo.GiveItem(orb.itemIndex, orb.stack);
			}
		}

		public static ItemTransferOrb DispatchItemTransferOrb(UnityEngine.Vector3 origin, Inventory inventoryToGrantTo, ItemIndex itemIndex, int itemStack, Action<ItemTransferOrb> onArrivalBehavior = null, Either<NetworkIdentity, HurtBox> orbDestinationOverride = default(Either<NetworkIdentity, HurtBox>))
		{
			if (onArrivalBehavior == null)
			{
				onArrivalBehavior = DefaultOnArrivalBehavior;
			}
			ItemTransferOrb itemTransferOrb = new ItemTransferOrb();
			itemTransferOrb.origin = origin;
			itemTransferOrb.inventoryToGrantTo = inventoryToGrantTo;
			itemTransferOrb.itemIndex = itemIndex;
			itemTransferOrb.stack = itemStack;
			itemTransferOrb.onArrival = onArrivalBehavior;
			NetworkIdentity a = orbDestinationOverride.a;
			HurtBox b = orbDestinationOverride.b;
			if (!b)
			{
				if ((bool)inventoryToGrantTo)
				{
					CharacterMaster component = inventoryToGrantTo.GetComponent<CharacterMaster>();
					if ((bool)component)
					{
						CharacterBody body = component.GetBody();
						if ((bool)body)
						{
							itemTransferOrb.target = body.mainHurtBox;
						}
					}
				}
				if ((bool)a)
				{
					itemTransferOrb.orbEffectTargetObjectOverride = a;
				}
			}
			else
			{
				itemTransferOrb.target = b;
			}
			OrbManager.instance.AddOrb(itemTransferOrb);
			return itemTransferOrb;
		}
	}
	public class LightningOrb : Orb
	{
		public enum LightningType
		{
			Ukulele,
			Tesla,
			BFG,
			TreePoisonDart,
			HuntressGlaive,
			Loader,
			RazorWire,
			CrocoDisease,
			MageLightning,
			AntlerShield,
			BeadDamage,
			Count
		}

		public float speed = 100f;

		public float damageValue;

		public GameObject attacker;

		public GameObject inflictor;

		public int bouncesRemaining;

		public List<HealthComponent> bouncedObjects;

		public TeamIndex teamIndex;

		public bool isCrit;

		public ProcChainMask procChainMask;

		public float procCoefficient = 1f;

		public DamageColorIndex damageColorIndex;

		public float range = 20f;

		public float damageCoefficientPerBounce = 1f;

		public int targetsToFindPerBounce = 1;

		public DamageTypeCombo damageType = DamageType.Generic;

		private bool canBounceOnSameTarget;

		private bool failedToKill;

		public LightningType lightningType;

		private BullseyeSearch search;

		public static event Action<LightningOrb> onLightningOrbKilledOnAllBounces;

		public override void Begin()
		{
			base.duration = 0.1f;
			string path = null;
			switch (lightningType)
			{
			case LightningType.Ukulele:
				path = "Prefabs/Effects/OrbEffects/LightningOrbEffect";
				break;
			case LightningType.Tesla:
				path = "Prefabs/Effects/OrbEffects/TeslaOrbEffect";
				break;
			case LightningType.BFG:
				path = "Prefabs/Effects/OrbEffects/BeamSphereOrbEffect";
				base.duration = 0.4f;
				break;
			case LightningType.HuntressGlaive:
				path = "Prefabs/Effects/OrbEffects/HuntressGlaiveOrbEffect";
				base.duration = base.distanceToTarget / speed;
				canBounceOnSameTarget = true;
				break;
			case LightningType.TreePoisonDart:
				path = "Prefabs/Effects/OrbEffects/TreePoisonDartOrbEffect";
				speed = 40f;
				base.duration = base.distanceToTarget / speed;
				break;
			case LightningType.Loader:
				path = "Prefabs/Effects/OrbEffects/LoaderLightningOrbEffect";
				break;
			case LightningType.RazorWire:
				path = "Prefabs/Effects/OrbEffects/RazorwireOrbEffect";
				base.duration = 0.2f;
				break;
			case LightningType.CrocoDisease:
				path = "Prefabs/Effects/OrbEffects/CrocoDiseaseOrbEffect";
				base.duration = 0.6f;
				targetsToFindPerBounce = 2;
				break;
			case LightningType.MageLightning:
				path = "Prefabs/Effects/OrbEffects/MageLightningOrbEffect";
				base.duration = 0.1f;
				break;
			case LightningType.AntlerShield:
				path = "Prefabs/Effects/OrbEffects/NegateAttackOrbEffect";
				base.duration = 0.2f;
				break;
			case LightningType.BeadDamage:
				path = "Prefabs/Effects/OrbEffects/BeadDamageOrbEffect";
				base.duration = 0.2f;
				break;
			}
			EffectData effectData = new EffectData
			{
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			EffectManager.SpawnEffect(OrbStorageUtility.Get(path), effectData, transmit: true);
		}

		public override void OnArrival()
		{
			if (!target)
			{
				return;
			}
			HealthComponent healthComponent = target.healthComponent;
			if ((bool)healthComponent)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = damageValue;
				damageInfo.attacker = attacker;
				damageInfo.inflictor = inflictor;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.crit = isCrit;
				damageInfo.procChainMask = procChainMask;
				damageInfo.procCoefficient = procCoefficient;
				damageInfo.position = target.transform.position;
				damageInfo.damageColorIndex = damageColorIndex;
				damageInfo.damageType = damageType;
				healthComponent.TakeDamage(damageInfo);
				GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
				GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
			}
			failedToKill |= !healthComponent || healthComponent.alive;
			if (bouncesRemaining > 0)
			{
				for (int i = 0; i < targetsToFindPerBounce; i++)
				{
					if (bouncedObjects != null)
					{
						if (canBounceOnSameTarget)
						{
							bouncedObjects.Clear();
						}
						bouncedObjects.Add(target.healthComponent);
					}
					HurtBox hurtBox = PickNextTarget(target.transform.position);
					if ((bool)hurtBox)
					{
						LightningOrb lightningOrb = new LightningOrb();
						lightningOrb.search = search;
						lightningOrb.origin = target.transform.position;
						lightningOrb.target = hurtBox;
						lightningOrb.attacker = attacker;
						lightningOrb.inflictor = inflictor;
						lightningOrb.teamIndex = teamIndex;
						lightningOrb.damageValue = damageValue * damageCoefficientPerBounce;
						lightningOrb.bouncesRemaining = bouncesRemaining - 1;
						lightningOrb.isCrit = isCrit;
						lightningOrb.bouncedObjects = bouncedObjects;
						lightningOrb.lightningType = lightningType;
						lightningOrb.procChainMask = procChainMask;
						lightningOrb.procCoefficient = procCoefficient;
						lightningOrb.damageColorIndex = damageColorIndex;
						lightningOrb.damageCoefficientPerBounce = damageCoefficientPerBounce;
						lightningOrb.speed = speed;
						lightningOrb.range = range;
						lightningOrb.damageType = damageType;
						lightningOrb.failedToKill = failedToKill;
						OrbManager.instance.AddOrb(lightningOrb);
					}
				}
			}
			else if (!failedToKill)
			{
				LightningOrb.onLightningOrbKilledOnAllBounces?.Invoke(this);
			}
		}

		public HurtBox PickNextTarget(UnityEngine.Vector3 position)
		{
			if (search == null)
			{
				search = new BullseyeSearch();
			}
			search.searchOrigin = position;
			search.searchDirection = UnityEngine.Vector3.zero;
			search.teamMaskFilter = TeamMask.allButNeutral;
			search.teamMaskFilter.RemoveTeam(teamIndex);
			search.filterByLoS = false;
			search.sortMode = BullseyeSearch.SortMode.Distance;
			search.maxDistanceFilter = range;
			search.RefreshCandidates();
			HurtBox hurtBox = (from v in search.GetResults()
				where !bouncedObjects.Contains(v.healthComponent)
				select v).FirstOrDefault();
			if ((bool)hurtBox)
			{
				bouncedObjects.Add(hurtBox.healthComponent);
			}
			return hurtBox;
		}
	}
	public class LightningStrikeOrb : GenericDamageOrb, IOrbFixedUpdateBehavior
	{
		private UnityEngine.Vector3 lastKnownTargetPosition;

		private static readonly float positionLockDuration = 0.3f;

		public override void Begin()
		{
			base.Begin();
			base.duration = 0.5f;
			if ((bool)target)
			{
				lastKnownTargetPosition = target.transform.position;
			}
		}

		protected override GameObject GetOrbEffect()
		{
			return OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/LightningStrikeOrbEffect");
		}

		public override void OnArrival()
		{
			EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/ImpactEffects/LightningStrikeImpact"), new EffectData
			{
				origin = lastKnownTargetPosition
			}, transmit: true);
			if ((bool)attacker)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = attacker;
				blastAttack.baseDamage = damageValue;
				blastAttack.baseForce = 0f;
				blastAttack.bonusForce = UnityEngine.Vector3.down * 3000f;
				blastAttack.crit = isCrit;
				blastAttack.damageColorIndex = DamageColorIndex.Item;
				blastAttack.damageType = DamageType.Stun1s;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.inflictor = null;
				blastAttack.position = lastKnownTargetPosition;
				blastAttack.procChainMask = procChainMask;
				blastAttack.procCoefficient = procCoefficient;
				blastAttack.radius = 3f;
				blastAttack.teamIndex = TeamComponent.GetObjectTeam(attacker);
				blastAttack.Fire();
			}
		}

		public void FixedUpdate()
		{
			if ((bool)target && base.timeUntilArrival >= positionLockDuration)
			{
				lastKnownTargetPosition = target.transform.position;
			}
		}
	}
	public class LunarDetonatorOrb : Orb
	{
		public float travelSpeed = 60f;

		public float baseDamage;

		public float damagePerStack;

		public GameObject attacker;

		public bool isCrit;

		public ProcChainMask procChainMask;

		public float procCoefficient;

		public DamageColorIndex damageColorIndex;

		public GameObject detonationEffectPrefab;

		public GameObject orbEffectPrefab;

		public override void Begin()
		{
			base.duration = base.distanceToTarget / travelSpeed;
			EffectData effectData = new EffectData
			{
				scale = 1f,
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			if ((bool)orbEffectPrefab)
			{
				EffectManager.SpawnEffect(orbEffectPrefab, effectData, transmit: true);
			}
		}

		public override void OnArrival()
		{
			base.OnArrival();
			if (!target)
			{
				return;
			}
			HealthComponent healthComponent = target.healthComponent;
			if (!healthComponent)
			{
				return;
			}
			CharacterBody body = healthComponent.body;
			if ((bool)body)
			{
				int buffCount = body.GetBuffCount(RoR2Content.Buffs.LunarDetonationCharge);
				if (buffCount > 0)
				{
					body.ClearTimedBuffs(RoR2Content.Buffs.LunarDetonationCharge);
					UnityEngine.Vector3 position = target.transform.position;
					DamageInfo damageInfo = new DamageInfo();
					damageInfo.damage = baseDamage + damagePerStack * (float)buffCount;
					damageInfo.attacker = attacker;
					damageInfo.inflictor = null;
					damageInfo.force = UnityEngine.Vector3.zero;
					damageInfo.crit = isCrit;
					damageInfo.procChainMask = procChainMask;
					damageInfo.procCoefficient = procCoefficient;
					damageInfo.position = position;
					damageInfo.damageColorIndex = damageColorIndex;
					healthComponent.TakeDamage(damageInfo);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
					GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
					EffectManager.SpawnEffect(detonationEffectPrefab, new EffectData
					{
						origin = position,
						rotation = UnityEngine.Quaternion.identity,
						scale = Mathf.Log(buffCount, 5f)
					}, transmit: true);
				}
			}
		}
	}
	public class MicroMissileOrb : GenericDamageOrb
	{
		public override void Begin()
		{
			speed = 55f;
			base.Begin();
		}

		protected override GameObject GetOrbEffect()
		{
			return OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/MicroMissileOrbEffect");
		}
	}
	public class MissileVoidOrb : GenericDamageOrb
	{
		public override void Begin()
		{
			speed = 75f;
			base.Begin();
		}

		protected override GameObject GetOrbEffect()
		{
			return Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/MissileVoid/MissileVoidOrbEffect.prefab").WaitForCompletion();
		}
	}
	public class Orb
	{
		public UnityEngine.Vector3 origin;

		public HurtBox target;

		public Orb nextOrb;

		public float arrivalTime;

		public int instanceID = -1;

		protected static int _InstanceCount;

		protected OrbPool _OwningPool;

		public float duration { get; protected set; }

		public float timeUntilArrival => arrivalTime - OrbManager.instance.time;

		public static int InstanceCount => _InstanceCount;

		protected float distanceToTarget
		{
			get
			{
				if ((bool)target)
				{
					return UnityEngine.Vector3.Distance(target.transform.position, origin);
				}
				return 0f;
			}
		}

		public void SetOwningPool(OrbPool inOwningPool)
		{
			_OwningPool = inOwningPool;
		}

		public Orb()
		{
			_InstanceCount++;
		}

		public virtual void Reset()
		{
			origin = UnityEngine.Vector3.zero;
			target = null;
			duration = 0f;
			arrivalTime = 0f;
			nextOrb = null;
		}

		public virtual void Begin()
		{
		}

		public virtual void OnArrival()
		{
			ReturnToPool();
		}

		public virtual void ReturnToPool()
		{
			if (OrbPool.UsePools && _OwningPool != null)
			{
				_OwningPool.ReturnObject(this);
			}
		}
	}
	public static class OrbCatalog
	{
		private static readonly Dictionary<Type, int> typeToIndex;

		private static Type[] indexToType;

		private static void GenerateCatalog()
		{
			indexToType = (from t in typeof(Orb).Assembly.GetTypes()
				where t.IsSubclassOf(typeof(Orb))
				orderby t.Name
				select t).ToArray();
			typeToIndex.Clear();
			Type[] array = indexToType;
			foreach (Type key in array)
			{
				typeToIndex[key] = typeToIndex.Count;
			}
		}

		static OrbCatalog()
		{
			typeToIndex = new Dictionary<Type, int>();
			indexToType = Array.Empty<Type>();
			GenerateCatalog();
		}

		public static int FindIndex(Type type)
		{
			if (typeToIndex.TryGetValue(type, out var value))
			{
				return value;
			}
			return -1;
		}

		public static Type FindType(int index)
		{
			if (index < 0 || index >= indexToType.Length)
			{
				return null;
			}
			return indexToType[index];
		}

		public static Orb Instantiate(int index)
		{
			return Instantiate(FindType(index));
		}

		public static Orb Instantiate(Type type)
		{
			if (type == null)
			{
				return null;
			}
			return (Orb)Activator.CreateInstance(type);
		}
	}
	[RequireComponent(typeof(EffectComponent))]
	public class OrbEffect : MonoBehaviour
	{
		private Transform targetTransform;

		private float duration;

		private UnityEngine.Vector3 startPosition;

		private UnityEngine.Vector3 previousPosition;

		private UnityEngine.Vector3 lastKnownTargetPosition;

		private float age;

		[HideInInspector]
		public Transform parentObjectTransform;

		[Header("Curve Parameters")]
		public UnityEngine.Vector3 startVelocity1;

		public UnityEngine.Vector3 startVelocity2;

		public UnityEngine.Vector3 endVelocity1;

		public UnityEngine.Vector3 endVelocity2;

		private UnityEngine.Vector3 startVelocity;

		private UnityEngine.Vector3 endVelocity;

		public AnimationCurve movementCurve;

		public BezierCurveLine bezierCurveLine;

		public bool faceMovement = true;

		public bool callArrivalIfTargetIsGone;

		[Header("Start Effect")]
		[Tooltip("An effect prefab to spawn on Start")]
		public GameObject startEffect;

		public float startEffectScale = 1f;

		public bool startEffectCopiesRotation;

		[Header("End Effect")]
		[Tooltip("An effect prefab to spawn on end")]
		public GameObject endEffect;

		public float endEffectScale = 1f;

		public bool endEffectCopiesRotation;

		[Header("Arrival Behavior")]
		public UnityEvent onArrival;

		protected EffectComponent _effectComponent;

		protected EffectManagerHelper _effectManagerHelper;

		protected EffectManagerHelper _parentEffectManagerHelper;

		protected EffectData _effectData;

		protected List<TrailRenderer> _trailRenderers;

		protected bool _arrived;

		protected bool _startCalled;

		private bool orbEffectHasOnArrivalAnimateShaderAlpha;

		public int singletonArrayIndex = -1;

		public void PrepForPoolUsage()
		{
			if (onArrival == null)
			{
				return;
			}
			int num = -1;
			int persistentEventCount = onArrival.GetPersistentEventCount();
			for (int i = 0; i < persistentEventCount; i++)
			{
				UnityEngine.Object persistentTarget = onArrival.GetPersistentTarget(i);
				string persistentMethodName = onArrival.GetPersistentMethodName(i);
				if (persistentMethodName == "DetachChildren")
				{
					num = i;
				}
				else if (persistentMethodName == "set_enabled" && persistentTarget.GetType() == typeof(AnimateShaderAlpha))
				{
					orbEffectHasOnArrivalAnimateShaderAlpha = true;
					AnimateShaderAlpha animateShaderAlpha = persistentTarget as AnimateShaderAlpha;
					if (!animateShaderAlpha.continueExistingAfterTimeMaxIsReached)
					{
						animateShaderAlpha.OnFinished.AddListener(OnAllEffectsOnArrivalCompleted);
					}
					if (animateShaderAlpha.destroyOnEnd)
					{
						animateShaderAlpha.destroyOnEnd = false;
						animateShaderAlpha.disableOnEnd = true;
					}
				}
			}
			if (num != -1)
			{
				onArrival.SetPersistentListenerState(num, UnityEventCallState.Off);
			}
			if (_trailRenderers != null)
			{
				return;
			}
			TrailRenderer[] components = base.gameObject.GetComponents<TrailRenderer>();
			if (components != null && components.Length != 0)
			{
				if (_trailRenderers == null)
				{
					_trailRenderers = new List<TrailRenderer>();
				}
				_trailRenderers.AddRange(components);
			}
			TrailRenderer[] componentsInChildren = base.gameObject.GetComponentsInChildren<TrailRenderer>(includeInactive: true);
			if (componentsInChildren != null && componentsInChildren.Length != 0)
			{
				if (_trailRenderers == null)
				{
					_trailRenderers = new List<TrailRenderer>();
				}
				_trailRenderers.AddRange(componentsInChildren);
			}
		}

		private void OnAllEffectsOnArrivalCompleted()
		{
			if (_effectManagerHelper != null && _effectManagerHelper.OwningPool != null)
			{
				_effectManagerHelper.OwningPool.ReturnObject(_effectManagerHelper);
				return;
			}
			if (_effectManagerHelper != null)
			{
				UnityEngine.Debug.LogErrorFormat("OrbEffect: No owning pool set. {0} ({1})", base.gameObject.name, base.gameObject.GetInstanceID());
			}
			UnityEngine.Object.Destroy(base.gameObject);
		}

		public void Reset()
		{
			if (!_startCalled)
			{
				return;
			}
			if (_effectManagerHelper == null)
			{
				_effectManagerHelper = base.gameObject.GetComponent<EffectManagerHelper>();
			}
			if (_effectComponent == null)
			{
				_effectComponent = base.gameObject.GetComponent<EffectComponent>();
			}
			if (_parentEffectManagerHelper == null)
			{
				_parentEffectManagerHelper = ((base.gameObject.transform.parent != null) ? base.gameObject.transform.parent.gameObject.GetComponent<EffectManagerHelper>() : null);
			}
			if (_effectData != null)
			{
				_effectData.Reset();
			}
			targetTransform = null;
			duration = 0f;
			startPosition = UnityEngine.Vector3.zero;
			previousPosition = UnityEngine.Vector3.zero;
			lastKnownTargetPosition = UnityEngine.Vector3.zero;
			age = 0f;
			startVelocity = UnityEngine.Vector3.zero;
			endVelocity = UnityEngine.Vector3.zero;
			parentObjectTransform = null;
			startPosition = _effectComponent.effectData.origin;
			previousPosition = startPosition;
			GameObject gameObject = _effectComponent.effectData.ResolveHurtBoxReference();
			targetTransform = (gameObject ? gameObject.transform : null);
			duration = _effectComponent.effectData.genericFloat;
			if (duration == 0f)
			{
				UnityEngine.Debug.LogFormat("Zero duration for effect \"{0}\" {1}:{2}:{3}.{4}", base.gameObject.name, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond);
				if (!EffectManager.UsePools)
				{
					UnityEngine.Object.Destroy(base.gameObject);
					return;
				}
				if (_effectManagerHelper != null && _effectManagerHelper.OwningPool != null)
				{
					_effectManagerHelper.OwningPool.ReturnObject(_effectManagerHelper);
					return;
				}
				if (_effectManagerHelper != null)
				{
					UnityEngine.Debug.LogErrorFormat("OrbEffect: No owning pool set. {0} ({1})", base.gameObject.name, base.gameObject.GetInstanceID());
				}
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			lastKnownTargetPosition = (targetTransform ? targetTransform.position : startPosition);
			if ((bool)startEffect)
			{
				if (_effectData == null)
				{
					_effectData = new EffectData();
				}
				_effectData.Reset();
				_effectData.origin = base.transform.position;
				_effectData.scale = startEffectScale;
				if (startEffectCopiesRotation)
				{
					_effectData.rotation = base.transform.rotation;
				}
				EffectManager.SpawnEffect(startEffect, _effectData, transmit: false);
			}
			startVelocity.x = Mathf.Lerp(startVelocity1.x, startVelocity2.x, UnityEngine.Random.value);
			startVelocity.y = Mathf.Lerp(startVelocity1.y, startVelocity2.y, UnityEngine.Random.value);
			startVelocity.z = Mathf.Lerp(startVelocity1.z, startVelocity2.z, UnityEngine.Random.value);
			endVelocity.x = Mathf.Lerp(endVelocity1.x, endVelocity2.x, UnityEngine.Random.value);
			endVelocity.y = Mathf.Lerp(endVelocity1.y, endVelocity2.y, UnityEngine.Random.value);
			endVelocity.z = Mathf.Lerp(endVelocity1.z, endVelocity2.z, UnityEngine.Random.value);
			if (_trailRenderers != null)
			{
				foreach (TrailRenderer trailRenderer in _trailRenderers)
				{
					trailRenderer.Clear();
				}
			}
			_arrived = false;
			UpdateOrb(0f);
		}

		private void OnEnable()
		{
			OrbEffectSingleton.RegisterInstance(this);
		}

		private void OnDisable()
		{
			OrbEffectSingleton.UnregisterInstance(this);
		}

		private void Start()
		{
			_startCalled = true;
			EffectComponent component = GetComponent<EffectComponent>();
			_effectComponent = component;
			_effectManagerHelper = base.gameObject.GetComponent<EffectManagerHelper>();
			_parentEffectManagerHelper = ((base.gameObject.transform.parent != null) ? base.gameObject.transform.parent.gameObject.GetComponent<EffectManagerHelper>() : null);
			Reset();
		}

		public void UpdateOrb(float deltaTime)
		{
			if (_arrived)
			{
				return;
			}
			if ((bool)parentObjectTransform)
			{
				startPosition = parentObjectTransform.position;
			}
			if ((bool)targetTransform)
			{
				lastKnownTargetPosition = targetTransform.position;
			}
			float num = ((duration == 0f) ? 0f : Mathf.Clamp01(age / duration));
			float num2 = movementCurve.Evaluate(num);
			UnityEngine.Vector3 vector = UnityEngine.Vector3.Lerp(startPosition + startVelocity * num2, lastKnownTargetPosition + endVelocity * (1f - num2), num2);
			base.transform.position = vector;
			if (faceMovement && vector != previousPosition)
			{
				base.transform.forward = vector - previousPosition;
			}
			UpdateBezier();
			if ((num >= 1f || (callArrivalIfTargetIsGone && targetTransform == null)) && !_arrived)
			{
				onArrival.Invoke();
				if ((bool)endEffect)
				{
					if (_effectData == null)
					{
						_effectData = new EffectData();
					}
					_effectData.Reset();
					_effectData.origin = base.transform.position;
					_effectData.scale = endEffectScale;
					if (endEffectCopiesRotation)
					{
						_effectData.rotation = base.transform.rotation;
					}
					EffectManager.SpawnEffect(endEffect, _effectData, transmit: false);
				}
				if (!EffectManager.UsePools)
				{
					UnityEngine.Object.Destroy(base.gameObject);
				}
				else if (_effectManagerHelper != null && _effectManagerHelper.OwningPool != null)
				{
					if (!_effectManagerHelper.HasDestroyOnTimer && !_effectManagerHelper.HasAnimateShaderAlphas && !orbEffectHasOnArrivalAnimateShaderAlpha)
					{
						_effectManagerHelper.OwningPool.ReturnObject(_effectManagerHelper);
					}
				}
				else
				{
					if (_effectManagerHelper != null)
					{
						UnityEngine.Debug.LogErrorFormat("OrbEffect: No owning pool set. {0} ({1})", base.gameObject.name, base.gameObject.GetInstanceID());
					}
					UnityEngine.Object.Destroy(base.gameObject);
				}
				_arrived = true;
			}
			if (!_arrived)
			{
				previousPosition = vector;
				age += deltaTime;
			}
		}

		private void UpdateBezier()
		{
			if ((bool)bezierCurveLine)
			{
				bezierCurveLine.p1 = startPosition;
				bezierCurveLine.v0 = endVelocity;
				bezierCurveLine.v1 = startVelocity;
				bezierCurveLine.UpdateBezier(0f);
			}
		}

		public void InstantiatePrefab(GameObject prefab)
		{
			UnityEngine.Object.Instantiate(prefab, base.transform.position, base.transform.rotation);
		}

		public void InstantiateEffect(GameObject prefab)
		{
			EffectManager.SpawnEffect(prefab, new EffectData
			{
				origin = base.transform.position
			}, transmit: false);
		}

		public void InstantiateEffectCopyRotation(GameObject prefab)
		{
			EffectManager.SpawnEffect(prefab, new EffectData
			{
				origin = base.transform.position,
				rotation = base.transform.rotation
			}, transmit: false);
		}

		public void InstantiateEffectOppositeFacing(GameObject prefab)
		{
			EffectManager.SpawnEffect(prefab, new EffectData
			{
				origin = base.transform.position,
				rotation = Util.QuaternionSafeLookRotation(-base.transform.forward)
			}, transmit: false);
		}

		public void InstantiatePrefabOppositeFacing(GameObject prefab)
		{
			UnityEngine.Object.Instantiate(prefab, base.transform.position, Util.QuaternionSafeLookRotation(-base.transform.forward));
		}
	}
	public class OrbManager : MonoBehaviour
	{
		private List<Orb> travelingOrbs = new List<Orb>();

		private float nextOrbArrival = float.PositiveInfinity;

		private List<IOrbFixedUpdateBehavior> orbsWithFixedUpdateBehavior = new List<IOrbFixedUpdateBehavior>();

		public static OrbManager instance { get; private set; }

		public float time { get; private set; }

		private void OnEnable()
		{
			if (!instance)
			{
				instance = this;
				return;
			}
			UnityEngine.Debug.LogErrorFormat(this, "Duplicate instance of singleton class {0}. Only one should exist at a time.", GetType().Name);
		}

		private void OnDisable()
		{
			if (instance == this)
			{
				instance = null;
			}
		}

		private void FixedUpdate()
		{
			time += Time.fixedDeltaTime;
			for (int i = 0; i < orbsWithFixedUpdateBehavior.Count; i++)
			{
				orbsWithFixedUpdateBehavior[i].FixedUpdate();
			}
			if (!(nextOrbArrival <= time))
			{
				return;
			}
			nextOrbArrival = float.PositiveInfinity;
			for (int num = travelingOrbs.Count - 1; num >= 0; num--)
			{
				Orb orb = travelingOrbs[num];
				if (orb.arrivalTime <= time)
				{
					travelingOrbs.RemoveAt(num);
					if (orb is IOrbFixedUpdateBehavior item)
					{
						orbsWithFixedUpdateBehavior.Remove(item);
					}
					orb.OnArrival();
				}
				else if (nextOrbArrival > orb.arrivalTime)
				{
					nextOrbArrival = orb.arrivalTime;
				}
			}
		}

		public void ForceImmediateArrival(Orb orb)
		{
			orb.OnArrival();
			travelingOrbs.Remove(orb);
		}

		public void AddOrb(Orb orb)
		{
			orb.Begin();
			orb.arrivalTime = time + orb.duration;
			travelingOrbs.Add(orb);
			if (orb is IOrbFixedUpdateBehavior item)
			{
				orbsWithFixedUpdateBehavior.Add(item);
			}
			if (nextOrbArrival > orb.arrivalTime)
			{
				nextOrbArrival = orb.arrivalTime;
			}
		}
	}
	public static class OrbStorageUtility
	{
		private static Dictionary<string, GameObject> _orbDictionary = new Dictionary<string, GameObject>();

		public static GameObject Get(string path)
		{
			if (!_orbDictionary.ContainsKey(path))
			{
				_orbDictionary.Add(path, LegacyResourcesAPI.Load<GameObject>(path));
			}
			return _orbDictionary[path];
		}

		public static void Clear()
		{
			_orbDictionary.Clear();
		}
	}
	public class SimpleLightningStrikeOrb : GenericDamageOrb, IOrbFixedUpdateBehavior
	{
		private UnityEngine.Vector3 lastKnownTargetPosition;

		public override void Begin()
		{
			base.Begin();
			base.duration = 0.25f;
			if ((bool)target)
			{
				lastKnownTargetPosition = target.transform.position;
			}
		}

		protected override GameObject GetOrbEffect()
		{
			return OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/SimpleLightningStrikeOrbEffect");
		}

		public override void OnArrival()
		{
			EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/ImpactEffects/SimpleLightningStrikeImpact"), new EffectData
			{
				origin = lastKnownTargetPosition
			}, transmit: true);
			if ((bool)attacker)
			{
				BlastAttack blastAttack = new BlastAttack();
				blastAttack.attacker = attacker;
				blastAttack.baseDamage = damageValue;
				blastAttack.baseForce = 0f;
				blastAttack.bonusForce = UnityEngine.Vector3.down * 1500f;
				blastAttack.crit = isCrit;
				blastAttack.damageColorIndex = DamageColorIndex.Item;
				blastAttack.falloffModel = BlastAttack.FalloffModel.None;
				blastAttack.inflictor = null;
				blastAttack.position = lastKnownTargetPosition;
				blastAttack.procChainMask = procChainMask;
				blastAttack.procCoefficient = procCoefficient;
				blastAttack.radius = 3f;
				blastAttack.teamIndex = TeamComponent.GetObjectTeam(attacker);
				blastAttack.Fire();
			}
		}

		public void FixedUpdate()
		{
			if ((bool)target)
			{
				lastKnownTargetPosition = target.transform.position;
			}
		}
	}
	public class SquidOrb : GenericDamageOrb
	{
		public float forceScalar;

		public override void Begin()
		{
			speed = 120f;
			base.Begin();
		}

		protected override GameObject GetOrbEffect()
		{
			return OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/SquidOrbEffect");
		}

		public override void OnArrival()
		{
			if (!target)
			{
				return;
			}
			HealthComponent healthComponent = target.healthComponent;
			if ((bool)healthComponent)
			{
				UnityEngine.Vector3 force = target.transform.position - origin;
				if (force.sqrMagnitude > 0f)
				{
					force.Normalize();
					force *= forceScalar;
				}
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = damageValue;
				damageInfo.attacker = attacker;
				damageInfo.inflictor = null;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.crit = isCrit;
				damageInfo.procChainMask = procChainMask;
				damageInfo.procCoefficient = procCoefficient;
				damageInfo.position = target.transform.position;
				damageInfo.damageColorIndex = damageColorIndex;
				damageInfo.damageType = damageType;
				damageInfo.force = force;
				healthComponent.TakeDamage(damageInfo);
				GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
				GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
			}
		}
	}
	public class TitanRechargeOrb : Orb
	{
		public int targetRockInt;

		public TitanRockController titanRockController;

		public override void Begin()
		{
			base.duration = 1f;
			EffectData effectData = new EffectData
			{
				origin = origin,
				genericFloat = base.duration
			};
			effectData.SetHurtBoxReference(target);
			EffectManager.SpawnEffect(OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/HealthOrbEffect"), effectData, transmit: true);
		}

		public override void OnArrival()
		{
		}
	}
	public class VendingMachineOrb : Orb
	{
		public float healFraction;

		public bool scaleOrb = true;

		public float speed = 10f;

		public override void Begin()
		{
			if ((bool)target)
			{
				base.duration = Mathf.Max(1f, base.distanceToTarget / speed);
				float scale = (scaleOrb ? Mathf.Min(healFraction, 1f) : 1f);
				EffectData effectData = new EffectData
				{
					scale = scale,
					origin = origin,
					genericFloat = base.duration
				};
				effectData.SetHurtBoxReference(target);
				EffectManager.SpawnEffect(Addressables.LoadAssetAsync<GameObject>("RoR2/DLC1/VendingMachine/VendingMachineOrbEffect.prefab").WaitForCompletion(), effectData, transmit: true);
			}
		}

		public override void OnArrival()
		{
			if ((bool)target)
			{
				HealthComponent healthComponent = target.healthComponent;
				if ((bool)healthComponent)
				{
					healthComponent.HealFraction(healFraction, default(ProcChainMask));
				}
			}
		}
	}
	public class VoidLightningOrb : Orb, IOrbFixedUpdateBehavior
	{
		public float damageValue;

		public GameObject attacker;

		public GameObject inflictor;

		public int totalStrikes;

		public float secondsPerStrike = 0.5f;

		public TeamIndex teamIndex;

		public bool isCrit;

		public ProcChainMask procChainMask;

		public float procCoefficient = 1f;

		public DamageColorIndex damageColorIndex;

		public DamageTypeCombo damageType = DamageType.Generic;

		private GameObject effectPrefab;

		private float accumulatedTime;

		public override void Begin()
		{
			accumulatedTime = 0f;
			base.duration = (float)(totalStrikes - 1) * secondsPerStrike;
			effectPrefab = OrbStorageUtility.Get("Prefabs/Effects/OrbEffects/VoidLightningOrbEffect");
			Strike();
		}

		public override void OnArrival()
		{
		}

		public void FixedUpdate()
		{
			accumulatedTime += Time.fixedDeltaTime;
			while (accumulatedTime > secondsPerStrike)
			{
				accumulatedTime -= secondsPerStrike;
				if ((bool)target)
				{
					origin = target.transform.position;
					Strike();
				}
			}
		}

		private void Strike()
		{
			if (!target)
			{
				return;
			}
			HealthComponent healthComponent = target.healthComponent;
			if ((bool)healthComponent)
			{
				DamageInfo damageInfo = new DamageInfo();
				damageInfo.damage = damageValue;
				damageInfo.attacker = attacker;
				damageInfo.inflictor = inflictor;
				damageInfo.force = UnityEngine.Vector3.zero;
				damageInfo.crit = isCrit;
				damageInfo.procChainMask = procChainMask;
				damageInfo.procCoefficient = procCoefficient;
				damageInfo.position = target.transform.position;
				damageInfo.damageColorIndex = damageColorIndex;
				damageInfo.damageType = damageType;
				healthComponent.TakeDamage(damageInfo);
				GlobalEventManager.instance.OnHitEnemy(damageInfo, healthComponent.gameObject);
				GlobalEventManager.instance.OnHitAll(damageInfo, healthComponent.gameObject);
				if ((bool)target.hurtBoxGroup)
				{
					target = target.hurtBoxGroup.hurtBoxes[UnityEngine.Random.Range(0, target.hurtBoxGroup.hurtBoxes.Length)];
				}
				EffectData effectData = new EffectData
				{
					origin = origin,
					genericFloat = 0.1f
				};
				effectData.SetHurtBoxReference(target);
				EffectManager.SpawnEffect(effectPrefab, effectData, transmit: true);
			}
		}
	}
}
namespace RoR2.CameraModes
{
	public abstract class CameraModeBase
	{
		public struct CameraInfo
		{
			public CameraRigController cameraRigController;

			public Camera sceneCam;

			public ICameraStateProvider overrideCam;

			public CameraState previousCameraState;

			public float baseFov;
		}

		public struct TargetInfo
		{
			public GameObject target;

			public CharacterBody body;

			public InputBankTest inputBank;

			public CameraTargetParams targetParams;

			public TeamIndex teamIndex;

			public bool isSprinting;

			public bool skillsAreDisabled;

			public bool isViewerControlled;

			public CharacterMaster master;

			public NetworkUser networkUser;

			public NetworkedViewAngles networkedViewAngles;
		}

		public struct ViewerInfo
		{
			public LocalUser localUser;

			public UserProfile userProfile;

			public Player inputPlayer;

			public MPEventSystem eventSystem;

			public bool hasCursor;

			public bool isUIFocused;
		}

		public struct CameraModeContext
		{
			public CameraInfo cameraInfo;

			public TargetInfo targetInfo;

			public ViewerInfo viewerInfo;
		}

		public struct UpdateArgs
		{
			public CameraInfo cameraInfo;

			public TargetInfo targetInfo;
		}

		public struct UpdateResult
		{
			public GameObject firstPersonTarget;

			public CameraState cameraState;

			public bool showSprintParticles;

			public bool showDisabledSkillsParticles;

			public UnityEngine.Vector3 crosshairWorldPosition;
		}

		public struct CollectLookInputResult
		{
			public UnityEngine.Vector2 lookInput;
		}

		public struct ApplyLookInputArgs
		{
			public UnityEngine.Vector2 lookInput;
		}

		public struct OnTargetChangedArgs
		{
			public GameObject oldTarget;

			public GameObject newTarget;
		}

		private Dictionary<UnityObjectWrapperKey<CameraRigController>, object> camToRawInstanceData = new Dictionary<UnityObjectWrapperKey<CameraRigController>, object>();

		public void OnInstall(CameraRigController cameraRigController)
		{
			object obj = CreateInstanceData(cameraRigController);
			camToRawInstanceData.Add(cameraRigController, obj);
			try
			{
				OnInstallInternal(obj, cameraRigController);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			if ((object)cameraRigController.target != null)
			{
				OnTargetChanged(cameraRigController, new OnTargetChangedArgs
				{
					oldTarget = null,
					newTarget = cameraRigController.target
				});
			}
		}

		protected virtual void OnInstallInternal(object rawInstancedata, CameraRigController cameraRigController)
		{
		}

		public void OnUninstall(CameraRigController cameraRigController)
		{
			if ((object)cameraRigController.target != null)
			{
				OnTargetChanged(cameraRigController, new OnTargetChangedArgs
				{
					oldTarget = cameraRigController.target,
					newTarget = null
				});
			}
			try
			{
				OnUninstallInternal(camToRawInstanceData[cameraRigController], cameraRigController);
			}
			catch (Exception message)
			{
				UnityEngine.Debug.LogError(message);
			}
			camToRawInstanceData.Remove(cameraRigController);
		}

		protected virtual void OnUninstallInternal(object rawInstanceData, CameraRigController cameraRigController)
		{
		}

		protected abstract object CreateInstanceData(CameraRigController cameraRigController);

		public abstract bool IsSpectating(CameraRigController cameraRigController);

		public void Update(in CameraModeContext context, out UpdateResult result)
		{
			if ((bool)context.cameraInfo.cameraRigController)
			{
				object rawInstanceData = camToRawInstanceData[context.cameraInfo.cameraRigController];
				UpdateInternal(rawInstanceData, in context, out result);
			}
			else
			{
				result = default(UpdateResult);
			}
		}

		protected abstract void UpdateInternal(object rawInstanceData, in CameraModeContext context, out UpdateResult result);

		public void CollectLookInput(in CameraModeContext context, out CollectLookInputResult result)
		{
			object rawInstanceData = camToRawInstanceData[context.cameraInfo.cameraRigController];
			CollectLookInputInternal(rawInstanceData, in context, out result);
		}

		protected abstract void CollectLookInputInternal(object rawInstanceData, in CameraModeContext context, out CollectLookInputResult result);

		public void ApplyLookInput(in CameraModeContext context, in ApplyLookInputArgs args)
		{
			object rawInstanceData = camToRawInstanceData[context.cameraInfo.cameraRigController];
			ApplyLookInputInternal(rawInstanceData, in context, in args);
		}

		protected abstract void ApplyLookInputInternal(object rawInstanceData, in CameraModeContext context, in ApplyLookInputArgs input);

		public void OnTargetChanged(CameraRigController cameraRigController, OnTargetChangedArgs args)
		{
			object rawInstanceData = camToRawInstanceData[cameraRigController];
			OnTargetChangedInternal(rawInstanceData, cameraRigController, in args);
		}

		protected abstract void OnTargetChangedInternal(object rawInstanceData, CameraRigController cameraRigController, in OnTargetChangedArgs args);

		public void MatchState(in CameraModeContext context, in CameraState cameraStateToMatch)
		{
			object rawInstanceData = camToRawInstanceData[context.cameraInfo.cameraRigController];
			MatchStateInternal(rawInstanceData, in context, in cameraStateToMatch);
		}

		protected abstract void MatchStateInternal(object rawInstanceData, in CameraModeContext context, in CameraState cameraStateToMatch);

		public object DebugGetInstanceData(CameraRigController cameraRigController)
		{
			camToRawInstanceData.TryGetValue(cameraRigController, out var value);
			return value;
		}
	}
	public class CameraModeNone : CameraModeBase
	{
		public static readonly CameraModeNone instance;

		public override bool IsSpectating(CameraRigController cameraRigController)
		{
			return true;
		}

		protected override void ApplyLookInputInternal(object rawInstanceData, in CameraModeContext context, in ApplyLookInputArgs input)
		{
		}

		protected override void CollectLookInputInternal(object rawInstanceData, in CameraModeContext context, out CollectLookInputResult result)
		{
			result.lookInput = UnityEngine.Vector2.zero;
		}

		protected override object CreateInstanceData(CameraRigController cameraRigController)
		{
			return null;
		}

		protected override void MatchStateInternal(object rawInstanceData, in CameraModeContext context, in CameraState cameraStateToMatch)
		{
		}

		protected override void OnTargetChangedInternal(object rawInstanceData, CameraRigController cameraRigController, in OnTargetChangedArgs args)
		{
		}

		protected override void UpdateInternal(object rawInstanceData, in CameraModeContext context, out UpdateResult result)
		{
			result.cameraState = context.cameraInfo.previousCameraState;
			result.firstPersonTarget = null;
			result.showSprintParticles = false;
			result.showDisabledSkillsParticles = false;
			result.crosshairWorldPosition = result.cameraState.position;
		}
	}
	public class CameraModePlayer2D : CameraModeBase
	{
		private class InstanceData
		{
			public float facing = 1f;
		}

		public static readonly CameraModePlayer2D instance = new CameraModePlayer2D();

		public override bool IsSpectating(CameraRigController cameraRigController)
		{
			return false;
		}

		protected override void ApplyLookInputInternal(object rawInstanceData, in CameraModeContext context, in ApplyLookInputArgs input)
		{
		}

		protected override void CollectLookInputInternal(object rawInstanceData, in CameraModeContext context, out CollectLookInputResult result)
		{
			result.lookInput = UnityEngine.Vector2.zero;
		}

		protected override object CreateInstanceData(CameraRigController cameraRigController)
		{
			return new InstanceData();
		}

		protected override void MatchStateInternal(object rawInstanceData, in CameraModeContext context, in CameraState cameraStateToMatch)
		{
		}

		protected override void OnTargetChangedInternal(object rawInstanceData, CameraRigController cameraRigController, in OnTargetChangedArgs args)
		{
		}

		protected override void UpdateInternal(object rawInstanceData, in CameraModeContext context, out UpdateResult result)
		{
			InstanceData instanceData = (InstanceData)rawInstanceData;
			result.cameraState = context.cameraInfo.previousCameraState;
			result.firstPersonTarget = null;
			result.showSprintParticles = false;
			result.showDisabledSkillsParticles = false;
			result.crosshairWorldPosition = result.cameraState.position;
			if (!context.targetInfo.target)
			{
				return;
			}
			UnityEngine.Quaternion identity = UnityEngine.Quaternion.identity;
			UnityEngine.Vector3 vector = identity * UnityEngine.Quaternion.Euler(0f, 90f, 0f) * UnityEngine.Vector3.forward;
			UnityEngine.Quaternion quaternion = ((!context.targetInfo.body || !context.targetInfo.body.characterDirection) ? context.targetInfo.target.transform.rotation : UnityEngine.Quaternion.Euler(0f, context.targetInfo.body.characterDirection.yaw, 0f));
			UnityEngine.Vector3 vector2 = context.targetInfo.target.transform.position;
			if ((bool)context.targetInfo.inputBank)
			{
				float num = UnityEngine.Vector3.Dot(vector, context.targetInfo.inputBank.moveVector);
				if (num != 0f)
				{
					instanceData.facing = num;
				}
				vector2 = context.targetInfo.inputBank.aimOrigin;
			}
			_ = quaternion * UnityEngine.Quaternion.Euler(0f, 90f, 0f);
			result.cameraState.rotation = identity;
			result.cameraState.position = context.targetInfo.target.transform.position + new UnityEngine.Vector3(0f, 10f, 0f) + identity * UnityEngine.Vector3.forward * -30f;
			result.cameraState.fov = 60f;
			result.crosshairWorldPosition = vector2 + vector * instanceData.facing * 30f;
		}
	}
	public class CameraModePlayerBasic : CameraModeBase
	{
		protected class InstanceData
		{
			public float currentCameraDistance;

			public float cameraDistanceVelocity;

			public float stickAimPreviousAcceleratedMagnitude;

			public float minPitch;

			public float maxPitch;

			public PitchYawPair pitchYaw;

			public CameraRigController.AimAssistInfo lastAimAssist;

			public CameraRigController.AimAssistInfo aimAssist;

			public HurtBox lastCrosshairHurtBox;

			public bool hasEverHadTarget;

			public float neutralFov;

			public float neutralFovVelocity;

			public void SetPitchYawFromLookVector(UnityEngine.Vector3 lookVector)
			{
				UnityEngine.Vector3 vector = lookVector;
				float x = Mathf.Sqrt(vector.x * vector.x + vector.z * vector.z);
				pitchYaw.pitch = Mathf.Atan2(0f - vector.y, x) * 57.29578f;
				pitchYaw.yaw = Mathf.Repeat(Mathf.Atan2(vector.x, vector.z) * 57.29578f, 360f);
			}
		}

		public SurvivorIndex targetSurvivorClass;

		private bool skipFirst;

		public bool isSpectatorMode;

		public UnityEngine.Vector3 prevGyroAngle;

		public static CameraModePlayerBasic playerBasic = new CameraModePlayerBasic
		{
			isSpectatorMode = false
		};

		public static CameraModePlayerBasic spectator = new CameraModePlayerBasic
		{
			isSpectatorMode = true
		};

		protected override object CreateInstanceData(CameraRigController cameraRigController)
		{
			return new InstanceData();
		}

		protected override void OnInstallInternal(object rawInstancedata, CameraRigController cameraRigController)
		{
			base.OnInstallInternal(rawInstancedata, cameraRigController);
			((InstanceData)rawInstancedata).neutralFov = cameraRigController.baseFov;
		}

		public override bool IsSpectating(CameraRigController cameraRigController)
		{
			return isSpectatorMode;
		}

		protected override void UpdateInternal(object rawInstanceData, in CameraModeContext context, out UpdateResult result)
		{
			InstanceData instanceData = (InstanceData)rawInstanceData;
			CameraRigController cameraRigController = context.cameraInfo.cameraRigController;
			CameraTargetParams targetParams = context.targetInfo.targetParams;
			float fov = context.cameraInfo.baseFov;
			UnityEngine.Quaternion quaternion = context.cameraInfo.previousCameraState.rotation;
			UnityEngine.Vector3 position = context.cameraInfo.previousCameraState.position;
			GameObject firstPersonTarget = null;
			float num = cameraRigController.baseFov;
			if (context.targetInfo.isSprinting)
			{
				num *= 1.3f;
			}
			instanceData.neutralFov = Mathf.SmoothDamp(instanceData.neutralFov, num, ref instanceData.neutralFovVelocity, 0.2f, float.PositiveInfinity, Time.deltaTime);
			CharacterCameraParamsData dest = CharacterCameraParamsData.basic;
			dest.fov = instanceData.neutralFov;
			UnityEngine.Vector2 vector = UnityEngine.Vector2.zero;
			if ((bool)targetParams)
			{
				CharacterCameraParamsData.Blend(in targetParams.currentCameraParamsData, ref dest, 1f);
				fov = dest.fov.value;
				vector = targetParams.recoil;
			}
			if (dest.isFirstPerson.value)
			{
				firstPersonTarget = context.targetInfo.target;
			}
			instanceData.minPitch = dest.minPitch.value;
			instanceData.maxPitch = dest.maxPitch.value;
			float pitch = instanceData.pitchYaw.pitch;
			float yaw = instanceData.pitchYaw.yaw;
			pitch += vector.y;
			yaw += vector.x;
			pitch = Mathf.Clamp(pitch, instanceData.minPitch, instanceData.maxPitch);
			yaw = Mathf.Repeat(yaw, 360f);
			UnityEngine.Vector3 targetPivotPosition = CalculateTargetPivotPosition(in context);
			if ((bool)context.targetInfo.target)
			{
				quaternion = UnityEngine.Quaternion.Euler(pitch, yaw, 0f);
				UnityEngine.Vector3 direction = targetPivotPosition + quaternion * dest.idealLocalCameraPos.value - targetPivotPosition;
				float magnitude = direction.magnitude;
				float num2 = (1f + pitch / -90f) * 0.5f;
				magnitude *= Mathf.Sqrt(1f - num2);
				if (magnitude < 0.25f)
				{
					magnitude = 0.25f;
				}
				Ray ray = new Ray(targetPivotPosition, direction);
				float num3 = cameraRigController.Raycast(new Ray(targetPivotPosition, direction), magnitude, dest.wallCushion.value - 0.01f);
				UnityEngine.Debug.DrawRay(ray.origin, ray.direction * magnitude, UnityEngine.Color.yellow, Time.deltaTime);
				UnityEngine.Debug.DrawRay(ray.origin, ray.direction * num3, UnityEngine.Color.red, Time.deltaTime);
				if (instanceData.currentCameraDistance >= num3)
				{
					instanceData.currentCameraDistance = num3;
					instanceData.cameraDistanceVelocity = 0f;
				}
				else
				{
					instanceData.currentCameraDistance = Mathf.SmoothDamp(instanceData.currentCameraDistance, num3, ref instanceData.cameraDistanceVelocity, 0.5f);
				}
				position = targetPivotPosition + direction.normalized * instanceData.currentCameraDistance;
			}
			result.cameraState.position = position;
			result.cameraState.rotation = quaternion;
			result.cameraState.fov = fov;
			result.showSprintParticles = context.targetInfo.isSprinting;
			result.showDisabledSkillsParticles = context.targetInfo.skillsAreDisabled;
			result.firstPersonTarget = firstPersonTarget;
			UpdateCrosshair(rawInstanceData, in context, in result.cameraState, in targetPivotPosition, out result.crosshairWorldPosition);
		}

		protected override void CollectLookInputInternal(object rawInstanceData, in CameraModeContext context, out CollectLookInputResult output)
		{
			InstanceData instanceData = (InstanceData)rawInstanceData;
			ref readonly CameraInfo cameraInfo = ref context.cameraInfo;
			ref readonly ViewerInfo viewerInfo = ref context.viewerInfo;
			ref readonly TargetInfo targetInfo = ref context.targetInfo;
			bool hasCursor = viewerInfo.hasCursor;
			Player inputPlayer = viewerInfo.inputPlayer;
			UserProfile userProfile = viewerInfo.userProfile;
			ICameraStateProvider overrideCam = cameraInfo.overrideCam;
			output.lookInput = UnityEngine.Vector3.zero;
			if (!hasCursor && viewerInfo.inputPlayer != null && userProfile != null && !viewerInfo.isUIFocused && (!(UnityEngine.Object)overrideCam || overrideCam.IsUserLookAllowed(cameraInfo.cameraRigController)))
			{
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(inputPlayer.GetAxisRaw(2), inputPlayer.GetAxisRaw(3));
				UnityEngine.Vector2 aimStickVector = new UnityEngine.Vector2(inputPlayer.GetAxisRaw(16), inputPlayer.GetAxisRaw(17));
				ConditionalNegate(ref vector.x, userProfile.mouseLookInvertX);
				ConditionalNegate(ref vector.y, userProfile.mouseLookInvertY);
				ConditionalNegate(ref aimStickVector.x, userProfile.stickLookInvertX);
				ConditionalNegate(ref aimStickVector.y, userProfile.stickLookInvertY);
				PerformStickPostProcessing(instanceData, in context, ref aimStickVector);
				float mouseLookSensitivity = userProfile.mouseLookSensitivity;
				float num = userProfile.stickLookSensitivity * CameraRigController.aimStickGlobalScale.value * 45f;
				UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(userProfile.mouseLookScaleX, userProfile.mouseLookScaleY);
				UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(userProfile.stickLookScaleX, userProfile.stickLookScaleY);
				vector *= vector2 * mouseLookSensitivity;
				aimStickVector *= vector3 * num;
				PerformAimAssist(in context, ref aimStickVector);
				aimStickVector *= Time.deltaTime;
				output.lookInput = vector + aimStickVector;
				if (userProfile.gyroEnabled)
				{
					UnityEngine.Vector3 gyroAimDeltaVector = PlatformSystems.platformManager.GetGyroAimDeltaVector();
					bool flag = false;
					flag = ((targetSurvivorClass == RoR2Content.Survivors.Huntress.survivorIndex) ? userProfile.gyroDisabledDuringSprint_Huntress : ((targetSurvivorClass != RoR2Content.Survivors.Loader.survivorIndex && targetSurvivorClass != RoR2Content.Survivors.Merc.survivorIndex && targetSurvivorClass != RoR2Content.Survivors.Croco.survivorIndex) ? userProfile.gyroDisabledDuringSprint : userProfile.gyroDisabledDuringSprint_Melee));
					if (!context.targetInfo.isSprinting || !flag)
					{
						ConditionalNegate(ref gyroAimDeltaVector.x, userProfile.gyroLookInvertY);
						ConditionalNegate(ref gyroAimDeltaVector.y, userProfile.gyroLookInvertX);
						if (skipFirst)
						{
							output.lookInput += new UnityEngine.Vector2((0f - gyroAimDeltaVector.y) * userProfile.gyroLookSensitivity * userProfile.gyroLookScaleX * 1250f, gyroAimDeltaVector.x * userProfile.gyroLookSensitivity * userProfile.gyroLookScaleY * 1250f);
						}
						else
						{
							skipFirst = true;
						}
					}
				}
			}
			output.lookInput *= cameraInfo.previousCameraState.fov / cameraInfo.baseFov;
			if (targetInfo.isSprinting && CameraRigController.enableSprintSensitivitySlowdown.value)
			{
				output.lookInput *= 0.5f;
			}
			static void ConditionalNegate(ref float value, bool condition)
			{
				value = (condition ? (0f - value) : value);
			}
		}

		private void PerformStickPostProcessing(InstanceData instanceData, in CameraModeContext context, ref UnityEngine.Vector2 aimStickVector)
		{
			float magnitude = aimStickVector.magnitude;
			float num = magnitude;
			_ = UnityEngine.Vector2.zero;
			_ = UnityEngine.Vector2.zero;
			_ = UnityEngine.Vector2.zero;
			if (CameraRigController.aimStickDualZoneSmoothing.value != 0f)
			{
				float maxDelta = Time.deltaTime / CameraRigController.aimStickDualZoneSmoothing.value;
				num = (instanceData.stickAimPreviousAcceleratedMagnitude = Mathf.Min(Mathf.MoveTowards(instanceData.stickAimPreviousAcceleratedMagnitude, magnitude, maxDelta), magnitude));
				if (magnitude == 0f)
				{
					_ = UnityEngine.Vector2.zero;
				}
				else
				{
					_ = aimStickVector * (num / magnitude);
				}
			}
			float num2 = num;
			float value = CameraRigController.aimStickDualZoneSlope.value;
			float num3 = ((!(num2 <= CameraRigController.aimStickDualZoneThreshold.value)) ? (1f - value) : 0f);
			num = value * num2 + num3;
			if (magnitude == 0f)
			{
				_ = UnityEngine.Vector2.zero;
			}
			else
			{
				_ = aimStickVector * (num / magnitude);
			}
			num = Mathf.Pow(num, CameraRigController.aimStickExponent.value);
			if (magnitude == 0f)
			{
				_ = UnityEngine.Vector2.zero;
			}
			else
			{
				_ = aimStickVector * (num / magnitude);
			}
			if (magnitude != 0f)
			{
				aimStickVector *= num / magnitude;
			}
		}

		private void PerformAimAssist(in CameraModeContext context, ref UnityEngine.Vector2 aimStickVector)
		{
			ref readonly TargetInfo targetInfo = ref context.targetInfo;
			ref readonly CameraInfo cameraInfo = ref context.cameraInfo;
			ref readonly UserProfile userProfile = ref context.viewerInfo.userProfile;
			if (!context.targetInfo.isViewerControlled || context.targetInfo.isSprinting || userProfile.inputAimAssistSensitivity == 0f)
			{
				return;
			}
			Camera sceneCam = cameraInfo.sceneCam;
			if (!userProfile.aimAssistEnabled)
			{
				return;
			}
			AimAssistTarget aimAssistTarget = null;
			AimAssistTarget aimAssistTarget2 = null;
			float value = CameraRigController.aimStickAssistMinSize.value;
			float num = value * CameraRigController.aimStickAssistMaxSize.value;
			Util.Remap(userProfile.inputAimAssistSensitivity, 1f, 10f, 0.4f, 0.15f);
			float value2 = CameraRigController.aimStickAssistMinSlowdownScale.value;
			float num2 = 0f;
			float num3 = 0f;
			UnityEngine.Vector2 vector = UnityEngine.Vector2.zero;
			UnityEngine.Vector2 normalized = aimStickVector.normalized;
			UnityEngine.Vector2 vector2 = new UnityEngine.Vector2(0.5f, 0.5f);
			for (int i = 0; i < AimAssistTarget.instancesList.Count; i++)
			{
				AimAssistTarget aimAssistTarget3 = AimAssistTarget.instancesList[i];
				if (aimAssistTarget3.teamComponent.teamIndex == targetInfo.teamIndex)
				{
					continue;
				}
				UnityEngine.Vector3 vA = sceneCam.WorldToViewportPoint(aimAssistTarget3.point0.position);
				UnityEngine.Vector3 vB = sceneCam.WorldToViewportPoint(aimAssistTarget3.point1.position);
				float num4 = Mathf.Lerp(vA.z, vB.z, 0.5f);
				if (!(num4 <= 18f))
				{
					float num5 = 1f / num4;
					UnityEngine.Vector2 vector3 = (UnityEngine.Vector2)Util.ClosestPointOnLine(vA, vB, vector2) - vector2;
					float num6 = Mathf.Clamp01(Util.Remap(vector3.magnitude, value * aimAssistTarget3.assistScale * num5, num * aimAssistTarget3.assistScale * num5, 1f, 0f));
					float num7 = Mathf.Clamp01(UnityEngine.Vector3.Dot(vector3, normalized));
					if (num6 > num2)
					{
						num2 = num6;
						aimAssistTarget2 = aimAssistTarget3;
						num3 = num7;
						aimAssistTarget = aimAssistTarget3;
						vector = vector3;
					}
				}
			}
			UnityEngine.Vector2 vector4 = aimStickVector;
			if ((bool)aimAssistTarget2)
			{
				float outMin = Util.Remap(userProfile.aimAssistSensitivity, 1f, 10f, 0.4f, 0.15f);
				float num8 = Mathf.Clamp01(Util.Remap(1f - num2, 0f, 1f, outMin, value2));
				vector4 *= num8;
			}
			if ((bool)aimAssistTarget && num3 != 0f)
			{
				float maxRadiansDelta = Util.Remap(num3, 0f, 1f, CameraRigController.aimStickAssistMinDelta.value, CameraRigController.aimStickAssistMaxDelta.value);
				vector4 = UnityEngine.Vector3.RotateTowards(vector4, vector, maxRadiansDelta, 0f);
			}
			aimStickVector = vector4;
		}

		protected override void ApplyLookInputInternal(object rawInstanceData, in CameraModeContext context, in ApplyLookInputArgs input)
		{
			InstanceData instanceData = (InstanceData)rawInstanceData;
			ref readonly TargetInfo targetInfo = ref context.targetInfo;
			if (targetInfo.isViewerControlled)
			{
				float minPitch = instanceData.minPitch;
				float maxPitch = instanceData.maxPitch;
				instanceData.pitchYaw.pitch = Mathf.Clamp(instanceData.pitchYaw.pitch - input.lookInput.y, minPitch, maxPitch);
				instanceData.pitchYaw.yaw += input.lookInput.x;
				if ((bool)targetInfo.networkedViewAngles && targetInfo.networkedViewAngles.hasEffectiveAuthority)
				{
					targetInfo.networkedViewAngles.viewAngles = instanceData.pitchYaw;
				}
			}
			else if ((bool)targetInfo.networkedViewAngles)
			{
				instanceData.pitchYaw = targetInfo.networkedViewAngles.viewAngles;
			}
			else if ((bool)targetInfo.inputBank)
			{
				instanceData.SetPitchYawFromLookVector(targetInfo.inputBank.aimDirection);
			}
		}

		protected void UpdateCrosshair(object rawInstanceData, in CameraModeContext context, in CameraState cameraState, in UnityEngine.Vector3 targetPivotPosition, out UnityEngine.Vector3 crosshairWorldPosition)
		{
			InstanceData instanceData = (InstanceData)rawInstanceData;
			instanceData.lastAimAssist = instanceData.aimAssist;
			Ray crosshairRaycastRay = GetCrosshairRaycastRay(in context, UnityEngine.Vector2.zero, targetPivotPosition, in cameraState);
			bool flag = false;
			instanceData.lastCrosshairHurtBox = null;
			RaycastHit raycastHit = default(RaycastHit);
			int num = 0;
			num = HGPhysics.RaycastAll(out var hits, crosshairRaycastRay.origin, crosshairRaycastRay.direction, context.cameraInfo.cameraRigController.maxAimRaycastDistance, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.Ignore);
			float num2 = float.PositiveInfinity;
			int num3 = -1;
			for (int i = 0; i < num; i++)
			{
				RaycastHit raycastHit2 = hits[i];
				HurtBox hurtBox = raycastHit2.collider.GetComponent<HurtBox>();
				EntityLocator component = raycastHit2.collider.GetComponent<EntityLocator>();
				float distance = raycastHit2.distance;
				if (distance <= 3f || num2 <= distance)
				{
					continue;
				}
				if ((bool)hurtBox)
				{
					if (hurtBox.teamIndex == context.targetInfo.teamIndex)
					{
						continue;
					}
					if ((bool)hurtBox.healthComponent && hurtBox.healthComponent.dontShowHealthbar)
					{
						hurtBox = null;
					}
				}
				if ((bool)component)
				{
					VehicleSeat vehicleSeat = (component.entity ? component.entity.GetComponent<VehicleSeat>() : null);
					if ((bool)vehicleSeat && vehicleSeat.currentPassengerBody == context.targetInfo.body)
					{
						continue;
					}
				}
				num2 = distance;
				num3 = i;
				instanceData.lastCrosshairHurtBox = hurtBox;
			}
			if (num3 != -1)
			{
				flag = true;
				raycastHit = hits[num3];
			}
			HGPhysics.ReturnResults(hits);
			instanceData.aimAssist.aimAssistHurtbox = null;
			if (flag)
			{
				crosshairWorldPosition = raycastHit.point;
				float num4 = 1000f;
				if (!(raycastHit.distance < num4))
				{
					return;
				}
				HurtBox component2 = raycastHit.collider.GetComponent<HurtBox>();
				if (!component2)
				{
					return;
				}
				HealthComponent healthComponent = component2.healthComponent;
				if (!healthComponent)
				{
					return;
				}
				TeamComponent component3 = healthComponent.GetComponent<TeamComponent>();
				if ((bool)component3 && component3.teamIndex != context.targetInfo.teamIndex && component3.teamIndex != TeamIndex.None)
				{
					HurtBox hurtBox2 = healthComponent.body?.mainHurtBox;
					if ((bool)hurtBox2)
					{
						instanceData.aimAssist.aimAssistHurtbox = hurtBox2;
						instanceData.aimAssist.worldPosition = raycastHit.point;
						instanceData.aimAssist.localPositionOnHurtbox = hurtBox2.transform.InverseTransformPoint(raycastHit.point);
					}
				}
			}
			else
			{
				crosshairWorldPosition = crosshairRaycastRay.GetPoint(context.cameraInfo.cameraRigController.maxAimRaycastDistance);
			}
		}

		private Ray GetCrosshairRaycastRay(in CameraModeContext context, UnityEngine.Vector2 crosshairOffset, UnityEngine.Vector3 raycastStartPlanePoint, in CameraState cameraState)
		{
			if (!context.cameraInfo.sceneCam)
			{
				return default(Ray);
			}
			float fov = cameraState.fov;
			float num = fov * context.cameraInfo.sceneCam.aspect;
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(crosshairOffset.y * fov, crosshairOffset.x * num, 0f);
			quaternion = cameraState.rotation * quaternion;
			return new Ray(UnityEngine.Vector3.ProjectOnPlane(cameraState.position - raycastStartPlanePoint, cameraState.rotation * UnityEngine.Vector3.forward) + raycastStartPlanePoint, quaternion * UnityEngine.Vector3.forward);
		}

		private UnityEngine.Vector3 CalculateTargetPivotPosition(in CameraModeContext context)
		{
			CameraRigController cameraRigController = context.cameraInfo.cameraRigController;
			CameraTargetParams targetParams = context.targetInfo.targetParams;
			UnityEngine.Vector3 result = context.cameraInfo.previousCameraState.position;
			if ((bool)targetParams)
			{
				UnityEngine.Vector3 position = targetParams.transform.position;
				UnityEngine.Vector3 vector = (targetParams.cameraPivotTransform ? targetParams.cameraPivotTransform.position : position) + new UnityEngine.Vector3(0f, targetParams.currentCameraParamsData.pivotVerticalOffset.value, 0f);
				if (targetParams.dontRaycastToPivot)
				{
					result = vector;
				}
				else
				{
					UnityEngine.Vector3 direction = vector - position;
					float magnitude = direction.magnitude;
					Ray ray = new Ray(position, direction);
					float num = cameraRigController.Raycast(ray, magnitude, targetParams.currentCameraParamsData.wallCushion.value);
					UnityEngine.Debug.DrawRay(ray.origin, ray.direction * magnitude, UnityEngine.Color.green, Time.deltaTime);
					UnityEngine.Debug.DrawRay(ray.origin, ray.direction * num, UnityEngine.Color.red, Time.deltaTime);
					result = ray.GetPoint(num);
				}
			}
			return result;
		}

		protected override void OnTargetChangedInternal(object rawInstanceData, CameraRigController cameraRigController, in OnTargetChangedArgs args)
		{
			InstanceData instanceData = (InstanceData)rawInstanceData;
			if (instanceData.hasEverHadTarget)
			{
				return;
			}
			if ((bool)args.newTarget)
			{
				CharacterBody component = args.newTarget.GetComponent<CharacterBody>();
				if ((bool)component)
				{
					CharacterDirection characterDirection = component.characterDirection;
					if ((bool)characterDirection)
					{
						instanceData.pitchYaw = new PitchYawPair(0f, characterDirection.yaw);
					}
					targetSurvivorClass = SurvivorCatalog.GetSurvivorIndexFromBodyIndex(component.bodyIndex);
				}
				instanceData.hasEverHadTarget = true;
			}
			else
			{
				targetSurvivorClass = SurvivorIndex.None;
			}
		}

		protected override void MatchStateInternal(object rawInstanceData, in CameraModeContext context, in CameraState cameraStateToMatch)
		{
			((InstanceData)rawInstanceData).SetPitchYawFromLookVector(cameraStateToMatch.rotation * UnityEngine.Vector3.forward);
		}
	}
}
namespace RoR2.Audio
{
	public struct AkEventIdArg
	{
		public readonly uint id;

		public static explicit operator AkEventIdArg(string eventName)
		{
			return new AkEventIdArg((eventName != null) ? AkSoundEngine.GetIDFromString(eventName) : 0u);
		}

		public static implicit operator AkEventIdArg(uint akEventId)
		{
			return new AkEventIdArg(akEventId);
		}

		public static implicit operator uint(AkEventIdArg akEventIdArg)
		{
			return akEventIdArg.id;
		}

		private AkEventIdArg(uint id)
		{
			this.id = id;
		}
	}
	public static class EntitySoundManager
	{
		private class EntitySoundMessage : MessageBase
		{
			public NetworkSoundEventIndex networkSoundEventIndex;

			public NetworkIdentity networkIdentity;

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
				writer.WriteNetworkSoundEventIndex(networkSoundEventIndex);
				writer.Write(networkIdentity);
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
				networkSoundEventIndex = reader.ReadNetworkSoundEventIndex();
				networkIdentity = reader.ReadNetworkIdentity();
			}

			public void Clear()
			{
				networkSoundEventIndex = NetworkSoundEventIndex.Invalid;
				networkIdentity = null;
			}
		}

		private static readonly EntitySoundMessage sharedMessage = new EntitySoundMessage();

		private static readonly QosChannelIndex channel = QosChannelIndex.defaultReliable;

		private static readonly short messageType = 73;

		[NetworkMessageHandler(client = true, server = false, msgType = 73)]
		private static void HandleMessage(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(sharedMessage);
			if ((bool)sharedMessage.networkIdentity)
			{
				EmitSoundLocal(NetworkSoundEventCatalog.GetAkIdFromNetworkSoundEventIndex(sharedMessage.networkSoundEventIndex), sharedMessage.networkIdentity.gameObject);
			}
			sharedMessage.Clear();
		}

		public static uint EmitSoundLocal(AkEventIdArg akEventId, GameObject gameObject)
		{
			if ((uint)akEventId == 0)
			{
				return 0u;
			}
			return AkSoundEngine.PostEvent(akEventId, gameObject);
		}

		public static void EmitSoundServer(AkEventIdArg akEventId, GameObject gameObject)
		{
			NetworkSoundEventIndex networkSoundEventIndex = NetworkSoundEventCatalog.FindNetworkSoundEventIndex(akEventId);
			if (networkSoundEventIndex == NetworkSoundEventIndex.Invalid)
			{
				UnityEngine.Debug.LogWarningFormat("Cannot emit sound \"{0}\" on object \"{1}\": Event is not registered in NetworkSoundEventCatalog.", akEventId.id, gameObject);
			}
			else
			{
				EmitSoundServer(networkSoundEventIndex, gameObject);
			}
		}

		public static void EmitSoundServer(NetworkSoundEventIndex networkSoundEventIndex, GameObject gameObject)
		{
			NetworkIdentity component = gameObject.GetComponent<NetworkIdentity>();
			if (!component)
			{
				UnityEngine.Debug.LogWarningFormat("Cannot emit sound \"{0}\" on object \"{1}\": Object has no NetworkIdentity.", NetworkSoundEventCatalog.GetAkIdFromNetworkSoundEventIndex(networkSoundEventIndex), gameObject);
			}
			else
			{
				EmitSoundServer(networkSoundEventIndex, component);
			}
		}

		public static void EmitSoundServer(NetworkSoundEventIndex networkSoundEventIndex, NetworkIdentity networkIdentity)
		{
			sharedMessage.networkIdentity = networkIdentity;
			sharedMessage.networkSoundEventIndex = networkSoundEventIndex;
			NetworkServer.SendByChannelToAll(messageType, sharedMessage, channel.intVal);
			sharedMessage.Clear();
		}
	}
	[CreateAssetMenu(menuName = "RoR2/LoopSoundDef")]
	public class LoopSoundDef : ScriptableObject
	{
		public string startSoundName;

		public string stopSoundName;
	}
	public static class LoopSoundManager
	{
		public struct SoundLoopPtr
		{
			public readonly ValueHeap<SoundLoopNode>.Ptr ptr;

			public bool isValid => soundLoopHeap.PtrIsValid(in ptr);

			public SoundLoopPtr(ValueHeap<SoundLoopNode>.Ptr ptr)
			{
				this.ptr = ptr;
			}

			public SoundLoopNode GetValue()
			{
				return soundLoopHeap.GetValue(in ptr);
			}

			public void SetValue(in SoundLoopNode value)
			{
				soundLoopHeap.SetValue(in ptr, in value);
			}

			public ref SoundLoopNode GetRef()
			{
				return ref soundLoopHeap.GetRef(ptr);
			}

			public void SetRtpc(string rtpcName, float value)
			{
				AkSoundEngine.SetRTPCValueByPlayingID(rtpcName, value, GetRef().akId);
			}
		}

		public class SoundLoopHelper : MonoBehaviour
		{
			public SoundLoopPtr first { get; set; }

			public SoundLoopPtr last { get; set; }

			public GameObject cachedGameObject { get; set; }

			private void OnDestroy()
			{
				while (first.isValid)
				{
					StopSoundLoopLocal(first);
				}
			}
		}

		public struct SoundLoopNode
		{
			public SoundLoopHelper owner;

			public LoopSoundDef loopSoundDef;

			public uint akId;

			public SoundLoopPtr next;

			public SoundLoopPtr previous;
		}

		private static readonly ValueHeap<SoundLoopNode> soundLoopHeap = new ValueHeap<SoundLoopNode>(128u);

		public static SoundLoopPtr PlaySoundLoopLocal(GameObject gameObject, LoopSoundDef loopSoundDef)
		{
			gameObject.GetComponent<AkGameObj>();
			SoundLoopHelper soundLoopHelper = gameObject.GetComponent<SoundLoopHelper>();
			if (!soundLoopHelper)
			{
				soundLoopHelper = gameObject.AddComponent<SoundLoopHelper>();
				soundLoopHelper.cachedGameObject = soundLoopHelper.gameObject;
			}
			SoundLoopPtr soundLoopPtr = new SoundLoopPtr(soundLoopHeap.Alloc());
			SoundLoopPtr last = soundLoopHelper.last;
			ref SoundLoopNode @ref = ref soundLoopPtr.GetRef();
			@ref.owner = soundLoopHelper;
			@ref.loopSoundDef = loopSoundDef;
			if (soundLoopHelper.last.isValid)
			{
				@ref.previous = last;
				last.GetRef().next = soundLoopPtr;
			}
			else
			{
				soundLoopHelper.first = soundLoopPtr;
			}
			soundLoopHelper.last = soundLoopPtr;
			@ref.akId = AkSoundEngine.PostEvent(loopSoundDef.startSoundName, gameObject);
			return soundLoopPtr;
		}

		public static SoundLoopPtr PlaySoundLoopLocalRtpc(GameObject gameObject, LoopSoundDef loopSoundDef, string rtpcName, float rtpcValue)
		{
			SoundLoopPtr result = PlaySoundLoopLocal(gameObject, loopSoundDef);
			ref SoundLoopNode @ref = ref result.GetRef();
			if (@ref.akId != 0)
			{
				AkSoundEngine.SetRTPCValueByPlayingID(rtpcName, rtpcValue, @ref.akId);
			}
			return result;
		}

		public static void StopSoundLoopLocal(SoundLoopPtr ptr)
		{
			if (ptr.isValid)
			{
				ref SoundLoopNode @ref = ref ptr.GetRef();
				AkSoundEngine.PostEvent(@ref.loopSoundDef.stopSoundName, @ref.owner.cachedGameObject);
				if (@ref.previous.isValid)
				{
					@ref.previous.GetRef().next = @ref.next;
				}
				else
				{
					@ref.owner.first = @ref.next;
				}
				if (@ref.next.isValid)
				{
					@ref.next.GetRef().previous = @ref.previous;
				}
				else
				{
					@ref.owner.last = @ref.previous;
				}
				soundLoopHeap.Free(in ptr.ptr);
			}
		}
	}
	public enum NetworkSoundEventIndex
	{
		Invalid = -1
	}
	public static class NetworkSoundEventCatalog
	{
		private static NetworkSoundEventDef[] entries = Array.Empty<NetworkSoundEventDef>();

		private static readonly Dictionary<string, NetworkSoundEventIndex> eventNameToIndexTable = new Dictionary<string, NetworkSoundEventIndex>();

		private static readonly Dictionary<uint, NetworkSoundEventIndex> eventIdToIndexTable = new Dictionary<uint, NetworkSoundEventIndex>();

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<NetworkSoundEventDef>> getSoundEventDefs
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.Audio.NetworkSoundCatalog.getSoundEventDefs", value, LegacyModContentPackProvider.instance.registrationContentPack.networkSoundEventDefs);
			}
			remove
			{
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			SetNetworkSoundEvents(ContentManager.networkSoundEventDefs);
		}

		public static void SetNetworkSoundEvents(NetworkSoundEventDef[] newEntries)
		{
			eventNameToIndexTable.Clear();
			eventIdToIndexTable.Clear();
			ArrayUtils.CloneTo(newEntries, ref entries);
			Array.Sort(entries, (NetworkSoundEventDef a, NetworkSoundEventDef b) => string.CompareOrdinal(a.name, b.name));
			for (int i = 0; i < entries.Length; i++)
			{
				NetworkSoundEventDef networkSoundEventDef = entries[i];
				networkSoundEventDef.index = (NetworkSoundEventIndex)i;
				networkSoundEventDef.akId = AkSoundEngine.GetIDFromString(networkSoundEventDef.eventName);
				if (networkSoundEventDef.akId == 0)
				{
					UnityEngine.Debug.LogErrorFormat("Error during network sound registration: Wwise event \"{0}\" does not exist.", networkSoundEventDef.eventName);
				}
			}
			for (int j = 0; j < entries.Length; j++)
			{
				NetworkSoundEventDef networkSoundEventDef2 = entries[j];
				eventNameToIndexTable[networkSoundEventDef2.eventName] = networkSoundEventDef2.index;
				eventIdToIndexTable[networkSoundEventDef2.akId] = networkSoundEventDef2.index;
			}
		}

		public static NetworkSoundEventIndex FindNetworkSoundEventIndex(string eventName)
		{
			if (eventNameToIndexTable.TryGetValue(eventName, out var value))
			{
				return value;
			}
			return NetworkSoundEventIndex.Invalid;
		}

		public static NetworkSoundEventIndex FindNetworkSoundEventIndex(uint akEventId)
		{
			if (eventIdToIndexTable.TryGetValue(akEventId, out var value))
			{
				return value;
			}
			return NetworkSoundEventIndex.Invalid;
		}

		public static uint GetAkIdFromNetworkSoundEventIndex(NetworkSoundEventIndex eventIndex)
		{
			if (eventIndex == NetworkSoundEventIndex.Invalid)
			{
				return 0u;
			}
			return entries[(int)eventIndex].akId;
		}

		public static void WriteNetworkSoundEventIndex(this NetworkWriter writer, NetworkSoundEventIndex networkSoundEventIndex)
		{
			writer.WritePackedUInt32((uint)(networkSoundEventIndex + 1));
		}

		public static NetworkSoundEventIndex ReadNetworkSoundEventIndex(this NetworkReader reader)
		{
			return (NetworkSoundEventIndex)(reader.ReadPackedUInt32() - 1);
		}

		public static string GetEventNameFromId(uint akEventId)
		{
			if (eventIdToIndexTable.TryGetValue(akEventId, out var value))
			{
				return entries[(int)value].eventName;
			}
			return null;
		}

		public static string GetEventNameFromNetworkIndex(NetworkSoundEventIndex networkSoundEventIndex)
		{
			return ArrayUtils.GetSafe(entries, (int)networkSoundEventIndex)?.eventName;
		}
	}
	public static class PointSoundManager
	{
		private class NetworkSoundEventMessage : MessageBase
		{
			public NetworkSoundEventIndex soundEventIndex;

			public UnityEngine.Vector3 position;

			public override void Serialize(NetworkWriter writer)
			{
				base.Serialize(writer);
				writer.WriteNetworkSoundEventIndex(soundEventIndex);
				writer.Write(position);
			}

			public override void Deserialize(NetworkReader reader)
			{
				base.Deserialize(reader);
				soundEventIndex = reader.ReadNetworkSoundEventIndex();
				position = reader.ReadVector3();
			}
		}

		private struct TimeoutInfo
		{
			public readonly AkGameObj emitter;

			public readonly float startTime;

			public TimeoutInfo(AkGameObj emitter, float startTime)
			{
				this.emitter = emitter;
				this.startTime = startTime;
			}
		}

		private static readonly Stack<AkGameObj> emitterPool = new Stack<AkGameObj>();

		private static GameObject emitterObjectPrefab;

		private const uint EMPTY_AK_EVENT_SOUND = 2166136261u;

		private static readonly NetworkSoundEventMessage sharedMessage = new NetworkSoundEventMessage();

		private static readonly QosChannelIndex channel = QosChannelIndex.effects;

		private const short messageType = 72;

		private static readonly FloatConVar cvPointSoundManagerTimeout = new FloatConVar("pointsoundmanager_timeout", ConVarFlags.None, "4.5", "Timeout value in seconds to use for sound emitters dispatched by PointSoundManager. -1 for end-of-playback callbacks instead, which we suspect may have thread-safety issues.");

		private static readonly Queue<TimeoutInfo> timeouts = new Queue<TimeoutInfo>();

		[InitDuringStartup]
		private static void InitSoundEmitter()
		{
			RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, (Action)delegate
			{
				LoadEmitterPrefab();
			});
		}

		private static void LoadEmitterPrefab()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("29b2b6ef68391f74e91693f36016b301");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> obj)
			{
				SetEmitterPrefab(obj.Result);
			};
		}

		private static void SetEmitterPrefab(GameObject emitterPrefab)
		{
			emitterObjectPrefab = emitterPrefab;
		}

		private static AkGameObj RequestEmitter()
		{
			if (emitterPool.Count > 0)
			{
				return emitterPool.Pop();
			}
			if ((bool)emitterObjectPrefab)
			{
				return UnityEngine.Object.Instantiate(emitterObjectPrefab).GetComponent<AkGameObj>();
			}
			LoadEmitterPrefab();
			GameObject gameObject = new GameObject("SoundEmitter");
			gameObject.AddComponent<Rigidbody>().isKinematic = true;
			return gameObject.AddComponent<AkGameObj>();
		}

		private static void FreeEmitter(AkGameObj emitter)
		{
			if ((bool)emitter)
			{
				emitterPool.Push(emitter);
			}
		}

		public static uint EmitSoundLocal(AkEventIdArg akEventId, UnityEngine.Vector3 position)
		{
			if (WwiseIntegrationManager.noAudio || akEventId.id == 0 || akEventId.id == 2166136261u)
			{
				return 0u;
			}
			AkGameObj akGameObj = RequestEmitter();
			akGameObj.transform.position = position;
			akGameObj.SetPosition();
			uint result;
			if (cvPointSoundManagerTimeout.value < 0f)
			{
				result = AkSoundEngine.PostEvent(akEventId, akGameObj.gameObject, 1u, Callback, akGameObj);
			}
			else
			{
				result = AkSoundEngine.PostEvent(akEventId, akGameObj.gameObject);
				timeouts.Enqueue(new TimeoutInfo(akGameObj, Time.unscaledTime));
			}
			return result;
		}

		private static void Callback(object cookie, AkCallbackType in_type, AkCallbackInfo in_info)
		{
			if (in_type == AkCallbackType.AK_EndOfEvent)
			{
				FreeEmitter((AkGameObj)cookie);
			}
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			RoR2Application.onUpdate += StaticUpdate;
		}

		private static void StaticUpdate()
		{
			ProcessTimeoutQueue();
		}

		private static void OnSceneUnloaded(Scene scene)
		{
			ClearEmitterPool();
		}

		private static void ClearEmitterPool()
		{
			foreach (AkGameObj item in emitterPool)
			{
				if ((bool)item)
				{
					UnityEngine.Object.Destroy(item.gameObject);
				}
			}
			emitterPool.Clear();
		}

		public static void EmitSoundServer(NetworkSoundEventIndex networkSoundEventIndex, UnityEngine.Vector3 position)
		{
			sharedMessage.soundEventIndex = networkSoundEventIndex;
			sharedMessage.position = position;
			NetworkServer.SendByChannelToAll(72, sharedMessage, channel.intVal);
		}

		[NetworkMessageHandler(client = true, server = false, msgType = 72)]
		private static void HandleMessage(NetworkMessage netMsg)
		{
			netMsg.ReadMessage(sharedMessage);
			EmitSoundLocal(NetworkSoundEventCatalog.GetAkIdFromNetworkSoundEventIndex(sharedMessage.soundEventIndex), sharedMessage.position);
		}

		private static void ProcessTimeoutQueue()
		{
			float num = Time.unscaledTime - cvPointSoundManagerTimeout.value;
			while (timeouts.Count > 0)
			{
				TimeoutInfo timeoutInfo = timeouts.Peek();
				if (!(num <= timeoutInfo.startTime))
				{
					timeouts.Dequeue();
					FreeEmitter(timeoutInfo.emitter);
					continue;
				}
				break;
			}
		}
	}
}
namespace RoR2.Artifacts
{
	public static class BombArtifactManager
	{
		private struct BombRequest
		{
			public UnityEngine.Vector3 spawnPosition;

			public UnityEngine.Vector3 raycastOrigin;

			public float bombBaseDamage;

			public GameObject attacker;

			public TeamIndex teamIndex;

			public float velocityY;
		}

		private static FloatConVar cvSpiteBombCoefficient = new FloatConVar("spite_bomb_coefficient", ConVarFlags.Cheat, "0.5", "Multiplier for number of spite bombs.");

		private static GameObject bombPrefab;

		private static readonly int maxBombCount = 30;

		private static readonly float extraBombPerRadius = 4f;

		private static readonly float bombSpawnBaseRadius = 3f;

		private static readonly float bombSpawnRadiusCoefficient = 4f;

		private static readonly float bombDamageCoefficient = 1.5f;

		private static readonly Queue<BombRequest> bombRequestQueue = new Queue<BombRequest>();

		private static readonly float bombBlastRadius = 7f;

		private static readonly float bombFuseTimeout = 8f;

		private static readonly float maxBombStepUpDistance = 8f;

		private static readonly float maxBombFallDistance = 60f;

		private static ArtifactDef myArtifact => RoR2Content.Artifacts.bombArtifactDef;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/SpiteBomb", delegate(GameObject operationResult)
			{
				bombPrefab = operationResult;
			});
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (NetworkServer.active && !(artifactDef != myArtifact))
			{
				GlobalEventManager.onCharacterDeathGlobal += OnServerCharacterDeath;
				RoR2Application.onFixedUpdate += ProcessBombQueue;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				bombRequestQueue.Clear();
				RoR2Application.onFixedUpdate -= ProcessBombQueue;
				GlobalEventManager.onCharacterDeathGlobal -= OnServerCharacterDeath;
			}
		}

		private static void SpawnBomb(BombRequest bombRequest, float groundY)
		{
			UnityEngine.Vector3 spawnPosition = bombRequest.spawnPosition;
			if (spawnPosition.y < groundY + 4f)
			{
				spawnPosition.y = groundY + 4f;
			}
			UnityEngine.Vector3 raycastOrigin = bombRequest.raycastOrigin;
			raycastOrigin.y = groundY;
			GameObject gameObject = UnityEngine.Object.Instantiate(bombPrefab, spawnPosition, UnityEngine.Random.rotation);
			SpiteBombController component = gameObject.GetComponent<SpiteBombController>();
			DelayBlast delayBlast = component.delayBlast;
			TeamFilter component2 = gameObject.GetComponent<TeamFilter>();
			component.bouncePosition = raycastOrigin;
			component.initialVelocityY = bombRequest.velocityY;
			delayBlast.position = spawnPosition;
			delayBlast.baseDamage = bombRequest.bombBaseDamage;
			delayBlast.baseForce = 2300f;
			delayBlast.attacker = bombRequest.attacker;
			delayBlast.radius = bombBlastRadius;
			delayBlast.crit = false;
			delayBlast.procCoefficient = 0.75f;
			delayBlast.maxTimer = bombFuseTimeout;
			delayBlast.timerStagger = 0f;
			delayBlast.falloffModel = BlastAttack.FalloffModel.None;
			component2.teamIndex = bombRequest.teamIndex;
			NetworkServer.Spawn(gameObject);
		}

		private static void OnServerCharacterDeath(DamageReport damageReport)
		{
			if (damageReport.victimTeamIndex == TeamIndex.Monster)
			{
				CharacterBody victimBody = damageReport.victimBody;
				UnityEngine.Vector3 corePosition = victimBody.corePosition;
				int num = Mathf.Min(maxBombCount, Mathf.CeilToInt(victimBody.bestFitRadius * extraBombPerRadius * cvSpiteBombCoefficient.value));
				for (int i = 0; i < num; i++)
				{
					UnityEngine.Vector3 vector = UnityEngine.Random.insideUnitSphere * (bombSpawnBaseRadius + victimBody.bestFitRadius * bombSpawnRadiusCoefficient);
					BombRequest bombRequest = default(BombRequest);
					bombRequest.spawnPosition = corePosition;
					bombRequest.raycastOrigin = corePosition + vector;
					bombRequest.bombBaseDamage = victimBody.damage * bombDamageCoefficient;
					bombRequest.attacker = victimBody.gameObject;
					bombRequest.teamIndex = damageReport.victimTeamIndex;
					bombRequest.velocityY = UnityEngine.Random.Range(5f, 25f);
					BombRequest item = bombRequest;
					bombRequestQueue.Enqueue(item);
				}
			}
		}

		private static void ProcessBombQueue()
		{
			if (bombRequestQueue.Count > 0)
			{
				BombRequest bombRequest = bombRequestQueue.Dequeue();
				Ray ray = new Ray(bombRequest.raycastOrigin + new UnityEngine.Vector3(0f, maxBombStepUpDistance, 0f), UnityEngine.Vector3.down);
				float maxDistance = maxBombStepUpDistance + maxBombFallDistance;
				if (Physics.Raycast(ray, out var hitInfo, maxDistance, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
				{
					SpawnBomb(bombRequest, hitInfo.point.y);
				}
			}
		}
	}
	public static class CommandArtifactManager
	{
		public static GameObject commandCubePrefab;

		public static bool IsCommandArtifactEnabled => RunArtifactManager.instance.IsArtifactEnabled(myArtifact);

		private static ArtifactDef myArtifact => RoR2Content.Artifacts.commandArtifactDef;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/CommandCube", delegate(GameObject operationResult)
			{
				commandCubePrefab = operationResult;
			});
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact) && NetworkServer.active)
			{
				SceneDirector.onGenerateInteractableCardSelection += OnGenerateInteractableCardSelection;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				SceneDirector.onGenerateInteractableCardSelection -= OnGenerateInteractableCardSelection;
			}
		}

		private static void OnGenerateInteractableCardSelection(SceneDirector sceneDirector, DirectorCardCategorySelection dccs)
		{
			dccs.RemoveCardsThatFailFilter(DoesNotOfferChoice);
			static bool DoesNotOfferChoice(DirectorCard card)
			{
				return !OffersChoice(card);
			}
			static bool OffersChoice(DirectorCard card)
			{
				GameObject prefab = card.spawnCard.prefab;
				if (!prefab.GetComponent<ShopTerminalBehavior>() && !prefab.GetComponent<MultiShopController>())
				{
					return prefab.GetComponent<ScrapperController>();
				}
				return true;
			}
		}
	}
	public static class DevotionArtifactManager
	{
		private static ArtifactDef myArtifact;

		private static GameObject devotionArtifactManagerPrefab;

		public static DirectorCard lumerianEgg;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/DevotionArtifactInfo", delegate(GameObject operationResult)
			{
				devotionArtifactManagerPrefab = operationResult;
			});
			myArtifact = CU8Content.Artifacts.Devotion;
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (NetworkServer.active && !(artifactDef != myArtifact))
			{
				SceneDirector.onGenerateInteractableCardSelection += OnGenerateInteractableCardSelection;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				SceneDirector.onGenerateInteractableCardSelection -= OnGenerateInteractableCardSelection;
			}
		}

		private static void CalcCardWeight(DirectorCard card, ref float weight)
		{
			InteractableSpawnCard interactableSpawnCard = card.spawnCard as InteractableSpawnCard;
			if (interactableSpawnCard != null)
			{
				weight *= interactableSpawnCard.weightScalarWhenSacrificeArtifactEnabled;
			}
		}

		private static void OnGenerateInteractableCardSelection(SceneDirector sceneDirector, DirectorCardCategorySelection dccs)
		{
		}
	}
	public class DoppelgangerInvasionManager : MonoBehaviour
	{
		private readonly float invasionInterval = 600f;

		private int previousInvasionCycle;

		private ulong seed;

		private Run run;

		private Xoroshiro128Plus treasureRng;

		private PickupDropTable dropTable;

		private bool artifactIsEnabled => RunArtifactManager.instance.IsArtifactEnabled(RoR2Content.Artifacts.shadowCloneArtifactDef);

		public static event Action<DamageReport> onDoppelgangerDeath;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			Run.onRunStartGlobal += OnRunStartGlobal;
		}

		private static void OnRunStartGlobal(Run run)
		{
			if (NetworkServer.active)
			{
				run.gameObject.AddComponent<DoppelgangerInvasionManager>();
			}
		}

		private void Start()
		{
			run = GetComponent<Run>();
			seed = run.seed;
			treasureRng = new Xoroshiro128Plus(seed);
			dropTable = LegacyResourcesAPI.Load<PickupDropTable>("DropTables/dtDoppelganger");
		}

		private void OnEnable()
		{
			GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
			ArtifactTrialMissionController.onShellTakeDamageServer += OnArtifactTrialShellTakeDamageServer;
		}

		private void OnDisable()
		{
			ArtifactTrialMissionController.onShellTakeDamageServer -= OnArtifactTrialShellTakeDamageServer;
			GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
		}

		private void FixedUpdate()
		{
			int currentInvasionCycle = GetCurrentInvasionCycle();
			if (previousInvasionCycle < currentInvasionCycle)
			{
				previousInvasionCycle = currentInvasionCycle;
				if (artifactIsEnabled)
				{
					PerformInvasion(new Xoroshiro128Plus(seed + (ulong)currentInvasionCycle));
				}
			}
		}

		private void OnCharacterDeathGlobal(DamageReport damageReport)
		{
			Inventory inventory = damageReport.victimMaster?.inventory;
			if (!inventory)
			{
				return;
			}
			bool flag = damageReport.victimMaster.minionOwnership.ownerMaster;
			if (inventory.GetItemCount(RoR2Content.Items.InvadingDoppelganger) > 0 && inventory.GetItemCount(RoR2Content.Items.ExtraLife) == 0 && inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) == 0 && !flag && !damageReport.victimBody.HasBuff(DLC2Content.Buffs.ExtraLifeBuff) && damageReport.victimBody.equipmentSlot.equipmentIndex != DLC2Content.Equipment.HealAndRevive.equipmentIndex)
			{
				DoppelgangerInvasionManager.onDoppelgangerDeath?.Invoke(damageReport);
				PickupIndex pickupIndex = dropTable.GenerateDrop(treasureRng);
				if (!(pickupIndex == PickupIndex.none))
				{
					PickupDropletController.CreatePickupDroplet(pickupIndex, damageReport.victimBody.corePosition, UnityEngine.Vector3.up * 20f);
				}
			}
		}

		private void OnArtifactTrialShellTakeDamageServer(ArtifactTrialMissionController missionController, DamageReport damageReport)
		{
			if (artifactIsEnabled && damageReport.victim.alive)
			{
				PerformInvasion(new Xoroshiro128Plus((ulong)damageReport.victim.health));
			}
		}

		private int GetCurrentInvasionCycle()
		{
			return Mathf.FloorToInt(run.GetRunStopwatch() / invasionInterval);
		}

		public static void PerformInvasion(Xoroshiro128Plus rng)
		{
			for (int num = CharacterMaster.readOnlyInstancesList.Count - 1; num >= 0; num--)
			{
				CharacterMaster characterMaster = CharacterMaster.readOnlyInstancesList[num];
				if (characterMaster.teamIndex == TeamIndex.Player && (bool)characterMaster.playerCharacterMasterController)
				{
					CreateDoppelganger(characterMaster, rng);
				}
			}
		}

		private static void CreateDoppelganger(CharacterMaster srcCharacterMaster, Xoroshiro128Plus rng)
		{
			SpawnCard spawnCard = DoppelgangerSpawnCard.FromMaster(srcCharacterMaster);
			if (!spawnCard)
			{
				return;
			}
			Transform coreTransform;
			DirectorCore.MonsterSpawnDistance input;
			if ((bool)TeleporterInteraction.instance)
			{
				coreTransform = TeleporterInteraction.instance.transform;
				input = DirectorCore.MonsterSpawnDistance.Close;
			}
			else
			{
				coreTransform = srcCharacterMaster.GetBody().coreTransform;
				input = DirectorCore.MonsterSpawnDistance.Far;
			}
			DirectorPlacementRule directorPlacementRule = new DirectorPlacementRule
			{
				spawnOnTarget = coreTransform,
				placementMode = DirectorPlacementRule.PlacementMode.NearestNode
			};
			DirectorCore.GetMonsterSpawnDistance(input, out directorPlacementRule.minDistance, out directorPlacementRule.maxDistance);
			DirectorSpawnRequest directorSpawnRequest = new DirectorSpawnRequest(spawnCard, directorPlacementRule, rng);
			directorSpawnRequest.teamIndexOverride = TeamIndex.Monster;
			directorSpawnRequest.ignoreTeamMemberLimit = true;
			CombatSquad combatSquad = null;
			directorSpawnRequest.onSpawnedServer = (Action<SpawnCard.SpawnResult>)Delegate.Combine(directorSpawnRequest.onSpawnedServer, (Action<SpawnCard.SpawnResult>)delegate(SpawnCard.SpawnResult result)
			{
				if (!combatSquad)
				{
					combatSquad = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/Encounters/ShadowCloneEncounter")).GetComponent<CombatSquad>();
				}
				combatSquad.AddMember(result.spawnedInstance.GetComponent<CharacterMaster>());
			});
			DirectorCore.instance.TrySpawnObject(directorSpawnRequest);
			if ((bool)combatSquad)
			{
				NetworkServer.Spawn(combatSquad.gameObject);
			}
			UnityEngine.Object.Destroy(spawnCard);
		}
	}
	public class DoppelgangerSpawnCard : MasterCopySpawnCard
	{
		public static DoppelgangerSpawnCard FromMaster(CharacterMaster srcCharacterMaster)
		{
			if (!srcCharacterMaster || !srcCharacterMaster.GetBody())
			{
				return null;
			}
			DoppelgangerSpawnCard doppelgangerSpawnCard = ScriptableObject.CreateInstance<DoppelgangerSpawnCard>();
			MasterCopySpawnCard.CopyDataFromMaster(doppelgangerSpawnCard, srcCharacterMaster, copyItems: true, copyEquipment: true);
			doppelgangerSpawnCard.GiveItem(RoR2Content.Items.InvadingDoppelganger);
			doppelgangerSpawnCard.onPreSpawnSetup = OnPreSpawnSetup;
			return doppelgangerSpawnCard;
			void OnPreSpawnSetup(CharacterMaster spawnedMaster)
			{
				BaseAI ai = spawnedMaster.GetComponent<BaseAI>();
				CharacterBody srcBody = srcCharacterMaster.GetBody();
				ai.onBodyDiscovered += SetEnemyToOriginator;
				void SetEnemyToOriginator(CharacterBody body)
				{
					ai.currentEnemy.gameObject = srcBody.gameObject;
					ai.onBodyDiscovered -= SetEnemyToOriginator;
				}
			}
		}
	}
	public static class EnigmaArtifactManager
	{
		private static readonly Xoroshiro128Plus serverInitialEquipmentRng = new Xoroshiro128Plus(0uL);

		private static readonly Xoroshiro128Plus serverActivationEquipmentRng = new Xoroshiro128Plus(0uL);

		private static List<EquipmentIndex> validEquipment = new List<EquipmentIndex>();

		private static BodyIndex toolbotBodyIndex = BodyIndex.None;

		private static ArtifactDef myArtifact => RoR2Content.Artifacts.enigmaArtifactDef;

		[SystemInitializer(new Type[]
		{
			typeof(ArtifactCatalog),
			typeof(BodyCatalog)
		})]
		private static void Init()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
			Run.onRunStartGlobal += OnRunStartGlobal;
			toolbotBodyIndex = BodyCatalog.FindBodyIndex("ToolbotBody");
		}

		private static void OnRunStartGlobal(Run run)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			serverInitialEquipmentRng.ResetSeed(run.seed);
			serverActivationEquipmentRng.ResetSeed(serverInitialEquipmentRng.nextUlong);
			validEquipment.Clear();
			foreach (EquipmentIndex enigmaEquipment in EquipmentCatalog.enigmaEquipmentList)
			{
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(enigmaEquipment);
				if ((bool)equipmentDef && (!equipmentDef.requiredExpansion || run.IsExpansionEnabled(equipmentDef.requiredExpansion)))
				{
					validEquipment.Add(enigmaEquipment);
				}
			}
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact) && NetworkServer.active)
			{
				CharacterBody.onBodyStartGlobal += OnBodyStartGlobalServer;
				EquipmentSlot.onServerEquipmentActivated += OnServerEquipmentActivated;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				EquipmentSlot.onServerEquipmentActivated -= OnServerEquipmentActivated;
				CharacterBody.onBodyStartGlobal -= OnBodyStartGlobalServer;
			}
		}

		private static void OnBodyStartGlobalServer(CharacterBody characterBody)
		{
			if (characterBody.isPlayerControlled)
			{
				OnPlayerCharacterBodyStartServer(characterBody);
			}
		}

		private static void OnPlayerCharacterBodyStartServer(CharacterBody characterBody)
		{
			Inventory inventory = characterBody.inventory;
			int val = ((characterBody.bodyIndex != toolbotBodyIndex) ? 1 : 2);
			int num = Math.Max(inventory.GetEquipmentSlotCount(), val);
			for (int i = 0; i < num; i++)
			{
				if (inventory.GetEquipment((uint)i).equipmentIndex == EquipmentIndex.None)
				{
					EquipmentIndex randomEquipment = GetRandomEquipment(serverInitialEquipmentRng, (int)(i + characterBody.bodyIndex));
					EquipmentState equipmentState = new EquipmentState(randomEquipment, Run.FixedTimeStamp.negativeInfinity, 1);
					inventory.SetEquipment(equipmentState, (uint)i);
				}
			}
		}

		private static void OnServerEquipmentActivated(EquipmentSlot equipmentSlot, EquipmentIndex equipmentIndex)
		{
			EquipmentIndex randomEquipment = GetRandomEquipment(serverActivationEquipmentRng, (int)equipmentIndex);
			equipmentSlot.characterBody.inventory.SetEquipmentIndex(randomEquipment);
		}

		private static EquipmentIndex GetRandomEquipment(Xoroshiro128Plus rng, int offset)
		{
			int count = validEquipment.Count;
			int num = rng.RangeInt(0, count);
			num += offset;
			num %= count;
			return validEquipment[num];
		}
	}
	public static class FriendlyFireArtifactManager
	{
		private static ArtifactDef myArtifact => RoR2Content.Artifacts.friendlyFireArtifactDef;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabledGlobal;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabledGlobal;
		}

		private static void OnArtifactEnabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				FriendlyFireManager.friendlyFireMode = FriendlyFireManager.FriendlyFireMode.FriendlyFire;
			}
		}

		private static void OnArtifactDisabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				FriendlyFireManager.friendlyFireMode = FriendlyFireManager.FriendlyFireMode.Off;
			}
		}
	}
	public static class MonsterTeamGainsItemsArtifactManager
	{
		private static GameObject networkedInventoryPrefab;

		private static Inventory monsterTeamInventory;

		private static readonly Xoroshiro128Plus treasureRng = new Xoroshiro128Plus(0uL);

		private static PickupDropTable[] dropPattern;

		private static int currentItemIterator = 0;

		private static ArtifactDef myArtifact => RoR2Content.Artifacts.monsterTeamGainsItemsArtifactDef;

		[SystemInitializer(new Type[]
		{
			typeof(ArtifactCatalog),
			typeof(ItemCatalog)
		})]
		private static void Init()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
			Run.onRunStartGlobal += OnRunStartGlobal;
			Run.onRunDestroyGlobal += OnRunDestroyGlobal;
			Stage.onServerStageBegin += OnServerStageBegin;
			SceneDirector.onPrePopulateSceneServer += OnPrePopulateSceneServer;
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/MonsterTeamGainsItemsArtifactInventory", delegate(GameObject operationResult)
			{
				networkedInventoryPrefab = operationResult;
			});
			PickupDropTable pickupDropTable = LegacyResourcesAPI.Load<PickupDropTable>("DropTables/dtMonsterTeamTier1Item");
			PickupDropTable pickupDropTable2 = LegacyResourcesAPI.Load<PickupDropTable>("DropTables/dtMonsterTeamTier2Item");
			PickupDropTable pickupDropTable3 = LegacyResourcesAPI.Load<PickupDropTable>("DropTables/dtMonsterTeamTier3Item");
			dropPattern = new PickupDropTable[5] { pickupDropTable, pickupDropTable, pickupDropTable2, pickupDropTable2, pickupDropTable3 };
		}

		private static void OnRunStartGlobal(Run run)
		{
			if (NetworkServer.active)
			{
				currentItemIterator = 0;
				treasureRng.ResetSeed(run.seed);
				monsterTeamInventory = UnityEngine.Object.Instantiate(networkedInventoryPrefab).GetComponent<Inventory>();
				monsterTeamInventory.GetComponent<TeamFilter>().teamIndex = TeamIndex.Monster;
				NetworkServer.Spawn(monsterTeamInventory.gameObject);
				EnsureMonsterItemCountMatchesStageCount();
			}
		}

		private static void OnRunDestroyGlobal(Run run)
		{
			treasureRng.ResetSeed(0uL);
			if ((bool)monsterTeamInventory)
			{
				NetworkServer.Destroy(monsterTeamInventory.gameObject);
			}
			monsterTeamInventory = null;
		}

		private static void GrantMonsterTeamItem()
		{
			PickupDropTable pickupDropTable = dropPattern[currentItemIterator++ % dropPattern.Length];
			if (!pickupDropTable)
			{
				return;
			}
			PickupIndex pickupIndex = pickupDropTable.GenerateDrop(treasureRng);
			if (pickupIndex != PickupIndex.none)
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
				if (pickupDef != null)
				{
					monsterTeamInventory.GiveItem(pickupDef.itemIndex);
				}
			}
		}

		private static void EnsureMonsterItemCountMatchesStageCount()
		{
			EnsureMonsterTeamItemCount(Run.instance.stageClearCount + 1);
		}

		private static void OnServerStageBegin(Stage stage)
		{
			EnsureMonsterItemCountMatchesStageCount();
		}

		private static void OnPrePopulateSceneServer(SceneDirector sceneDirector)
		{
			EnsureMonsterItemCountMatchesStageCount();
		}

		private static void EnsureMonsterTeamItemCount(int itemCount)
		{
			while (currentItemIterator < itemCount)
			{
				GrantMonsterTeamItem();
			}
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact) && NetworkServer.active)
			{
				SpawnCard.onSpawnedServerGlobal += OnServerCardSpawnedGlobal;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				SpawnCard.onSpawnedServerGlobal -= OnServerCardSpawnedGlobal;
			}
		}

		private static void OnServerCardSpawnedGlobal(SpawnCard.SpawnResult spawnResult)
		{
			CharacterMaster characterMaster = (spawnResult.spawnedInstance ? spawnResult.spawnedInstance.GetComponent<CharacterMaster>() : null);
			if ((bool)characterMaster && characterMaster.teamIndex == TeamIndex.Monster)
			{
				characterMaster.inventory.AddItemsFrom(monsterTeamInventory);
			}
		}
	}
	public static class SacrificeArtifactManager
	{
		private static PickupDropTable dropTable;

		private static readonly Xoroshiro128Plus treasureRng = new Xoroshiro128Plus(0uL);

		private static ArtifactDef myArtifact => RoR2Content.Artifacts.sacrificeArtifactDef;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			LegacyResourcesAPI.LoadAsyncCallback("DropTables/dtSacrificeArtifact", delegate(PickupDropTable operationResult)
			{
				dropTable = operationResult;
			});
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
			Stage.onServerStageBegin += OnServerStageBegin;
		}

		private static void OnServerStageBegin(Stage stage)
		{
			treasureRng.ResetSeed(Run.instance.treasureRng.nextUlong);
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (NetworkServer.active && !(artifactDef != myArtifact))
			{
				GlobalEventManager.onCharacterDeathGlobal += OnServerCharacterDeath;
				SceneDirector.onPrePopulateSceneServer += OnPrePopulateSceneServer;
				SceneDirector.onGenerateInteractableCardSelection += OnGenerateInteractableCardSelection;
				DirectorCardCategorySelection.calcCardWeight += CalcCardWeight;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				SceneDirector.onGenerateInteractableCardSelection -= OnGenerateInteractableCardSelection;
				SceneDirector.onPrePopulateSceneServer -= OnPrePopulateSceneServer;
				GlobalEventManager.onCharacterDeathGlobal -= OnServerCharacterDeath;
				DirectorCardCategorySelection.calcCardWeight -= CalcCardWeight;
			}
		}

		private static void CalcCardWeight(DirectorCard card, ref float weight)
		{
			InteractableSpawnCard interactableSpawnCard = card.spawnCard as InteractableSpawnCard;
			if (interactableSpawnCard != null)
			{
				weight *= interactableSpawnCard.weightScalarWhenSacrificeArtifactEnabled;
			}
		}

		private static void OnGenerateInteractableCardSelection(SceneDirector sceneDirector, DirectorCardCategorySelection dccs)
		{
			dccs.RemoveCardsThatFailFilter(IsNotChest);
			static bool IsNotChest(DirectorCard card)
			{
				InteractableSpawnCard obj = card.spawnCard as InteractableSpawnCard;
				if ((object)obj == null)
				{
					return true;
				}
				return !obj.skipSpawnWhenSacrificeArtifactEnabled;
			}
		}

		private static void OnPrePopulateSceneServer(SceneDirector sceneDirector)
		{
			sceneDirector.onPopulateCreditMultiplier *= 0.5f;
		}

		private static void OnServerCharacterDeath(DamageReport damageReport)
		{
			if (!damageReport.victimMaster || (damageReport.attackerTeamIndex == damageReport.victimTeamIndex && (bool)damageReport.victimMaster.minionOwnership.ownerMaster))
			{
				return;
			}
			float expAdjustedDropChancePercent = Util.GetExpAdjustedDropChancePercent(5f, damageReport.victim.gameObject);
			UnityEngine.Debug.LogFormat("Drop chance from {0}: {1}", damageReport.victimBody, expAdjustedDropChancePercent);
			if (Util.CheckRoll(expAdjustedDropChancePercent))
			{
				PickupIndex pickupIndex = dropTable.GenerateDrop(treasureRng);
				if (pickupIndex != PickupIndex.none)
				{
					PickupDropletController.CreatePickupDroplet(pickupIndex, damageReport.victimBody.corePosition, UnityEngine.Vector3.up * 20f);
				}
			}
		}
	}
	public static class SwarmsArtifactManager
	{
		private const int swarmSpawnCount = 2;

		private static bool inSpawn;

		private static ArtifactDef myArtifact => RoR2Content.Artifacts.swarmsArtifactDef;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact) && NetworkServer.active)
			{
				SpawnCard.onSpawnedServerGlobal += OnSpawnCardOnSpawnedServerGlobal;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifact))
			{
				SpawnCard.onSpawnedServerGlobal -= OnSpawnCardOnSpawnedServerGlobal;
			}
		}

		private static void OnSpawnCardOnSpawnedServerGlobal(SpawnCard.SpawnResult result)
		{
			if (!result.success || !(result.spawnRequest.spawnCard as CharacterSpawnCard) || result.spawnRequest.teamIndexOverride == TeamIndex.Player)
			{
				return;
			}
			CharacterMaster component = result.spawnedInstance.gameObject.GetComponent<CharacterMaster>();
			if ((bool)component)
			{
				component.inventory.GiveItem(RoR2Content.Items.CutHp);
				GameObject bodyObject = component.GetBodyObject();
				if ((bool)bodyObject)
				{
					DeathRewards component2 = bodyObject.GetComponent<DeathRewards>();
					if ((bool)component2)
					{
						component2.spawnValue = (int)Mathf.Max(1f, (float)component2.spawnValue / 2f);
						component2.expReward = (uint)Mathf.Ceil((float)component2.expReward / 2f);
						component2.goldReward = (uint)Mathf.Ceil((float)component2.goldReward / 2f);
					}
				}
			}
			if (inSpawn)
			{
				return;
			}
			for (int i = 1; i < 2; i++)
			{
				inSpawn = true;
				try
				{
					DirectorCore.instance.TrySpawnObject(result.spawnRequest);
				}
				catch (Exception message)
				{
					UnityEngine.Debug.LogError(message);
				}
				inSpawn = false;
			}
		}
	}
	public static class TeamDeathArtifactManager
	{
		private static GameObject forceSpectatePrefab;

		private static bool inTeamKill;

		private static ArtifactDef myArtifactDef => RoR2Content.Artifacts.teamDeathArtifactDef;

		[SystemInitializer(new Type[] { typeof(ArtifactCatalog) })]
		private static void Init()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabled;
			RunArtifactManager.onArtifactDisabledGlobal += OnArtifactDisabled;
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/NetworkedObjects/ForceSpectate", delegate(GameObject operationResult)
			{
				forceSpectatePrefab = operationResult;
			});
		}

		private static void OnArtifactEnabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifactDef))
			{
				GlobalEventManager.onCharacterDeathGlobal += OnServerCharacterDeathGlobal;
			}
		}

		private static void OnArtifactDisabled(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			if (!(artifactDef != myArtifactDef))
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnServerCharacterDeathGlobal;
			}
		}

		private static void OnServerCharacterDeathGlobal(DamageReport damageReport)
		{
			TeamIndex teamIndex;
			NetworkUser victimNetworkUser;
			if (!inTeamKill && (bool)damageReport.victimMaster && (bool)damageReport.victimMaster.playerCharacterMasterController)
			{
				if (damageReport.victimMaster.inventory.GetItemCount(RoR2Content.Items.ExtraLife) <= 0 && damageReport.victimMaster.inventory.GetItemCount(DLC1Content.Items.ExtraLifeVoid) <= 0 && !damageReport.victimBody.HasBuff(DLC2Content.Buffs.ExtraLifeBuff) && damageReport.victimBody.equipmentSlot.equipmentIndex != DLC2Content.Equipment.HealAndRevive.equipmentIndex)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(forceSpectatePrefab);
					gameObject.GetComponent<ForceSpectate>().Networktarget = damageReport.victimBody.gameObject;
					NetworkServer.Spawn(gameObject);
					teamIndex = damageReport.victimTeamIndex;
					PlayerCharacterMasterController playerCharacterMasterController = damageReport.victimMaster.playerCharacterMasterController;
					victimNetworkUser = (playerCharacterMasterController ? playerCharacterMasterController.networkUser : null);
					RoR2Application.onNextUpdate += KillTeam;
				}
			}
			void KillTeam()
			{
				inTeamKill = true;
				Chat.SendBroadcastChat(new SubjectChatMessage
				{
					baseToken = "ARTIFACT_TEAMDEATH_DEATHMESSAGE",
					subjectAsNetworkUser = victimNetworkUser
				});
				ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
				for (int num = readOnlyInstancesList.Count - 1; num >= 0; num--)
				{
					if (readOnlyInstancesList[num].teamIndex == teamIndex)
					{
						readOnlyInstancesList[num].TrueKill();
					}
				}
				inTeamKill = false;
			}
		}
	}
}
namespace RoR2.CharacterAI
{
	public class LemurianEggController : NetworkBehaviour
	{
		private static float itemVFXDuration;

		[Tooltip("The master to spawn")]
		public GameObject masterPrefab;

		public SfxLocator sfxLocator;

		private Interactor interactor;

		private static int kCmdCmdOfferItem;

		public void SetInteractability(bool interactable)
		{
			PickupPickerController component = GetComponent<PickupPickerController>();
			if ((bool)component)
			{
				component.SetAvailable(interactable);
			}
		}

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

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		[Server]
		public void AssignPotentialInteractor(Interactor potentialInteractor)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterAI.LemurianEggController::AssignPotentialInteractor(RoR2.Interactor)' called on client");
			}
			else
			{
				interactor = potentialInteractor;
			}
		}

		public override int GetNetworkChannel()
		{
			return QosChannelIndex.defaultReliable.intVal;
		}

		[Server]
		private void OfferItem(int intPickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterAI.LemurianEggController::OfferItem(System.Int32)' called on client");
				return;
			}
			PickupIndex pickupIndex = new PickupIndex(intPickupIndex);
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			if (pickupDef != null && (bool)interactor)
			{
				CharacterBody component = interactor.GetComponent<CharacterBody>();
				if ((bool)component && (bool)component.inventory && component.inventory.GetItemCount(pickupDef.itemIndex) > 0)
				{
					component.inventory.RemoveItem(pickupDef.itemIndex);
					CreateItemTakenOrb(component.corePosition, base.gameObject, pickupDef.itemIndex);
					GetComponent<PickupPickerController>().SetAvailable(newAvailable: false);
					StartCoroutine(WaitToSummonLemurian(pickupIndex));
				}
			}
		}

		[Command]
		public void CmdOfferItem(int intPickupIndex)
		{
			OfferItem(intPickupIndex);
		}

		[Server]
		public void CreateItemTakenOrb(UnityEngine.Vector3 effectOrigin, GameObject targetObject, ItemIndex itemIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterAI.LemurianEggController::CreateItemTakenOrb(UnityEngine.Vector3,UnityEngine.GameObject,RoR2.ItemIndex)' called on client");
				return;
			}
			EffectData effectData = new EffectData
			{
				origin = effectOrigin,
				genericFloat = itemVFXDuration,
				genericUInt = (uint)(itemIndex + 1)
			};
			effectData.SetNetworkedObjectReference(targetObject);
			EffectManager.SpawnEffect(DevotionInventoryController.s_effectPrefab, effectData, transmit: true);
		}

		private IEnumerator WaitToSummonLemurian(PickupIndex pickupIndex)
		{
			yield return new WaitForSeconds(itemVFXDuration);
			SummonLemurian(pickupIndex);
		}

		[Server]
		private void SummonLemurian(PickupIndex pickupIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.CharacterAI.LemurianEggController::SummonLemurian(RoR2.PickupIndex)' called on client");
				return;
			}
			float num = 0f;
			CharacterMaster characterMaster = new MasterSummon
			{
				masterPrefab = masterPrefab,
				position = base.transform.position + UnityEngine.Vector3.up * num,
				rotation = base.transform.rotation,
				summonerBodyObject = interactor?.gameObject,
				ignoreTeamMemberLimit = true,
				useAmbientLevel = true
			}.Perform();
			EffectData effectData = new EffectData
			{
				origin = base.gameObject.transform.position
			};
			if ((bool)characterMaster)
			{
				interactor.GetComponent<CharacterBody>();
				DevotionInventoryController orCreateDevotionInventoryController = DevotionInventoryController.GetOrCreateDevotionInventoryController(interactor);
				characterMaster.GetComponent<DevotedLemurianController>().InitializeDevotedLemurian(pickupIndex.itemIndex, orCreateDevotionInventoryController);
				orCreateDevotionInventoryController.GiveItem(pickupIndex.itemIndex);
				orCreateDevotionInventoryController.UpdateAllMinions();
				EffectManager.SpawnEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/LemurianEggHatching"), effectData, transmit: true);
			}
			UnityEngine.Object.Destroy(base.gameObject);
		}

		static LemurianEggController()
		{
			itemVFXDuration = 1.5f;
			kCmdCmdOfferItem = -1179441837;
			NetworkBehaviour.RegisterCommandDelegate(typeof(LemurianEggController), kCmdCmdOfferItem, InvokeCmdCmdOfferItem);
			NetworkCRC.RegisterBehaviour("LemurianEggController", 0);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdOfferItem(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdOfferItem called on client.");
			}
			else
			{
				((LemurianEggController)obj).CmdOfferItem((int)reader.ReadPackedUInt32());
			}
		}

		public void CallCmdOfferItem(int intPickupIndex)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdOfferItem called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdOfferItem(intPickupIndex);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdOfferItem);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)intPickupIndex);
			SendCommandInternal(networkWriter, 0, "CmdOfferItem");
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	[RequireComponent(typeof(BaseAI))]
	[DisallowMultipleComponent]
	public class AIOwnership : MonoBehaviour
	{
		public CharacterMaster ownerMaster;

		private BaseAI baseAI;

		private void Awake()
		{
			baseAI = GetComponent<BaseAI>();
		}

		private void FixedUpdate()
		{
			if ((bool)ownerMaster)
			{
				baseAI.leader.gameObject = ownerMaster.GetBodyObject();
			}
		}
	}
	public class AISkillDriver : MonoBehaviour
	{
		public enum TargetType
		{
			CurrentEnemy,
			NearestFriendlyInSkillRange,
			CurrentLeader,
			Custom
		}

		public enum AimType
		{
			None,
			AtMoveTarget,
			AtCurrentEnemy,
			AtCurrentLeader,
			MoveDirection
		}

		public enum MovementType
		{
			Stop,
			ChaseMoveTarget,
			StrafeMovetarget,
			FleeMoveTarget
		}

		public enum ButtonPressType
		{
			Hold,
			Abstain,
			TapContinuous
		}

		[Tooltip("The name of this skill driver for reference purposes.")]
		public string customName;

		[Tooltip("The slot of the associated skill. Set to None to allow this behavior to run regardless of skill availability.")]
		public SkillSlot skillSlot;

		[Tooltip("The skill that the specified slot must have for this behavior to run. Set to none to allow any skill.")]
		[Header("Selection Conditions")]
		public SkillDef requiredSkill;

		[Tooltip("If set, this cannot be the dominant driver while the skill is on cooldown or out of stock.")]
		public bool requireSkillReady;

		[Tooltip("If set, this cannot be the dominant driver while the equipment is on cooldown or out of stock.")]
		public bool requireEquipmentReady;

		[Tooltip("The minimum health fraction required of the user for this behavior.")]
		public float minUserHealthFraction = float.NegativeInfinity;

		[Tooltip("The maximum health fraction required of the user for this behavior.")]
		public float maxUserHealthFraction = float.PositiveInfinity;

		[Tooltip("The minimum health fraction required of the target for this behavior.")]
		public float minTargetHealthFraction = float.NegativeInfinity;

		[Tooltip("The maximum health fraction required of the target for this behavior.")]
		public float maxTargetHealthFraction = float.PositiveInfinity;

		[Tooltip("The minimum distance from the target required for this behavior.")]
		public float minDistance;

		[Tooltip("The maximum distance from the target required for this behavior.")]
		public float maxDistance = float.PositiveInfinity;

		public bool selectionRequiresTargetLoS;

		public bool selectionRequiresOnGround;

		public bool selectionRequiresAimTarget;

		[Tooltip("The maximum number of times that this skill can be selected.  If the value is < 0, then there is no maximum.")]
		public int maxTimesSelected = -1;

		[FormerlySerializedAs("targetType")]
		[Tooltip("The type of object targeted for movement.")]
		[Header("Behavior")]
		public TargetType moveTargetType;

		[Tooltip("If set, this skill will not be activated unless there is LoS to the target.")]
		public bool activationRequiresTargetLoS;

		[Tooltip("If set, this skill will not be activated unless there is LoS to the aim target.")]
		public bool activationRequiresAimTargetLoS;

		[Tooltip("If set, this skill will not be activated unless the aim vector is pointing close to the target.")]
		public bool activationRequiresAimConfirmation;

		[Tooltip("The movement type to use while this is the dominant skill driver.")]
		public MovementType movementType = MovementType.ChaseMoveTarget;

		public float moveInputScale = 1f;

		[Tooltip("Where to look while this is the dominant skill driver")]
		public AimType aimType = AimType.AtMoveTarget;

		[Tooltip("If set, the nodegraph will not be used to direct the local navigator while this is the dominant skill driver. Direction toward the target will be used instead.")]
		public bool ignoreNodeGraph;

		[Tooltip("If true, the AI will attempt to sprint while this is the dominant skill driver.")]
		public bool shouldSprint;

		public bool shouldFireEquipment;

		[ShowFieldObsolete]
		[Obsolete("Use buttonPressType instead.")]
		public bool shouldTapButton;

		public ButtonPressType buttonPressType;

		[Header("Transition Behavior")]
		[Tooltip("If non-negative, this value will be used for the driver evaluation timer while this is the dominant skill driver.")]
		public float driverUpdateTimerOverride = -1f;

		[Tooltip("If set and this is the dominant skill driver, the current enemy will be reset at the time of the next evaluation.")]
		public bool resetCurrentEnemyOnNextDriverSelection;

		[Tooltip("If true, this skill driver cannot be chosen twice in a row.")]
		public bool noRepeat;

		[Tooltip("The AI skill driver that will be treated as having top priority after this one.")]
		public AISkillDriver nextHighPriorityOverride;

		public float minDistanceSqr => minDistance * minDistance;

		public float maxDistanceSqr => maxDistance * maxDistance;

		public int timesSelected { get; private set; }

		private void OnValidate()
		{
			if (shouldTapButton)
			{
				buttonPressType = ButtonPressType.TapContinuous;
			}
		}

		private void OnEnable()
		{
		}

		public void OnSelected()
		{
			int num = timesSelected + 1;
			timesSelected = num;
		}
	}
	[RequireComponent(typeof(CharacterMaster))]
	public class BaseAI : MonoBehaviour, IManagedMonoBehaviour
	{
		[Serializable]
		public class Target
		{
			private readonly BaseAI owner;

			private bool unset = true;

			private GameObject _gameObject;

			private float losCheckTimer;

			public HurtBox bestHurtBox;

			private HurtBoxGroup hurtBoxGroup;

			private HurtBox mainHurtBox;

			private int bullseyeCount;

			private UnityEngine.Vector3? lastKnownBullseyePosition;

			private Run.FixedTimeStamp lastKnownBullseyePositionTime = Run.FixedTimeStamp.negativeInfinity;

			public bool hasLoS;

			public GameObject gameObject
			{
				get
				{
					return _gameObject;
				}
				set
				{
					if ((object)value != _gameObject)
					{
						_gameObject = value;
						characterBody = gameObject?.GetComponent<CharacterBody>();
						healthComponent = characterBody?.healthComponent;
						hurtBoxGroup = characterBody?.hurtBoxGroup;
						bullseyeCount = (hurtBoxGroup ? hurtBoxGroup.bullseyeCount : 0);
						mainHurtBox = (hurtBoxGroup ? hurtBoxGroup.mainHurtBox : null);
						bestHurtBox = mainHurtBox;
						hasLoS = false;
						unset = !_gameObject;
					}
				}
			}

			public CharacterBody characterBody { get; private set; }

			public HealthComponent healthComponent { get; private set; }

			public Target([NotNull] BaseAI owner)
			{
				this.owner = owner;
			}

			public void Update()
			{
				if ((bool)gameObject)
				{
					hasLoS = (bool)bestHurtBox && owner.HasLOS(bestHurtBox.transform.position);
					if (bullseyeCount > 1 && !hasLoS)
					{
						bestHurtBox = GetBestHurtBox(out hasLoS);
					}
				}
			}

			public bool TestLOSNow()
			{
				if ((bool)bestHurtBox)
				{
					return owner.HasLOS(bestHurtBox.transform.position);
				}
				return false;
			}

			public bool GetBullseyePosition(out UnityEngine.Vector3 position)
			{
				if ((bool)characterBody && (bool)owner.body && (characterBody.GetVisibilityLevel(owner.body) >= VisibilityLevel.Revealed || lastKnownBullseyePositionTime.timeSince >= 2f))
				{
					if ((bool)bestHurtBox)
					{
						lastKnownBullseyePosition = bestHurtBox.transform.position;
					}
					else
					{
						lastKnownBullseyePosition = null;
					}
					lastKnownBullseyePositionTime = Run.FixedTimeStamp.now;
				}
				if (lastKnownBullseyePosition.HasValue)
				{
					position = lastKnownBullseyePosition.Value;
					return true;
				}
				position = (gameObject ? gameObject.transform.position : UnityEngine.Vector3.zero);
				return false;
			}

			private HurtBox GetBestHurtBox(out bool hadLoS)
			{
				if ((bool)owner && (bool)owner.bodyInputBank && (bool)hurtBoxGroup)
				{
					UnityEngine.Vector3 aimOrigin = owner.bodyInputBank.aimOrigin;
					HurtBox hurtBox = null;
					float num = float.PositiveInfinity;
					HurtBox[] hurtBoxes = hurtBoxGroup.hurtBoxes;
					foreach (HurtBox hurtBox2 in hurtBoxes)
					{
						if (!hurtBox2 || !hurtBox2.transform || !hurtBox2.isBullseye)
						{
							continue;
						}
						UnityEngine.Vector3 position = hurtBox2.transform.position;
						if (CheckLoS(aimOrigin, hurtBox2.transform.position))
						{
							float sqrMagnitude = (position - aimOrigin).sqrMagnitude;
							if (sqrMagnitude < num)
							{
								num = sqrMagnitude;
								hurtBox = hurtBox2;
							}
						}
					}
					if ((bool)hurtBox)
					{
						hadLoS = true;
						return hurtBox;
					}
				}
				hadLoS = false;
				return mainHurtBox;
			}

			public void Reset()
			{
				if (!unset)
				{
					_gameObject = null;
					characterBody = null;
					healthComponent = null;
					hurtBoxGroup = null;
					bullseyeCount = 0;
					mainHurtBox = null;
					bestHurtBox = mainHurtBox;
					hasLoS = false;
					unset = true;
					losCheckTimer = 0f;
				}
			}
		}

		public struct SkillDriverEvaluation
		{
			public AISkillDriver dominantSkillDriver;

			public Target target;

			public Target aimTarget;

			public float separationSqrMagnitude;
		}

		public struct BodyInputs
		{
			public UnityEngine.Vector3 desiredAimDirection;

			public UnityEngine.Vector3 moveVector;

			public bool pressSprint;

			public bool pressJump;

			public bool pressSkill1;

			public bool pressSkill2;

			public bool pressSkill3;

			public bool pressSkill4;

			public bool pressActivateEquipment;
		}

		public bool showDebugStateChanges;

		[Tooltip("If true, this character can spot enemies behind itself.")]
		public bool fullVision;

		[Tooltip("If true, this AI will not be allowed to retaliate against damage received from a source on its own team.")]
		public bool neverRetaliateFriendlies;

		public float enemyAttentionDuration = 5f;

		public MapNodeGroup.GraphType desiredSpawnNodeGraphType;

		[Tooltip("The state machine to run while the body exists.")]
		public EntityStateMachine stateMachine;

		public SerializableEntityStateType scanState;

		public bool isHealer;

		public float enemyAttention;

		public float aimVectorDampTime = 0.2f;

		public float aimVectorMaxSpeed = 6f;

		private float aimVelocity;

		private float targetRefreshTimer;

		private const float targetRefreshInterval = 0.5f;

		public LocalNavigator localNavigator = new LocalNavigator();

		public string selectedSkilldriverName;

		private const float maxVisionDistance = float.PositiveInfinity;

		[Tooltip("If true and this AI remains off-screen from players until its first shot, that shot will miss. The desired skill must handle this behaviour itself. If not this will do nothing")]
		public bool shouldMissFirstOffScreenShot;

		private float offScreenUpdateTimer;

		private const float offScreenUpdateInterval = 0.25f;

		public static readonly NodeGraphNavigationSystem nodeGraphNavigationSystem = new NodeGraphNavigationSystem();

		private BroadNavigationSystem _broadNavigationSystem;

		private BroadNavigationSystem.Agent _broadNavigationAgent = BroadNavigationSystem.Agent.invalid;

		public bool forceUpdateEveryFrame;

		public HurtBox debugEnemyHurtBox;

		private BullseyeSearch enemySearch = new BullseyeSearch();

		private BullseyeSearch buddySearch = new BullseyeSearch();

		private float skillDriverUpdateTimer;

		private const float skillDriverMinUpdateInterval = 1f / 6f;

		private const float skillDriverMaxUpdateInterval = 0.2f;

		public SkillDriverEvaluation skillDriverEvaluation;

		protected BodyInputs bodyInputs;

		public CharacterMaster master { get; protected set; }

		public CharacterBody body { get; protected set; }

		public Transform bodyTransform { get; protected set; }

		public CharacterDirection bodyCharacterDirection { get; protected set; }

		public CharacterMotor bodyCharacterMotor { get; protected set; }

		public InputBankTest bodyInputBank { get; protected set; }

		public HealthComponent bodyHealthComponent { get; protected set; }

		public SkillLocator bodySkillLocator { get; protected set; }

		public NetworkIdentity networkIdentity { get; protected set; }

		public AISkillDriver[] skillDrivers { get; protected set; }

		public bool hasAimConfirmation { get; private set; }

		public bool hasAimTarget
		{
			get
			{
				if (skillDriverEvaluation.aimTarget != null)
				{
					return skillDriverEvaluation.aimTarget.gameObject;
				}
				return false;
			}
		}

		private BroadNavigationSystem broadNavigationSystem
		{
			get
			{
				return _broadNavigationSystem;
			}
			set
			{
				if (_broadNavigationSystem != value)
				{
					_broadNavigationSystem?.ReturnAgent(ref _broadNavigationAgent);
					_broadNavigationSystem = value;
					_broadNavigationSystem?.RequestAgent(ref _broadNavigationAgent);
				}
			}
		}

		public BroadNavigationSystem.Agent broadNavigationAgent => _broadNavigationAgent;

		public bool AlwaysUpdate => forceUpdateEveryFrame;

		public Target currentEnemy { get; private set; }

		public Target leader { get; private set; }

		private Target buddy { get; set; }

		public Target customTarget { get; private set; }

		public event Action<CharacterBody> onBodyDiscovered;

		public event Action<CharacterBody> onBodyLost;

		[ContextMenu("Toggle broad navigation debug drawing")]
		private void ToggleBroadNavigationDebugDraw()
		{
			if (broadNavigationSystem is NodeGraphNavigationSystem)
			{
				NodeGraphNavigationSystem.Agent agent = (NodeGraphNavigationSystem.Agent)broadNavigationAgent;
				agent.drawPath = !agent.drawPath;
			}
		}

		public void SetBroadNavigationDebugDrawEnabled(bool newBroadNavigationDebugDrawEnabled)
		{
			if (broadNavigationSystem is NodeGraphNavigationSystem)
			{
				NodeGraphNavigationSystem.Agent agent = (NodeGraphNavigationSystem.Agent)broadNavigationAgent;
				agent.drawPath = newBroadNavigationDebugDrawEnabled;
			}
		}

		protected void Awake()
		{
			targetRefreshTimer = 0.5f;
			master = GetComponent<CharacterMaster>();
			stateMachine = GetComponent<EntityStateMachine>();
			stateMachine.enabled = false;
			networkIdentity = GetComponent<NetworkIdentity>();
			skillDrivers = GetComponents<AISkillDriver>();
			currentEnemy = new Target(this);
			leader = new Target(this);
			buddy = new Target(this);
			customTarget = new Target(this);
			broadNavigationSystem = nodeGraphNavigationSystem;
		}

		protected void OnDestroy()
		{
			broadNavigationSystem = null;
		}

		protected void Start()
		{
			if (!Util.HasEffectiveAuthority(networkIdentity))
			{
				base.enabled = false;
				if ((bool)stateMachine)
				{
					stateMachine.enabled = false;
				}
			}
			if (NetworkServer.active)
			{
				skillDriverUpdateTimer = UnityEngine.Random.value;
			}
		}

		protected void FixedUpdate()
		{
			ManagedFixedUpdate(Time.fixedDeltaTime);
		}

		public void ManagedFixedUpdate(float deltaTime)
		{
			enemyAttention -= deltaTime;
			targetRefreshTimer -= deltaTime;
			skillDriverUpdateTimer -= deltaTime;
			if ((bool)body)
			{
				if (shouldMissFirstOffScreenShot)
				{
					offScreenUpdateTimer -= deltaTime;
					if (offScreenUpdateTimer <= 0f)
					{
						offScreenUpdateTimer = 0.25f;
						shouldMissFirstOffScreenShot = OffScreenMissHelper.IsPositionOffScreen(body.transform.position);
					}
				}
				broadNavigationAgent.ConfigureFromBody(body);
				if (skillDriverUpdateTimer <= 0f)
				{
					if ((bool)skillDriverEvaluation.dominantSkillDriver && skillDriverEvaluation.dominantSkillDriver.resetCurrentEnemyOnNextDriverSelection)
					{
						currentEnemy.Reset();
						targetRefreshTimer = 0f;
					}
					if (!currentEnemy.gameObject && targetRefreshTimer <= 0f)
					{
						targetRefreshTimer = 0.5f;
						HurtBox hurtBox = null;
						hurtBox = FindEnemyHurtBox(float.PositiveInfinity, fullVision, filterByLoS: true);
						if ((bool)hurtBox && (bool)hurtBox.healthComponent)
						{
							currentEnemy.gameObject = hurtBox.healthComponent.gameObject;
							currentEnemy.bestHurtBox = hurtBox;
						}
						if ((bool)currentEnemy.gameObject)
						{
							enemyAttention = enemyAttentionDuration;
						}
					}
					BeginSkillDriver(EvaluateSkillDrivers());
				}
			}
			_broadNavigationAgent.currentPosition = GetNavigationStartPos();
			UpdateBodyInputs();
			UpdateBodyAim(deltaTime);
			debugEnemyHurtBox = currentEnemy.bestHurtBox;
		}

		private void BeginSkillDriver(SkillDriverEvaluation newSkillDriverEvaluation)
		{
			if ((bool)skillDriverEvaluation.dominantSkillDriver)
			{
				_ = skillDriverEvaluation.dominantSkillDriver.customName;
			}
			skillDriverEvaluation = newSkillDriverEvaluation;
			skillDriverUpdateTimer = UnityEngine.Random.Range(1f / 6f, 0.2f);
			if ((bool)skillDriverEvaluation.dominantSkillDriver)
			{
				_ = showDebugStateChanges;
				selectedSkilldriverName = skillDriverEvaluation.dominantSkillDriver.customName;
				if (skillDriverEvaluation.dominantSkillDriver.driverUpdateTimerOverride >= 0f)
				{
					skillDriverUpdateTimer = skillDriverEvaluation.dominantSkillDriver.driverUpdateTimerOverride;
				}
				skillDriverEvaluation.dominantSkillDriver.OnSelected();
			}
			else
			{
				_ = showDebugStateChanges;
				selectedSkilldriverName = "";
			}
		}

		public virtual void OnBodyStart(CharacterBody newBody)
		{
			body = newBody;
			bodyTransform = newBody.transform;
			bodyCharacterDirection = newBody.GetComponent<CharacterDirection>();
			bodyCharacterMotor = newBody.GetComponent<CharacterMotor>();
			bodyInputBank = newBody.GetComponent<InputBankTest>();
			bodyHealthComponent = newBody.GetComponent<HealthComponent>();
			bodySkillLocator = newBody.GetComponent<SkillLocator>();
			localNavigator.SetBody(newBody);
			_broadNavigationAgent.enabled = true;
			if ((bool)stateMachine && Util.HasEffectiveAuthority(networkIdentity))
			{
				stateMachine.enabled = true;
				stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref scanState));
			}
			base.enabled = true;
			if ((bool)bodyCharacterDirection)
			{
				bodyInputs.desiredAimDirection = bodyCharacterDirection.forward;
			}
			else
			{
				bodyInputs.desiredAimDirection = bodyTransform.forward;
			}
			if ((bool)bodyInputBank)
			{
				bodyInputBank.aimDirection = bodyInputs.desiredAimDirection;
			}
			this.onBodyDiscovered?.Invoke(newBody);
		}

		public virtual void OnBodyDeath(CharacterBody characterBody)
		{
			OnBodyLost(characterBody);
		}

		public virtual void OnBodyDestroyed(CharacterBody characterBody)
		{
			OnBodyLost(characterBody);
		}

		public virtual void OnBodyLost(CharacterBody characterBody)
		{
			if ((object)body != null)
			{
				base.enabled = false;
				body = null;
				bodyTransform = null;
				bodyCharacterDirection = null;
				bodyCharacterMotor = null;
				bodyInputBank = null;
				bodyHealthComponent = null;
				bodySkillLocator = null;
				localNavigator.SetBody(null);
				_broadNavigationAgent.enabled = false;
				if ((bool)stateMachine)
				{
					stateMachine.enabled = false;
					stateMachine.SetNextState(new EntityStates.Idle());
				}
				this.onBodyLost?.Invoke(characterBody);
			}
		}

		public virtual void OnBodyDamaged(DamageReport damageReport)
		{
			DamageInfo damageInfo = damageReport.damageInfo;
			if ((bool)damageInfo.attacker && (bool)body && (!currentEnemy.gameObject || enemyAttention <= 0f) && damageInfo.attacker != body.gameObject && (!neverRetaliateFriendlies || !damageReport.isFriendlyFire))
			{
				currentEnemy.gameObject = damageInfo.attacker;
				enemyAttention = enemyAttentionDuration;
			}
		}

		[Obsolete]
		public virtual bool HasLOS(UnityEngine.Vector3 start, UnityEngine.Vector3 end)
		{
			if (!body)
			{
				return false;
			}
			UnityEngine.Vector3 direction = end - start;
			float magnitude = direction.magnitude;
			if (body.visionDistance < magnitude)
			{
				return false;
			}
			Ray ray = default(Ray);
			ray.origin = start;
			ray.direction = direction;
			RaycastHit hitInfo;
			return !Physics.Raycast(ray, out hitInfo, magnitude, LayerIndex.world.mask);
		}

		public virtual bool HasLOS(UnityEngine.Vector3 end)
		{
			if (!body || !bodyInputBank)
			{
				return false;
			}
			UnityEngine.Vector3 aimOrigin = bodyInputBank.aimOrigin;
			UnityEngine.Vector3 direction = end - aimOrigin;
			float magnitude = direction.magnitude;
			if (body.visionDistance < magnitude)
			{
				return false;
			}
			Ray ray = default(Ray);
			ray.origin = aimOrigin;
			ray.direction = direction;
			RaycastHit hitInfo;
			return !Physics.Raycast(ray, out hitInfo, magnitude, LayerIndex.world.mask);
		}

		private UnityEngine.Vector3? GetNavigationStartPos()
		{
			if (!body)
			{
				return null;
			}
			return body.footPosition;
		}

		public NodeGraph GetDesiredSpawnNodeGraph()
		{
			return SceneInfo.instance.GetNodeGraph(desiredSpawnNodeGraphType);
		}

		public void SetGoalPosition(UnityEngine.Vector3? goalPos)
		{
			BroadNavigationSystem.Agent agent = broadNavigationAgent;
			agent.goalPosition = goalPos;
		}

		public void SetGoalPosition(Target goalTarget)
		{
			UnityEngine.Vector3? goalPosition = null;
			if (goalTarget.GetBullseyePosition(out var position))
			{
				UnityEngine.Vector3 value = position;
				goalPosition = value;
			}
			SetGoalPosition(goalPosition);
		}

		public void DebugDrawPath(UnityEngine.Color color, float duration)
		{
			if (broadNavigationSystem is NodeGraphNavigationSystem)
			{
				((NodeGraphNavigationSystem.Agent)broadNavigationAgent).DebugDrawPath(color, duration);
			}
		}

		private static bool CheckLoS(UnityEngine.Vector3 start, UnityEngine.Vector3 end)
		{
			UnityEngine.Vector3 direction = end - start;
			RaycastHit hitInfo;
			return !Physics.Raycast(start, direction, out hitInfo, direction.magnitude, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
		}

		public HurtBox GetBestHurtBox(GameObject target)
		{
			HurtBoxGroup hurtBoxGroup = target.GetComponent<CharacterBody>()?.hurtBoxGroup;
			if ((bool)hurtBoxGroup && hurtBoxGroup.bullseyeCount > 1 && (bool)bodyInputBank)
			{
				UnityEngine.Vector3 aimOrigin = bodyInputBank.aimOrigin;
				HurtBox hurtBox = null;
				float num = float.PositiveInfinity;
				HurtBox[] hurtBoxes = hurtBoxGroup.hurtBoxes;
				foreach (HurtBox hurtBox2 in hurtBoxes)
				{
					if (!hurtBox2.isBullseye)
					{
						continue;
					}
					UnityEngine.Vector3 position = hurtBox2.transform.position;
					if (CheckLoS(aimOrigin, hurtBox2.transform.position))
					{
						float sqrMagnitude = (position - aimOrigin).sqrMagnitude;
						if (sqrMagnitude < num)
						{
							num = sqrMagnitude;
							hurtBox = hurtBox2;
						}
					}
				}
				if ((bool)hurtBox)
				{
					return hurtBox;
				}
			}
			return Util.FindBodyMainHurtBox(target);
		}

		public void ForceAcquireNearestEnemyIfNoCurrentEnemy()
		{
			if ((bool)currentEnemy.gameObject)
			{
				return;
			}
			if (!body)
			{
				UnityEngine.Debug.LogErrorFormat("BaseAI.ForceAcquireNearestEnemyIfNoCurrentEnemy for CharacterMaster '{0}' failed: AI has no body to search from.", base.gameObject.name);
				return;
			}
			HurtBox hurtBox = FindEnemyHurtBox(float.PositiveInfinity, full360Vision: true, filterByLoS: false);
			if ((bool)hurtBox && (bool)hurtBox.healthComponent)
			{
				currentEnemy.gameObject = hurtBox.healthComponent.gameObject;
				currentEnemy.bestHurtBox = hurtBox;
			}
		}

		private HurtBox FindEnemyHurtBox(float maxDistance, bool full360Vision, bool filterByLoS)
		{
			if (!body)
			{
				return null;
			}
			enemySearch.viewer = body;
			enemySearch.teamMaskFilter = TeamMask.allButNeutral;
			enemySearch.teamMaskFilter.RemoveTeam(master.teamIndex);
			enemySearch.sortMode = BullseyeSearch.SortMode.Distance;
			enemySearch.minDistanceFilter = 0f;
			enemySearch.maxDistanceFilter = maxDistance;
			enemySearch.searchOrigin = bodyInputBank.aimOrigin;
			enemySearch.searchDirection = bodyInputBank.aimDirection;
			enemySearch.maxAngleFilter = (full360Vision ? 180f : 90f);
			enemySearch.filterByLoS = filterByLoS;
			enemySearch.RefreshCandidates();
			return enemySearch.GetResults().FirstOrDefault();
		}

		public bool GameObjectPassesSkillDriverFilters(Target target, AISkillDriver skillDriver, out float separationSqrMagnitude)
		{
			separationSqrMagnitude = 0f;
			if (!target.gameObject)
			{
				return false;
			}
			float num = 1f;
			if ((bool)target.healthComponent)
			{
				num = target.healthComponent.combinedHealthFraction;
			}
			if (num < skillDriver.minTargetHealthFraction || num > skillDriver.maxTargetHealthFraction)
			{
				return false;
			}
			float num2 = 0f;
			if ((bool)body)
			{
				num2 = body.radius;
			}
			float num3 = 0f;
			if ((bool)target.characterBody)
			{
				num3 = target.characterBody.radius;
			}
			UnityEngine.Vector3 vector = (bodyInputBank ? bodyInputBank.aimOrigin : bodyTransform.position);
			target.GetBullseyePosition(out var position);
			float sqrMagnitude = (position - vector).sqrMagnitude;
			separationSqrMagnitude = sqrMagnitude - num3 * num3 - num2 * num2;
			if (separationSqrMagnitude < skillDriver.minDistanceSqr || separationSqrMagnitude > skillDriver.maxDistanceSqr)
			{
				return false;
			}
			if (skillDriver.selectionRequiresTargetLoS && !target.hasLoS)
			{
				return false;
			}
			return true;
		}

		private void UpdateTargets()
		{
			currentEnemy.Update();
			leader.Update();
		}

		protected SkillDriverEvaluation? EvaluateSingleSkillDriver(in SkillDriverEvaluation currentSkillDriverEvaluation, AISkillDriver aiSkillDriver, float myHealthFraction)
		{
			if (!body || !bodySkillLocator)
			{
				return null;
			}
			float separationSqrMagnitude = float.PositiveInfinity;
			if (aiSkillDriver.noRepeat && currentSkillDriverEvaluation.dominantSkillDriver == aiSkillDriver)
			{
				return null;
			}
			if (aiSkillDriver.maxTimesSelected >= 0 && aiSkillDriver.timesSelected >= aiSkillDriver.maxTimesSelected)
			{
				return null;
			}
			Target target = null;
			if (aiSkillDriver.requireEquipmentReady && body.equipmentSlot.stock <= 0)
			{
				return null;
			}
			if (aiSkillDriver.skillSlot != SkillSlot.None)
			{
				GenericSkill skill = bodySkillLocator.GetSkill(aiSkillDriver.skillSlot);
				if (aiSkillDriver.requireSkillReady && (!skill || !skill.IsReady()))
				{
					return null;
				}
				if ((bool)aiSkillDriver.requiredSkill && (!skill || !(skill.skillDef == aiSkillDriver.requiredSkill)))
				{
					return null;
				}
			}
			if (aiSkillDriver.minUserHealthFraction > myHealthFraction || aiSkillDriver.maxUserHealthFraction < myHealthFraction)
			{
				return null;
			}
			if ((bool)bodyCharacterMotor && !bodyCharacterMotor.isGrounded && aiSkillDriver.selectionRequiresOnGround)
			{
				return null;
			}
			switch (aiSkillDriver.moveTargetType)
			{
			case AISkillDriver.TargetType.CurrentEnemy:
				if (GameObjectPassesSkillDriverFilters(currentEnemy, aiSkillDriver, out separationSqrMagnitude))
				{
					target = currentEnemy;
				}
				break;
			case AISkillDriver.TargetType.NearestFriendlyInSkillRange:
				if ((bool)bodyInputBank)
				{
					buddySearch.teamMaskFilter = TeamMask.none;
					buddySearch.teamMaskFilter.AddTeam(master.teamIndex);
					buddySearch.sortMode = BullseyeSearch.SortMode.Distance;
					buddySearch.minDistanceFilter = aiSkillDriver.minDistanceSqr;
					buddySearch.maxDistanceFilter = aiSkillDriver.maxDistance;
					buddySearch.searchOrigin = bodyInputBank.aimOrigin;
					buddySearch.searchDirection = bodyInputBank.aimDirection;
					buddySearch.maxAngleFilter = 180f;
					buddySearch.filterByLoS = aiSkillDriver.activationRequiresTargetLoS;
					buddySearch.RefreshCandidates();
					if ((bool)body)
					{
						buddySearch.FilterOutGameObject(body.gameObject);
					}
					buddySearch.FilterCandidatesByHealthFraction(aiSkillDriver.minTargetHealthFraction, aiSkillDriver.maxTargetHealthFraction);
					HurtBox hurtBox = buddySearch.GetResults().FirstOrDefault();
					if ((bool)hurtBox && (bool)hurtBox.healthComponent)
					{
						buddy.gameObject = hurtBox.healthComponent.gameObject;
						buddy.bestHurtBox = hurtBox;
					}
					if (GameObjectPassesSkillDriverFilters(buddy, aiSkillDriver, out separationSqrMagnitude))
					{
						target = buddy;
					}
				}
				break;
			case AISkillDriver.TargetType.CurrentLeader:
				if (GameObjectPassesSkillDriverFilters(leader, aiSkillDriver, out separationSqrMagnitude))
				{
					target = leader;
				}
				break;
			case AISkillDriver.TargetType.Custom:
				if (GameObjectPassesSkillDriverFilters(customTarget, aiSkillDriver, out separationSqrMagnitude))
				{
					target = customTarget;
				}
				break;
			}
			if (target == null)
			{
				return null;
			}
			Target target2 = null;
			if (aiSkillDriver.aimType != 0)
			{
				bool flag = aiSkillDriver.selectionRequiresAimTarget;
				switch (aiSkillDriver.aimType)
				{
				case AISkillDriver.AimType.AtMoveTarget:
					target2 = target;
					break;
				case AISkillDriver.AimType.AtCurrentEnemy:
					target2 = currentEnemy;
					break;
				case AISkillDriver.AimType.AtCurrentLeader:
					target2 = leader;
					break;
				default:
					flag = false;
					break;
				}
				if (flag && (target2 == null || !target2.gameObject))
				{
					return null;
				}
			}
			SkillDriverEvaluation value = default(SkillDriverEvaluation);
			value.dominantSkillDriver = aiSkillDriver;
			value.target = target;
			value.aimTarget = target2;
			value.separationSqrMagnitude = separationSqrMagnitude;
			return value;
		}

		public SkillDriverEvaluation EvaluateSkillDrivers()
		{
			UpdateTargets();
			float myHealthFraction = 1f;
			if ((bool)bodyHealthComponent)
			{
				myHealthFraction = bodyHealthComponent.combinedHealthFraction;
			}
			if ((bool)bodySkillLocator)
			{
				if ((bool)this.skillDriverEvaluation.dominantSkillDriver && (bool)this.skillDriverEvaluation.dominantSkillDriver.nextHighPriorityOverride)
				{
					SkillDriverEvaluation? skillDriverEvaluation = EvaluateSingleSkillDriver(in this.skillDriverEvaluation, this.skillDriverEvaluation.dominantSkillDriver.nextHighPriorityOverride, myHealthFraction);
					if (skillDriverEvaluation.HasValue)
					{
						return skillDriverEvaluation.Value;
					}
				}
				for (int i = 0; i < skillDrivers.Length; i++)
				{
					AISkillDriver aISkillDriver = skillDrivers[i];
					if (aISkillDriver.enabled)
					{
						SkillDriverEvaluation? skillDriverEvaluation2 = EvaluateSingleSkillDriver(in this.skillDriverEvaluation, aISkillDriver, myHealthFraction);
						if (skillDriverEvaluation2.HasValue)
						{
							return skillDriverEvaluation2.Value;
						}
					}
				}
			}
			return default(SkillDriverEvaluation);
		}

		protected void UpdateBodyInputs()
		{
			if (stateMachine.state is BaseAIState baseAIState)
			{
				bodyInputs = baseAIState.GenerateBodyInputs(in bodyInputs);
			}
			if ((bool)bodyInputBank)
			{
				bodyInputBank.skill1.PushState(bodyInputs.pressSkill1);
				bodyInputBank.skill2.PushState(bodyInputs.pressSkill2);
				bodyInputBank.skill3.PushState(bodyInputs.pressSkill3);
				bodyInputBank.skill4.PushState(bodyInputs.pressSkill4);
				bodyInputBank.jump.PushState(bodyInputs.pressJump);
				bodyInputBank.sprint.PushState(bodyInputs.pressSprint);
				bodyInputBank.activateEquipment.PushState(bodyInputs.pressActivateEquipment);
				bodyInputBank.moveVector = bodyInputs.moveVector;
			}
		}

		protected void UpdateBodyAim(float deltaTime)
		{
			hasAimConfirmation = false;
			if ((bool)bodyInputBank)
			{
				UnityEngine.Vector3 aimDirection = bodyInputBank.aimDirection;
				UnityEngine.Vector3 desiredAimDirection = bodyInputs.desiredAimDirection;
				if (desiredAimDirection != UnityEngine.Vector3.zero)
				{
					UnityEngine.Quaternion target = Util.QuaternionSafeLookRotation(desiredAimDirection);
					UnityEngine.Vector3 vector = Util.SmoothDampQuaternion(Util.QuaternionSafeLookRotation(aimDirection), maxSpeed: aimVectorMaxSpeed, target: target, currentVelocity: ref aimVelocity, smoothTime: aimVectorDampTime, deltaTime: deltaTime) * UnityEngine.Vector3.forward;
					bodyInputBank.aimDirection = vector;
					hasAimConfirmation = UnityEngine.Vector3.Dot(vector, desiredAimDirection) >= 0.95f;
				}
			}
		}

		[ConCommand(commandName = "ai_draw_path", flags = ConVarFlags.Cheat, helpText = "Enables or disables the drawing of the specified AI's broad navigation path. Format: ai_draw_path <CharacterMaster selector> <0/1>")]
		private static void CCAiDrawPath(ConCommandArgs args)
		{
			CharacterMaster argCharacterMasterInstance = args.GetArgCharacterMasterInstance(0);
			args.GetArgBool(1);
			if (!argCharacterMasterInstance)
			{
				throw new ConCommandException("Could not find target.");
			}
			BaseAI component = argCharacterMasterInstance.GetComponent<BaseAI>();
			if (!component)
			{
				throw new ConCommandException("Target has no AI.");
			}
			component.ToggleBroadNavigationDebugDraw();
		}
	}
	[RequireComponent(typeof(BaseAI))]
	public class EmergencyDroneCustomTarget : MonoBehaviour
	{
		private BaseAI ai;

		private BullseyeSearch search;

		public float searchInterval;

		private float timer;

		private void Awake()
		{
			ai = GetComponent<BaseAI>();
			if (NetworkServer.active)
			{
				search = new BullseyeSearch();
			}
		}

		private void FixedUpdate()
		{
			if (NetworkServer.active)
			{
				FixedUpdateServer();
			}
		}

		private void FixedUpdateServer()
		{
			timer -= Time.fixedDeltaTime;
			if (timer <= 0f)
			{
				timer = searchInterval;
				DoSearch();
			}
		}

		private void DoSearch()
		{
			if ((bool)ai.body)
			{
				Ray aimRay = ai.bodyInputBank.GetAimRay();
				search.viewer = ai.body;
				search.filterByDistinctEntity = true;
				search.filterByLoS = false;
				search.maxDistanceFilter = float.PositiveInfinity;
				search.minDistanceFilter = 0f;
				search.maxAngleFilter = 360f;
				search.searchDirection = aimRay.direction;
				search.searchOrigin = aimRay.origin;
				search.sortMode = BullseyeSearch.SortMode.Distance;
				search.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
				TeamMask none = TeamMask.none;
				none.AddTeam(ai.master.teamIndex);
				search.teamMaskFilter = none;
				search.RefreshCandidates();
				search.FilterOutGameObject(ai.body.gameObject);
				ai.customTarget.gameObject = search.GetResults().Where(TargetPassesFilters).FirstOrDefault()?.healthComponent.gameObject;
			}
		}

		private bool TargetPassesFilters(HurtBox hurtBox)
		{
			if (IsHurt(hurtBox))
			{
				return !HealBeamController.HealBeamAlreadyExists(ai.body.gameObject, hurtBox.healthComponent);
			}
			return false;
		}

		private static bool IsHurt(HurtBox hurtBox)
		{
			if (hurtBox.healthComponent.alive)
			{
				return hurtBox.healthComponent.health < hurtBox.healthComponent.fullHealth;
			}
			return false;
		}
	}
}
namespace RoR2.Skills
{
	[CreateAssetMenu(menuName = "RoR2/SkillDef/SeekerWeaponSkillDef", fileName = "New SeekerSkillDef.asset")]
	public class SeekerWeaponSkillDef : SteppedSkillDef
	{
		public bool targetTrackingIndicator;

		public GameObject crosshairOverridePrefab;
	}
	public class ConditionalSkillOverride : MonoBehaviour
	{
		[Serializable]
		public struct ConditionalSkillInfo
		{
			public GenericSkill skillSlot;

			public SkillDef sprintSkillDef;

			public SkillDef airborneSkillDef;
		}

		public CharacterBody characterBody;

		public ConditionalSkillInfo[] conditionalSkillInfos;

		private bool wasSprinting;

		private bool wasAirborne;

		private void Start()
		{
		}

		private void FixedUpdate()
		{
			bool flag = false;
			bool flag2 = false;
			if ((bool)characterBody)
			{
				flag = characterBody.isSprinting;
				if ((bool)characterBody.characterMotor)
				{
					flag2 = characterBody.characterMotor.isGrounded;
				}
			}
			bool flag3 = wasSprinting || wasAirborne;
			bool flag4 = flag || flag2;
			ConditionalSkillInfo[] array = conditionalSkillInfos;
			for (int i = 0; i < array.Length; i++)
			{
				ConditionalSkillInfo conditionalSkillInfo = array[i];
				if (flag3)
				{
					if (wasAirborne && !flag2)
					{
						conditionalSkillInfo.skillSlot.UnsetSkillOverride(this, conditionalSkillInfo.airborneSkillDef, GenericSkill.SkillOverridePriority.Contextual);
					}
					else if (wasSprinting && !flag)
					{
						conditionalSkillInfo.skillSlot.UnsetSkillOverride(this, conditionalSkillInfo.sprintSkillDef, GenericSkill.SkillOverridePriority.Contextual);
					}
				}
				if (flag4)
				{
					if (flag2 && !wasAirborne)
					{
						conditionalSkillInfo.skillSlot.SetSkillOverride(this, conditionalSkillInfo.airborneSkillDef, GenericSkill.SkillOverridePriority.Contextual);
					}
					else if (flag && !wasSprinting)
					{
						conditionalSkillInfo.skillSlot.SetSkillOverride(this, conditionalSkillInfo.sprintSkillDef, GenericSkill.SkillOverridePriority.Contextual);
					}
				}
			}
			wasAirborne = flag2;
			wasSprinting = flag;
		}
	}
	public class CaptainOrbitalSkillDef : SkillDef
	{
		public Sprite disabledIcon;

		public string disabledNameToken;

		public string disabledDescriptionToken;

		private bool isAvailable => !SceneCatalog.mostRecentSceneDef.blockOrbitalSkills;

		public override Sprite GetCurrentIcon(GenericSkill skillSlot)
		{
			if (!isAvailable)
			{
				return disabledIcon;
			}
			return base.GetCurrentIcon(skillSlot);
		}

		public override string GetCurrentNameToken(GenericSkill skillSlot)
		{
			if (!isAvailable)
			{
				return disabledNameToken;
			}
			return base.GetCurrentNameToken(skillSlot);
		}

		public override string GetCurrentDescriptionToken(GenericSkill skillSlot)
		{
			if (!isAvailable)
			{
				return disabledDescriptionToken;
			}
			return base.GetCurrentDescriptionToken(skillSlot);
		}

		public override bool CanExecute(GenericSkill skillSlot)
		{
			if (isAvailable)
			{
				return base.CanExecute(skillSlot);
			}
			return false;
		}

		public override bool IsReady(GenericSkill skillSlot)
		{
			if (isAvailable)
			{
				return base.IsReady(skillSlot);
			}
			return false;
		}
	}
	public class CaptainSupplyDropSkillDef : CaptainOrbitalSkillDef
	{
		protected class InstanceData : BaseSkillInstanceData, IDisposable
		{
			public List<GenericSkill> supplySkillSlots;

			public bool anySupplyDropsAvailable;

			private GenericSkill skillSlot;

			private string[] supplyDropSkillSlotNames;

			public InstanceData(GenericSkill skillSlot, string[] supplyDropSkillSlotNames)
			{
				supplySkillSlots = CollectionPool<GenericSkill, List<GenericSkill>>.RentCollection();
				this.skillSlot = skillSlot;
				this.supplyDropSkillSlotNames = supplyDropSkillSlotNames;
			}

			public void Dispose()
			{
				supplySkillSlots = CollectionPool<GenericSkill, List<GenericSkill>>.ReturnCollection(supplySkillSlots);
				skillSlot = null;
				supplyDropSkillSlotNames = null;
			}

			private bool CheckForSupplyDropAvailable()
			{
				for (int i = 0; i < supplySkillSlots.Count; i++)
				{
					if (supplySkillSlots[i].IsReady())
					{
						return true;
					}
				}
				return false;
			}

			private void FindSupplyDropSkillSlots()
			{
				for (int i = 0; i < supplyDropSkillSlotNames.Length; i++)
				{
					GenericSkill genericSkill = skillSlot.GetComponent<SkillLocator>().FindSkill(supplyDropSkillSlotNames[i]);
					if ((bool)genericSkill)
					{
						supplySkillSlots.Add(genericSkill);
					}
				}
			}

			public void FixedUpdate()
			{
				if (supplySkillSlots.Count == 0)
				{
					FindSupplyDropSkillSlots();
				}
				anySupplyDropsAvailable = CheckForSupplyDropAvailable();
			}
		}

		public string[] supplyDropSkillSlotNames = Array.Empty<string>();

		public Sprite exhaustedIcon;

		public string exhaustedNameToken;

		public string exhaustedDescriptionToken;

		public override Sprite GetCurrentIcon(GenericSkill skillSlot)
		{
			if (!((InstanceData)skillSlot.skillInstanceData).anySupplyDropsAvailable)
			{
				return exhaustedIcon;
			}
			return base.GetCurrentIcon(skillSlot);
		}

		public override string GetCurrentNameToken(GenericSkill skillSlot)
		{
			if (!((InstanceData)skillSlot.skillInstanceData).anySupplyDropsAvailable)
			{
				return exhaustedNameToken;
			}
			return base.GetCurrentNameToken(skillSlot);
		}

		public override string GetCurrentDescriptionToken(GenericSkill skillSlot)
		{
			if (!((InstanceData)skillSlot.skillInstanceData).anySupplyDropsAvailable)
			{
				return exhaustedDescriptionToken;
			}
			return base.GetCurrentDescriptionToken(skillSlot);
		}

		public override bool CanExecute(GenericSkill skillSlot)
		{
			if (((InstanceData)skillSlot.skillInstanceData).anySupplyDropsAvailable)
			{
				return base.CanExecute(skillSlot);
			}
			return false;
		}

		public override bool IsReady(GenericSkill skillSlot)
		{
			if (((InstanceData)skillSlot.skillInstanceData).anySupplyDropsAvailable)
			{
				return base.IsReady(skillSlot);
			}
			return false;
		}

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			return new InstanceData(skillSlot, supplyDropSkillSlotNames);
		}

		public override void OnUnassigned(GenericSkill skillSlot)
		{
			((InstanceData)skillSlot.skillInstanceData).Dispose();
			base.OnUnassigned(skillSlot);
		}

		public override void OnFixedUpdate(GenericSkill skillSlot, float deltaTime)
		{
			base.OnFixedUpdate(skillSlot, deltaTime);
			((InstanceData)skillSlot.skillInstanceData).FixedUpdate();
		}
	}
	public class ComboSkillDef : SkillDef
	{
		[Serializable]
		public struct Combo
		{
			public SerializableEntityStateType activationStateType;
		}

		protected class InstanceData : BaseSkillInstanceData
		{
			public int comboCounter;
		}

		public Combo[] comboList;

		protected SerializableEntityStateType GetNextStateType(GenericSkill skillSlot)
		{
			return ArrayUtils.GetSafe(comboList, ((InstanceData)skillSlot.skillInstanceData).comboCounter).activationStateType;
		}

		protected override EntityState InstantiateNextState(GenericSkill skillSlot)
		{
			SerializableEntityStateType serializableStateType = GetNextStateType(skillSlot);
			return EntityStateCatalog.InstantiateState(ref serializableStateType);
		}

		public override void OnExecute(GenericSkill skillSlot)
		{
			base.OnExecute(skillSlot);
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			instanceData.comboCounter++;
			if (instanceData.comboCounter >= comboList.Length)
			{
				instanceData.comboCounter = 0;
			}
		}
	}
	public class ConditionalSkillDef : SkillDef
	{
		protected class InstanceData : BaseSkillInstanceData
		{
			public CharacterBody characterBody;
		}

		public SerializableEntityStateType baseStateType;

		public SerializableEntityStateType sprintStateType;

		public SerializableEntityStateType jumpStateType;

		public override BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return new InstanceData
			{
				characterBody = skillSlot.GetComponent<CharacterBody>()
			};
		}

		public bool IsGrounded([NotNull] GenericSkill skillSlot)
		{
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if ((bool)instanceData.characterBody.characterMotor && instanceData.characterBody.characterMotor.isGrounded)
			{
				return true;
			}
			return false;
		}

		public bool IsSprinting([NotNull] GenericSkill skillSlot)
		{
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if ((bool)instanceData.characterBody && instanceData.characterBody.isSprinting)
			{
				return true;
			}
			return false;
		}

		protected override EntityState InstantiateNextState(GenericSkill skillSlot)
		{
			bool num = IsGrounded(skillSlot);
			bool flag = IsSprinting(skillSlot);
			if (!num)
			{
				return EntityStateCatalog.InstantiateState(ref jumpStateType);
			}
			if (flag)
			{
				return EntityStateCatalog.InstantiateState(ref sprintStateType);
			}
			return EntityStateCatalog.InstantiateState(ref baseStateType);
		}
	}
	public class EngiMineDeployerSkill : SkillDef
	{
		public override bool CanExecute(GenericSkill skillSlot)
		{
			List<BaseMineDeployerState> instancesList = BaseMineDeployerState.instancesList;
			for (int i = 0; i < instancesList.Count; i++)
			{
				if (instancesList[i].owner == skillSlot.gameObject)
				{
					return false;
				}
			}
			return base.CanExecute(skillSlot);
		}
	}
	public class GroundedSkillDef : SkillDef
	{
		protected class InstanceData : BaseSkillInstanceData
		{
			public CharacterMotor characterMotor;
		}

		public override BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return new InstanceData
			{
				characterMotor = skillSlot.GetComponent<CharacterMotor>()
			};
		}

		public bool IsGrounded([NotNull] GenericSkill skillSlot)
		{
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if ((bool)instanceData.characterMotor && instanceData.characterMotor.isGrounded)
			{
				return true;
			}
			return false;
		}

		public override bool IsReady([NotNull] GenericSkill skillSlot)
		{
			if (HasRequiredStockAndDelay(skillSlot))
			{
				return IsGrounded(skillSlot);
			}
			return false;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/HuntressTrackingSkillDef")]
	public class HuntressTrackingSkillDef : SkillDef
	{
		protected class InstanceData : BaseSkillInstanceData
		{
			public HuntressTracker huntressTracker;
		}

		public override BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return new InstanceData
			{
				huntressTracker = skillSlot.GetComponent<HuntressTracker>()
			};
		}

		private static bool HasTarget([NotNull] GenericSkill skillSlot)
		{
			if (!(((InstanceData)skillSlot.skillInstanceData).huntressTracker?.GetTrackingTarget()))
			{
				return false;
			}
			return true;
		}

		public override bool CanExecute([NotNull] GenericSkill skillSlot)
		{
			if (!HasTarget(skillSlot))
			{
				return false;
			}
			return base.CanExecute(skillSlot);
		}

		public override bool IsReady([NotNull] GenericSkill skillSlot)
		{
			if (base.IsReady(skillSlot))
			{
				return HasTarget(skillSlot);
			}
			return false;
		}
	}
	public class LunarDetonatorSkill : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			private GenericSkill _skillSlot;

			private LunarDetonatorPassiveAttachment lunarDetonatorPassiveAttachment;

			public GenericSkill skillSlot
			{
				get
				{
					return _skillSlot;
				}
				set
				{
					if ((object)_skillSlot == value)
					{
						return;
					}
					if ((object)_skillSlot != null)
					{
						_skillSlot.characterBody.onInventoryChanged -= OnInventoryChanged;
					}
					if ((bool)lunarDetonatorPassiveAttachment)
					{
						UnityEngine.Object.Destroy(lunarDetonatorPassiveAttachment.gameObject);
					}
					lunarDetonatorPassiveAttachment = null;
					_skillSlot = value;
					if ((object)_skillSlot != null)
					{
						_skillSlot.characterBody.onInventoryChanged += OnInventoryChanged;
						if (NetworkServer.active && (bool)_skillSlot.characterBody)
						{
							GameObject gameObject = UnityEngine.Object.Instantiate(lunarDetonatorPassiveAttachmentPrefab);
							lunarDetonatorPassiveAttachment = gameObject.GetComponent<LunarDetonatorPassiveAttachment>();
							lunarDetonatorPassiveAttachment.monitoredSkill = skillSlot;
							gameObject.GetComponent<NetworkedBodyAttachment>().AttachToGameObjectAndSpawn(_skillSlot.characterBody.gameObject);
						}
					}
				}
			}

			public void OnInventoryChanged()
			{
				skillSlot.RecalculateValues();
			}
		}

		private static GameObject lunarDetonatorPassiveAttachmentPrefab;

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/NetworkedObjects/BodyAttachments/LunarDetonatorPassiveAttachment");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				lunarDetonatorPassiveAttachmentPrefab = x.Result;
			};
		}

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			return new InstanceData
			{
				skillSlot = skillSlot
			};
		}

		public override void OnUnassigned(GenericSkill skillSlot)
		{
			((InstanceData)skillSlot.skillInstanceData).skillSlot = null;
		}

		public override float GetRechargeInterval(GenericSkill skillSlot)
		{
			return (float)skillSlot.characterBody.inventory.GetItemCount(RoR2Content.Items.LunarSpecialReplacement) * baseRechargeInterval;
		}
	}
	public class LunarPrimaryReplacementSkill : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			public GenericSkill skillSlot;

			public void OnInventoryChanged()
			{
				skillSlot.RecalculateValues();
			}
		}

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			InstanceData instanceData = new InstanceData();
			instanceData.skillSlot = skillSlot;
			skillSlot.characterBody.onInventoryChanged += instanceData.OnInventoryChanged;
			return instanceData;
		}

		public override void OnUnassigned(GenericSkill skillSlot)
		{
			skillSlot.characterBody.onInventoryChanged -= ((InstanceData)skillSlot.skillInstanceData).OnInventoryChanged;
		}

		public override int GetMaxStock(GenericSkill skillSlot)
		{
			return skillSlot.characterBody.inventory.GetItemCount(RoR2Content.Items.LunarPrimaryReplacement) * baseMaxStock;
		}

		public override float GetRechargeInterval(GenericSkill skillSlot)
		{
			return (float)skillSlot.characterBody.inventory.GetItemCount(RoR2Content.Items.LunarPrimaryReplacement) * baseRechargeInterval;
		}

		public override int GetRechargeStock(GenericSkill skillSlot)
		{
			return GetMaxStock(skillSlot);
		}
	}
	public class LunarSecondaryReplacementSkill : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			public GenericSkill skillSlot;

			public void OnInventoryChanged()
			{
				skillSlot.RecalculateValues();
			}
		}

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			InstanceData instanceData = new InstanceData();
			instanceData.skillSlot = skillSlot;
			skillSlot.characterBody.onInventoryChanged += instanceData.OnInventoryChanged;
			return instanceData;
		}

		public override void OnUnassigned(GenericSkill skillSlot)
		{
			skillSlot.characterBody.onInventoryChanged -= ((InstanceData)skillSlot.skillInstanceData).OnInventoryChanged;
		}

		public override float GetRechargeInterval(GenericSkill skillSlot)
		{
			return (float)skillSlot.characterBody.inventory.GetItemCount(RoR2Content.Items.LunarSecondaryReplacement) * baseRechargeInterval;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/MasterSpawnSlotSkillDef")]
	public class MasterSpawnSlotSkillDef : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			public MasterSpawnSlotController slotController;
		}

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			return new InstanceData
			{
				slotController = skillSlot.GetComponent<MasterSpawnSlotController>()
			};
		}

		private bool IsAnySlotOpen([NotNull] GenericSkill skillSlot)
		{
			if (skillSlot.skillInstanceData is InstanceData instanceData && (bool)instanceData.slotController)
			{
				return instanceData.slotController.openSlotCount > 0;
			}
			return false;
		}

		public override bool IsReady([NotNull] GenericSkill skillSlot)
		{
			if (base.IsReady(skillSlot))
			{
				return IsAnySlotOpen(skillSlot);
			}
			return false;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/MercDashSkillDef")]
	public class MercDashSkillDef : SkillDef
	{
		protected class InstanceData : BaseSkillInstanceData
		{
			public int currentDashIndex;

			public float timeoutTimer;

			public bool waitingForHit;

			public bool hasExtraStock;
		}

		public int maxDashes;

		public float timeoutDuration;

		public Sprite[] icons;

		public override BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return new InstanceData();
		}

		public override void OnUnassigned([NotNull] GenericSkill skillSlot)
		{
			base.OnUnassigned(skillSlot);
		}

		public override void OnFixedUpdate([NotNull] GenericSkill skillSlot, float deltaTime)
		{
			base.OnFixedUpdate(skillSlot, deltaTime);
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if (instanceData.waitingForHit && skillSlot.stateMachine.state is Assaulter2 { grantAnotherDash: not false })
			{
				instanceData.waitingForHit = false;
				AddHit(skillSlot);
			}
			instanceData.timeoutTimer -= deltaTime;
			if (instanceData.timeoutTimer <= 0f && instanceData.currentDashIndex != 0)
			{
				if (instanceData.hasExtraStock)
				{
					skillSlot.stock--;
					instanceData.hasExtraStock = false;
				}
				instanceData.currentDashIndex = 0;
			}
		}

		protected override EntityState InstantiateNextState([NotNull] GenericSkill skillSlot)
		{
			EntityState entityState = base.InstantiateNextState(skillSlot);
			if (entityState is PrepAssaulter2 prepAssaulter)
			{
				prepAssaulter.dashIndex = ((InstanceData)skillSlot.skillInstanceData).currentDashIndex;
			}
			return entityState;
		}

		public override void OnExecute([NotNull] GenericSkill skillSlot)
		{
			base.OnExecute(skillSlot);
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if (!instanceData.hasExtraStock)
			{
				instanceData.currentDashIndex = 0;
			}
			instanceData.waitingForHit = true;
			instanceData.hasExtraStock = false;
			instanceData.timeoutTimer = timeoutDuration;
		}

		protected void AddHit([NotNull] GenericSkill skillSlot)
		{
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if (instanceData.currentDashIndex < maxDashes - 1)
			{
				instanceData.currentDashIndex++;
				int stock = skillSlot.stock + 1;
				skillSlot.stock = stock;
				instanceData.hasExtraStock = true;
			}
			else
			{
				instanceData.currentDashIndex = 0;
			}
		}

		public override Sprite GetCurrentIcon([NotNull] GenericSkill skillSlot)
		{
			int index = ((InstanceData)skillSlot.skillInstanceData)?.currentDashIndex ?? 0;
			return ArrayUtils.GetSafe(icons, index);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/PassiveItem")]
	public class PassiveItemSkillDef : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			public bool hasItemBeenGiven;
		}

		[SerializeField]
		public ItemDef passiveItem;

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			InstanceData instanceData = new InstanceData
			{
				hasItemBeenGiven = false
			};
			if (NetworkServer.active)
			{
				TryGiveItem(skillSlot, instanceData);
			}
			return instanceData;
		}

		public override void OnFixedUpdate(GenericSkill skillSlot, float deltaTime)
		{
			if (NetworkServer.active)
			{
				TryGiveItem(skillSlot, (InstanceData)skillSlot.skillInstanceData);
			}
		}

		public override void OnUnassigned(GenericSkill skillSlot)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if (instanceData.hasItemBeenGiven)
			{
				CharacterBody component = skillSlot.GetComponent<CharacterBody>();
				if ((bool)component && (bool)component.inventory)
				{
					component.inventory.RemoveItem(passiveItem);
					instanceData.hasItemBeenGiven = false;
				}
			}
		}

		private void TryGiveItem(GenericSkill skillSlot, InstanceData data)
		{
			if (!data.hasItemBeenGiven)
			{
				CharacterBody component = skillSlot.GetComponent<CharacterBody>();
				if ((bool)component && (bool)component.inventory)
				{
					component.inventory.GiveItem(passiveItem);
					data.hasItemBeenGiven = true;
				}
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/RailgunSkillDef")]
	public class RailgunSkillDef : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			public EntityStateMachine backpackStateMachine;

			public EntityStateMachine reloadStateMachine;
		}

		private const string backpackStateMachineName = "Backpack";

		private const string reloadStateMachineName = "Reload";

		[SerializeField]
		public Sprite offlineIcon;

		[SerializeField]
		public bool restockOnReload;

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			return new InstanceData
			{
				backpackStateMachine = EntityStateMachine.FindByCustomName(skillSlot.gameObject, "Backpack"),
				reloadStateMachine = EntityStateMachine.FindByCustomName(skillSlot.gameObject, "Reload")
			};
		}

		private bool IsBackpackOffline([NotNull] GenericSkill skillSlot)
		{
			if (skillSlot.skillInstanceData is InstanceData instanceData && (bool)instanceData.backpackStateMachine)
			{
				return instanceData.backpackStateMachine.state is Offline;
			}
			return false;
		}

		private bool IsReloading([NotNull] GenericSkill skillSlot)
		{
			if (skillSlot.skillInstanceData is InstanceData instanceData && (bool)instanceData.reloadStateMachine)
			{
				return instanceData.reloadStateMachine.state is Reloading;
			}
			return false;
		}

		public override bool IsReady([NotNull] GenericSkill skillSlot)
		{
			if (base.IsReady(skillSlot) && !IsBackpackOffline(skillSlot))
			{
				return !IsReloading(skillSlot);
			}
			return false;
		}

		public override void OnFixedUpdate([NotNull] GenericSkill skillSlot, float deltaTime)
		{
			base.OnFixedUpdate(skillSlot, deltaTime);
			if (IsBackpackOffline(skillSlot))
			{
				skillSlot.rechargeStopwatch = 0f;
			}
		}

		public override Sprite GetCurrentIcon([NotNull] GenericSkill skillSlot)
		{
			if (IsBackpackOffline(skillSlot))
			{
				return offlineIcon;
			}
			return base.GetCurrentIcon(skillSlot);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/ReloadSkillDef")]
	public class ReloadSkillDef : SkillDef
	{
		protected class InstanceData : BaseSkillInstanceData
		{
			public int currentStock;

			public float graceStopwatch;
		}

		[Header("Reload Parameters")]
		[Tooltip("The reload state to go into, when stock is less than max.")]
		public SerializableEntityStateType reloadState;

		[Tooltip("The priority of this reload state.")]
		public InterruptPriority reloadInterruptPriority = InterruptPriority.Skill;

		[Tooltip("The amount of time to wait between when we COULD reload, and when we actually start")]
		public float graceDuration;

		public override BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return new InstanceData();
		}

		public override void OnUnassigned([NotNull] GenericSkill skillSlot)
		{
			base.OnUnassigned(skillSlot);
		}

		public override void OnFixedUpdate([NotNull] GenericSkill skillSlot, float deltaTime)
		{
			base.OnFixedUpdate(skillSlot, deltaTime);
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			instanceData.currentStock = skillSlot.stock;
			if (instanceData.currentStock >= GetMaxStock(skillSlot))
			{
				return;
			}
			if ((bool)skillSlot.stateMachine && !skillSlot.stateMachine.HasPendingState() && skillSlot.stateMachine.CanInterruptState(reloadInterruptPriority))
			{
				instanceData.graceStopwatch += deltaTime;
				if (instanceData.graceStopwatch >= graceDuration || instanceData.currentStock == 0)
				{
					skillSlot.stateMachine.SetNextState(EntityStateCatalog.InstantiateState(ref reloadState));
				}
			}
			else
			{
				instanceData.graceStopwatch = 0f;
			}
		}

		public override void OnExecute([NotNull] GenericSkill skillSlot)
		{
			base.OnExecute(skillSlot);
			((InstanceData)skillSlot.skillInstanceData).currentStock = skillSlot.stock;
		}
	}
	public static class SkillCatalog
	{
		private static SkillDef[] _allSkillDefs = Array.Empty<SkillDef>();

		private static string[] _allSkillNames = Array.Empty<string>();

		private static SkillFamily[] _allSkillFamilies = Array.Empty<SkillFamily>();

		private static string[] _allSkillFamilyNames = Array.Empty<string>();

		public static ResourceAvailability skillsDefined;

		public static IEnumerable<SkillDef> allSkillDefs => _allSkillDefs;

		public static IEnumerable<SkillFamily> allSkillFamilies => _allSkillFamilies;

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<SkillDef>> getAdditionalSkillDefs
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.Skills.SkillCatalog.getAdditionalSkillDefs", value, LegacyModContentPackProvider.instance.registrationContentPack.skillDefs);
			}
			remove
			{
			}
		}

		[Obsolete("Use IContentPackProvider instead.")]
		public static event Action<List<SkillFamily>> getAdditionalSkillFamilies
		{
			add
			{
				LegacyModContentPackProvider.instance.HandleLegacyGetAdditionalEntries("RoR2.Skills.SkillCatalog.getAdditionalSkillFamilies", value, LegacyModContentPackProvider.instance.registrationContentPack.skillFamilies);
			}
			remove
			{
			}
		}

		public static SkillDef GetSkillDef(int skillDefIndex)
		{
			return ArrayUtils.GetSafe(_allSkillDefs, skillDefIndex);
		}

		public static string GetSkillName(int skillDefIndex)
		{
			return ArrayUtils.GetSafe(_allSkillNames, skillDefIndex);
		}

		public static SkillFamily GetSkillFamily(int skillFamilyIndex)
		{
			return ArrayUtils.GetSafe(_allSkillFamilies, skillFamilyIndex);
		}

		public static string GetSkillFamilyName(int skillFamilyIndex)
		{
			return ArrayUtils.GetSafe(_allSkillFamilyNames, skillFamilyIndex);
		}

		public static int FindSkillIndexByName(string skillName)
		{
			for (int i = 0; i < _allSkillDefs.Length; i++)
			{
				if (_allSkillDefs[i].skillName == skillName)
				{
					return i;
				}
			}
			return -1;
		}

		[SystemInitializer(new Type[] { typeof(BodyCatalog) })]
		private static void Init()
		{
			SetSkillDefs(ContentManager.skillDefs);
			SetSkillFamilies(ContentManager.skillFamilies);
			skillsDefined.MakeAvailable();
		}

		private static void SetSkillDefs(SkillDef[] newSkillDefs)
		{
			SkillDef[] array = _allSkillDefs;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].skillIndex = -1;
			}
			ArrayUtils.CloneTo(newSkillDefs, ref _allSkillDefs);
			Array.Resize(ref _allSkillNames, _allSkillDefs.Length);
			for (int j = 0; j < _allSkillDefs.Length; j++)
			{
				_allSkillDefs[j].skillIndex = j;
				_allSkillNames[j] = ((UnityEngine.Object)_allSkillDefs[j]).name;
			}
		}

		private static void SetSkillFamilies(SkillFamily[] newSkillFamilies)
		{
			SkillFamily[] array = _allSkillFamilies;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].catalogIndex = -1;
			}
			ArrayUtils.CloneTo(newSkillFamilies, ref _allSkillFamilies);
			Array.Resize(ref _allSkillFamilyNames, _allSkillDefs.Length);
			for (int j = 0; j < _allSkillFamilies.Length; j++)
			{
				_allSkillFamilies[j].catalogIndex = j;
				_allSkillFamilyNames[j] = ((UnityEngine.Object)_allSkillFamilies[j]).name;
			}
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/Generic")]
	public class SkillDef : ScriptableObject
	{
		public class BaseSkillInstanceData
		{
		}

		[Tooltip("The name of the skill. This is mainly for purposes of identification in the inspector and currently has no direct effect.")]
		[Header("Skill Identifier")]
		public string skillName = "";

		[Tooltip("The language token with the name of this skill.")]
		[Header("User-Facing Info")]
		public string skillNameToken = "";

		[Tooltip("The language token with the description of this skill.")]
		public string skillDescriptionToken = "";

		[Tooltip("Extra tooltips when hovered over in character select. Currently only used in that area!")]
		public string[] keywordTokens;

		[Tooltip("The icon to display for this skill.")]
		[ShowThumbnail]
		public Sprite icon;

		[Header("State Machine Parameters")]
		[Tooltip("The state machine this skill operates upon.")]
		public string activationStateMachineName;

		[Tooltip("The state to enter when this skill is activated.")]
		public SerializableEntityStateType activationState;

		[Tooltip("The priority of this skill.")]
		public InterruptPriority interruptPriority = InterruptPriority.Skill;

		[Tooltip("How long it takes for this skill to recharge after being used.")]
		[Header("Stock and Cooldown")]
		public float baseRechargeInterval = 1f;

		[Tooltip("Maximum number of charges this skill can carry.")]
		public int baseMaxStock = 1;

		[Tooltip("How much stock to restore on a recharge.")]
		public int rechargeStock = 1;

		[Tooltip("How much stock is required to activate this skill.")]
		public int requiredStock = 1;

		[Tooltip("How much stock to deduct when the skill is activated.")]
		public int stockToConsume = 1;

		[Tooltip("Makes the skill restock interval divided by attack speed if checked.")]
		public bool attackSpeedBuffsRestockSpeed;

		[Tooltip("Increases the efficacy of attack speed on restock time.")]
		[Range(1f, 10f)]
		public float attackSpeedBuffsRestockSpeed_Multiplier = 1f;

		[Tooltip("Whether or not it resets any progress on cooldowns.")]
		[Header("Optional Parameters, Stock")]
		[FormerlySerializedAs("isBullets")]
		public bool resetCooldownTimerOnUse;

		[Tooltip("Whether or not to fully restock this skill when it's assigned.")]
		public bool fullRestockOnAssign = true;

		[Tooltip("Whether or not this skill can hold past it's maximum stock.")]
		public bool dontAllowPastMaxStocks;

		[Tooltip("Whether or not the cooldown waits until it leaves the set state")]
		public bool beginSkillCooldownOnSkillEnd;

		[Tooltip("Whether or not activating the skill forces off sprinting.")]
		[FormerlySerializedAs("noSprint")]
		[Header("Optional Parameters, Sprinting")]
		public bool cancelSprintingOnActivation = true;

		[FormerlySerializedAs("mobilitySkill")]
		[Tooltip("Whether or not this skill is considered 'mobility'. Currently just forces sprint.")]
		public bool forceSprintDuringState;

		[Tooltip("Whether or not sprinting sets the skill's state to be reset.")]
		public bool canceledFromSprinting;

		[Header("Optional Parameters, Misc")]
		[Tooltip("Whether or not this is considered a combat skill.")]
		public bool isCombatSkill = true;

		[Tooltip("The skill can't be activated if the key is held.")]
		public bool mustKeyPress;

		[Tooltip("If true, CharacterBody handles LuminiousShot buffs. If false, the skill must handle it.")]
		public bool autoHandleLuminousShot = true;

		[Tooltip("If true, the SkillIcon will not show this skill's stock count.")]
		public bool hideStockCount;

		[Obsolete("Accessing UnityEngine.Object.Name causes allocations on read. Look up the name from the catalog instead. If absolutely necessary to perform direct access, cast to ScriptableObject first.")]
		public new string name => null;

		public int skillIndex { get; set; }

		public virtual BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return null;
		}

		public virtual void OnUnassigned([NotNull] GenericSkill skillSlot)
		{
		}

		public virtual Sprite GetCurrentIcon([NotNull] GenericSkill skillSlot)
		{
			return icon;
		}

		public virtual string GetCurrentNameToken([NotNull] GenericSkill skillSlot)
		{
			return skillNameToken;
		}

		public virtual string GetCurrentDescriptionToken([NotNull] GenericSkill skillSlot)
		{
			return skillDescriptionToken;
		}

		protected bool HasRequiredStockAndDelay([NotNull] GenericSkill skillSlot)
		{
			return skillSlot.stock >= requiredStock;
		}

		public virtual bool CanExecute([NotNull] GenericSkill skillSlot)
		{
			if (HasRequiredStockAndDelay(skillSlot) && IsReady(skillSlot) && (bool)skillSlot.stateMachine && !skillSlot.stateMachine.HasPendingState())
			{
				return skillSlot.stateMachine.CanInterruptState(interruptPriority);
			}
			return false;
		}

		public virtual bool IsReady([NotNull] GenericSkill skillSlot)
		{
			return HasRequiredStockAndDelay(skillSlot);
		}

		protected virtual EntityState InstantiateNextState([NotNull] GenericSkill skillSlot)
		{
			EntityState entityState = EntityStateCatalog.InstantiateState(ref activationState);
			if (entityState is ISkillState skillState)
			{
				skillState.activatorSkillSlot = skillSlot;
			}
			return entityState;
		}

		public virtual void OnExecute([NotNull] GenericSkill skillSlot)
		{
			skillSlot.stateMachine.SetInterruptState(InstantiateNextState(skillSlot), interruptPriority);
			if (cancelSprintingOnActivation)
			{
				skillSlot.characterBody.isSprinting = false;
			}
			skillSlot.stock -= stockToConsume;
			if (resetCooldownTimerOnUse)
			{
				skillSlot.rechargeStopwatch = 0f;
			}
			if ((bool)skillSlot.characterBody)
			{
				skillSlot.characterBody.OnSkillActivated(skillSlot);
			}
		}

		public virtual void OnFixedUpdate([NotNull] GenericSkill skillSlot, float deltaTime)
		{
			skillSlot.RunRecharge(deltaTime);
			if (((canceledFromSprinting && skillSlot.characterBody.isSprinting) || forceSprintDuringState) && skillSlot.stateMachine.state.GetType() == activationState.stateType)
			{
				if (canceledFromSprinting && skillSlot.characterBody.isSprinting)
				{
					skillSlot.stateMachine.SetNextStateToMain();
				}
				if (forceSprintDuringState)
				{
					skillSlot.characterBody.isSprinting = true;
				}
			}
		}

		public bool IsAlreadyInState([NotNull] GenericSkill skillSlot)
		{
			return skillSlot?.stateMachine.state.GetType() == activationState.stateType;
		}

		public virtual int GetMaxStock([NotNull] GenericSkill skillSlot)
		{
			return baseMaxStock;
		}

		public virtual int GetRechargeStock([NotNull] GenericSkill skillSlot)
		{
			return rechargeStock;
		}

		public virtual float GetRechargeInterval([NotNull] GenericSkill skillSlot)
		{
			if (attackSpeedBuffsRestockSpeed)
			{
				float num = skillSlot.characterBody.attackSpeed - skillSlot.characterBody.baseAttackSpeed;
				num *= attackSpeedBuffsRestockSpeed_Multiplier;
				num += 1f;
				if (num < 0.5f)
				{
					num = 0.5f;
				}
				return baseRechargeInterval / num;
			}
			return baseRechargeInterval;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillFamily")]
	public class SkillFamily : ScriptableObject
	{
		[Serializable]
		public struct Variant
		{
			public SkillDef skillDef;

			[Obsolete("Use 'unlockableDef' instead.")]
			public string unlockableName;

			public UnlockableDef unlockableDef;

			public ViewablesCatalog.Node viewableNode { get; set; }
		}

		[FormerlySerializedAs("Entries")]
		public Variant[] variants = Array.Empty<Variant>();

		[FormerlySerializedAs("defaultEntryIndex")]
		public uint defaultVariantIndex;

		[Obsolete("Accessing UnityEngine.Object.Name causes allocations on read. Look up the name from the catalog instead. If absolutely necessary to perform direct access, cast to ScriptableObject first.")]
		public new string name => null;

		public int catalogIndex { get; set; }

		public SkillDef defaultSkillDef => variants[defaultVariantIndex].skillDef;

		public void OnValidate()
		{
			string text = base.name;
			if (variants == null)
			{
				UnityEngine.Debug.LogError("Skill Family \"" + text + "\" Has no Variants");
			}
			else if (defaultVariantIndex >= variants.Length)
			{
				UnityEngine.Debug.LogError($"Skill Family \"{text}\" defaultVariantIndex ({defaultVariantIndex}) is outside the bounds of the variants array ({variants.Length}).");
			}
		}

		public string GetVariantName(int variantIndex)
		{
			return SkillCatalog.GetSkillName(variants[variantIndex].skillDef.skillIndex);
		}

		public int GetVariantIndex(string variantName)
		{
			for (int i = 0; i < variants.Length; i++)
			{
				if (GetVariantName(i).Equals(variantName, StringComparison.Ordinal))
				{
					return i;
				}
			}
			return -1;
		}

		[ContextMenu("Upgrade unlockableName to unlockableDef")]
		public void UpgradeUnlockableNameToUnlockableDef()
		{
			for (int i = 0; i < variants.Length; i++)
			{
				ref Variant reference = ref variants[i];
				if (!string.IsNullOrEmpty(reference.unlockableName) && !reference.unlockableDef)
				{
					UnlockableDef unlockableDef = LegacyResourcesAPI.Load<UnlockableDef>("UnlockableDefs/" + reference.unlockableName);
					if ((bool)unlockableDef)
					{
						reference.unlockableDef = unlockableDef;
						reference.unlockableName = null;
					}
				}
			}
			EditorUtil.SetDirty(this);
		}
	}
	public class SteppedSkillDef : SkillDef
	{
		public class InstanceData : BaseSkillInstanceData
		{
			public int step;
		}

		public interface IStepSetter
		{
			void SetStep(int i);
		}

		public int stepCount = 2;

		[Tooltip("The amount of time a step is 'held' before it resets. Only begins to count down when available to execute.")]
		public float stepGraceDuration = 0.1f;

		private float stepResetTimer;

		public override BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return new InstanceData();
		}

		protected override EntityState InstantiateNextState([NotNull] GenericSkill skillSlot)
		{
			EntityState entityState = base.InstantiateNextState(skillSlot);
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if (entityState is IStepSetter stepSetter)
			{
				stepSetter.SetStep(instanceData.step);
			}
			return entityState;
		}

		public override void OnExecute([NotNull] GenericSkill skillSlot)
		{
			base.OnExecute(skillSlot);
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			instanceData.step++;
			if (instanceData.step >= stepCount)
			{
				instanceData.step = 0;
			}
		}

		public override void OnFixedUpdate([NotNull] GenericSkill skillSlot, float deltaTime)
		{
			base.OnFixedUpdate(skillSlot, deltaTime);
			if (skillSlot.CanExecute())
			{
				stepResetTimer += deltaTime;
			}
			else
			{
				stepResetTimer = 0f;
			}
			if (stepResetTimer > stepGraceDuration)
			{
				((InstanceData)skillSlot.skillInstanceData).step = 0;
			}
		}
	}
	public class ToolbotWeaponSkillDef : SkillDef
	{
		public string stanceName;

		public string entrySound;

		public string entryAnimState;

		public string enterGestureAnimState;

		public string exitAnimState;

		public string exitGestureAnimState;

		public int animatorWeaponIndex;

		public GameObject crosshairPrefab;

		public AnimationCurve crosshairSpreadCurve;
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/VoidRaidCrabBodySkillDef")]
	public class VoidRaidCrabBodySkillDef : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			public EntityStateMachine weaponStateMachine;
		}

		private const string weaponStateMachineName = "Weapon";

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			return new InstanceData
			{
				weaponStateMachine = EntityStateMachine.FindByCustomName(skillSlot.gameObject, "Weapon")
			};
		}

		public override bool IsReady([NotNull] GenericSkill skillSlot)
		{
			if (base.IsReady(skillSlot))
			{
				return !IsWeaponBusy(skillSlot);
			}
			return false;
		}

		private bool IsWeaponBusy([NotNull] GenericSkill skillSlot)
		{
			if (skillSlot.skillInstanceData is InstanceData instanceData && (bool)instanceData.weaponStateMachine)
			{
				return !instanceData.weaponStateMachine.IsInMainState();
			}
			return false;
		}
	}
	[CreateAssetMenu(menuName = "RoR2/SkillDef/VoidRaidCrabWeaponSkillDef")]
	public class VoidRaidCrabWeaponSkillDef : SkillDef
	{
		private class InstanceData : BaseSkillInstanceData
		{
			public EntityStateMachine bodyStateMachine;

			public EntityStateMachine weaponStateMachine;
		}

		private const string bodyStateMachineName = "Body";

		private const string weaponStateMachineName = "Weapon";

		public override BaseSkillInstanceData OnAssigned(GenericSkill skillSlot)
		{
			return new InstanceData
			{
				bodyStateMachine = EntityStateMachine.FindByCustomName(skillSlot.gameObject, "Body"),
				weaponStateMachine = EntityStateMachine.FindByCustomName(skillSlot.gameObject, "Weapon")
			};
		}

		public override bool IsReady([NotNull] GenericSkill skillSlot)
		{
			if (base.IsReady(skillSlot) && CanReceiveInput(skillSlot))
			{
				return !IsWeaponBusy(skillSlot);
			}
			return false;
		}

		private bool CanReceiveInput([NotNull] GenericSkill skillSlot)
		{
			if (skillSlot.skillInstanceData is InstanceData instanceData && (bool)instanceData.bodyStateMachine)
			{
				return instanceData.bodyStateMachine.state is GenericCharacterMain;
			}
			return false;
		}

		private bool IsWeaponBusy([NotNull] GenericSkill skillSlot)
		{
			if (skillSlot.skillInstanceData is InstanceData instanceData && (bool)instanceData.weaponStateMachine)
			{
				return !instanceData.weaponStateMachine.IsInMainState();
			}
			return false;
		}
	}
	public class VoidSurvivorBlasterSkillDef : SteppedSkillDef
	{
		public Sprite[] icons;

		protected override EntityState InstantiateNextState([NotNull] GenericSkill skillSlot)
		{
			EntityState entityState = base.InstantiateNextState(skillSlot);
			VoidSurvivorController component = skillSlot.GetComponent<VoidSurvivorController>();
			if ((bool)component)
			{
				float corruptionPercentage = component.corruptionPercentage;
				entityState = ((corruptionPercentage >= 75f) ? new FireBlaster4() : ((corruptionPercentage >= 50f) ? new FireBlaster3() : ((!(corruptionPercentage >= 25f)) ? ((FireBlasterBase)new FireBlaster1()) : ((FireBlasterBase)new FireBlaster2()))));
			}
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if (entityState is IStepSetter stepSetter)
			{
				stepSetter.SetStep(instanceData.step);
			}
			return entityState;
		}
	}
	public class VoidSurvivorSkillDef : SkillDef
	{
		protected class InstanceData : BaseSkillInstanceData
		{
			public VoidSurvivorController voidSurvivorController;
		}

		public float minimumCorruption;

		public float maximumCorruption;

		public override BaseSkillInstanceData OnAssigned([NotNull] GenericSkill skillSlot)
		{
			return new InstanceData
			{
				voidSurvivorController = skillSlot.GetComponent<VoidSurvivorController>()
			};
		}

		public override bool IsReady([NotNull] GenericSkill skillSlot)
		{
			if (base.IsReady(skillSlot))
			{
				return HasRequiredCorruption(skillSlot);
			}
			return false;
		}

		public bool HasRequiredCorruption([NotNull] GenericSkill skillSlot)
		{
			InstanceData instanceData = (InstanceData)skillSlot.skillInstanceData;
			if ((bool)instanceData.voidSurvivorController && instanceData.voidSurvivorController.corruption >= minimumCorruption && instanceData.voidSurvivorController.corruption < maximumCorruption)
			{
				return true;
			}
			return false;
		}
	}
}
namespace RoR2.Achievements
{
	[RegisterAchievement("AttackSpeed", "Items.AttackSpeedOnCrit", null, 2u, null)]
	public class AttackSpeedAchievement : BaseAchievement
	{
		private const float requirement = 3f;

		public override void OnInstall()
		{
			base.OnInstall();
			RoR2Application.onUpdate += CheckAttackSpeed;
		}

		public override void OnUninstall()
		{
			RoR2Application.onUpdate -= CheckAttackSpeed;
			base.OnUninstall();
		}

		public void CheckAttackSpeed()
		{
			if (base.localUser != null && (bool)base.localUser.cachedBody && base.localUser.cachedBody.attackSpeed >= 3f)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("AutomationActivation", "Items.Squid", null, 2u, typeof(AutomationActivation))]
	public class AutomationActivation : BaseAchievement
	{
		private static readonly ulong requirement = 6uL;

		private static StatDef statDef => StatDef.totalTurretsPurchased;

		public override void OnInstall()
		{
			base.OnInstall();
			owner.onRunStatsUpdated += OnRunStatsUpdated;
		}

		public override void OnUninstall()
		{
			owner.onRunStatsUpdated -= OnRunStatsUpdated;
			base.OnUninstall();
		}

		private void OnRunStatsUpdated([NotNull] StatSheet runStatSheet)
		{
			if (runStatSheet.GetStatValueULong(statDef) >= requirement)
			{
				Grant();
			}
		}
	}
	public abstract class BaseAchievement
	{
		public UserAchievementManager owner;

		public bool shouldGrant;

		public bool shouldUpdateProgress;

		public AchievementDef achievementDef;

		private bool _meetsBodyRequirement;

		protected LocalUser localUser { get; private set; }

		protected UserProfile userProfile { get; private set; }

		protected bool isUserAlive
		{
			get
			{
				if (localUser != null && (bool)localUser.cachedBody && (bool)localUser.cachedBody.healthComponent)
				{
					return localUser.cachedBody.healthComponent.alive;
				}
				return false;
			}
		}

		protected BodyIndex requiredBodyIndex { get; private set; } = BodyIndex.None;


		protected bool meetsBodyRequirement
		{
			get
			{
				return _meetsBodyRequirement;
			}
			set
			{
				if (_meetsBodyRequirement != value)
				{
					_meetsBodyRequirement = value;
					if (_meetsBodyRequirement)
					{
						OnBodyRequirementMet();
					}
					else
					{
						OnBodyRequirementBroken();
					}
				}
			}
		}

		protected virtual bool wantsBodyCallbacks { get; }

		public virtual void OnInstall()
		{
			localUser = owner.localUser;
			userProfile = owner.userProfile;
			requiredBodyIndex = LookUpRequiredBodyIndex();
			if (requiredBodyIndex != BodyIndex.None)
			{
				localUser.onBodyChanged += HandleBodyChangedForBodyRequirement;
				Run.onRunDestroyGlobal += SetBodyRequirementBrokenOnRunEnd;
			}
		}

		public virtual bool IsProgressiveAchievement()
		{
			return false;
		}

		public virtual float ProgressForAchievement()
		{
			return 0f;
		}

		public virtual ulong GetCurrentProgress()
		{
			return 0uL;
		}

		public virtual ulong GetProgressRequirement()
		{
			return 100uL;
		}

		public virtual void OnUninstall()
		{
			if (achievementDef.serverTrackerType != null)
			{
				SetServerTracked(shouldTrack: false);
			}
			if (requiredBodyIndex != BodyIndex.None)
			{
				Run.onRunDestroyGlobal -= SetBodyRequirementBrokenOnRunEnd;
				localUser.onBodyChanged -= HandleBodyChangedForBodyRequirement;
				meetsBodyRequirement = false;
			}
			owner = null;
			localUser = null;
			userProfile = null;
		}

		public void Grant()
		{
			if (shouldGrant)
			{
				return;
			}
			UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(achievementDef.unlockableRewardIdentifier);
			if ((bool)unlockableDef)
			{
				ExpansionDef expansionDefForUnlockable = UnlockableCatalog.GetExpansionDefForUnlockable(unlockableDef.index);
				if ((bool)expansionDefForUnlockable && (bool)expansionDefForUnlockable.requiredEntitlement && !EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(expansionDefForUnlockable.requiredEntitlement))
				{
					return;
				}
			}
			if (!localUser.currentNetworkUser || localUser.currentNetworkUser.isParticipating)
			{
				shouldGrant = true;
				owner.dirtyGrantsCount++;
			}
		}

		public virtual void OnGranted()
		{
			if (!string.IsNullOrEmpty(achievementDef.unlockableRewardIdentifier))
			{
				if ((bool)localUser.currentNetworkUser)
				{
					UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(achievementDef.unlockableRewardIdentifier);
					localUser.currentNetworkUser.CallCmdReportUnlock(unlockableDef.index);
				}
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				string[] childAchievementIdentifiers = achievementDef.childAchievementIdentifiers;
				foreach (string activityAchievementID in childAchievementIdentifiers)
				{
					baseActivitySelector.activityAchievementID = activityAchievementID;
					PlatformSystems.activityManager.TryToSetActivityAvailability(baseActivitySelector, newAvailability: true);
				}
				userProfile.AddUnlockToken(achievementDef.unlockableRewardIdentifier);
			}
			if (achievementDef.lunarCoinReward != 0 && (bool)localUser.currentNetworkUser)
			{
				localUser.currentNetworkUser.CallCmdAwardLunarCoins(achievementDef.lunarCoinReward);
			}
		}

		public void UpdateProgress()
		{
		}

		public virtual void TryToCompleteActivity()
		{
		}

		public void SetServerTracked(bool shouldTrack)
		{
			owner.SetServerAchievementTracked(achievementDef.serverIndex, shouldTrack);
		}

		protected virtual BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyIndex.None;
		}

		private void HandleBodyChangedForBodyRequirement()
		{
			bool num = localUser.cachedBody;
			bool flag = meetsBodyRequirement;
			if (num)
			{
				flag = localUser.cachedBody.bodyIndex == requiredBodyIndex;
			}
			meetsBodyRequirement = flag;
		}

		protected virtual void OnBodyRequirementMet()
		{
		}

		protected virtual void OnBodyRequirementBroken()
		{
		}

		private void SetBodyRequirementBrokenOnRunEnd(Run run)
		{
			meetsBodyRequirement = false;
		}
	}
	public class BaseServerAchievement
	{
		public ServerAchievementTracker serverAchievementTracker;

		public AchievementDef achievementDef;

		public NetworkUser networkUser => serverAchievementTracker.networkUser;

		protected CharacterBody GetCurrentBody()
		{
			return networkUser.GetCurrentBody();
		}

		protected bool IsCurrentBody(GameObject gameObject)
		{
			CharacterBody currentBody = GetCurrentBody();
			if ((bool)currentBody)
			{
				return (object)currentBody.gameObject == gameObject;
			}
			return false;
		}

		protected bool IsCurrentBody(CharacterBody characterBody)
		{
			CharacterBody currentBody = GetCurrentBody();
			if ((bool)currentBody)
			{
				return (object)currentBody == characterBody;
			}
			return false;
		}

		public virtual void OnInstall()
		{
		}

		public virtual void OnUninstall()
		{
		}

		protected void Grant()
		{
			UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(achievementDef.unlockableRewardIdentifier);
			if ((bool)unlockableDef)
			{
				ExpansionDef expansionDefForUnlockable = UnlockableCatalog.GetExpansionDefForUnlockable(unlockableDef.index);
				if ((bool)expansionDefForUnlockable && (bool)expansionDefForUnlockable.requiredEntitlement && !EntitlementManager.networkUserEntitlementTracker.UserHasEntitlement(networkUser, expansionDefForUnlockable.requiredEntitlement))
				{
					return;
				}
			}
			serverAchievementTracker.CallRpcGrantAchievement(achievementDef.serverIndex);
		}

		protected void ServerTryToCompleteActivity()
		{
			serverAchievementTracker.CallRpcTryToCompleteActivity(achievementDef.serverIndex);
		}

		public static BaseServerAchievement Instantiate(ServerAchievementIndex serverAchievementIndex)
		{
			AchievementDef achievementDef = AchievementManager.GetAchievementDef(serverAchievementIndex);
			if (achievementDef == null || achievementDef.serverTrackerType == null)
			{
				return null;
			}
			BaseServerAchievement obj = (BaseServerAchievement)Activator.CreateInstance(achievementDef.serverTrackerType);
			obj.achievementDef = achievementDef;
			return obj;
		}
	}
	public class BasePerSurvivorClearGameMonsoonAchievement : BaseAchievement
	{
		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			Run.onClientGameOverGlobal += OnClientGameOverGlobal;
		}

		protected override void OnBodyRequirementBroken()
		{
			Run.onClientGameOverGlobal -= OnClientGameOverGlobal;
			base.OnBodyRequirementBroken();
		}

		private void OnClientGameOverGlobal(Run run, RunReport runReport)
		{
			if ((bool)runReport.gameEnding && runReport.gameEnding.isWin)
			{
				DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(runReport.ruleBook.FindDifficulty());
				if (difficultyDef != null && difficultyDef.countsAsHardMode)
				{
					Grant();
				}
			}
		}
	}
	public abstract class BaseStatMilestoneAchievement : BaseAchievement
	{
		protected abstract StatDef statDef { get; }

		protected abstract ulong statRequirement { get; }

		private ulong statProgress => base.userProfile.statSheet.GetStatValueULong(statDef);

		public override void OnInstall()
		{
			base.OnInstall();
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(Check));
			if (IsProgressiveAchievement())
			{
				StatDef obj2 = statDef;
				obj2.onChangeCallback = (Action)Delegate.Combine(obj2.onChangeCallback, new Action(base.UpdateProgress));
			}
			Check();
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(Check));
			if (IsProgressiveAchievement())
			{
				StatDef obj2 = statDef;
				obj2.onChangeCallback = (Action)Delegate.Remove(obj2.onChangeCallback, new Action(base.UpdateProgress));
			}
			base.OnUninstall();
		}

		public override float ProgressForAchievement()
		{
			return (float)statProgress / (float)statRequirement;
		}

		public override ulong GetCurrentProgress()
		{
			return statProgress;
		}

		public override ulong GetProgressRequirement()
		{
			return statRequirement;
		}

		private void Check()
		{
			if (statProgress >= statRequirement)
			{
				Grant();
				TryToCompleteActivity();
			}
		}
	}
	[RegisterAchievement("BeatArena", "Characters.Croco", null, 3u, typeof(BeatArenaServerAchievement))]
	public class BeatArenaAchievement : BaseAchievement
	{
		private class BeatArenaServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				ArenaMissionController.onBeatArena += OnBeatArena;
			}

			public override void OnUninstall()
			{
				ArenaMissionController.onBeatArena -= OnBeatArena;
				base.OnInstall();
			}

			private void OnBeatArena()
			{
				Grant();
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("BurnToDeath", "Items.Cleanse", null, 2u, null)]
	public class BurnToDeathAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalDeathsWhileBurning;

		protected override ulong statRequirement => 3uL;
	}
	[RegisterAchievement("CaptainBuyMegaDrone", "Skills.Captain.CaptainSupplyDropHacking", "CompleteMainEnding", 3u, typeof(CaptainBuyMegaDroneServerAchievement))]
	public class CaptainBuyMegaDroneAchievement : BaseAchievement
	{
		private class CaptainBuyMegaDroneServerAchievement : BaseServerAchievement
		{
			private GameObject megaDroneMasterPrefab;

			public override void OnInstall()
			{
				base.OnInstall();
				megaDroneMasterPrefab = MasterCatalog.FindMasterPrefab("MegaDroneMaster");
				GlobalEventManager.OnInteractionsGlobal += OnInteractionsGlobal;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.OnInteractionsGlobal -= OnInteractionsGlobal;
				megaDroneMasterPrefab = null;
				base.OnUninstall();
			}

			private void OnInteractionsGlobal(Interactor interactor, IInteractable interactable, GameObject interactableObject)
			{
				if (IsCurrentBody(interactor.gameObject) && interactableObject.GetComponent<SummonMasterBehavior>()?.masterPrefab == megaDroneMasterPrefab)
				{
					Grant();
				}
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CaptainBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("CaptainVisitSeveralStages", "Skills.Captain.CaptainSupplyDropEquipmentRestock", "CompleteMainEnding", 3u, null)]
	public class CaptainVisitSeveralStagesAchievement : BaseAchievement
	{
		private static readonly int requirement = 10;

		private List<SceneDef> visitedScenes;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CaptainBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			visitedScenes = CollectionPool<SceneDef, List<SceneDef>>.RentCollection();
			SceneCatalog.onMostRecentSceneDefChanged += HandleMostRecentSceneDefChanged;
		}

		protected override void OnBodyRequirementBroken()
		{
			SceneCatalog.onMostRecentSceneDefChanged -= HandleMostRecentSceneDefChanged;
			visitedScenes = CollectionPool<SceneDef, List<SceneDef>>.ReturnCollection(visitedScenes);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "CaptainVisitSeveralStages";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}

		private void HandleMostRecentSceneDefChanged(SceneDef newSceneDef)
		{
			if (!visitedScenes.Contains(newSceneDef))
			{
				visitedScenes.Add(newSceneDef);
			}
			if (visitedScenes.Count >= requirement)
			{
				Grant();
				TryToCompleteActivity();
			}
		}
	}
	[RegisterAchievement("CarryLunarItems", "Items.Meteor", null, 2u, null)]
	public class CarryLunarItemsAchievement : BaseAchievement
	{
		public const int requirement = 5;

		private PlayerCharacterMasterController currentMasterController;

		private Inventory currentInventory;

		public override void OnInstall()
		{
			base.OnInstall();
			base.localUser.onMasterChanged += OnMasterChanged;
			SetMasterController(base.localUser.cachedMasterController);
		}

		public override void OnUninstall()
		{
			SetMasterController(null);
			base.localUser.onMasterChanged -= OnMasterChanged;
			base.OnUninstall();
		}

		private void SetMasterController(PlayerCharacterMasterController newMasterController)
		{
			if ((object)currentMasterController != newMasterController)
			{
				if ((object)currentInventory != null)
				{
					currentInventory.onInventoryChanged -= OnInventoryChanged;
				}
				currentMasterController = newMasterController;
				currentInventory = currentMasterController?.master?.inventory;
				if ((object)currentInventory != null)
				{
					currentInventory.onInventoryChanged += OnInventoryChanged;
				}
			}
		}

		private void OnInventoryChanged()
		{
			if ((bool)currentInventory)
			{
				int num = 5;
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(currentInventory.currentEquipmentIndex);
				if (equipmentDef != null && equipmentDef.isLunar)
				{
					num--;
				}
				EquipmentDef equipmentDef2 = EquipmentCatalog.GetEquipmentDef(currentInventory.alternateEquipmentIndex);
				if (equipmentDef2 != null && equipmentDef2.isLunar)
				{
					num--;
				}
				if (currentInventory.HasAtLeastXTotalItemsOfTier(ItemTier.Lunar, num))
				{
					Grant();
				}
			}
		}

		private void OnMasterChanged()
		{
			SetMasterController(base.localUser.cachedMasterController);
		}
	}
	[RegisterAchievement("ChargeTeleporterWhileNearDeath", "Items.WarCryOnMultiKill", null, 2u, null)]
	public class ChargeTeleporterWhileNearDeathAchievement : BaseAchievement
	{
		private const float requirement = 0.1f;

		public override void OnInstall()
		{
			base.OnInstall();
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged;
		}

		public override void OnUninstall()
		{
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged;
			base.OnUninstall();
		}

		private void OnTeleporterCharged(TeleporterInteraction teleporterInteraction)
		{
			Check();
		}

		private void Check()
		{
			if ((bool)base.localUser.cachedBody && (bool)base.localUser.cachedBody.healthComponent && base.localUser.cachedBody.healthComponent.alive && base.localUser.cachedBody.healthComponent.combinedHealthFraction <= 0.1f)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("CleanupDuty", "Items.Recycle", null, 2u, null)]
	public class CleanupDuty : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalMaulingRockKills;

		protected override ulong statRequirement => 20uL;
	}
	[RegisterAchievement("Complete20Stages", "Items.Clover", null, 3u, null)]
	public class Complete20StagesAchievement : BaseAchievement
	{
		private const int requirement = 20;

		private bool listeningForStats;

		private UserProfile subscribedProfile;

		private MemoizedGetComponent<PlayerStatsComponent> playerStatsComponentGetter;

		public override void OnInstall()
		{
			base.OnInstall();
			Run.onRunStartGlobal += OnRunStart;
		}

		public override void OnUninstall()
		{
			Run.onRunStartGlobal -= OnRunStart;
			SetListeningForStats(shouldListen: false);
			base.OnUninstall();
		}

		private void OnRunStart(Run run)
		{
			SetListeningForStats(shouldListen: true);
		}

		private void SetListeningForStats(bool shouldListen)
		{
			if (listeningForStats != shouldListen)
			{
				listeningForStats = shouldListen;
				if (listeningForStats)
				{
					subscribedProfile = base.localUser.userProfile;
					UserProfile obj = subscribedProfile;
					obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(OnStatsReceived));
				}
				else
				{
					UserProfile obj2 = subscribedProfile;
					obj2.onStatsReceived = (Action)Delegate.Remove(obj2.onStatsReceived, new Action(OnStatsReceived));
					subscribedProfile = null;
				}
			}
		}

		private void OnStatsReceived()
		{
			PlayerStatsComponent playerStatsComponent = playerStatsComponentGetter.Get(base.localUser.cachedMasterObject);
			if ((bool)playerStatsComponent && playerStatsComponent.currentStats.GetStatValueULong(StatDef.highestStagesCompleted) >= 20)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("Complete30StagesCareer", "Characters.Engineer", null, 3u, null)]
	public class Complete30StagesCareerAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalStagesCompleted;

		protected override ulong statRequirement => 30uL;
	}
	[RegisterAchievement("CompleteMultiBossShrine", "Items.Lightning", null, 2u, typeof(CompleteMultiBossShrineServerAchievement))]
	public class CompleteMultiBossShrineAchievement : BaseAchievement
	{
		private class CompleteMultiBossShrineServerAchievement : BaseServerAchievement
		{
			private const int requirement = 2;

			public override void OnInstall()
			{
				base.OnInstall();
				BossGroup.onBossGroupDefeatedServer += OnBossGroupDefeatedServer;
			}

			public override void OnUninstall()
			{
				BossGroup.onBossGroupDefeatedServer -= OnBossGroupDefeatedServer;
				base.OnUninstall();
			}

			private void OnBossGroupDefeatedServer(BossGroup bossGroup)
			{
				CharacterBody currentBody = GetCurrentBody();
				if ((bool)currentBody && (bool)currentBody.healthComponent && currentBody.healthComponent.alive && (bool)TeleporterInteraction.instance && CheckTeleporter(bossGroup, TeleporterInteraction.instance))
				{
					Grant();
				}
			}

			private bool CheckTeleporter(BossGroup bossGroup, TeleporterInteraction teleporterInteraction)
			{
				if (teleporterInteraction.bossDirector.combatSquad == bossGroup.combatSquad)
				{
					return teleporterInteraction.shrineBonusStacks >= 2;
				}
				return false;
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("CompleteTeleporter", "Items.BossDamageBonus", null, 1u, typeof(CompleteTeleporterServerAchievement))]
	public class CompleteTeleporterAchievement : BaseAchievement
	{
		private class CompleteTeleporterServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SceneExitController.onBeginExit += OnSceneBeginExit;
				SceneExitControllerColossusPortal.onBeginExit += OnSceneColossusExit;
			}

			public override void OnUninstall()
			{
				SceneExitController.onBeginExit -= OnSceneBeginExit;
				SceneExitControllerColossusPortal.onBeginExit -= OnSceneColossusExit;
				base.OnInstall();
			}

			private void OnSceneBeginExit(SceneExitController exitController)
			{
				if (exitController.portalUsedAfterTeleporterEventFinish)
				{
					Check();
				}
			}

			private void OnSceneColossusExit(SceneExitControllerColossusPortal exitColossusController)
			{
				Check();
			}

			private void Check()
			{
				CharacterBody currentBody = GetCurrentBody();
				if ((bool)currentBody && (bool)currentBody.healthComponent && currentBody.healthComponent.alive)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			SetServerTracked(shouldTrack: false);
			base.OnUninstall();
		}
	}
	[RegisterAchievement("CompleteTeleporterWithoutInjury", "Items.SecondarySkillMagazine", null, 1u, null)]
	public class CompleteTeleporterWithoutInjuryAchievement : BaseAchievement
	{
		private bool hasBeenHit;

		public override void OnInstall()
		{
			base.OnInstall();
			TeleporterInteraction.onTeleporterBeginChargingGlobal += OnTeleporterBeginCharging;
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged;
			GlobalEventManager.onClientDamageNotified += OnClientDamageNotified;
		}

		public override void OnUninstall()
		{
			TeleporterInteraction.onTeleporterBeginChargingGlobal -= OnTeleporterBeginCharging;
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged;
			GlobalEventManager.onClientDamageNotified -= OnClientDamageNotified;
			base.OnUninstall();
		}

		private void OnTeleporterBeginCharging(TeleporterInteraction teleporterInteraction)
		{
			hasBeenHit = false;
		}

		private void OnTeleporterCharged(TeleporterInteraction teleporterInteraction)
		{
			Check();
		}

		private void OnClientDamageNotified(DamageDealtMessage damageDealtMessage)
		{
			if (!hasBeenHit && (bool)damageDealtMessage.victim && damageDealtMessage.victim == base.localUser.cachedBodyObject)
			{
				hasBeenHit = true;
			}
		}

		private void Check()
		{
			if ((bool)base.localUser.cachedBody && (bool)base.localUser.cachedBody.healthComponent && base.localUser.cachedBody.healthComponent.alive && !hasBeenHit)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("CompleteThreeStages", "Characters.Bandit2", null, 3u, null)]
	public class CompleteThreeStagesAchievement : BaseAchievement
	{
		private const int requirement = 3;

		public override void OnInstall()
		{
			base.OnInstall();
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged;
		}

		public override void OnUninstall()
		{
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged;
			base.OnUninstall();
		}

		private void OnTeleporterCharged(TeleporterInteraction teleporterInteraction)
		{
			Check();
		}

		private void Check()
		{
			if ((bool)Run.instance && Run.instance.GetType() == typeof(Run))
			{
				SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene();
				if (!(sceneDefForCurrentScene == null) && base.localUser.currentNetworkUser.masterPlayerStatsComponent.currentStats.GetStatValueULong(StatDef.totalDeaths) == 0L && sceneDefForCurrentScene.stageOrder == 3)
				{
					Grant();
				}
			}
		}
	}
	[RegisterAchievement("CompleteThreeStagesWithoutHealing", "Items.IncreaseHealing", null, 3u, typeof(CompleteThreeStagesWithoutHealingServerAchievement))]
	public class CompleteThreeStagesWithoutHealingsAchievement : BaseAchievement
	{
		private class CompleteThreeStagesWithoutHealingServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SceneExitController.onBeginExit += OnSceneBeginExit;
			}

			public override void OnUninstall()
			{
				SceneExitController.onBeginExit -= OnSceneBeginExit;
				base.OnUninstall();
			}

			private void OnSceneBeginExit(SceneExitController exitController)
			{
				Check();
			}

			private void Check()
			{
				if (!Run.instance || !(Run.instance.GetType() == typeof(Run)) || !(serverAchievementTracker != null) || !(base.networkUser != null) || serverAchievementTracker == null || serverAchievementTracker.networkUser == null)
				{
					return;
				}
				SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene();
				if (!(base.networkUser.masterPlayerStatsComponent == null) && base.networkUser.masterPlayerStatsComponent.currentStats != null)
				{
					StatSheet currentStats = base.networkUser.masterPlayerStatsComponent.currentStats;
					CharacterBody currentBody = GetCurrentBody();
					if (sceneDefForCurrentScene != null && currentStats.GetStatValueULong(StatDef.highestStagesCompleted) >= 2 && (float)currentStats.GetStatValueULong(StatDef.totalHealthHealed) <= 0f && (bool)currentBody && (bool)currentBody.healthComponent && currentBody.healthComponent.alive)
					{
						Grant();
					}
				}
			}
		}

		private const int requirement = 2;

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			SetServerTracked(shouldTrack: false);
			base.OnUninstall();
		}
	}
	[RegisterAchievement("CompleteUnknownEnding", "Characters.Mercenary", null, 3u, typeof(CompleteUnknownEndingServerAchievement))]
	public class CompleteUnknownEndingAchievement : BaseAchievement
	{
		private class CompleteUnknownEndingServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				Run.onServerGameOver += OnServerGameOver;
			}

			public override void OnUninstall()
			{
				base.OnInstall();
				Run.onServerGameOver -= OnServerGameOver;
			}

			private void OnServerGameOver(Run run, GameEndingDef gameEndingDef)
			{
				if (gameEndingDef == RoR2Content.GameEndings.ObliterationEnding || gameEndingDef == RoR2Content.GameEndings.LimboEnding)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("DefeatFalseSon", "Items.HealAndRevive", null, 5u, typeof(DefeatFalseSonServerAchievement))]
	public class DefeatFalseSonAchievement : BaseAchievement
	{
		private class DefeatFalseSonServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnFalseSonDefeated;
			}

			public override void OnUninstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnFalseSonDefeated;
			}

			private void OnFalseSonDefeated()
			{
				Grant();
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("DefeatSuperRoboBallBoss", "Characters.Loader", null, 3u, typeof(DefeatSuperRoboBallBossServerAchievement))]
	public class DefeatSuperRoboBallBossAchievement : BaseAchievement
	{
		private class DefeatSuperRoboBallBossServerAchievement : BaseServerAchievement
		{
			private BodyIndex superRoboBallBossBodyIndex;

			public override void OnInstall()
			{
				base.OnInstall();
				superRoboBallBossBodyIndex = BodyCatalog.FindBodyIndex("SuperRoboBallBossBody");
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if (damageReport.victimBodyIndex == superRoboBallBossBodyIndex && damageReport.victimTeamIndex != TeamIndex.Player)
				{
					Grant();
				}
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				base.OnUninstall();
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("Die20Times", "Items.DeathProjectile", null, 2u, null)]
	public class Die20TimesAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalDeaths;

		protected override ulong statRequirement => 20uL;
	}
	[RegisterAchievement("Die5Times", "Items.Bear", null, 1u, null)]
	public class Die5TimesAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalDeaths;

		protected override ulong statRequirement => 5uL;
	}
	[RegisterAchievement("Discover10UniqueTier1", "Items.Crowbar", null, 1u, null)]
	public class Discover10UniqueTier1Achievement : BaseAchievement
	{
		private const int requirement = 10;

		public override void OnInstall()
		{
			base.OnInstall();
			UserProfile obj = base.userProfile;
			obj.onPickupDiscovered = (Action<PickupIndex>)Delegate.Combine(obj.onPickupDiscovered, new Action<PickupIndex>(OnPickupDiscovered));
			Check();
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onPickupDiscovered = (Action<PickupIndex>)Delegate.Remove(obj.onPickupDiscovered, new Action<PickupIndex>(OnPickupDiscovered));
			base.OnUninstall();
		}

		public override float ProgressForAchievement()
		{
			return (float)UniqueTier1Discovered() / 10f;
		}

		private void OnPickupDiscovered(PickupIndex pickupIndex)
		{
			ItemIndex itemIndex = PickupCatalog.GetPickupDef(pickupIndex)?.itemIndex ?? ItemIndex.None;
			if (itemIndex != ItemIndex.None && ItemCatalog.GetItemDef(itemIndex).tier == ItemTier.Tier1)
			{
				Check();
			}
		}

		private int UniqueTier1Discovered()
		{
			int num = 0;
			ItemIndex itemIndex = ItemIndex.Count;
			for (ItemIndex itemCount = (ItemIndex)ItemCatalog.itemCount; itemIndex < itemCount; itemIndex++)
			{
				if (ItemCatalog.GetItemDef(itemIndex).tier == ItemTier.Tier1 && base.userProfile.HasDiscoveredPickup(PickupCatalog.FindPickupIndex(itemIndex)))
				{
					num++;
				}
			}
			return num;
		}

		private void Check()
		{
			if (UniqueTier1Discovered() >= 10)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("Discover5Equipment", "Items.EquipmentMagazine", null, 2u, null)]
	public class Discover5EquipmentAchievement : BaseAchievement
	{
		private const int requirement = 5;

		public override void OnInstall()
		{
			base.OnInstall();
			UserProfile obj = base.userProfile;
			obj.onPickupDiscovered = (Action<PickupIndex>)Delegate.Combine(obj.onPickupDiscovered, new Action<PickupIndex>(OnPickupDiscovered));
			Check();
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onPickupDiscovered = (Action<PickupIndex>)Delegate.Remove(obj.onPickupDiscovered, new Action<PickupIndex>(OnPickupDiscovered));
			base.OnUninstall();
		}

		public override float ProgressForAchievement()
		{
			return (float)EquipmentDiscovered() / 5f;
		}

		private void OnPickupDiscovered(PickupIndex pickupIndex)
		{
			if ((PickupCatalog.GetPickupDef(pickupIndex)?.equipmentIndex ?? EquipmentIndex.None) != EquipmentIndex.None)
			{
				Check();
			}
		}

		private int EquipmentDiscovered()
		{
			int num = 0;
			EquipmentIndex equipmentIndex = (EquipmentIndex)0;
			for (EquipmentIndex equipmentCount = (EquipmentIndex)EquipmentCatalog.equipmentCount; equipmentIndex < equipmentCount; equipmentIndex++)
			{
				if (base.userProfile.HasDiscoveredPickup(PickupCatalog.FindPickupIndex(equipmentIndex)))
				{
					num++;
				}
			}
			return num;
		}

		private void Check()
		{
			if (EquipmentDiscovered() >= 5)
			{
				Grant();
			}
		}
	}
	public abstract class BaseEndingAchievement : BaseAchievement
	{
		protected abstract bool ShouldGrant(RunReport runReport);

		public override void OnInstall()
		{
			base.OnInstall();
			Run.onClientGameOverGlobal += OnClientGameOverGlobal;
		}

		public override void OnUninstall()
		{
			Run.onClientGameOverGlobal -= OnClientGameOverGlobal;
			base.OnUninstall();
		}

		protected virtual void OnClientGameOverGlobal(Run run, RunReport runReport)
		{
			if (ShouldGrant(runReport))
			{
				Grant();
			}
			TryToCompleteActivity();
		}
	}
	[RegisterAchievement("CompleteMainEnding", "Characters.Captain", null, 3u, null)]
	public class CompleteMainEndingAchievement : BaseEndingAchievement
	{
		protected override bool ShouldGrant(RunReport runReport)
		{
			if (runReport.gameEnding == RoR2Content.GameEndings.MainEnding)
			{
				return true;
			}
			return false;
		}

		public override void TryToCompleteActivity()
		{
			bool flag = base.localUser.id == LocalUserManager.GetFirstLocalUser().id;
			if (shouldGrant && flag)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "CompleteMainEnding";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("CompleteMainEndingHard", "Items.LunarBadLuck", null, 10u, null)]
	public class CompleteMainEndingHardAchievement : BaseEndingAchievement
	{
		protected override bool ShouldGrant(RunReport runReport)
		{
			if (runReport.gameEnding == RoR2Content.GameEndings.MainEnding && runReport.ruleBook.FindDifficulty() >= DifficultyIndex.Hard)
			{
				return true;
			}
			return false;
		}
	}
	[RegisterAchievement("CompletePrismaticTrial", "Items.HealOnCrit", null, 2u, null)]
	public class CompletePrismaticTrialAchievement : BaseEndingAchievement
	{
		protected override bool ShouldGrant(RunReport runReport)
		{
			return runReport.gameEnding == GameEndingCatalog.FindGameEndingDef("PrismaticTrialEnding");
		}

		public override void TryToCompleteActivity()
		{
			bool flag = base.localUser.id == LocalUserManager.GetFirstLocalUser().id;
			if (shouldGrant && flag)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "CompletePrismaticTrial";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("CompleteVoidEnding", "Characters.VoidSurvivor", null, 3u, typeof(CompleteWave50ServerAchievement))]
	public class CompleteVoidEndingAchievement : BaseEndingAchievement
	{
		private class CompleteWave50ServerAchievement : BaseServerAchievement
		{
			public const int waveRequirement = 50;

			public override void OnInstall()
			{
				base.OnInstall();
				InfiniteTowerRun.onAllEnemiesDefeatedServer += OnAllEnemiesDefeatedServer;
			}

			public override void OnUninstall()
			{
				InfiniteTowerRun.onAllEnemiesDefeatedServer -= OnAllEnemiesDefeatedServer;
				base.OnUninstall();
			}

			private void OnAllEnemiesDefeatedServer(InfiniteTowerWaveController waveController)
			{
				InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun;
				if ((bool)infiniteTowerRun && infiniteTowerRun.waveIndex >= 50)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			SetServerTracked(shouldTrack: false);
			base.OnUninstall();
		}

		protected override bool ShouldGrant(RunReport runReport)
		{
			if (runReport.gameEnding == DLC1Content.GameEndings.VoidEnding)
			{
				return true;
			}
			return false;
		}
	}
	[RegisterAchievement("FailShrineChance", "Items.Hoof", null, 1u, typeof(FailShrineChanceServerAchievement))]
	public class FailShrineChanceAchievement : BaseAchievement
	{
		private class FailShrineChanceServerAchievement : BaseServerAchievement
		{
			private int failedInARow;

			private const int requirement = 3;

			public override void OnInstall()
			{
				base.OnInstall();
				ShrineChanceBehavior.onShrineChancePurchaseGlobal += OnShrineChancePurchase;
				Run.onRunStartGlobal += OnRunStartGlobal;
			}

			public override void OnUninstall()
			{
				base.OnInstall();
				ShrineChanceBehavior.onShrineChancePurchaseGlobal -= OnShrineChancePurchase;
				Run.onRunStartGlobal -= OnRunStartGlobal;
			}

			private void OnRunStartGlobal(Run run)
			{
				failedInARow = 0;
			}

			private void OnShrineChancePurchase(bool failed, Interactor interactor)
			{
				CharacterBody currentBody = serverAchievementTracker.networkUser.GetCurrentBody();
				if (!currentBody || !(currentBody.GetComponent<Interactor>() == interactor))
				{
					return;
				}
				if (failed)
				{
					failedInARow++;
					if (failedInARow >= 3)
					{
						Grant();
					}
				}
				else
				{
					failedInARow = 0;
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("FindDevilAltar", "Items.NovaOnHeal", null, 3u, null)]
	public class FindDevilAltarAchievement : BaseAchievement
	{
		public override void OnInstall()
		{
			base.OnInstall();
			AltarSkeletonDeath.onDeath += OnDeath;
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
			AltarSkeletonDeath.onDeath -= OnDeath;
		}

		private void OnDeath()
		{
			Grant();
		}
	}
	[RegisterAchievement("FindTimedChest", "Items.BFG", null, 2u, typeof(FindTimedChestServerAchievement))]
	public class FindTimedChestAchievement : BaseAchievement
	{
		private class FindTimedChestServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				EntityStates.TimedChest.Opening.onOpened += OnOpened;
			}

			public override void OnUninstall()
			{
				base.OnInstall();
				EntityStates.TimedChest.Opening.onOpened -= OnOpened;
			}

			private void OnOpened()
			{
				Grant();
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("FindUniqueNewtStatues", "Items.Talisman", null, 3u, null)]
	public class FindUniqueNewtStatues : BaseAchievement
	{
		private const int requirement = 8;

		public override void OnInstall()
		{
			base.OnInstall();
			Check();
			UserProfile.onUnlockableGranted += OnUnlockCheck;
		}

		public override void OnUninstall()
		{
			UserProfile.onUnlockableGranted -= OnUnlockCheck;
			base.OnUninstall();
		}

		public override float ProgressForAchievement()
		{
			return (float)UniqueNewtStatueCount() / 8f;
		}

		private static bool IsUnlockableNewtStatue(UnlockableDef unlockableDef)
		{
			return unlockableDef.cachedName.StartsWith("NewtStatue.");
		}

		private int UniqueNewtStatueCount()
		{
			StatSheet statSheet = base.userProfile.statSheet;
			int num = 0;
			int i = 0;
			for (int unlockableCount = statSheet.GetUnlockableCount(); i < unlockableCount; i++)
			{
				if (IsUnlockableNewtStatue(statSheet.GetUnlockable(i)))
				{
					num++;
				}
			}
			return num;
		}

		private void Check()
		{
			if (UniqueNewtStatueCount() >= 8)
			{
				Grant();
			}
		}

		private void OnUnlockCheck(UserProfile userProfile, UnlockableDef unlockableDef)
		{
			if (userProfile == base.userProfile && IsUnlockableNewtStatue(unlockableDef))
			{
				Check();
			}
		}
	}
	[RegisterAchievement("FreeMage", "Characters.Mage", null, 3u, typeof(FreeMageServerAchievement))]
	public class FreeMageAchievement : BaseAchievement
	{
		private class FreeMageServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				UnlockingMage.onOpened += OnOpened;
			}

			public override void OnUninstall()
			{
				base.OnInstall();
				UnlockingMage.onOpened -= OnOpened;
			}

			private void OnOpened(Interactor interactor)
			{
				CharacterBody currentBody = serverAchievementTracker.networkUser.GetCurrentBody();
				if ((bool)currentBody && currentBody.GetComponent<Interactor>() == interactor)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("HardEliteBossKill", "Items.KillEliteFrenzy", null, 3u, typeof(EliteBossKillServerAchievement))]
	internal class HardEliteBossKillAchievement : BaseAchievement
	{
		private class EliteBossKillServerAchievement : BaseServerAchievement
		{
			private static readonly List<EliteBossKillServerAchievement> instancesList = new List<EliteBossKillServerAchievement>();

			public override void OnInstall()
			{
				base.OnInstall();
				instancesList.Add(this);
				if (instancesList.Count == 1)
				{
					GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
				}
			}

			public override void OnUninstall()
			{
				if (instancesList.Count == 1)
				{
					GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				}
				instancesList.Remove(this);
				base.OnUninstall();
			}

			private static void OnCharacterDeath(DamageReport damageReport)
			{
				if (!damageReport.victim)
				{
					return;
				}
				CharacterBody body = damageReport.victim.body;
				if (!body || !body.isChampion || !body.isElite)
				{
					return;
				}
				foreach (EliteBossKillServerAchievement instances in instancesList)
				{
					GameObject masterObject = instances.serverAchievementTracker.networkUser.masterObject;
					if (!masterObject)
					{
						continue;
					}
					CharacterMaster component = masterObject.GetComponent<CharacterMaster>();
					if ((bool)component)
					{
						CharacterBody body2 = component.GetBody();
						if ((bool)body2 && (bool)body2.healthComponent && body2.healthComponent.alive)
						{
							instances.Grant();
						}
					}
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			NetworkUser.OnPostNetworkUserStart += OnPostNetworkUserStart;
			Run.onRunStartGlobal += OnRunStart;
		}

		public override void OnUninstall()
		{
			NetworkUser.OnPostNetworkUserStart -= OnPostNetworkUserStart;
			Run.onRunStartGlobal -= OnRunStart;
			base.OnUninstall();
		}

		private void UpdateTracking()
		{
			SetServerTracked((bool)Run.instance && (DifficultyCatalog.GetDifficultyDef(Run.instance.selectedDifficulty)?.countsAsHardMode ?? false));
		}

		private void OnPostNetworkUserStart(NetworkUser networkUser)
		{
			UpdateTracking();
		}

		private void OnRunStart(Run run)
		{
			UpdateTracking();
		}
	}
	[RegisterAchievement("HardHitter", "Items.ShockNearby", null, 3u, null)]
	public class HardHitterAchievement : BaseAchievement
	{
		private const float requirement = 5000f;

		public override void OnInstall()
		{
			base.OnInstall();
			GlobalEventManager.onClientDamageNotified += CheckDamage;
		}

		public override void OnUninstall()
		{
			GlobalEventManager.onClientDamageNotified -= CheckDamage;
			base.OnUninstall();
		}

		public void CheckDamage(DamageDealtMessage damageDealtMessage)
		{
			if (damageDealtMessage.damage >= 5000f && (bool)damageDealtMessage.attacker && damageDealtMessage.attacker == base.localUser.cachedBodyObject)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("KillBossQuantityInRun", "Items.LunarSkillReplacements", null, 2u, null)]
	public class KillBossQuantityInRunAchievement : BaseAchievement
	{
		private static readonly ulong requirement = 15uL;

		private PlayerStatsComponent playerStatsComponent;

		public override void OnInstall()
		{
			base.OnInstall();
			base.localUser.onMasterChanged += OnMasterChanged;
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(OnStatsReceived));
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(OnStatsReceived));
			base.localUser.onMasterChanged -= OnMasterChanged;
			base.OnUninstall();
		}

		private void OnMasterChanged()
		{
			playerStatsComponent = base.localUser.cachedMasterController?.GetComponent<PlayerStatsComponent>();
		}

		private void OnStatsReceived()
		{
			Check();
		}

		private void Check()
		{
			if (playerStatsComponent != null && requirement <= playerStatsComponent.currentStats.GetStatValueULong(StatDef.totalTeleporterBossKillsWitnessed))
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("KillBossQuick", "Items.TreasureCache", null, 1u, typeof(KillBossQuickServerAchievement))]
	public class KillBossQuickAchievement : BaseAchievement
	{
		private class KillBossQuickServerAchievement : BaseServerAchievement
		{
			private const float requirement = 15f;

			public override void OnInstall()
			{
				base.OnInstall();
				BossGroup.onBossGroupDefeatedServer += OnBossGroupDefeatedServer;
			}

			public override void OnUninstall()
			{
				BossGroup.onBossGroupDefeatedServer -= OnBossGroupDefeatedServer;
				base.OnUninstall();
			}

			private void OnBossGroupDefeatedServer(BossGroup bossGroup)
			{
				if (bossGroup.fixedTimeSinceEnabled <= 15f && (bool)bossGroup.GetComponent<TeleporterInteraction>())
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("KillElementalLemurians", "Items.ElementalRings", null, 2u, typeof(KillElementalLemuriansServerAchievement))]
	public class KillElementalLemuriansAchievement : BaseAchievement
	{
		private class KillElementalLemuriansServerAchievement : BaseServerAchievement
		{
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}
	}
	[RegisterAchievement("KillEliteMonster", "Items.Medkit", null, 1u, typeof(KillEliteMonsterServerAchievement))]
	public class KillEliteMonsterAchievement : BaseAchievement
	{
		private class KillEliteMonsterServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if (damageReport.victimIsElite && (bool)damageReport.attackerMaster && damageReport.attackerMaster.gameObject == serverAchievementTracker.networkUser.masterObject)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			SetServerTracked(shouldTrack: false);
			base.OnUninstall();
		}
	}
	[RegisterAchievement("KillElitesMilestone", "Items.ExecuteLowHealthElite", null, 2u, null)]
	public class KillElitesMilestoneAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalEliteKills;

		protected override ulong statRequirement => 500uL;
	}
	[RegisterAchievement("KillGoldTitanInOneCycle", "Items.Gateway", null, 2u, typeof(KillGoldTitanInOnePhaseServerAchievement))]
	public class KillGoldTitanInOneCycleAchievement : BaseAchievement
	{
		public class KillGoldTitanInOnePhaseServerAchievement : BaseServerAchievement
		{
			private BodyIndex goldTitanBodyIndex = BodyIndex.None;

			public override void OnInstall()
			{
				base.OnInstall();
				goldTitanBodyIndex = BodyCatalog.FindBodyIndex("TitanGoldBody");
				GoldshoresBossfight.onOneCycleGoldTitanKill += OnOneCycleGoldTitanKill;
			}

			private void OnOneCycleGoldTitanKill()
			{
				if ((bool)serverAchievementTracker.networkUser.GetCurrentBody())
				{
					Grant();
				}
			}

			public override void OnUninstall()
			{
				GoldshoresBossfight.onOneCycleGoldTitanKill -= OnOneCycleGoldTitanKill;
				base.OnUninstall();
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			SetServerTracked(shouldTrack: false);
			base.OnUninstall();
		}
	}
	[RegisterAchievement("KillTotalEnemies", "Items.Infusion", null, 2u, null)]
	public class KillTotalEnemiesAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalKills;

		protected override ulong statRequirement => 3000uL;
	}
	[RegisterAchievement("LoaderBigSlam", "Skills.Loader.ZapFist", "DefeatSuperRoboBallBoss", 3u, null)]
	public class LoaderBigSlamAchievement : BaseAchievement
	{
		private static readonly float requirement = (float)(300.0 * HGUnitConversions.milesToMeters / (1.0 * HGUnitConversions.hoursToSeconds));

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("LoaderBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			BaseSwingChargedFist.onHitAuthorityGlobal += SwingChargedFistOnOnHitAuthorityGlobal;
		}

		protected override void OnBodyRequirementBroken()
		{
			BaseSwingChargedFist.onHitAuthorityGlobal -= SwingChargedFistOnOnHitAuthorityGlobal;
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "LoaderBigSlam";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}

		private void SwingChargedFistOnOnHitAuthorityGlobal(BaseSwingChargedFist state)
		{
			if ((object)state.outer.commonComponents.characterBody == base.localUser.cachedBody)
			{
				UnityEngine.Debug.LogFormat("{0}/{1}", state.punchSpeed, requirement);
				if (state.punchSpeed >= requirement)
				{
					Grant();
					TryToCompleteActivity();
				}
			}
		}
	}
	[RegisterAchievement("LoaderKillLoaders", "Skills.Loader.Thunderslam", "DefeatSuperRoboBallBoss", 3u, typeof(LoaderKillLoadersServerAchievement))]
	public class LoaderKillLoadersAchievement : BaseAchievement
	{
		private class LoaderKillLoadersServerAchievement : BaseServerAchievement
		{
			private BodyIndex bodyIndex;

			private List<SceneDef> requiredSceneDefs = new List<SceneDef>();

			private int numKills;

			public override void OnInstall()
			{
				base.OnInstall();
				bodyIndex = BodyCatalog.FindBodyIndex("LoaderBody");
				requiredSceneDefs.Add(SceneCatalog.GetSceneDefFromSceneName("artifactworld"));
				requiredSceneDefs.Add(SceneCatalog.GetSceneDefFromSceneName("artifactworld01"));
				requiredSceneDefs.Add(SceneCatalog.GetSceneDefFromSceneName("artifactworld02"));
				requiredSceneDefs.Add(SceneCatalog.GetSceneDefFromSceneName("artifactworld03"));
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if ((bool)damageReport.victimBody)
				{
					if (damageReport.victimBody.bodyIndex == bodyIndex && IsCurrentBody(damageReport.attackerBody) && CheckForArtifactWorldScene())
					{
						numKills++;
					}
					if (numKills >= 3)
					{
						Grant();
					}
				}
			}

			private bool CheckForArtifactWorldScene()
			{
				bool result = false;
				for (int i = 0; i < requiredSceneDefs.Count; i++)
				{
					if (SceneCatalog.mostRecentSceneDef == requiredSceneDefs[i])
					{
						result = true;
						break;
					}
				}
				return result;
			}
		}

		private const int requirement = 3;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("LoaderBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("LogCollector", "Items.Scanner", null, 2u, null)]
	public class LogCollectorAchievement : BaseAchievement
	{
		private const int requirement = 10;

		public override void OnInstall()
		{
			base.OnInstall();
			Check();
			UserProfile.onUnlockableGranted += OnUnlockCheck;
		}

		public override void OnUninstall()
		{
			UserProfile.onUnlockableGranted -= OnUnlockCheck;
			base.OnUninstall();
		}

		public override float ProgressForAchievement()
		{
			return (float)MonsterLogCount() / 10f;
		}

		private static bool IsUnlockableMonsterLog(UnlockableDef unlockableDef)
		{
			return unlockableDef.cachedName.StartsWith("Logs.");
		}

		private int MonsterLogCount()
		{
			StatSheet statSheet = base.userProfile.statSheet;
			int num = 0;
			int i = 0;
			for (int unlockableCount = statSheet.GetUnlockableCount(); i < unlockableCount; i++)
			{
				if (IsUnlockableMonsterLog(statSheet.GetUnlockable(i)))
				{
					num++;
				}
			}
			return num;
		}

		private void Check()
		{
			if (MonsterLogCount() >= 10)
			{
				Grant();
			}
		}

		private void OnUnlockCheck(UserProfile userProfile, UnlockableDef unlockableDef)
		{
			if (userProfile == base.userProfile && IsUnlockableMonsterLog(unlockableDef))
			{
				Check();
			}
		}
	}
	[RegisterAchievement("LoopOnce", "Items.BounceNearby", null, 3u, null)]
	public class LoopOnceAchievement : BaseAchievement
	{
		public override void OnInstall()
		{
			base.OnInstall();
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(Check));
			Check();
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(Check));
			base.OnUninstall();
		}

		private void Check()
		{
			if ((bool)Run.instance && Run.instance.GetType() == typeof(Run) && Run.instance.loopClearCount > 0)
			{
				SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene();
				if ((bool)sceneDefForCurrentScene && (sceneDefForCurrentScene.sceneType == SceneType.Stage || sceneDefForCurrentScene.sceneType == SceneType.UntimedStage) && !sceneDefForCurrentScene.isFinalStage && sceneDefForCurrentScene.stageOrder == 1)
				{
					Grant();
				}
			}
		}
	}
	[RegisterAchievement("MajorMultikill", "Items.BurnNearby", null, 2u, typeof(MajorMultikillServerAchievement))]
	public class MajorMultikillAchievement : BaseAchievement
	{
		private class MajorMultikillServerAchievement : BaseServerAchievement
		{
			private const int multiKillThreshold = 15;

			public override void OnInstall()
			{
				base.OnInstall();
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				GameObject attacker = damageReport.damageInfo.attacker;
				if ((bool)attacker)
				{
					CharacterBody component = attacker.GetComponent<CharacterBody>();
					if ((bool)component && component.multiKillCount >= 15 && component.masterObject == serverAchievementTracker.networkUser.masterObject)
					{
						Grant();
					}
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("MaxHealingShrine", "Items.PassiveHealing", null, 1u, typeof(MaxHealingShrineServerAchievement))]
	public class MaxHealingShrineAchievement : BaseAchievement
	{
		private class MaxHealingShrineServerAchievement : BaseServerAchievement
		{
			private const int requirement = 2;

			public override void OnInstall()
			{
				base.OnInstall();
				ShrineHealingBehavior.onActivated += OnHealingShrineActivated;
			}

			public override void OnUninstall()
			{
				ShrineHealingBehavior.onActivated -= OnHealingShrineActivated;
				base.OnUninstall();
			}

			private void OnHealingShrineActivated(ShrineHealingBehavior shrine, Interactor activator)
			{
				if (shrine.purchaseCount >= shrine.maxPurchaseCount)
				{
					CharacterBody currentBody = GetCurrentBody();
					if ((bool)currentBody && currentBody.gameObject == activator.gameObject)
					{
						Grant();
					}
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	public class MeridianEventTriggerAchievement : BaseAchievement
	{
		public override void OnInstall()
		{
			base.OnInstall();
			SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
			SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
		}

		private void OnMeridianEventTriggerActivated()
		{
			if (base.isUserAlive)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("MoveSpeed", "Items.JumpBoost", null, 2u, null)]
	public class MoveSpeedAchievement : BaseAchievement
	{
		private const float requirement = 4f;

		public override void OnInstall()
		{
			base.OnInstall();
			RoR2Application.onUpdate += CheckMoveSpeed;
		}

		public override void OnUninstall()
		{
			RoR2Application.onUpdate -= CheckMoveSpeed;
			base.OnUninstall();
		}

		public void CheckMoveSpeed()
		{
			if (base.localUser != null && (bool)base.localUser.cachedBody && base.localUser.cachedBody.moveSpeed / base.localUser.cachedBody.baseMoveSpeed >= 4f)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("MultiCombatShrine", "Items.EnergizedOnEquipmentUse", null, 2u, typeof(MultiCombatShrineServerAchievement))]
	public class MultiCombatShrineAchievement : BaseAchievement
	{
		private class MultiCombatShrineServerAchievement : BaseServerAchievement
		{
			private int counter;

			private static readonly int requirement = 3;

			public override void OnInstall()
			{
				base.OnInstall();
				ShrineCombatBehavior.onDefeatedServerGlobal += OnShrineDefeated;
				Stage.onServerStageBegin += OnServerStageBegin;
			}

			public override void OnUninstall()
			{
				Stage.onServerStageBegin -= OnServerStageBegin;
				ShrineCombatBehavior.onDefeatedServerGlobal -= OnShrineDefeated;
				base.OnUninstall();
			}

			private void OnServerStageBegin(Stage stage)
			{
				counter = 0;
			}

			private void OnShrineDefeated(ShrineCombatBehavior instance)
			{
				counter++;
				Check();
			}

			private void Check()
			{
				if (counter >= requirement)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			SetServerTracked(shouldTrack: false);
			base.OnUninstall();
		}
	}
	[RegisterAchievement("NeverBackDown", "Items.FocusConvergence", null, 2u, typeof(NeverBackDown))]
	public class NeverBackDown : BaseAchievement
	{
		private bool _checkingForFailure;

		private static readonly int requirement = 4;

		private bool hasLeftRadius;

		private int levels;

		private Run.FixedTimeStamp teleporterStartChargingTime = Run.FixedTimeStamp.negativeInfinity;

		private static readonly float gracePeriod = 2f;

		private bool checkingForFailure
		{
			get
			{
				return _checkingForFailure;
			}
			set
			{
				if (_checkingForFailure != value)
				{
					_checkingForFailure = value;
					if (_checkingForFailure)
					{
						RoR2Application.onFixedUpdate += CheckForFailure;
					}
					else
					{
						RoR2Application.onFixedUpdate -= CheckForFailure;
					}
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			TeleporterInteraction.onTeleporterBeginChargingGlobal += OnTeleporterBeginCharging;
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged;
			Run.onRunStartGlobal += OnRunStartGlobal;
		}

		public override void OnUninstall()
		{
			checkingForFailure = false;
			Run.onRunStartGlobal -= OnRunStartGlobal;
			TeleporterInteraction.onTeleporterBeginChargingGlobal -= OnTeleporterBeginCharging;
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged;
			base.OnUninstall();
		}

		private void OnRunStartGlobal(Run run)
		{
			levels = 0;
		}

		private void OnTeleporterBeginCharging(TeleporterInteraction teleporterInteraction)
		{
			hasLeftRadius = false;
			teleporterStartChargingTime = Run.FixedTimeStamp.now;
			checkingForFailure = true;
		}

		private void OnTeleporterCharged(TeleporterInteraction teleporterInteraction)
		{
			if (!hasLeftRadius)
			{
				levels++;
			}
			if (levels >= requirement)
			{
				Grant();
			}
		}

		private void CheckForFailure()
		{
			if (!TeleporterInteraction.instance || TeleporterInteraction.instance.isCharged)
			{
				checkingForFailure = false;
			}
			else if ((bool)base.localUser.cachedBody && (teleporterStartChargingTime + gracePeriod).hasPassed && !TeleporterInteraction.instance.holdoutZoneController.IsBodyInChargingRadius(base.localUser.cachedBody))
			{
				hasLeftRadius = true;
				levels = 0;
				checkingForFailure = false;
			}
		}
	}
	[RegisterAchievement("RepeatedlyDuplicateItems", "Items.Firework", null, 1u, typeof(RepeatedlyDuplicateItemsServerAchievement))]
	public class RepeatedlyDuplicateItemsAchievement : BaseAchievement
	{
		private class RepeatedlyDuplicateItemsServerAchievement : BaseServerAchievement
		{
			private const int requirement = 7;

			private ItemIndex trackingItemIndex = ItemIndex.None;

			private int progress;

			public override void OnInstall()
			{
				base.OnInstall();
				PurchaseInteraction.onItemSpentOnPurchase += OnItemSpentOnPurchase;
				Run.onRunStartGlobal += OnRunStartGlobal;
			}

			public override void OnUninstall()
			{
				base.OnInstall();
				PurchaseInteraction.onItemSpentOnPurchase -= OnItemSpentOnPurchase;
				Run.onRunStartGlobal -= OnRunStartGlobal;
			}

			private void OnRunStartGlobal(Run run)
			{
				progress = 0;
			}

			private void OnItemSpentOnPurchase(PurchaseInteraction purchaseInteraction, Interactor interactor)
			{
				CharacterBody currentBody = serverAchievementTracker.networkUser.GetCurrentBody();
				if (!currentBody || !(currentBody.GetComponent<Interactor>() == interactor) || !purchaseInteraction.gameObject.name.Contains("Duplicator"))
				{
					return;
				}
				ShopTerminalBehavior component = purchaseInteraction.GetComponent<ShopTerminalBehavior>();
				if ((bool)component)
				{
					ItemIndex itemIndex = PickupCatalog.GetPickupDef(component.CurrentPickupIndex())?.itemIndex ?? ItemIndex.None;
					if (trackingItemIndex != itemIndex)
					{
						trackingItemIndex = itemIndex;
						progress = 0;
					}
					progress++;
					if (progress >= 7)
					{
						Grant();
					}
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("RepeatFirstTeleporter", "Characters.Toolbot", null, 3u, typeof(RepeatFirstTeleporterServerAchievement))]
	public class RepeatFirstTeleporterAchievement : BaseAchievement
	{
		private class RepeatFirstTeleporterServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged;
			}

			public override void OnUninstall()
			{
				TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged;
				base.OnUninstall();
			}

			private void OnTeleporterCharged(TeleporterInteraction teleporterInteraction)
			{
				SceneCatalog.GetSceneDefForCurrentScene();
				_ = base.networkUser.masterPlayerStatsComponent.currentStats;
				if ((bool)Run.instance && Run.instance.stageClearCount == 0)
				{
					PlayerStatsComponent masterPlayerStatsComponent = base.networkUser.masterPlayerStatsComponent;
					if ((bool)masterPlayerStatsComponent)
					{
						masterPlayerStatsComponent.currentStats.PushStatValue(StatDef.firstTeleporterCompleted, 1uL);
					}
				}
			}
		}

		private const int requirement = 5;

		public override void OnInstall()
		{
			base.OnInstall();
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(Check));
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(Check));
			base.OnUninstall();
		}

		private void Check()
		{
			if (base.userProfile.statSheet.GetStatValueULong(StatDef.firstTeleporterCompleted) >= 5)
			{
				Grant();
			}
		}

		public override float ProgressForAchievement()
		{
			return (float)base.userProfile.statSheet.GetStatValueULong(StatDef.firstTeleporterCompleted) / 5f;
		}
	}
	[RegisterAchievement("RescueTreebot", "Characters.Treebot", null, 3u, typeof(RescueTreebotServerAchievement))]
	public class RescueTreebotAchievement : BaseAchievement
	{
		public class RescueTreebotServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				Unlock.onActivated += OnActivated;
			}

			public override void OnUninstall()
			{
				Unlock.onActivated -= OnActivated;
				base.OnInstall();
			}

			private void OnActivated(Interactor interactor)
			{
				CharacterBody currentBody = serverAchievementTracker.networkUser.GetCurrentBody();
				if ((bool)currentBody && currentBody.GetComponent<Interactor>() == interactor)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("StayAlive1", "Items.ExtraLife", null, 3u, null)]
	public class StayAlive1Achievement : BaseAchievement
	{
		private const float requirement = 1800f;

		public override void OnInstall()
		{
			base.OnInstall();
			RoR2Application.onUpdate += Check;
		}

		public override void OnUninstall()
		{
			RoR2Application.onUpdate -= Check;
			base.OnUninstall();
		}

		private void Check()
		{
			NetworkUser networkUser = NetworkUser.readOnlyLocalPlayersList.FirstOrDefault((NetworkUser v) => v.localUser == base.localUser);
			if (!networkUser)
			{
				return;
			}
			GameObject masterObject = networkUser.masterObject;
			if ((bool)masterObject)
			{
				CharacterMaster component = masterObject.GetComponent<CharacterMaster>();
				if ((bool)component && component.currentLifeStopwatch >= 1800f)
				{
					Grant();
				}
			}
		}
	}
	[RegisterAchievement("SuicideHermitCrabs", "Items.AutoCastEquipment", null, 2u, typeof(SuicideHermitCrabsServerAchievement))]
	public class SuicideHermitCrabsAchievement : BaseAchievement
	{
		private class SuicideHermitCrabsServerAchievement : BaseServerAchievement
		{
			private BodyIndex crabBodyIndex;

			public override void OnInstall()
			{
				base.OnInstall();
				crabBodyIndex = BodyCatalog.FindBodyIndex("HermitCrabBody");
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if (!damageReport.victimBody || damageReport.victimBody.bodyIndex != crabBodyIndex || damageReport.victimBody.teamComponent.teamIndex == TeamIndex.Player)
				{
					return;
				}
				GameObject inflictor = damageReport.damageInfo.inflictor;
				if ((bool)inflictor && (bool)inflictor.GetComponent<MapZone>())
				{
					PlayerStatsComponent masterPlayerStatsComponent = base.networkUser.masterPlayerStatsComponent;
					if ((bool)masterPlayerStatsComponent)
					{
						masterPlayerStatsComponent.currentStats.PushStatValue(StatDef.suicideHermitCrabsAchievementProgress, 1uL);
					}
				}
			}
		}

		private const int requirement = 20;

		public override void OnInstall()
		{
			base.OnInstall();
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(Check));
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(Check));
			base.OnUninstall();
		}

		private void Check()
		{
			if (base.userProfile.statSheet.GetStatValueULong(StatDef.suicideHermitCrabsAchievementProgress) >= 20)
			{
				Grant();
			}
		}

		public override float ProgressForAchievement()
		{
			return (float)base.userProfile.statSheet.GetStatValueULong(StatDef.suicideHermitCrabsAchievementProgress) / 20f;
		}
	}
	[RegisterAchievement("TotalDronesRepaired", "Items.DroneBackup", null, 3u, null)]
	public class TotalDronesRepairedAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalDronesPurchased;

		protected override ulong statRequirement => 30uL;
	}
	[RegisterAchievement("TotalMoneyCollected", "Items.GoldGat", null, 2u, null)]
	public class TotalMoneyCollectedAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.goldCollected;

		protected override ulong statRequirement => 30480uL;
	}
	[RegisterAchievement("UnlockFalseSon", "Characters.FalseSon", null, 3u, typeof(UnlockFalseSonAchievementServer))]
	public class UnlockFalseSonAchievement : BaseAchievement
	{
		public class UnlockFalseSonAchievementServer : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonUnlockEvent += OnFalseSonUnlock;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonUnlockEvent -= OnFalseSonUnlock;
			}

			private void OnFalseSonUnlock()
			{
				Grant();
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("UseThreePortals", "Items.Tonic", null, 2u, null)]
	public class UseThreePortalsAchievement : BaseAchievement
	{
		private StatDef[] statsToCheck;

		private const int requirement = 3;

		public override void OnInstall()
		{
			base.OnInstall();
			statsToCheck = new StatDef[5]
			{
				PerStageStatDef.totalTimesVisited.FindStatDef("bazaar"),
				PerStageStatDef.totalTimesVisited.FindStatDef("mysteryspace"),
				PerStageStatDef.totalTimesVisited.FindStatDef("goldshores"),
				PerStageStatDef.totalTimesVisited.FindStatDef("arena"),
				PerStageStatDef.totalTimesVisited.FindStatDef("artifactworld")
			};
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(Check));
			Check();
		}

		public override void OnUninstall()
		{
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(Check));
			base.OnUninstall();
		}

		public override float ProgressForAchievement()
		{
			return (float)GetUniquePortalsUsedCount() / 3f;
		}

		private int GetUniquePortalsUsedCount()
		{
			StatSheet statSheet = base.userProfile.statSheet;
			int num = 0;
			StatDef[] array = statsToCheck;
			foreach (StatDef statDef in array)
			{
				if (statSheet.GetStatValueULong(statDef) != 0)
				{
					num++;
				}
			}
			return num;
		}

		private void Check()
		{
			if (GetUniquePortalsUsedCount() >= 3)
			{
				Grant();
			}
		}
	}
	[RequireComponent(typeof(NetworkUser))]
	public class ServerAchievementTracker : NetworkBehaviour
	{
		private BaseServerAchievement[] achievementTrackers;

		private SerializableBitArray maskBitArrayConverter;

		private byte[] maskBuffer;

		private static int kCmdCmdSetAchievementTrackerRequests;

		private static int kRpcRpcGrantAchievement;

		private static int kRpcRpcTryToCompleteActivity;

		public NetworkUser networkUser { get; private set; }

		private void Awake()
		{
			networkUser = GetComponent<NetworkUser>();
			maskBitArrayConverter = new SerializableBitArray(AchievementManager.serverAchievementCount);
			if (NetworkServer.active)
			{
				achievementTrackers = new BaseServerAchievement[AchievementManager.serverAchievementCount];
			}
			if (NetworkClient.active)
			{
				maskBuffer = new byte[maskBitArrayConverter.byteCount];
			}
		}

		private void Start()
		{
			if (networkUser.localUser != null)
			{
				AchievementManager.GetUserAchievementManager(networkUser.localUser)?.TransmitAchievementRequestsToServer();
			}
		}

		private void OnDestroy()
		{
			if (achievementTrackers != null)
			{
				int serverAchievementCount = AchievementManager.serverAchievementCount;
				for (int i = 0; i < serverAchievementCount; i++)
				{
					SetAchievementTracked(new ServerAchievementIndex
					{
						intValue = i
					}, shouldTrack: false);
				}
			}
		}

		[Client]
		public void SendAchievementTrackerRequestsMaskToServer(bool[] serverAchievementsToTrackMask)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogWarning("[Client] function 'System.Void RoR2.Achievements.ServerAchievementTracker::SendAchievementTrackerRequestsMaskToServer(System.Boolean[])' called on server");
				return;
			}
			int serverAchievementCount = AchievementManager.serverAchievementCount;
			for (int i = 0; i < serverAchievementCount; i++)
			{
				maskBitArrayConverter[i] = serverAchievementsToTrackMask[i];
			}
			maskBitArrayConverter.GetBytes(maskBuffer);
			CallCmdSetAchievementTrackerRequests(maskBuffer);
		}

		[Command]
		private void CmdSetAchievementTrackerRequests(byte[] packedServerAchievementsToTrackMask)
		{
			int serverAchievementCount = AchievementManager.serverAchievementCount;
			if (packedServerAchievementsToTrackMask.Length << 3 >= serverAchievementCount)
			{
				for (int i = 0; i < serverAchievementCount; i++)
				{
					int num = i >> 3;
					int num2 = i & 7;
					SetAchievementTracked(new ServerAchievementIndex
					{
						intValue = i
					}, ((packedServerAchievementsToTrackMask[num] >> num2) & 1) != 0);
				}
			}
		}

		private void SetAchievementTracked(ServerAchievementIndex serverAchievementIndex, bool shouldTrack)
		{
			BaseServerAchievement baseServerAchievement = achievementTrackers[serverAchievementIndex.intValue];
			if (shouldTrack != (baseServerAchievement != null))
			{
				if (shouldTrack)
				{
					BaseServerAchievement baseServerAchievement2 = BaseServerAchievement.Instantiate(serverAchievementIndex);
					baseServerAchievement2.serverAchievementTracker = this;
					achievementTrackers[serverAchievementIndex.intValue] = baseServerAchievement2;
					baseServerAchievement2.OnInstall();
				}
				else
				{
					baseServerAchievement.OnUninstall();
					achievementTrackers[serverAchievementIndex.intValue] = null;
				}
			}
		}

		[ClientRpc]
		public void RpcGrantAchievement(ServerAchievementIndex serverAchievementIndex)
		{
			LocalUser localUser = networkUser.localUser;
			if (localUser != null)
			{
				AchievementManager.GetUserAchievementManager(localUser)?.HandleServerAchievementCompleted(serverAchievementIndex);
			}
		}

		[ClientRpc]
		public void RpcTryToCompleteActivity(ServerAchievementIndex serverAchievementIndex)
		{
			LocalUser localUser = networkUser.localUser;
			if (localUser != null)
			{
				AchievementManager.GetUserAchievementManager(localUser)?.HandleServerTryToCompleteActivity(serverAchievementIndex);
			}
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdSetAchievementTrackerRequests(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdSetAchievementTrackerRequests called on client.");
			}
			else
			{
				((ServerAchievementTracker)obj).CmdSetAchievementTrackerRequests(reader.ReadBytesAndSize());
			}
		}

		public void CallCmdSetAchievementTrackerRequests(byte[] packedServerAchievementsToTrackMask)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdSetAchievementTrackerRequests called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdSetAchievementTrackerRequests(packedServerAchievementsToTrackMask);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdSetAchievementTrackerRequests);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WriteBytesFull(packedServerAchievementsToTrackMask);
			SendCommandInternal(networkWriter, 0, "CmdSetAchievementTrackerRequests");
		}

		protected static void InvokeRpcRpcGrantAchievement(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcGrantAchievement called on server.");
			}
			else
			{
				((ServerAchievementTracker)obj).RpcGrantAchievement(GeneratedNetworkCode._ReadServerAchievementIndex_None(reader));
			}
		}

		protected static void InvokeRpcRpcTryToCompleteActivity(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcTryToCompleteActivity called on server.");
			}
			else
			{
				((ServerAchievementTracker)obj).RpcTryToCompleteActivity(GeneratedNetworkCode._ReadServerAchievementIndex_None(reader));
			}
		}

		public void CallRpcGrantAchievement(ServerAchievementIndex serverAchievementIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcGrantAchievement called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcGrantAchievement);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteServerAchievementIndex_None(networkWriter, serverAchievementIndex);
			SendRPCInternal(networkWriter, 0, "RpcGrantAchievement");
		}

		public void CallRpcTryToCompleteActivity(ServerAchievementIndex serverAchievementIndex)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcTryToCompleteActivity called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcTryToCompleteActivity);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			GeneratedNetworkCode._WriteServerAchievementIndex_None(networkWriter, serverAchievementIndex);
			SendRPCInternal(networkWriter, 0, "RpcTryToCompleteActivity");
		}

		static ServerAchievementTracker()
		{
			kCmdCmdSetAchievementTrackerRequests = 387052099;
			NetworkBehaviour.RegisterCommandDelegate(typeof(ServerAchievementTracker), kCmdCmdSetAchievementTrackerRequests, InvokeCmdCmdSetAchievementTrackerRequests);
			kRpcRpcGrantAchievement = -1713740939;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ServerAchievementTracker), kRpcRpcGrantAchievement, InvokeRpcRpcGrantAchievement);
			kRpcRpcTryToCompleteActivity = -1526039716;
			NetworkBehaviour.RegisterRpcDelegate(typeof(ServerAchievementTracker), kRpcRpcTryToCompleteActivity, InvokeRpcRpcTryToCompleteActivity);
			NetworkCRC.RegisterBehaviour("ServerAchievementTracker", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
}
namespace RoR2.Achievements.VoidSurvivor
{
	[RegisterAchievement("VoidSurvivorClearGameMonsoon", "Skins.VoidSurvivor.Alt1", "CompleteVoidEnding", 10u, null)]
	public class VoidSurvivorClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("VoidSurvivorBody");
		}
	}
	[RegisterAchievement("VoidSurvivorClearMeridianEvent", "Skins.VoidSurvivor.Alt2", "CompleteVoidEnding", 3u, typeof(VoidSurvivorMeridianEventTriggerServerAchievement))]
	public class VoidSurvivorMeridianEventTriggerAchievement : BaseAchievement
	{
		private class VoidSurvivorMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("VoidSurvivorBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Treebot
{
	[RegisterAchievement("TreebotBigHeal", "Skills.Treebot.SpecialAlt1", "RescueTreebot", 3u, typeof(TreebotBigHealServerAchievement))]
	public class TreebotBigHealAchievement : BaseAchievement
	{
		private class TreebotBigHealServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				HealthComponent.onCharacterHealServer += OnCharacterHealServer;
			}

			public override void OnUninstall()
			{
				HealthComponent.onCharacterHealServer -= OnCharacterHealServer;
				base.OnInstall();
			}

			private void OnCharacterHealServer(HealthComponent healthComponent, float amount, ProcChainMask procChainMask)
			{
				if (amount >= requirement)
				{
					HealthComponent component = GetCurrentBody().GetComponent<HealthComponent>();
					if ((object)healthComponent == component)
					{
						Grant();
						ServerTryToCompleteActivity();
					}
				}
			}
		}

		private static readonly float requirement = 1000f;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("TreebotBody");
		}

		public override void OnInstall()
		{
			base.OnInstall();
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "TreebotBigHeal";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("TreebotClearGameMonsoon", "Skins.Treebot.Alt1", "RescueTreebot", 10u, null)]
	public class TreebotClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("TreebotBody");
		}
	}
	[RegisterAchievement("TreebotDunkClayBoss", "Skills.Treebot.PlantSonicBoom", "RescueTreebot", 3u, typeof(TreebotDunkClayBossServerAchievement))]
	public class TreebotDunkClayBossAchievement : BaseAchievement
	{
		private class TreebotDunkClayBossServerAchievement : BaseServerAchievement
		{
			private BodyIndex clayBossBodyIndex;

			private SceneDef requiredSceneDef;

			public override void OnInstall()
			{
				base.OnInstall();
				clayBossBodyIndex = BodyCatalog.FindBodyIndex("ClayBossBody");
				requiredSceneDef = SceneCatalog.GetSceneDefFromSceneName("goolake");
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if (damageReport.victimBodyIndex == clayBossBodyIndex && IsCurrentBody(damageReport.attackerBody) && (bool)damageReport.damageInfo.inflictor && (bool)damageReport.damageInfo.inflictor.GetComponent<MapZone>() && SceneCatalog.mostRecentSceneDef == requiredSceneDef)
				{
					Grant();
				}
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				base.OnUninstall();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("TreebotBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("TreebotLowHealthTeleporter", "Skills.Treebot.Barrage", "RescueTreebot", 3u, null)]
	public class TreebotLowHealthTeleporterAchievement : BaseAchievement
	{
		private static readonly float requirement = 0.5f;

		private ToggleAction healthMonitor;

		private HealthComponent targetHealthComponent;

		private bool failed = true;

		private HealthComponent healthComponent;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("TreebotBody");
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "TreebotLowHealthTeleporter";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}

		private void OnTeleporterBeginChargingGlobal(TeleporterInteraction teleporterInteraction)
		{
			failed = false;
			healthMonitor.SetActive(newActive: true);
		}

		private void OnTeleporterChargedGlobal(TeleporterInteraction teleporterInteraction)
		{
			if (!failed)
			{
				Grant();
				TryToCompleteActivity();
			}
		}

		private void SubscribeHealthMonitor()
		{
			RoR2Application.onFixedUpdate += OnFixedUpdateMonitorHealth;
		}

		private void UnsubscribeHealthMonitor()
		{
			RoR2Application.onFixedUpdate -= OnFixedUpdateMonitorHealth;
		}

		private void OnFixedUpdateMonitorHealth()
		{
			if (!healthComponent || requirement < healthComponent.combinedHealthFraction)
			{
				failed = true;
				healthMonitor.SetActive(newActive: false);
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			healthMonitor = new ToggleAction(SubscribeHealthMonitor, UnsubscribeHealthMonitor);
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			TeleporterInteraction.onTeleporterBeginChargingGlobal += OnTeleporterBeginChargingGlobal;
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterChargedGlobal;
			base.localUser.onBodyChanged += OnBodyChanged;
			OnBodyChanged();
		}

		private void OnBodyChanged()
		{
			healthComponent = base.localUser.cachedBody?.healthComponent;
		}

		protected override void OnBodyRequirementBroken()
		{
			base.localUser.onBodyChanged -= OnBodyChanged;
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterChargedGlobal;
			TeleporterInteraction.onTeleporterBeginChargingGlobal -= OnTeleporterBeginChargingGlobal;
			healthMonitor.SetActive(newActive: false);
			healthComponent = null;
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("TreebotClearMeridianEvent", "Skins.Treebot.Alt2", "RescueTreebot", 5u, typeof(TreebotMeridianEventTriggerServerAchievement))]
	public class TreebotMeridianEventTriggerAchievement : BaseAchievement
	{
		private class TreebotMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("TreebotBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Toolbot
{
	[RegisterAchievement("ToolbotBeatArenaLater", "Skills.Toolbot.SpecialAlt", "RepeatFirstTeleporter", 3u, typeof(ToolbotBeatArenaLaterServerAchievement))]
	public class ToolbotBeatArenaLaterAchievement : BaseAchievement
	{
		private class ToolbotBeatArenaLaterServerAchievement : BaseServerAchievement
		{
			private MemoizedGetComponent<PlayerStatsComponent> playerStatsComponentGetter;

			public override void OnInstall()
			{
				base.OnInstall();
				ArenaMissionController.onBeatArena += OnBeatArena;
			}

			public override void OnUninstall()
			{
				ArenaMissionController.onBeatArena -= OnBeatArena;
				base.OnInstall();
			}

			private void OnBeatArena()
			{
				PlayerStatsComponent playerStatsComponent = playerStatsComponentGetter.Get(base.networkUser.masterObject);
				if ((bool)playerStatsComponent && playerStatsComponent.currentStats.GetStatValueULong(StatDef.highestStagesCompleted) >= 6)
				{
					Grant();
				}
			}
		}

		private const int requirement = 6;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("ToolbotBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("ToolbotClearGameMonsoon", "Skins.Toolbot.Alt1", "RepeatFirstTeleporter", 10u, null)]
	public class ToolbotClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("ToolbotBody");
		}
	}
	[RegisterAchievement("ToolbotGuardTeleporter", "Skills.Toolbot.Grenade", "RepeatFirstTeleporter", 3u, typeof(ToolbotGuardTeleporterServerAchievement))]
	public class ToolbotGuardTeleporterAchievement : BaseAchievement
	{
		public class ToolbotGuardTeleporterServerAchievement : BaseServerAchievement
		{
			private bool stayedInZone;

			private int killCount;

			private int killRequirement = 2;

			private BodyIndex beetleQueenBodyIndex = BodyIndex.None;

			private Run.FixedTimeStamp teleporterStartChargingTime = Run.FixedTimeStamp.negativeInfinity;

			private static readonly float gracePeriod = 2f;

			public override void OnInstall()
			{
				base.OnInstall();
				TeleporterInteraction.onTeleporterBeginChargingGlobal += OnTeleporterBeginCharging;
				TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterCharged;
				killCount = 0;
				beetleQueenBodyIndex = BodyCatalog.FindBodyIndex("BeetleQueen2Body");
			}

			public override void OnUninstall()
			{
				TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterCharged;
				TeleporterInteraction.onTeleporterBeginChargingGlobal -= OnTeleporterBeginCharging;
				SetStayedInZone(newStayedInZone: false);
				base.OnUninstall();
			}

			private void OnTeleporterBeginCharging(TeleporterInteraction teleporterInteraction)
			{
				teleporterStartChargingTime = Run.FixedTimeStamp.now;
				SetStayedInZone(newStayedInZone: true);
			}

			private void OnTeleporterCharged(TeleporterInteraction teleporterInteraction)
			{
				SetStayedInZone(newStayedInZone: false);
			}

			private void SetStayedInZone(bool newStayedInZone)
			{
				if (stayedInZone != newStayedInZone)
				{
					stayedInZone = newStayedInZone;
					if (stayedInZone)
					{
						RoR2Application.onFixedUpdate += FixedUpdateTeleporterCharging;
						GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
						UpdateStayedInZone();
					}
					else
					{
						killCount = 0;
						GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
						RoR2Application.onFixedUpdate -= FixedUpdateTeleporterCharging;
					}
				}
			}

			private void FixedUpdateTeleporterCharging()
			{
				UpdateStayedInZone();
			}

			private void UpdateStayedInZone()
			{
				if (stayedInZone)
				{
					TeleporterInteraction instance = TeleporterInteraction.instance;
					CharacterBody currentBody = GetCurrentBody();
					if ((!instance || !instance.holdoutZoneController.IsBodyInChargingRadius(currentBody)) && (teleporterStartChargingTime + gracePeriod).hasPassed)
					{
						SetStayedInZone(newStayedInZone: false);
					}
				}
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if (damageReport.victimBodyIndex == beetleQueenBodyIndex)
				{
					killCount++;
					if (killCount >= killRequirement)
					{
						Grant();
					}
				}
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("ToolbotBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("ToolbotKillImpBossWithBfg", "Skills.Toolbot.Buzzsaw", "RepeatFirstTeleporter", 3u, typeof(ToolbotKillImpBossWithBfgServerAchievement))]
	public class ToolbotKillImpBossWithBfgAchievement : BaseAchievement
	{
		private class ToolbotKillImpBossWithBfgServerAchievement : BaseServerAchievement
		{
			private BodyIndex impBossBodyIndex = BodyIndex.None;

			private int bfgProjectileIndex = -1;

			public override void OnInstall()
			{
				base.OnInstall();
				impBossBodyIndex = BodyCatalog.FindBodyIndex("ImpBossBody");
				bfgProjectileIndex = ProjectileCatalog.FindProjectileIndex("BeamSphere");
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if ((bool)damageReport.victimBody && damageReport.victimBody.bodyIndex == impBossBodyIndex && IsCurrentBody(damageReport.damageInfo.attacker) && ProjectileCatalog.GetProjectileIndex(damageReport.damageInfo.inflictor) == bfgProjectileIndex)
				{
					Grant();
				}
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("ToolbotBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("ToolbotClearMeridianEvent", "Skins.Toolbot.Alt2", "RepeatFirstTeleporter", 5u, typeof(ToolbotMeridianEventTriggerServerAchievement))]
	public class ToolbotMeridianEventTriggerAchievement : BaseAchievement
	{
		private class ToolbotMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("ToolbotBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Seeker
{
	[RegisterAchievement("SeekerClearGameMonsoon", "Skins.Seeker.Alt1", null, 10u, null)]
	public class SeekerClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("SeekerBody");
		}
	}
	[RegisterAchievement("SeekerAirMultiHit", "Skills.Seeker.SoulSearch", null, 3u, typeof(SeekerAirMultiHitServerAchievement))]
	public class SeekerAirMultiHit : BaseAchievement
	{
		private class SeekerAirMultiHitServerAchievement : BaseServerAchievement
		{
			private int hitCount;

			private bool hasShotSpiritOrb;

			public override void OnInstall()
			{
				base.OnInstall();
				SpiritPunch.onSpiritOrbFired += OnSpiritPunch;
				BlastAttack.BlastAttackMultiHit += MultiAirborneBlastAttack;
			}

			public override void OnUninstall()
			{
				BlastAttack.BlastAttackMultiHit -= MultiAirborneBlastAttack;
				SpiritPunch.onSpiritOrbFired -= OnSpiritPunch;
				base.OnUninstall();
			}

			private void MultiAirborneBlastAttack(BlastAttack.HitPoint[] hitPoints, GameObject attacker)
			{
				hitCount = 0;
				if (!(attacker != null))
				{
					return;
				}
				CharacterMaster master = attacker.GetComponent<CharacterBody>().master;
				if ((object)master == null || (object)master != base.networkUser.master || !hasShotSpiritOrb)
				{
					return;
				}
				for (int i = 0; i < hitPoints.Length; i++)
				{
					BlastAttack.HitPoint hitPoint = hitPoints[i];
					HealthComponent healthComponent = (hitPoint.hurtBox ? hitPoint.hurtBox.healthComponent : null);
					if ((bool)healthComponent)
					{
						CharacterBody body = healthComponent.body;
						if (VictimInAir(body))
						{
							hitCount++;
						}
					}
				}
				if (hitCount >= requirement)
				{
					Grant();
				}
				else
				{
					hasShotSpiritOrb = false;
				}
			}

			private bool VictimInAir(CharacterBody victimBody)
			{
				bool flag = false;
				if (victimBody.baseNameToken == "WISP_BODY_NAME" || victimBody.baseNameToken == "GREATERWISP_BODY_NAME")
				{
					flag = true;
				}
				return ((bool)victimBody && (bool)victimBody.characterMotor && !victimBody.characterMotor.isGrounded) || flag;
			}

			private void OnSpiritPunch(bool spiritOrbFired)
			{
				hasShotSpiritOrb = spiritOrbFired;
			}
		}

		private static readonly int requirement = 3;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("SeekerBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Railgunner
{
	[RegisterAchievement("RailgunnerAirborneMultiKill", "Skills.Railgunner.SpecialAlt1", null, 3u, typeof(RailgunnerAirborneMultiKillServerAchievement))]
	public class RailgunnerAirborneMultiKillAchievement : BaseAchievement
	{
		private class RailgunnerAirborneMultiKillServerAchievement : BaseServerAchievement
		{
			private int killCount;

			public override void OnInstall()
			{
				base.OnInstall();
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
				BaseFireSnipe.onFireSnipe += OnFireSnipe;
			}

			private void OnFireSnipe(BaseFireSnipe state)
			{
				killCount = 0;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private bool CharacterIsInAir()
			{
				CharacterBody currentBody = base.networkUser.GetCurrentBody();
				if ((bool)currentBody && (bool)currentBody.characterMotor)
				{
					return !currentBody.characterMotor.isGrounded;
				}
				return false;
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if (damageReport.damageInfo.attacker == damageReport.damageInfo.inflictor && (object)damageReport.attackerMaster != null && (object)damageReport.attackerMaster == base.networkUser.master && CharacterIsInAir())
				{
					killCount++;
					if (requirement <= killCount)
					{
						Grant();
						ServerTryToCompleteActivity();
					}
				}
			}
		}

		private static readonly int requirement = 3;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("RailgunnerBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "RailgunnerAirborneMultiKill";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("RailgunnerClearGameMonsoon", "Skins.RailGunner.Alt1", null, 10u, null)]
	public class RailgunnerClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("RailgunnerBody");
		}
	}
	[RegisterAchievement("RailgunnerConsecutiveWeakPoints", "Skills.Railgunner.SecondaryAlt1", null, 3u, null)]
	public class RailgunnerConsecutiveWeakPointsAchievement : BaseAchievement
	{
		private const int requirement = 30;

		private int consecutiveCount;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("RailgunnerBody");
		}

		protected override void OnBodyRequirementMet()
		{
			BaseFireSnipe.onWeakPointHit += OnWeakPointHit;
			BaseFireSnipe.onWeakPointMissed += OnWeakPointMissed;
		}

		protected override void OnBodyRequirementBroken()
		{
			BaseFireSnipe.onWeakPointHit -= OnWeakPointHit;
			BaseFireSnipe.onWeakPointMissed -= OnWeakPointMissed;
			consecutiveCount = 0;
		}

		private void OnWeakPointMissed()
		{
			consecutiveCount = 0;
		}

		private void OnWeakPointHit(DamageInfo damageInfo)
		{
			consecutiveCount++;
			if (consecutiveCount >= 30)
			{
				Grant();
				TryToCompleteActivity();
			}
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "RailgunnerConsecutiveWeakPoints";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("RailgunnerDealMassiveDamage", "Skills.Railgunner.UtilityAlt1", null, 3u, null)]
	public class RailgunnerDealMassiveDamageAchievement : BaseAchievement
	{
		private const float minimumDamage = 1000000f;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("RailgunnerBody");
		}

		protected override void OnBodyRequirementMet()
		{
			GlobalEventManager.onClientDamageNotified += onClientDamageNotified;
		}

		protected override void OnBodyRequirementBroken()
		{
			GlobalEventManager.onClientDamageNotified -= onClientDamageNotified;
		}

		private void onClientDamageNotified(DamageDealtMessage message)
		{
			if ((object)message.attacker == base.localUser.cachedBodyObject && message.damage >= 1000000f)
			{
				Grant();
				TryToCompleteActivity();
			}
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "RailgunnerDealMassiveDamage";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("RailgunnerClearMeridianEvent", "Skins.RailGunner.Alt2", null, 5u, typeof(RailgunnerMeridianEventTriggerServerAchievement))]
	public class RailgunnerMeridianEventTriggerAchievement : BaseAchievement
	{
		private class RailgunnerMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("RailgunnerBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Merc
{
	[RegisterAchievement("MercClearGameMonsoon", "Skins.Merc.Alt1", "CompleteUnknownEnding", 10u, null)]
	public class MercClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MercBody");
		}
	}
	[RegisterAchievement("MercCompleteTrialWithFullHealth", "Skills.Merc.EvisProjectile", "CompleteUnknownEnding", 3u, typeof(MercCompleteTrialWithFullHealthServerAchievement))]
	public class MercCompleteTrialWithFullHealthAchievement : BaseAchievement
	{
		private class MercCompleteTrialWithFullHealthServerAchievement : BaseServerAchievement
		{
			private ToggleAction listenForDamage;

			private ToggleAction listenForGameOver;

			private bool failed;

			private bool runOk;

			public override void OnInstall()
			{
				base.OnInstall();
				listenForDamage = new ToggleAction(delegate
				{
					RoR2Application.onFixedUpdate += OnFixedUpdate;
				}, delegate
				{
					RoR2Application.onFixedUpdate -= OnFixedUpdate;
				});
				listenForGameOver = new ToggleAction(delegate
				{
					Run.onServerGameOver += OnServerGameOver;
				}, delegate
				{
					Run.onServerGameOver -= OnServerGameOver;
				});
				Run.onRunStartGlobal += OnRunStart;
				Run.onRunDestroyGlobal += OnRunDestroy;
				if ((bool)Run.instance)
				{
					OnRunDiscovered(Run.instance);
				}
			}

			public override void OnUninstall()
			{
				Run.onRunDestroyGlobal -= OnRunDestroy;
				Run.onRunStartGlobal -= OnRunStart;
				listenForGameOver.SetActive(newActive: false);
				listenForDamage.SetActive(newActive: false);
				base.OnUninstall();
			}

			private bool CharacterIsAtFullHealthOrNull()
			{
				CharacterBody currentBody = GetCurrentBody();
				if ((bool)currentBody)
				{
					return currentBody.healthComponent.fullCombinedHealth <= currentBody.healthComponent.combinedHealth;
				}
				return true;
			}

			private void OnFixedUpdate()
			{
				if (!CharacterIsAtFullHealthOrNull())
				{
					Fail();
				}
			}

			private void Fail()
			{
				failed = true;
				listenForDamage.SetActive(newActive: false);
				listenForGameOver.SetActive(newActive: false);
			}

			private void OnServerGameOver(Run run, GameEndingDef gameEndingDef)
			{
				if (gameEndingDef.isWin)
				{
					if (runOk && !failed)
					{
						Grant();
					}
					runOk = false;
				}
			}

			private void OnRunStart(Run run)
			{
				OnRunDiscovered(run);
			}

			private void OnRunDiscovered(Run run)
			{
				runOk = run is WeeklyRun;
				if (runOk)
				{
					listenForGameOver.SetActive(newActive: true);
					listenForDamage.SetActive(newActive: true);
					failed = false;
				}
			}

			private void OnRunDestroy(Run run)
			{
				OnRunLost(run);
			}

			private void OnRunLost(Run run)
			{
				listenForGameOver.SetActive(newActive: false);
				listenForDamage.SetActive(newActive: false);
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MercBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("MercDontTouchGround", "Skills.Merc.Uppercut", "CompleteUnknownEnding", 3u, null)]
	public class MercDontTouchGroundAchievement : BaseAchievement
	{
		private static readonly float requirement = 30f;

		private CharacterMotor motor;

		private CharacterBody body;

		private float stopwatch;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MercBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			RoR2Application.onFixedUpdate += MercFixedUpdate;
			base.localUser.onBodyChanged += OnBodyChanged;
			OnBodyChanged();
		}

		protected override void OnBodyRequirementBroken()
		{
			base.localUser.onBodyChanged -= OnBodyChanged;
			RoR2Application.onFixedUpdate -= MercFixedUpdate;
			base.OnBodyRequirementBroken();
		}

		private void OnBodyChanged()
		{
			body = base.localUser.cachedBody;
			motor = (body ? body.characterMotor : null);
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "MercDontTouchGround";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}

		private void MercFixedUpdate()
		{
			bool flag = (bool)motor && !motor.isGrounded && !body.currentVehicle;
			stopwatch = (flag ? (stopwatch + Time.fixedDeltaTime) : 0f);
			if (requirement <= stopwatch)
			{
				Grant();
				TryToCompleteActivity();
			}
		}
	}
	[RegisterAchievement("MercClearMeridianEvent", "Skins.Merc.Alt2", "CompleteUnknownEnding", 5u, typeof(MercMeridianEventTriggerServerAchievement))]
	public class MercMeridianEventTriggerAchievement : BaseAchievement
	{
		private class MercMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MercBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("MercXSkillsInYSeconds", "Skills.Merc.FocusedAssault", "CompleteUnknownEnding", 3u, null)]
	public class MercXSkillsInYSecondsAchievement : BaseAchievement
	{
		private static readonly int requiredSkillCount = 20;

		private static readonly float windowSecconds = 10f;

		private DoXInYSecondsTracker tracker;

		private CharacterBody _trackedBody;

		private CharacterBody trackedBody
		{
			get
			{
				return _trackedBody;
			}
			set
			{
				if ((object)_trackedBody != value)
				{
					if ((object)_trackedBody != null)
					{
						_trackedBody.onSkillActivatedAuthority -= OnSkillActivated;
					}
					_trackedBody = value;
					if ((object)_trackedBody != null)
					{
						_trackedBody.onSkillActivatedAuthority += OnSkillActivated;
					}
				}
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MercBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			trackedBody = base.localUser.cachedBody;
			base.localUser.onBodyChanged += OnBodyChanged;
			tracker.Clear();
		}

		protected override void OnBodyRequirementBroken()
		{
			if (base.localUser != null)
			{
				base.localUser.onBodyChanged -= OnBodyChanged;
			}
			trackedBody = null;
			base.OnBodyRequirementBroken();
			if (tracker != null)
			{
				tracker.Clear();
			}
		}

		private void OnBodyChanged()
		{
			trackedBody = base.localUser.cachedBody;
			tracker.Clear();
		}

		public override void OnInstall()
		{
			base.OnInstall();
			tracker = new DoXInYSecondsTracker(requiredSkillCount, windowSecconds);
		}

		public override void OnUninstall()
		{
			tracker = null;
			base.OnUninstall();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "MercXSkillsInYSeconds";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}

		private void OnSkillActivated(GenericSkill skill)
		{
			if (tracker.Push(Run.FixedTimeStamp.now.t))
			{
				Grant();
				TryToCompleteActivity();
			}
		}
	}
}
namespace RoR2.Achievements.Mage
{
	[RegisterAchievement("MageAirborneMultiKill", "Skills.Mage.FlyUp", "FreeMage", 3u, typeof(MageAirborneMultiKillServerAchievement))]
	public class MageAirborneMultiKillAchievement : BaseAchievement
	{
		private class MageAirborneMultiKillServerAchievement : BaseServerAchievement
		{
			private int killCount;

			public override void OnInstall()
			{
				base.OnInstall();
				RoR2Application.onFixedUpdate += OnFixedUpdate;
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				RoR2Application.onFixedUpdate -= OnFixedUpdate;
				base.OnUninstall();
			}

			private bool CharacterIsInAir()
			{
				CharacterBody currentBody = base.networkUser.GetCurrentBody();
				if ((bool)currentBody && (bool)currentBody.characterMotor)
				{
					return !currentBody.characterMotor.isGrounded;
				}
				return false;
			}

			private void OnFixedUpdate()
			{
				if (!CharacterIsInAir())
				{
					killCount = 0;
				}
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if ((object)damageReport.attackerMaster == base.networkUser.master && (object)damageReport.attackerMaster != null && CharacterIsInAir())
				{
					killCount++;
					if (requirement <= killCount)
					{
						Grant();
						ServerTryToCompleteActivity();
					}
				}
			}
		}

		private static readonly int requirement = 15;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MageBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "MageAirborneMultiKill";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("MageClearGameMonsoon", "Skins.Mage.Alt1", "FreeMage", 10u, null)]
	public class MageClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MageBody");
		}
	}
	[RegisterAchievement("MageFastBoss", "Skills.Mage.IceBomb", "FreeMage", 3u, typeof(MageFastBossServerAchievement))]
	public class MageFastBossAchievement : BaseAchievement
	{
		private class MageFastBossServerAchievement : BaseServerAchievement
		{
			private ToggleAction listenForBossDamage;

			private ToggleAction listenForBossDefeated;

			private Run.FixedTimeStamp expirationTimeStamp;

			private void OnBossDamageFirstTaken()
			{
				expirationTimeStamp = Run.FixedTimeStamp.now + window;
				listenForBossDamage.SetActive(newActive: false);
				listenForBossDefeated.SetActive(newActive: true);
			}

			public override void OnInstall()
			{
				base.OnInstall();
				listenForBossDamage = new ToggleAction(delegate
				{
					GlobalEventManager.onServerDamageDealt += OnServerDamageDealt;
				}, delegate
				{
					GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt;
				});
				listenForBossDefeated = new ToggleAction(delegate
				{
					BossGroup.onBossGroupDefeatedServer += OnBossGroupDefeatedServer;
				}, delegate
				{
					BossGroup.onBossGroupDefeatedServer -= OnBossGroupDefeatedServer;
				});
				BossGroup.onBossGroupStartServer += OnBossGroupStartServer;
				Run.onRunStartGlobal += OnRunStart;
				Reset();
			}

			public override void OnUninstall()
			{
				BossGroup.onBossGroupStartServer -= OnBossGroupStartServer;
				listenForBossDefeated.SetActive(newActive: false);
				listenForBossDamage.SetActive(newActive: false);
				base.OnUninstall();
			}

			private void OnRunStart(Run run)
			{
				Reset();
			}

			private void Reset()
			{
				expirationTimeStamp = Run.FixedTimeStamp.negativeInfinity;
				listenForBossDefeated.SetActive(newActive: false);
				listenForBossDamage.SetActive(newActive: false);
			}

			private static bool BossGroupIsTeleporterBoss(BossGroup bossGroup)
			{
				return bossGroup.GetComponent<TeleporterInteraction>();
			}

			private void OnBossGroupStartServer(BossGroup bossGroup)
			{
				if (BossGroupIsTeleporterBoss(bossGroup))
				{
					listenForBossDamage.SetActive(newActive: true);
				}
			}

			private void OnServerDamageDealt(DamageReport damageReport)
			{
				if ((bool)damageReport.victimMaster && damageReport.victimMaster.isBoss)
				{
					OnBossDamageFirstTaken();
				}
			}

			private void OnBossGroupDefeatedServer(BossGroup bossGroup)
			{
				if (BossGroupIsTeleporterBoss(bossGroup) && !expirationTimeStamp.hasPassed)
				{
					Grant();
					ServerTryToCompleteActivity();
				}
			}
		}

		private static readonly float window = 1f;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MageBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "MageFastBoss";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("MageClearMeridianEvent", "Skins.Mage.Alt2", "FreeMage", 5u, typeof(MageMeridianEventTriggerServerAchievement))]
	public class MageMeridianEventTriggerAchievement : BaseAchievement
	{
		private class MageMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MageBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	public class MageMultiExecuteAchievement : BaseAchievement
	{
		private class MageMultiExecuteServerAchievement : BaseServerAchievement
		{
			private DoXInYSecondsTracker tracker;

			public override void OnInstall()
			{
				base.OnInstall();
				tracker = new DoXInYSecondsTracker(requirement, window);
				Run.onRunStartGlobal += OnRunStart;
				GlobalEventManager.onServerCharacterExecuted += OnServerCharacterExecuted;
			}

			public override void OnUninstall()
			{
				Run.onRunStartGlobal -= OnRunStart;
				GlobalEventManager.onServerCharacterExecuted -= OnServerCharacterExecuted;
				base.OnUninstall();
			}

			private void OnRunStart(Run run)
			{
				tracker.Clear();
			}

			private void OnServerCharacterExecuted(DamageReport damageReport, float executionHealthLost)
			{
				if ((object)damageReport.attackerMaster == base.networkUser.master && (object)base.networkUser.master != null && tracker.Push(Run.FixedTimeStamp.now.t))
				{
					Grant();
				}
			}
		}

		private static int requirement = 10;

		private static float window = 10f;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MageBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("MageMultiKill", "Skills.Mage.LightningBolt", "FreeMage", 3u, typeof(MageMultiKillServerAchievement))]
	public class MageMultiKillAchievement : BaseAchievement
	{
		private class MageMultiKillServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				RoR2Application.onFixedUpdate += OnFixedUpdate;
			}

			public override void OnUninstall()
			{
				RoR2Application.onFixedUpdate -= OnFixedUpdate;
				base.OnUninstall();
			}

			private void OnFixedUpdate()
			{
				CharacterBody currentBody = GetCurrentBody();
				if ((bool)currentBody && requirement <= currentBody.multiKillCount)
				{
					Grant();
					ServerTryToCompleteActivity();
				}
			}
		}

		private static readonly int requirement = 20;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("MageBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "MageMultiKill";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
}
namespace RoR2.Achievements.Loader
{
	[RegisterAchievement("LoaderClearGameMonsoon", "Skins.Loader.Alt1", "DefeatSuperRoboBallBoss", 10u, null)]
	public class LoaderClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("LoaderBody");
		}
	}
	[RegisterAchievement("LoaderClearMeridianEvent", "Skins.Loader.Alt2", "DefeatSuperRoboBallBoss", 5u, typeof(LoaderMeridianEventTriggerServerAchievement))]
	public class LoaderMeridianEventTriggerAchievement : BaseAchievement
	{
		private class LoaderMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("LoaderBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("LoaderSpeedRun", "Skills.Loader.YankHook", "DefeatSuperRoboBallBoss", 3u, null)]
	public class LoaderSpeedRunAchievement : BaseAchievement
	{
		private SceneDef requiredSceneDef;

		private static readonly float requirement = 1500f;

		public override void OnInstall()
		{
			base.OnInstall();
			requiredSceneDef = SceneCatalog.GetSceneDefFromSceneName("mysteryspace");
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("LoaderBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SceneCatalog.onMostRecentSceneDefChanged += OnMostRecentSceneDefChanged;
		}

		private void OnMostRecentSceneDefChanged(SceneDef sceneDef)
		{
			if (sceneDef == requiredSceneDef && Run.instance.GetRunStopwatch() <= requirement)
			{
				Grant();
			}
		}

		protected override void OnBodyRequirementBroken()
		{
			SceneCatalog.onMostRecentSceneDefChanged -= OnMostRecentSceneDefChanged;
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Huntress
{
	[RegisterAchievement("HuntressAllGlaiveBouncesKill", "Skills.Huntress.FlurryArrow", null, 3u, typeof(HuntressAllGlaiveBouncesKillServerAchievement))]
	public class HuntressAllGlaiveBouncesKillAchievement : BaseAchievement
	{
		private class HuntressAllGlaiveBouncesKillServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				LightningOrb.onLightningOrbKilledOnAllBounces += OnLightningOrbKilledOnAllBounces;
			}

			private void OnLightningOrbKilledOnAllBounces(LightningOrb lightningOrb)
			{
				CharacterBody currentBody = base.networkUser.GetCurrentBody();
				if ((bool)currentBody && lightningOrb.attacker == currentBody.gameObject && lightningOrb.lightningType == LightningOrb.LightningType.HuntressGlaive)
				{
					Grant();
					ServerTryToCompleteActivity();
				}
			}

			public override void OnUninstall()
			{
				LightningOrb.onLightningOrbKilledOnAllBounces -= OnLightningOrbKilledOnAllBounces;
				base.OnUninstall();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("HuntressBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			bool flag = base.localUser.id == LocalUserManager.GetFirstLocalUser().id;
			if (shouldGrant && flag)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "HuntressAllGlaiveBouncesKill";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("HuntressClearGameMonsoon", "Skins.Huntress.Alt1", null, 10u, null)]
	public class HuntressClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("HuntressBody");
		}
	}
	[RegisterAchievement("HuntressCollectCrowbars", "Skills.Huntress.MiniBlink", null, 3u, null)]
	public class HuntressCollectCrowbarsAchievement : BaseAchievement
	{
		private Inventory currentInventory;

		private static readonly int requirement = 12;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("HuntressBody");
		}

		public override void OnInstall()
		{
			base.OnInstall();
		}

		public override void OnUninstall()
		{
			SetCurrentInventory(null);
			base.OnUninstall();
		}

		private void UpdateInventory()
		{
			Inventory inventory = null;
			if ((bool)base.localUser.cachedMasterController)
			{
				inventory = base.localUser.cachedMasterController.master.inventory;
			}
			SetCurrentInventory(inventory);
		}

		private void SetCurrentInventory(Inventory newInventory)
		{
			if ((object)currentInventory != newInventory)
			{
				if ((object)currentInventory != null)
				{
					currentInventory.onInventoryChanged -= OnInventoryChanged;
				}
				currentInventory = newInventory;
				if ((object)currentInventory != null)
				{
					currentInventory.onInventoryChanged += OnInventoryChanged;
					OnInventoryChanged();
				}
			}
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			base.localUser.onMasterChanged += UpdateInventory;
			UpdateInventory();
		}

		protected override void OnBodyRequirementBroken()
		{
			base.localUser.onMasterChanged -= UpdateInventory;
			SetCurrentInventory(null);
			base.OnBodyRequirementBroken();
		}

		private void OnInventoryChanged()
		{
			if (requirement <= currentInventory.GetItemCount(RoR2Content.Items.Crowbar))
			{
				Grant();
				TryToCompleteActivity();
			}
		}

		public override void TryToCompleteActivity()
		{
			bool flag = base.localUser.id == LocalUserManager.GetFirstLocalUser().id;
			if (shouldGrant && flag)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "HuntressCollectCrowbars";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("HuntressMaintainFullHealthOnFrozenWall", "Skills.Huntress.Snipe", null, 3u, null)]
	public class HuntressMaintainFullHealthOnFrozenWallAchievement : BaseAchievement
	{
		private static readonly string[] requiredScenes = new string[2] { "frozenwall", "wispgraveyard" };

		private HealthComponent healthComponent;

		private bool failed;

		private bool sceneOk;

		private bool characterOk;

		private ToggleAction healthCheck;

		private ToggleAction teleporterCheck;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("HuntressBody");
		}

		private void SubscribeHealthCheck()
		{
			RoR2Application.onFixedUpdate += CheckHealth;
		}

		private void UnsubscribeHealthCheck()
		{
			RoR2Application.onFixedUpdate -= CheckHealth;
		}

		private void SubscribeTeleporterCheck()
		{
			TeleporterInteraction.onTeleporterChargedGlobal += CheckTeleporter;
		}

		private void UnsubscribeTeleporterCheck()
		{
			TeleporterInteraction.onTeleporterChargedGlobal -= CheckTeleporter;
		}

		private void CheckTeleporter(TeleporterInteraction teleporterInteraction)
		{
			if (sceneOk && characterOk && !failed)
			{
				Grant();
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			healthCheck = new ToggleAction(SubscribeHealthCheck, UnsubscribeHealthCheck);
			teleporterCheck = new ToggleAction(SubscribeTeleporterCheck, UnsubscribeTeleporterCheck);
			SceneCatalog.onMostRecentSceneDefChanged += OnMostRecentSceneDefChanged;
			base.localUser.onBodyChanged += OnBodyChanged;
		}

		public override void OnUninstall()
		{
			base.localUser.onBodyChanged -= OnBodyChanged;
			SceneCatalog.onMostRecentSceneDefChanged -= OnMostRecentSceneDefChanged;
			healthCheck.Dispose();
			teleporterCheck.Dispose();
			base.OnUninstall();
		}

		private void OnBodyChanged()
		{
			if (sceneOk && characterOk && !failed && (bool)base.localUser.cachedBody)
			{
				healthComponent = base.localUser.cachedBody.healthComponent;
				healthCheck.SetActive(newActive: true);
				teleporterCheck.SetActive(newActive: true);
			}
		}

		private void OnMostRecentSceneDefChanged(SceneDef sceneDef)
		{
			sceneOk = Array.IndexOf(requiredScenes, sceneDef.baseSceneName) != -1;
			if (sceneOk)
			{
				failed = false;
			}
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			characterOk = true;
		}

		protected override void OnBodyRequirementBroken()
		{
			characterOk = false;
			Fail();
			base.OnBodyRequirementBroken();
		}

		private void Fail()
		{
			failed = true;
			healthCheck.SetActive(newActive: false);
			teleporterCheck.SetActive(newActive: false);
		}

		private void CheckHealth()
		{
			if ((bool)healthComponent && healthComponent.combinedHealth < healthComponent.fullCombinedHealth)
			{
				Fail();
			}
		}
	}
	[RegisterAchievement("HuntressClearMeridianEvent", "Skins.Huntress.Alt2", null, 5u, typeof(HuntressMeridianEventTriggerServerAchievement))]
	public class HuntressMeridianEventTriggerAchievement : BaseAchievement
	{
		private class HuntressMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("HuntressBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.FalseSon
{
	[RegisterAchievement("FalseSonLaserMultiKill", "Skills.FalseSon.LaserBurst", "UnlockFalseSon", 3u, typeof(FalseSonLaserMultiKillServerAchievement))]
	public class FalseSonLaserMultiKill : BaseAchievement
	{
		private class FalseSonLaserMultiKillServerAchievement : BaseServerAchievement
		{
			private int killCount;

			private float localLaserDuration;

			public override void OnInstall()
			{
				base.OnInstall();
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
				LaserFatherCharged.laserTracking += TrackLaserActivation;
			}

			public override void OnUninstall()
			{
				LaserFatherCharged.laserTracking -= TrackLaserActivation;
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void TrackLaserActivation(float laserDuration)
			{
				localLaserDuration = laserDuration;
				if (localLaserDuration <= 0f)
				{
					killCount = 0;
				}
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if (localLaserDuration > 0f && (object)damageReport.attackerMaster != null && (object)damageReport.attackerMaster == base.networkUser.master && (bool)damageReport.victimBody && (damageReport.victimBody.bodyFlags & CharacterBody.BodyFlags.Masterless) == 0)
				{
					killCount++;
					if (requirement <= killCount)
					{
						Grant();
					}
				}
			}
		}

		private static readonly int requirement = 15;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("FalseSonBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("FalseSonClearGameMonsoon", "Skins.FalseSon.Alt1", "UnlockFalseSon", 10u, null)]
	public class FalseSonClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("FalseSonBody");
		}
	}
}
namespace RoR2.Achievements.Engi
{
	[RegisterAchievement("EngiArmy", "Skills.Engi.WalkerTurret", "Complete30StagesCareer", 3u, null)]
	public class EngiArmyAchievement : BaseAchievement
	{
		private static readonly int requirement = 12;

		private ToggleAction monitorMinions;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("EngiBody");
		}

		private void SubscribeToMinionChanges()
		{
			MinionOwnership.onMinionGroupChangedGlobal += OnMinionGroupChangedGlobal;
		}

		private void UnsubscribeFromMinionChanges()
		{
			MinionOwnership.onMinionGroupChangedGlobal -= OnMinionGroupChangedGlobal;
		}

		private void OnMinionGroupChangedGlobal(MinionOwnership minion)
		{
			if (requirement > (minion.group?.memberCount ?? 0))
			{
				return;
			}
			CharacterMaster master = base.localUser.cachedMasterController.master;
			if ((bool)master)
			{
				NetworkInstanceId netId = master.netId;
				if (minion.group.ownerId == netId)
				{
					Grant();
					TryToCompleteActivity();
				}
			}
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "EngiArmy";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			monitorMinions = new ToggleAction(SubscribeToMinionChanges, UnsubscribeFromMinionChanges);
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			monitorMinions.SetActive(newActive: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			monitorMinions.SetActive(newActive: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("EngiClearGameMonsoon", "Skins.Engi.Alt1", "Complete30StagesCareer", 10u, null)]
	public class EngiClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("EngiBody");
		}
	}
	[RegisterAchievement("EngiClearTeleporterWithZeroMonsters", "Skills.Engi.Harpoon", "Complete30StagesCareer", 3u, null)]
	public class EngiClearTeleporterWithZeroMonstersAchievement : BaseAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("EngiBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterChargedGlobal;
		}

		protected override void OnBodyRequirementBroken()
		{
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterChargedGlobal;
			base.OnBodyRequirementBroken();
		}

		private void OnTeleporterChargedGlobal(TeleporterInteraction teleporterInteraction)
		{
			if (!base.isUserAlive)
			{
				return;
			}
			foreach (TeamComponent teamMember in TeamComponent.GetTeamMembers(TeamIndex.Monster))
			{
				if (teamMember.body.healthComponent.alive)
				{
					return;
				}
			}
			Grant();
			TryToCompleteActivity();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "EngiClearTeleporterWithZeroMonsters";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("EngiKillBossQuick", "Skills.Engi.SpiderMine", "Complete30StagesCareer", 3u, typeof(EngiKillBossQuickServerAchievement))]
	public class EngiKillBossQuickAchievement : BaseAchievement
	{
		private class EngiKillBossQuickServerAchievement : BaseServerAchievement
		{
			private const float requirement = 5f;

			public override void OnInstall()
			{
				base.OnInstall();
				BossGroup.onBossGroupDefeatedServer += OnBossGroupDefeatedServer;
			}

			public override void OnUninstall()
			{
				BossGroup.onBossGroupDefeatedServer -= OnBossGroupDefeatedServer;
				base.OnUninstall();
			}

			private void OnBossGroupDefeatedServer(BossGroup bossGroup)
			{
				if (bossGroup.fixedTimeSinceEnabled <= 5f)
				{
					Grant();
					ServerTryToCompleteActivity();
				}
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("EngiBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "EngiKillBossQuick";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("EngiClearMeridianEvent", "Skins.Engi.Alt2", "Complete30StagesCareer", 5u, typeof(EngiMeridianEventTriggerServerAchievement))]
	public class EngiMeridianEventTriggerAchievement : BaseAchievement
	{
		private class EngiMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("EngiBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Croco
{
	[RegisterAchievement("CrocoKillScavenger", "Skills.Croco.CrocoBite", "BeatArena", 3u, typeof(CrocoKillScavengerServerAchievement))]
	public class CrocoKillScavengerAchievement : BaseAchievement
	{
		private class CrocoKillScavengerServerAchievement : BaseServerAchievement
		{
			private BodyIndex requiredVictimBodyIndex;

			public override void OnInstall()
			{
				base.OnInstall();
				requiredVictimBodyIndex = BodyCatalog.FindBodyIndex("ScavBody");
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				base.OnUninstall();
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if (damageReport.victimBodyIndex == requiredVictimBodyIndex && serverAchievementTracker.networkUser.master == damageReport.attackerMaster)
				{
					Grant();
				}
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CrocoBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("CrocoKillWeakEnemiesMilestone", "Skills.Croco.PassivePoisonLethal", "BeatArena", 3u, null)]
	public class CrocoKillWeakEnemiesMilestoneAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalCrocoWeakEnemyKills;

		protected override ulong statRequirement => 50uL;

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "CrocoKillWeakEnemiesMilestone";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("CrocoClearMeridianEvent", "Skins.Croco.Alt2", "BeatArena", 5u, typeof(CrocoMeridianEventTriggerServerAchievement))]
	public class CrocoMeridianEventTriggerAchievement : BaseAchievement
	{
		private class CrocoMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CrocoBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("CrocoTotalInfectionsMilestone", "Skills.Croco.ChainableLeap", "BeatArena", 3u, null)]
	public class CrocoTotalInfectionsMilestoneAchievement : BaseStatMilestoneAchievement
	{
		protected override StatDef statDef => StatDef.totalCrocoInfectionsInflicted;

		protected override ulong statRequirement => 1000uL;

		public override void TryToCompleteActivity()
		{
			if (base.localUser.id == LocalUserManager.GetFirstLocalUser().id && shouldGrant)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "CrocoTotalInfectionsMilestone";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
}
namespace RoR2.Achievements.Chef
{
	[RegisterAchievement("ActivateChef", "Characters.Chef", null, 3u, typeof(ActivateChefServerAchievement))]
	public class ActivateChefAchievement : BaseAchievement
	{
		private class ActivateChefServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				WokController.chefRecipeComplete += OnRecipeComplete;
			}

			public override void OnUninstall()
			{
				base.OnInstall();
				WokController.chefRecipeComplete -= OnRecipeComplete;
			}

			private void OnRecipeComplete(Interactor interactor)
			{
				CharacterBody currentBody = serverAchievementTracker.networkUser.GetCurrentBody();
				if ((bool)currentBody && currentBody.GetComponent<Interactor>() == interactor)
				{
					Grant();
				}
			}
		}

		public override void OnInstall()
		{
			base.OnInstall();
			SetServerTracked(shouldTrack: true);
		}

		public override void OnUninstall()
		{
			base.OnUninstall();
		}
	}
	[RegisterAchievement("BarbecueQuantityBisonInRun", "Skills.Chef.YesChef", "ActivateChef", 3u, typeof(ChefAlternateSpecialBarbecueBisonServer))]
	public class ChefAlternateSpecialBarbecueBison : BaseAchievement
	{
		private class ChefAlternateSpecialBarbecueBisonServer : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if ((object)damageReport.attackerMaster == base.networkUser.master && (object)damageReport.attackerMaster != null && damageReport.victimBody.baseNameToken == "BISON_BODY_NAME" && damageReport.victimBody.HasBuff(DLC2Content.Buffs.CookingFlambe) && damageReport.victimBody.HasBuff(DLC2Content.Buffs.CookingRoasted))
				{
					PlayerStatsComponent masterPlayerStatsComponent = base.networkUser.masterPlayerStatsComponent;
					if ((bool)masterPlayerStatsComponent)
					{
						masterPlayerStatsComponent.currentStats.PushStatValue(StatDef.chefAlternateSpecialBarbecueBisonAchievementProgress, 1uL);
					}
				}
			}
		}

		private ulong requirement = 10uL;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("ChefBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(Check));
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
			UserProfile obj = base.userProfile;
			obj.onStatsReceived = (Action)Delegate.Remove(obj.onStatsReceived, new Action(Check));
		}

		private void Check()
		{
			if (base.userProfile.statSheet.GetStatValueULong(StatDef.chefAlternateSpecialBarbecueBisonAchievementProgress) >= requirement)
			{
				Grant();
			}
		}

		public override float ProgressForAchievement()
		{
			return (float)base.userProfile.statSheet.GetStatValueULong(StatDef.chefAlternateSpecialBarbecueBisonAchievementProgress) / (float)requirement;
		}
	}
	[RegisterAchievement("ChefClearGameMonsoon", "Skins.Chef.Alt1", "ActivateChef", 10u, null)]
	public class ChefClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("ChefBody");
		}
	}
}
namespace RoR2.Achievements.Captain
{
	[RegisterAchievement("CaptainClearMeridianEvent", "Skins.Captain.Alt2", "CompleteMainEnding", 5u, typeof(CaptainMeridianEventTriggerServerAchievement))]
	public class CaptainMeridianEventTriggerAchievement : BaseAchievement
	{
		private class CaptainMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CaptainBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("CaptainSupplyDropFinale", "Skills.Captain.UtilityAlt1", "CompleteMainEnding", 3u, typeof(CaptainSupplyDropFinaleServerAchievement))]
	public class CaptainSupplyDropFinaleAchievement : BaseAchievement
	{
		private class CaptainSupplyDropFinaleServerAchievement : BaseServerAchievement
		{
			private const float lastHitWindowSeconds = 0.1f;

			private BodyIndex requiredVictimBodyIndex;

			private float lastHitTime;

			public override void OnInstall()
			{
				base.OnInstall();
				requiredVictimBodyIndex = BodyCatalog.FindBodyIndex("BrotherHurtBody");
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
				GlobalEventManager.onServerDamageDealt += OnServerDamageDealt;
				lastHitTime = float.NegativeInfinity;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt;
				base.OnUninstall();
			}

			private void OnServerDamageDealt(DamageReport damageReport)
			{
				if (damageReport.victimBodyIndex == requiredVictimBodyIndex && DoesDamageQualify(damageReport) && (object)serverAchievementTracker.networkUser.master == damageReport.attackerMaster && (bool)damageReport.attackerMaster)
				{
					lastHitTime = Run.FixedTimeStamp.now.t;
				}
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if (damageReport.victimBodyIndex == requiredVictimBodyIndex && (object)serverAchievementTracker.networkUser.master == damageReport.attackerMaster && (bool)damageReport.attackerMaster && (DoesDamageQualify(damageReport) || Run.FixedTimeStamp.now.t - lastHitTime <= 0.1f))
				{
					Grant();
				}
			}

			private bool DoesDamageQualify(DamageReport damageReport)
			{
				GenericDisplayNameProvider component = damageReport.damageInfo.inflictor.GetComponent<GenericDisplayNameProvider>();
				if ((bool)component && component.displayToken != null)
				{
					return component.displayToken.StartsWith("CAPTAIN_SUPPLY_");
				}
				return false;
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CaptainBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
}
namespace RoR2.Achievements.Commando
{
	[RegisterAchievement("CaptainClearGameMonsoon", "Skins.Captain.Alt1", "CompleteMainEnding", 10u, null)]
	public class CaptainClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CaptainBody");
		}
	}
	[RegisterAchievement("CommandoClearGameMonsoon", "Skins.Commando.Alt1", null, 10u, null)]
	public class CommandoClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CommandoBody");
		}
	}
	[RegisterAchievement("CommandoFastFirstStageClear", "Skills.Commando.SlideJet", null, 3u, null)]
	public class CommandoFastFirstStageClearAchievement : BaseAchievement
	{
		private static readonly float timeRequirement = 300f;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CommandoBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			TeleporterInteraction.onTeleporterChargedGlobal += OnTeleporterChargedGlobal;
		}

		private void OnTeleporterChargedGlobal(TeleporterInteraction teleporterInteraction)
		{
			if (Run.instance.GetRunStopwatch() < timeRequirement && Run.instance.stageClearCount == 0 && base.isUserAlive)
			{
				Grant();
			}
		}

		protected override void OnBodyRequirementBroken()
		{
			TeleporterInteraction.onTeleporterChargedGlobal -= OnTeleporterChargedGlobal;
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("CommandoKillOverloadingWorm", "Skills.Commando.FireShotgunBlast", null, 3u, typeof(CommandoKillOverloadingWormServerAchievement))]
	public class CommandoKillOverloadingWormAchievement : BaseAchievement
	{
		public class CommandoKillOverloadingWormServerAchievement : BaseServerAchievement
		{
			private BodyIndex overloadingWormBodyIndex;

			public override void OnInstall()
			{
				base.OnInstall();
				overloadingWormBodyIndex = BodyCatalog.FindBodyIndex("ElectricWormBody");
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeath;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeath;
				base.OnUninstall();
			}

			private void OnCharacterDeath(DamageReport damageReport)
			{
				if ((bool)damageReport.victimBody && damageReport.victimBody.bodyIndex == overloadingWormBodyIndex && IsCurrentBody(damageReport.damageInfo.attacker))
				{
					Grant();
				}
			}
		}

		private int commandoBodyIndex;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CommandoBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("CommandoClearMeridianEvent", "Skins.Commando.Alt2", null, 5u, typeof(CommandoMeridianEventTriggerServerAchievement))]
	public class CommandoMeridianEventTriggerAchievement : BaseAchievement
	{
		private class CommandoMeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CommandoBody");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("CommandoNonLunarEndurance", "Skills.Commando.ThrowGrenade", null, 3u, null)]
	public class CommandoNonLunarEnduranceAchievement : BaseAchievement
	{
		private static readonly ulong requirement = 20uL;

		private PlayerCharacterMasterController cachedMasterController;

		private PlayerStatsComponent cachedStatsComponent;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CommandoBody");
		}

		private static bool EverPickedUpLunarItems(StatSheet statSheet)
		{
			foreach (ItemIndex lunarItem in ItemCatalog.lunarItemList)
			{
				if (statSheet.GetStatValueULong(PerItemStatDef.totalCollected.FindStatDef(lunarItem)) != 0)
				{
					return true;
				}
			}
			foreach (EquipmentIndex equipment in EquipmentCatalog.equipmentList)
			{
				if (EquipmentCatalog.GetEquipmentDef(equipment).isLunar && statSheet.GetStatValueDouble(PerEquipmentStatDef.totalTimeHeld.FindStatDef(equipment)) > 0.0)
				{
					return true;
				}
			}
			return false;
		}

		private void OnMasterChanged()
		{
			if (base.localUser != null)
			{
				SetMasterController(base.localUser.cachedMasterController);
			}
		}

		private void SetMasterController(PlayerCharacterMasterController playerCharacterMasterController)
		{
			if ((object)base.localUser.cachedMasterController == cachedMasterController)
			{
				return;
			}
			bool num = (object)cachedStatsComponent != null;
			cachedMasterController = base.localUser.cachedMasterController;
			cachedStatsComponent = (cachedMasterController ? cachedMasterController.GetComponent<PlayerStatsComponent>() : null);
			bool flag = (object)cachedStatsComponent != null;
			if (num != flag && base.userProfile != null)
			{
				if (flag)
				{
					UserProfile obj = base.userProfile;
					obj.onStatsReceived = (Action)Delegate.Combine(obj.onStatsReceived, new Action(OnStatsChanged));
				}
				else
				{
					UserProfile obj2 = base.userProfile;
					obj2.onStatsReceived = (Action)Delegate.Remove(obj2.onStatsReceived, new Action(OnStatsChanged));
				}
			}
		}

		private void OnStatsChanged()
		{
			if ((object)cachedStatsComponent != null && requirement <= cachedStatsComponent.currentStats.GetStatValueULong(StatDef.totalStagesCompleted))
			{
				if (EverPickedUpLunarItems(cachedStatsComponent.currentStats))
				{
					SetMasterController(null);
					return;
				}
				Grant();
				TryToCompleteActivity();
			}
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			base.localUser.onMasterChanged += OnMasterChanged;
			OnMasterChanged();
		}

		protected override void OnBodyRequirementBroken()
		{
			base.localUser.onMasterChanged -= OnMasterChanged;
			SetMasterController(null);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			bool flag = base.localUser.id == LocalUserManager.GetFirstLocalUser().id;
			if (shouldGrant && flag)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "CommandoNonLunarEndurance";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("CrocoClearGameMonsoon", "Skins.Croco.Alt1", "BeatArena", 10u, null)]
	public class CrocoClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("CrocoBody");
		}
	}
}
namespace RoR2.Achievements.Bandit2
{
	[RegisterAchievement("Bandit2ClearGameMonsoon", "Skins.Bandit2.Alt1", "CompleteThreeStages", 10u, null)]
	public class Bandit2ClearGameMonsoonAchievement : BasePerSurvivorClearGameMonsoonAchievement
	{
		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("Bandit2Body");
		}
	}
	[RegisterAchievement("Bandit2ConsecutiveReset", "Skills.Bandit2.Rifle", "CompleteThreeStages", 3u, typeof(Bandit2ConsecutiveResetServerAchievement))]
	public class Bandit2ConsecutiveResetAchievement : BaseAchievement
	{
		private class Bandit2ConsecutiveResetServerAchievement : BaseServerAchievement
		{
			private int progress;

			private SkillDef requiredSkillDef;

			private bool waitingForKill;

			private CharacterBody _trackedBody;

			private CharacterBody trackedBody
			{
				get
				{
					return _trackedBody;
				}
				set
				{
					if ((object)_trackedBody != value)
					{
						if ((object)_trackedBody != null)
						{
							_trackedBody.onSkillActivatedServer -= OnBodySKillActivatedServer;
						}
						_trackedBody = value;
						if ((object)_trackedBody != null)
						{
							_trackedBody.onSkillActivatedServer += OnBodySKillActivatedServer;
							progress = 0;
							waitingForKill = false;
						}
					}
				}
			}

			private void OnBodySKillActivatedServer(GenericSkill skillSlot)
			{
				if ((object)skillSlot.skillDef == requiredSkillDef && (object)requiredSkillDef != null)
				{
					if (waitingForKill)
					{
						progress = 0;
					}
					waitingForKill = true;
				}
			}

			public override void OnInstall()
			{
				base.OnInstall();
				requiredSkillDef = SkillCatalog.GetSkillDef(SkillCatalog.FindSkillIndexByName("Bandit2.ResetRevolver"));
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
				RoR2Application.onFixedUpdate += FixedUpdate;
			}

			public override void OnUninstall()
			{
				trackedBody = null;
				RoR2Application.onFixedUpdate -= FixedUpdate;
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				base.OnUninstall();
			}

			private void FixedUpdate()
			{
				trackedBody = GetCurrentBody();
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if ((DamageType)(damageReport.damageInfo.damageType & DamageType.ResetCooldownsOnKill) == DamageType.ResetCooldownsOnKill && !(damageReport.attackerBody == null) && (object)damageReport.attackerBody == trackedBody)
				{
					waitingForKill = false;
					progress++;
					if (progress >= requirement)
					{
						Grant();
						ServerTryToCompleteActivity();
					}
				}
			}
		}

		private static readonly int requirement = 15;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("Bandit2Body");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			bool flag = base.localUser.id == LocalUserManager.GetFirstLocalUser().id;
			if (shouldGrant && flag)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "Bandit2ConsecutiveReset";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
	[RegisterAchievement("Bandit2ClearMeridianEvent", "Skins.Bandit2.Alt2", "CompleteThreeStages", 5u, typeof(Bandit2MeridianEventTriggerServerAchievement))]
	public class Bandit2MeridianEventTriggerAchievement : BaseAchievement
	{
		private class Bandit2MeridianEventTriggerServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				SkyJumpDeathState.falseSonDeathEvent += OnMeridianEventTriggerActivated;
			}

			public override void OnUninstall()
			{
				base.OnUninstall();
				SkyJumpDeathState.falseSonDeathEvent -= OnMeridianEventTriggerActivated;
			}

			private void OnMeridianEventTriggerActivated()
			{
				Grant();
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("Bandit2Body");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("Bandit2RevolverFinale", "Skills.Bandit2.SkullRevolver", "CompleteThreeStages", 3u, typeof(Bandit2RevolverFinaleServerAchievement))]
	public class Bandit2RevolverFinaleAchievement : BaseAchievement
	{
		private class Bandit2RevolverFinaleServerAchievement : BaseServerAchievement
		{
			private const float lastHitWindowSeconds = 0.1f;

			private List<BodyIndex> requiredVictimBodyIndices;

			private float lastHitTime;

			public override void OnInstall()
			{
				base.OnInstall();
				requiredVictimBodyIndices = new List<BodyIndex>();
				requiredVictimBodyIndices.Add(BodyCatalog.FindBodyIndex("BrotherHurtBody"));
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
				GlobalEventManager.onServerDamageDealt += OnServerDamageDealt;
				lastHitTime = float.NegativeInfinity;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				GlobalEventManager.onServerDamageDealt -= OnServerDamageDealt;
				base.OnUninstall();
			}

			private void OnServerDamageDealt(DamageReport damageReport)
			{
				if (DoesDamageQualify(damageReport) && !(damageReport.attackerMaster == null) && (object)serverAchievementTracker.networkUser.master == damageReport.attackerMaster && requiredVictimBodyIndices.Contains(damageReport.victimBodyIndex))
				{
					lastHitTime = Run.FixedTimeStamp.now.t;
				}
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if ((DoesDamageQualify(damageReport) || !(Run.FixedTimeStamp.now.t - lastHitTime > 0.1f)) && !(damageReport.attackerMaster == null) && (object)serverAchievementTracker.networkUser.master == damageReport.attackerMaster && requiredVictimBodyIndices.Contains(damageReport.victimBodyIndex))
				{
					Grant();
				}
			}

			private bool DoesDamageQualify(DamageReport damageReport)
			{
				return (DamageType)(damageReport.damageInfo.damageType & DamageType.ResetCooldownsOnKill) == DamageType.ResetCooldownsOnKill;
			}
		}

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("Bandit2Body");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}
	}
	[RegisterAchievement("Bandit2StackSuperBleed", "Skills.Bandit2.SerratedShivs", "CompleteThreeStages", 3u, typeof(Bandit2StackSuperBleedServerAchievement))]
	public class Bandit2StackSuperBleedAchievement : BaseAchievement
	{
		private class Bandit2StackSuperBleedServerAchievement : BaseServerAchievement
		{
			public override void OnInstall()
			{
				base.OnInstall();
				GlobalEventManager.onCharacterDeathGlobal += OnCharacterDeathGlobal;
			}

			public override void OnUninstall()
			{
				GlobalEventManager.onCharacterDeathGlobal -= OnCharacterDeathGlobal;
				base.OnUninstall();
			}

			private void OnCharacterDeathGlobal(DamageReport damageReport)
			{
				if ((bool)damageReport.attackerBody && (object)damageReport.attackerBody == GetCurrentBody() && (bool)damageReport.victimBody && damageReport.victimBody.GetBuffCount(RoR2Content.Buffs.SuperBleed) >= requirement)
				{
					Grant();
					ServerTryToCompleteActivity();
				}
			}
		}

		private static readonly int requirement = 20;

		protected override BodyIndex LookUpRequiredBodyIndex()
		{
			return BodyCatalog.FindBodyIndex("Bandit2Body");
		}

		protected override void OnBodyRequirementMet()
		{
			base.OnBodyRequirementMet();
			SetServerTracked(shouldTrack: true);
		}

		protected override void OnBodyRequirementBroken()
		{
			SetServerTracked(shouldTrack: false);
			base.OnBodyRequirementBroken();
		}

		public override void TryToCompleteActivity()
		{
			bool flag = base.localUser.id == LocalUserManager.GetFirstLocalUser().id;
			if (shouldGrant && flag)
			{
				BaseActivitySelector baseActivitySelector = new BaseActivitySelector();
				baseActivitySelector.activityAchievementID = "Bandit2StackSuperBleed";
				PlatformSystems.activityManager.TryToCompleteActivity(baseActivitySelector);
			}
		}
	}
}
namespace RoR2.Achievements.Artifacts
{
	[RegisterAchievement("ObtainArtifactDevotion", "Artifacts.Devotion", null, 2u, null)]
	public class ObtainArtifactDevotionAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => CU8Content.Artifacts.Devotion;
	}
	[RegisterAchievement("ObtainArtifactDelusion", "Artifacts.Delusion", null, 2u, null)]
	public class ObtainArtifactDelusionAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => CU8Content.Artifacts.Delusion;
	}
	[RegisterAchievement("ObtainArtifactRebirth", "Artifacts.Rebirth", null, 2u, null)]
	public class ObtainArtifactRebirthAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => DLC2Content.Artifacts.Rebirth;
	}
	public abstract class BaseObtainArtifactAchievement : BaseAchievement
	{
		private UnlockableDef unlockableDef;

		protected abstract ArtifactDef artifactDef { get; }

		public override void OnInstall()
		{
			base.OnInstall();
			unlockableDef = artifactDef.unlockableDef;
			UserProfile.onUnlockableGranted += OnUnlockableGranted;
			if ((object)unlockableDef != null && base.userProfile.HasUnlockable(unlockableDef))
			{
				Grant();
			}
		}

		public override void OnUninstall()
		{
			UserProfile.onUnlockableGranted -= OnUnlockableGranted;
			unlockableDef = null;
			base.OnUninstall();
		}

		private void OnUnlockableGranted(UserProfile userProfile, UnlockableDef unlockableDef)
		{
			if ((object)unlockableDef == this.unlockableDef)
			{
				Grant();
			}
		}
	}
	[RegisterAchievement("ObtainArtifactBomb", "Artifacts.Bomb", null, 3u, null)]
	public class ObtainArtifactBombAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.bombArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactCommand", "Artifacts.Command", null, 3u, null)]
	public class ObtainArtifactCommandAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.commandArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactEliteOnly", "Artifacts.EliteOnly", null, 3u, null)]
	public class ObtainArtifactAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.eliteOnlyArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactEnigma", "Artifacts.Enigma", null, 3u, null)]
	public class ObtainArtifactEnigmaAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.enigmaArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactFriendlyFire", "Artifacts.FriendlyFire", null, 3u, null)]
	public class ObtainArtifactFriendlyFireAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.friendlyFireArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactGlass", "Artifacts.Glass", null, 3u, null)]
	public class ObtainArtifactGlassAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.glassArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactMixEnemy", "Artifacts.MixEnemy", null, 3u, null)]
	public class ObtainArtifactMixEnemyAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.mixEnemyArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactMonsterTeamGainsItems", "Artifacts.MonsterTeamGainsItems", null, 3u, null)]
	public class ObtainArtifactMonsterTeamGainsItemsAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.monsterTeamGainsItemsArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactRandomSurvivorOnRespawn", "Artifacts.RandomSurvivorOnRespawn", null, 3u, null)]
	public class ObtainArtifactRandomSurvivorOnRespawnAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.randomSurvivorOnRespawnArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactSacrifice", "Artifacts.Sacrifice", null, 3u, null)]
	public class ObtainArtifactSacrificeAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.sacrificeArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactShadowClone", "Artifacts.ShadowClone", null, 3u, null)]
	public class ObtainArtifactShadowCloneAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.shadowCloneArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactSingleMonsterType", "Artifacts.SingleMonsterType", null, 3u, null)]
	public class ObtainArtifactSingleMonsterTypeAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.singleMonsterTypeArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactSwarms", "Artifacts.Swarms", null, 3u, null)]
	public class ObtainArtifactSwarmsAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.swarmsArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactTeamDeath", "Artifacts.TeamDeath", null, 3u, null)]
	public class ObtainArtifactTeamDeathAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.teamDeathArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactWeakAssKnees", "Artifacts.WeakAssKnees", null, 3u, null)]
	public class ObtainArtifactWeakAssKneesAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.weakAssKneesArtifactDef;
	}
	[RegisterAchievement("ObtainArtifactWispOnDeath", "Artifacts.WispOnDeath", null, 3u, null)]
	public class ObtainArtifactWispOnDeathAchievement : BaseObtainArtifactAchievement
	{
		protected override ArtifactDef artifactDef => RoR2Content.Artifacts.wispOnDeath;
	}
}
namespace RoR2.UI
{
	public class RunTimerSpriteAsNumberManager : MonoBehaviour
	{
		public SpriteAsNumberManager spriteAsNumberManager;

		private void Update()
		{
			if ((bool)spriteAsNumberManager)
			{
				spriteAsNumberManager.SetTimerValue(Run.instance ? ((int)Run.instance.GetRunStopwatch()) : 0);
			}
		}
	}
	public class SpriteAsNumberManager : MonoBehaviour, ILayoutGroup, ILayoutController
	{
		private enum Alignment
		{
			Right,
			Center,
			Left
		}

		private enum SpriteCharacterType
		{
			Number,
			Punctuation
		}

		[Tooltip("This is only used internally on editor refresh to tell the object how to format itself.")]
		[SerializeField]
		private bool internalUseOnlyIsTimer;

		[SerializeField]
		private Alignment textAlignment = Alignment.Center;

		[SerializeField]
		private int debugValue;

		[SerializeField]
		[FormerlySerializedAs("spaceBetweenImages")]
		[Tooltip("Additional Space between non-punctuation characters.")]
		private float spaceBetweenCharacters;

		[Tooltip("Will scale punctuation sprites up or down (1 = normal). It will not change the spacing around the sprite.")]
		[SerializeField]
		private float scalePunctuationBy;

		[SerializeField]
		private float spaceBetweenPunctuation;

		[SerializeField]
		private Transform imagePrefab;

		[SerializeField]
		private int startingNumberOfPrefabs;

		[SerializeField]
		private Sprite colonSprite;

		[SerializeField]
		private Sprite forwardSlashSprite;

		[SerializeField]
		private Sprite questionMarkSprite;

		[SerializeField]
		private Sprite negativeSymbolSprite;

		[SerializeField]
		private Sprite percentSymbolSprite;

		[SerializeField]
		private Sprite dollarSignSymbolSprite;

		[SerializeField]
		private Sprite xSprite;

		private const int CONST_COLON = -1111;

		private const int CONST_NEGATIVE = -2222;

		private const int CONST_FSLASH = -3333;

		private const int CONST_PERCENT = -4444;

		private const int CONST_DOLLARSIGN = -5555;

		private const int CONST_X = -6666;

		private RectTransform rectTransform;

		private int cachedValue = -1111;

		private float cachedCanvasHeight;

		private float defaultSpriteHeight;

		private float defaultSpriteWidth;

		private bool isVisible = true;

		[SerializeField]
		private Sprite[] referenceArray;

		private List<UnityEngine.UI.Image> imageList = new List<UnityEngine.UI.Image>();

		private List<RectTransform> rtList = new List<RectTransform>();

		private List<SpriteCharacterType> charTypeList = new List<SpriteCharacterType>();

		private int totalImagesInUse;

		private bool finishedSetup;

		private void Awake()
		{
			TrySetup();
		}

		public void TrySetup()
		{
			if (!finishedSetup)
			{
				rectTransform = GetComponent<RectTransform>();
				rtList = new List<RectTransform>();
				imageList = new List<UnityEngine.UI.Image>();
				charTypeList = new List<SpriteCharacterType>();
				defaultSpriteHeight = referenceArray[0].rect.height;
				defaultSpriteWidth = referenceArray[0].rect.width;
				LoadAnyExistingChildren();
				int num = Mathf.Max(startingNumberOfPrefabs - base.transform.childCount, 0);
				for (int i = 0; i < num; i++)
				{
					InstantiateNewImage();
				}
				totalImagesInUse = 0;
				RebuildLayout();
				finishedSetup = true;
			}
		}

		public void LoadAnyExistingChildren()
		{
			foreach (RectTransform item in base.transform)
			{
				if (item.TryGetComponent<UnityEngine.UI.Image>(out var component))
				{
					rtList.Add(item);
					imageList.Add(component);
					charTypeList.Add(SpriteCharacterType.Number);
				}
			}
		}

		public void SetVisible(bool b)
		{
			isVisible = b;
			HandleActivationOfImages();
		}

		public void SetPercentValue(int intPercent)
		{
			TrySetup();
			if (intPercent != cachedValue || !isVisible)
			{
				cachedValue = intPercent;
				isVisible = true;
				List<int> list = new List<int>();
				list.Add(-4444);
				LoadListWithDigitPositions(intPercent, ref list);
				UpdateSpriteObjectsWithListValues(list);
			}
		}

		public void SetItemCount(int count)
		{
			TrySetup();
			if (count != cachedValue || !isVisible)
			{
				cachedValue = count;
				isVisible = true;
				List<int> list = new List<int>();
				LoadListWithDigitPositions(count, ref list);
				list.Add(-6666);
				UpdateSpriteObjectsWithListValues(list);
			}
		}

		public void SetTimerValue(int totalTimeInSeconds)
		{
			TrySetup();
			if (totalTimeInSeconds == cachedValue && isVisible)
			{
				return;
			}
			cachedValue = totalTimeInSeconds;
			isVisible = true;
			List<int> list = new List<int>();
			float num = totalTimeInSeconds;
			int num2 = Mathf.Min(Mathf.FloorToInt(num * (1f / 60f)), 999);
			int value = (int)num - num2 * 60;
			list.Add(GetDigitPosition(value, 0));
			list.Add(GetDigitPosition(value, 1));
			list.Add(-1111);
			int num3 = Mathf.Max(GetTotalDigitPositions(num2), 2);
			for (int i = 0; i < num3; i++)
			{
				int digitPosition = GetDigitPosition(num2, i);
				if (digitPosition > 0 || i < 2)
				{
					list.Add(digitPosition);
				}
			}
			UpdateSpriteObjectsWithListValues(list);
		}

		public void SetHitPointValues(int currentHP, int totalHP)
		{
			TrySetup();
			List<int> list = new List<int>();
			LoadListWithDigitPositions(totalHP, ref list);
			list.Add(-3333);
			LoadListWithDigitPositions(currentHP, ref list);
			UpdateSpriteObjectsWithListValues(list);
		}

		public int GetDigitPosition(int value, int position)
		{
			value = Mathf.Abs(value);
			int num = (int)Mathf.Pow(10f, (float)position + 1f);
			position = (int)Mathf.Pow(10f, position);
			if (value >= num)
			{
				float num2 = value / num;
				value -= (int)num2 * num;
			}
			return value / position;
		}

		public void LoadListWithDigitPositions(int value, ref List<int> list, int forceZeroTillAtLeastXPosition = 0)
		{
			bool flag = value < 0;
			value = Mathf.Abs(value);
			if (value == 0 && forceZeroTillAtLeastXPosition == 0)
			{
				list.Add(0);
				return;
			}
			int num = Math.Max(GetTotalDigitPositions(value), forceZeroTillAtLeastXPosition);
			for (int i = 0; i < num; i++)
			{
				int digitPosition = GetDigitPosition(value, i);
				list.Add(digitPosition);
			}
			if (flag)
			{
				list.Add(-2222);
			}
		}

		public int GetTotalDigitPositions(int val)
		{
			val = Mathf.Abs(val);
			int i;
			for (i = 0; (float)val >= Mathf.Pow(10f, i); i++)
			{
			}
			return i;
		}

		public void SetSpriteColor(UnityEngine.Color color)
		{
			for (int i = 0; i < totalImagesInUse; i++)
			{
				imageList[i].color = color;
			}
		}

		public void UpdateSpriteObjectsWithListValues(List<int> listValues, int startingImageIndex = 0)
		{
			VerifyAllObjectsInList();
			int count = listValues.Count;
			int count2;
			for (count2 = imageList.Count; count2 <= startingImageIndex + count; count2 = imageList.Count)
			{
				InstantiateNewImage();
			}
			totalImagesInUse = count2 + startingImageIndex;
			for (int i = 0; i < count2; i++)
			{
				if (i >= count)
				{
					totalImagesInUse = i;
					break;
				}
				UnityEngine.UI.Image image = imageList[i];
				switch (listValues[i])
				{
				case -1111:
					image.sprite = colonSprite;
					charTypeList[i] = SpriteCharacterType.Punctuation;
					break;
				case -2222:
					image.sprite = negativeSymbolSprite ?? questionMarkSprite;
					charTypeList[i] = SpriteCharacterType.Punctuation;
					break;
				case -3333:
					image.sprite = forwardSlashSprite ?? questionMarkSprite;
					charTypeList[i] = SpriteCharacterType.Punctuation;
					break;
				case -4444:
					image.sprite = percentSymbolSprite ?? questionMarkSprite;
					charTypeList[i] = SpriteCharacterType.Punctuation;
					break;
				case -5555:
					image.sprite = dollarSignSymbolSprite ?? questionMarkSprite;
					charTypeList[i] = SpriteCharacterType.Punctuation;
					break;
				case -6666:
					image.sprite = xSprite ?? questionMarkSprite;
					charTypeList[i] = SpriteCharacterType.Punctuation;
					break;
				default:
					image.sprite = referenceArray[Mathf.Clamp(listValues[i], 0, 9)];
					charTypeList[i] = SpriteCharacterType.Number;
					break;
				}
			}
			UpdateSpriteSizes();
			RebuildLayout();
		}

		private void VerifyAllObjectsInList()
		{
			int count = rtList.Count;
			if (count < 1)
			{
				return;
			}
			for (int num = count - 1; num >= 0; num--)
			{
				if (rtList[num] == null || imageList[num] == null)
				{
					rtList.RemoveAt(num);
					imageList.RemoveAt(num);
					charTypeList.RemoveAt(num);
				}
			}
		}

		private void UpdateSpriteSizes()
		{
			cachedCanvasHeight = rectTransform.rect.height;
			float num = cachedCanvasHeight / defaultSpriteHeight;
			UnityEngine.Vector2 sizeDelta = default(UnityEngine.Vector2);
			for (int i = 0; i < totalImagesInUse; i++)
			{
				if (charTypeList[i] == SpriteCharacterType.Punctuation)
				{
					sizeDelta.x = imageList[i].sprite.rect.width * num * scalePunctuationBy;
					sizeDelta.y = imageList[i].sprite.rect.height * num * scalePunctuationBy;
				}
				else
				{
					sizeDelta.x = imageList[i].sprite.rect.width * num;
					sizeDelta.y = imageList[i].sprite.rect.height * num;
				}
				sizeDelta.x = Mathf.Round(sizeDelta.x * 100f) / 100f;
				sizeDelta.y = Mathf.Round(sizeDelta.y * 100f) / 100f;
				rtList[i].sizeDelta = sizeDelta;
			}
		}

		private void InstantiateNewImage()
		{
			RectTransform component = UnityEngine.Object.Instantiate(imagePrefab, rectTransform).GetComponent<RectTransform>();
			rtList.Add(component);
			UnityEngine.UI.Image component2 = component.GetComponent<UnityEngine.UI.Image>();
			imageList.Add(component2);
			charTypeList.Add(SpriteCharacterType.Number);
			component.sizeDelta = new UnityEngine.Vector2(defaultSpriteWidth, defaultSpriteHeight);
			component2.preserveAspect = true;
		}

		private void RebuildLayout()
		{
			if (base.transform.childCount < 1)
			{
				return;
			}
			HandleActivationOfImages();
			if (isVisible && totalImagesInUse >= 1)
			{
				if (cachedCanvasHeight != this.rectTransform.rect.height)
				{
					UpdateSpriteSizes();
				}
				float num = this.rectTransform.rect.height / defaultSpriteHeight;
				float singleImageWidth = defaultSpriteWidth * num;
				float totalImageWidth = GetTotalImageWidth();
				float num2 = GetStartingX(textAlignment, singleImageWidth, totalImageWidth, rtList[0].pivot.x);
				float y = 0f;
				for (int i = 0; i < totalImagesInUse; i++)
				{
					RectTransform rectTransform = rtList[i];
					bool num3 = charTypeList[i] != SpriteCharacterType.Punctuation && i + 1 < totalImagesInUse && charTypeList[i + 1] != SpriteCharacterType.Punctuation;
					singleImageWidth = rtList[i].rect.width * 0.5f;
					num2 -= singleImageWidth;
					rectTransform.anchoredPosition = new UnityEngine.Vector2(num2, y);
					num2 = ((!num3) ? (num2 - (singleImageWidth + spaceBetweenPunctuation)) : (num2 - (singleImageWidth + spaceBetweenCharacters)));
				}
			}
		}

		private void InitializeVariablesForInEditorViewing()
		{
			rectTransform = GetComponent<RectTransform>();
			rtList = new List<RectTransform>();
			imageList = new List<UnityEngine.UI.Image>();
			charTypeList = new List<SpriteCharacterType>();
			defaultSpriteHeight = referenceArray[0].rect.height;
			defaultSpriteWidth = referenceArray[0].rect.width;
			LoadAnyExistingChildren();
			totalImagesInUse = rtList.Count;
		}

		private float GetTotalImageWidth()
		{
			float num = 0f;
			for (int i = 0; i < totalImagesInUse; i++)
			{
				num += rtList[i].rect.width;
				num = ((charTypeList[i] != 0) ? (num + spaceBetweenPunctuation) : (num + spaceBetweenCharacters));
			}
			return num;
		}

		private float GetStartingX(Alignment textAlignment, float singleImageWidth, float totalImageWidth, float singleImageAlignment)
		{
			singleImageAlignment *= singleImageWidth;
			float num = rectTransform.pivot.x * rectTransform.rect.width;
			switch (textAlignment)
			{
			case Alignment.Left:
				return totalImageWidth - (singleImageWidth - singleImageAlignment) - num;
			case Alignment.Right:
				return num;
			default:
				num = rectTransform.rect.width * 0.5f - num;
				return num + totalImageWidth * 0.5f;
			}
		}

		private void HandleActivationOfImages()
		{
			for (int num = rtList.Count - 1; num >= 0; num--)
			{
				if (rtList[num] == null)
				{
					rtList.RemoveAt(num);
					imageList.RemoveAt(num);
					if (num < charTypeList.Count)
					{
						charTypeList.RemoveAt(num);
					}
				}
				else if (num < totalImagesInUse)
				{
					rtList[num].gameObject.SetActive(isVisible);
				}
				else
				{
					rtList[num].gameObject.SetActive(value: false);
				}
			}
		}

		public void SetLayoutHorizontal()
		{
		}

		public void SetLayoutVertical()
		{
			VerifyAllObjectsInList();
			RebuildLayout();
		}

		[ContextMenu("Format As Timer")]
		public void FormatAsTimer()
		{
			InitializeVariablesForInEditorViewing();
			SetTimerValue(754);
		}

		[ContextMenu("Format As ItemCounter")]
		public void FormatAsItemCounter()
		{
			InitializeVariablesForInEditorViewing();
			SetItemCount(debugValue);
		}

		[ContextMenu("Format As Hitpoints")]
		public void FormatAsHitpoints()
		{
			InitializeVariablesForInEditorViewing();
			SetHitPointValues(1234, 5768);
		}

		[ContextMenu("Format as Percent")]
		public void FormatAsPercent()
		{
			InitializeVariablesForInEditorViewing();
			SetPercentValue(100);
		}
	}
	[CreateAssetMenu(menuName = "RoR2/UI/HealthBarStyle")]
	public class HealthBarStyle : ScriptableObject
	{
		[Serializable]
		public struct BarStyle
		{
			public bool enabled;

			public UnityEngine.Color baseColor;

			public Sprite sprite;

			public UnityEngine.UI.Image.Type imageType;

			public float sizeDelta;
		}

		public GameObject barPrefab;

		public bool flashOnHealthCritical;

		[FormerlySerializedAs("trailingBarStyle")]
		public BarStyle trailingUnderHealthBarStyle;

		[FormerlySerializedAs("healthBarStyle")]
		public BarStyle instantHealthBarStyle;

		public BarStyle trailingOverHealthBarStyle;

		public BarStyle shieldBarStyle;

		public BarStyle curseBarStyle;

		public BarStyle barrierBarStyle;

		public BarStyle flashBarStyle;

		public BarStyle cullBarStyle;

		public BarStyle magneticStyle;

		public BarStyle ospStyle;

		public BarStyle lowHealthOverStyle;

		public BarStyle lowHealthUnderStyle;
	}
	[CreateAssetMenu(menuName = "RoR2/UISkinData")]
	public class UISkinData : ScriptableObject
	{
		[Serializable]
		public struct TextStyle
		{
			public TMP_FontAsset font;

			public float fontSize;

			public TextAlignmentOptions alignment;

			public UnityEngine.Color color;

			public void Apply(TextMeshProUGUI label, bool useAlignment = true)
			{
				if (label.font != font && !(label is HGTextMeshProUGUI { useLanguageDefaultFont: not false }))
				{
					label.font = font;
				}
				if (label.fontSize != fontSize)
				{
					label.fontSize = fontSize;
				}
				if (label.color != color)
				{
					label.color = color;
				}
				if (useAlignment && label.alignment != alignment)
				{
					label.alignment = alignment;
				}
			}
		}

		[Serializable]
		public struct PanelStyle
		{
			public Material material;

			public Sprite sprite;

			public UnityEngine.Color color;

			public void Apply(UnityEngine.UI.Image image)
			{
				image.material = material;
				image.sprite = sprite;
				image.color = color;
			}
		}

		[Serializable]
		public struct ButtonStyle
		{
			public Material material;

			public Sprite sprite;

			public ColorBlock colors;

			public TextStyle interactableTextStyle;

			public TextStyle disabledTextStyle;

			public float recommendedWidth;

			public float recommendedHeight;
		}

		[Serializable]
		public struct ScrollRectStyle
		{
			[FormerlySerializedAs("viewportPanelStyle")]
			public PanelStyle backgroundPanelStyle;

			public PanelStyle scrollbarBackgroundStyle;

			public ColorBlock scrollbarHandleColors;

			public Sprite scrollbarHandleImage;
		}

		[Header("Main Panel Style")]
		public PanelStyle mainPanelStyle;

		[Header("Header Style")]
		public PanelStyle headerPanelStyle;

		public TextStyle headerTextStyle;

		[Header("Detail Style")]
		public PanelStyle detailPanelStyle;

		public TextStyle detailTextStyle;

		[Header("Body Style")]
		public TextStyle bodyTextStyle;

		[Header("Button Style")]
		public ButtonStyle buttonStyle;

		[Header("Scroll Rect Style")]
		public ScrollRectStyle scrollRectStyle;
	}
	public class DebugStats : MonoBehaviour
	{
		public GameObject statsRoot;

		public TextMeshProUGUI fpsAverageText;

		public float fpsAverageFrequency = 1f;

		public float fpsAverageTime = 60f;

		public float fpsAverageDisplayUpdateFrequency = 1f;

		private float fpsStopwatch;

		private float fpsDisplayStopwatch;

		private static Queue<float> fpsTimestamps;

		private int fpsTimestampCount;

		public TextMeshProUGUI budgetAverageText;

		public float budgetAverageFrequency = 1f;

		public float budgetAverageTime = 60f;

		private const float budgetAverageDisplayUpdateFrequency = 1f;

		private float budgetStopwatch;

		private float budgetDisplayStopwatch;

		private static Queue<float> budgetTimestamps;

		private int budgetTimestampCount;

		private static bool showStats;

		public TextMeshProUGUI teamText;

		private void Awake()
		{
			fpsTimestamps = new Queue<float>();
			fpsTimestampCount = (int)(fpsAverageTime / fpsAverageFrequency);
			budgetTimestamps = new Queue<float>();
			budgetTimestampCount = (int)(budgetAverageTime / budgetAverageFrequency);
		}

		private float GetAverageFPS()
		{
			if (fpsTimestamps.Count == 0)
			{
				return 0f;
			}
			float num = 0f;
			foreach (float fpsTimestamp in fpsTimestamps)
			{
				num += fpsTimestamp;
			}
			num /= (float)fpsTimestamps.Count;
			return Mathf.Round(num);
		}

		private float GetAverageParticleCost()
		{
			if (budgetTimestamps.Count == 0)
			{
				return 0f;
			}
			float num = 0f;
			foreach (float budgetTimestamp in budgetTimestamps)
			{
				num += budgetTimestamp;
			}
			num /= (float)budgetTimestamps.Count;
			return Mathf.Round(num);
		}

		private void Update()
		{
			statsRoot.SetActive(showStats);
			if (!showStats)
			{
				return;
			}
			fpsStopwatch += Time.unscaledDeltaTime;
			fpsDisplayStopwatch += Time.unscaledDeltaTime;
			float num = 1f / Time.unscaledDeltaTime;
			if (fpsStopwatch >= 1f / fpsAverageFrequency)
			{
				fpsStopwatch = 0f;
				fpsTimestamps.Enqueue(num);
				if (fpsTimestamps.Count > fpsTimestampCount)
				{
					fpsTimestamps.Dequeue();
				}
			}
			if (fpsDisplayStopwatch > fpsAverageDisplayUpdateFrequency)
			{
				fpsDisplayStopwatch = 0f;
				float averageFPS = GetAverageFPS();
				fpsAverageText.text = "FPS: " + Mathf.Round(num) + " (" + averageFPS + ")";
				TextMeshProUGUI textMeshProUGUI = fpsAverageText;
				textMeshProUGUI.text = textMeshProUGUI.text + "\n ms: " + Mathf.Round(100000f / num) / 100f + "(" + Mathf.Round(100000f / averageFPS) / 100f + ")";
			}
			budgetStopwatch += Time.unscaledDeltaTime;
			budgetDisplayStopwatch += Time.unscaledDeltaTime;
			float num2 = VFXBudget.totalCost;
			if (budgetStopwatch >= 1f / budgetAverageFrequency)
			{
				budgetStopwatch = 0f;
				budgetTimestamps.Enqueue(num2);
				if (budgetTimestamps.Count > budgetTimestampCount)
				{
					budgetTimestamps.Dequeue();
				}
			}
			if (budgetDisplayStopwatch > 1f)
			{
				budgetDisplayStopwatch = 0f;
				float averageParticleCost = GetAverageParticleCost();
				budgetAverageText.text = "Particle Cost: " + Mathf.Round(num2) + " (" + averageParticleCost + ")";
			}
			if (!teamText)
			{
				return;
			}
			string text = "Allies: " + TeamComponent.GetTeamMembers(TeamIndex.Player).Count + "\n";
			string text2 = "Enemies: " + TeamComponent.GetTeamMembers(TeamIndex.Monster).Count + "\n";
			string text3 = "Bosses: " + BossGroup.GetTotalBossCount() + "\n";
			string text4 = "Directors:";
			foreach (CombatDirector instances in CombatDirector.instancesList)
			{
				string text5 = "\n==[" + instances.gameObject.name + "]==";
				if (instances.enabled)
				{
					string text6 = "\n - Credit: " + instances.monsterCredit;
					string text7 = "\n - Target: " + (instances.currentSpawnTarget ? instances.currentSpawnTarget.name : "null");
					string text8 = "\n - Last Spawn Card: ";
					if (instances.lastAttemptedMonsterCard != null && (bool)instances.lastAttemptedMonsterCard.spawnCard)
					{
						text8 += instances.lastAttemptedMonsterCard.spawnCard.name;
					}
					string text9 = "\n - Reroll Timer: " + Mathf.Round(instances.monsterSpawnTimer);
					text5 = text5 + text6 + text7 + text8 + text9;
				}
				else
				{
					text5 += " (Off)";
				}
				text4 = text4 + text5 + "\n \n";
			}
			teamText.text = text + text2 + text3 + text4;
		}
	}
	public class FPS : MonoBehaviour
	{
		public TextMeshProUGUI targetText;

		private float deltaTime;

		private float stopwatch;

		private const float updateTime = 1f;

		private void Update()
		{
			stopwatch += Time.unscaledDeltaTime;
			deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
			if (stopwatch >= 1f)
			{
				stopwatch -= 1f;
				float num = deltaTime * 1000f;
				float num2 = 1f / deltaTime;
				string text = $"{num:0.0} ms \n{num2:0.} fps";
				targetText.text = text;
			}
		}
	}
	public class MPInput : BaseInput, IMouseInputSource
	{
		public Player player;

		private MPEventSystem eventSystem;

		[FormerlySerializedAs("useAcceleration")]
		public bool useCursorAcceleration = true;

		[FormerlySerializedAs("acceleration")]
		public float cursorAcceleration = 8f;

		public float cursorStickyModifier = 1f / 3f;

		public float cursorScreenSpeed = 0.75f;

		private float stickMagnitude;

		private UnityEngine.Vector2 _scrollDelta;

		private UnityEngine.Vector2 internalScreenPositionDelta;

		public UnityEngine.Vector2 internalMousePosition;

		public override UnityEngine.Vector2 mousePosition => internalMousePosition;

		public override UnityEngine.Vector2 mouseScrollDelta => _scrollDelta;

		public int playerId => player.id;

		public bool locked => !eventSystem.isCursorVisible;

		public int buttonCount => 3;

		public UnityEngine.Vector2 screenPosition => internalMousePosition;

		public UnityEngine.Vector2 screenPositionDelta => internalScreenPositionDelta;

		public UnityEngine.Vector2 wheelDelta => _scrollDelta;

		protected override void Awake()
		{
			base.Awake();
			eventSystem = GetComponent<MPEventSystem>();
		}

		private static int MouseButtonToAction(int button)
		{
			return button switch
			{
				0 => 20, 
				1 => 21, 
				2 => 22, 
				_ => -1, 
			};
		}

		public override bool GetMouseButtonDown(int button)
		{
			return player.GetButtonDown(MouseButtonToAction(button));
		}

		public override bool GetMouseButtonUp(int button)
		{
			return player.GetButtonUp(MouseButtonToAction(button));
		}

		public override bool GetMouseButton(int button)
		{
			return player.GetButton(MouseButtonToAction(button));
		}

		public void CenterCursor()
		{
			internalMousePosition = new UnityEngine.Vector2((float)Screen.width * 0.5f, (float)Screen.height * 0.5f);
		}

		public void Update()
		{
			if (!eventSystem.isCursorVisible)
			{
				return;
			}
			float num = Screen.width;
			float num2 = Screen.height;
			float num3 = Mathf.Min(num / 1920f, num2 / 1080f);
			internalScreenPositionDelta = UnityEngine.Vector2.zero;
			if (eventSystem.currentInputSource == MPEventSystem.InputSource.MouseAndKeyboard)
			{
				if (Application.isFocused)
				{
					internalMousePosition = Input.mousePosition;
				}
			}
			else
			{
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(player.GetAxis(23), player.GetAxis(24));
				float magnitude = vector.magnitude;
				stickMagnitude = Mathf.Min(Mathf.MoveTowards(stickMagnitude, magnitude, cursorAcceleration * Time.unscaledDeltaTime), magnitude);
				float num4 = stickMagnitude;
				if (eventSystem.isHovering)
				{
					num4 *= cursorStickyModifier;
				}
				UnityEngine.Vector2 vector2 = ((magnitude == 0f) ? UnityEngine.Vector2.zero : (vector * (num4 / magnitude)));
				float num5 = 1920f * cursorScreenSpeed * num3;
				internalScreenPositionDelta = vector2 * Time.unscaledDeltaTime * num5;
				internalMousePosition += internalScreenPositionDelta;
			}
			internalMousePosition.x = Mathf.Clamp(internalMousePosition.x, 0f, num);
			internalMousePosition.y = Mathf.Clamp(internalMousePosition.y, 0f, num2);
			_scrollDelta = new UnityEngine.Vector2(0f, player.GetAxis(26));
		}

		public bool GetButtonDown(int button)
		{
			return GetMouseButtonDown(button);
		}

		public bool GetButtonUp(int button)
		{
			return GetMouseButtonUp(button);
		}

		public bool GetButton(int button)
		{
			return GetMouseButton(button);
		}

		[SpecialName]
		bool IMouseInputSource.get_enabled()
		{
			return base.enabled;
		}
	}
	public class NetworkMultiOptionPickupPicker : NetworkBehaviour
	{
		[SerializeField]
		private PickupPickerPanel pickupPickerPanel;

		private static int kRpcRpcRemovePickupButtonAvailability;

		private static int kCmdCmdRemovePickupButtonAvailability;

		public void RemovePickupButtonAvailability(int pickupOption)
		{
			if (NetworkServer.active)
			{
				ServerRemovePickupButtonAvailability(pickupOption);
			}
			else
			{
				CallCmdRemovePickupButtonAvailability(pickupOption);
			}
		}

		[Server]
		private void ServerRemovePickupButtonAvailability(int pickupOption)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogWarning("[Server] function 'System.Void RoR2.UI.NetworkMultiOptionPickupPicker::ServerRemovePickupButtonAvailability(System.Int32)' called on client");
				return;
			}
			pickupPickerPanel.RemovePickupButtonAvailability(pickupOption);
			CallRpcRemovePickupButtonAvailability(pickupOption);
		}

		[ClientRpc]
		private void RpcRemovePickupButtonAvailability(int pickupOption)
		{
			pickupPickerPanel.RemovePickupButtonAvailability(pickupOption);
		}

		[Command]
		private void CmdRemovePickupButtonAvailability(int pickupOption)
		{
			pickupPickerPanel.RemovePickupButtonAvailability(pickupOption);
			CallRpcRemovePickupButtonAvailability(pickupOption);
		}

		private void UNetVersion()
		{
		}

		protected static void InvokeCmdCmdRemovePickupButtonAvailability(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("Command CmdRemovePickupButtonAvailability called on client.");
			}
			else
			{
				((NetworkMultiOptionPickupPicker)obj).CmdRemovePickupButtonAvailability((int)reader.ReadPackedUInt32());
			}
		}

		public void CallCmdRemovePickupButtonAvailability(int pickupOption)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("Command function CmdRemovePickupButtonAvailability called on server.");
				return;
			}
			if (base.isServer)
			{
				CmdRemovePickupButtonAvailability(pickupOption);
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)5);
			networkWriter.WritePackedUInt32((uint)kCmdCmdRemovePickupButtonAvailability);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)pickupOption);
			SendCommandInternal(networkWriter, 0, "CmdRemovePickupButtonAvailability");
		}

		protected static void InvokeRpcRpcRemovePickupButtonAvailability(NetworkBehaviour obj, NetworkReader reader)
		{
			if (!NetworkClient.active)
			{
				UnityEngine.Debug.LogError("RPC RpcRemovePickupButtonAvailability called on server.");
			}
			else
			{
				((NetworkMultiOptionPickupPicker)obj).RpcRemovePickupButtonAvailability((int)reader.ReadPackedUInt32());
			}
		}

		public void CallRpcRemovePickupButtonAvailability(int pickupOption)
		{
			if (!NetworkServer.active)
			{
				UnityEngine.Debug.LogError("RPC Function RpcRemovePickupButtonAvailability called on client.");
				return;
			}
			NetworkWriter networkWriter = new NetworkWriter();
			networkWriter.Write((short)0);
			networkWriter.Write((short)2);
			networkWriter.WritePackedUInt32((uint)kRpcRpcRemovePickupButtonAvailability);
			networkWriter.Write(GetComponent<NetworkIdentity>().netId);
			networkWriter.WritePackedUInt32((uint)pickupOption);
			SendRPCInternal(networkWriter, 0, "RpcRemovePickupButtonAvailability");
		}

		static NetworkMultiOptionPickupPicker()
		{
			kCmdCmdRemovePickupButtonAvailability = 752063031;
			NetworkBehaviour.RegisterCommandDelegate(typeof(NetworkMultiOptionPickupPicker), kCmdCmdRemovePickupButtonAvailability, InvokeCmdCmdRemovePickupButtonAvailability);
			kRpcRpcRemovePickupButtonAvailability = 752475021;
			NetworkBehaviour.RegisterRpcDelegate(typeof(NetworkMultiOptionPickupPicker), kRpcRpcRemovePickupButtonAvailability, InvokeRpcRpcRemovePickupButtonAvailability);
			NetworkCRC.RegisterBehaviour("NetworkMultiOptionPickupPicker", 0);
		}

		public override bool OnSerialize(NetworkWriter writer, bool forceAll)
		{
			bool result = default(bool);
			return result;
		}

		public override void OnDeserialize(NetworkReader reader, bool initialState)
		{
		}

		public override void PreStartClient()
		{
		}
	}
	public class OutroFlavorTextController : MonoBehaviour
	{
		public LanguageTextMeshController languageTextMeshController;

		protected void Start()
		{
			UpdateFlavorText();
		}

		protected void UpdateFlavorText()
		{
			string text = null;
			LocalUser localUser = GetComponent<MPEventSystemLocator>().eventSystem?.localUser;
			RunReport runReport = GameOverController.instance?.runReport;
			if (localUser != null && runReport != null)
			{
				RunReport.PlayerInfo playerInfo = runReport.FindPlayerInfo(localUser);
				if (playerInfo != null)
				{
					SurvivorDef survivorDef = SurvivorCatalog.GetSurvivorDef(SurvivorCatalog.GetSurvivorIndexFromBodyIndex(playerInfo.bodyIndex));
					if ((bool)survivorDef)
					{
						text = ((!playerInfo.isDead) ? survivorDef.outroFlavorToken : survivorDef.mainEndingEscapeFailureFlavorToken);
					}
				}
			}
			if (string.IsNullOrEmpty(text))
			{
				text = "GENERIC_OUTRO_FLAVOR";
			}
			if ((bool)languageTextMeshController)
			{
				languageTextMeshController.token = text;
			}
		}
	}
	public class AchievementCardController : MonoBehaviour
	{
		public UnityEngine.UI.Image iconImage;

		public LanguageTextMeshController nameLabel;

		public LanguageTextMeshController descriptionLabel;

		public LayoutElement tabLayoutElement;

		public float tabWidth;

		public GameObject unlockedImage;

		public GameObject cantBeAchievedImage;

		public TooltipProvider tooltipProvider;

		private static string GetAchievementParentIdentifier(string achievementIdentifier)
		{
			return AchievementManager.GetAchievementDef(achievementIdentifier)?.prerequisiteAchievementIdentifier;
		}

		private static int CalcAchievementTabCount(string achievementIdentifier)
		{
			int num = -1;
			while (!string.IsNullOrEmpty(achievementIdentifier))
			{
				num++;
				achievementIdentifier = GetAchievementParentIdentifier(achievementIdentifier);
			}
			return num;
		}

		public void SetAchievement(string achievementIdentifier, UserProfile userProfile)
		{
			AchievementDef achievementDef = AchievementManager.GetAchievementDef(achievementIdentifier);
			if (achievementDef == null)
			{
				return;
			}
			bool flag = userProfile.HasAchievement(achievementIdentifier);
			bool flag2 = userProfile.CanSeeAchievement(achievementIdentifier);
			if ((bool)iconImage)
			{
				iconImage.sprite = (flag ? achievementDef.GetAchievedIcon() : achievementDef.GetUnachievedIcon());
			}
			if ((bool)nameLabel)
			{
				nameLabel.token = (userProfile.CanSeeAchievement(achievementIdentifier) ? achievementDef.nameToken : "???");
			}
			if ((bool)descriptionLabel)
			{
				descriptionLabel.token = (userProfile.CanSeeAchievement(achievementIdentifier) ? achievementDef.descriptionToken : "???");
			}
			if ((bool)unlockedImage)
			{
				unlockedImage.gameObject.SetActive(flag);
			}
			if ((bool)cantBeAchievedImage)
			{
				cantBeAchievedImage.gameObject.SetActive(!flag2);
			}
			if ((bool)tooltipProvider)
			{
				string overrideBodyText = "???";
				if (flag2)
				{
					if (flag)
					{
						UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(achievementDef.unlockableRewardIdentifier);
						if (unlockableDef != null)
						{
							string @string = Language.GetString("ACHIEVEMENT_CARD_REWARD_FORMAT");
							string string2 = Language.GetString(unlockableDef.nameToken);
							overrideBodyText = string.Format(@string, string2);
						}
					}
					else
					{
						string string3 = Language.GetString("ACHIEVEMENT_CARD_REWARD_FORMAT");
						string arg = "???";
						overrideBodyText = string.Format(string3, arg);
					}
				}
				else
				{
					AchievementDef achievementDef2 = AchievementManager.GetAchievementDef(achievementDef.prerequisiteAchievementIdentifier);
					if (achievementDef2 != null)
					{
						string string4 = Language.GetString("ACHIEVEMENT_CARD_PREREQ_FORMAT");
						string string5 = Language.GetString(achievementDef2.nameToken);
						overrideBodyText = string.Format(string4, string5);
					}
				}
				tooltipProvider.titleToken = (flag2 ? achievementDef.nameToken : "???");
				tooltipProvider.overrideBodyText = overrideBodyText;
			}
			if ((bool)tabLayoutElement)
			{
				tabLayoutElement.preferredWidth = (float)CalcAchievementTabCount(achievementIdentifier) * tabWidth;
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class AchievementListPanelController : MonoBehaviour
	{
		public GameObject achievementCardPrefab;

		public RectTransform container;

		private MPEventSystemLocator eventSystemLocator;

		private readonly List<AchievementCardController> cardsList = new List<AchievementCardController>();

		private static readonly List<string> sortedAchievementIdentifiers;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private void OnEnable()
		{
			Rebuild();
		}

		private UserProfile GetUserProfile()
		{
			MPEventSystem eventSystem = eventSystemLocator.eventSystem;
			if ((bool)eventSystem)
			{
				LocalUser localUser = LocalUserManager.FindLocalUser(eventSystem.player);
				if (localUser != null)
				{
					return localUser.userProfile;
				}
			}
			return null;
		}

		static AchievementListPanelController()
		{
			sortedAchievementIdentifiers = new List<string>();
			BuildAchievementListOrder();
			AchievementManager.onAchievementsRegistered += BuildAchievementListOrder;
		}

		private static void BuildAchievementListOrder()
		{
			sortedAchievementIdentifiers.Clear();
			HashSet<string> encounteredIdentifiers = new HashSet<string>();
			ReadOnlyCollection<string> readOnlyAchievementIdentifiers = AchievementManager.readOnlyAchievementIdentifiers;
			for (int i = 0; i < readOnlyAchievementIdentifiers.Count; i++)
			{
				string achievementIdentifier = readOnlyAchievementIdentifiers[i];
				if (string.IsNullOrEmpty(AchievementManager.GetAchievementDef(achievementIdentifier).prerequisiteAchievementIdentifier))
				{
					AddAchievementToOrderedList(achievementIdentifier, encounteredIdentifiers);
				}
			}
		}

		private static void AddAchievementToOrderedList(string achievementIdentifier, HashSet<string> encounteredIdentifiers)
		{
			if (!encounteredIdentifiers.Contains(achievementIdentifier))
			{
				encounteredIdentifiers.Add(achievementIdentifier);
				sortedAchievementIdentifiers.Add(achievementIdentifier);
				string[] childAchievementIdentifiers = AchievementManager.GetAchievementDef(achievementIdentifier).childAchievementIdentifiers;
				for (int i = 0; i < childAchievementIdentifiers.Length; i++)
				{
					AddAchievementToOrderedList(childAchievementIdentifiers[i], encounteredIdentifiers);
				}
			}
		}

		private void SetCardCount(int desiredCardCount)
		{
			while (cardsList.Count < desiredCardCount)
			{
				AchievementCardController component = UnityEngine.Object.Instantiate(achievementCardPrefab, container).GetComponent<AchievementCardController>();
				cardsList.Add(component);
			}
			while (cardsList.Count > desiredCardCount)
			{
				UnityEngine.Object.Destroy(cardsList[cardsList.Count - 1].gameObject);
				cardsList.RemoveAt(cardsList.Count - 1);
			}
		}

		private void Rebuild()
		{
			UserProfile userProfile = GetUserProfile();
			SetCardCount(sortedAchievementIdentifiers.Count);
			for (int i = 0; i < sortedAchievementIdentifiers.Count; i++)
			{
				cardsList[i].SetAchievement(sortedAchievementIdentifiers[i], userProfile);
			}
		}
	}
	public class AchievementNotificationPanel : MonoBehaviour
	{
		private static readonly List<AchievementNotificationPanel> instancesList = new List<AchievementNotificationPanel>();

		public UnityEngine.UI.Image achievementIconImage;

		public TextMeshProUGUI achievementName;

		public TextMeshProUGUI achievementDescription;

		public GameObject rewardArea;

		public TextMeshProUGUI rewardAmount;

		public UnityEvent onStart;

		private void Awake()
		{
			instancesList.Add(this);
			onStart.Invoke();
		}

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

		public void SetAchievementDef(AchievementDef achievementDef)
		{
			achievementIconImage.sprite = achievementDef.GetAchievedIcon();
			achievementName.text = Language.GetString(achievementDef.nameToken);
			achievementDescription.text = Language.GetString(achievementDef.descriptionToken);
			if (achievementDef.lunarCoinReward != 0)
			{
				rewardArea.SetActive(value: true);
				rewardAmount.text = achievementDef.GetReward();
			}
		}

		[CanBeNull]
		private static Canvas GetUserCanvas([NotNull] LocalUser localUser)
		{
			if ((bool)Run.instance)
			{
				CameraRigController cameraRigController = localUser.cameraRigController;
				if (!cameraRigController)
				{
					return null;
				}
				HUD hud = cameraRigController.hud;
				if (!hud)
				{
					return null;
				}
				return hud.mainContainerCanvas;
			}
			return RoR2Application.instance.mainCanvas;
		}

		private static bool IsAppropriateTimeToDisplayUserAchievementNotification(LocalUser localUser)
		{
			return !GameOverController.instance;
		}

		private static void DispatchAchievementNotification(Canvas canvas, AchievementDef achievementDef)
		{
			UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/AchievementNotificationPanel"), canvas.transform).GetComponent<AchievementNotificationPanel>().SetAchievementDef(achievementDef);
			Util.PlaySound(achievementDef.GetAchievementSoundString(), RoR2Application.instance.gameObject);
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			RoR2Application.onFixedUpdate += StaticFixedUpdate;
		}

		private static void StaticFixedUpdate()
		{
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				if (!readOnlyLocalUsers.userProfile.hasUnviewedAchievement)
				{
					continue;
				}
				Canvas canvas = GetUserCanvas(readOnlyLocalUsers);
				if (canvas == null || instancesList.Any((AchievementNotificationPanel instance) => instance.transform.parent == canvas.transform) || !IsAppropriateTimeToDisplayUserAchievementNotification(readOnlyLocalUsers))
				{
					continue;
				}
				string text = readOnlyLocalUsers.userProfile.PopNextUnviewedAchievementName();
				if (text != null)
				{
					AchievementDef achievementDef = AchievementManager.GetAchievementDef(text);
					if (achievementDef != null)
					{
						DispatchAchievementNotification(canvas, achievementDef);
					}
				}
			}
		}
	}
	public class ActiveReloadBarController : MonoBehaviour
	{
		[SerializeField]
		private RectTransform timeIndicatorTransform;

		[SerializeField]
		private RectTransform windowIndicatorTransform;

		[SerializeField]
		private Animator animator;

		[SerializeField]
		private string isWindowActiveParamName;

		[SerializeField]
		private string wasWindowHitParamName;

		[SerializeField]
		private string wasFailureParamName;

		private int isWindowActiveParamHash;

		private int wasWindowHitParamHash;

		private int wasFailureParamHash;

		public void OnEnable()
		{
			isWindowActiveParamHash = Animator.StringToHash(isWindowActiveParamName);
			wasWindowHitParamHash = Animator.StringToHash(wasWindowHitParamName);
			wasFailureParamHash = Animator.StringToHash(wasFailureParamName);
			SetTValue(0f);
		}

		public void SetWindowRange(float tStart, float tEnd)
		{
			tStart = Mathf.Max(0f, tStart);
			tEnd = Mathf.Min(1f, tEnd);
			windowIndicatorTransform.anchorMin = new UnityEngine.Vector2(tStart, windowIndicatorTransform.anchorMin.y);
			windowIndicatorTransform.anchorMax = new UnityEngine.Vector2(tEnd, windowIndicatorTransform.anchorMax.y);
		}

		public void SetIsWindowActive(bool isWindowActive)
		{
			if ((bool)animator)
			{
				animator.SetBool(isWindowActiveParamHash, isWindowActive);
			}
		}

		public void SetWasWindowHit(bool wasWindowHit)
		{
			if ((bool)animator)
			{
				animator.SetBool(wasWindowHitParamHash, wasWindowHit);
			}
		}

		public void SetWasFailure(bool wasFailure)
		{
			if ((bool)animator)
			{
				animator.SetBool(wasFailureParamHash, wasFailure);
			}
		}

		public void SetTValue(float t)
		{
			timeIndicatorTransform.anchorMin = new UnityEngine.Vector2(t, timeIndicatorTransform.anchorMin.y);
			timeIndicatorTransform.anchorMax = new UnityEngine.Vector2(t, timeIndicatorTransform.anchorMax.y);
		}
	}
	[RequireComponent(typeof(LayoutElement))]
	[RequireComponent(typeof(RectTransform))]
	public class AllyCardController : MonoBehaviour
	{
		public HealthBar healthBar;

		public TextMeshProUGUI nameLabel;

		public RawImage portraitIconImage;

		private CharacterMaster cachedSourceMaster;

		private CharacterBody cachedSourceCharacterBody;

		private HealthComponent cachedHealthComponent;

		private string cachedBestName = "";

		private Texture cachedPortraitIcon;

		public bool shouldIndent { get; set; }

		public CharacterMaster sourceMaster { get; set; }

		public RectTransform rectTransform { get; private set; }

		public LayoutElement layoutElement { get; private set; }

		private void Awake()
		{
			rectTransform = (RectTransform)base.transform;
			layoutElement = GetComponent<LayoutElement>();
		}

		private void LateUpdate()
		{
			if (ShouldWeUpdate())
			{
				UpdateInfo();
			}
		}

		private bool ShouldWeUpdate()
		{
			if (sourceMaster != cachedSourceMaster)
			{
				return true;
			}
			CharacterBody body = sourceMaster.GetBody();
			if (body != cachedSourceCharacterBody)
			{
				return true;
			}
			if ((bool)body)
			{
				if (cachedHealthComponent != body.healthComponent || cachedPortraitIcon != body.portraitIcon)
				{
					return true;
				}
				if (cachedBestName != Util.GetBestBodyName(body.gameObject))
				{
					return true;
				}
			}
			else if (cachedBestName != Util.GetBestMasterName(sourceMaster))
			{
				return true;
			}
			return false;
		}

		private void UpdateInfo()
		{
			HealthComponent source = null;
			string text = "";
			Texture texture = null;
			if ((bool)sourceMaster)
			{
				cachedSourceMaster = sourceMaster;
				CharacterBody body = sourceMaster.GetBody();
				if ((bool)body)
				{
					texture = body.portraitIcon;
					source = body.healthComponent;
					text = Util.GetBestBodyName(body.gameObject);
					cachedSourceCharacterBody = body;
				}
				else
				{
					text = Util.GetBestMasterName(sourceMaster);
					cachedSourceCharacterBody = null;
				}
			}
			else
			{
				cachedSourceMaster = null;
			}
			healthBar.source = source;
			nameLabel.text = text;
			portraitIconImage.texture = texture;
			portraitIconImage.enabled = texture != null;
			cachedHealthComponent = source;
			cachedBestName = text;
			cachedPortraitIcon = texture;
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class AllyCardManager : MonoBehaviour, ILayoutGroup, ILayoutController
	{
		private struct SourceInfo
		{
			public readonly GameObject gameObject;

			public readonly TeamComponent teamComponent;

			public readonly CharacterMaster master;

			public SourceInfo(GameObject gameObject)
			{
				bool flag = gameObject;
				this.gameObject = gameObject;
				teamComponent = (flag ? gameObject.GetComponent<TeamComponent>() : null);
				CharacterBody characterBody = (flag ? gameObject.GetComponent<CharacterBody>() : null);
				master = (characterBody ? characterBody.master : null);
			}
		}

		private struct DisplayElement
		{
			public CharacterMaster master;

			public bool shouldIndent;

			public int priority;
		}

		private class DisplayElementComparer : IComparer<DisplayElement>
		{
			public static DisplayElementComparer instance = new DisplayElementComparer();

			public int Compare(DisplayElement a, DisplayElement b)
			{
				int num = a.priority - b.priority;
				if (num == 0)
				{
					num = (int)(a.master.netId.Value - b.master.netId.Value);
				}
				return num;
			}

			private DisplayElementComparer()
			{
			}
		}

		private struct CharacterData
		{
			public readonly CharacterMaster master;

			public readonly CharacterMaster leaderMaster;

			private readonly int masterInstanceId;

			private readonly int leaderMasterInstanceId;

			public readonly bool isMinion;

			public readonly bool isPlayer;

			public CharacterData(CharacterMaster master)
			{
				this.master = master;
				leaderMaster = master.minionOwnership.ownerMaster;
				isMinion = leaderMaster;
				isPlayer = master.playerCharacterMasterController;
				masterInstanceId = master.gameObject.GetInstanceID();
				leaderMasterInstanceId = (isMinion ? leaderMaster.gameObject.GetInstanceID() : 0);
			}

			public bool Equals(in CharacterData other)
			{
				if (masterInstanceId == other.masterInstanceId && leaderMasterInstanceId == other.leaderMasterInstanceId && isMinion == other.isMinion)
				{
					return isPlayer == other.isPlayer;
				}
				return false;
			}
		}

		private class CharacterDataSet
		{
			private CharacterData[] buffer = new CharacterData[128];

			private int _count;

			public int count => _count;

			public ref CharacterData this[int i] => ref buffer[i];

			public bool Equals(CharacterDataSet other)
			{
				if (other == null)
				{
					return false;
				}
				if (_count != other._count)
				{
					return false;
				}
				for (int i = 0; i < _count; i++)
				{
					if (!buffer[i].Equals(in other.buffer[i]))
					{
						return false;
					}
				}
				return true;
			}

			public void Clear()
			{
				Array.Clear(buffer, 0, _count);
				_count = 0;
			}

			public void Add(ref CharacterData element)
			{
				ArrayUtils.ArrayAppend(ref buffer, ref _count, in element);
			}

			public void CopyFrom(CharacterDataSet src)
			{
				int num = _count - src._count;
				if (num > 0)
				{
					Array.Clear(buffer, src._count, num);
				}
				ArrayUtils.EnsureCapacity(ref buffer, src.buffer.Length);
				_count = src.count;
				Array.Copy(src.buffer, buffer, _count);
			}
		}

		private static class CharacterDataSetPool
		{
			private static readonly Stack<CharacterDataSet> pool = new Stack<CharacterDataSet>();

			public static CharacterDataSet Request()
			{
				if (pool.Count == 0)
				{
					return new CharacterDataSet();
				}
				return pool.Pop();
			}

			public static void Return(ref CharacterDataSet characterDataSet)
			{
				characterDataSet.Clear();
				pool.Push(characterDataSet);
			}
		}

		public float indentWidth = 16f;

		private SourceInfo currentSource;

		private UIElementAllocator<AllyCardController> cardAllocator;

		private RectTransform rectTransform;

		private bool needsRefresh;

		private DisplayElement[] displayElements = Array.Empty<DisplayElement>();

		private int displayElementCount;

		private CharacterDataSet currentCharacterData;

		private float updateTimer;

		private const float updateDelay = 0f;

		public GameObject sourceGameObject
		{
			get
			{
				return currentSource.gameObject;
			}
			set
			{
				if ((object)currentSource.gameObject != value)
				{
					currentSource = new SourceInfo(value);
					OnSourceChanged();
				}
			}
		}

		private void OnCardCreated(int index, AllyCardController element)
		{
			UnityEngine.Vector2 anchorMin = element.rectTransform.anchorMin;
			anchorMin.x = 0f;
			anchorMin.y = 1f;
			element.rectTransform.anchorMin = anchorMin;
			anchorMin = element.rectTransform.anchorMax;
			anchorMin.x = 1f;
			anchorMin.y = 1f;
			element.rectTransform.anchorMax = anchorMin;
		}

		private void OnSourceChanged()
		{
			needsRefresh = true;
		}

		private TeamIndex FindTargetTeam()
		{
			TeamIndex result = TeamIndex.None;
			TeamComponent teamComponent = currentSource.teamComponent;
			if ((bool)teamComponent)
			{
				result = teamComponent.teamIndex;
			}
			return result;
		}

		private void SetCharacterData(CharacterDataSet newCharacterData)
		{
			if (!newCharacterData.Equals(currentCharacterData))
			{
				currentCharacterData.CopyFrom(newCharacterData);
				BuildFromCharacterData(currentCharacterData);
			}
		}

		private void PopulateCharacterDataSet(CharacterDataSet characterDataSet)
		{
			TeamIndex teamIndex = FindTargetTeam();
			ReadOnlyCollection<CharacterMaster> readOnlyInstancesList = CharacterMaster.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				CharacterMaster characterMaster = readOnlyInstancesList[i];
				if (characterMaster.teamIndex == teamIndex)
				{
					CharacterBody body = characterMaster.GetBody();
					if ((!body || !body.teamComponent || !body.teamComponent.hideAllyCardDisplay) && (!characterMaster.playerCharacterMasterController || (bool)characterMaster.playerCharacterMasterController.networkUser) && (object)currentSource.master != characterMaster)
					{
						CharacterData element = new CharacterData(characterMaster);
						characterDataSet.Add(ref element);
					}
				}
			}
		}

		private void BuildFromCharacterData(CharacterDataSet characterDataSet)
		{
			if (characterDataSet.count < displayElementCount)
			{
				Array.Clear(displayElements, characterDataSet.count, displayElementCount - characterDataSet.count);
			}
			displayElementCount = characterDataSet.count;
			ArrayUtils.EnsureCapacity(ref displayElements, displayElementCount);
			int i = 0;
			for (int count = characterDataSet.count; i < count; i++)
			{
				ref CharacterData reference = ref characterDataSet[i];
				displayElements[i] = new DisplayElement
				{
					master = reference.master,
					priority = -1
				};
			}
			int num = 0;
			int j = 0;
			for (int count2 = characterDataSet.count; j < count2; j++)
			{
				if (characterDataSet[j].isPlayer)
				{
					displayElements[j].priority = num;
					num += 2;
				}
			}
			int k = 0;
			for (int count3 = characterDataSet.count; k < count3; k++)
			{
				if (!characterDataSet[k].isMinion)
				{
					ref DisplayElement reference2 = ref displayElements[k];
					if (reference2.priority == -1)
					{
						reference2.priority = num;
						num += 2;
					}
				}
			}
			int l = 0;
			for (int count4 = characterDataSet.count; l < count4; l++)
			{
				ref CharacterData reference3 = ref characterDataSet[l];
				if (!reference3.isMinion)
				{
					continue;
				}
				ref DisplayElement reference4 = ref displayElements[l];
				if (reference4.priority == -1)
				{
					int num2 = FindIndexForMaster(reference3.leaderMaster);
					if (num2 != -1)
					{
						reference4.priority = displayElements[num2].priority + 1;
						reference4.shouldIndent = true;
					}
				}
			}
			int m = 0;
			for (int count5 = characterDataSet.count; m < count5; m++)
			{
				ref DisplayElement reference5 = ref displayElements[m];
				if (reference5.priority == -1)
				{
					reference5.priority = num;
					num += 2;
				}
			}
			Array.Sort(displayElements, 0, comparer: DisplayElementComparer.instance, length: displayElementCount);
			cardAllocator.AllocateElements(displayElementCount);
			for (int n = 0; n < displayElementCount; n++)
			{
				ref DisplayElement reference6 = ref displayElements[n];
				AllyCardController allyCardController = cardAllocator.elements[n];
				allyCardController.sourceMaster = reference6.master;
				allyCardController.shouldIndent = reference6.shouldIndent;
			}
			ArrayUtils.Clear(displayElements, ref displayElementCount);
			int FindIndexForMaster(CharacterMaster master)
			{
				for (int num3 = 0; num3 < displayElementCount; num3++)
				{
					if ((object)master == displayElements[num3].master)
					{
						return num3;
					}
				}
				return -1;
			}
		}

		private void Awake()
		{
			cardAllocator = new UIElementAllocator<AllyCardController>((RectTransform)base.transform, LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/AllyCard"));
			rectTransform = (RectTransform)base.transform;
			UIElementAllocator<AllyCardController> uIElementAllocator = cardAllocator;
			uIElementAllocator.onCreateElement = (UIElementAllocator<AllyCardController>.ElementOperationDelegate)Delegate.Combine(uIElementAllocator.onCreateElement, new UIElementAllocator<AllyCardController>.ElementOperationDelegate(OnCardCreated));
		}

		private void Update()
		{
			updateTimer -= Time.deltaTime;
			if (updateTimer <= 0f)
			{
				updateTimer = 0f;
				CharacterDataSet characterDataSet = CharacterDataSetPool.Request();
				PopulateCharacterDataSet(characterDataSet);
				SetCharacterData(characterDataSet);
				CharacterDataSetPool.Return(ref characterDataSet);
			}
		}

		private void OnEnable()
		{
			needsRefresh = true;
			currentCharacterData = CharacterDataSetPool.Request();
		}

		private void OnDisable()
		{
			CharacterDataSetPool.Return(ref currentCharacterData);
		}

		public void SetLayoutHorizontal()
		{
			if (cardAllocator != null)
			{
				ReadOnlyCollection<AllyCardController> elements = cardAllocator.elements;
				int i = 0;
				for (int count = elements.Count; i < count; i++)
				{
					AllyCardController allyCardController = elements[i];
					RectTransform obj = allyCardController.rectTransform;
					UnityEngine.Vector2 offsetMin = obj.offsetMin;
					offsetMin.x = (allyCardController.shouldIndent ? indentWidth : 0f);
					obj.offsetMin = offsetMin;
					offsetMin = obj.offsetMax;
					offsetMin.x = 0f;
					obj.offsetMax = offsetMin;
				}
			}
		}

		public void SetLayoutVertical()
		{
			if (cardAllocator != null)
			{
				ReadOnlyCollection<AllyCardController> elements = cardAllocator.elements;
				float b = this.rectTransform.rect.height / (float)elements.Count;
				float num = 0f;
				int i = 0;
				for (int count = elements.Count; i < count; i++)
				{
					AllyCardController allyCardController = elements[i];
					RectTransform rectTransform = allyCardController.rectTransform;
					float preferredHeight = allyCardController.layoutElement.preferredHeight;
					rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, preferredHeight);
					UnityEngine.Vector2 anchoredPosition = rectTransform.anchoredPosition;
					anchoredPosition.y = num;
					rectTransform.anchoredPosition = anchoredPosition;
					num -= Mathf.Min(preferredHeight, b);
				}
			}
		}
	}
	public class AmbientLevelDisplay : MonoBehaviour
	{
		public TextMeshProUGUI text;

		private int lastLevel = -1;

		private void Update()
		{
			int num = -1;
			if ((bool)Run.instance)
			{
				num = Run.instance.ambientLevelFloor;
			}
			if (num != lastLevel)
			{
				string text = "-";
				if ((bool)Run.instance)
				{
					text = num.ToString();
				}
				this.text.text = Language.GetStringFormatted("AMBIENT_LEVEL_DISPLAY_FORMAT", text);
				lastLevel = num;
			}
		}
	}
	public class AnimateUIAlpha : MonoBehaviour
	{
		public AnimationCurve alphaCurve;

		public UnityEngine.UI.Image image;

		public RawImage rawImage;

		public SpriteRenderer spriteRenderer;

		public float timeMax = 5f;

		public bool destroyOnEnd;

		public bool loopOnEnd;

		public bool disableGameObjectOnEnd;

		[HideInInspector]
		public float time;

		private UnityEngine.Color originalColor;

		private void Start()
		{
			if ((bool)image)
			{
				originalColor = image.color;
			}
			if ((bool)rawImage)
			{
				originalColor = rawImage.color;
			}
			else if ((bool)spriteRenderer)
			{
				originalColor = spriteRenderer.color;
			}
			UpdateAlphas(0f);
		}

		private void OnDisable()
		{
			time = 0f;
		}

		private void Update()
		{
			UpdateAlphas(Time.unscaledDeltaTime);
		}

		private void UpdateAlphas(float deltaTime)
		{
			time = Mathf.Min(timeMax, time + deltaTime);
			float num = alphaCurve.Evaluate(time / timeMax);
			UnityEngine.Color color = new UnityEngine.Color(originalColor.r, originalColor.g, originalColor.b, originalColor.a * num);
			if ((bool)image)
			{
				image.color = color;
			}
			if ((bool)rawImage)
			{
				rawImage.color = color;
			}
			else if ((bool)spriteRenderer)
			{
				spriteRenderer.color = color;
			}
			if (loopOnEnd && time >= timeMax)
			{
				time -= timeMax;
			}
			if (destroyOnEnd && time >= timeMax)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
			if (disableGameObjectOnEnd && time >= timeMax)
			{
				base.gameObject.SetActive(value: false);
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class ArtifactDisplayPanelController : MonoBehaviour
	{
		[Tooltip("The panel object that this component controls. Should usually a child, as this component manages the enabled/disabled status of the designated gameobject.")]
		public GameObject panelObject;

		public RectTransform iconContainer;

		public GameObject iconPrefab;

		private UIElementAllocator<RawImage> iconAllocator;

		public void SetDisplayData<T>(ref T enabledArtifacts) where T : IEnumerator<ArtifactDef>
		{
			if (!panelObject)
			{
				return;
			}
			enabledArtifacts.Reset();
			int num = 0;
			while (enabledArtifacts.MoveNext())
			{
				num++;
			}
			panelObject.SetActive(num > 0);
			if (iconAllocator == null)
			{
				iconAllocator = new UIElementAllocator<RawImage>(iconContainer, iconPrefab);
			}
			iconAllocator.AllocateElements(num);
			int num2 = 0;
			enabledArtifacts.Reset();
			while (enabledArtifacts.MoveNext())
			{
				RawImage rawImage = iconAllocator.elements[num2++];
				ArtifactDef current = enabledArtifacts.Current;
				rawImage.texture = current.smallIconSelectedSprite.texture;
				TooltipProvider component = rawImage.GetComponent<TooltipProvider>();
				if ((bool)component)
				{
					component.titleToken = current.nameToken;
					component.titleColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Artifact);
					component.bodyToken = current.descriptionToken;
					component.bodyColor = UnityEngine.Color.black;
					component.extraUIDisplayPrefab = current.extraUIDisplayPrefab;
				}
			}
		}
	}
	public class ArtifactOfRebirthTooltipController : MonoBehaviour
	{
		public InspectPanelController inspectPanelController;

		private InspectInfo inspectInfo;

		private void Awake()
		{
			Initialize();
		}

		public void Start()
		{
			ShowInspectInfoIfAvailable();
		}

		public void OnEnable()
		{
			ShowInspectInfoIfAvailable();
		}

		public void Initialize()
		{
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				if (readOnlyLocalPlayers.isLocalPlayer)
				{
					inspectPanelController.gameObject.SetActive(value: true);
					ItemIndex rebirthItem = readOnlyLocalPlayers.rebirthItem;
					if (rebirthItem != ItemIndex.None)
					{
						PickupIndex pickupIndex = PickupCatalog.FindPickupIndex(rebirthItem);
						inspectInfo = PickupCatalog.GetPickupDef(pickupIndex);
						inspectInfo.MarkForceShowInfo();
					}
					break;
				}
			}
		}

		private void ShowInspectInfoIfAvailable()
		{
			if (inspectInfo != null)
			{
				inspectPanelController.Show(inspectInfo);
			}
			else
			{
				inspectPanelController.ForceEnableInspectPanel();
			}
		}
	}
	public class AssignStageToken : MonoBehaviour
	{
		public TextMeshProUGUI titleText;

		public TextMeshProUGUI subtitleText;

		private void Start()
		{
			SceneDef mostRecentSceneDef = SceneCatalog.mostRecentSceneDef;
			titleText.SetText(Language.GetString(mostRecentSceneDef.nameToken));
			subtitleText.SetText(Language.GetString(mostRecentSceneDef.subtitleToken));
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class BaseSettingsControl : MonoBehaviour
	{
		public enum SettingSource
		{
			ConVar,
			UserProfilePref,
			None
		}

		public SettingSource settingSource;

		[FormerlySerializedAs("convarName")]
		public string settingName;

		public string nameToken;

		public LanguageTextMeshController nameLabel;

		[Tooltip("Whether or not this setting requires a confirmation dialog. This is mainly for video options.")]
		public bool useConfirmationDialog;

		[Tooltip("Whether or not this updates every frame. Should be disabled unless the setting is being modified from some other source.")]
		public bool updateControlsInUpdate;

		public UnityAction onValueChanged;

		private MPEventSystemLocator eventSystemLocator;

		private static UserProfile defaultUserProfile;

		private string originalValue;

		public bool hasBeenChanged => originalValue != null;

		protected bool inUpdateControls { get; private set; }

		protected void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			if ((bool)nameLabel && !string.IsNullOrEmpty(nameToken))
			{
				nameLabel.token = nameToken;
			}
			if (settingSource == SettingSource.ConVar && GetConVar() == null)
			{
				UnityEngine.Debug.LogErrorFormat("Null convar {0} detected in options", settingName);
			}
		}

		protected void Start()
		{
			Initialize();
			UpdateControls();
		}

		protected void OnEnable()
		{
			UpdateControls();
		}

		protected virtual void Update()
		{
			if (updateControlsInUpdate)
			{
				UpdateControls();
			}
		}

		public virtual void Initialize()
		{
		}

		public void SubmitSetting(string newValue)
		{
			if (useConfirmationDialog)
			{
				SubmitSettingTemporary(newValue);
			}
			else
			{
				SubmitSettingInternal(newValue);
			}
		}

		private void SubmitSettingInternal(string newValue)
		{
			if (originalValue == null)
			{
				originalValue = GetCurrentValue();
			}
			if (originalValue == newValue)
			{
				originalValue = null;
			}
			switch (settingSource)
			{
			case SettingSource.ConVar:
				GetConVar()?.AttemptSetString(newValue);
				break;
			case SettingSource.UserProfilePref:
				GetCurrentUserProfile()?.SetSaveFieldString(settingName, newValue);
				break;
			}
			RoR2Application.onNextUpdate += UpdateControls;
			onValueChanged?.Invoke();
		}

		private void SubmitSettingTemporary(string newValue)
		{
			string oldValue = GetCurrentValue();
			if (newValue == oldValue)
			{
				return;
			}
			SubmitSettingInternal(newValue);
			SimpleDialogBox dialogBox = SimpleDialogBox.Create();
			Action revertFunction = delegate
			{
				if ((bool)dialogBox)
				{
					SubmitSettingInternal(oldValue);
				}
			};
			float num = 10f;
			float timeEnd = Time.unscaledTime + num;
			MPButton revertButton = dialogBox.AddActionButton(delegate
			{
				revertFunction();
			}, "OPTION_REVERT", true);
			dialogBox.AddActionButton(delegate
			{
			}, "OPTION_ACCEPT", true);
			Action updateText = null;
			updateText = delegate
			{
				if ((bool)dialogBox)
				{
					int num2 = Mathf.FloorToInt(timeEnd - Time.unscaledTime);
					if (num2 < 0)
					{
						num2 = 0;
					}
					dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
					{
						token = "OPTION_AUTOREVERT_DIALOG_DESCRIPTION",
						formatParams = new object[1] { num2 }
					};
					if (num2 > 0)
					{
						RoR2Application.unscaledTimeTimers.CreateTimer(1f, updateText);
					}
				}
			};
			updateText();
			dialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "OPTION_AUTOREVERT_DIALOG_TITLE"
			};
			RoR2Application.unscaledTimeTimers.CreateTimer(num, delegate
			{
				if ((bool)revertButton)
				{
					revertButton.onClick.Invoke();
				}
			});
		}

		public string GetCurrentValue()
		{
			return settingSource switch
			{
				SettingSource.ConVar => GetConVar()?.GetString(), 
				SettingSource.UserProfilePref => GetCurrentUserProfile()?.GetSaveFieldString(settingName) ?? "", 
				_ => "", 
			};
		}

		protected BaseConVar GetConVar()
		{
			return Console.instance.FindConVar(settingName);
		}

		public UserProfile GetCurrentUserProfile()
		{
			return eventSystemLocator.eventSystem?.localUser?.userProfile;
		}

		public void Revert()
		{
			if (hasBeenChanged)
			{
				SubmitSetting(originalValue);
				originalValue = null;
			}
		}

		public void ResetToDefault()
		{
			string newValue = null;
			switch (settingSource)
			{
			case SettingSource.ConVar:
				newValue = GetConVar()?.defaultValue;
				break;
			case SettingSource.UserProfilePref:
				newValue = GetOrCreateDefaultProfile()?.GetSaveFieldString(settingName) ?? "";
				break;
			}
			SubmitSetting(newValue);
		}

		private UserProfile GetOrCreateDefaultProfile()
		{
			if (defaultUserProfile == null)
			{
				defaultUserProfile = PlatformSystems.saveSystem.CreateGuestProfile();
			}
			return defaultUserProfile;
		}

		public virtual void SetSettingState(bool turnedOn)
		{
		}

		public virtual bool IsSettingEnabled()
		{
			return true;
		}

		protected void UpdateControls()
		{
			if ((bool)this && !inUpdateControls)
			{
				inUpdateControls = true;
				OnUpdateControls();
				inUpdateControls = false;
			}
		}

		protected virtual void OnUpdateControls()
		{
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class BuffDisplay : MonoBehaviour
	{
		public class BuffIconDisplayData
		{
			public BuffIndex buffIndex;

			public BuffIcon buffIconComponent;

			public BuffDef buffDef;

			public int buffCount;

			public bool removeIcon;

			public BuffIconDisplayData(BuffIndex _buffIndex)
			{
				buffIndex = _buffIndex;
				buffDef = BuffCatalog.GetBuffDef(_buffIndex);
				buffCount = 0;
				buffIconComponent = null;
				removeIcon = false;
			}
		}

		private static int _staticFrameIndex;

		private static int maxFramesToWait = 4;

		private int frameIndex;

		private static PrefabComponentPool<BuffIcon> pool;

		private List<BuffIconDisplayData> buffIconDisplayData = new List<BuffIconDisplayData>();

		private bool buffsReallocated;

		private RectTransform rectTranform;

		private CharacterBody source;

		public GameObject buffIconPrefab;

		public float iconWidth = 24f;

		private static int frameIndexTicket
		{
			get
			{
				_staticFrameIndex = (_staticFrameIndex + 1) % maxFramesToWait;
				return _staticFrameIndex;
			}
		}

		private void Awake()
		{
			frameIndex = frameIndexTicket;
			rectTranform = GetComponent<RectTransform>();
			if (pool == null)
			{
				pool = new PrefabComponentPool<BuffIcon>
				{
					PrefabObject = buffIconPrefab,
					AlwaysGrowable = true,
					AddComponentIfMissing = true
				};
				pool.Initialize(1, 3);
			}
		}

		public void SetSource(CharacterBody _source)
		{
			if (!(source == _source))
			{
				source = _source;
				ResetAllocatedIcons();
			}
		}

		private void ResetAllocatedIcons()
		{
			PrepareToCullBuffDisplayData();
			CullExpiredBuffIcons();
			buffsReallocated = false;
			UpdateLayout();
		}

		private void AllocateIcons()
		{
			if (buffsReallocated || source == null)
			{
				return;
			}
			PrepareToCullBuffDisplayData();
			int num = this.buffIconDisplayData.Count;
			int i = 0;
			int num2 = num;
			BuffIndex[] nonHiddenBuffIndices = BuffCatalog.nonHiddenBuffIndices;
			foreach (BuffIndex buffIndex in nonHiddenBuffIndices)
			{
				if (!source.HasBuff(buffIndex))
				{
					continue;
				}
				int buffCount = source.GetBuffCount(buffIndex);
				for (; i < num && this.buffIconDisplayData[i].buffIndex < buffIndex; i++)
				{
				}
				if (i < num)
				{
					BuffIconDisplayData buffIconDisplayData = this.buffIconDisplayData[i];
					if (buffIconDisplayData.buffIndex == buffIndex)
					{
						buffsReallocated |= buffIconDisplayData.buffCount != buffCount;
						buffIconDisplayData.removeIcon = false;
						buffIconDisplayData.buffCount = buffCount;
						i++;
					}
					else
					{
						buffIconDisplayData = new BuffIconDisplayData(buffIndex);
						buffIconDisplayData.buffCount = buffCount;
						this.buffIconDisplayData.Insert(i, buffIconDisplayData);
						i++;
						num++;
						buffsReallocated = true;
					}
				}
				else
				{
					BuffIconDisplayData buffIconDisplayData = new BuffIconDisplayData(buffIndex);
					buffIconDisplayData.buffCount = buffCount;
					this.buffIconDisplayData.Add(buffIconDisplayData);
					buffsReallocated = true;
				}
			}
			buffsReallocated |= num2 != this.buffIconDisplayData.Count;
		}

		private void PrepareToCullBuffDisplayData()
		{
			foreach (BuffIconDisplayData buffIconDisplayDatum in buffIconDisplayData)
			{
				buffIconDisplayDatum.removeIcon = true;
			}
		}

		private void CullExpiredBuffIcons()
		{
			for (int num = this.buffIconDisplayData.Count - 1; num >= 0; num--)
			{
				BuffIconDisplayData buffIconDisplayData = this.buffIconDisplayData[num];
				if (buffIconDisplayData.removeIcon || buffIconDisplayData.buffDef == null || (buffIconDisplayData.buffDef != null && buffIconDisplayData.buffDef.iconSprite == null))
				{
					if (buffIconDisplayData.buffIconComponent != null)
					{
						ReturnBuffIconToPool(buffIconDisplayData.buffIconComponent);
					}
					this.buffIconDisplayData.RemoveAt(num);
					buffsReallocated = true;
				}
			}
		}

		public void UpdateLayout()
		{
			AllocateIcons();
			CullExpiredBuffIcons();
			if (!buffsReallocated)
			{
				return;
			}
			if ((bool)source)
			{
				UnityEngine.Vector2 zero = UnityEngine.Vector2.zero;
				foreach (BuffIconDisplayData buffIconDisplayDatum in buffIconDisplayData)
				{
					if (buffIconDisplayDatum.buffIconComponent == null)
					{
						buffIconDisplayDatum.buffIconComponent = GetNewBuffIcon();
					}
					BuffIcon buffIconComponent = buffIconDisplayDatum.buffIconComponent;
					buffIconComponent.buffDef = buffIconDisplayDatum.buffDef;
					buffIconComponent.buffCount = buffIconDisplayDatum.buffCount;
					buffIconComponent.rectTransform.anchoredPosition = zero;
					zero.x += iconWidth;
					buffIconComponent.UpdateIcon();
				}
			}
			buffsReallocated = false;
		}

		private void Update()
		{
			if (frameIndex == 0)
			{
				UpdateLayout();
			}
			frameIndex = (frameIndex + 1) % maxFramesToWait;
		}

		private BuffIcon GetNewBuffIcon()
		{
			BuffIcon @object = pool.GetObject();
			@object.ResetBuffIcon();
			Transform obj = @object.transform;
			obj.SetParent(rectTranform);
			obj.localPosition = UnityEngine.Vector3.zero;
			obj.localScale = UnityEngine.Vector3.one;
			@object.gameObject.SetActive(value: true);
			return @object;
		}

		private void ReturnBuffIconToPool(BuffIcon buffIcon)
		{
			buffIcon.transform.SetParent(null);
			pool.ReturnObject(buffIcon);
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class BuffIcon : MonoBehaviour
	{
		public BuffDef buffDef;

		private BuffDef lastBuffDef;

		public int buffCount;

		private int lastBuffCount;

		public UnityEngine.UI.Image iconImage;

		public TextMeshProUGUI stackCount;

		private float stopwatch;

		private const float flashDuration = 0.25f;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		public RectTransform rectTransform { get; private set; }

		private void Awake()
		{
			rectTransform = GetComponent<RectTransform>();
		}

		private void OnEnable()
		{
			UpdateIcon();
		}

		private void OnDisable()
		{
			ResetBuffIcon();
		}

		public void ResetBuffIcon()
		{
			buffDef = null;
			lastBuffCount = -1;
		}

		public void Flash()
		{
			iconImage.color = UnityEngine.Color.white;
			iconImage.CrossFadeColor(buffDef.buffColor, 0.25f, ignoreTimeScale: true, useAlpha: false);
		}

		public void UpdateIcon()
		{
			if (buffDef == lastBuffDef && buffCount == lastBuffCount)
			{
				return;
			}
			lastBuffDef = buffDef;
			lastBuffCount = buffCount;
			if ((bool)buffDef)
			{
				iconImage.enabled = true;
				iconImage.sprite = buffDef.iconSprite;
				iconImage.color = buffDef.buffColor;
				if (buffDef.canStack)
				{
					sharedStringBuilder.Clear();
					sharedStringBuilder.Append("x");
					sharedStringBuilder.AppendInt(buffCount);
					stackCount.enabled = true;
					stackCount.SetText(sharedStringBuilder);
				}
				else
				{
					stackCount.enabled = false;
				}
			}
			else
			{
				iconImage.sprite = null;
				iconImage.enabled = false;
				stackCount.enabled = false;
			}
		}
	}
	public class ButtonSelectionController : MonoBehaviour
	{
		public MPButton[] buttons;

		public void SelectThisButton(MPButton selectedButton)
		{
			for (int i = 0; i < buttons.Length; i++)
			{
				_ = buttons[i] == selectedButton;
			}
		}
	}
	public class CarouselController : BaseSettingsControl
	{
		[Serializable]
		public struct Choice
		{
			public string suboptionDisplayToken;

			public string convarValue;

			public Sprite customSprite;
		}

		public GameObject leftArrowButton;

		public GameObject rightArrowButton;

		public UnityEngine.UI.Image optionalImage;

		public TextMeshProUGUI optionalText;

		[FormerlySerializedAs("choices")]
		[SerializeField]
		[NotNull]
		private Choice[] _choices = Array.Empty<Choice>();

		public bool forceValidChoice;

		[Tooltip("If true, this setting will control+reflect the given subsectionHelper's child settings")]
		public bool controlsSubsection;

		public SettingSubsectionHelper subsectionHelper;

		private int selectionIndex;

		private HGButton leftButton;

		private HGButton rightButton;

		private HGButton carouselButton;

		[NotNull]
		public Choice[] choices
		{
			get
			{
				return _choices;
			}
			set
			{
				_choices = value;
				UpdateFromCurrentValue();
			}
		}

		public override void Initialize()
		{
			base.Initialize();
			if (controlsSubsection)
			{
				SetSettingState(subsectionHelper.AreAnyChildSettingsEnabled());
			}
		}

		protected override void OnUpdateControls()
		{
			UpdateFromCurrentValue();
		}

		public void ToggleArrowsInteractable(bool isInteractable)
		{
			if (leftButton == null)
			{
				leftButton = leftArrowButton.GetComponent<HGButton>();
			}
			if (rightButton == null)
			{
				rightButton = rightArrowButton.GetComponent<HGButton>();
			}
			if (carouselButton == null)
			{
				carouselButton = base.gameObject.GetComponent<HGButton>();
			}
			if (leftButton != null && rightButton != null && carouselButton != null)
			{
				leftButton.interactable = isInteractable;
				rightButton.interactable = isInteractable;
				carouselButton.interactable = isInteractable;
			}
		}

		public void MoveCarousel(int direction)
		{
			selectionIndex = Mathf.Clamp(selectionIndex + direction, 0, choices.Length - 1);
			UpdateFromSelectionIndex();
			SubmitSetting(choices[selectionIndex].convarValue);
		}

		public void BoolCarousel()
		{
			selectionIndex = ((selectionIndex == 0) ? 1 : 0);
			UpdateFromSelectionIndex();
			if (controlsSubsection)
			{
				subsectionHelper.ApplyStateToChildSettings(selectionIndex == 1);
			}
			SubmitSetting(choices[selectionIndex].convarValue);
		}

		public override void SetSettingState(bool turnedOn)
		{
			selectionIndex = (turnedOn ? 1 : 0);
			UpdateFromSelectionIndex();
			SubmitSetting(choices[selectionIndex].convarValue);
		}

		public override bool IsSettingEnabled()
		{
			return selectionIndex > 0;
		}

		private void UpdateFromCurrentValue()
		{
			if (controlsSubsection)
			{
				return;
			}
			string currentValue = GetCurrentValue();
			bool flag = false;
			for (int i = 0; i < choices.Length; i++)
			{
				if (choices[i].convarValue == currentValue)
				{
					flag = true;
					selectionIndex = i;
					break;
				}
			}
			if (!flag && forceValidChoice)
			{
				selectionIndex = 0;
			}
			UpdateFromSelectionIndex();
		}

		private void UpdateFromSelectionIndex()
		{
			string text = "OPTION_CUSTOM";
			Sprite sprite = null;
			if (0 <= selectionIndex && selectionIndex < choices.Length)
			{
				Choice choice = choices[selectionIndex];
				text = choice.suboptionDisplayToken;
				sprite = choice.customSprite;
			}
			else if (choices.Length == 0)
			{
				text = string.Empty;
			}
			if ((bool)optionalText)
			{
				optionalText.GetComponent<LanguageTextMeshController>().token = text ?? string.Empty;
			}
			if ((bool)optionalImage)
			{
				optionalImage.sprite = sprite;
			}
		}

		protected override void Update()
		{
			base.Update();
			bool active = true;
			bool active2 = true;
			if (selectionIndex == 0)
			{
				active = false;
			}
			if (selectionIndex == choices.Length - 1)
			{
				active2 = false;
			}
			if ((bool)leftArrowButton)
			{
				leftArrowButton.SetActive(active);
			}
			if ((bool)rightArrowButton)
			{
				rightArrowButton.SetActive(active2);
			}
		}
	}
	public class CarouselNavigationController : MonoBehaviour
	{
		public struct DisplayData : IEquatable<DisplayData>
		{
			public readonly int pageCount;

			public readonly int pageIndex;

			public DisplayData(int pageCount, int pageIndex)
			{
				this.pageCount = pageCount;
				this.pageIndex = pageIndex;
			}

			public bool Equals(DisplayData other)
			{
				if (pageCount == other.pageCount)
				{
					return pageIndex == other.pageIndex;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is DisplayData other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (pageCount * 397) ^ pageIndex;
			}
		}

		public GameObject buttonPrefab;

		public RectTransform container;

		public MPButton leftButton;

		public MPButton rightButton;

		public bool allowLooping;

		public UIElementAllocator<MPButton> buttonAllocator;

		private int currentPageIndex;

		private DisplayData displayData = new DisplayData(0, 0);

		public event Action<int> onPageChangeSubmitted;

		public event Action onUnderflow;

		public event Action onOverflow;

		private void Awake()
		{
			buttonAllocator = new UIElementAllocator<MPButton>(container, buttonPrefab);
		}

		private void Start()
		{
			if ((bool)leftButton)
			{
				leftButton.onClick.AddListener(NavigatePreviousPage);
			}
			if ((bool)rightButton)
			{
				rightButton.onClick.AddListener(NavigateNextPage);
			}
		}

		private void OnEnable()
		{
			Rebuild();
		}

		public void SetDisplayData(DisplayData newDisplayData)
		{
			if (!newDisplayData.Equals(displayData))
			{
				displayData = newDisplayData;
				Rebuild();
			}
		}

		private void Rebuild()
		{
			buttonAllocator.AllocateElements(displayData.pageCount);
			int i = 0;
			for (int count = buttonAllocator.elements.Count; i < count; i++)
			{
				MPButton mPButton = buttonAllocator.elements[i];
				ColorBlock colors = mPButton.colors;
				colors.colorMultiplier = 1f;
				mPButton.colors = colors;
				mPButton.onClick.RemoveAllListeners();
				DisplayData buttonDisplayData = new DisplayData(displayData.pageCount, i);
				mPButton.onClick.AddListener(delegate
				{
					SetDisplayData(buttonDisplayData);
					this.onPageChangeSubmitted?.Invoke(displayData.pageIndex);
				});
			}
			if (displayData.pageIndex >= 0 && displayData.pageIndex < displayData.pageCount)
			{
				MPButton mPButton2 = buttonAllocator.elements[displayData.pageIndex];
				ColorBlock colors2 = mPButton2.colors;
				colors2.colorMultiplier = 2f;
				mPButton2.colors = colors2;
			}
			bool flag = displayData.pageCount > 1;
			bool interactable = flag && (allowLooping || displayData.pageIndex > 0);
			bool interactable2 = flag && (allowLooping || displayData.pageIndex < displayData.pageCount - 1);
			if ((bool)leftButton)
			{
				leftButton.gameObject.SetActive(flag);
				leftButton.interactable = interactable;
			}
			if ((bool)rightButton)
			{
				rightButton.gameObject.SetActive(flag);
				rightButton.interactable = interactable2;
			}
		}

		public void NavigateNextPage()
		{
			if (displayData.pageCount <= 0)
			{
				return;
			}
			int num = displayData.pageIndex + 1;
			bool flag = num >= displayData.pageCount;
			if (flag)
			{
				if (!allowLooping)
				{
					return;
				}
				num = 0;
			}
			UnityEngine.Debug.LogFormat("NavigateNextPage() desiredPageIndex={0} overflow={1}", num, flag);
			SetDisplayData(new DisplayData(displayData.pageCount, num));
			this.onPageChangeSubmitted?.Invoke(num);
			if (flag)
			{
				this.onOverflow?.Invoke();
			}
		}

		public void NavigatePreviousPage()
		{
			if (displayData.pageCount <= 0)
			{
				return;
			}
			int num = displayData.pageIndex - 1;
			bool flag = num < 0;
			if (flag)
			{
				if (!allowLooping)
				{
					return;
				}
				num = displayData.pageCount - 1;
			}
			UnityEngine.Debug.LogFormat("NavigatePreviousPage() desiredPageIndex={0} underflow={1}", num, flag);
			SetDisplayData(new DisplayData(displayData.pageCount, num));
			this.onPageChangeSubmitted?.Invoke(num);
			if (flag)
			{
				this.onUnderflow?.Invoke();
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class CharacterSelectController : MonoBehaviour
	{
		[Serializable]
		public struct SkillStrip
		{
			public GameObject stripRoot;

			public UnityEngine.UI.Image skillIcon;

			public TextMeshProUGUI skillName;

			public TextMeshProUGUI skillDescription;
		}

		private struct BodyInfo
		{
			public readonly BodyIndex bodyIndex;

			public readonly GameObject bodyPrefab;

			public readonly CharacterBody bodyPrefabBodyComponent;

			public readonly UnityEngine.Color bodyColor;

			public readonly SkillLocator skillLocator;

			public readonly GenericSkill[] skillSlots;

			public BodyInfo(BodyIndex bodyIndex)
			{
				this.bodyIndex = bodyIndex;
				bodyPrefab = BodyCatalog.GetBodyPrefab(bodyIndex);
				bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndex);
				bodyColor = (bodyPrefabBodyComponent ? bodyPrefabBodyComponent.bodyColor : UnityEngine.Color.gray);
				skillLocator = (bodyPrefab ? bodyPrefab.GetComponent<SkillLocator>() : null);
				skillSlots = BodyCatalog.GetBodyPrefabSkillSlots(bodyIndex);
			}
		}

		private struct StripDisplayData
		{
			public bool enabled;

			public UnityEngine.Color primaryColor;

			public Sprite icon;

			public string titleString;

			public string descriptionString;

			public string keywordString;

			public string actionName;
		}

		[Header("Survivor Panel")]
		public TextMeshProUGUI survivorName;

		public UnityEngine.UI.Image[] primaryColorImages;

		public TextMeshProUGUI[] primaryColorTexts;

		public GameObject activeSurvivorInfoPanel;

		public GameObject inactiveSurvivorInfoPanel;

		[Header("Overview Panel")]
		public TextMeshProUGUI survivorDescription;

		[Header("Skill Panel")]
		public GameObject skillStripPrefab;

		public GameObject skillStripFillerPrefab;

		public RectTransform skillStripContainer;

		private UIElementAllocator<RectTransform> skillStripAllocator;

		private UIElementAllocator<RectTransform> skillStripFillerAllocator;

		[Tooltip("The header button for the loadout tab. Will be disabled if the user has no unlocked loadout options.")]
		[Header("Loadout Panel")]
		public GameObject loadoutHeaderButton;

		public ViewableTag loadoutViewableTag;

		[Header("Ready and Misc")]
		public MPButton readyButton;

		public MPButton unreadyButton;

		public GameObject[] multiplayerOnlyObjects;

		private MPEventSystemLocator eventSystemLocator;

		private CharacterSelectBarController characterSelectBarController;

		private MPEventSystem eventSystem;

		private LocalUser localUser;

		private SurvivorDef currentSurvivorDef;

		private static UnlockableDef[] loadoutAssociatedUnlockableDefs;

		private bool shouldRebuild = true;

		private bool shouldShowSurvivorInfoPanel;

		private void Awake()
		{
			EntitlementManager.UpdateLocalUsersEntitlements();
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			skillStripAllocator = new UIElementAllocator<RectTransform>(skillStripContainer, skillStripPrefab);
			skillStripFillerAllocator = new UIElementAllocator<RectTransform>(skillStripContainer, skillStripFillerPrefab);
			bool active = true;
			loadoutHeaderButton.SetActive(active);
			characterSelectBarController = GetComponentInChildren<CharacterSelectBarController>();
		}

		private void OnEnable()
		{
			UserProfile.onLoadoutChangedGlobal += OnLoadoutChangedGlobal;
			EntitlementManager.onEntitlementsUpdated += OnEntitlementsUpdated;
			eventSystemLocator.onEventSystemDiscovered += OnEventSystemDiscovered;
			eventSystemLocator.onEventSystemLost += OnEventSystemLost;
			if ((bool)eventSystemLocator.eventSystem)
			{
				OnEventSystemDiscovered(eventSystemLocator.eventSystem);
			}
		}

		private void OnDisable()
		{
			eventSystemLocator.onEventSystemLost -= OnEventSystemLost;
			eventSystemLocator.onEventSystemDiscovered -= OnEventSystemDiscovered;
			if ((bool)eventSystemLocator.eventSystem)
			{
				OnEventSystemLost(eventSystemLocator.eventSystem);
			}
			EntitlementManager.onEntitlementsUpdated -= OnEntitlementsUpdated;
			UserProfile.onLoadoutChangedGlobal -= OnLoadoutChangedGlobal;
		}

		private void Update()
		{
			SurvivorDef survivorDef = null;
			NetworkUser networkUser = localUser?.currentNetworkUser;
			if ((bool)networkUser)
			{
				survivorDef = networkUser.GetSurvivorPreference();
			}
			if ((object)currentSurvivorDef != survivorDef)
			{
				bool deselectButtons = false;
				if ((bool)currentSurvivorDef && (bool)survivorDef)
				{
					deselectButtons = currentSurvivorDef.cachedName != survivorDef.cachedName;
				}
				currentSurvivorDef = survivorDef;
				RebuildLocal(deselectButtons);
			}
			if (shouldRebuild)
			{
				shouldRebuild = false;
				RebuildLocal();
			}
			UpdateSurvivorInfoPanel();
			if (!RoR2Application.isInSinglePlayer)
			{
				bool flag = IsClientReady();
				readyButton.gameObject.SetActive(!flag);
				unreadyButton.gameObject.SetActive(flag);
			}
		}

		private void OnEntitlementsUpdated()
		{
			shouldRebuild = true;
		}

		private void OnEventSystemDiscovered(MPEventSystem discoveredEventSystem)
		{
			eventSystem = discoveredEventSystem;
			localUser = (eventSystem ? eventSystem.localUser : null);
			shouldRebuild = true;
		}

		private void OnEventSystemLost(MPEventSystem lostEventSystem)
		{
			eventSystem = null;
			localUser = null;
			shouldRebuild = true;
		}

		private static UnlockableDef[] GenerateLoadoutAssociatedUnlockableDefs()
		{
			HashSet<UnlockableDef> encounteredUnlockables = new HashSet<UnlockableDef>();
			foreach (SkillFamily allSkillFamily in SkillCatalog.allSkillFamilies)
			{
				for (int i = 0; i < allSkillFamily.variants.Length; i++)
				{
					TryAddUnlockableByDef(allSkillFamily.variants[i].unlockableDef);
				}
			}
			foreach (CharacterBody allBodyPrefabBodyBodyComponent in BodyCatalog.allBodyPrefabBodyBodyComponents)
			{
				SkinDef[] bodySkins = BodyCatalog.GetBodySkins(allBodyPrefabBodyBodyComponent.bodyIndex);
				for (int j = 0; j < bodySkins.Length; j++)
				{
					TryAddUnlockableByDef(bodySkins[j].unlockableDef);
				}
			}
			return encounteredUnlockables.ToArray();
			void TryAddUnlockableByDef(UnlockableDef unlockableDef)
			{
				if (unlockableDef != null)
				{
					encounteredUnlockables.Add(unlockableDef);
				}
			}
		}

		private static bool UserHasAnyLoadoutUnlockables(LocalUser localUser)
		{
			if (loadoutAssociatedUnlockableDefs == null)
			{
				loadoutAssociatedUnlockableDefs = GenerateLoadoutAssociatedUnlockableDefs();
			}
			UserProfile userProfile = localUser.userProfile;
			UnlockableDef[] array = loadoutAssociatedUnlockableDefs;
			foreach (UnlockableDef unlockableDef in array)
			{
				if (userProfile.HasUnlockable(unlockableDef))
				{
					return true;
				}
			}
			return false;
		}

		private void RebuildLocal(bool deselectButtons = false)
		{
			Loadout loadout = Loadout.RequestInstance();
			try
			{
				NetworkUser networkUser = localUser?.currentNetworkUser;
				SurvivorDef survivorDef = (networkUser ? networkUser.GetSurvivorPreference() : null);
				if (localUser.userProfile != null)
				{
					localUser.userProfile.loadout.EnforceUnlockables(localUser.userProfile);
				}
				localUser?.userProfile.CopyLoadout(loadout);
				BodyInfo bodyInfo = new BodyInfo(SurvivorCatalog.GetBodyIndexFromSurvivorIndex(survivorDef ? survivorDef.survivorIndex : SurvivorIndex.None));
				string sourceText = string.Empty;
				string sourceText2 = string.Empty;
				if ((bool)survivorDef)
				{
					sourceText = Language.GetString(survivorDef.displayNameToken);
					sourceText2 = Language.GetString(survivorDef.descriptionToken);
				}
				survivorName.SetText(sourceText);
				survivorDescription.SetText(sourceText2);
				UnityEngine.UI.Image[] array = primaryColorImages;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].color = bodyInfo.bodyColor;
				}
				TextMeshProUGUI[] array2 = primaryColorTexts;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i].color = bodyInfo.bodyColor;
				}
				List<StripDisplayData> list = new List<StripDisplayData>();
				BuildSkillStripDisplayData(loadout, in bodyInfo, list);
				skillStripFillerAllocator.AllocateElements(0);
				skillStripAllocator.AllocateElements(list.Count);
				for (int j = 0; j < list.Count; j++)
				{
					RebuildStrip(skillStripAllocator.elements[j], list[j]);
				}
				if (deselectButtons)
				{
					DeselectButton();
				}
				skillStripFillerAllocator.AllocateElements(Mathf.Max(0, 5 - list.Count));
				skillStripFillerAllocator.MoveElementsToContainerEnd();
				string empty = string.Empty;
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				stringBuilder.Append("/Loadout/Bodies/").Append(BodyCatalog.GetBodyName(bodyInfo.bodyIndex)).Append("/");
				empty = stringBuilder.ToString();
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
				loadoutViewableTag.viewableName = empty;
				bool active = RoR2Application.isInMultiPlayer && !RoR2Application.isInLocalMultiPlayer;
				GameObject[] array3 = multiplayerOnlyObjects;
				for (int i = 0; i < array3.Length; i++)
				{
					array3[i].SetActive(active);
				}
			}
			finally
			{
				Loadout.ReturnInstance(loadout);
			}
		}

		public void RebuildOptions()
		{
			characterSelectBarController?.Build();
		}

		public void DeselectButton()
		{
			if (eventSystem.currentSelectedGameObject != null)
			{
				eventSystem.SetSelectedGameObject(null);
			}
		}

		private void RebuildStrip(RectTransform skillStrip, StripDisplayData stripDisplayData)
		{
			GameObject gameObject = skillStrip.gameObject;
			UnityEngine.UI.Image component = skillStrip.Find("Inner/Icon").GetComponent<UnityEngine.UI.Image>();
			HGTextMeshProUGUI component2 = skillStrip.Find("Inner/SkillDescriptionPanel/SkillName").GetComponent<HGTextMeshProUGUI>();
			HGTextMeshProUGUI component3 = skillStrip.Find("Inner/SkillDescriptionPanel/SkillDescription").GetComponent<HGTextMeshProUGUI>();
			HGButton component4 = skillStrip.gameObject.GetComponent<HGButton>();
			if (stripDisplayData.enabled)
			{
				gameObject.SetActive(value: true);
				component.sprite = stripDisplayData.icon;
				component2.SetText(stripDisplayData.titleString);
				component2.color = stripDisplayData.primaryColor;
				component3.SetText(stripDisplayData.descriptionString);
				component4.hoverToken = stripDisplayData.keywordString;
			}
			else
			{
				gameObject.SetActive(value: false);
			}
		}

		private void BuildSkillStripDisplayData(Loadout loadout, in BodyInfo bodyInfo, List<StripDisplayData> dest)
		{
			if (!bodyInfo.bodyPrefab || !bodyInfo.bodyPrefabBodyComponent || !bodyInfo.skillLocator)
			{
				return;
			}
			BodyIndex bodyIndex = bodyInfo.bodyIndex;
			SkillLocator skillLocator = bodyInfo.skillLocator;
			GenericSkill[] skillSlots = bodyInfo.skillSlots;
			UnityEngine.Color bodyColor = bodyInfo.bodyColor;
			if (skillLocator.passiveSkill.enabled)
			{
				dest.Add(new StripDisplayData
				{
					enabled = true,
					primaryColor = bodyColor,
					icon = skillLocator.passiveSkill.icon,
					titleString = Language.GetString(skillLocator.passiveSkill.skillNameToken),
					descriptionString = Language.GetString(skillLocator.passiveSkill.skillDescriptionToken),
					keywordString = (string.IsNullOrEmpty(skillLocator.passiveSkill.keywordToken) ? "" : Language.GetString(skillLocator.passiveSkill.keywordToken)),
					actionName = ""
				});
			}
			for (int i = 0; i < skillSlots.Length; i++)
			{
				GenericSkill genericSkill = skillSlots[i];
				if (genericSkill.hideInCharacterSelect)
				{
					continue;
				}
				uint skillVariant = loadout.bodyLoadoutManager.GetSkillVariant(bodyIndex, i);
				SkillDef skillDef = genericSkill.skillFamily.variants[skillVariant].skillDef;
				string actionName = "";
				switch (skillLocator.FindSkillSlot(genericSkill))
				{
				case SkillSlot.Primary:
					actionName = "PrimarySkill";
					break;
				case SkillSlot.Secondary:
					actionName = "SecondarySkill";
					break;
				case SkillSlot.Utility:
					actionName = "UtilitySkill";
					break;
				case SkillSlot.Special:
					actionName = "SpecialSkill";
					break;
				}
				string keywordString = string.Empty;
				if (skillDef.keywordTokens != null)
				{
					StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
					for (int j = 0; j < skillDef.keywordTokens.Length; j++)
					{
						string @string = Language.GetString(skillDef.keywordTokens[j]);
						stringBuilder.Append(@string).Append("\n\n");
					}
					keywordString = stringBuilder.ToString();
					stringBuilder = HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
				}
				dest.Add(new StripDisplayData
				{
					enabled = true,
					primaryColor = bodyColor,
					icon = skillDef.icon,
					titleString = Language.GetString(skillDef.skillNameToken),
					descriptionString = Language.GetString(skillDef.skillDescriptionToken),
					keywordString = keywordString,
					actionName = actionName
				});
			}
		}

		private void OnLoadoutChangedGlobal(UserProfile userProfile)
		{
			if (userProfile == localUser?.userProfile)
			{
				shouldRebuild = true;
			}
		}

		private void UpdateSurvivorInfoPanel()
		{
			if ((bool)eventSystem && eventSystem.currentInputSource == MPEventSystem.InputSource.MouseAndKeyboard)
			{
				shouldShowSurvivorInfoPanel = true;
			}
			activeSurvivorInfoPanel.SetActive(shouldShowSurvivorInfoPanel);
			inactiveSurvivorInfoPanel.SetActive(!shouldShowSurvivorInfoPanel);
		}

		public void SetSurvivorInfoPanelActive(bool active)
		{
			shouldShowSurvivorInfoPanel = active;
			UpdateSurvivorInfoPanel();
		}

		private static bool InputPlayerIsAssigned(Player inputPlayer)
		{
			ReadOnlyCollection<NetworkUser> readOnlyInstancesList = NetworkUser.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				if (readOnlyInstancesList[i].inputPlayer == inputPlayer)
				{
					return true;
				}
			}
			return false;
		}

		public bool IsClientReady()
		{
			int num = 0;
			if (!PreGameController.instance)
			{
				return false;
			}
			VoteController component = PreGameController.instance.GetComponent<VoteController>();
			if (!component)
			{
				return false;
			}
			int i = 0;
			for (int voteCount = component.GetVoteCount(); i < voteCount; i++)
			{
				UserVote vote = component.GetVote(i);
				if ((bool)vote.networkUserObject && vote.receivedVote)
				{
					NetworkUser component2 = vote.networkUserObject.GetComponent<NetworkUser>();
					if ((bool)component2 && component2.isLocalPlayer)
					{
						num++;
					}
				}
			}
			return num == NetworkUser.readOnlyLocalPlayersList.Count;
		}

		public void ClientSetReady()
		{
			if (PauseManager.isPaused)
			{
				return;
			}
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				if ((bool)readOnlyLocalPlayers && eventSystemLocator.eventSystem == readOnlyLocalPlayers.localUser.eventSystem)
				{
					readOnlyLocalPlayers.CallCmdSubmitVote(PreGameController.instance.gameObject, 0);
				}
				else
				{
					_ = (bool)readOnlyLocalPlayers;
				}
			}
		}

		public void ClientSetUnready()
		{
			foreach (NetworkUser readOnlyLocalPlayers in NetworkUser.readOnlyLocalPlayersList)
			{
				readOnlyLocalPlayers.CallCmdSubmitVote(PreGameController.instance.gameObject, -1);
			}
		}
	}
	public class ChargeIndicatorController : MonoBehaviour
	{
		[Header("Cached Values")]
		public SpriteRenderer[] iconSprites;

		public TextMeshPro chargingText;

		public TextMeshPro pingText;

		public HoldoutZoneController holdoutZoneController;

		public ObjectScaleCurve pingBounceAnimation;

		[Header("Color Values")]
		public UnityEngine.Color spriteBaseColor;

		public UnityEngine.Color spriteFlashColor;

		public UnityEngine.Color spriteChargingColor;

		public UnityEngine.Color spriteChargedColor;

		public UnityEngine.Color textBaseColor;

		public UnityEngine.Color textChargingColor;

		public UnityEngine.Color playerPingColor;

		[Header("Options")]
		public bool disableTextWhenNotCharging;

		public bool disableTextWhenCharged;

		public bool flashWhenNotCharging;

		public float flashFrequency;

		[Header("Control Values - Don't assign via inspector!")]
		public bool isCharging;

		public bool isCharged;

		public bool isDiscovered;

		public bool isActivated;

		private float flashStopwatch;

		public bool isPinged;

		private UserProfile cachedUserProfile;

		private bool showIndicatorWhenDiscovered;

		public uint chargeValue { get; set; }

		private void Awake()
		{
			UserProfile userProfile = LocalUserManager.GetFirstLocalUser()?.userProfile;
			if (userProfile != null)
			{
				cachedUserProfile = userProfile;
			}
		}

		public void TriggerPing(string pingOwnerName, bool triggerAnimation = true)
		{
			if (!isActivated || isCharged)
			{
				pingText.SetText(pingOwnerName);
				isPinged = true;
				if (triggerAnimation)
				{
					TriggerPingAnimation();
				}
			}
		}

		public void TriggerPingAnimation()
		{
			if (cachedUserProfile != null)
			{
				showIndicatorWhenDiscovered = cachedUserProfile.useTeleporterDiscoveryIndicator;
			}
			if ((bool)pingBounceAnimation && (!isActivated || isCharged) && (showIndicatorWhenDiscovered || isPinged))
			{
				pingBounceAnimation.enabled = true;
				pingBounceAnimation.Reset();
			}
		}

		private void Update()
		{
			if ((bool)holdoutZoneController)
			{
				chargeValue = (uint)holdoutZoneController.displayChargePercent;
				isCharging = holdoutZoneController.isAnyoneCharging;
			}
			if (cachedUserProfile != null)
			{
				showIndicatorWhenDiscovered = cachedUserProfile.useTeleporterDiscoveryIndicator;
			}
			UnityEngine.Color color = spriteBaseColor;
			UnityEngine.Color color2 = textBaseColor;
			if (!isActivated && (isPinged || (isDiscovered && showIndicatorWhenDiscovered)))
			{
				color = (isPinged ? playerPingColor : spriteChargedColor);
				chargingText.enabled = false;
				pingText.enabled = isPinged;
			}
			else if (!isCharged)
			{
				pingText.enabled = false;
				if (flashWhenNotCharging)
				{
					flashStopwatch += Time.deltaTime;
					color = (((int)(flashStopwatch * flashFrequency) % 2 == 0) ? spriteFlashColor : spriteBaseColor);
				}
				if (isCharging)
				{
					color = spriteChargingColor;
					color2 = textChargingColor;
				}
				if (disableTextWhenNotCharging)
				{
					chargingText.enabled = isCharging;
				}
				else
				{
					chargingText.enabled = true;
				}
			}
			else
			{
				color = (isPinged ? playerPingColor : spriteChargedColor);
				chargingText.enabled = !disableTextWhenCharged && !isPinged;
				pingText.enabled = isPinged;
			}
			if (chargingText.enabled)
			{
				StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
				stringBuilder.AppendUint(chargeValue, 1u, 3u).Append("%");
				chargingText.SetText(stringBuilder);
				HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
			}
			if (pingText.enabled)
			{
				pingText.color = playerPingColor;
			}
			SpriteRenderer[] array = iconSprites;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].color = color;
			}
			chargingText.color = color2;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class ChatBox : MonoBehaviour
	{
		[Header("Cached Components")]
		public TMP_InputField messagesText;

		public TMP_InputField inputField;

		public Button sendButton;

		public Graphic[] gameplayHiddenGraphics;

		public RectTransform standardChatboxRect;

		public RectTransform expandedChatboxRect;

		public ScrollRect scrollRect;

		[Tooltip("The canvas group to use to fade this chat box. Leave empty for no fading behavior.")]
		public CanvasGroup fadeGroup;

		[Header("Parameters")]
		public bool allowExpandedChatbox;

		public bool deselectAfterSubmitChat;

		public bool deactivateInputFieldIfInactive;

		public float fadeWait = 5f;

		public float fadeDuration = 5f;

		private float fadeTimer;

		[Tooltip("If we're limiting the number of lines to display on this platform, only display this many lines")]
		public int lineCountLimit;

		private MPEventSystemLocator eventSystemLocator;

		private bool _showInput;

		private bool showKeybindTipOnStart => Chat.readOnlyLog.Count == 0;

		private bool showInput
		{
			get
			{
				return _showInput;
			}
			set
			{
				if (_showInput != value)
				{
					_showInput = value;
					RebuildChatRects();
					if ((bool)inputField && deactivateInputFieldIfInactive)
					{
						inputField.gameObject.SetActive(_showInput);
					}
					if ((bool)sendButton)
					{
						sendButton.gameObject.SetActive(_showInput);
					}
					for (int i = 0; i < gameplayHiddenGraphics.Length; i++)
					{
						gameplayHiddenGraphics[i].enabled = _showInput;
					}
					if (_showInput)
					{
						FocusInputField();
					}
					else
					{
						UnfocusInputField();
					}
				}
			}
		}

		private void UpdateFade(float deltaTime)
		{
			fadeTimer -= deltaTime;
			if ((bool)fadeGroup)
			{
				float alpha;
				if (!showInput)
				{
					alpha = ((fadeTimer < 0f) ? 0f : ((!(fadeTimer < fadeDuration)) ? 1f : Mathf.Sqrt(Util.Remap(fadeTimer, fadeDuration, 0f, 1f, 0f))));
				}
				else
				{
					alpha = 1f;
					ResetFadeTimer();
				}
				fadeGroup.alpha = alpha;
			}
		}

		private void ResetFadeTimer()
		{
			fadeTimer = fadeDuration + fadeWait;
		}

		public void SetShowInput(bool value)
		{
			showInput = value;
		}

		public void SubmitChat()
		{
			string text = inputField.text;
			if (text != "")
			{
				inputField.text = "";
				ReadOnlyCollection<NetworkUser> readOnlyLocalPlayersList = NetworkUser.readOnlyLocalPlayersList;
				if (readOnlyLocalPlayersList.Count > 0)
				{
					string text2 = text;
					text2 = text2.Replace("\\", "\\\\");
					text2 = text2.Replace("\"", "\\\"");
					Console.instance.SubmitCmd(readOnlyLocalPlayersList[0], "say \"" + text2 + "\"");
				}
			}
			UnityEngine.Debug.LogFormat("SubmitChat() submittedText={0}", text);
			if (deselectAfterSubmitChat)
			{
				showInput = false;
			}
			else
			{
				FocusInputField();
			}
		}

		public void OnInputFieldEndEdit()
		{
		}

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			showInput = true;
			showInput = false;
			Chat.onChatChanged += OnChatChangedHandler;
		}

		private void OnDestroy()
		{
			Chat.onChatChanged -= OnChatChangedHandler;
		}

		private void Start()
		{
			if (showKeybindTipOnStart && !RoR2Application.isInSinglePlayer)
			{
				Chat.AddMessage(Language.GetString("CHAT_KEYBIND_TIP"));
			}
			BuildChat();
			ScrollToBottom();
			inputField.resetOnDeActivation = true;
			Action callback = delegate
			{
				if (PlatformSystems.userManager.CurrentUserHasRestriction(UserManager.PlatformRestriction.TextChat))
				{
					inputField.gameObject.SetActive(value: false);
				}
			};
			if (PlatformSystems.userManager.CurrentUserHasRestriction(UserManager.PlatformRestriction.TextChat, callback))
			{
				inputField.gameObject.SetActive(value: false);
			}
		}

		private void OnEnable()
		{
			BuildChat();
			ScrollToBottom();
			Invoke("ScrollToBottom", 0f);
		}

		private void OnDisable()
		{
		}

		private void OnChatChangedHandler()
		{
			ResetFadeTimer();
			if (base.enabled)
			{
				BuildChat();
				ScrollToBottom();
			}
		}

		public void ScrollToBottom()
		{
			messagesText.verticalScrollbar.value = 0f;
			messagesText.verticalScrollbar.value = 1f;
		}

		private void BuildChat()
		{
			ReadOnlyCollection<string> readOnlyLog = Chat.readOnlyLog;
			int count = readOnlyLog.Count;
			string[] array = new string[count];
			readOnlyLog.CopyTo(array, 0);
			int num = count;
			messagesText.text = string.Join("\n", array, count - num, num);
			RebuildChatRects();
		}

		private void Update()
		{
			if (PlatformSystems.userManager.CurrentUserHasRestriction(UserManager.PlatformRestriction.TextChat))
			{
				return;
			}
			VirtualTextChatLookForInput();
			UpdateFade(Time.deltaTime);
			MPEventSystem eventSystem = eventSystemLocator.eventSystem;
			GameObject gameObject = (eventSystem ? eventSystem.currentSelectedGameObject : null);
			bool flag = false;
			flag = Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.KeypadEnter);
			if (!showInput && flag && !(ConsoleWindow.instance != null))
			{
				showInput = true;
			}
			else if (gameObject == inputField.gameObject)
			{
				if (flag)
				{
					if (showInput)
					{
						SubmitChat();
					}
					else if (!gameObject)
					{
						showInput = true;
					}
				}
				if (Input.GetKeyDown(KeyCode.Escape))
				{
					showInput = false;
				}
			}
			else
			{
				showInput = false;
			}
		}

		private void RebuildChatRects()
		{
			RectTransform component = scrollRect.GetComponent<RectTransform>();
			component.SetParent((showInput && allowExpandedChatbox) ? expandedChatboxRect : standardChatboxRect);
			component.offsetMin = UnityEngine.Vector2.zero;
			component.offsetMax = UnityEngine.Vector2.zero;
			ScrollToBottom();
		}

		private void FocusInputField()
		{
			MPEventSystem eventSystem = eventSystemLocator.eventSystem;
			if ((bool)eventSystem)
			{
				eventSystem.SetSelectedGameObject(inputField.gameObject);
			}
			inputField.ActivateInputField();
			inputField.text = "";
		}

		private void UnfocusInputField()
		{
			MPEventSystem eventSystem = eventSystemLocator.eventSystem;
			if ((bool)eventSystem && eventSystem.currentSelectedGameObject == inputField.gameObject)
			{
				eventSystem.SetSelectedGameObject(null);
			}
			inputField.DeactivateInputField();
		}

		public void VritualTextChatStart()
		{
		}

		public void VirtualTextChatSubmit()
		{
		}

		private void VirtualTextChatLookForInput()
		{
		}
	}
	[RequireComponent(typeof(RectTransform))]
	[RequireComponent(typeof(LayoutElement))]
	[ExecuteAlways]
	public class ColumnLayoutGroupElement : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler
	{
		private enum ClickLocation
		{
			None,
			Middle,
			RightHandle,
			LeftHandle
		}

		private RectTransform rectTransform;

		private LayoutElement layoutElement;

		public RectTransform rectTransformToLayoutInvalidate;

		private float handleWidth = 4f;

		private ClickLocation lastClickLocation;

		private void Awake()
		{
			rectTransform = (RectTransform)base.transform;
			layoutElement = GetComponent<LayoutElement>();
		}

		public void OnBeginDrag(PointerEventData eventData)
		{
			ClickLocation clickLocation = ClickLocation.None;
			if (RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out var localPoint))
			{
				UnityEngine.Rect rect = rectTransform.rect;
				float width = rect.width;
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(localPoint.x * rect.width, localPoint.y * rect.height);
				clickLocation = ClickLocation.Middle;
				if (vector.x < handleWidth)
				{
					clickLocation = ClickLocation.LeftHandle;
				}
				if (vector.x > width - handleWidth)
				{
					clickLocation = ClickLocation.RightHandle;
				}
			}
			lastClickLocation = clickLocation;
		}

		public void OnDrag(PointerEventData eventData)
		{
			Transform parent = rectTransform.parent;
			int siblingIndex = rectTransform.GetSiblingIndex();
			if (lastClickLocation == ClickLocation.LeftHandle && siblingIndex != 0)
			{
				AdjustWidth(parent.GetChild(siblingIndex - 1)?.GetComponent<LayoutElement>(), layoutElement, eventData.delta.x);
			}
			if (lastClickLocation == ClickLocation.RightHandle && siblingIndex != parent.childCount - 1)
			{
				AdjustWidth(layoutElement, parent.GetChild(siblingIndex + 1)?.GetComponent<LayoutElement>(), eventData.delta.x);
			}
			void AdjustWidth(LayoutElement lhs, LayoutElement rhs, float change)
			{
				if ((bool)lhs && (bool)rhs)
				{
					if (lhs.preferredWidth + change < lhs.minWidth)
					{
						change = lhs.minWidth - lhs.preferredWidth;
					}
					if (rhs.preferredWidth - change < rhs.minWidth)
					{
						change = rhs.preferredWidth - rhs.minWidth;
					}
					if (change != 0f)
					{
						lhs.preferredWidth += change;
						rhs.preferredWidth -= change;
						if ((bool)rectTransformToLayoutInvalidate)
						{
							LayoutRebuilder.MarkLayoutForRebuild(rectTransformToLayoutInvalidate);
						}
					}
				}
			}
		}
	}
	[RequireComponent(typeof(Canvas))]
	[RequireComponent(typeof(RectTransform))]
	public class CombatHealthBarViewer : MonoBehaviour, ILayoutGroup, ILayoutController
	{
		[Serializable]
		public class HealthBarInfo
		{
			public HealthComponent sourceHealthComponent;

			public Transform sourceTransform;

			public GameObject healthBarRootObject;

			public Transform healthBarRootObjectTransform;

			public HealthBar healthBar;

			public BuffDisplay buffdisplay;

			public float verticalOffset;

			public float endTime = float.NegativeInfinity;

			public int poolIndex;

			public bool frameDelay;

			private static UnityEngine.Vector3 hiddenPosition = new UnityEngine.Vector3(-9999f, -9999f, -9999f);

			private bool active = true;

			public bool SetInactive()
			{
				if (active)
				{
					healthBarRootObjectTransform.position = hiddenPosition;
					healthBar.enabled = false;
					active = false;
					return true;
				}
				return false;
			}

			public void SetActive()
			{
				if (!active)
				{
					frameDelay = true;
					healthBar.enabled = true;
					healthBar.gameObject.SetActive(value: true);
					buffdisplay.UpdateLayout();
					active = true;
				}
			}
		}

		private static readonly List<CombatHealthBarViewer> instancesList;

		public RectTransform container;

		public GameObject healthBarPrefab;

		public float healthBarDuration;

		private const float hoverHealthBarDuration = 1f;

		private RectTransform rectTransform;

		private Canvas canvas;

		private UICamera uiCamera;

		private List<HealthComponent> trackedVictims = new List<HealthComponent>();

		private Dictionary<HealthComponent, HealthBarInfo> victimToHealthBarInfo = new Dictionary<HealthComponent, HealthBarInfo>();

		public float zPosition;

		private const float overheadOffset = 1f;

		public static bool doingUIRebuild;

		public HealthComponent crosshairTarget { get; set; }

		public GameObject viewerBodyObject { get; set; }

		public CharacterBody viewerBody { get; set; }

		public TeamIndex viewerTeamIndex { get; set; }

		private HealthBarInfo GetHealthBarInfo()
		{
			HealthBarInfo obj = new HealthBarInfo
			{
				healthBarRootObject = UnityEngine.Object.Instantiate(healthBarPrefab, container)
			};
			obj.healthBarRootObjectTransform = obj.healthBarRootObject.transform;
			obj.healthBar = obj.healthBarRootObject.GetComponent<HealthBar>();
			return obj;
		}

		private void InitializeHealthBarInfos()
		{
		}

		static CombatHealthBarViewer()
		{
			instancesList = new List<CombatHealthBarViewer>();
			doingUIRebuild = false;
			GlobalEventManager.onClientDamageNotified += delegate(DamageDealtMessage msg)
			{
				if ((bool)msg.victim && !msg.isSilent)
				{
					HealthComponent component = msg.victim.GetComponent<HealthComponent>();
					if ((bool)component && !component.dontShowHealthbar)
					{
						TeamIndex objectTeam = TeamComponent.GetObjectTeam(component.gameObject);
						foreach (CombatHealthBarViewer instances in instancesList)
						{
							if (msg.attacker == instances.viewerBodyObject && (bool)instances.viewerBodyObject)
							{
								instances.HandleDamage(component, objectTeam);
							}
						}
					}
				}
			};
		}

		private void Update()
		{
			SetDirty();
		}

		private void Awake()
		{
			rectTransform = (RectTransform)base.transform;
			canvas = GetComponent<Canvas>();
			InitializeHealthBarInfos();
		}

		private void Start()
		{
			FindCamera();
		}

		private void FindCamera()
		{
			uiCamera = canvas.rootCanvas.worldCamera.GetComponent<UICamera>();
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
			for (int num = trackedVictims.Count - 1; num >= 0; num--)
			{
				Remove(num);
			}
		}

		private void Remove(int trackedVictimIndex)
		{
			Remove(trackedVictimIndex, victimToHealthBarInfo[trackedVictims[trackedVictimIndex]]);
		}

		private void Remove(int trackedVictimIndex, HealthBarInfo healthBarInfo)
		{
			trackedVictims.RemoveAt(trackedVictimIndex);
			UnityEngine.Object.Destroy(healthBarInfo.healthBarRootObject);
			victimToHealthBarInfo.Remove(healthBarInfo.sourceHealthComponent);
		}

		private bool VictimIsValid(HealthComponent victim)
		{
			if ((bool)victim && victim.alive)
			{
				if (!(victimToHealthBarInfo[victim].endTime > Time.time))
				{
					return victim == crosshairTarget;
				}
				return true;
			}
			return false;
		}

		private void LateUpdate()
		{
			CleanUp();
		}

		private void CleanUp()
		{
			for (int num = trackedVictims.Count - 1; num >= 0; num--)
			{
				HealthComponent healthComponent = trackedVictims[num];
				if (!VictimIsValid(healthComponent))
				{
					Remove(num, victimToHealthBarInfo[healthComponent]);
				}
			}
		}

		private void UpdateAllHealthbarPositions(Camera sceneCam, Camera uiCam)
		{
			if (!sceneCam || !uiCam)
			{
				return;
			}
			foreach (HealthBarInfo value in victimToHealthBarInfo.Values)
			{
				if ((bool)value.sourceTransform && (bool)value.healthBarRootObjectTransform)
				{
					UnityEngine.Vector3 position = value.sourceTransform.position;
					position.y += value.verticalOffset;
					UnityEngine.Vector3 vector = sceneCam.WorldToScreenPoint(position);
					vector.z = ((vector.z > 0f) ? 1f : (-1f));
					vector = ((vector.z > 0f) ? vector : new UnityEngine.Vector3(-9999f, -9999f, -1f));
					UnityEngine.Vector3 position2 = uiCam.ScreenToWorldPoint(vector);
					value.healthBarRootObjectTransform.position = position2;
				}
			}
		}

		private void HandleDamage(HealthComponent victimHealthComponent, TeamIndex victimTeam)
		{
			if (viewerTeamIndex == victimTeam || victimTeam == TeamIndex.None)
			{
				return;
			}
			CharacterBody body = victimHealthComponent.body;
			if (!body || body.GetVisibilityLevel(viewerBody) >= VisibilityLevel.Revealed)
			{
				HealthBarInfo healthBarInfo = GetHealthBarInfo(victimHealthComponent);
				if (healthBarInfo != null)
				{
					healthBarInfo.endTime = Time.time + healthBarDuration;
				}
			}
		}

		private HealthBarInfo GetHealthBarInfo(HealthComponent victimHealthComponent)
		{
			if (!victimToHealthBarInfo.TryGetValue(victimHealthComponent, out var value))
			{
				value = GetHealthBarInfo();
				if (value == null)
				{
					return null;
				}
				value.healthBarRootObject.GetComponentInChildren<BuffDisplay>().SetSource(victimHealthComponent.body);
				value.healthBar.source = victimHealthComponent;
				value.healthBar.viewerBody = viewerBody;
				value.sourceHealthComponent = victimHealthComponent;
				value.verticalOffset = 0f;
				Collider component = victimHealthComponent.GetComponent<Collider>();
				if ((bool)component)
				{
					value.verticalOffset = component.bounds.extents.y;
				}
				value.sourceTransform = victimHealthComponent.body.coreTransform ?? victimHealthComponent.transform;
				ModelLocator component2 = victimHealthComponent.GetComponent<ModelLocator>();
				if ((bool)component2)
				{
					Transform modelTransform = component2.modelTransform;
					if ((bool)modelTransform)
					{
						ChildLocator component3 = modelTransform.GetComponent<ChildLocator>();
						if ((bool)component3)
						{
							Transform transform = component3.FindChild("HealthBarOrigin");
							if ((bool)transform)
							{
								value.sourceTransform = transform;
								value.verticalOffset = 0f;
							}
						}
					}
				}
				value.healthBar.InitializeHealthBar();
				victimToHealthBarInfo.Add(victimHealthComponent, value);
				trackedVictims.Add(victimHealthComponent);
			}
			return value;
		}

		private void SetDirty()
		{
			if (base.isActiveAndEnabled && !CanvasUpdateRegistry.IsRebuildingLayout())
			{
				LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
			}
		}

		private static void LayoutForCamera(UICamera uiCamera)
		{
			Camera camera = uiCamera.camera;
			Camera sceneCam = uiCamera.cameraRigController.sceneCam;
			for (int i = 0; i < instancesList.Count; i++)
			{
				instancesList[i].UpdateAllHealthbarPositions(sceneCam, camera);
			}
		}

		public void SetLayoutHorizontal()
		{
			if ((bool)uiCamera)
			{
				doingUIRebuild = true;
				LayoutForCamera(uiCamera);
				doingUIRebuild = false;
			}
		}

		public void SetLayoutVertical()
		{
		}
	}
	[RequireComponent(typeof(MPEventSystemProvider))]
	public class ConsoleWindow : MonoBehaviour
	{
		private enum InputFieldState
		{
			Neutral,
			History,
			AutoComplete
		}

		public TMP_InputField inputField;

		public TMP_InputField outputField;

		private TMP_Dropdown autoCompleteDropdown;

		private Console.AutoComplete autoComplete;

		private bool preventAutoCompleteUpdate;

		private bool preventHistoryReset;

		private int historyIndex = -1;

		private readonly StringBuilder stringBuilder = new StringBuilder();

		private const string consoleEnabledDefaultValue = "0";

		private static BoolConVar cvConsoleEnabled = new BoolConVar("console_enabled", ConVarFlags.None, "0", "Enables/Disables the console.");

		public static ConsoleWindow instance { get; private set; }

		private bool autoCompleteInUse
		{
			get
			{
				if ((bool)autoCompleteDropdown)
				{
					return autoCompleteDropdown.IsExpanded;
				}
				return false;
			}
		}

		public void Start()
		{
			GetComponent<MPEventSystemProvider>().eventSystem = MPEventSystemManager.kbmEventSystem;
			if ((bool)outputField.verticalScrollbar)
			{
				outputField.verticalScrollbar.value = 1f;
			}
			outputField.textComponent.gameObject.AddComponent<RectTransformDimensionsChangeEvent>().onRectTransformDimensionsChange += OnOutputFieldRectTransformDimensionsChange;
		}

		private void OnOutputFieldRectTransformDimensionsChange()
		{
			if ((bool)outputField.verticalScrollbar)
			{
				outputField.verticalScrollbar.value = 0f;
				outputField.verticalScrollbar.value = 1f;
			}
		}

		public void OnEnable()
		{
			Console.onLogReceived += OnLogReceived;
			Console.onClear += OnClear;
			RebuildOutput();
			inputField.onSubmit.AddListener(Submit);
			inputField.onValueChanged.AddListener(OnInputFieldValueChanged);
			instance = this;
		}

		public void SubmitInputField()
		{
			inputField.onSubmit.Invoke(inputField.text);
		}

		public void Submit(string text)
		{
			if (!(inputField.text == ""))
			{
				if ((bool)autoCompleteDropdown)
				{
					autoCompleteDropdown.Hide();
				}
				inputField.text = "";
				Console.instance.SubmitCmd(LocalUserManager.GetFirstLocalUser(), text, recordSubmit: true);
				if ((bool)inputField && inputField.IsActive())
				{
					inputField.ActivateInputField();
				}
			}
		}

		private void OnInputFieldValueChanged(string text)
		{
			if (!preventHistoryReset)
			{
				historyIndex = -1;
			}
			if (preventAutoCompleteUpdate)
			{
				return;
			}
			if (text.Length > 0 != (autoComplete != null))
			{
				if (autoComplete != null)
				{
					UnityEngine.Object.Destroy(autoCompleteDropdown.gameObject);
					autoComplete = null;
				}
				else
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/ConsoleAutoCompleteDropdown"), inputField.transform);
					autoCompleteDropdown = gameObject.GetComponent<TMP_Dropdown>();
					autoComplete = new Console.AutoComplete(Console.instance);
					autoCompleteDropdown.onValueChanged.AddListener(ApplyAutoComplete);
				}
			}
			if (autoComplete != null && autoComplete.SetSearchString(text))
			{
				List<TMP_Dropdown.OptionData> list = new List<TMP_Dropdown.OptionData>();
				List<string> resultsList = autoComplete.resultsList;
				for (int i = 0; i < resultsList.Count; i++)
				{
					list.Add(new TMP_Dropdown.OptionData(resultsList[i]));
				}
				autoCompleteDropdown.options = list;
			}
		}

		public void Update()
		{
			EventSystem eventSystem = MPEventSystemManager.FindEventSystem(ReInput.players.GetPlayer(0));
			if (!eventSystem || !(eventSystem.currentSelectedGameObject == inputField.gameObject))
			{
				return;
			}
			InputFieldState inputFieldState = InputFieldState.Neutral;
			if ((bool)autoCompleteDropdown && autoCompleteInUse)
			{
				inputFieldState = InputFieldState.AutoComplete;
			}
			else if (historyIndex != -1)
			{
				inputFieldState = InputFieldState.History;
			}
			bool keyDown = Input.GetKeyDown(KeyCode.UpArrow);
			bool keyDown2 = Input.GetKeyDown(KeyCode.DownArrow);
			switch (inputFieldState)
			{
			case InputFieldState.Neutral:
				if (keyDown)
				{
					if (Console.userCmdHistory.Count > 0)
					{
						historyIndex = Console.userCmdHistory.Count - 1;
						preventHistoryReset = true;
						inputField.text = Console.userCmdHistory[historyIndex];
						inputField.MoveToEndOfLine(shift: false, ctrl: false);
						preventHistoryReset = false;
					}
				}
				else if (keyDown2 && (bool)autoCompleteDropdown)
				{
					autoCompleteDropdown.Show();
					autoCompleteDropdown.value = 0;
					autoCompleteDropdown.onValueChanged.Invoke(autoCompleteDropdown.value);
				}
				break;
			case InputFieldState.History:
			{
				int num = 0;
				if (keyDown)
				{
					num--;
				}
				if (keyDown2)
				{
					num++;
				}
				if (num != 0)
				{
					historyIndex += num;
					if (historyIndex < 0)
					{
						historyIndex = 0;
					}
					if (historyIndex >= Console.userCmdHistory.Count)
					{
						historyIndex = -1;
						break;
					}
					preventHistoryReset = true;
					inputField.text = Console.userCmdHistory[historyIndex];
					inputField.MoveToEndOfLine(shift: false, ctrl: false);
					preventHistoryReset = false;
				}
				break;
			}
			case InputFieldState.AutoComplete:
				if (keyDown2)
				{
					TMP_Dropdown tMP_Dropdown = autoCompleteDropdown;
					int value = tMP_Dropdown.value + 1;
					tMP_Dropdown.value = value;
				}
				if (keyDown)
				{
					if (autoCompleteDropdown.value > 0)
					{
						TMP_Dropdown tMP_Dropdown2 = autoCompleteDropdown;
						int value = tMP_Dropdown2.value - 1;
						tMP_Dropdown2.value = value;
					}
					else
					{
						autoCompleteDropdown.Hide();
					}
				}
				break;
			}
			eventSystem.SetSelectedGameObject(inputField.gameObject);
		}

		private void ApplyAutoComplete(int optionIndex)
		{
			if ((bool)autoCompleteDropdown && autoCompleteDropdown.options.Count > optionIndex)
			{
				preventAutoCompleteUpdate = true;
				inputField.text = autoCompleteDropdown.options[optionIndex].text;
				inputField.MoveToEndOfLine(shift: false, ctrl: false);
				preventAutoCompleteUpdate = false;
			}
		}

		public void OnDisable()
		{
			Console.onLogReceived -= OnLogReceived;
			Console.onClear -= OnClear;
			inputField.onSubmit.RemoveListener(Submit);
			inputField.onValueChanged.RemoveListener(OnInputFieldValueChanged);
			if (instance == this)
			{
				instance = null;
			}
		}

		private void OnLogReceived(Console.Log log)
		{
			RebuildOutput();
		}

		private void OnClear()
		{
			RebuildOutput();
		}

		private void RebuildOutput()
		{
			float value = 0f;
			if ((bool)outputField.verticalScrollbar)
			{
				value = outputField.verticalScrollbar.value;
			}
			string[] array = new string[Console.logs.Count];
			stringBuilder.Clear();
			for (int i = 0; i < array.Length; i++)
			{
				stringBuilder.AppendLine(Console.logs[i].message);
			}
			outputField.text = stringBuilder.ToString();
			if ((bool)outputField.verticalScrollbar)
			{
				outputField.verticalScrollbar.value = 0f;
				outputField.verticalScrollbar.value = 1f;
				outputField.verticalScrollbar.value = value;
			}
		}

		private static void CheckConsoleKey()
		{
			bool keyDown = Input.GetKeyDown(KeyCode.BackQuote);
			if (Input.GetKey(KeyCode.LeftControl) && Input.GetKey(KeyCode.LeftAlt) && keyDown)
			{
				cvConsoleEnabled.SetBool(!cvConsoleEnabled.value);
			}
			if (cvConsoleEnabled.value && keyDown)
			{
				if ((bool)instance)
				{
					UnityEngine.Object.Destroy(instance.gameObject);
				}
				else
				{
					UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/ConsoleWindow")).GetComponent<ConsoleWindow>().inputField.ActivateInputField();
				}
			}
			if (Input.GetKeyDown(KeyCode.Escape) && (bool)instance)
			{
				UnityEngine.Object.Destroy(instance.gameObject);
			}
		}

		[RuntimeInitializeOnLoadMethod]
		public static void Init()
		{
			RoR2Application.onUpdate += CheckConsoleKey;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class ContextManager : MonoBehaviour
	{
		public TextMeshProUGUI glyphTMP;

		public TextMeshProUGUI descriptionTMP;

		public TextMeshProUGUI inspectDescriptionTMP;

		public GameObject contextDisplay;

		public TextMeshProUGUI inspectGlyphTMP;

		public GameObject inspectDisplay;

		public HUD hud;

		private MPEventSystemLocator eventSystemLocator;

		private string glyphString;

		private GameObject cachedInteractionTarget;

		private bool lastContextEnabled = true;

		private string basicInspectString;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			basicInspectString = Language.GetString("ACTION_INSPECT");
			InputBindingDisplayController.onBindingsChanged = (Action)Delegate.Combine(InputBindingDisplayController.onBindingsChanged, new Action(UpdateGlyphString));
		}

		private void OnDestroy()
		{
			InputBindingDisplayController.onBindingsChanged = (Action)Delegate.Remove(InputBindingDisplayController.onBindingsChanged, new Action(UpdateGlyphString));
		}

		private void Start()
		{
			UpdateGlyphString();
			Update();
		}

		private void UpdateGlyphString()
		{
			glyphString = string.Format(CultureInfo.InvariantCulture, "<style=cKeyBinding>{0}</style>", Glyphs.GetGlyphString(eventSystemLocator, "Interact"));
			glyphTMP.text = glyphString;
		}

		private void Update()
		{
			string text = "";
			string text2 = "";
			string text3 = "";
			string text4 = "";
			bool flag = false;
			bool active = false;
			if ((bool)hud && (bool)hud.targetBodyObject)
			{
				InteractionDriver component = hud.targetBodyObject.GetComponent<InteractionDriver>();
				if ((bool)component)
				{
					GameObject currentInteractable = component.currentInteractable;
					if ((bool)currentInteractable)
					{
						PlayerCharacterMasterController component2 = hud.targetMaster.GetComponent<PlayerCharacterMasterController>();
						if ((bool)component2 && (bool)component2.networkUser && component2.networkUser.localUser != null)
						{
							IInteractable component3 = currentInteractable.GetComponent<IInteractable>();
							if (component3 != null && ((MonoBehaviour)component3).isActiveAndEnabled)
							{
								string text5 = ((component3.GetInteractability(component.interactor) == Interactability.Available) ? component3.GetContextString(component.interactor) : null);
								if (text5 != null)
								{
									text3 = text5;
									text = string.Format(CultureInfo.InvariantCulture, "<style=cKeyBinding>{0}</style>", Glyphs.GetGlyphString(eventSystemLocator, "Interact"));
									flag = true;
								}
								if (hud.localUserViewer.userProfile.useInspectFeature)
								{
									IInspectable component4 = currentInteractable.GetComponent<IInspectable>();
									if (component4 != null)
									{
										IInspectInfoProvider inspectInfoProvider = component4.GetInspectInfoProvider();
										if (inspectInfoProvider != null)
										{
											text4 = basicInspectString;
											text2 = string.Format(CultureInfo.InvariantCulture, "<style=cKeyBinding>{0}</style>", Glyphs.GetGlyphString(eventSystemLocator, "info"));
											active = true;
											if (inspectInfoProvider is IHasInspectHintOverride hasInspectHintOverride && hasInspectHintOverride.GetInspectHintOverride(out var hintOverride))
											{
												text4 = hintOverride;
											}
										}
									}
								}
							}
						}
					}
				}
			}
			if (flag || (!flag && lastContextEnabled))
			{
				glyphTMP.text = text;
				descriptionTMP.text = text3;
				contextDisplay.SetActive(flag);
			}
			inspectGlyphTMP.text = text2;
			inspectDescriptionTMP.text = text4;
			inspectDisplay.SetActive(active);
		}
	}
	[RequireComponent(typeof(RectTransform))]
	[ExecuteAlways]
	public class CreditsPanelController : MonoBehaviour
	{
		public abstract class BaseCreditsPanelState : BaseState
		{
			protected CreditsPanelController creditsPanelController { get; private set; }

			protected abstract bool enableSkipButton { get; }

			public override void OnEnter()
			{
				base.OnEnter();
				creditsPanelController = GetComponent<CreditsPanelController>();
				if ((bool)creditsPanelController && (bool)creditsPanelController.skipButton)
				{
					creditsPanelController.skipButton.gameObject.SetActive(enableSkipButton);
				}
			}

			protected void SetScroll(float scroll)
			{
				if ((bool)creditsPanelController)
				{
					creditsPanelController.SetScroll(scroll);
				}
			}

			protected void SetFade(float fade)
			{
				fade = Mathf.Clamp01(fade);
				if ((bool)creditsPanelController && (bool)creditsPanelController.fadePanel)
				{
					UnityEngine.Color color = creditsPanelController.fadePanel.color;
					color.a = fade;
					creditsPanelController.fadePanel.color = color;
				}
			}
		}

		public class IntroState : BaseCreditsPanelState
		{
			protected override bool enableSkipButton => false;

			public override void OnEnter()
			{
				base.OnEnter();
				SetScroll(0f);
				SetFade(base.creditsPanelController.introFadeCurve.Evaluate(0f));
				base.creditsPanelController.StartCoroutine(PrepareContent());
			}

			public override void Update()
			{
				base.Update();
				float num = Mathf.Clamp01(base.age / base.creditsPanelController.introDuration);
				SetFade(1f - num);
				if (num >= 1f)
				{
					outer.SetNextState(new MainScrollState());
				}
			}

			private IEnumerator PrepareContent()
			{
				SetIgnoreLayout(value: false);
				yield return null;
				VerticalLayoutGroup component = base.creditsPanelController.content.GetComponent<VerticalLayoutGroup>();
				if (component != null)
				{
					component.enabled = false;
				}
				ContentSizeFitter component2 = base.creditsPanelController.content.GetComponent<ContentSizeFitter>();
				if (component2 != null)
				{
					component2.enabled = false;
				}
				yield return null;
				SetIgnoreLayout(value: true);
			}

			private void SetIgnoreLayout(bool value)
			{
				for (int i = 0; i < base.creditsPanelController.content.childCount; i++)
				{
					LayoutElement component = base.creditsPanelController.content.GetChild(i).GetComponent<LayoutElement>();
					if (component != null)
					{
						component.ignoreLayout = value;
					}
				}
			}
		}

		public class MainScrollState : BaseCreditsPanelState
		{
			public static AnimationCurve scrollCurve;

			protected override bool enableSkipButton => true;

			public override void OnEnter()
			{
				base.OnEnter();
				SetFade(0f);
				base.creditsPanelController.skipButton.gameObject.SetActive(value: true);
			}

			public override void Update()
			{
				base.Update();
				float num = Mathf.Clamp01(base.age / base.creditsPanelController.scrollDuration);
				SetScroll(scrollCurve.Evaluate(num));
				base.creditsPanelController.DisableInvisibleElements();
				if (num >= 1f)
				{
					outer.SetNextState(new OutroState());
				}
			}
		}

		public class OutroState : BaseCreditsPanelState
		{
			protected override bool enableSkipButton => true;

			public override void OnEnter()
			{
				base.OnEnter();
				SetScroll(1f);
				SetFade(base.creditsPanelController.outroFadeCurve.Evaluate(0f));
			}

			public override void Update()
			{
				base.Update();
				float num = Mathf.Clamp01(base.age / base.creditsPanelController.outroDuration);
				SetFade(num);
				if (num >= 1f)
				{
					EntityState.Destroy(base.gameObject);
				}
			}
		}

		public RectTransform content;

		public ScrollRect scrollRect;

		public float introDuration;

		public AnimationCurve introFadeCurve;

		public float outroDuration;

		public AnimationCurve outroFadeCurve;

		public float scrollDuration;

		public RawImage fadePanel;

		public MPButton skipButton;

		public VoteInfoPanelController voteInfoPanel;

		[Range(0f, 1f)]
		public float editorScroll;

		private Dictionary<Canvas, List<CanvasRenderer>> canvases = new Dictionary<Canvas, List<CanvasRenderer>>();

		private const float SCREEN_HEIGHT = 1080f;

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			GameObject[] array = GameObject.FindGameObjectsWithTag("CreditsGroup");
			for (int i = 0; i < array.Length; i++)
			{
				Canvas component = array[i].GetComponent<Canvas>();
				if (component != null)
				{
					canvases.Add(component, new List<CanvasRenderer>(component.GetComponentsInChildren<CanvasRenderer>()));
				}
			}
		}

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
		}

		private void SetScroll(float scroll)
		{
			if ((bool)scrollRect)
			{
				scrollRect.verticalNormalizedPosition = 1f - scroll;
			}
		}

		private void Update()
		{
			if (!Application.IsPlaying(this))
			{
				SetScroll(editorScroll);
			}
		}

		public void DisableInvisibleElements()
		{
			float height = scrollRect.viewport.rect.height;
			float num = 100f;
			for (int i = 1; i < scrollRect.content.childCount; i++)
			{
				RectTransform component = scrollRect.content.GetChild(i).GetComponent<RectTransform>();
				float num2 = component.sizeDelta.y * 0.5f + num;
				float num3 = Mathf.Abs(component.localPosition.y) - num2;
				float num4 = Mathf.Abs(component.localPosition.y) + num2;
				float y = ((RectTransform)content.transform).anchoredPosition.y;
				bool active = num4 > y && num3 < y + height;
				component.gameObject.SetActive(active);
			}
		}

		[ContextMenu("Generate Credits Roles JSON")]
		private void GenerateCreditsRoles()
		{
			CreditsStripGroupBuilder[] componentsInChildren = GetComponentsInChildren<CreditsStripGroupBuilder>();
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			CreditsStripGroupBuilder[] array = componentsInChildren;
			for (int i = 0; i < array.Length; i++)
			{
				foreach (var namesAndEnglishRole in array[i].GetNamesAndEnglishRoles())
				{
					string text = CreditsStripGroupBuilder.EnglishRoleToToken(namesAndEnglishRole.englishRoleName);
					if (dictionary.TryGetValue(text, out var value))
					{
						if (!string.Equals(namesAndEnglishRole.englishRoleName, value, StringComparison.Ordinal))
						{
							UnityEngine.Debug.LogError("Conflict in role \"" + text + "\": a=\"" + value + "\" b=\"" + namesAndEnglishRole.englishRoleName + "\"");
						}
					}
					else
					{
						dictionary.Add(text, namesAndEnglishRole.englishRoleName);
					}
				}
			}
			List<KeyValuePair<string, string>> list = dictionary.OrderBy((KeyValuePair<string, string> kv) => kv.Key).ToList();
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, string> item in list)
			{
				stringBuilder.Append("\"").Append(item.Key).Append("\": \"")
					.Append(item.Value)
					.Append("\",")
					.AppendLine();
			}
			GUIUtility.systemCopyBuffer = stringBuilder.ToString();
		}

		[ConCommand(commandName = "credits_start", flags = ConVarFlags.None, helpText = "Begins the credits sequence.")]
		private static void CCCreditsStart(ConCommandArgs args)
		{
			if (InstanceTracker.GetInstancesList<CreditsPanelController>().Count != 0)
			{
				throw new ConCommandException("Already in credits sequence.");
			}
			CreditsPanelController creditsPanelController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Credits/CreditsPanel"), RoR2Application.instance.mainCanvas.transform).GetComponent<CreditsPanelController>();
			creditsPanelController.skipButton.onClick.AddListener(delegate
			{
				UnityEngine.Object.Destroy(creditsPanelController.gameObject);
			});
		}
	}
	public class CreditsStripGroupBuilder : MonoBehaviour
	{
		[Multiline]
		public string source;

		public GameObject stripPrefab;

		public static string EnglishRoleToToken(string englishRoleString)
		{
			StringBuilder stringBuilder = new StringBuilder(englishRoleString);
			stringBuilder.Replace("&", "AND");
			stringBuilder.Replace(",", "");
			stringBuilder.Replace("(", "");
			stringBuilder.Replace(")", "");
			for (int num = stringBuilder.Length - 1; num >= 0; num--)
			{
				if (char.IsWhiteSpace(stringBuilder[num]))
				{
					stringBuilder[num] = '_';
				}
			}
			for (int num2 = stringBuilder.Length - 1; num2 >= 0; num2--)
			{
				char c = stringBuilder[num2];
				if (!char.IsLetterOrDigit(c) && c != '_' && c != '/')
				{
					stringBuilder.Remove(num2, 1);
				}
			}
			stringBuilder.Insert(0, "CREDITS_ROLE_");
			return stringBuilder.ToString().ToUpper(CultureInfo.InvariantCulture);
		}

		public List<(string name, string englishRoleName)> GetNamesAndEnglishRoles()
		{
			string text = source.Replace("\r", "").Replace("\n", "\t");
			List<(string, string)> list = new List<(string, string)>();
			string[] array = text.Split('\t');
			for (int i = 0; i < array.Length; i += 2)
			{
				list.Add((array[i], array[i + 1]));
			}
			return list;
		}

		[ContextMenu("Build")]
		private void Build()
		{
			List<(string, string)> namesAndEnglishRoles = GetNamesAndEnglishRoles();
			List<Transform> list = new List<Transform>(base.transform.childCount);
			int i = 0;
			for (int childCount = base.transform.childCount; i < childCount; i++)
			{
				list.Add(base.transform.GetChild(i));
			}
			for (int num = list.Count - 1; num >= 0; num--)
			{
				Transform transform = list[num];
				if (EditorUtil.PrefabUtilityGetNearestPrefabInstanceRoot(transform.gameObject) != stripPrefab)
				{
					UnityEngine.Object.DestroyImmediate(transform.gameObject);
					list.RemoveAt(num);
				}
			}
			while (list.Count < namesAndEnglishRoles.Count)
			{
				GameObject gameObject = (GameObject)EditorUtil.PrefabUtilityInstantiatePrefab(stripPrefab, base.transform);
				list.Add(gameObject.transform);
			}
			while (list.Count > namesAndEnglishRoles.Count)
			{
				int index = list.Count - 1;
				UnityEngine.Object.DestroyImmediate(list[index].gameObject);
				list.RemoveAt(index);
			}
			int j = 0;
			for (int num2 = Math.Min(namesAndEnglishRoles.Count, list.Count); j < num2; j++)
			{
				(string, string) tuple = namesAndEnglishRoles[j];
				SetStripValues(list[j].gameObject, tuple.Item1, tuple.Item2);
			}
			static void SetStripValues(GameObject stripInstance, string name, string rawRoleText)
			{
				stripInstance.transform.Find("CreditNameLabel").GetComponent<HGTextMeshProUGUI>().SetText(name);
				stripInstance.transform.Find("CreditRoleLabel").GetComponent<LanguageTextMeshController>().token = EnglishRoleToToken(rawRoleText);
				stripInstance.transform.Find("CreditRoleLabel").GetComponent<HGTextMeshProUGUI>().SetText(rawRoleText);
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	[RequireComponent(typeof(HudElement))]
	public class CrosshairController : MonoBehaviour
	{
		[Serializable]
		public struct SpritePosition
		{
			public RectTransform target;

			public UnityEngine.Vector3 zeroPosition;

			public UnityEngine.Vector3 onePosition;
		}

		[Serializable]
		public struct SkillStockSpriteDisplay
		{
			public GameObject target;

			public SkillSlot skillSlot;

			public SkillDef requiredSkillDef;

			public int minimumStockCountToBeValid;

			public int maximumStockCountToBeValid;
		}

		public SpritePosition[] spriteSpreadPositions;

		public SkillStockSpriteDisplay[] skillStockSpriteDisplays;

		public RawImage[] remapSprites;

		public float minSpreadAlpha;

		public float maxSpreadAlpha;

		[Tooltip("The angle the crosshair represents when alpha = 1")]
		public float maxSpreadAngle;

		private MaterialPropertyBlock _propBlock;

		public RectTransform rectTransform { get; private set; }

		public HudElement hudElement { get; private set; }

		private void Awake()
		{
			rectTransform = GetComponent<RectTransform>();
			hudElement = GetComponent<HudElement>();
			SetCrosshairSpread();
			SetSkillStockDisplays();
		}

		private void SetCrosshairSpread()
		{
			float num = 0f;
			if ((bool)hudElement.targetCharacterBody)
			{
				num = hudElement.targetCharacterBody.spreadBloomAngle;
			}
			for (int i = 0; i < spriteSpreadPositions.Length; i++)
			{
				SpritePosition spritePosition = spriteSpreadPositions[i];
				spritePosition.target.localPosition = UnityEngine.Vector3.Lerp(spritePosition.zeroPosition, spritePosition.onePosition, num / maxSpreadAngle);
			}
			for (int j = 0; j < remapSprites.Length; j++)
			{
				remapSprites[j].color = new UnityEngine.Color(1f, 1f, 1f, Util.Remap(num / maxSpreadAngle, 0f, 1f, minSpreadAlpha, maxSpreadAlpha));
			}
		}

		private void SetSkillStockDisplays()
		{
			if (!hudElement.targetCharacterBody)
			{
				return;
			}
			SkillLocator component = hudElement.targetCharacterBody.GetComponent<SkillLocator>();
			for (int i = 0; i < skillStockSpriteDisplays.Length; i++)
			{
				bool active = false;
				SkillStockSpriteDisplay skillStockSpriteDisplay = skillStockSpriteDisplays[i];
				GenericSkill skill = component.GetSkill(skillStockSpriteDisplay.skillSlot);
				if ((bool)skill && skill.stock >= skillStockSpriteDisplay.minimumStockCountToBeValid && (skill.stock <= skillStockSpriteDisplay.maximumStockCountToBeValid || skillStockSpriteDisplay.maximumStockCountToBeValid < 0) && (skillStockSpriteDisplay.requiredSkillDef == null || skill.skillDef == skillStockSpriteDisplay.requiredSkillDef))
				{
					active = true;
				}
				skillStockSpriteDisplay.target.SetActive(active);
			}
		}

		private void LateUpdate()
		{
			SetCrosshairSpread();
			SetSkillStockDisplays();
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class CrosshairManager : MonoBehaviour
	{
		public delegate void ShouldShowCrosshairDelegate(CrosshairManager crosshairManager, ref bool shouldShow);

		public delegate void PickCrosshairDelegate(CrosshairManager crosshairManager, ref GameObject crosshairPrefab);

		[Tooltip("The transform which should act as the container for the crosshair.")]
		public RectTransform container;

		public CameraRigController cameraRigController;

		[Tooltip("The hitmarker image.")]
		public UnityEngine.UI.Image hitmarker;

		private float hitmarkerAlpha;

		private float hitmarkerTimer;

		private const float hitmarkerDuration = 0.2f;

		private bool isCurrentFrameUpdated;

		private GameObject currentCrosshairPrefab;

		public CrosshairController crosshairController;

		private HudElement crosshairHudElement;

		private RtpcSetter rtpcDamageDirection;

		private static readonly List<CrosshairManager> instancesList;

		public event ShouldShowCrosshairDelegate shouldShowCrosshairGlobal;

		public event PickCrosshairDelegate pickCrosshairGlobal;

		private void OnEnable()
		{
			instancesList.Add(this);
			rtpcDamageDirection = new RtpcSetter("damageDirection", RoR2Application.instance.gameObject);
		}

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private static void StaticLateUpdate()
		{
			for (int i = 0; i < instancesList.Count; i++)
			{
				instancesList[i].DoLateUpdate();
			}
		}

		private void DoLateUpdate()
		{
			isCurrentFrameUpdated = false;
			if ((bool)cameraRigController)
			{
				UpdateCrosshair(cameraRigController.target ? cameraRigController.target.GetComponent<CharacterBody>() : null, cameraRigController.crosshairWorldPosition, cameraRigController.uiCam);
			}
			UpdateHitMarker();
		}

		private void UpdateCrosshair(CharacterBody targetBody, UnityEngine.Vector3 crosshairWorldPosition, Camera uiCamera)
		{
			GameObject crosshairPrefab = null;
			bool shouldShow = (bool)targetBody && !targetBody.currentVehicle;
			this.shouldShowCrosshairGlobal?.Invoke(this, ref shouldShow);
			if (shouldShow && (bool)targetBody)
			{
				if (!cameraRigController.hasOverride)
				{
					if ((bool)targetBody && targetBody.healthComponent.alive)
					{
						crosshairPrefab = (targetBody.isSprinting ? LegacyResourcesAPI.Load<GameObject>("Prefabs/Crosshair/SprintingCrosshair") : (targetBody.hideCrosshair ? null : CrosshairUtils.GetCrosshairPrefabForBody(targetBody)));
					}
				}
				else
				{
					crosshairPrefab = CrosshairUtils.GetCrosshairPrefabForBody(targetBody);
				}
				this.pickCrosshairGlobal?.Invoke(this, ref crosshairPrefab);
			}
			if (crosshairPrefab != currentCrosshairPrefab)
			{
				if ((bool)crosshairController)
				{
					UnityEngine.Object.Destroy(crosshairController.gameObject);
					crosshairController = null;
				}
				if ((bool)crosshairPrefab)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(crosshairPrefab, container);
					crosshairController = gameObject.GetComponent<CrosshairController>();
					crosshairHudElement = gameObject.GetComponent<HudElement>();
				}
				currentCrosshairPrefab = crosshairPrefab;
			}
			if ((bool)crosshairController)
			{
				((RectTransform)crosshairController.gameObject.transform).anchoredPosition = new UnityEngine.Vector2(0.5f, 0.5f);
			}
			if ((bool)crosshairHudElement)
			{
				crosshairHudElement.targetCharacterBody = targetBody;
			}
		}

		public void RefreshHitmarker(bool crit)
		{
			hitmarkerTimer = 0.2f;
			hitmarker.gameObject.SetActive(value: false);
			hitmarker.gameObject.SetActive(value: true);
			Util.PlaySound("Play_UI_hit", RoR2Application.instance.gameObject);
			if (crit)
			{
				Util.PlaySound("Play_UI_crit", RoR2Application.instance.gameObject);
			}
			isCurrentFrameUpdated = true;
		}

		private void UpdateHitMarker()
		{
			hitmarkerAlpha = Mathf.Pow(hitmarkerTimer / 0.2f, 0.75f);
			hitmarkerTimer = Mathf.Max(0f, hitmarkerTimer - Time.deltaTime);
			if ((bool)hitmarker)
			{
				UnityEngine.Color color = hitmarker.color;
				color.a = hitmarkerAlpha;
				hitmarker.color = color;
			}
		}

		private static void HandleHitMarker(DamageDealtMessage damageDealtMessage)
		{
			for (int i = 0; i < instancesList.Count; i++)
			{
				CrosshairManager crosshairManager = instancesList[i];
				if (!crosshairManager.cameraRigController)
				{
					continue;
				}
				GameObject target = crosshairManager.cameraRigController.target;
				if (damageDealtMessage.attacker == target && !crosshairManager.isCurrentFrameUpdated)
				{
					crosshairManager.RefreshHitmarker(damageDealtMessage.crit);
				}
				else if (damageDealtMessage.victim == target)
				{
					Transform obj = crosshairManager.cameraRigController.transform;
					UnityEngine.Vector3 position = obj.position;
					UnityEngine.Vector3 forward = obj.forward;
					_ = obj.position;
					UnityEngine.Vector3 vector = damageDealtMessage.position - position;
					float num = UnityEngine.Vector2.SignedAngle(new UnityEngine.Vector2(vector.x, vector.z), new UnityEngine.Vector2(forward.x, forward.z));
					if (num < 0f)
					{
						num += 360f;
					}
					crosshairManager.rtpcDamageDirection.value = num;
					Util.PlaySound("Play_UI_takeDamage", RoR2Application.instance.gameObject);
				}
			}
		}

		static CrosshairManager()
		{
			instancesList = new List<CrosshairManager>();
			GlobalEventManager.onClientDamageNotified += HandleHitMarker;
			RoR2Application.onLateUpdate += StaticLateUpdate;
		}
	}
	public static class CrosshairUtils
	{
		public enum OverridePriority
		{
			Sprint,
			Skill,
			PrioritySkill
		}

		public class OverrideRequest : IDisposable, IComparable<OverrideRequest>
		{
			public readonly GameObject prefab;

			public readonly OverridePriority priority;

			private Action<OverrideRequest> disposeCallback;

			public OverrideRequest(GameObject crosshairPrefab, OverridePriority overridePriority, Action<OverrideRequest> onDispose)
			{
				disposeCallback = onDispose;
				prefab = crosshairPrefab;
				priority = overridePriority;
			}

			public int CompareTo(OverrideRequest other)
			{
				return priority.CompareTo(other.priority);
			}

			public void Dispose()
			{
				disposeCallback?.Invoke(this);
				disposeCallback = null;
			}
		}

		private class CrosshairOverrideBehavior : MonoBehaviour
		{
			private List<OverrideRequest> requestList = new List<OverrideRequest>();

			public GameObject GetOverridePrefab()
			{
				if (requestList.Count > 0)
				{
					return requestList[requestList.Count - 1].prefab;
				}
				return null;
			}

			public OverrideRequest AddRequest(GameObject crosshairPrefab, OverridePriority overridePriority)
			{
				OverrideRequest overrideRequest = new OverrideRequest(crosshairPrefab, overridePriority, RemoveRequest);
				requestList.Add(overrideRequest);
				if (requestList.Count > 1)
				{
					requestList.Sort();
				}
				return overrideRequest;
			}

			private void RemoveRequest(OverrideRequest request)
			{
				requestList.Remove(request);
			}

			public void OnDestroy()
			{
				foreach (OverrideRequest request in requestList)
				{
					request.Dispose();
				}
				requestList.Clear();
			}
		}

		public static OverrideRequest RequestOverrideForBody(CharacterBody body, GameObject crosshairPrefab, OverridePriority overridePriority)
		{
			CrosshairOverrideBehavior crosshairOverrideBehavior = body.GetComponent<CrosshairOverrideBehavior>();
			if (!crosshairOverrideBehavior)
			{
				crosshairOverrideBehavior = body.gameObject.AddComponent<CrosshairOverrideBehavior>();
			}
			return crosshairOverrideBehavior.AddRequest(crosshairPrefab, overridePriority);
		}

		public static GameObject GetCrosshairPrefabForBody(CharacterBody body)
		{
			CrosshairOverrideBehavior component = body.GetComponent<CrosshairOverrideBehavior>();
			if ((bool)component)
			{
				GameObject overridePrefab = component.GetOverridePrefab();
				if ((bool)overridePrefab)
				{
					return overridePrefab;
				}
			}
			return body.defaultCrosshairPrefab;
		}
	}
	[RequireComponent(typeof(UnityEngine.UI.Image))]
	internal class CurrentDifficultyIconController : MonoBehaviour
	{
		private void Start()
		{
			if ((bool)Run.instance)
			{
				DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(Run.instance.selectedDifficulty);
				GetComponent<UnityEngine.UI.Image>().sprite = difficultyDef.GetIconSprite();
			}
		}
	}
	public class CurrentRunArtifactDisplayDataDriver : MonoBehaviour
	{
		public ArtifactDisplayPanelController artifactDisplayPanelController;

		private bool dirty;

		private void OnEnable()
		{
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactEnabledGlobal;
			RunArtifactManager.onArtifactEnabledGlobal += OnArtifactDisabledGlobal;
			MarkDirty();
		}

		private void OnDisable()
		{
			RunArtifactManager.onArtifactEnabledGlobal -= OnArtifactDisabledGlobal;
			RunArtifactManager.onArtifactEnabledGlobal -= OnArtifactEnabledGlobal;
		}

		private void OnArtifactEnabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			MarkDirty();
		}

		private void OnArtifactDisabledGlobal(RunArtifactManager runArtifactManager, ArtifactDef artifactDef)
		{
			MarkDirty();
		}

		private void MarkDirty()
		{
			if (!dirty)
			{
				dirty = true;
				RoR2Application.onLateUpdate += Refresh;
			}
		}

		private void Refresh()
		{
			RunArtifactManager.RunEnabledArtifacts enabledArtifacts = RunArtifactManager.enabledArtifactsEnumerable.GetEnumerator();
			artifactDisplayPanelController.SetDisplayData(ref enabledArtifacts);
			dirty = false;
		}
	}
	public class CursorIndicatorController : MonoBehaviour
	{
		public enum CursorImage
		{
			None,
			Pointer,
			Hover
		}

		[Serializable]
		public struct CursorSet
		{
			public GameObject pointerObject;

			public GameObject hoverObject;

			public GameObject GetGameObject(CursorImage cursorImage)
			{
				return cursorImage switch
				{
					CursorImage.None => null, 
					CursorImage.Pointer => pointerObject, 
					CursorImage.Hover => hoverObject, 
					_ => null, 
				};
			}
		}

		[NonSerialized]
		public CursorSet noneCursorSet;

		public CursorSet mouseCursorSet;

		public CursorSet gamepadCursorSet;

		private GameObject currentChildIndicator;

		public RectTransform containerTransform;

		private UnityEngine.Color cachedIndicatorColor = UnityEngine.Color.clear;

		public void SetCursor(CursorSet cursorSet, CursorImage cursorImage, UnityEngine.Color color)
		{
			GameObject gameObject = cursorSet.GetGameObject(cursorImage);
			bool flag = color != cachedIndicatorColor;
			if (gameObject != currentChildIndicator)
			{
				if ((bool)currentChildIndicator)
				{
					currentChildIndicator.SetActive(value: false);
				}
				currentChildIndicator = gameObject;
				if ((bool)currentChildIndicator)
				{
					currentChildIndicator.SetActive(value: true);
				}
				flag = true;
			}
			if (flag)
			{
				cachedIndicatorColor = color;
				ApplyIndicatorColor();
			}
		}

		private void ApplyIndicatorColor()
		{
			if ((bool)currentChildIndicator)
			{
				UnityEngine.UI.Image[] componentsInChildren = currentChildIndicator.GetComponentsInChildren<UnityEngine.UI.Image>();
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].color = cachedIndicatorColor;
				}
			}
		}

		public void SetPosition(UnityEngine.Vector2 position)
		{
			containerTransform.position = position;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class CursorOpener : MonoBehaviour
	{
		[SerializeField]
		[Tooltip("If enabled, the cursor will be shown even if the user is on a gamepad.")]
		private bool _forceCursorForGamepad;

		private MPEventSystemLocator eventSystemLocator;

		private static MPEventSystem[] buffer = new MPEventSystem[8];

		private bool _opening;

		protected int linkedEventSystemCount;

		protected MPEventSystem[] linkedEventSystems = Array.Empty<MPEventSystem>();

		protected bool opening
		{
			get
			{
				return _opening;
			}
			set
			{
				if (_opening != value)
				{
					_opening = value;
					RebuildLinks();
				}
			}
		}

		public bool forceCursorForGamePad
		{
			get
			{
				return _forceCursorForGamepad;
			}
			set
			{
				if (_forceCursorForGamepad != value)
				{
					if (linkedEventSystemCount > 0)
					{
						ClearLinkedEventSystems();
					}
					_forceCursorForGamepad = value;
					RebuildLinks();
				}
			}
		}

		private void CacheComponents()
		{
			MPEventSystemLocator component = GetComponent<MPEventSystemLocator>();
			if ((object)component == eventSystemLocator)
			{
				return;
			}
			if ((object)eventSystemLocator != null)
			{
				eventSystemLocator.onEventSystemDiscovered -= OnEventSystemDiscovered;
				eventSystemLocator.onEventSystemLost -= OnEventSystemLost;
				if ((object)eventSystemLocator.eventSystem != null)
				{
					OnEventSystemLost(eventSystemLocator.eventSystem);
				}
			}
			eventSystemLocator = component;
			if ((object)eventSystemLocator != null)
			{
				eventSystemLocator.onEventSystemDiscovered += OnEventSystemDiscovered;
				eventSystemLocator.onEventSystemLost += OnEventSystemLost;
				if ((object)eventSystemLocator.eventSystem != null)
				{
					OnEventSystemDiscovered(eventSystemLocator.eventSystem);
				}
			}
		}

		protected void ClearLinkedEventSystems()
		{
			SetLinkedEventSystems(Array.Empty<MPEventSystem>(), 0);
		}

		protected void SetLinkedEventSystems(MPEventSystem[] newLinkedEventSystems, int newLinkedEventSystemCount)
		{
			for (int num = linkedEventSystemCount - 1; num >= 0; num--)
			{
				ref MPEventSystem reference = ref linkedEventSystems[num];
				MPEventSystem obj = reference;
				int cursorOpenerCount = obj.cursorOpenerCount - 1;
				obj.cursorOpenerCount = cursorOpenerCount;
				if (_forceCursorForGamepad)
				{
					MPEventSystem obj2 = reference;
					cursorOpenerCount = obj2.cursorOpenerForGamepadCount - 1;
					obj2.cursorOpenerForGamepadCount = cursorOpenerCount;
				}
				reference = null;
			}
			ArrayUtils.EnsureCapacity(ref linkedEventSystems, newLinkedEventSystemCount);
			for (int i = 0; i < newLinkedEventSystemCount; i++)
			{
				ref MPEventSystem reference2 = ref linkedEventSystems[i];
				reference2 = newLinkedEventSystems[i];
				MPEventSystem obj3 = reference2;
				int cursorOpenerCount = obj3.cursorOpenerCount + 1;
				obj3.cursorOpenerCount = cursorOpenerCount;
				if (_forceCursorForGamepad)
				{
					MPEventSystem obj4 = reference2;
					cursorOpenerCount = obj4.cursorOpenerForGamepadCount + 1;
					obj4.cursorOpenerForGamepadCount = cursorOpenerCount;
				}
			}
			linkedEventSystemCount = newLinkedEventSystemCount;
		}

		protected void RebuildLinks()
		{
			MPEventSystem eventSystem = eventSystemLocator.eventSystem;
			bool fallBackToMainEventSystem = eventSystemLocator.eventSystemProvider.fallBackToMainEventSystem;
			int count = 0;
			if (opening)
			{
				if (fallBackToMainEventSystem)
				{
					ReadOnlyCollection<MPEventSystem> readOnlyInstancesList = MPEventSystem.readOnlyInstancesList;
					ArrayUtils.EnsureCapacity(ref buffer, readOnlyInstancesList.Count);
					for (int i = 0; i < readOnlyInstancesList.Count; i++)
					{
						buffer[i] = readOnlyInstancesList[i];
					}
					count = readOnlyInstancesList.Count;
				}
				else if ((bool)eventSystemLocator.eventSystem)
				{
					buffer[0] = eventSystem;
					count = 1;
				}
			}
			SetLinkedEventSystems(buffer, count);
			ArrayUtils.Clear(buffer, ref count);
		}

		private void OnEventSystemDiscovered(MPEventSystem discoveredEventSystem)
		{
			if (opening)
			{
				RebuildLinks();
			}
		}

		private void OnEventSystemLost(MPEventSystem lostEventSystem)
		{
			if (opening)
			{
				RebuildLinks();
			}
		}

		protected void Awake()
		{
			CacheComponents();
		}

		protected void OnEnable()
		{
			opening = true;
		}

		protected void OnDisable()
		{
			opening = false;
		}

		[AssetCheck(typeof(CursorOpener))]
		private static void CheckCursorOpener(AssetCheckArgs args)
		{
			if (!((CursorOpener)args.asset).GetComponent<MPEventSystemLocator>())
			{
				args.Log("Missing MPEventSystemLocator.");
			}
		}
	}
	public class CustomScrollbar : MPScrollbar
	{
		private UnityEngine.Vector3 originalPosition;

		public bool scaleButtonOnHover = true;

		public bool showImageOnHover;

		public UnityEngine.UI.Image imageOnHover;

		public UnityEngine.UI.Image imageOnInteractable;

		private bool hovering;

		private float imageOnHoverAlphaVelocity;

		protected override void Awake()
		{
			base.Awake();
		}

		protected override void Start()
		{
			base.Start();
		}

		protected override void DoStateTransition(SelectionState state, bool instant)
		{
			base.DoStateTransition(state, instant);
			switch (state)
			{
			case SelectionState.Normal:
				hovering = false;
				break;
			case SelectionState.Highlighted:
				Util.PlaySound("Play_UI_menuHover", RoR2Application.instance.gameObject);
				hovering = true;
				break;
			case SelectionState.Pressed:
				hovering = true;
				break;
			case SelectionState.Disabled:
				hovering = false;
				break;
			case SelectionState.Selected:
				break;
			}
		}

		public void OnClickCustom()
		{
			Util.PlaySound("Play_UI_menuClick", RoR2Application.instance.gameObject);
		}

		private void LateUpdate()
		{
			if (Application.isPlaying)
			{
				if (showImageOnHover)
				{
					float target = (hovering ? 1f : 0f);
					UnityEngine.Color color = imageOnHover.color;
					float a = Mathf.SmoothDamp(color.a, target, ref imageOnHoverAlphaVelocity, 0.03f, 100f, Time.unscaledDeltaTime);
					UnityEngine.Color color2 = new UnityEngine.Color(color.r, color.g, color.g, a);
					imageOnHover.color = color2;
				}
				if ((bool)imageOnInteractable)
				{
					imageOnInteractable.enabled = base.interactable;
				}
			}
		}
	}
	public class DefaultSettings : MonoBehaviour
	{
		public void DefaultControllerMapping(Player player)
		{
			if (player == null)
			{
				return;
			}
			Controller lastActiveController = player.controllers.GetLastActiveController(ControllerType.Joystick);
			if (lastActiveController == null)
			{
				return;
			}
			JoystickMap defaultJoystickMap = DefaultControllerMaps.GetDefaultJoystickMap(lastActiveController.hardwareTypeGuid);
			if (defaultJoystickMap == null)
			{
				return;
			}
			LocalUser localUser = LocalUserManager.FindLocalUser(player);
			if (localUser != null)
			{
				localUser.userProfile.joystickMap = defaultJoystickMap;
				localUser.userProfile.UpdateJoystickMap(lastActiveController.hardwareTypeGuid, defaultJoystickMap);
				localUser.ApplyUserProfileBindingsToRewiredPlayer();
				localUser.userProfile.RequestEventualSave();
				MPEventSystem.RefreshAllControllerGlyphs();
				if (InputBindingDisplayController.onBindingsChanged != null)
				{
					InputBindingDisplayController.onBindingsChanged();
				}
			}
		}

		public void RestoreDefaultControllerSettings(Player player)
		{
			DefaultControllerMapping(player);
		}
	}
	public class DialogBoxManager : MonoBehaviour
	{
		private static DialogBoxManager instance;

		private static bool isAwait;

		private static DialogBoxManager Instance
		{
			get
			{
				if (!instance)
				{
					Init();
				}
				return instance;
			}
		}

		public static void Init()
		{
			instance = new GameObject("DialogBoxManager").AddComponent<DialogBoxManager>();
			UnityEngine.Object.DontDestroyOnLoad(instance.gameObject);
		}

		public static void DialogBoxDelay(string headerToken, string descriptionToken, string displayToken, float delay)
		{
			Instance.StartCoroutine(Instance.DialogBoxDelayCoroutine(headerToken, descriptionToken, displayToken, delay));
		}

		private IEnumerator DialogBoxDelayCoroutine(string headerToken, string descriptionToken, string displayToken, float delay)
		{
			isAwait = true;
			yield return new WaitForSeconds(delay);
			isAwait = false;
			DialogBox(headerToken, descriptionToken, displayToken);
		}

		public static SimpleDialogBox DialogBox(string headerToken, string descriptionToken, string displayToken, bool allowMultipleInstances = false)
		{
			if ((allowMultipleInstances || SimpleDialogBox.instancesList.Count == 0) && !isAwait)
			{
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
				simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair(headerToken);
				simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair(descriptionToken);
				simpleDialogBox.AddCancelButton(displayToken);
				simpleDialogBox.rootObject.transform.SetParent(RoR2Application.instance.mainCanvas.transform);
				SelectButton(simpleDialogBox);
				return simpleDialogBox;
			}
			return null;
		}

		public static SimpleDialogBox DialogBox(SimpleDialogBox.TokenParamsPair headerToken, SimpleDialogBox.TokenParamsPair descriptionToken, string displayToken, bool allowMultipleInstances = false)
		{
			if ((allowMultipleInstances || SimpleDialogBox.instancesList.Count == 0) && !isAwait)
			{
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
				simpleDialogBox.headerToken = headerToken;
				simpleDialogBox.descriptionToken = descriptionToken;
				simpleDialogBox.AddCancelButton(displayToken);
				simpleDialogBox.rootObject.transform.SetParent(RoR2Application.instance.mainCanvas.transform);
				SelectButton(simpleDialogBox);
				return simpleDialogBox;
			}
			return null;
		}

		public static SimpleDialogBox DialogBox(string headerToken, string descriptionToken, UnityAction action, string displayToken, bool destroyDialog = true, params object[] formatParams)
		{
			if (SimpleDialogBox.instancesList.Count == 0 && !isAwait)
			{
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
				simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair(headerToken);
				simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair(descriptionToken);
				simpleDialogBox.AddActionButton(action, displayToken, true);
				simpleDialogBox.rootObject.transform.SetParent(RoR2Application.instance.mainCanvas.transform);
				SelectButton(simpleDialogBox);
				return simpleDialogBox;
			}
			return null;
		}

		public static SimpleDialogBox DialogBox(SimpleDialogBox.TokenParamsPair headerToken, SimpleDialogBox.TokenParamsPair descriptionToken, UnityAction action, string displayToken, bool destroyDialog = true, params object[] formatParams)
		{
			if (SimpleDialogBox.instancesList.Count == 0 && !isAwait)
			{
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
				simpleDialogBox.headerToken = headerToken;
				simpleDialogBox.descriptionToken = descriptionToken;
				simpleDialogBox.AddActionButton(action, displayToken, true);
				simpleDialogBox.rootObject.transform.SetParent(RoR2Application.instance.mainCanvas.transform);
				SelectButton(simpleDialogBox);
				return simpleDialogBox;
			}
			return null;
		}

		public static void SelectButton(SimpleDialogBox dialogBox)
		{
			dialogBox.GetComponentInChildren<MPButton>().Select();
		}
	}
	[ExecuteAlways]
	public class DifficultyBarController : MonoBehaviour
	{
		[Serializable]
		public struct SegmentDef
		{
			[Tooltip("The default English string to use for the element at design time.")]
			public string debugString;

			[Tooltip("The final language token to use for this element at runtime.")]
			public string token;

			[Tooltip("The color to use for the panel.")]
			public UnityEngine.Color color;
		}

		private class SegmentImageAnimation
		{
			public UnityEngine.UI.Image segmentImage;

			public float age;

			public float duration;

			public AnimationCurve colorCurve;

			public UnityEngine.Color color0;

			public UnityEngine.Color color1;

			public void Update(float t)
			{
				segmentImage.color = UnityEngine.Color.Lerp(color0, color1, colorCurve.Evaluate(t));
			}
		}

		[Header("Component References")]
		public RectTransform viewPort;

		public RectTransform segmentContainer;

		public UnityEngine.UI.Image difficultyBarBackdrop;

		[Tooltip("How wide each segment should be.")]
		[Header("Layout")]
		public float elementWidth;

		public float levelsPerSegment;

		public float debugTime;

		[Header("Segment Parameters")]
		public SegmentDef[] segmentDefs;

		[Tooltip("The prefab to instantiate for each segment.")]
		public GameObject segmentPrefab;

		[Header("Colors")]
		public float pastSaturationMultiplier;

		public float pastValueMultiplier;

		public UnityEngine.Color pastLabelColor;

		public float currentSaturationMultiplier;

		public float currentValueMultiplier;

		public UnityEngine.Color currentLabelColor;

		public float upcomingSaturationMultiplier;

		public float upcomingValueMultiplier;

		public UnityEngine.Color upcomingLabelColor;

		[Tooltip("If the increasedDifficultyBarFX user setting is enabled and the next difficulty color's value is below this, flash white instead.")]
		public float backdropFlashWhiteThreshold = 0.43f;

		[Header("Animations")]
		public AnimationCurve fadeAnimationCurve;

		public float fadeAnimationDuration = 1f;

		public AnimationCurve flashAnimationCurve;

		public float flashAnimationDuration = 0.5f;

		private int currentSegmentIndex = -1;

		private static readonly UnityEngine.Color labelFadedColor = UnityEngine.Color.Lerp(UnityEngine.Color.gray, UnityEngine.Color.white, 0.5f);

		[SerializeField]
		private string onDifficultyChangeSoundString = "Play_wDifficulty_New";

		[Header("Final Segment")]
		public Sprite finalSegmentSprite;

		private HUD hud;

		private float scrollX;

		private float scrollXRaw;

		private float lastSegmentScroll;

		[Tooltip("Do not set this manually. Regenerate the children instead.")]
		public UnityEngine.UI.Image[] images;

		[Tooltip("Do not set this manually. Regenerate the children instead.")]
		public TextMeshProUGUI[] labels;

		public RawImage[] wormGearImages;

		public float UVScaleToScrollX;

		public float gearUVOffset;

		private readonly List<SegmentImageAnimation> playingAnimations = new List<SegmentImageAnimation>();

		private static UnityEngine.Color ColorMultiplySaturationAndValue(ref UnityEngine.Color col, float saturationMultiplier, float valueMultiplier)
		{
			UnityEngine.Color.RGBToHSV(col, out var H, out var S, out var V);
			return UnityEngine.Color.HSVToRGB(H, S * saturationMultiplier, V * valueMultiplier);
		}

		private void OnCurrentSegmentIndexChanged(int newSegmentIndex)
		{
			if (!Application.isPlaying)
			{
				return;
			}
			int num = newSegmentIndex - 1;
			float width = viewPort.rect.width;
			int i = 0;
			for (int num2 = images.Length - 1; i < num2; i++)
			{
				UnityEngine.UI.Image obj = images[i];
				TextMeshProUGUI textMeshProUGUI = labels[i];
				RectTransform rectTransform = obj.rectTransform;
				bool flag2 = (obj.enabled = rectTransform.offsetMax.x + scrollX >= 0f && rectTransform.offsetMin.x + scrollX <= width);
				textMeshProUGUI.enabled = flag2;
			}
			int num3 = images.Length - 1;
			UnityEngine.UI.Image obj2 = images[num3];
			TextMeshProUGUI textMeshProUGUI2 = labels[num3];
			bool flag4 = (obj2.enabled = obj2.rectTransform.offsetMax.x + scrollX >= 0f);
			textMeshProUGUI2.enabled = flag4;
			for (int j = 0; j <= num; j++)
			{
				images[j].color = ColorMultiplySaturationAndValue(ref segmentDefs[j].color, pastSaturationMultiplier, pastValueMultiplier);
				labels[j].color = pastLabelColor;
			}
			for (int k = newSegmentIndex + 1; k < images.Length; k++)
			{
				images[k].color = ColorMultiplySaturationAndValue(ref segmentDefs[k].color, upcomingSaturationMultiplier, upcomingValueMultiplier);
				labels[k].color = upcomingLabelColor;
			}
			UnityEngine.UI.Image image = ((num != -1) ? images[num] : null);
			UnityEngine.UI.Image image2 = ((newSegmentIndex != -1) ? images[newSegmentIndex] : null);
			TextMeshProUGUI textMeshProUGUI3 = ((newSegmentIndex != -1) ? labels[newSegmentIndex] : null);
			if ((bool)image)
			{
				playingAnimations.Add(new SegmentImageAnimation
				{
					age = 0f,
					duration = fadeAnimationDuration,
					segmentImage = image,
					colorCurve = fadeAnimationCurve,
					color0 = segmentDefs[num].color,
					color1 = ColorMultiplySaturationAndValue(ref segmentDefs[num].color, pastSaturationMultiplier, pastValueMultiplier)
				});
			}
			UnityEngine.Color color = ColorMultiplySaturationAndValue(ref segmentDefs[newSegmentIndex].color, currentSaturationMultiplier, currentValueMultiplier);
			if ((bool)image2)
			{
				playingAnimations.Add(new SegmentImageAnimation
				{
					age = 0f,
					duration = flashAnimationDuration,
					segmentImage = image2,
					colorCurve = flashAnimationCurve,
					color0 = color,
					color1 = UnityEngine.Color.white
				});
			}
			if ((bool)hud && (bool)difficultyBarBackdrop)
			{
				UserProfile userProfile = hud.localUserViewer.userProfile;
				if (userProfile != null && userProfile.increasedDifficultyBarFX)
				{
					UnityEngine.Color.RGBToHSV(segmentDefs[newSegmentIndex].color, out var _, out var _, out var V);
					playingAnimations.Add(new SegmentImageAnimation
					{
						age = 0f,
						duration = flashAnimationDuration,
						segmentImage = difficultyBarBackdrop,
						colorCurve = flashAnimationCurve,
						color0 = difficultyBarBackdrop.color,
						color1 = ((V < backdropFlashWhiteThreshold) ? UnityEngine.Color.white : color)
					});
					if (newSegmentIndex > 0)
					{
						Util.PlaySound(onDifficultyChangeSoundString, RoR2Application.instance.gameObject);
					}
				}
			}
			if ((bool)textMeshProUGUI3)
			{
				textMeshProUGUI3.color = currentLabelColor;
			}
		}

		private void SetSegmentScroll(float segmentScroll)
		{
			if (segmentScroll == lastSegmentScroll)
			{
				return;
			}
			lastSegmentScroll = segmentScroll;
			float num = segmentDefs.Length + 2;
			if (segmentScroll > num)
			{
				segmentScroll = num - 1f + (segmentScroll - Mathf.Floor(segmentScroll));
			}
			scrollXRaw = (segmentScroll - 1f) * (0f - elementWidth);
			scrollX = Mathf.Floor(scrollXRaw);
			int num2 = currentSegmentIndex;
			currentSegmentIndex = Mathf.Clamp(Mathf.FloorToInt(segmentScroll), 0, segmentContainer.childCount - 1);
			if (num2 != currentSegmentIndex)
			{
				OnCurrentSegmentIndexChanged(currentSegmentIndex);
			}
			UnityEngine.Vector2 offsetMin = segmentContainer.offsetMin;
			offsetMin.x = scrollX;
			segmentContainer.offsetMin = offsetMin;
			if ((bool)segmentContainer && segmentContainer.childCount > 0)
			{
				int num3 = segmentContainer.childCount - 1;
				RectTransform rectTransform = (RectTransform)segmentContainer.GetChild(num3);
				RectTransform rectTransform2 = (RectTransform)rectTransform.Find("Label");
				_ = labels[num3];
				if (segmentScroll >= (float)(num3 - 1))
				{
					float num4 = elementWidth;
					UnityEngine.Vector2 offsetMin2 = rectTransform.offsetMin;
					offsetMin2.x = CalcSegmentStartX(num3);
					rectTransform.offsetMin = offsetMin2;
					UnityEngine.Vector2 offsetMax = rectTransform.offsetMax;
					offsetMax.x = offsetMin2.x + num4;
					rectTransform.offsetMax = offsetMax;
					rectTransform2.anchorMin = new UnityEngine.Vector2(0f, 0f);
					rectTransform2.anchorMax = new UnityEngine.Vector2(0f, 1f);
					rectTransform2.offsetMin = new UnityEngine.Vector2(0f, 0f);
					rectTransform2.offsetMax = new UnityEngine.Vector2(elementWidth, 0f);
				}
				else
				{
					rectTransform.offsetMax = rectTransform.offsetMin + new UnityEngine.Vector2(elementWidth, 0f);
					SetLabelDefaultDimensions(rectTransform2);
				}
			}
		}

		private float CalcSegmentStartX(int i)
		{
			return (float)i * elementWidth;
		}

		private float CalcSegmentEndX(int i)
		{
			return (float)(i + 1) * elementWidth;
		}

		private void SetLabelDefaultDimensions(RectTransform labelRectTransform)
		{
			labelRectTransform.anchorMin = new UnityEngine.Vector2(0f, 0f);
			labelRectTransform.anchorMax = new UnityEngine.Vector2(1f, 1f);
			labelRectTransform.pivot = new UnityEngine.Vector2(0.5f, 0.5f);
			labelRectTransform.offsetMin = new UnityEngine.Vector2(0f, 0f);
			labelRectTransform.offsetMax = new UnityEngine.Vector2(0f, 0f);
		}

		private void SetSegmentCount(uint desiredCount)
		{
			if ((bool)segmentContainer && (bool)segmentPrefab)
			{
				uint num = (uint)segmentContainer.childCount;
				if (images == null || images.Length != desiredCount)
				{
					images = new UnityEngine.UI.Image[desiredCount];
					labels = new TextMeshProUGUI[desiredCount];
				}
				int i = 0;
				for (int num2 = Mathf.Min(images.Length, segmentContainer.childCount); i < num2; i++)
				{
					Transform child = segmentContainer.GetChild(i);
					images[i] = child.GetComponent<UnityEngine.UI.Image>();
					labels[i] = child.Find("Label").GetComponent<TextMeshProUGUI>();
				}
				while (num > desiredCount)
				{
					UnityEngine.Object.DestroyImmediate(segmentContainer.GetChild((int)(num - 1)).gameObject);
					num--;
				}
				for (; num < desiredCount; num++)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(segmentPrefab, segmentContainer);
					gameObject.SetActive(value: true);
					images[i] = gameObject.GetComponent<UnityEngine.UI.Image>();
					labels[i] = gameObject.transform.Find("Label").GetComponent<TextMeshProUGUI>();
					i++;
				}
			}
		}

		private void SetupSegments()
		{
			if ((bool)segmentContainer && (bool)segmentPrefab)
			{
				SetSegmentCount((uint)segmentDefs.Length);
				for (int i = 0; i < segmentContainer.childCount; i++)
				{
					SetupSegment((RectTransform)segmentContainer.GetChild(i), ref segmentDefs[i], i);
				}
				SetupFinalSegment((RectTransform)segmentContainer.GetChild(segmentContainer.childCount - 1));
			}
		}

		private static void ScaleLabelToWidth(TextMeshProUGUI label, float width)
		{
			RectTransform obj = (RectTransform)label.transform;
			float x = label.textBounds.size.x;
			UnityEngine.Vector3 localScale = obj.localScale;
			localScale.x = width / x;
			obj.localScale = localScale;
		}

		private void SetupFinalSegment(RectTransform segmentTransform)
		{
			TextMeshProUGUI[] array = segmentTransform.GetComponentsInChildren<TextMeshProUGUI>();
			int num = 4;
			if (array.Length < num)
			{
				TextMeshProUGUI[] array2 = new TextMeshProUGUI[num];
				for (int i = 0; i < array.Length; i++)
				{
					array2[i] = array[i];
				}
				for (int j = array.Length; j < num; j++)
				{
					array2[j] = UnityEngine.Object.Instantiate(array[0].gameObject, segmentTransform).GetComponent<TextMeshProUGUI>();
				}
				array = array2;
			}
			int k = 0;
			for (int num2 = array.Length; k < num2; k++)
			{
				TextMeshProUGUI obj = array[k];
				obj.enableWordWrapping = false;
				obj.overflowMode = TextOverflowModes.Overflow;
				obj.alignment = TextAlignmentOptions.MidlineLeft;
				obj.text = Language.GetString(segmentDefs[segmentDefs.Length - 1].token);
				obj.enableAutoSizing = true;
				UnityEngine.Vector3 localPosition = obj.transform.localPosition;
				localPosition.x = (float)k * elementWidth;
				obj.transform.localPosition = localPosition;
			}
			segmentTransform.GetComponent<UnityEngine.UI.Image>().sprite = finalSegmentSprite;
		}

		private void SetupSegment(RectTransform segmentTransform, ref SegmentDef segmentDef, int i)
		{
			UnityEngine.Vector2 offsetMin = segmentTransform.offsetMin;
			UnityEngine.Vector2 offsetMax = segmentTransform.offsetMax;
			offsetMin.x = CalcSegmentStartX(i);
			offsetMax.x = CalcSegmentEndX(i);
			segmentTransform.offsetMin = offsetMin;
			segmentTransform.offsetMax = offsetMax;
			segmentTransform.GetComponent<UnityEngine.UI.Image>().color = segmentDef.color;
			((RectTransform)segmentTransform.Find("Label")).GetComponent<LanguageTextMeshController>().token = segmentDef.token;
		}

		private void Awake()
		{
			hud = GetComponentInParent<HUD>();
			SetupSegments();
		}

		private void DoBarUpdates(float deltaTime)
		{
			if ((bool)Run.instance)
			{
				SetSegmentScroll((Run.instance.ambientLevel - 1f) / levelsPerSegment);
			}
			if (Application.isPlaying)
			{
				RunAnimations(deltaTime);
			}
		}

		private void Update()
		{
			DoBarUpdates(Time.deltaTime);
			UpdateGears();
		}

		private void UpdateGears()
		{
			RawImage[] array = wormGearImages;
			foreach (RawImage obj in array)
			{
				UnityEngine.Rect uvRect = obj.uvRect;
				float num = Mathf.Sign(uvRect.width);
				uvRect.x = scrollXRaw * UVScaleToScrollX * num + ((num < 0f) ? gearUVOffset : 0f);
				obj.uvRect = uvRect;
			}
		}

		private void RunAnimations(float deltaTime)
		{
			for (int num = playingAnimations.Count - 1; num >= 0; num--)
			{
				SegmentImageAnimation segmentImageAnimation = playingAnimations[num];
				segmentImageAnimation.age += deltaTime;
				float num2 = Mathf.Clamp01(segmentImageAnimation.age / segmentImageAnimation.duration);
				segmentImageAnimation.Update(num2);
				if (num2 >= 1f)
				{
					playingAnimations.RemoveAt(num);
				}
			}
		}
	}
	public class DifficultyTutorialController : MonoBehaviour
	{
		private HUD hud;

		[Tooltip("The tutorial popup object.")]
		public GameObject difficultyTutorialObject;

		[Tooltip("The time at which to trigger the tutorial popup.")]
		public float difficultyTutorialTriggerTime = 60f;

		private void Awake()
		{
			hud = GetComponentInParent<HUD>();
			if ((bool)difficultyTutorialObject)
			{
				difficultyTutorialObject.SetActive(value: false);
			}
		}

		private void Update()
		{
			if ((bool)hud)
			{
				UserProfile userProfile = hud.localUserViewer.userProfile;
				CharacterBody cachedBody = hud.localUserViewer.cachedBody;
				if (userProfile != null && (bool)cachedBody && (bool)difficultyTutorialObject && userProfile.tutorialDifficulty.shouldShow && (bool)Run.instance && Run.instance.fixedTime >= difficultyTutorialTriggerTime)
				{
					difficultyTutorialObject.SetActive(value: true);
					userProfile.tutorialDifficulty.shouldShow = false;
					userProfile.tutorialDifficulty.showCount++;
				}
			}
		}
	}
	public class DisableIfTextIsEmpty : MonoBehaviour
	{
		public GameObject[] gameObjects;

		public TextMeshProUGUI tmpUGUI;

		private bool isActive;

		private void Update()
		{
			bool flag = !string.IsNullOrEmpty(tmpUGUI.text);
			if (flag != isActive)
			{
				isActive = flag;
				GameObject[] array = gameObjects;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(isActive);
				}
			}
		}
	}
	public class DisplayStock : MonoBehaviour
	{
		public SkillSlot skillSlot;

		public UnityEngine.UI.Image[] stockImages;

		public Sprite fullStockSprite;

		public UnityEngine.Color fullStockColor;

		public Sprite emptyStockSprite;

		public UnityEngine.Color emptyStockColor;

		private HudElement hudElement;

		private SkillLocator skillLocator;

		private void Awake()
		{
			hudElement = GetComponent<HudElement>();
		}

		private void Update()
		{
			if (!hudElement.targetCharacterBody)
			{
				return;
			}
			if (!skillLocator)
			{
				skillLocator = hudElement.targetCharacterBody.GetComponent<SkillLocator>();
			}
			if (!skillLocator)
			{
				return;
			}
			GenericSkill skill = skillLocator.GetSkill(skillSlot);
			if (!skill)
			{
				return;
			}
			for (int i = 0; i < stockImages.Length; i++)
			{
				if (skill.stock > i)
				{
					stockImages[i].sprite = fullStockSprite;
					stockImages[i].color = fullStockColor;
				}
				else
				{
					stockImages[i].sprite = emptyStockSprite;
					stockImages[i].color = emptyStockColor;
				}
			}
		}
	}
	[RequireComponent(typeof(PositionIndicator))]
	public class DistanceIndicator : MonoBehaviour
	{
		public PositionIndicator positionIndicator;

		public TextMeshPro tmp;

		private static readonly List<DistanceIndicator> instancesList;

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		static DistanceIndicator()
		{
			instancesList = new List<DistanceIndicator>();
			UICamera.onUICameraPreCull += UpdateText;
		}

		private static void UpdateText(UICamera uiCamera)
		{
			CameraRigController cameraRigController = uiCamera.cameraRigController;
			Transform transform = null;
			if ((bool)cameraRigController && (bool)cameraRigController.target)
			{
				CharacterBody component = cameraRigController.target.GetComponent<CharacterBody>();
				transform = ((!component) ? cameraRigController.target.transform : component.coreTransform);
			}
			if ((bool)transform)
			{
				for (int i = 0; i < instancesList.Count; i++)
				{
					DistanceIndicator distanceIndicator = instancesList[i];
					string text = (distanceIndicator.positionIndicator.targetTransform.position - transform.position).magnitude.ToString("0.0") + "m";
					distanceIndicator.tmp.text = text;
				}
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class DragMove : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler
	{
		public RectTransform targetTransform;

		private UnityEngine.Vector2 grabPoint;

		private RectTransform rectTransform;

		private void OnAwake()
		{
			rectTransform = (RectTransform)base.transform;
		}

		public void OnDrag(PointerEventData eventData)
		{
			UpdateDrag(eventData);
		}

		public void OnBeginDrag(PointerEventData eventData)
		{
			if ((bool)targetTransform)
			{
				RectTransformUtility.ScreenPointToLocalPointInRectangle(targetTransform, eventData.position, eventData.pressEventCamera, out grabPoint);
			}
		}

		private void UpdateDrag(PointerEventData eventData)
		{
			if (eventData.button == PointerEventData.InputButton.Left && (bool)targetTransform)
			{
				RectTransformUtility.ScreenPointToLocalPointInRectangle(targetTransform, eventData.position, eventData.pressEventCamera, out var localPoint);
				UnityEngine.Vector2 vector = localPoint - grabPoint;
				targetTransform.localPosition += new UnityEngine.Vector3(vector.x, vector.y, 0f);
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class DragResize : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler
	{
		public RectTransform targetTransform;

		public UnityEngine.Vector2 minSize;

		private UnityEngine.Vector2 grabPoint;

		private RectTransform rectTransform;

		private void Awake()
		{
			rectTransform = (RectTransform)base.transform;
		}

		public void OnDrag(PointerEventData eventData)
		{
			UpdateDrag(eventData);
		}

		public void OnBeginDrag(PointerEventData eventData)
		{
			if ((bool)targetTransform)
			{
				RectTransformUtility.ScreenPointToLocalPointInRectangle(targetTransform, eventData.position, eventData.pressEventCamera, out grabPoint);
			}
		}

		private void UpdateDrag(PointerEventData eventData)
		{
			if (eventData.button == PointerEventData.InputButton.Left && (bool)targetTransform)
			{
				RectTransformUtility.ScreenPointToLocalPointInRectangle(targetTransform, eventData.position, eventData.pressEventCamera, out var localPoint);
				UnityEngine.Vector2 vector = localPoint - grabPoint;
				grabPoint = localPoint;
				vector.y = 0f - vector.y;
				minSize = UnityEngine.Vector2.Max(rhs: new UnityEngine.Vector2(LayoutUtility.GetMinSize(targetTransform, 0), LayoutUtility.GetMinSize(targetTransform, 1)), lhs: minSize);
				targetTransform.sizeDelta = UnityEngine.Vector2.Max(targetTransform.sizeDelta + vector, minSize);
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class EclipseRunScreenController : MonoBehaviour
	{
		[Header("Required references")]
		public LanguageTextMeshController survivorName;

		public LanguageTextMeshController eclipseDifficultyName;

		public LanguageTextMeshController eclipseDifficultyDescription;

		private LocalUser localUser;

		private MPEventSystemLocator eventSystemLocator;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private void OnEnable()
		{
			UserProfile.onSurvivorPreferenceChangedGlobal += OnSurvivorPreferenceChangedGlobal;
			eventSystemLocator.onEventSystemDiscovered += OnEventSystemDiscovered;
			if ((bool)eventSystemLocator.eventSystem)
			{
				OnEventSystemDiscovered(eventSystemLocator.eventSystem);
			}
		}

		private void OnDisable()
		{
			eventSystemLocator.onEventSystemDiscovered -= OnEventSystemDiscovered;
			UserProfile.onSurvivorPreferenceChangedGlobal -= OnSurvivorPreferenceChangedGlobal;
			localUser = null;
		}

		private void OnSurvivorPreferenceChangedGlobal(UserProfile userProfile)
		{
			UpdateDisplayedSurvivor();
		}

		public void BeginGamemode()
		{
			Console.instance.SubmitCmd(null, "transition_command \"gamemode EclipseRun; host 0;\"");
		}

		public void SetDisplayedSurvivor(SurvivorDef newSurvivorDef)
		{
			_ = (bool)newSurvivorDef;
		}

		private void OnEventSystemDiscovered(MPEventSystem eventSystem)
		{
			localUser = eventSystem.localUser;
			UpdateDisplayedSurvivor();
		}

		private void UpdateDisplayedSurvivor()
		{
			_ = string.Empty;
			string token = string.Empty;
			string token2 = string.Empty;
			SurvivorDef survivorDef = eventSystemLocator.eventSystem?.localUser?.userProfile.GetSurvivorPreference();
			if ((bool)survivorDef)
			{
				DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(EclipseRun.GetEclipseDifficultyIndex(Mathf.Clamp(EclipseRun.GetLocalUserSurvivorCompletedEclipseLevel(localUser, survivorDef) + 1, EclipseRun.minEclipseLevel, EclipseRun.maxEclipseLevel)));
				token = difficultyDef.nameToken;
				token2 = difficultyDef.descriptionToken;
			}
			if ((bool)survivorName)
			{
				survivorName.token = survivorDef.displayNameToken;
			}
			if ((bool)eclipseDifficultyName)
			{
				eclipseDifficultyName.token = token;
			}
			if ((bool)eclipseDifficultyDescription)
			{
				eclipseDifficultyDescription.token = token2;
			}
		}
	}
	[RequireComponent(typeof(HudElement))]
	public class EnemyInfoPanel : MonoBehaviour
	{
		public GameObject monsterBodiesContainer;

		public RectTransform monsterBodyIconContainer;

		public GameObject inventoryContainer;

		public ItemInventoryDisplay inventoryDisplay;

		public GameObject iconPrefab;

		private UIElementAllocator<RawImage> monsterBodyIconAllocator;

		private BodyIndex[] currentMonsterBodyIndices = Array.Empty<BodyIndex>();

		private HUD hud;

		private ItemIndex[] itemAcquisitionOrder;

		private int itemAcquisitionOrderLength;

		private int[] itemStacks;

		private static GameObject panelPrefab = null;

		private static readonly List<BodyIndex> bodyIndexList = new List<BodyIndex>();

		private static bool isDirty = false;

		private static readonly List<int> cachedArenaMonsterBodiesList = new List<int>();

		private void Awake()
		{
			monsterBodyIconAllocator = new UIElementAllocator<RawImage>(monsterBodyIconContainer, iconPrefab);
			itemStacks = ItemCatalog.RequestItemStackArray();
			itemAcquisitionOrder = ItemCatalog.RequestItemOrderBuffer();
			monsterBodiesContainer.SetActive(value: false);
			inventoryContainer.SetActive(value: false);
		}

		private void OnDestroy()
		{
			ItemCatalog.ReturnItemOrderBuffer(itemAcquisitionOrder);
			itemAcquisitionOrder = null;
			ItemCatalog.ReturnItemStackArray(itemStacks);
			itemStacks = null;
		}

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			MarkDirty();
		}

		private void OnDisable()
		{
			MarkDirty();
			InstanceTracker.Remove(this);
		}

		private void TrySetMonsterBodies<T>([NotNull] T newBodyIndices) where T : IList<BodyIndex>
		{
			bool flag = false;
			if (currentMonsterBodyIndices.Length != newBodyIndices.Count)
			{
				Array.Resize(ref currentMonsterBodyIndices, newBodyIndices.Count);
				flag = true;
			}
			for (int i = 0; i < newBodyIndices.Count; i++)
			{
				if (currentMonsterBodyIndices[i] != newBodyIndices[i])
				{
					currentMonsterBodyIndices[i] = newBodyIndices[i];
					flag = true;
				}
			}
			if (flag)
			{
				SetMonsterBodies(currentMonsterBodyIndices);
			}
		}

		private void SetMonsterBodies([NotNull] BodyIndex[] bodyIndices)
		{
			monsterBodyIconAllocator.AllocateElements(bodyIndices.Length);
			for (int i = 0; i < bodyIndices.Length; i++)
			{
				CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndices[i]);
				monsterBodyIconAllocator.elements[i].texture = bodyPrefabBodyComponent?.portraitIcon;
			}
			monsterBodiesContainer.SetActive(bodyIndices.Length != 0);
		}

		private void TrySetItems<T1, T2>([NotNull] T1 newItemAcquisitionOrder, int newItemAcquisitionOrderLength, [NotNull] T2 newItemStacks) where T1 : IList<ItemIndex> where T2 : IList<int>
		{
			bool flag = false;
			bool flag2 = false;
			if (itemAcquisitionOrderLength != newItemAcquisitionOrderLength)
			{
				flag = true;
			}
			else
			{
				for (int i = 0; i < itemAcquisitionOrderLength; i++)
				{
					if (itemAcquisitionOrder[i] != newItemAcquisitionOrder[i])
					{
						flag = true;
						break;
					}
				}
			}
			for (int j = 0; j < itemStacks.Length; j++)
			{
				if (itemStacks[j] != newItemStacks[j])
				{
					flag2 = true;
					break;
				}
			}
			if (flag)
			{
				itemAcquisitionOrderLength = newItemAcquisitionOrderLength;
				for (int k = 0; k < itemAcquisitionOrderLength; k++)
				{
					itemAcquisitionOrder[k] = newItemAcquisitionOrder[k];
				}
			}
			if (flag2)
			{
				for (int l = 0; l < itemStacks.Length; l++)
				{
					itemStacks[l] = newItemStacks[l];
				}
			}
			if (flag || flag2)
			{
				SetItems(itemAcquisitionOrder, itemAcquisitionOrderLength, itemStacks);
			}
		}

		private void SetItems([NotNull] ItemIndex[] newItemAcquisitionOrder, int newItemAcquisitionOrderLength, [NotNull] int[] newItemStacks)
		{
			inventoryContainer.SetActive(newItemAcquisitionOrderLength > 0);
			inventoryDisplay.SetItems(newItemAcquisitionOrder, newItemAcquisitionOrderLength, newItemStacks);
		}

		private static EnemyInfoPanel SetDisplayingOnHud([NotNull] HUD hud, bool shouldDisplay)
		{
			List<EnemyInfoPanel> instancesList = InstanceTracker.GetInstancesList<EnemyInfoPanel>();
			EnemyInfoPanel enemyInfoPanel = null;
			for (int i = 0; i < instancesList.Count; i++)
			{
				EnemyInfoPanel enemyInfoPanel2 = instancesList[i];
				if ((object)enemyInfoPanel2.hud == hud)
				{
					enemyInfoPanel = enemyInfoPanel2;
					break;
				}
			}
			if ((bool)enemyInfoPanel != shouldDisplay)
			{
				if (!enemyInfoPanel)
				{
					Transform transform = null;
					if ((bool)hud.gameModeUiInstance)
					{
						ChildLocator component = hud.gameModeUiInstance.GetComponent<ChildLocator>();
						if ((bool)component)
						{
							Transform transform2 = component.FindChild("RightInfoBar");
							if ((bool)transform2)
							{
								transform = transform2.GetComponent<RectTransform>();
							}
						}
					}
					if ((bool)transform)
					{
						EnemyInfoPanel component2 = UnityEngine.Object.Instantiate(panelPrefab, transform).GetComponent<EnemyInfoPanel>();
						component2.hud = hud;
						enemyInfoPanel = component2;
					}
				}
				else
				{
					UnityEngine.Object.Destroy(enemyInfoPanel.gameObject);
					enemyInfoPanel = null;
				}
			}
			return enemyInfoPanel;
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			ArenaMissionController.onInstanceChangedGlobal += ArenaMissionControllerOnOnInstanceChangedGlobal;
			LegacyResourcesAPI.LoadAsyncCallback("Prefabs/UI/EnemyInfoPanel", delegate(GameObject operationResult)
			{
				panelPrefab = operationResult;
			});
			HUD.onHudTargetChangedGlobal += OnHudTargetChangedGlobal;
			EnemyInfoPanelInventoryProvider.onInventoriesChanged += RefreshAll;
			RoR2Application.onFixedUpdate += StaticFixedUpdate;
		}

		private static void ArenaMissionControllerOnOnInstanceChangedGlobal()
		{
			MarkDirty();
		}

		private static void OnHudTargetChangedGlobal([NotNull] HUD hud)
		{
			MarkDirty();
		}

		private static void MarkDirty()
		{
			if (!isDirty)
			{
				RoR2Application.onNextUpdate += RefreshAll;
			}
		}

		private static void RefreshAll()
		{
			for (int i = 0; i < HUD.readOnlyInstanceList.Count; i++)
			{
				RefreshHUD(HUD.readOnlyInstanceList[i]);
			}
			isDirty = false;
		}

		private static void RefreshHUD(HUD hud)
		{
			if (!hud.targetMaster)
			{
				return;
			}
			TeamIndex teamIndex = hud.targetMaster.teamIndex;
			ItemIndex[] array = ItemCatalog.RequestItemOrderBuffer();
			int itemAcquisitonOrderLength = 0;
			int[] array2 = ItemCatalog.RequestItemStackArray();
			int[] array3 = ItemCatalog.RequestItemStackArray();
			List<EnemyInfoPanelInventoryProvider> instancesList = InstanceTracker.GetInstancesList<EnemyInfoPanelInventoryProvider>();
			int i = 0;
			for (int count = instancesList.Count; i < count; i++)
			{
				EnemyInfoPanelInventoryProvider enemyInfoPanelInventoryProvider = instancesList[i];
				if (enemyInfoPanelInventoryProvider.teamFilter.teamIndex == teamIndex)
				{
					continue;
				}
				List<ItemIndex> list = enemyInfoPanelInventoryProvider.inventory.itemAcquisitionOrder;
				int j = 0;
				for (int count2 = list.Count; j < count2; j++)
				{
					ItemIndex itemIndex = list[j];
					ref int reference = ref array3[(int)itemIndex];
					if (reference == 0)
					{
						reference = 1;
						array[itemAcquisitonOrderLength++] = itemIndex;
					}
				}
				for (int k = 0; k < array2.Length; k++)
				{
					array2[k] += enemyInfoPanelInventoryProvider.inventory.GetItemCount((ItemIndex)k);
				}
			}
			bodyIndexList.Clear();
			if ((bool)ArenaMissionController.instance)
			{
				SyncListInt syncActiveMonsterBodies = ArenaMissionController.instance.syncActiveMonsterBodies;
				for (int l = 0; l < syncActiveMonsterBodies.Count; l++)
				{
					bodyIndexList.Add((BodyIndex)syncActiveMonsterBodies[l]);
				}
			}
			else
			{
				BodyIndex bodyIndex = (Stage.instance ? Stage.instance.singleMonsterTypeBodyIndex : BodyIndex.None);
				if (bodyIndex != BodyIndex.None)
				{
					bodyIndexList.Add(bodyIndex);
				}
			}
			SetDisplayDataForViewer(hud, bodyIndexList, array, itemAcquisitonOrderLength, array2);
			ItemCatalog.ReturnItemStackArray(array3);
			ItemCatalog.ReturnItemStackArray(array2);
			ItemCatalog.ReturnItemOrderBuffer(array);
		}

		private static void SetDisplayDataForViewer([NotNull] HUD hud, [NotNull] List<BodyIndex> bodyIndices, [NotNull] ItemIndex[] itemAcquisitionOrderBuffer, int itemAcquisitonOrderLength, int[] itemStacks)
		{
			bool shouldDisplay = bodyIndices.Count > 0 || itemAcquisitonOrderLength > 0;
			EnemyInfoPanel enemyInfoPanel = SetDisplayingOnHud(hud, shouldDisplay);
			if ((bool)enemyInfoPanel && enemyInfoPanel.isActiveAndEnabled)
			{
				enemyInfoPanel.TrySetMonsterBodies(bodyIndices);
				enemyInfoPanel.TrySetItems(itemAcquisitionOrderBuffer, itemAcquisitonOrderLength, itemStacks);
			}
		}

		private static void StaticFixedUpdate()
		{
			if (!ArenaMissionController.instance)
			{
				return;
			}
			bool flag = false;
			SyncListInt syncActiveMonsterBodies = ArenaMissionController.instance.syncActiveMonsterBodies;
			if (cachedArenaMonsterBodiesList.Count == syncActiveMonsterBodies.Count)
			{
				int i = 0;
				for (int count = syncActiveMonsterBodies.Count; i < count; i++)
				{
					if (cachedArenaMonsterBodiesList[i] != syncActiveMonsterBodies[i])
					{
						flag = true;
						break;
					}
				}
			}
			else
			{
				flag = true;
			}
			if (flag)
			{
				cachedArenaMonsterBodiesList.Clear();
				int j = 0;
				for (int count2 = syncActiveMonsterBodies.Count; j < count2; j++)
				{
					cachedArenaMonsterBodiesList.Add(syncActiveMonsterBodies[j]);
				}
				MarkDirty();
			}
		}
	}
	public class EquipmentIcon : MonoBehaviour
	{
		private struct DisplayData
		{
			public EquipmentDef equipmentDef;

			public int cooldownValue;

			public int stock;

			public int maxStock;

			public bool hideEntireDisplay;

			public bool equipmentDisabled;

			public bool isReady => stock > 0;

			public bool hasEquipment => equipmentDef != null;

			public bool showCooldown
			{
				get
				{
					if (!isReady)
					{
						return hasEquipment;
					}
					return false;
				}
			}
		}

		public Inventory targetInventory;

		public EquipmentSlot targetEquipmentSlot;

		public GameObject displayRoot;

		public PlayerCharacterMasterController playerCharacterMasterController;

		public RawImage iconImage;

		public TextMeshProUGUI cooldownText;

		public TextMeshProUGUI stockText;

		public GameObject stockFlashPanelObject;

		public GameObject reminderFlashPanelObject;

		public GameObject isReadyPanelObject;

		public GameObject isAutoCastPanelObject;

		public TooltipProvider tooltipProvider;

		private HGButton NavButtonToEnable;

		public bool displayAlternateEquipment;

		private int previousStockCount;

		private float equipmentReminderTimer;

		public const string equipmentDisabledNameToken = "EQUIPMENT_DISABLED_NAME";

		public const string equipmentDisabledDescriptionToken = "EQUIPMENT_DISABLED_DESC";

		public static Texture equipmentDisabledSprite;

		private DisplayData currentDisplayData;

		private MPEventSystemLocator eventSystemLocator;

		private InspectPanelLocator inspectPanelLocator;

		private UserProfile userProfile;

		public bool hasEquipment => currentDisplayData.hasEquipment;

		public MPEventSystem eventSystem => eventSystemLocator.eventSystem;

		public InspectPanelController inspectPanel
		{
			get
			{
				if ((bool)inspectPanelLocator)
				{
					return inspectPanelLocator.InspectPanel;
				}
				return null;
			}
		}

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			NavButtonToEnable = GetComponent<HGButton>();
			inspectPanelLocator = GetComponent<InspectPanelLocator>();
			userProfile = GetComponentInParent<HUD>().localUserViewer.userProfile;
		}

		private void SetDisplayData(DisplayData newDisplayData)
		{
			if (!currentDisplayData.isReady && newDisplayData.isReady)
			{
				DoStockFlash();
			}
			if ((bool)displayRoot)
			{
				displayRoot.SetActive(!newDisplayData.hideEntireDisplay);
			}
			if (newDisplayData.stock > currentDisplayData.stock)
			{
				Util.PlaySound("Play_item_proc_equipMag", RoR2Application.instance.gameObject);
				DoStockFlash();
			}
			if ((bool)isReadyPanelObject)
			{
				isReadyPanelObject.SetActive(newDisplayData.isReady);
			}
			if ((bool)isAutoCastPanelObject)
			{
				if ((bool)targetInventory)
				{
					isAutoCastPanelObject.SetActive(targetInventory.GetItemCount(RoR2Content.Items.AutoCastEquipment) > 0);
				}
				else
				{
					isAutoCastPanelObject.SetActive(value: false);
				}
			}
			if ((bool)iconImage)
			{
				Texture texture = null;
				UnityEngine.Color color = UnityEngine.Color.clear;
				if ((object)newDisplayData.equipmentDef != null)
				{
					if (newDisplayData.equipmentDisabled)
					{
						color = UnityEngine.Color.gray;
						texture = equipmentDisabledSprite;
					}
					else
					{
						color = ((newDisplayData.stock > 0) ? UnityEngine.Color.white : UnityEngine.Color.gray);
						texture = newDisplayData.equipmentDef.pickupIconTexture;
					}
				}
				iconImage.texture = texture;
				iconImage.color = color;
			}
			if ((bool)cooldownText)
			{
				if (newDisplayData.equipmentDisabled)
				{
					cooldownText.gameObject.SetActive(value: false);
				}
				else
				{
					cooldownText.gameObject.SetActive(newDisplayData.showCooldown);
					if (newDisplayData.cooldownValue != currentDisplayData.cooldownValue)
					{
						StringBuilder stringBuilder = HG.StringBuilderPool.RentStringBuilder();
						stringBuilder.AppendInt(newDisplayData.cooldownValue);
						cooldownText.SetText(stringBuilder);
						HG.StringBuilderPool.ReturnStringBuilder(stringBuilder);
					}
				}
			}
			if ((bool)stockText)
			{
				if (newDisplayData.hasEquipment && !newDisplayData.equipmentDisabled && (newDisplayData.maxStock > 1 || newDisplayData.stock > 1))
				{
					stockText.gameObject.SetActive(value: true);
					StringBuilder stringBuilder2 = HG.StringBuilderPool.RentStringBuilder();
					stringBuilder2.AppendInt(newDisplayData.stock);
					stockText.SetText(stringBuilder2);
					HG.StringBuilderPool.ReturnStringBuilder(stringBuilder2);
				}
				else
				{
					stockText.gameObject.SetActive(value: false);
				}
			}
			string titleToken = null;
			string bodyToken = null;
			UnityEngine.Color titleColor = UnityEngine.Color.white;
			UnityEngine.Color gray = UnityEngine.Color.gray;
			if (newDisplayData.equipmentDef != null)
			{
				if (newDisplayData.equipmentDisabled)
				{
					titleToken = "EQUIPMENT_DISABLED_NAME";
					bodyToken = "EQUIPMENT_DISABLED_DESC";
					titleColor = ColorCatalog.GetColor(newDisplayData.equipmentDef.colorIndex);
				}
				else
				{
					titleToken = newDisplayData.equipmentDef.nameToken;
					bodyToken = newDisplayData.equipmentDef.pickupToken;
					titleColor = ColorCatalog.GetColor(newDisplayData.equipmentDef.colorIndex);
				}
			}
			if ((bool)tooltipProvider)
			{
				tooltipProvider.titleToken = titleToken;
				tooltipProvider.titleColor = titleColor;
				tooltipProvider.bodyToken = bodyToken;
				tooltipProvider.bodyColor = gray;
			}
			if ((bool)NavButtonToEnable && newDisplayData.hasEquipment)
			{
				NavButtonToEnable.enabled = true;
			}
			currentDisplayData = newDisplayData;
		}

		private void DoReminderFlash()
		{
			if ((bool)reminderFlashPanelObject)
			{
				AnimateUIAlpha component = reminderFlashPanelObject.GetComponent<AnimateUIAlpha>();
				if ((bool)component)
				{
					component.time = 0f;
				}
				reminderFlashPanelObject.SetActive(value: true);
			}
			equipmentReminderTimer = 5f;
		}

		private void DoStockFlash()
		{
			DoReminderFlash();
			if ((bool)stockFlashPanelObject)
			{
				AnimateUIAlpha component = stockFlashPanelObject.GetComponent<AnimateUIAlpha>();
				if ((bool)component)
				{
					component.time = 0f;
				}
				stockFlashPanelObject.SetActive(value: true);
			}
		}

		private DisplayData GenerateDisplayData()
		{
			DisplayData result = default(DisplayData);
			EquipmentIndex equipmentIndex = EquipmentIndex.None;
			if ((bool)targetInventory)
			{
				EquipmentState equipmentState;
				if (displayAlternateEquipment)
				{
					equipmentState = targetInventory.alternateEquipmentState;
					result.hideEntireDisplay = targetInventory.GetEquipmentSlotCount() <= 1;
				}
				else
				{
					equipmentState = targetInventory.currentEquipmentState;
					result.hideEntireDisplay = false;
				}
				result.equipmentDisabled = targetInventory.GetEquipmentDisabled();
				_ = Run.FixedTimeStamp.now;
				Run.FixedTimeStamp chargeFinishTime = equipmentState.chargeFinishTime;
				equipmentIndex = equipmentState.equipmentIndex;
				result.cooldownValue = ((!chargeFinishTime.isInfinity) ? Mathf.CeilToInt(chargeFinishTime.timeUntilClamped) : 0);
				result.stock = equipmentState.charges;
				result.maxStock = ((!targetEquipmentSlot) ? 1 : targetEquipmentSlot.maxStock);
			}
			else if (displayAlternateEquipment)
			{
				result.hideEntireDisplay = true;
			}
			result.equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
			return result;
		}

		private void Start()
		{
			if (equipmentDisabledSprite == null)
			{
				HandleDisabledSpriteReference();
			}
		}

		private void HandleDisabledSpriteReference()
		{
			equipmentDisabledSprite = LegacyResourcesAPI.Load<Texture>("UI/texDisabledIcon");
		}

		private void Update()
		{
			SetDisplayData(GenerateDisplayData());
			equipmentReminderTimer -= Time.deltaTime;
			if (currentDisplayData.isReady && equipmentReminderTimer < 0f && currentDisplayData.equipmentDef != null)
			{
				DoReminderFlash();
			}
		}

		public bool TrySelect()
		{
			if (currentDisplayData.hasEquipment)
			{
				eventSystem.SetSelectedObject(base.gameObject);
				ItemClicked();
				return true;
			}
			return false;
		}

		public void ItemClicked()
		{
			if (userProfile.useInspectFeature && currentDisplayData.hasEquipment)
			{
				inspectPanel?.Show(currentDisplayData.equipmentDef);
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class ExpBar : MonoBehaviour
	{
		public CharacterMaster source;

		public RectTransform fillRectTransform;

		private RectTransform rectTransform;

		private void Awake()
		{
			rectTransform = GetComponent<RectTransform>();
		}

		public void Update()
		{
			TeamIndex teamIndex = (source ? source.teamIndex : TeamIndex.Neutral);
			float x = 0f;
			if ((bool)source && (bool)TeamManager.instance)
			{
				x = Mathf.InverseLerp(TeamManager.instance.GetTeamCurrentLevelExperience(teamIndex), TeamManager.instance.GetTeamNextLevelExperience(teamIndex), TeamManager.instance.GetTeamExperience(teamIndex));
			}
			if ((bool)fillRectTransform)
			{
				_ = rectTransform.rect;
				_ = fillRectTransform.rect;
				fillRectTransform.anchorMin = new UnityEngine.Vector2(0f, 0f);
				fillRectTransform.anchorMax = new UnityEngine.Vector2(x, 1f);
				fillRectTransform.sizeDelta = new UnityEngine.Vector2(1f, 1f);
			}
		}
	}
	public class FlashPanel : MonoBehaviour
	{
		public RectTransform flashRectTransform;

		public float strength = 1f;

		public float freq = 1f;

		public float flashAlpha = 0.7f;

		public bool alwaysFlash = true;

		private bool isFlashing;

		private float theta = 1f;

		private UnityEngine.UI.Image image;

		private void Start()
		{
			image = flashRectTransform.GetComponent<UnityEngine.UI.Image>();
		}

		private void Update()
		{
			flashRectTransform.anchorMin = new UnityEngine.Vector2(0f, 0f);
			flashRectTransform.anchorMax = new UnityEngine.Vector2(1f, 1f);
			if (alwaysFlash)
			{
				isFlashing = true;
			}
			if (isFlashing)
			{
				theta += Time.deltaTime * freq;
			}
			if (theta > 1f)
			{
				if (alwaysFlash)
				{
					theta -= theta - theta % 1f;
				}
				else
				{
					theta = 1f;
				}
				isFlashing = false;
			}
			float num = 1f - (1f + Mathf.Cos(theta * MathF.PI * 0.5f + MathF.PI / 2f));
			flashRectTransform.sizeDelta = new UnityEngine.Vector2(1f + num * 20f * strength, 1f + num * 20f * strength);
			if ((bool)image)
			{
				UnityEngine.Color color = image.color;
				color.a = (1f - num) * strength * flashAlpha;
				image.color = color;
			}
		}

		public void Flash()
		{
			theta = 0f;
			isFlashing = true;
		}
	}
	[RequireComponent(typeof(MPEventSystemProvider))]
	public class GameEndReportPanelController : MonoBehaviour
	{
		public struct DisplayData : IEquatable<DisplayData>
		{
			[CanBeNull]
			public RunReport runReport;

			public int playerIndex;

			public bool Equals(DisplayData other)
			{
				if (object.Equals(runReport, other.runReport))
				{
					return playerIndex == other.playerIndex;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is DisplayData other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return ((-1418150836 * -1521134295 + base.GetHashCode()) * -1521134295 + EqualityComparer<RunReport>.Default.GetHashCode(runReport)) * -1521134295 + playerIndex.GetHashCode();
			}
		}

		[Header("Result")]
		[Tooltip("The TextMeshProUGUI component to use to display the result of the game: Win or Loss")]
		public TextMeshProUGUI resultLabel;

		public UnityEngine.UI.Image resultIconBackgroundImage;

		public UnityEngine.UI.Image resultIconForegroundImage;

		public HGTextMeshProUGUI finalMessageLabel;

		[Tooltip("The Image component to use to display the selected difficulty of the run.")]
		[Header("Run Settings")]
		public UnityEngine.UI.Image selectedDifficultyImage;

		[Tooltip("The LanguageTextMeshController component to use to display the selected difficulty of the run.")]
		public LanguageTextMeshController selectedDifficultyLabel;

		[Tooltip("The ArtifactDisplayPanelController component to send the enabled artifacts of the run to.")]
		public ArtifactDisplayPanelController artifactDisplayPanelController;

		[Tooltip("A list of StatDef names to display in the stats section.")]
		[Header("Stats")]
		public string[] statsToDisplay;

		[Tooltip("Prefab to be used for stat display.")]
		public GameObject statStripPrefab;

		[Tooltip("The RectTransform in which to build the stat strips.")]
		public RectTransform statContentArea;

		[Tooltip("The TextMeshProUGUI component used to display the total points.")]
		public TextMeshProUGUI totalPointsLabel;

		[Tooltip("Prefab to be used for unlock display.")]
		[Header("Unlocks")]
		public GameObject unlockStripPrefab;

		[Tooltip("The RectTransform in which to build the unlock strips.")]
		public RectTransform unlockContentArea;

		[Header("Items")]
		[Tooltip("The inventory display controller.")]
		public ItemInventoryDisplay itemInventoryDisplay;

		[Tooltip("The RawImage component to use to display the player character's portrait.")]
		[Header("Player Info")]
		public RawImage playerBodyPortraitImage;

		[Tooltip("The TextMeshProUGUI component to use to display the player character's body name.")]
		public TextMeshProUGUI playerBodyLabel;

		[Tooltip("The TextMeshProUGUI component to use to display the player's username.")]
		public TextMeshProUGUI playerUsernameLabel;

		[Tooltip("The RawImage component to use to display the killer character's portrait.")]
		[Header("Killer Info")]
		public RawImage killerBodyPortraitImage;

		[Tooltip("The TextMeshProUGUI component to use to display the killer character's body name.")]
		public TextMeshProUGUI killerBodyLabel;

		[Tooltip("The GameObject used as the panel for the killer information. This is used to disable the killer panel when the player has won the game.")]
		public GameObject killerPanelObject;

		[Header("Navigation and Misc")]
		public MPButton continueButton;

		public RectTransform chatboxTransform;

		public CarouselNavigationController playerNavigationController;

		public RectTransform selectedPlayerEffectRoot;

		public RectTransform acceptButtonArea;

		private readonly List<GameObject> statStrips = new List<GameObject>();

		private readonly List<GameObject> unlockStrips = new List<GameObject>();

		public DisplayData displayData { get; private set; }

		private void Awake()
		{
			playerNavigationController.onPageChangeSubmitted += OnPlayerNavigationControllerPageChangeSubmitted;
			SetContinueButtonAction(null);
		}

		private void AllocateStatStrips(int count)
		{
			while (statStrips.Count > count)
			{
				int index = statStrips.Count - 1;
				UnityEngine.Object.Destroy(statStrips[index].gameObject);
				statStrips.RemoveAt(index);
			}
			while (statStrips.Count < count)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(statStripPrefab, statContentArea);
				gameObject.SetActive(value: true);
				statStrips.Add(gameObject);
			}
		}

		private void AllocateUnlockStrips(int count)
		{
			while (unlockStrips.Count > count)
			{
				int index = unlockStrips.Count - 1;
				UnityEngine.Object.Destroy(unlockStrips[index].gameObject);
				unlockStrips.RemoveAt(index);
			}
			while (unlockStrips.Count < count)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(unlockStripPrefab, unlockContentArea);
				gameObject.SetActive(value: true);
				unlockStrips.Add(gameObject);
			}
		}

		public void SetDisplayData(DisplayData newDisplayData)
		{
			if (displayData.Equals(newDisplayData))
			{
				return;
			}
			displayData = newDisplayData;
			bool flag = (bool)Run.instance && displayData.runReport != null && Run.instance.GetUniqueId() == displayData.runReport.runGuid;
			if ((bool)resultLabel && (bool)resultIconBackgroundImage && (bool)resultIconForegroundImage)
			{
				GameEndingDef gameEndingDef = null;
				if (displayData.runReport != null)
				{
					gameEndingDef = displayData.runReport.gameEnding;
				}
				resultLabel.gameObject.SetActive(gameEndingDef);
				resultIconBackgroundImage.gameObject.SetActive(gameEndingDef);
				resultIconForegroundImage.gameObject.SetActive(gameEndingDef);
				if ((bool)gameEndingDef)
				{
					resultLabel.text = Language.GetString(gameEndingDef.endingTextToken);
					resultIconBackgroundImage.color = gameEndingDef.backgroundColor;
					resultIconForegroundImage.color = gameEndingDef.foregroundColor;
					resultIconForegroundImage.sprite = gameEndingDef.icon;
					resultIconBackgroundImage.material = gameEndingDef.material;
				}
			}
			DifficultyIndex difficultyIndex = DifficultyIndex.Invalid;
			if (displayData.runReport != null)
			{
				difficultyIndex = displayData.runReport.ruleBook.FindDifficulty();
			}
			DifficultyDef difficultyDef = DifficultyCatalog.GetDifficultyDef(difficultyIndex);
			if ((bool)selectedDifficultyImage)
			{
				selectedDifficultyImage.sprite = difficultyDef?.GetIconSprite();
			}
			if ((bool)selectedDifficultyLabel)
			{
				selectedDifficultyLabel.token = difficultyDef?.nameToken;
			}
			if ((bool)artifactDisplayPanelController)
			{
				RuleBook ruleBook = displayData.runReport.ruleBook;
				List<ArtifactDef> list = new List<ArtifactDef>(ArtifactCatalog.artifactCount);
				for (int i = 0; i < RuleCatalog.choiceCount; i++)
				{
					RuleChoiceDef choiceDef = RuleCatalog.GetChoiceDef(i);
					if (choiceDef.artifactIndex != ArtifactIndex.None && ruleBook.GetRuleChoice(choiceDef.ruleDef) == choiceDef)
					{
						list.Add(ArtifactCatalog.GetArtifactDef(choiceDef.artifactIndex));
					}
				}
				List<ArtifactDef>.Enumerator enabledArtifacts = list.GetEnumerator();
				artifactDisplayPanelController.SetDisplayData(ref enabledArtifacts);
			}
			RunReport.PlayerInfo playerInfo = displayData.runReport?.GetPlayerInfoSafe(displayData.playerIndex);
			SetPlayerInfo(playerInfo, displayData.playerIndex);
			int pageCount = displayData.runReport?.playerInfoCount ?? 0;
			playerNavigationController.gameObject.SetActive((displayData.runReport?.playerInfoCount ?? 0) > 1);
			if ((bool)chatboxTransform)
			{
				chatboxTransform.gameObject.SetActive(!RoR2Application.isInSinglePlayer && flag);
			}
			playerNavigationController.SetDisplayData(new CarouselNavigationController.DisplayData(pageCount, displayData.playerIndex));
			ReadOnlyCollection<MPButton> elements = playerNavigationController.buttonAllocator.elements;
			for (int j = 0; j < elements.Count; j++)
			{
				MPButton mPButton = elements[j];
				RunReport.PlayerInfo playerInfo2 = displayData.runReport.GetPlayerInfo(j);
				CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(playerInfo2.bodyIndex);
				Texture texture = (bodyPrefabBodyComponent ? bodyPrefabBodyComponent.portraitIcon : null);
				mPButton.GetComponentInChildren<RawImage>().texture = texture;
				mPButton.GetComponent<TooltipProvider>().SetContent(TooltipProvider.GetPlayerNameTooltipContent(playerInfo2.name));
			}
			selectedPlayerEffectRoot.transform.SetParent(playerNavigationController.buttonAllocator.elements[displayData.playerIndex].transform);
			selectedPlayerEffectRoot.gameObject.SetActive(value: false);
			selectedPlayerEffectRoot.gameObject.SetActive(value: true);
			selectedPlayerEffectRoot.offsetMin = UnityEngine.Vector2.zero;
			selectedPlayerEffectRoot.offsetMax = UnityEngine.Vector2.zero;
			selectedPlayerEffectRoot.localScale = UnityEngine.Vector3.one;
		}

		public void SetContinueButtonAction(UnityAction action)
		{
			continueButton.onClick.RemoveAllListeners();
			if (action != null)
			{
				continueButton.onClick.AddListener(action);
			}
			acceptButtonArea.gameObject.SetActive(action != null);
		}

		private void OnPlayerNavigationControllerPageChangeSubmitted(int newPage)
		{
			DisplayData displayData = this.displayData;
			displayData.playerIndex = newPage;
			SetDisplayData(displayData);
		}

		private void SetPlayerInfo([CanBeNull] RunReport.PlayerInfo playerInfo, int playerIndex)
		{
			ulong num = 0uL;
			if (playerInfo != null && playerInfo.statSheet != null)
			{
				StatSheet statSheet = playerInfo.statSheet;
				AllocateStatStrips(statsToDisplay.Length);
				for (int i = 0; i < statsToDisplay.Length; i++)
				{
					string text = statsToDisplay[i];
					StatDef statDef = StatDef.Find(text);
					if (statDef == null)
					{
						UnityEngine.Debug.LogWarningFormat("GameEndReportPanelController.SetStatSheet: Could not find stat def \"{0}\".", text);
					}
					else
					{
						AssignStatToStrip(statSheet, statDef, statStrips[i]);
						num += statSheet.GetStatPointValue(statDef);
					}
				}
				int unlockableCount = statSheet.GetUnlockableCount();
				int num2 = 0;
				for (int j = 0; j < unlockableCount; j++)
				{
					UnlockableDef unlockable = statSheet.GetUnlockable(j);
					if (unlockable != null && !unlockable.hidden)
					{
						num2++;
					}
				}
				AllocateUnlockStrips(num2);
				int num3 = 0;
				for (int k = 0; k < unlockableCount; k++)
				{
					UnlockableDef unlockable2 = statSheet.GetUnlockable(k);
					if (unlockable2 != null && !unlockable2.hidden)
					{
						AssignUnlockToStrip(unlockable2, unlockStrips[num3]);
						num3++;
					}
				}
				if ((bool)itemInventoryDisplay && playerInfo.itemAcquisitionOrder != null)
				{
					itemInventoryDisplay.SetItems(playerInfo.itemAcquisitionOrder, playerInfo.itemAcquisitionOrder.Length, playerInfo.itemStacks);
					itemInventoryDisplay.UpdateDisplay();
				}
				string token = playerInfo.finalMessageToken + "_2P";
				if (Language.IsTokenInvalid(token))
				{
					token = playerInfo.finalMessageToken;
				}
				finalMessageLabel.SetText(Language.GetStringFormatted(token, playerInfo.name));
			}
			else
			{
				AllocateStatStrips(0);
				AllocateUnlockStrips(0);
				if ((bool)itemInventoryDisplay)
				{
					itemInventoryDisplay.ResetItems();
				}
				finalMessageLabel.SetText(string.Empty);
			}
			string @string = Language.GetString("STAT_POINTS_FORMAT");
			totalPointsLabel.text = string.Format(@string, TextSerialization.ToStringNumeric(num));
			GameObject gameObject = null;
			if (playerInfo != null)
			{
				gameObject = BodyCatalog.GetBodyPrefab(playerInfo.bodyIndex);
			}
			string text2 = "";
			Texture texture = null;
			if ((bool)gameObject)
			{
				texture = gameObject.GetComponent<CharacterBody>().portraitIcon;
				text2 = Language.GetString(gameObject.GetComponent<CharacterBody>().baseNameToken);
				if (playerIndex == 0)
				{
					if (PlatformSystems.userManager.ShouldAlwaysUseCurrentDisplayName())
					{
						playerUsernameLabel.text = PlatformSystems.userManager.GetUserName();
					}
					else
					{
						playerUsernameLabel.text = playerInfo.name;
					}
				}
				else if (PlatformSystems.userManager.ShouldHideOtherDisplayNames())
				{
					playerUsernameLabel.text = text2;
				}
				else
				{
					playerUsernameLabel.text = playerInfo.name;
				}
			}
			string string2 = Language.GetString("STAT_CLASS_NAME_FORMAT");
			playerBodyLabel.text = string.Format(string2, text2);
			playerBodyPortraitImage.texture = texture;
			GameObject gameObject2 = null;
			if (playerInfo != null)
			{
				gameObject2 = BodyCatalog.GetBodyPrefab(playerInfo.killerBodyIndex);
				killerPanelObject?.SetActive(playerInfo.isDead);
			}
			string string3 = Language.GetString("UNIDENTIFIED_KILLER_NAME");
			Texture texture2 = LegacyResourcesAPI.Load<Texture>("Textures/BodyIcons/texUnidentifiedKillerIcon");
			if ((bool)gameObject2)
			{
				Texture portraitIcon = gameObject2.GetComponent<CharacterBody>().portraitIcon;
				string baseNameToken = gameObject2.GetComponent<CharacterBody>().baseNameToken;
				if (portraitIcon != null)
				{
					texture2 = portraitIcon;
				}
				if (!Language.IsTokenInvalid(baseNameToken))
				{
					string3 = Language.GetString(gameObject2.GetComponent<CharacterBody>().baseNameToken);
				}
			}
			string string4 = Language.GetString("STAT_KILLER_NAME_FORMAT");
			killerBodyLabel.text = string.Format(string4, string3);
			killerBodyPortraitImage.texture = texture2;
		}

		private void AssignStatToStrip([CanBeNull] StatSheet srcStatSheet, [NotNull] StatDef statDef, GameObject destStatStrip)
		{
			string arg = "0";
			ulong value = 0uL;
			if (srcStatSheet != null)
			{
				arg = srcStatSheet.GetStatDisplayValue(statDef);
				value = srcStatSheet.GetStatPointValue(statDef);
			}
			string @string = Language.GetString(statDef.displayToken);
			string text = string.Format(Language.GetString("STAT_NAME_VALUE_FORMAT"), @string, arg);
			destStatStrip.transform.Find("StatNameLabel").GetComponent<TextMeshProUGUI>().text = text;
			string string2 = Language.GetString("STAT_POINTS_FORMAT");
			destStatStrip.transform.Find("PointValueLabel").GetComponent<TextMeshProUGUI>().text = string.Format(string2, TextSerialization.ToStringNumeric(value));
		}

		private void AssignUnlockToStrip(UnlockableDef unlockableDef, GameObject destUnlockableStrip)
		{
			AchievementDef achievementDefFromUnlockable = AchievementManager.GetAchievementDefFromUnlockable(unlockableDef.cachedName);
			Texture texture = null;
			string @string = Language.GetString("TOOLTIP_UNLOCK_GENERIC_NAME");
			string string2 = Language.GetString("TOOLTIP_UNLOCK_GENERIC_DESCRIPTION");
			if (unlockableDef.cachedName.Contains("Items."))
			{
				@string = Language.GetString("TOOLTIP_UNLOCK_ITEM_NAME");
				string2 = Language.GetString("TOOLTIP_UNLOCK_ITEM_DESCRIPTION");
			}
			else if (unlockableDef.cachedName.Contains("Logs."))
			{
				@string = Language.GetString("TOOLTIP_UNLOCK_LOG_NAME");
				string2 = Language.GetString("TOOLTIP_UNLOCK_LOG_DESCRIPTION");
			}
			else if (unlockableDef.cachedName.Contains("Characters."))
			{
				@string = Language.GetString("TOOLTIP_UNLOCK_SURVIVOR_NAME");
				string2 = Language.GetString("TOOLTIP_UNLOCK_SURVIVOR_DESCRIPTION");
			}
			else if (unlockableDef.cachedName.Contains("Artifacts."))
			{
				@string = Language.GetString("TOOLTIP_UNLOCK_ARTIFACT_NAME");
				string2 = Language.GetString("TOOLTIP_UNLOCK_ARTIFACT_DESCRIPTION");
			}
			string string3;
			if (achievementDefFromUnlockable != null)
			{
				texture = achievementDefFromUnlockable.GetAchievedIcon().texture;
				string3 = Language.GetString(achievementDefFromUnlockable.nameToken);
			}
			else
			{
				string3 = Language.GetString(unlockableDef.nameToken);
			}
			if (texture != null)
			{
				destUnlockableStrip.transform.Find("IconImage").GetComponent<RawImage>().texture = texture;
			}
			destUnlockableStrip.transform.Find("NameLabel").GetComponent<TextMeshProUGUI>().text = string3;
			destUnlockableStrip.GetComponent<TooltipProvider>().overrideTitleText = @string;
			destUnlockableStrip.GetComponent<TooltipProvider>().overrideBodyText = string2;
		}
	}
	public class GenericNotification : MonoBehaviour
	{
		public LanguageTextMeshController titleText;

		public TextMeshProUGUI titleTMP;

		public LanguageTextMeshController descriptionText;

		public RawImage iconImage;

		public RawImage previousIconImage;

		public CanvasGroup canvasGroup;

		public float fadeOutT = 0.916f;

		public void SetNotificationT(float t)
		{
			canvasGroup.alpha = 1f - Mathf.Clamp01(t - fadeOutT) / (1f - fadeOutT);
		}

		public void SetItem(ItemDef itemDef)
		{
			titleText.token = itemDef.nameToken;
			descriptionText.token = itemDef.pickupToken;
			if (itemDef.pickupIconTexture != null)
			{
				iconImage.texture = itemDef.pickupIconTexture;
			}
			titleTMP.color = ColorCatalog.GetColor(itemDef.colorIndex);
		}

		public void SetEquipment(EquipmentDef equipmentDef)
		{
			titleText.token = equipmentDef.nameToken;
			descriptionText.token = equipmentDef.pickupToken;
			if ((bool)equipmentDef.pickupIconTexture)
			{
				iconImage.texture = equipmentDef.pickupIconTexture;
			}
			titleTMP.color = ColorCatalog.GetColor(equipmentDef.colorIndex);
		}

		public void SetArtifact(ArtifactDef artifactDef)
		{
			titleText.token = artifactDef.nameToken;
			descriptionText.token = artifactDef.descriptionToken;
			iconImage.texture = artifactDef.smallIconSelectedSprite.texture;
			titleTMP.color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Artifact);
		}

		public void SetPreviousItem(ItemDef itemDef)
		{
			if ((bool)previousIconImage && (bool)itemDef.pickupIconTexture)
			{
				previousIconImage.texture = itemDef.pickupIconTexture;
			}
		}

		public void SetPreviousEquipment(EquipmentDef equipmentDef)
		{
			if ((bool)previousIconImage && (bool)equipmentDef.pickupIconTexture)
			{
				previousIconImage.texture = equipmentDef.pickupIconTexture;
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	[RequireComponent(typeof(Canvas))]
	public class HealthBar : MonoBehaviour
	{
		public struct BarInfo
		{
			public bool enabled;

			public UnityEngine.Color color;

			public Sprite sprite;

			public UnityEngine.UI.Image.Type imageType;

			public int index;

			public float normalizedXMin;

			public float normalizedXMax;

			public float sizeDelta;

			public bool DimsEqual(BarInfo rhs)
			{
				if (normalizedXMin == rhs.normalizedXMin && normalizedXMax == rhs.normalizedXMax)
				{
					return sizeDelta == rhs.sizeDelta;
				}
				return false;
			}

			public void SetDims(BarInfo rhs)
			{
				normalizedXMin = rhs.normalizedXMin;
				normalizedXMax = rhs.normalizedXMax;
				sizeDelta = rhs.sizeDelta;
			}
		}

		private struct BarInfoCollection
		{
			public BarInfo trailingUnderHealthbarInfo;

			public BarInfo instantHealthbarInfo;

			public BarInfo trailingOverHealthbarInfo;

			public BarInfo shieldBarInfo;

			public BarInfo curseBarInfo;

			public BarInfo barrierBarInfo;

			public BarInfo cullBarInfo;

			public BarInfo flashBarInfo;

			public BarInfo magneticBarInfo;

			public BarInfo ospBarInfo;

			public BarInfo lowHealthOverBarInfo;

			public BarInfo lowHealthUnderBarInfo;

			public void Init()
			{
				trailingUnderHealthbarInfo.index = -1;
				instantHealthbarInfo.index = -1;
				trailingOverHealthbarInfo.index = -1;
				shieldBarInfo.index = -1;
				curseBarInfo.index = -1;
				barrierBarInfo.index = -1;
				cullBarInfo.index = -1;
				flashBarInfo.index = -1;
				magneticBarInfo.index = -1;
				ospBarInfo.index = -1;
				lowHealthOverBarInfo.index = -1;
				lowHealthUnderBarInfo.index = -1;
			}

			public int GetActiveCount()
			{
				int count = 0;
				Check(ref lowHealthUnderBarInfo);
				Check(ref trailingUnderHealthbarInfo);
				Check(ref instantHealthbarInfo);
				Check(ref trailingOverHealthbarInfo);
				Check(ref shieldBarInfo);
				Check(ref curseBarInfo);
				Check(ref barrierBarInfo);
				Check(ref flashBarInfo);
				Check(ref cullBarInfo);
				Check(ref magneticBarInfo);
				Check(ref ospBarInfo);
				Check(ref lowHealthOverBarInfo);
				return count;
				void Check(ref BarInfo field)
				{
					count += (field.enabled ? 1 : 0);
				}
			}
		}

		private HealthComponent _source;

		private HealthComponent oldSource;

		public Material baseSubBarMat;

		public HealthBarStyle style;

		[Tooltip("The container rect for the actual bars.")]
		public RectTransform barContainer;

		public RectTransform eliteBackdropRectTransform;

		public UnityEngine.UI.Image criticallyHurtImage;

		public UnityEngine.UI.Image deadImage;

		public float maxLastHitTimer = 1f;

		public bool scaleHealthbarWidth;

		public float minHealthbarWidth;

		public float maxHealthbarWidth;

		public float minHealthbarHealth;

		public float maxHealthbarHealth;

		private float displayStringCurrentHealth;

		private float displayStringFullHealth;

		private RectTransform rectTransform;

		private float cachedFractionalValue = 1f;

		private float healthFractionVelocity;

		private bool healthCritical;

		private bool isInventoryCheckDirty = true;

		private bool hasLowHealthItem;

		private bool hasLowHealthBuff;

		public float updateDelay = 0.1f;

		private float updateTimer;

		[NonSerialized]
		public CharacterBody viewerBody;

		private static readonly UnityEngine.Color infusionPanelColor = new Color32(231, 84, 58, byte.MaxValue);

		private static readonly UnityEngine.Color voidPanelColor = new Color32(217, 123, byte.MaxValue, byte.MaxValue);

		private static readonly UnityEngine.Color voidShieldsColor = new Color32(byte.MaxValue, 57, 199, byte.MaxValue);

		private float theta;

		private UIElementPairAllocator<UnityEngine.UI.Image, BarInfo> barAllocator;

		private BarInfoCollection barInfoCollection;

		private float oldHealth;

		private float oldFullHealth;

		private bool oldHealthCritical;

		private bool oldAlive = true;

		public TextMeshProUGUI currentHealthText;

		public TextMeshProUGUI fullHealthText;

		public SpriteAsNumberManager spriteAsNumberManager;

		public HealthComponent source
		{
			get
			{
				return _source;
			}
			set
			{
				if (_source != value)
				{
					RemoveInventoryChangedHandler();
					_source = value;
					healthFractionVelocity = 0f;
					cachedFractionalValue = (_source ? (_source.health / _source.fullCombinedHealth) : 0f);
					AddInventoryChangedHandler();
					isInventoryCheckDirty = true;
				}
			}
		}

		private void Awake()
		{
			updateDelay = 0f;
			rectTransform = (RectTransform)base.transform;
			barAllocator = new UIElementPairAllocator<UnityEngine.UI.Image, BarInfo>(barContainer, style.barPrefab);
		}

		private void Start()
		{
			barInfoCollection.Init();
			UpdateHealthbar(0f);
		}

		public void Update()
		{
			updateTimer -= Time.deltaTime;
			if (_source != oldSource)
			{
				updateTimer = 0f;
				oldSource = _source;
			}
			if (updateTimer <= 0f)
			{
				UpdateHealthbar(updateDelay - updateTimer);
				updateTimer = updateDelay;
			}
		}

		private void OnEnable()
		{
			AddInventoryChangedHandler();
			isInventoryCheckDirty = true;
		}

		private void OnDisable()
		{
			RemoveInventoryChangedHandler();
		}

		private void SetRectPosition(RectTransform rectTransform, float xMin, float xMax, float sizeDelta)
		{
			rectTransform.anchorMin = new UnityEngine.Vector2(xMin, 0f);
			rectTransform.anchorMax = new UnityEngine.Vector2(xMax, 1f);
			rectTransform.anchoredPosition = UnityEngine.Vector2.zero;
			rectTransform.sizeDelta = new UnityEngine.Vector2(sizeDelta * 0.5f + 1f, sizeDelta + 1f);
		}

		public void UpdateBarRects()
		{
			int i = 0;
			barAllocator.AllocateElements(barInfoCollection.GetActiveCount());
			HandleBar(ref barInfoCollection.lowHealthUnderBarInfo);
			HandleBar(ref barInfoCollection.trailingUnderHealthbarInfo);
			HandleBar(ref barInfoCollection.instantHealthbarInfo);
			HandleBar(ref barInfoCollection.trailingOverHealthbarInfo);
			HandleBar(ref barInfoCollection.shieldBarInfo);
			HandleBar(ref barInfoCollection.curseBarInfo);
			HandleBar(ref barInfoCollection.barrierBarInfo);
			HandleBar(ref barInfoCollection.flashBarInfo);
			HandleBar(ref barInfoCollection.cullBarInfo);
			HandleBar(ref barInfoCollection.magneticBarInfo);
			HandleBar(ref barInfoCollection.ospBarInfo);
			HandleBar(ref barInfoCollection.lowHealthOverBarInfo);
			void HandleBar(ref BarInfo barInfo)
			{
				if (barInfo.enabled)
				{
					barInfo.index = i;
					UnityEngine.UI.Image image = barAllocator.elements[i];
					BarInfo barInfo2 = barAllocator.elementsData[i];
					if (!barInfo2.DimsEqual(barInfo))
					{
						barInfo2.SetDims(barInfo);
						SetRectPosition((RectTransform)image.transform, barInfo.normalizedXMin, barInfo.normalizedXMax, barInfo.sizeDelta);
					}
					int num = i + 1;
					i = num;
				}
			}
		}

		private void ApplyBars()
		{
			int i = 0;
			barAllocator.AllocateElements(barInfoCollection.GetActiveCount());
			HandleBar(ref barInfoCollection.lowHealthUnderBarInfo);
			HandleBar(ref barInfoCollection.trailingUnderHealthbarInfo);
			HandleBar(ref barInfoCollection.instantHealthbarInfo);
			HandleBar(ref barInfoCollection.trailingOverHealthbarInfo);
			HandleBar(ref barInfoCollection.shieldBarInfo);
			HandleBar(ref barInfoCollection.curseBarInfo);
			HandleBar(ref barInfoCollection.barrierBarInfo);
			HandleBar(ref barInfoCollection.flashBarInfo);
			HandleBar(ref barInfoCollection.cullBarInfo);
			HandleBar(ref barInfoCollection.magneticBarInfo);
			HandleBar(ref barInfoCollection.ospBarInfo);
			HandleBar(ref barInfoCollection.lowHealthOverBarInfo);
			void HandleBar(ref BarInfo barInfo)
			{
				if (barInfo.enabled)
				{
					UnityEngine.UI.Image image = barAllocator.elements[i];
					BarInfo val = barAllocator.elementsData[i];
					if (!val.DimsEqual(barInfo))
					{
						val.SetDims(barInfo);
						SetRectPosition((RectTransform)image.transform, barInfo.normalizedXMin, barInfo.normalizedXMax, barInfo.sizeDelta);
					}
					if (barInfo.imageType != val.imageType)
					{
						val.imageType = barInfo.imageType;
						image.type = barInfo.imageType;
					}
					if (barInfo.sprite != val.sprite)
					{
						val.sprite = barInfo.sprite;
						image.sprite = barInfo.sprite;
					}
					if (barInfo.color != image.color)
					{
						val.color = barInfo.color;
						image.color = barInfo.color;
					}
					if (barInfo.normalizedXMin != val.normalizedXMin)
					{
						val.normalizedXMin = barInfo.normalizedXMin;
					}
					if (barInfo.normalizedXMax != val.normalizedXMax)
					{
						val.normalizedXMax = barInfo.normalizedXMax;
					}
					barAllocator.SetData(val, i);
					int num = i + 1;
					i = num;
				}
			}
		}

		private void UpdateBarInfos()
		{
			float currentBarEnd;
			if ((bool)source)
			{
				if (isInventoryCheckDirty)
				{
					CheckInventory();
				}
				if ((bool)source && (bool)source.body)
				{
					hasLowHealthBuff = source.body.HasBuff(DLC2Content.Buffs.RevitalizeBuff);
				}
				HealthComponent.HealthBarValues healthBarValues = source.GetHealthBarValues();
				currentBarEnd = 0f;
				_ = source.fullCombinedHealth;
				ref BarInfo lowHealthUnderBarInfo = ref barInfoCollection.lowHealthUnderBarInfo;
				lowHealthUnderBarInfo.enabled = (hasLowHealthItem || hasLowHealthBuff) && source.isHealthLow;
				lowHealthUnderBarInfo.normalizedXMin = 0f;
				lowHealthUnderBarInfo.normalizedXMax = HealthComponent.lowHealthFraction * (1f - healthBarValues.curseFraction);
				ApplyStyle(ref lowHealthUnderBarInfo, ref style.lowHealthUnderStyle);
				cachedFractionalValue = Mathf.SmoothDamp(cachedFractionalValue, healthBarValues.healthFraction, ref healthFractionVelocity, 0.2f, float.PositiveInfinity, Time.deltaTime);
				ref BarInfo trailingUnderHealthbarInfo = ref barInfoCollection.trailingUnderHealthbarInfo;
				trailingUnderHealthbarInfo.normalizedXMin = 0f;
				trailingUnderHealthbarInfo.normalizedXMax = Mathf.Max(cachedFractionalValue, healthBarValues.healthFraction);
				trailingUnderHealthbarInfo.enabled = !trailingUnderHealthbarInfo.normalizedXMax.Equals(trailingUnderHealthbarInfo.normalizedXMin);
				ApplyStyle(ref trailingUnderHealthbarInfo, ref style.trailingUnderHealthBarStyle);
				ref BarInfo instantHealthbarInfo = ref barInfoCollection.instantHealthbarInfo;
				instantHealthbarInfo.enabled = healthBarValues.healthFraction > 0f;
				ApplyStyle(ref instantHealthbarInfo, ref style.instantHealthBarStyle);
				AddBar(ref instantHealthbarInfo, healthBarValues.healthFraction);
				ref BarInfo trailingOverHealthbarInfo = ref barInfoCollection.trailingOverHealthbarInfo;
				trailingOverHealthbarInfo.normalizedXMin = 0f;
				trailingOverHealthbarInfo.normalizedXMax = Mathf.Min(cachedFractionalValue + 0.01f, healthBarValues.healthFraction);
				trailingOverHealthbarInfo.enabled = !trailingOverHealthbarInfo.normalizedXMax.Equals(trailingOverHealthbarInfo.normalizedXMin);
				ApplyStyle(ref trailingOverHealthbarInfo, ref style.trailingOverHealthBarStyle);
				if (healthBarValues.isVoid)
				{
					trailingOverHealthbarInfo.color = voidPanelColor;
				}
				if (healthBarValues.isBoss || healthBarValues.hasInfusion)
				{
					trailingOverHealthbarInfo.color = infusionPanelColor;
				}
				if (healthCritical && style.flashOnHealthCritical)
				{
					trailingOverHealthbarInfo.color = GetCriticallyHurtColor();
				}
				ref BarInfo shieldBarInfo = ref barInfoCollection.shieldBarInfo;
				shieldBarInfo.enabled = healthBarValues.shieldFraction > 0f;
				ApplyStyle(ref shieldBarInfo, ref style.shieldBarStyle);
				if (healthBarValues.hasVoidShields)
				{
					shieldBarInfo.color = voidShieldsColor;
				}
				AddBar(ref shieldBarInfo, healthBarValues.shieldFraction);
				ref BarInfo curseBarInfo = ref barInfoCollection.curseBarInfo;
				curseBarInfo.enabled = healthBarValues.curseFraction > 0f;
				ApplyStyle(ref curseBarInfo, ref style.curseBarStyle);
				curseBarInfo.normalizedXMin = 1f - healthBarValues.curseFraction;
				curseBarInfo.normalizedXMax = 1f;
				ref BarInfo barrierBarInfo = ref barInfoCollection.barrierBarInfo;
				barrierBarInfo.enabled = source.barrier > 0f;
				ApplyStyle(ref barrierBarInfo, ref style.barrierBarStyle);
				barrierBarInfo.normalizedXMin = 0f;
				barrierBarInfo.normalizedXMax = healthBarValues.barrierFraction;
				ref BarInfo magneticBarInfo = ref barInfoCollection.magneticBarInfo;
				magneticBarInfo.enabled = source.magnetiCharge > 0f;
				magneticBarInfo.normalizedXMin = 0f;
				magneticBarInfo.normalizedXMax = healthBarValues.magneticFraction;
				magneticBarInfo.color = new UnityEngine.Color(75f, 0f, 130f);
				ApplyStyle(ref magneticBarInfo, ref style.magneticStyle);
				float num = healthBarValues.cullFraction;
				if (healthBarValues.isElite && (bool)viewerBody)
				{
					num = Mathf.Max(num, viewerBody.executeEliteHealthFraction);
				}
				ref BarInfo cullBarInfo = ref barInfoCollection.cullBarInfo;
				cullBarInfo.enabled = num > 0f;
				cullBarInfo.normalizedXMin = 0f;
				cullBarInfo.normalizedXMax = num;
				ApplyStyle(ref cullBarInfo, ref style.cullBarStyle);
				float ospFraction = healthBarValues.ospFraction;
				ref BarInfo ospBarInfo = ref barInfoCollection.ospBarInfo;
				ospBarInfo.enabled = ospFraction > 0f;
				ospBarInfo.normalizedXMin = 0f;
				ospBarInfo.normalizedXMax = ospFraction;
				ApplyStyle(ref ospBarInfo, ref style.ospStyle);
				ref BarInfo lowHealthOverBarInfo = ref barInfoCollection.lowHealthOverBarInfo;
				lowHealthOverBarInfo.enabled = (hasLowHealthItem || hasLowHealthBuff) && !source.isHealthLow;
				lowHealthOverBarInfo.normalizedXMin = HealthComponent.lowHealthFraction * (1f - healthBarValues.curseFraction);
				lowHealthOverBarInfo.normalizedXMax = HealthComponent.lowHealthFraction * (1f - healthBarValues.curseFraction) + 0.005f;
				ApplyStyle(ref lowHealthOverBarInfo, ref style.lowHealthOverStyle);
			}
			void AddBar(ref BarInfo barInfo, float fraction)
			{
				if (barInfo.enabled)
				{
					barInfo.normalizedXMin = currentBarEnd;
					currentBarEnd = (barInfo.normalizedXMax = barInfo.normalizedXMin + fraction);
				}
			}
			static void ApplyStyle(ref BarInfo barInfo, ref HealthBarStyle.BarStyle barStyle)
			{
				barInfo.enabled &= barStyle.enabled;
				barInfo.color = barStyle.baseColor;
				barInfo.sprite = barStyle.sprite;
				barInfo.imageType = barStyle.imageType;
				barInfo.sizeDelta = barStyle.sizeDelta;
			}
		}

		public void InitializeHealthBar()
		{
			float num = 1f;
			if (!source)
			{
				return;
			}
			CharacterBody body = source.body;
			bool isElite = body.isElite;
			float fullHealth = source.fullHealth;
			if ((bool)eliteBackdropRectTransform)
			{
				if (isElite)
				{
					num += 1f;
				}
				eliteBackdropRectTransform.gameObject.SetActive(isElite);
			}
			if (scaleHealthbarWidth && (bool)body)
			{
				float x = Util.Remap(Mathf.Clamp((body.baseMaxHealth + body.baseMaxShield) * num, 0f, maxHealthbarHealth), minHealthbarHealth, maxHealthbarHealth, minHealthbarWidth, maxHealthbarWidth);
				rectTransform.sizeDelta = new UnityEngine.Vector2(x, rectTransform.sizeDelta.y);
			}
			if ((bool)spriteAsNumberManager)
			{
				float num2 = Mathf.Ceil(source.combinedHealth);
				float num3 = Mathf.Ceil(fullHealth);
				if (num2 != displayStringCurrentHealth || num3 != displayStringFullHealth)
				{
					displayStringFullHealth = num3;
					displayStringCurrentHealth = num2;
					spriteAsNumberManager.SetHitPointValues((int)displayStringCurrentHealth, (int)displayStringFullHealth);
				}
			}
			else
			{
				if ((bool)currentHealthText)
				{
					float num4 = Mathf.Ceil(source.combinedHealth);
					if (num4 != displayStringCurrentHealth)
					{
						displayStringCurrentHealth = num4;
						currentHealthText.text = num4.ToString();
					}
				}
				if ((bool)fullHealthText)
				{
					float num5 = Mathf.Ceil(fullHealth);
					if (num5 != displayStringFullHealth)
					{
						displayStringFullHealth = num5;
						fullHealthText.text = num5.ToString();
					}
				}
			}
			healthCritical = source.isHealthLow && source.alive;
			if ((bool)criticallyHurtImage)
			{
				if (healthCritical)
				{
					criticallyHurtImage.enabled = true;
					criticallyHurtImage.color = GetCriticallyHurtColor();
				}
				else
				{
					criticallyHurtImage.enabled = false;
				}
			}
			if ((bool)deadImage)
			{
				deadImage.enabled = !source.alive;
			}
		}

		public void UpdateHealthbar(float deltaTime)
		{
			float num = 1f;
			if ((bool)source)
			{
				_ = source.body.isElite;
				float fullHealth = source.fullHealth;
				float num2 = source.fullHealth + source.fullShield;
				Mathf.Clamp01(source.health / num2 * num);
				Mathf.Clamp01(source.shield / num2 * num);
				if ((bool)spriteAsNumberManager)
				{
					float num3 = Mathf.Ceil(source.combinedHealth);
					float num4 = Mathf.Ceil(fullHealth);
					if (num3 != displayStringCurrentHealth || num4 != displayStringFullHealth)
					{
						displayStringFullHealth = num4;
						displayStringCurrentHealth = num3;
						spriteAsNumberManager.SetHitPointValues((int)displayStringCurrentHealth, (int)displayStringFullHealth);
					}
				}
				else
				{
					if ((bool)currentHealthText && source.combinedHealth != oldHealth)
					{
						oldHealth = source.combinedHealth;
						float num5 = Mathf.Ceil(source.combinedHealth);
						if (num5 != displayStringCurrentHealth)
						{
							displayStringCurrentHealth = num5;
							currentHealthText.text = num5.ToString();
						}
					}
					if ((bool)fullHealthText && fullHealth != oldFullHealth)
					{
						oldFullHealth = fullHealth;
						float num6 = Mathf.Ceil(fullHealth);
						if (num6 != displayStringFullHealth)
						{
							displayStringFullHealth = num6;
							fullHealthText.text = num6.ToString();
						}
					}
				}
				healthCritical = source.isHealthLow && source.alive;
				if ((bool)criticallyHurtImage && healthCritical != oldHealthCritical)
				{
					oldHealthCritical = healthCritical;
					if (healthCritical)
					{
						criticallyHurtImage.enabled = true;
						criticallyHurtImage.color = GetCriticallyHurtColor();
					}
					else
					{
						criticallyHurtImage.enabled = false;
					}
				}
				if ((bool)deadImage && source.alive != oldAlive)
				{
					oldAlive = source.alive;
					deadImage.enabled = !source.alive;
				}
			}
			else if ((bool)deadImage && oldAlive)
			{
				oldAlive = false;
				deadImage.enabled = true;
			}
			UpdateBarInfos();
			ApplyBars();
		}

		private void AddInventoryChangedHandler()
		{
			if ((bool)source?.body?.inventory)
			{
				source.body.inventory.onInventoryChanged += OnInventoryChanged;
			}
		}

		private void RemoveInventoryChangedHandler()
		{
			if ((bool)source?.body?.inventory)
			{
				source.body.inventory.onInventoryChanged -= OnInventoryChanged;
			}
		}

		private void OnInventoryChanged()
		{
			isInventoryCheckDirty = true;
		}

		private void CheckInventory()
		{
			isInventoryCheckDirty = false;
			Inventory inventory = source?.body?.inventory;
			if (!inventory)
			{
				return;
			}
			hasLowHealthItem = false;
			foreach (ItemIndex item in ItemCatalog.GetItemsWithTag(ItemTag.LowHealth))
			{
				if (inventory.GetItemCount(item) > 0)
				{
					hasLowHealthItem = true;
					break;
				}
			}
		}

		public static UnityEngine.Color GetCriticallyHurtColor()
		{
			if (Mathf.FloorToInt(Time.fixedTime * 10f) % 2 != 0)
			{
				return ColorCatalog.GetColor(ColorCatalog.ColorIndex.Teleporter);
			}
			return UnityEngine.Color.white;
		}
	}
	public class HGButton : MPButton
	{
		private TextMeshProUGUI textMeshProUGui;

		private float stopwatch;

		private UnityEngine.Color originalColor;

		[Tooltip("For automatic navigation: prefer objects with the same parent over objects elsewhere in the tree structure.")]
		public bool preferSiblings;

		public bool showImageOnHover;

		public UnityEngine.UI.Image imageOnHover;

		public UnityEngine.UI.Image imageOnInteractable;

		public bool updateTextOnHover;

		public LanguageTextMeshController hoverLanguageTextMeshController;

		public string hoverToken;

		private bool hovering;

		private Coroutine enableButtonCoroutine;

		private SelectionState previousState = SelectionState.Disabled;

		public string uiClickSoundOverride;

		private float buttonScaleVelocity;

		private float imageOnHoverAlphaVelocity;

		private float imageOnHoverScaleVelocity;

		protected override void Awake()
		{
			base.Awake();
			textMeshProUGui = GetComponent<TextMeshProUGUI>();
		}

		protected override void Start()
		{
			base.Start();
			base.onClick.AddListener(OnClickCustom);
			if (updateTextOnHover && !hoverLanguageTextMeshController)
			{
				UnityEngine.Debug.LogErrorFormat("HGButton \"{0}\" is missing an object assigned to its .hoverLangaugeTextMeshController field.", Util.GetGameObjectHierarchyName(base.gameObject));
			}
		}

		protected override void DoStateTransition(SelectionState state, bool instant)
		{
			base.DoStateTransition(state, instant);
			if (previousState != state)
			{
				switch (state)
				{
				case SelectionState.Normal:
					hovering = false;
					break;
				case SelectionState.Highlighted:
				case SelectionState.Selected:
					if (!hovering)
					{
						Util.PlaySound("Play_UI_menuHover", RoR2Application.instance.gameObject);
					}
					hovering = true;
					break;
				case SelectionState.Pressed:
					hovering = true;
					break;
				case SelectionState.Disabled:
					hovering = false;
					break;
				}
				previousState = state;
			}
			originalColor = base.targetGraphic.color;
		}

		public void OnClickCustom()
		{
			Util.PlaySound((!string.IsNullOrEmpty(uiClickSoundOverride)) ? uiClickSoundOverride : "Play_UI_menuClick", RoR2Application.instance.gameObject);
		}

		private void LateUpdate()
		{
			stopwatch += Time.deltaTime;
			if (Application.isPlaying)
			{
				if (showImageOnHover)
				{
					float target = (hovering ? 1f : 0f);
					float target2 = (hovering ? 1f : 1.1f);
					UnityEngine.Color color = imageOnHover.color;
					float x = imageOnHover.transform.localScale.x;
					float a = Mathf.SmoothDamp(color.a, target, ref imageOnHoverAlphaVelocity, 0.03f * base.colors.fadeDuration, float.PositiveInfinity, Time.unscaledDeltaTime);
					float num = Mathf.SmoothDamp(x, target2, ref imageOnHoverScaleVelocity, 0.03f, float.PositiveInfinity, Time.unscaledDeltaTime);
					UnityEngine.Color color2 = new UnityEngine.Color(color.r, color.g, color.g, a);
					UnityEngine.Vector3 localScale = new UnityEngine.Vector3(num, num, num);
					imageOnHover.color = color2;
					imageOnHover.transform.localScale = localScale;
				}
				if ((bool)imageOnInteractable)
				{
					imageOnInteractable.enabled = base.interactable;
				}
			}
		}

		public override void OnPointerEnter(PointerEventData eventData)
		{
			base.OnPointerEnter(eventData);
			if (updateTextOnHover && (bool)hoverLanguageTextMeshController)
			{
				hoverLanguageTextMeshController.token = hoverToken;
			}
		}

		public override void OnPointerExit(PointerEventData eventData)
		{
			if (updateTextOnHover && (bool)hoverLanguageTextMeshController)
			{
				hoverLanguageTextMeshController.token = "";
			}
			base.OnPointerExit(eventData);
		}

		public override void OnSelect(BaseEventData eventData)
		{
			base.OnSelect(eventData);
			if (base.eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad)
			{
				hovering = true;
			}
			if (updateTextOnHover && (bool)hoverLanguageTextMeshController)
			{
				hoverLanguageTextMeshController.token = hoverToken;
			}
		}

		public override void OnDeselect(BaseEventData eventData)
		{
			base.OnDeselect(eventData);
			if (base.eventSystem != null && base.eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad)
			{
				hovering = false;
			}
		}

		public override Selectable FindSelectableOnLeft()
		{
			if (!preferSiblings)
			{
				return base.FindSelectableOnLeft();
			}
			if (base.navigation.mode == UnityEngine.UI.Navigation.Mode.Explicit)
			{
				return base.navigation.selectOnLeft;
			}
			if ((base.navigation.mode & UnityEngine.UI.Navigation.Mode.Horizontal) != 0)
			{
				return FindSelectablePreferSibling(base.transform.rotation * UnityEngine.Vector3.left);
			}
			return null;
		}

		public override Selectable FindSelectableOnRight()
		{
			if (!preferSiblings)
			{
				return base.FindSelectableOnRight();
			}
			if (base.navigation.mode == UnityEngine.UI.Navigation.Mode.Explicit)
			{
				return base.navigation.selectOnRight;
			}
			if ((base.navigation.mode & UnityEngine.UI.Navigation.Mode.Horizontal) != 0)
			{
				return FindSelectablePreferSibling(base.transform.rotation * UnityEngine.Vector3.right);
			}
			return null;
		}

		private static UnityEngine.Vector3 GetPointOnRectEdge(RectTransform rect, UnityEngine.Vector2 dir)
		{
			if (rect == null)
			{
				return UnityEngine.Vector3.zero;
			}
			if (dir != UnityEngine.Vector2.zero)
			{
				dir /= Mathf.Max(Mathf.Abs(dir.x), Mathf.Abs(dir.y));
			}
			dir = rect.rect.center + UnityEngine.Vector2.Scale(rect.rect.size, dir * 0.5f);
			return dir;
		}

		private Selectable FindSelectablePreferSibling(UnityEngine.Vector3 dir)
		{
			dir = dir.normalized;
			UnityEngine.Vector3 vector = UnityEngine.Quaternion.Inverse(base.transform.rotation) * dir;
			UnityEngine.Vector3 vector2 = base.transform.TransformPoint(GetPointOnRectEdge(base.transform as RectTransform, vector));
			float num = float.NegativeInfinity;
			float num2 = float.NegativeInfinity;
			float num3 = 0f;
			UnityEngine.UI.Navigation.Mode mode = base.navigation.mode;
			bool flag = base.navigation.wrapAround && (mode == UnityEngine.UI.Navigation.Mode.Vertical || mode == UnityEngine.UI.Navigation.Mode.Horizontal);
			Selectable selectable = null;
			Selectable result = null;
			for (int i = 0; i < Selectable.s_SelectableCount; i++)
			{
				Selectable selectable2 = Selectable.s_Selectables[i];
				if (selectable2 == this || !selectable2.IsInteractable() || selectable2.navigation.mode == UnityEngine.UI.Navigation.Mode.None)
				{
					continue;
				}
				bool flag2 = base.transform.parent == selectable2.transform.parent;
				RectTransform rectTransform = selectable2.transform as RectTransform;
				UnityEngine.Vector3 position = ((rectTransform != null) ? ((UnityEngine.Vector3)rectTransform.rect.center) : UnityEngine.Vector3.zero);
				UnityEngine.Vector3 rhs = selectable2.transform.TransformPoint(position) - vector2;
				float num4 = UnityEngine.Vector3.Dot(dir, rhs);
				if (flag && num4 < 0f)
				{
					num3 = (0f - num4) * rhs.sqrMagnitude;
					if (flag2)
					{
						num3 *= 2f;
					}
					if (num3 > num2)
					{
						num2 = num3;
						result = selectable2;
					}
				}
				else if (!(num4 <= 0f))
				{
					num3 = num4 / rhs.sqrMagnitude;
					if (flag2)
					{
						num3 *= 2f;
					}
					if (num3 > num)
					{
						num = num3;
						selectable = selectable2;
					}
				}
			}
			if (flag && null == selectable)
			{
				return result;
			}
			return selectable;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class HGButtonHistory : MonoBehaviour
	{
		public UILayerKey requiredTopLayer;

		public GameObject lastRememberedGameObject;

		private MPEventSystemLocator eventSystemLocator;

		private bool topLayerWasOn;

		protected MPEventSystem eventSystem => eventSystemLocator?.eventSystem;

		protected void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private void OnEnable()
		{
			SelectRememberedButton();
		}

		private void Update()
		{
			bool flag = !requiredTopLayer || requiredTopLayer.representsTopLayer;
			if (flag && !topLayerWasOn)
			{
				StartCoroutine(SelectRememberedButton());
			}
			topLayerWasOn = flag;
			if (!(eventSystem?.currentSelectedGameObject) || !topLayerWasOn)
			{
				return;
			}
			GameObject gameObject = eventSystem?.currentSelectedGameObject;
			if ((bool)gameObject)
			{
				MPButton component = gameObject.GetComponent<MPButton>();
				if ((bool)component && component.navigation.mode != 0)
				{
					lastRememberedGameObject = eventSystem?.currentSelectedGameObject;
				}
			}
		}

		private IEnumerator SelectRememberedButton()
		{
			yield return null;
			if (!lastRememberedGameObject)
			{
				yield break;
			}
			MPEventSystem mPEventSystem = eventSystem;
			if ((object)mPEventSystem != null && mPEventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad)
			{
				MPButton component = lastRememberedGameObject.GetComponent<MPButton>();
				if ((bool)component)
				{
					UnityEngine.Debug.LogFormat("Applying button history ({0})", lastRememberedGameObject);
					eventSystem.SetSelectedGameObject(lastRememberedGameObject);
					component.OnSelect(null);
				}
			}
		}

		public void ClearHistory()
		{
			lastRememberedGameObject = null;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class HGGamepadInputEvent : MonoBehaviour
	{
		public string actionName;

		public UnityEvent actionEvent;

		public UILayerKey requiredTopLayer;

		public GameObject[] enabledObjectsIfActive;

		private MPEventSystemLocator eventSystemLocator;

		public bool RequireInputMapperNotRunning;

		private bool couldAcceptInput;

		protected MPEventSystem eventSystem => eventSystemLocator?.eventSystem;

		protected void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		protected void Update()
		{
			bool flag = CanAcceptInput();
			if (couldAcceptInput != flag)
			{
				GameObject[] array = enabledObjectsIfActive;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(flag);
				}
			}
			if (CanAcceptInput() && eventSystem.player.GetButtonDown(actionName))
			{
				actionEvent.Invoke();
			}
			couldAcceptInput = flag;
		}

		protected bool CanAcceptInput()
		{
			if (base.gameObject.activeInHierarchy && (!requiredTopLayer || requiredTopLayer.representsTopLayer))
			{
				MPEventSystem mPEventSystem = eventSystem;
				if ((object)mPEventSystem != null && mPEventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad)
				{
					if (RequireInputMapperNotRunning)
					{
						if (!InputMapperHelper.anyRemapperListening)
						{
							return InputMapperHelper.anyRemapperListeningStopTimestamp != Time.unscaledTime;
						}
						return false;
					}
					return true;
				}
			}
			return false;
		}
	}
	public class HGHeaderNavigationController : MonoBehaviour
	{
		[Serializable]
		public struct Header
		{
			public MPButton headerButton;

			public string headerName;

			public TextMeshProUGUI tmpHeaderText;

			public GameObject headerRoot;

			public bool AreConsolePlatformsSupported;

			public bool isPrimaryPlayerOnly;
		}

		[FormerlySerializedAs("buttonSelectionRoot")]
		[Header("Header Parameters")]
		public GameObject headerHighlightObject;

		public int currentHeaderIndex;

		public UnityEngine.Color selectedTextColor = UnityEngine.Color.white;

		public UnityEngine.Color unselectedTextColor = UnityEngine.Color.gray;

		public bool makeSelectedHeaderButtonNoninteractable;

		public GameObject ControllerResetButton;

		public bool isPrimaryPlayer;

		private bool IsPlatformConsole;

		[Header("Header Infos")]
		public List<Header> headers;

		private void Start()
		{
			BuildInitialHeaderList();
			RebuildHeaders();
		}

		private void LateUpdate()
		{
			for (int i = 0; i < headers.Count; i++)
			{
				Header header = headers[i];
				if ((bool)header.tmpHeaderText)
				{
					if (i == currentHeaderIndex && header.tmpHeaderText.color != selectedTextColor)
					{
						header.tmpHeaderText.color = selectedTextColor;
					}
					else
					{
						header.tmpHeaderText.color = unselectedTextColor;
					}
				}
			}
		}

		private void BuildInitialHeaderList()
		{
			List<Header> list = new List<Header>();
			foreach (Header header in headers)
			{
				if (IsPlatformConsole && !header.AreConsolePlatformsSupported)
				{
					header.headerButton.gameObject.SetActive(value: false);
				}
				else if (header.isPrimaryPlayerOnly && !isPrimaryPlayer)
				{
					header.headerButton.gameObject.SetActive(value: false);
				}
				else
				{
					list.Add(header);
				}
			}
			headers = list;
		}

		public void ChooseFirstHeader()
		{
			if (headers.Count > 0)
			{
				currentHeaderIndex = 0;
				RebuildHeaders();
			}
		}

		public void ChooseHeader(string headerName)
		{
			for (int i = 0; i < headers.Count; i++)
			{
				if (headers[i].headerName == headerName)
				{
					currentHeaderIndex = i;
					RebuildHeaders();
					break;
				}
			}
		}

		public void ChooseHeaderByButton(MPButton mpButton)
		{
			for (int i = 0; i < headers.Count; i++)
			{
				if (headers[i].headerButton == mpButton)
				{
					currentHeaderIndex = i;
					RebuildHeaders();
					break;
				}
			}
		}

		public void MoveHeaderLeft()
		{
			currentHeaderIndex = Mathf.Max(0, currentHeaderIndex - 1);
			Util.PlaySound("Play_UI_menuClick", RoR2Application.instance.gameObject);
			RebuildHeaders();
		}

		public void MoveHeaderRight()
		{
			currentHeaderIndex = Mathf.Min(headers.Count - 1, currentHeaderIndex + 1);
			Util.PlaySound("Play_UI_menuClick", RoR2Application.instance.gameObject);
			RebuildHeaders();
		}

		private void BuildInitialHeadersList()
		{
			for (int i = 0; i < headers.Count; i++)
			{
				Header header = headers[i];
				if (IsPlatformConsole)
				{
					_ = header.AreConsolePlatformsSupported;
				}
			}
		}

		private void RebuildHeaders()
		{
			for (int i = 0; i < headers.Count; i++)
			{
				Header header = headers[i];
				if (IsPlatformConsole && !header.AreConsolePlatformsSupported)
				{
					header.headerRoot.SetActive(value: false);
				}
				else if (i == currentHeaderIndex)
				{
					if ((bool)header.headerRoot)
					{
						header.headerRoot.SetActive(value: true);
					}
					if ((bool)header.headerButton)
					{
						if (makeSelectedHeaderButtonNoninteractable)
						{
							header.headerButton.interactable = false;
						}
						if ((bool)headerHighlightObject)
						{
							headerHighlightObject.transform.SetParent(header.headerButton.transform, worldPositionStays: false);
							headerHighlightObject.SetActive(value: false);
							headerHighlightObject.SetActive(value: true);
							RectTransform component = headerHighlightObject.GetComponent<RectTransform>();
							component.offsetMin = UnityEngine.Vector2.zero;
							component.offsetMax = UnityEngine.Vector2.zero;
							component.localScale = UnityEngine.Vector3.one;
						}
					}
				}
				else
				{
					if ((bool)header.headerButton && makeSelectedHeaderButtonNoninteractable)
					{
						header.headerButton.interactable = true;
					}
					if ((bool)header.headerRoot)
					{
						header.headerRoot.SetActive(value: false);
					}
				}
			}
			if (ControllerResetButton != null)
			{
				if (headers[currentHeaderIndex].headerName == "Controller")
				{
					ControllerResetButton.SetActive(value: true);
				}
				else
				{
					ControllerResetButton.SetActive(value: false);
				}
			}
		}

		private Header GetCurrentHeader()
		{
			return headers[currentHeaderIndex];
		}
	}
	public class HGPopoutPanel : MonoBehaviour
	{
		public int popoutPanelLayer;

		public bool usesAdditionalInfo;

		[Header("Optional Referenced Components")]
		public RectTransform popoutPanelContentContainer;

		public LanguageTextMeshController popoutPanelTitleText;

		public LanguageTextMeshController popoutPanelSubtitleText;

		public LanguageTextMeshController popoutPanelDescriptionText;

		public GameObject popoutAdditionalInfoContainer;

		public static List<HGPopoutPanel> instances = new List<HGPopoutPanel>();

		private void OnEnable()
		{
			for (int i = 0; i < instances.Count; i++)
			{
				HGPopoutPanel hGPopoutPanel = instances[i];
				if (popoutPanelLayer == hGPopoutPanel.popoutPanelLayer)
				{
					hGPopoutPanel.gameObject.SetActive(value: false);
				}
			}
			instances.Add(this);
			if (usesAdditionalInfo)
			{
				popoutAdditionalInfoContainer.SetActive(value: true);
			}
		}

		private void OnDisable()
		{
			instances.Remove(this);
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	[RequireComponent(typeof(ScrollRect))]
	public class HGScrollRectHelper : MonoBehaviour
	{
		public float spacingPerElement;

		public bool allowVerticalScrollingWithGamepadSticks;

		public float stickScale;

		public UILayerKey requiredTopLayer;

		public MPDropdown dropDown;

		private ScrollRect scrollRect;

		private readonly List<Toggle> dropDownOptions = new List<Toggle>();

		private MPEventSystemLocator eventSystemLocator;

		private float idealVerticalNormalizedPosition;

		private float scrollbarVelocity;

		private const float scrollbarSmoothdampTime = 0.1f;

		private bool hasInitialized;

		private void Start()
		{
			Initialize();
		}

		private void Initialize()
		{
			if (!hasInitialized)
			{
				hasInitialized = true;
				scrollRect = GetComponent<ScrollRect>();
				eventSystemLocator = GetComponent<MPEventSystemLocator>();
				idealVerticalNormalizedPosition = scrollRect.verticalNormalizedPosition;
				if (!eventSystemLocator.eventSystem)
				{
					eventSystemLocator.eventSystem = MPEventSystemManager.primaryEventSystem;
				}
				if ((bool)dropDown)
				{
					scrollRect.content.GetComponentsInChildren(dropDownOptions);
				}
			}
		}

		private bool GamepadIsCurrentInputSource()
		{
			if (!hasInitialized)
			{
				return false;
			}
			if ((bool)eventSystemLocator.eventSystem)
			{
				return eventSystemLocator.eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad;
			}
			return false;
		}

		private bool CanAcceptInput()
		{
			if ((bool)requiredTopLayer)
			{
				return requiredTopLayer.representsTopLayer;
			}
			return true;
		}

		private void Update()
		{
			Initialize();
			if (!GamepadIsCurrentInputSource())
			{
				return;
			}
			if ((bool)eventSystemLocator && (bool)eventSystemLocator.eventSystem && CanAcceptInput())
			{
				float height = scrollRect.content.rect.height;
				float axis = eventSystemLocator.eventSystem.player.GetAxis(13);
				eventSystemLocator.eventSystem.player.GetAxis(12);
				if (allowVerticalScrollingWithGamepadSticks)
				{
					idealVerticalNormalizedPosition = Mathf.Clamp01(idealVerticalNormalizedPosition + axis * stickScale * Time.unscaledDeltaTime / height);
					scrollRect.verticalNormalizedPosition = idealVerticalNormalizedPosition;
					if ((bool)dropDown && dropDownOptions.Count > 0)
					{
						GamepadAutoScroll();
					}
				}
			}
			scrollRect.verticalNormalizedPosition = Mathf.SmoothDamp(scrollRect.verticalNormalizedPosition, idealVerticalNormalizedPosition, ref scrollbarVelocity, 0.1f, float.PositiveInfinity, Time.unscaledDeltaTime);
		}

		private void GamepadAutoScroll()
		{
			int num = -1;
			Toggle toggle = (eventSystemLocator.eventSystem.currentSelectedGameObject ? eventSystemLocator.eventSystem.currentSelectedGameObject.GetComponent<Toggle>() : null);
			if ((bool)toggle)
			{
				num = dropDownOptions.IndexOf(toggle);
			}
			if (num > -1)
			{
				idealVerticalNormalizedPosition = 1f - (float)num / (float)dropDownOptions.Count;
			}
		}

		public void ScrollToShowMe(MPButton mpButton)
		{
			Initialize();
			if (!GamepadIsCurrentInputSource() || !CanAcceptInput())
			{
				return;
			}
			Canvas.ForceUpdateCanvases();
			_ = scrollRect.content;
			RectTransform component = mpButton.GetComponent<RectTransform>();
			float num = (0f - scrollRect.viewport.rect.size.y) / 2f;
			float num2 = 0f - scrollRect.content.rect.size.y;
			float num3 = 0f;
			float num4 = 0f;
			SettingSubsectionHelper component2 = mpButton.transform.parent.GetComponent<SettingSubsectionHelper>();
			if ((object)component2 != null)
			{
				RectTransform component3 = component2.GetComponent<RectTransform>();
				num4 = component3.anchoredPosition.y + component3.sizeDelta.y * 0.5f;
			}
			float num5 = component.anchoredPosition.y + num4 - spacingPerElement;
			if (num5 > num3 + num)
			{
				idealVerticalNormalizedPosition = 1f;
			}
			else if (!(num5 > num))
			{
				if (num5 < num2 - num)
				{
					idealVerticalNormalizedPosition = 0f;
					return;
				}
				float num6 = Mathf.InverseLerp(num, num2 - num, num5);
				float num7 = 1f - num6;
				idealVerticalNormalizedPosition = num7;
			}
		}

		private static UnityEngine.Rect GetWorldspaceRect(UnityEngine.Vector3 pos, UnityEngine.Rect rect, UnityEngine.Vector2 offset)
		{
			float x = pos.x + rect.xMin - offset.x;
			float y = pos.y + rect.yMin - offset.y;
			return new UnityEngine.Rect(new UnityEngine.Vector2(x, y), rect.size);
		}
	}
	public class HGTextMeshProUGUI : TextMeshProUGUI
	{
		public bool useLanguageDefaultFont = true;

		public static TMP_FontAsset defaultLanguageFont;

		[InitDuringStartup]
		private static void Init()
		{
			Language.onCurrentLanguageChanged += OnCurrentLanguageChanged;
			OnCurrentLanguageChanged();
		}

		private static void OnCurrentLanguageChanged()
		{
			AsyncOperationHandle<TMP_FontAsset> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<TMP_FontAsset>(Language.GetString("DEFAULT_FONT"));
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<TMP_FontAsset> x)
			{
				defaultLanguageFont = x.Result;
			};
		}

		protected override void Awake()
		{
			base.Awake();
			if (useLanguageDefaultFont && defaultLanguageFont != null)
			{
				base.font = defaultLanguageFont;
				UpdateFontAsset();
			}
		}
	}
	[RequireComponent(typeof(Canvas))]
	public class HighlightRect : MonoBehaviour
	{
		public enum HighlightState
		{
			Expanding,
			Holding,
			Contracting
		}

		public AnimationCurve curve;

		public UnityEngine.Color highlightColor;

		public Sprite cornerImage;

		public string nametagString;

		private UnityEngine.UI.Image bottomLeftImage;

		private UnityEngine.UI.Image bottomRightImage;

		private UnityEngine.UI.Image topLeftImage;

		private UnityEngine.UI.Image topRightImage;

		private TextMeshProUGUI nametagText;

		public Renderer targetRenderer;

		public GameObject cameraTarget;

		public RectTransform nametagRectTransform;

		public RectTransform bottomLeftRectTransform;

		public RectTransform bottomRightRectTransform;

		public RectTransform topLeftRectTransform;

		public RectTransform topRightRectTransform;

		public float expandTime = 1f;

		public float maxLifeTime;

		public bool destroyOnLifeEnd;

		private float time;

		public HighlightState highlightState;

		private static List<HighlightRect> instancesList;

		private Canvas canvas;

		private Camera uiCam;

		private Camera sceneCam;

		private static readonly UnityEngine.Vector2[] extentPoints;

		static HighlightRect()
		{
			instancesList = new List<HighlightRect>();
			extentPoints = new UnityEngine.Vector2[8];
			RoR2Application.onLateUpdate += UpdateAll;
		}

		private void Awake()
		{
			canvas = GetComponent<Canvas>();
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void Start()
		{
			highlightState = HighlightState.Expanding;
			bottomLeftImage = bottomLeftRectTransform.GetComponent<UnityEngine.UI.Image>();
			bottomRightImage = bottomRightRectTransform.GetComponent<UnityEngine.UI.Image>();
			topLeftImage = topLeftRectTransform.GetComponent<UnityEngine.UI.Image>();
			topRightImage = topRightRectTransform.GetComponent<UnityEngine.UI.Image>();
			bottomLeftImage.sprite = cornerImage;
			bottomRightImage.sprite = cornerImage;
			topLeftImage.sprite = cornerImage;
			topRightImage.sprite = cornerImage;
			bottomLeftImage.color = highlightColor;
			bottomRightImage.color = highlightColor;
			topLeftImage.color = highlightColor;
			topRightImage.color = highlightColor;
			if ((bool)nametagRectTransform)
			{
				nametagText = nametagRectTransform.GetComponent<TextMeshProUGUI>();
				nametagText.color = highlightColor;
				nametagText.text = nametagString;
			}
		}

		private static void UpdateAll()
		{
			for (int num = instancesList.Count - 1; num >= 0; num--)
			{
				instancesList[num].DoUpdate();
			}
		}

		private void DoUpdate()
		{
			if (!targetRenderer)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			switch (highlightState)
			{
			case HighlightState.Expanding:
				time += Time.deltaTime;
				if (time >= expandTime)
				{
					time = expandTime;
					highlightState = HighlightState.Holding;
				}
				break;
			case HighlightState.Holding:
				if (destroyOnLifeEnd)
				{
					time += Time.deltaTime;
					if (time > maxLifeTime)
					{
						highlightState = HighlightState.Contracting;
						time = expandTime;
					}
				}
				break;
			case HighlightState.Contracting:
				time -= Time.deltaTime;
				if (time <= 0f)
				{
					UnityEngine.Object.Destroy(base.gameObject);
					return;
				}
				break;
			}
			UnityEngine.Rect rect = GUIRectWithObject(sceneCam, targetRenderer);
			UnityEngine.Vector2 a = new UnityEngine.Vector2(Mathf.Lerp(rect.xMin, rect.xMax, 0.5f), Mathf.Lerp(rect.yMin, rect.yMax, 0.5f));
			float t = curve.Evaluate(time / expandTime);
			bottomLeftRectTransform.anchoredPosition = UnityEngine.Vector2.LerpUnclamped(a, new UnityEngine.Vector2(rect.xMin, rect.yMin), t);
			bottomRightRectTransform.anchoredPosition = UnityEngine.Vector2.LerpUnclamped(a, new UnityEngine.Vector2(rect.xMax, rect.yMin), t);
			topLeftRectTransform.anchoredPosition = UnityEngine.Vector2.LerpUnclamped(a, new UnityEngine.Vector2(rect.xMin, rect.yMax), t);
			topRightRectTransform.anchoredPosition = UnityEngine.Vector2.LerpUnclamped(a, new UnityEngine.Vector2(rect.xMax, rect.yMax), t);
			if ((bool)nametagRectTransform)
			{
				nametagRectTransform.anchoredPosition = UnityEngine.Vector2.LerpUnclamped(a, new UnityEngine.Vector2(rect.xMin, rect.yMax), t);
			}
		}

		public static UnityEngine.Rect GUIRectWithObject(Camera cam, Renderer rend)
		{
			UnityEngine.Vector3 center = rend.bounds.center;
			UnityEngine.Vector3 extents = rend.bounds.extents;
			extentPoints[0] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x - extents.x, center.y - extents.y, center.z - extents.z));
			extentPoints[1] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x + extents.x, center.y - extents.y, center.z - extents.z));
			extentPoints[2] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x - extents.x, center.y - extents.y, center.z + extents.z));
			extentPoints[3] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x + extents.x, center.y - extents.y, center.z + extents.z));
			extentPoints[4] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x - extents.x, center.y + extents.y, center.z - extents.z));
			extentPoints[5] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x + extents.x, center.y + extents.y, center.z - extents.z));
			extentPoints[6] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x - extents.x, center.y + extents.y, center.z + extents.z));
			extentPoints[7] = WorldToGUIPoint(cam, new UnityEngine.Vector3(center.x + extents.x, center.y + extents.y, center.z + extents.z));
			UnityEngine.Vector2 lhs = extentPoints[0];
			UnityEngine.Vector2 lhs2 = extentPoints[0];
			UnityEngine.Vector2[] array = extentPoints;
			foreach (UnityEngine.Vector2 rhs in array)
			{
				lhs = UnityEngine.Vector2.Min(lhs, rhs);
				lhs2 = UnityEngine.Vector2.Max(lhs2, rhs);
			}
			return new UnityEngine.Rect(lhs.x, lhs.y, lhs2.x - lhs.x, lhs2.y - lhs.y);
		}

		public static UnityEngine.Vector2 WorldToGUIPoint(Camera cam, UnityEngine.Vector3 world)
		{
			return cam.WorldToScreenPoint(world);
		}

		public static void CreateHighlight(GameObject viewerBodyObject, Renderer targetRenderer, GameObject highlightPrefab, float overrideDuration = -1f, bool visibleToAll = false)
		{
			ReadOnlyCollection<CameraRigController> readOnlyInstancesList = CameraRigController.readOnlyInstancesList;
			int i = 0;
			for (int count = readOnlyInstancesList.Count; i < count; i++)
			{
				CameraRigController cameraRigController = readOnlyInstancesList[i];
				if (!(cameraRigController.target != viewerBodyObject) || visibleToAll)
				{
					HighlightRect component = UnityEngine.Object.Instantiate(highlightPrefab).GetComponent<HighlightRect>();
					component.targetRenderer = targetRenderer;
					component.canvas.worldCamera = cameraRigController.uiCam;
					component.uiCam = cameraRigController.uiCam;
					component.sceneCam = cameraRigController.sceneCam;
					if (overrideDuration > 0f)
					{
						component.maxLifeTime = overrideDuration;
					}
				}
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class HostGamePanelController : MonoBehaviour
	{
		public CarouselController gameModePicker;

		public CarouselController maxPlayersPicker;

		public GameObject capacityWarningLabel;

		private void Awake()
		{
			BuildGameModeChoices();
			SetDefaultHostNameIfEmpty();
			BuildMaxPlayerChoices();
		}

		private void OnEnable()
		{
			PlatformOnEnable();
		}

		private void OnDisable()
		{
			PlatformOnDisable();
		}

		private void Update()
		{
			capacityWarningLabel.SetActive(NetworkManagerSystem.SvMaxPlayersConVar.instance.intValue > RoR2Application.maxPlayers);
		}

		private void BuildGameModeChoices()
		{
			List<CarouselController.Choice> list = new List<CarouselController.Choice>(GameModeCatalog.gameModeCount);
			for (GameModeIndex gameModeIndex = (GameModeIndex)0; (int)gameModeIndex < GameModeCatalog.gameModeCount; gameModeIndex++)
			{
				Run gameModePrefabComponent = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex);
				ExpansionRequirementComponent component = gameModePrefabComponent.GetComponent<ExpansionRequirementComponent>();
				if (gameModePrefabComponent.userPickable && (!component || !component.requiredExpansion || EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(component.requiredExpansion.requiredEntitlement)))
				{
					list.Add(new CarouselController.Choice
					{
						suboptionDisplayToken = gameModePrefabComponent.nameToken,
						convarValue = gameModePrefabComponent.name
					});
				}
			}
			gameModePicker.choices = list.ToArray();
			gameModePicker.gameObject.SetActive(list.Count > 1);
			string @string = Console.instance.FindConVar("gamemode").GetString();
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].convarValue == @string)
				{
					flag = true;
					break;
				}
			}
			if (list.Count == 1 || !flag)
			{
				UnityEngine.Debug.LogFormat("Invalid gamemode {0} detected. Reverting to ClassicRun.", @string);
				gameModePicker.SubmitSetting(list[0].convarValue);
			}
		}

		private void BuildMaxPlayerChoices()
		{
			int num = 2;
			int num2 = RoR2Application.hardMaxPlayers;
			int? num3 = PlatformGetCurrentLobbyCapacity();
			if (num3.HasValue)
			{
				num = Math.Max(2, num3.Value);
				num2 = num;
			}
			List<CarouselController.Choice> list = new List<CarouselController.Choice>(num2 - num + 1);
			for (int i = num; i <= num2; i++)
			{
				string convarValue = TextSerialization.ToStringInvariant(i);
				list.Add(new CarouselController.Choice
				{
					suboptionDisplayToken = i.ToString(CultureInfo.CurrentCulture),
					convarValue = convarValue
				});
			}
			maxPlayersPicker.choices = list.ToArray();
		}

		private void SetDefaultHostNameIfEmpty()
		{
			NetworkManagerSystem.SvHostNameConVar instance = NetworkManagerSystem.SvHostNameConVar.instance;
			if (string.IsNullOrEmpty(instance.GetString()))
			{
				instance.SetString(Language.GetStringFormatted("HOSTGAMEPANEL_DEFAULT_SERVER_NAME_FORMAT", RoR2Application.GetBestUserName()));
			}
		}

		private void PlatformOnEnable()
		{
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyChanged = (Action)Delegate.Combine(lobbyManager.onLobbyChanged, new Action(OnLobbyChanged));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyDataUpdated = (Action)Delegate.Combine(lobbyManager2.onLobbyDataUpdated, new Action(OnLobbyDataUpdated));
		}

		private void PlatformOnDisable()
		{
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyDataUpdated = (Action)Delegate.Remove(lobbyManager.onLobbyDataUpdated, new Action(OnLobbyDataUpdated));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyChanged = (Action)Delegate.Remove(lobbyManager2.onLobbyChanged, new Action(OnLobbyChanged));
		}

		private void OnLobbyDataUpdated()
		{
			BuildMaxPlayerChoices();
		}

		private void OnLobbyChanged()
		{
			BuildMaxPlayerChoices();
		}

		private int? PlatformGetCurrentLobbyCapacity()
		{
			return PlatformSystems.lobbyManager.newestLobbyData?.totalMaxPlayers;
		}
	}
	public enum EScoreboardDeactivateReturnContext
	{
		Game,
		Pause
	}
	[RequireComponent(typeof(MPEventSystemProvider))]
	[RequireComponent(typeof(Canvas))]
	public class HUD : MonoBehaviour
	{
		public delegate void ShouldHudDisplayDelegate(HUD hud, ref bool shouldDisplay);

		private static List<HUD> instancesList;

		private static bool lockInstancesList;

		private static List<GameObject> instancesToReenableList;

		public static readonly ReadOnlyCollection<HUD> readOnlyInstanceList;

		private bool shouldForceScoreboardToggle;

		public GameObject oldTarget;

		private LocalUser _localUserViewer;

		[Header("Main")]
		[Tooltip("Immediate child of this object which contains all other UI.")]
		public GameObject mainContainer;

		private Canvas _mainContainerCanvas;

		[NonSerialized]
		public CameraRigController cameraRigController;

		public GameObject scoreboardPanel;

		public InspectPanelController inspectPanelController;

		public GameObject mainUIPanel;

		public GameObject cinematicPanel;

		public CombatHealthBarViewer combatHealthBarViewer;

		public ContextManager contextManager;

		public AllyCardManager allyCardManager;

		public Transform gameModeUiRoot;

		[Header("Character")]
		public HealthBar healthBar;

		public ExpBar expBar;

		public LevelText levelText;

		public BuffDisplay buffDisplay;

		public MoneyText moneyText;

		public GameObject lunarCoinContainer;

		public MoneyText lunarCoinText;

		public GameObject voidCoinContainer;

		public MoneyText voidCoinText;

		public SkillIcon[] skillIcons;

		public EquipmentIcon[] equipmentIcons;

		public ItemInventoryDisplay itemInventoryDisplay;

		[Header("Debug")]
		public HUDSpeedometer speedometer;

		private MPEventSystemProvider eventSystemProvider;

		private Canvas canvas;

		private EScoreboardDeactivateReturnContext scoreboardDeactivateReturnContext;

		private GameObject previousTargetBodyObject;

		public static readonly BoolConVar cvHudEnable;

		public GameObject targetBodyObject
		{
			get
			{
				if (!targetMaster)
				{
					return null;
				}
				return targetMaster.GetBodyObject();
			}
		}

		public CharacterMaster targetMaster { get; set; }

		public LocalUser localUserViewer
		{
			get
			{
				return _localUserViewer;
			}
			set
			{
				if (_localUserViewer != value)
				{
					_localUserViewer = value;
					eventSystemProvider.eventSystem = _localUserViewer.eventSystem;
				}
			}
		}

		public Canvas mainContainerCanvas
		{
			get
			{
				if (_mainContainerCanvas == null)
				{
					_mainContainerCanvas = mainContainer.GetComponent<Canvas>();
				}
				return _mainContainerCanvas;
			}
			set
			{
			}
		}

		public PostProcessVolume scoreboardPostProcessVolume { get; private set; }

		public GameObject gameModeUiInstance { get; private set; }

		public static event Action<HUD> onHudTargetChangedGlobal;

		public static event ShouldHudDisplayDelegate shouldHudDisplay;

		static HUD()
		{
			instancesList = new List<HUD>();
			lockInstancesList = false;
			instancesToReenableList = new List<GameObject>();
			readOnlyInstanceList = instancesList.AsReadOnly();
			cvHudEnable = new BoolConVar("hud_enable", ConVarFlags.Archive, "1", "Enable/disable the HUD.");
		}

		private static void OnUICameraPreRender(UICamera uiCamera)
		{
			CameraRigController cameraRigController = uiCamera.cameraRigController;
			if (!cameraRigController)
			{
				return;
			}
			LocalUser localUser = (cameraRigController.viewer ? cameraRigController.viewer.localUser : null);
			if (localUser == null)
			{
				return;
			}
			lockInstancesList = true;
			for (int i = 0; i < instancesList.Count; i++)
			{
				HUD hUD = instancesList[i];
				if (hUD.localUserViewer == localUser)
				{
					hUD.canvas.worldCamera = uiCamera.camera;
					continue;
				}
				GameObject gameObject = hUD.gameObject;
				instancesToReenableList.Add(gameObject);
				gameObject.SetActive(value: false);
			}
			lockInstancesList = false;
		}

		private static void OnUICameraPostRender(UICamera uiCamera)
		{
			lockInstancesList = true;
			for (int i = 0; i < instancesToReenableList.Count; i++)
			{
				instancesToReenableList[i].SetActive(value: true);
			}
			instancesToReenableList.Clear();
			lockInstancesList = false;
		}

		public static bool SetScoreboardActive(LocalUser localUser, bool isActive, EScoreboardDeactivateReturnContext returnContext, bool shouldForceScoreboardToggle = false)
		{
			if (localUser == null)
			{
				return false;
			}
			CameraRigController cameraRigController = localUser.cameraRigController;
			if (!cameraRigController)
			{
				return false;
			}
			HUD hud = cameraRigController.hud;
			hud.SetScoreboardState(isActive);
			if (isActive)
			{
				hud.shouldForceScoreboardToggle = shouldForceScoreboardToggle;
				hud.scoreboardDeactivateReturnContext = returnContext;
			}
			return true;
		}

		public static bool IsScoreboardActive(LocalUser localUser)
		{
			if (localUser == null)
			{
				return false;
			}
			CameraRigController cameraRigController = localUser.cameraRigController;
			if (!cameraRigController)
			{
				return false;
			}
			return cameraRigController.hud.scoreboardPanel.activeSelf;
		}

		public void OnEnable()
		{
			if (!lockInstancesList)
			{
				instancesList.Add(this);
				UpdateHudVisibility();
			}
		}

		public void OnDisable()
		{
			if (!lockInstancesList)
			{
				instancesList.Remove(this);
			}
		}

		private void Awake()
		{
			eventSystemProvider = GetComponent<MPEventSystemProvider>();
			canvas = GetComponent<Canvas>();
			if ((bool)scoreboardPanel)
			{
				scoreboardPostProcessVolume = scoreboardPanel.GetComponentInChildren<PostProcessVolume>();
				scoreboardPanel.SetActive(value: false);
			}
			mainUIPanel.SetActive(value: false);
			if ((bool)Run.instance)
			{
				gameModeUiInstance = Run.instance.InstantiateUi(gameModeUiRoot);
			}
		}

		private void OnDestroy()
		{
			if ((bool)Run.instance)
			{
				Run.instance.UnregisterUi(gameModeUiInstance);
			}
		}

		public void Update()
		{
			NetworkUser networkUser = ((!targetMaster) ? null : targetMaster.GetComponent<PlayerCharacterMasterController>()?.networkUser);
			PlayerCharacterMasterController playerCharacterMasterController = (targetMaster ? targetMaster.GetComponent<PlayerCharacterMasterController>() : null);
			Inventory inventory = (targetMaster ? targetMaster.inventory : null);
			GameObject gameObject = targetBodyObject;
			CharacterBody characterBody = (gameObject ? gameObject.GetComponent<CharacterBody>() : null);
			if ((bool)healthBar && (bool)targetBodyObject && gameObject != oldTarget)
			{
				healthBar.source = targetBodyObject.GetComponent<HealthComponent>();
				healthBar.InitializeHealthBar();
			}
			oldTarget = gameObject;
			if ((bool)expBar)
			{
				expBar.source = targetMaster;
			}
			if ((bool)levelText)
			{
				levelText.source = characterBody;
			}
			if ((bool)moneyText)
			{
				moneyText.targetValue = (int)(targetMaster ? targetMaster.money : 0);
			}
			if ((bool)lunarCoinContainer)
			{
				bool flag = localUserViewer != null && localUserViewer.userProfile.totalCollectedCoins != 0;
				uint targetValue = (networkUser ? networkUser.lunarCoins : 0u);
				lunarCoinContainer.SetActive(flag);
				if (flag && (bool)lunarCoinText)
				{
					lunarCoinText.targetValue = (int)targetValue;
				}
			}
			if ((bool)voidCoinContainer)
			{
				int num = (int)(targetMaster ? targetMaster.voidCoins : 0);
				bool flag2 = num > 0;
				voidCoinContainer.SetActive(flag2);
				if (flag2 && (bool)voidCoinText)
				{
					voidCoinText.targetValue = num;
				}
			}
			if ((bool)itemInventoryDisplay)
			{
				itemInventoryDisplay.SetSubscribedInventory(inventory);
			}
			if ((bool)targetBodyObject)
			{
				SkillLocator component = targetBodyObject.GetComponent<SkillLocator>();
				if ((bool)component)
				{
					if (skillIcons.Length != 0 && (bool)skillIcons[0])
					{
						skillIcons[0].targetSkillSlot = SkillSlot.Primary;
						skillIcons[0].targetSkill = component.primary;
						skillIcons[0].playerCharacterMasterController = playerCharacterMasterController;
					}
					if (skillIcons.Length > 1 && (bool)skillIcons[1])
					{
						skillIcons[1].targetSkillSlot = SkillSlot.Secondary;
						skillIcons[1].targetSkill = component.secondary;
						skillIcons[1].playerCharacterMasterController = playerCharacterMasterController;
					}
					if (skillIcons.Length > 2 && (bool)skillIcons[2])
					{
						skillIcons[2].targetSkillSlot = SkillSlot.Utility;
						skillIcons[2].targetSkill = component.utility;
						skillIcons[2].playerCharacterMasterController = playerCharacterMasterController;
					}
					if (skillIcons.Length > 3 && (bool)skillIcons[3])
					{
						skillIcons[3].targetSkillSlot = SkillSlot.Special;
						skillIcons[3].targetSkill = component.special;
						skillIcons[3].playerCharacterMasterController = playerCharacterMasterController;
					}
				}
			}
			EquipmentIcon[] array = equipmentIcons;
			foreach (EquipmentIcon obj in array)
			{
				obj.targetInventory = inventory;
				obj.targetEquipmentSlot = (targetBodyObject ? targetBodyObject.GetComponent<EquipmentSlot>() : null);
				obj.playerCharacterMasterController = (targetMaster ? targetMaster.GetComponent<PlayerCharacterMasterController>() : null);
			}
			if ((bool)buffDisplay)
			{
				buffDisplay.SetSource(characterBody);
			}
			if ((bool)allyCardManager)
			{
				allyCardManager.sourceGameObject = targetBodyObject;
			}
			if ((bool)scoreboardPanel)
			{
				bool flag3 = localUserViewer.userProfile.useToggleScoreboard || shouldForceScoreboardToggle;
				bool flag4 = localUserViewer != null && localUserViewer.inputPlayer != null && localUserViewer.inputPlayer.GetButton("info");
				if (((flag4 && localUserViewer.inputPlayer.GetButtonDown("info")) || !flag3) && (bool)targetBodyObject)
				{
					bool activeSelf = scoreboardPanel.activeSelf;
					bool flag5 = (flag3 ? (!activeSelf) : flag4);
					if (flag5 != activeSelf && !PauseManager.PauseScreenIsOpen())
					{
						SetScoreboardState(flag5);
					}
				}
			}
			if ((bool)speedometer)
			{
				speedometer.targetTransform = (targetBodyObject ? targetBodyObject.transform : null);
			}
			if ((bool)combatHealthBarViewer)
			{
				combatHealthBarViewer.viewerBody = characterBody;
				combatHealthBarViewer.viewerBodyObject = targetBodyObject;
				combatHealthBarViewer.viewerTeamIndex = TeamComponent.GetObjectTeam(targetBodyObject);
			}
			if ((object)targetBodyObject != previousTargetBodyObject)
			{
				previousTargetBodyObject = targetBodyObject;
				HUD.onHudTargetChangedGlobal?.Invoke(this);
			}
			int j = 0;
			for (int num2 = base.transform.childCount - 1; j < num2; j++)
			{
				base.transform.GetChild(j).gameObject.SetActive(value: false);
			}
			if (base.transform.childCount > 0)
			{
				base.transform.GetChild(base.transform.childCount - 1).gameObject.SetActive(value: true);
			}
			UpdateHudVisibility();
		}

		public void SetScoreboardState(bool newState)
		{
			if (newState != scoreboardPanel.activeSelf)
			{
				if (newState)
				{
					ActivateScoreboard();
				}
				else
				{
					DeactivateScoreboard();
				}
			}
		}

		public void ActivateScoreboard()
		{
			PauseManager.ClosePauseScreen(shouldResume: false);
			scoreboardPanel.SetActive(value: true);
			scoreboardPanel.GetComponent<ScoreboardController>()?.SelectFirstScoreboardStrip();
			if (!localUserViewer.userProfile.useInspectFeature)
			{
				return;
			}
			InteractionDriver component = targetBodyObject.GetComponent<InteractionDriver>();
			if (!(component.currentInteractable != null))
			{
				return;
			}
			IInspectable component2 = component.currentInteractable.GetComponent<IInspectable>();
			if (component2 != null)
			{
				IInspectInfoProvider inspectInfoProvider = component2.GetInspectInfoProvider();
				if (inspectInfoProvider != null && inspectInfoProvider.CanBeInspected())
				{
					inspectPanelController.Show(component2.GetInspectInfoProvider().GetInfo(), WithSidecar: true);
				}
			}
		}

		public void DeactivateScoreboard()
		{
			scoreboardPanel.SetActive(value: false);
			if (RoR2Application.isInSinglePlayer)
			{
				EScoreboardDeactivateReturnContext eScoreboardDeactivateReturnContext = scoreboardDeactivateReturnContext;
				if (eScoreboardDeactivateReturnContext != 0 && eScoreboardDeactivateReturnContext == EScoreboardDeactivateReturnContext.Pause)
				{
					PauseManager.TogglePauseScreen();
				}
				else
				{
					PauseStopController.instance?.Pause(shouldPause: false);
				}
			}
			else if ((bool)PauseStopController.instance && PauseStopController.instance.isPaused)
			{
				switch (scoreboardDeactivateReturnContext)
				{
				case EScoreboardDeactivateReturnContext.Pause:
					PauseManager.TogglePauseScreen();
					break;
				case EScoreboardDeactivateReturnContext.Game:
					PauseManager.OpenMinimalPauseScreen();
					break;
				}
			}
			scoreboardDeactivateReturnContext = EScoreboardDeactivateReturnContext.Game;
			shouldForceScoreboardToggle = false;
		}

		private void UpdateHudVisibility()
		{
			if (mainContainer.activeInHierarchy)
			{
				bool shouldDisplay = cameraRigController?.isHudAllowed ?? false;
				HUD.shouldHudDisplay?.Invoke(this, ref shouldDisplay);
				bool flag = cvHudEnable.value && shouldDisplay;
				if (mainUIPanel.activeSelf != flag)
				{
					mainUIPanel.SetActive(flag);
				}
			}
		}
	}
	public class HUDBossHealthBarController : MonoBehaviour
	{
		public HUD hud;

		public GameObject container;

		public UnityEngine.UI.Image fillRectImage;

		public UnityEngine.UI.Image delayRectImage;

		public SpriteAsNumberManager spriteAsNumberManager;

		public TextMeshProUGUI healthLabel;

		public TextMeshProUGUI bossNameLabel;

		public TextMeshProUGUI bossSubtitleLabel;

		private BossGroup currentBossGroup;

		private BossGroup oldBossGroup;

		private float delayedTotalHealthFraction;

		private float healthFractionVelocity;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		public Material healthMaterial;

		public Material delayMaterial;

		private HealthBar.BarInfo healthInfo;

		private HealthBar.BarInfo oldHealthInfo;

		private HealthBar.BarInfo delayInfo;

		private HealthBar.BarInfo oldDelayInfo;

		private int oldTotalHealth;

		private int oldTotalMaxHealth;

		private bool wasActive;

		private bool firstFrame;

		private string oldname = "";

		private string oldsub = "";

		private Run.TimeStamp nextAllowedSourceUpdateTime = Run.TimeStamp.negativeInfinity;

		private bool listeningForClientDamageNotified;

		private void Start()
		{
			if ((bool)healthLabel)
			{
				healthLabel.gameObject.SetActive(value: true);
			}
			if ((bool)spriteAsNumberManager)
			{
				spriteAsNumberManager.gameObject.SetActive(value: false);
			}
		}

		private void Update()
		{
			List<BossGroup> instancesList = InstanceTracker.GetInstancesList<BossGroup>();
			int num = 0;
			for (int i = 0; i < instancesList.Count; i++)
			{
				if (instancesList[i].shouldDisplayHealthBarOnHud)
				{
					num++;
				}
			}
			SetListeningForClientDamageNotified(num > 1);
			if ((bool)currentBossGroup && !currentBossGroup.shouldDisplayHealthBarOnHud)
			{
				currentBossGroup = null;
			}
			if (num > 0)
			{
				if (num != 1 && (bool)currentBossGroup)
				{
					return;
				}
				for (int j = 0; j < instancesList.Count; j++)
				{
					if (instancesList[j].shouldDisplayHealthBarOnHud)
					{
						currentBossGroup = instancesList[j];
						break;
					}
				}
			}
			else
			{
				currentBossGroup = null;
			}
		}

		private void OnEnable()
		{
			healthInfo = default(HealthBar.BarInfo);
			oldHealthInfo = default(HealthBar.BarInfo);
			healthInfo.normalizedXMin = 0f;
			oldHealthInfo.normalizedXMin = -1f;
			healthInfo.enabled = true;
			healthInfo.sprite = (oldHealthInfo.sprite = fillRectImage.sprite);
			delayInfo = default(HealthBar.BarInfo);
			oldDelayInfo = default(HealthBar.BarInfo);
			delayInfo.normalizedXMin = 0f;
			oldDelayInfo.normalizedXMin = -1f;
			delayInfo.sprite = (oldDelayInfo.sprite = delayRectImage.sprite);
			delayInfo.enabled = true;
			oldBossGroup = null;
			oldname = "";
			oldsub = "";
		}

		private void OnDisable()
		{
			SetListeningForClientDamageNotified(newListeningForClientDamageNotified: false);
		}

		private void OnClientDamageNotified(DamageDealtMessage damageDealtMessage)
		{
			if (!nextAllowedSourceUpdateTime.hasPassed || !damageDealtMessage.victim)
			{
				return;
			}
			CharacterBody component = damageDealtMessage.victim.GetComponent<CharacterBody>();
			if ((bool)component && component.isBoss && (object)damageDealtMessage.attacker == hud.targetBodyObject)
			{
				BossGroup bossGroup = BossGroup.FindBossGroup(component);
				if ((bool)bossGroup && bossGroup.shouldDisplayHealthBarOnHud)
				{
					currentBossGroup = bossGroup;
					nextAllowedSourceUpdateTime = Run.TimeStamp.now + 1f;
				}
			}
		}

		private void SetListeningForClientDamageNotified(bool newListeningForClientDamageNotified)
		{
			if (newListeningForClientDamageNotified != listeningForClientDamageNotified)
			{
				listeningForClientDamageNotified = newListeningForClientDamageNotified;
				if (listeningForClientDamageNotified)
				{
					GlobalEventManager.onClientDamageNotified += OnClientDamageNotified;
				}
				else
				{
					GlobalEventManager.onClientDamageNotified -= OnClientDamageNotified;
				}
			}
		}

		private void SetRectPosition(RectTransform rectTransform, float xMin, float xMax, float sizeDelta)
		{
			rectTransform.anchorMin = new UnityEngine.Vector2(xMin, 0f);
			rectTransform.anchorMax = new UnityEngine.Vector2(xMax, 1f);
			rectTransform.anchoredPosition = UnityEngine.Vector2.zero;
			rectTransform.sizeDelta = new UnityEngine.Vector2(sizeDelta * 0.5f + 1f, sizeDelta + 1f);
		}

		private void ApplyBars()
		{
			HandleBar(fillRectImage, ref healthInfo, ref oldHealthInfo);
			HandleBar(delayRectImage, ref delayInfo, ref oldDelayInfo);
			static void HandleBar(UnityEngine.UI.Image image, ref HealthBar.BarInfo barInfo, ref HealthBar.BarInfo oldInfo)
			{
				if (barInfo.enabled != image.gameObject.activeInHierarchy)
				{
					image.gameObject.SetActive(barInfo.enabled);
				}
				if (barInfo.enabled)
				{
					if (!oldInfo.DimsEqual(barInfo))
					{
						oldInfo.SetDims(barInfo);
						image.fillAmount = barInfo.normalizedXMax;
					}
					if (barInfo.normalizedXMin != oldInfo.normalizedXMin)
					{
						oldInfo.normalizedXMin = barInfo.normalizedXMin;
					}
					if (barInfo.normalizedXMax != oldInfo.normalizedXMax)
					{
						oldInfo.normalizedXMax = barInfo.normalizedXMax;
					}
				}
			}
		}

		private void LateUpdate()
		{
			bool flag = (bool)currentBossGroup && currentBossGroup.totalObservedHealth > 0f;
			if (wasActive != flag || !firstFrame)
			{
				container.SetActive(flag);
				wasActive = flag;
				oldname = "";
				oldsub = "";
				firstFrame = true;
			}
			if (flag)
			{
				float totalObservedHealth = currentBossGroup.totalObservedHealth;
				float totalMaxObservedMaxHealth = currentBossGroup.totalMaxObservedMaxHealth;
				float num = ((totalMaxObservedMaxHealth == 0f) ? 0f : Mathf.Clamp01(totalObservedHealth / totalMaxObservedMaxHealth));
				delayedTotalHealthFraction = Mathf.Clamp(Mathf.SmoothDamp(delayedTotalHealthFraction, num, ref healthFractionVelocity, 0.1f, float.PositiveInfinity, Time.deltaTime), num, 1f);
				healthInfo.normalizedXMax = num;
				delayInfo.normalizedXMax = delayedTotalHealthFraction;
				ApplyBars();
				int num2 = Mathf.FloorToInt(totalObservedHealth);
				int num3 = Mathf.FloorToInt(totalMaxObservedMaxHealth);
				if (num2 != oldTotalHealth || num3 != oldTotalMaxHealth)
				{
					oldTotalHealth = num2;
					oldTotalMaxHealth = num3;
					sharedStringBuilder.Clear().AppendInt(Mathf.FloorToInt(totalObservedHealth)).Append("/")
						.AppendInt(Mathf.FloorToInt(totalMaxObservedMaxHealth));
					healthLabel.SetText(sharedStringBuilder);
				}
				if (oldname.Length != currentBossGroup.bestObservedName.Length || oldsub.Length != currentBossGroup.bestObservedSubtitle.Length)
				{
					oldname = currentBossGroup.bestObservedName;
					oldsub = currentBossGroup.bestObservedSubtitle;
					oldBossGroup = currentBossGroup;
					bossNameLabel.SetText(currentBossGroup.bestObservedName);
					bossSubtitleLabel.SetText(currentBossGroup.bestObservedSubtitle);
				}
			}
		}
	}
	[DisallowMultipleComponent]
	public class HudElement : MonoBehaviour
	{
		private HUD _hud;

		private GameObject _targetBodyObject;

		private CharacterBody _targetCharacterBody;

		public HUD hud
		{
			get
			{
				return _hud;
			}
			set
			{
				_hud = value;
				if ((bool)_hud)
				{
					targetBodyObject = _hud.targetBodyObject;
				}
				else
				{
					targetBodyObject = null;
				}
			}
		}

		public GameObject targetBodyObject
		{
			get
			{
				return _targetBodyObject;
			}
			set
			{
				_targetBodyObject = value;
				if ((bool)_targetBodyObject)
				{
					_targetCharacterBody = _targetBodyObject.GetComponent<CharacterBody>();
				}
			}
		}

		public CharacterBody targetCharacterBody
		{
			get
			{
				return _targetCharacterBody;
			}
			set
			{
				_targetCharacterBody = value;
				if ((bool)targetCharacterBody)
				{
					_targetBodyObject = targetCharacterBody.gameObject;
				}
			}
		}
	}
	public class HudObjectiveTargetSetter : MonoBehaviour
	{
		public ObjectivePanelController objectivePanelController;

		private HUD hud;

		private void OnEnable()
		{
			hud = GetComponentInParent<HUD>();
		}

		private void Update()
		{
			if ((bool)hud && (bool)objectivePanelController)
			{
				objectivePanelController.SetCurrentMaster(hud.targetMaster);
			}
		}
	}
	public class HUDScaleController : MonoBehaviour
	{
		private class HUDScaleConVar : BaseConVar
		{
			public static HUDScaleConVar instance = new HUDScaleConVar("hud_scale", ConVarFlags.Archive, "100", "Scales the size of HUD elements in-game. Defaults to 100.");

			private int intValue;

			private HUDScaleConVar(string name, ConVarFlags flags, string defaultValue, string helpText)
				: base(name, flags, defaultValue, helpText)
			{
			}

			public override void SetString(string newValue)
			{
				if (!TextSerialization.TryParseInvariant(newValue, out int result) || result == 0)
				{
					return;
				}
				intValue = result;
				foreach (HUDScaleController instances in instancesList)
				{
					instances.SetScale();
				}
			}

			public override string GetString()
			{
				return TextSerialization.ToStringInvariant(intValue);
			}
		}

		public RectTransform[] rectTransforms;

		private static List<HUDScaleController> instancesList = new List<HUDScaleController>();

		public void OnEnable()
		{
			instancesList.Add(this);
		}

		public void OnDisable()
		{
			instancesList.Remove(this);
		}

		private void Start()
		{
			SetScale();
		}

		private void SetScale()
		{
			BaseConVar baseConVar = Console.instance.FindConVar("hud_scale");
			if (baseConVar != null && TextSerialization.TryParseInvariant(baseConVar.GetString(), out float result))
			{
				UnityEngine.Vector3 localScale = new UnityEngine.Vector3(result / 100f, result / 100f, result / 100f);
				RectTransform[] array = rectTransforms;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].localScale = localScale;
				}
			}
		}
	}
	public class HUDSpeedometer : MonoBehaviour
	{
		public TextMeshProUGUI label;

		public TextMeshProUGUI fixedUpdateLabel;

		private Transform _targetTransform;

		private UnityEngine.Vector3 lastTargetPosition;

		private UnityEngine.Vector3 lastTargetPositionFixedUpdate;

		public Transform targetTransform
		{
			get
			{
				return _targetTransform;
			}
			set
			{
				if (!(_targetTransform == value))
				{
					_targetTransform = value;
					if ((bool)_targetTransform)
					{
						lastTargetPosition = _targetTransform.position;
						lastTargetPositionFixedUpdate = _targetTransform.position;
					}
				}
			}
		}

		private float EstimateSpeed(ref UnityEngine.Vector3 oldPosition, UnityEngine.Vector3 newPosition, float deltaTime)
		{
			float result = 0f;
			if (deltaTime != 0f)
			{
				result = (newPosition - oldPosition).magnitude / deltaTime;
			}
			oldPosition = newPosition;
			return result;
		}

		private void Update()
		{
			if ((bool)_targetTransform)
			{
				float num = EstimateSpeed(ref lastTargetPosition, _targetTransform.position, Time.deltaTime);
				label.text = $"{num:0.00} m/s";
			}
		}

		private void FixedUpdate()
		{
			if ((bool)_targetTransform)
			{
				float num = EstimateSpeed(ref lastTargetPositionFixedUpdate, _targetTransform.position, Time.deltaTime);
				fixedUpdateLabel.text = $"{num:0.00} m/s";
			}
		}
	}
	[RequireComponent(typeof(HUD))]
	public class HUDTutorialController : MonoBehaviour
	{
		private HUD hud;

		[Tooltip("The tutorial popup object.")]
		[Header("Equipment Tutorial")]
		public GameObject equipmentTutorialObject;

		[Tooltip("The equipment icon to monitor for a change to trigger the tutorial popup.")]
		public EquipmentIcon equipmentIcon;

		[Tooltip("The tutorial popup object.")]
		[Header("Sprint Tutorial")]
		public GameObject sprintTutorialObject;

		[Tooltip("How long to wait for the player to sprint before showing the tutorial popup.")]
		public float sprintTutorialTriggerTime = 30f;

		private float sprintTutorialStopwatch;

		private void Awake()
		{
			hud = GetComponent<HUD>();
			if ((bool)equipmentTutorialObject)
			{
				equipmentTutorialObject.SetActive(value: false);
			}
			if ((bool)sprintTutorialObject)
			{
				sprintTutorialObject.SetActive(value: false);
			}
		}

		private UserProfile GetUserProfile()
		{
			if ((bool)hud && hud.localUserViewer != null)
			{
				return hud.localUserViewer.userProfile;
			}
			return null;
		}

		private void HandleTutorial(GameObject tutorialPopup, ref UserProfile.TutorialProgression tutorialProgression, bool dismiss = false, bool progress = true)
		{
			if ((bool)tutorialPopup && !dismiss)
			{
				tutorialPopup.SetActive(value: true);
			}
			tutorialProgression.shouldShow = false;
			if (progress)
			{
				tutorialProgression.showCount++;
			}
		}

		private void Update()
		{
			if (!hud || hud.localUserViewer == null)
			{
				return;
			}
			UserProfile userProfile = GetUserProfile();
			CharacterBody cachedBody = hud.localUserViewer.cachedBody;
			if (userProfile == null || !cachedBody)
			{
				return;
			}
			if (userProfile.tutorialEquipment.shouldShow && equipmentIcon.hasEquipment)
			{
				HandleTutorial(equipmentTutorialObject, ref userProfile.tutorialEquipment);
			}
			if (userProfile.tutorialSprint.shouldShow)
			{
				if (cachedBody.isSprinting)
				{
					HandleTutorial(null, ref userProfile.tutorialSprint, dismiss: true);
					return;
				}
				if (cachedBody.GetComponent<EntityStateMachine>()?.state is GenericCharacterMain)
				{
					sprintTutorialStopwatch += Time.deltaTime;
				}
				if (sprintTutorialStopwatch >= sprintTutorialTriggerTime)
				{
					HandleTutorial(sprintTutorialObject, ref userProfile.tutorialSprint, dismiss: false, progress: false);
				}
			}
			else if ((bool)sprintTutorialObject && sprintTutorialObject.activeInHierarchy && cachedBody.isSprinting)
			{
				UnityEngine.Object.Destroy(sprintTutorialObject);
				sprintTutorialObject = null;
				userProfile.tutorialSprint.showCount++;
			}
		}
	}
	public class ImageFillController : MonoBehaviour
	{
		[SerializeField]
		private UnityEngine.UI.Image[] images;

		[SerializeField]
		private float fillScalar;

		public void OnEnable()
		{
			SetTValue(0f);
		}

		public void SetTValue(float t)
		{
			float fillAmount = fillScalar * t;
			UnityEngine.UI.Image[] array = images;
			foreach (UnityEngine.UI.Image image in array)
			{
				if ((bool)image)
				{
					image.fillAmount = fillAmount;
				}
			}
		}
	}
	public class InfiniteTowerEnemyCounter : MonoBehaviour
	{
		[Tooltip("The root we're toggling")]
		[SerializeField]
		private GameObject rootObject;

		[SerializeField]
		[Tooltip("The text we're setting")]
		private TextMeshProUGUI counterText;

		[Tooltip("The language token for the text field")]
		[SerializeField]
		private string token;

		private InfiniteTowerWaveController waveController;

		private CombatSquad combatSquad;

		private string counterTextString;

		private bool wasActive;

		private int oldMemberCount = -1;

		private void OnEnable()
		{
			InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun;
			if ((bool)infiniteTowerRun)
			{
				waveController = infiniteTowerRun.waveController;
				if ((bool)waveController)
				{
					combatSquad = waveController.GetComponent<CombatSquad>();
					if ((bool)combatSquad)
					{
						rootObject.SetActive(waveController.HasFullProgress() && combatSquad.memberCount > 0);
					}
					else
					{
						rootObject.SetActive(value: false);
					}
				}
				else
				{
					rootObject.SetActive(value: false);
				}
			}
			counterTextString = Language.GetString(token);
		}

		private void Update()
		{
			if ((bool)combatSquad)
			{
				int memberCount = combatSquad.memberCount;
				bool flag = waveController.HasFullProgress() && combatSquad.memberCount > 0;
				if (flag != wasActive)
				{
					rootObject.SetActive(flag);
					wasActive = flag;
				}
				if (flag && (bool)counterText && memberCount != oldMemberCount)
				{
					oldMemberCount = memberCount;
					string arg = memberCount.ToString();
					counterText.text = string.Format(counterTextString, arg);
				}
			}
		}
	}
	public class InfiniteTowerTimeCounter : MonoBehaviour
	{
		[Tooltip("The root we're toggling")]
		[SerializeField]
		private GameObject rootObject;

		[Tooltip("The timer we're setting")]
		[SerializeField]
		private TimerText timerText;

		[SerializeField]
		private Animator animator;

		[SerializeField]
		private UnityEngine.UI.Image barImage;

		[Tooltip("The sound we loop while the timer is active")]
		[SerializeField]
		private LoopSoundDef timerLoop;

		[Tooltip("The sound we play on each second above criticalSecondsThreshold")]
		[SerializeField]
		private string onSecondRegularSound;

		[Tooltip("The sound we play on each second below criticalSecondsThreshold")]
		[SerializeField]
		private string onSecondCriticalSound;

		[Tooltip("Below this number of seconds remaining, we are 'critical'")]
		[SerializeField]
		private float criticalSecondsThreshold;

		private InfiniteTowerWaveController waveController;

		private bool wasTimerActive;

		private LoopSoundManager.SoundLoopPtr loopPtr;

		private void OnEnable()
		{
			InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun;
			if ((bool)infiniteTowerRun)
			{
				waveController = infiniteTowerRun.waveController;
			}
		}

		private void OnDisable()
		{
			LoopSoundManager.StopSoundLoopLocal(loopPtr);
		}

		private void Update()
		{
			if ((bool)waveController)
			{
				bool flag = waveController.secondsRemaining <= 0f;
				bool flag2 = waveController.isTimerActive;
				InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun;
				if ((bool)infiniteTowerRun && infiniteTowerRun.IsStageTransitionWave())
				{
					flag2 = false;
				}
				if (flag && loopPtr.isValid)
				{
					LoopSoundManager.StopSoundLoopLocal(loopPtr);
				}
				rootObject.SetActive(flag2 && !flag);
				if ((bool)animator && !wasTimerActive && flag2)
				{
					int layerIndex = animator.GetLayerIndex("Base");
					animator.Play("Idle", layerIndex);
					animator.Update(0f);
					animator.Play("Finish", layerIndex);
				}
				wasTimerActive = flag2;
				if (flag2)
				{
					if ((bool)timerText)
					{
						if ((bool)timerLoop && !loopPtr.isValid && waveController.secondsRemaining > 0f)
						{
							loopPtr = LoopSoundManager.PlaySoundLoopLocal(base.gameObject, timerLoop);
						}
						int num = Mathf.FloorToInt((float)timerText.seconds);
						int num2 = Mathf.FloorToInt(waveController.secondsRemaining);
						if (num != num2)
						{
							if (waveController.secondsRemaining < criticalSecondsThreshold)
							{
								Util.PlaySound(onSecondRegularSound, RoR2Application.instance.gameObject);
							}
							else
							{
								Util.PlaySound(onSecondCriticalSound, RoR2Application.instance.gameObject);
							}
						}
						timerText.seconds = waveController.secondsRemaining;
					}
					if ((bool)barImage)
					{
						barImage.fillAmount = waveController.secondsRemaining / (float)waveController.secondsAfterWave;
					}
				}
				else if (loopPtr.isValid)
				{
					LoopSoundManager.StopSoundLoopLocal(loopPtr);
				}
			}
			else
			{
				rootObject.SetActive(value: false);
			}
		}
	}
	public class InfiniteTowerWaveCounter : MonoBehaviour
	{
		[Tooltip("The text we're setting")]
		[SerializeField]
		private TextMeshProUGUI counterText;

		[Tooltip("The language token for the text field")]
		[SerializeField]
		private string token;

		private InfiniteTowerRun runInstance;

		private string counterTextString;

		private int oldWaveIndex = -1;

		private void OnEnable()
		{
			runInstance = Run.instance as InfiniteTowerRun;
			counterTextString = Language.GetString(token);
		}

		private void Update()
		{
			if ((bool)runInstance && (bool)counterText && runInstance.waveIndex != oldWaveIndex)
			{
				oldWaveIndex = runInstance.waveIndex;
				counterText.text = string.Format(counterTextString, runInstance.waveIndex);
			}
		}
	}
	public class InfiniteTowerWaveProgressBar : MonoBehaviour
	{
		[SerializeField]
		[Tooltip("The bar we're filling up")]
		private UnityEngine.UI.Image barImage;

		[SerializeField]
		private Animator animator;

		private InfiniteTowerWaveController waveController;

		private float previousFillAmount;

		private void OnEnable()
		{
			InfiniteTowerRun infiniteTowerRun = Run.instance as InfiniteTowerRun;
			if ((bool)infiniteTowerRun)
			{
				waveController = infiniteTowerRun.waveController;
			}
		}

		private void Update()
		{
			if (!waveController)
			{
				return;
			}
			float normalizedProgress = waveController.GetNormalizedProgress();
			if (normalizedProgress > previousFillAmount)
			{
				previousFillAmount = normalizedProgress;
				if ((bool)animator)
				{
					int layerIndex = animator.GetLayerIndex("Base");
					animator.Play("Idle", layerIndex);
					animator.Update(0f);
					animator.Play((normalizedProgress >= 1f) ? "Ready" : "Pulse", layerIndex);
				}
				if ((bool)barImage)
				{
					barImage.fillAmount = normalizedProgress;
				}
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class InfiniteTowerMenuController : MonoBehaviour
	{
		[SerializeField]
		private LanguageTextMeshController survivorNameText;

		[SerializeField]
		private LanguageTextMeshController easyHighestWaveText;

		[SerializeField]
		private LanguageTextMeshController normalHighestWaveText;

		[SerializeField]
		private LanguageTextMeshController hardHighestWaveText;

		private LocalUser localUser;

		private MPEventSystemLocator eventSystemLocator;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private void OnEnable()
		{
			UserProfile.onSurvivorPreferenceChangedGlobal += OnSurvivorPreferenceChangedGlobal;
			eventSystemLocator.onEventSystemDiscovered += OnEventSystemDiscovered;
			if ((bool)eventSystemLocator.eventSystem)
			{
				OnEventSystemDiscovered(eventSystemLocator.eventSystem);
			}
		}

		private void OnDisable()
		{
			eventSystemLocator.onEventSystemDiscovered -= OnEventSystemDiscovered;
			UserProfile.onSurvivorPreferenceChangedGlobal -= OnSurvivorPreferenceChangedGlobal;
			localUser = null;
		}

		private void OnSurvivorPreferenceChangedGlobal(UserProfile userProfile)
		{
			UpdateDisplayedSurvivor();
		}

		public void BeginGamemode()
		{
			Console.instance.SubmitCmd(null, "transition_command \"gamemode InfiniteTowerRun; host 0;\"");
		}

		public void SetDisplayedSurvivor(SurvivorDef newSurvivorDef)
		{
			_ = (bool)newSurvivorDef;
		}

		private void OnEventSystemDiscovered(MPEventSystem eventSystem)
		{
			localUser = eventSystem.localUser;
			UpdateDisplayedSurvivor();
		}

		private void UpdateDisplayedSurvivor()
		{
			UserProfile userProfile = eventSystemLocator.eventSystem?.localUser?.userProfile;
			if (userProfile != null)
			{
				StatSheet statSheet = userProfile.statSheet;
				SurvivorDef survivorPreference = userProfile.GetSurvivorPreference();
				if ((bool)survivorPreference)
				{
					string bodyName = BodyCatalog.GetBodyName(SurvivorCatalog.GetBodyIndexFromSurvivorIndex(survivorPreference.survivorIndex));
					SetHighestWaveDisplay(easyHighestWaveText, PerBodyStatDef.highestInfiniteTowerWaveReachedEasy, statSheet, bodyName);
					SetHighestWaveDisplay(normalHighestWaveText, PerBodyStatDef.highestInfiniteTowerWaveReachedNormal, statSheet, bodyName);
					SetHighestWaveDisplay(hardHighestWaveText, PerBodyStatDef.highestInfiniteTowerWaveReachedHard, statSheet, bodyName);
				}
				if ((bool)survivorNameText)
				{
					survivorNameText.token = survivorPreference.displayNameToken;
				}
			}
		}

		private void SetHighestWaveDisplay(LanguageTextMeshController text, PerBodyStatDef statDef, StatSheet statSheet, string bodyName)
		{
			ulong statValueULong = statSheet.GetStatValueULong(statDef, bodyName);
			text.formatArgs = new object[1] { statValueULong };
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class InputBindingControl : MonoBehaviour
	{
		public string actionName;

		public AxisRange axisRange;

		public LanguageTextMeshController nameLabel;

		public InputBindingDisplayController bindingDisplay;

		public MPEventSystem.InputSource inputSource;

		public MPButton button;

		private MPEventSystemLocator eventSystemLocator;

		private InputAction action;

		private InputMapperHelper inputMapperHelper;

		private Player currentPlayer;

		private float buttonReactivationTime;

		private bool isListening => inputMapperHelper.isListening;

		public void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			bindingDisplay.actionName = actionName;
			bindingDisplay.useExplicitInputSource = true;
			bindingDisplay.explicitInputSource = inputSource;
			bindingDisplay.axisRange = axisRange;
			nameLabel.token = InputCatalog.GetActionNameToken(actionName, axisRange);
			action = ReInput.mapping.GetAction(actionName);
		}

		public void ToggleListening()
		{
			if (!isListening)
			{
				StartListening();
			}
			else
			{
				StopListening();
			}
		}

		public void StartListening()
		{
			if (!button.IsInteractable())
			{
				return;
			}
			inputMapperHelper.Stop();
			currentPlayer = eventSystemLocator.eventSystem?.localUser?.inputPlayer;
			if (currentPlayer != null)
			{
				IList<Controller> controllers = null;
				switch (inputSource)
				{
				case MPEventSystem.InputSource.MouseAndKeyboard:
					controllers = new Controller[2]
					{
						currentPlayer.controllers.Keyboard,
						currentPlayer.controllers.Mouse
					};
					break;
				case MPEventSystem.InputSource.Gamepad:
					controllers = currentPlayer.controllers.Joysticks.ToArray();
					break;
				}
				inputMapperHelper.Start(currentPlayer, controllers, action, axisRange);
				if ((bool)button)
				{
					button.interactable = false;
				}
			}
		}

		private void StopListening()
		{
			if (currentPlayer != null)
			{
				currentPlayer = null;
				inputMapperHelper.Stop();
			}
		}

		private void OnEnable()
		{
			if (!eventSystemLocator.eventSystem)
			{
				base.enabled = false;
			}
			else
			{
				inputMapperHelper = eventSystemLocator.eventSystem.inputMapperHelper;
			}
		}

		private void OnDisable()
		{
			StopListening();
		}

		private void Update()
		{
			if (!button)
			{
				return;
			}
			if (!(eventSystemLocator?.eventSystem))
			{
				UnityEngine.Debug.LogError("MPEventSystem is invalid.");
				return;
			}
			bool flag = !eventSystemLocator.eventSystem.inputMapperHelper.isListening;
			if (!flag)
			{
				buttonReactivationTime = Time.unscaledTime + 0.25f;
			}
			button.interactable = flag && buttonReactivationTime <= Time.unscaledTime;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class InputSourceFilter : MonoBehaviour
	{
		public MPEventSystem.InputSource requiredInputSource;

		public GameObject[] objectsToFilter;

		private MPEventSystemLocator eventSystemLocator;

		private bool wasOn;

		protected MPEventSystem eventSystem => eventSystemLocator?.eventSystem;

		private void Start()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			Refresh(forceRefresh: true);
		}

		private void Update()
		{
			Refresh();
		}

		private void OnEnable()
		{
			Refresh(forceRefresh: true);
		}

		private IEnumerator RefreshFilteredObjects_Coroutine()
		{
			yield return null;
			if ((bool)eventSystemLocator && (bool)eventSystemLocator.eventSystem)
			{
				eventSystemLocator.eventSystem.RefreshControlGlyphs();
			}
			for (int i = 0; i < objectsToFilter.Length; i++)
			{
				MPEventSystemLocator[] componentsInChildren = objectsToFilter[i].gameObject.GetComponentsInChildren<MPEventSystemLocator>();
				foreach (MPEventSystemLocator mPEventSystemLocator in componentsInChildren)
				{
					if (mPEventSystemLocator.eventSystem != null)
					{
						mPEventSystemLocator.eventSystem.RefreshControlGlyphs();
					}
				}
			}
		}

		private void Refresh(bool forceRefresh = false)
		{
			if (eventSystem == null)
			{
				UnityEngine.Debug.LogWarningFormat("InputSourceFilter.Refresh: Null eventSystem on {0}", base.gameObject.name);
			}
			bool flag = eventSystem?.currentInputSource == requiredInputSource;
			if (flag != wasOn || forceRefresh)
			{
				for (int i = 0; i < objectsToFilter.Length; i++)
				{
					objectsToFilter[i].SetActive(flag);
				}
			}
			if (forceRefresh || (flag && !wasOn))
			{
				StartCoroutine(RefreshFilteredObjects_Coroutine());
			}
			wasOn = flag;
		}
	}
	[Serializable]
	public class InspectInfo
	{
		public Sprite Visual;

		public string TitleToken;

		public string DescriptionToken;

		public string FlavorToken;

		public UnityEngine.Color TitleColor = UnityEngine.Color.white;

		public bool isConsumedItem;

		[NonSerialized]
		public bool isDynamicInspectInfo;

		[NonSerialized]
		public PickupIndex dynamicInspectPickupIndex;

		public bool ForceShowInfo { get; private set; }

		private InspectInfo()
		{
		}

		public static implicit operator InspectInfo(PickupDef fromPickup)
		{
			if (fromPickup != null)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(fromPickup.itemIndex);
				if (itemDef != null)
				{
					return itemDef;
				}
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(fromPickup.equipmentIndex);
				if (equipmentDef != null)
				{
					return equipmentDef;
				}
				MiscPickupDef miscDef = MiscPickupCatalog.GetMiscDef(fromPickup.miscPickupIndex);
				if (miscDef != null)
				{
					return miscDef;
				}
			}
			return new InspectInfo();
		}

		public static implicit operator InspectInfo(ItemDef fromItem)
		{
			return new InspectInfo
			{
				Visual = fromItem.pickupIconSprite,
				TitleToken = fromItem.nameToken,
				DescriptionToken = fromItem.descriptionToken,
				FlavorToken = fromItem.loreToken,
				TitleColor = ColorCatalog.GetColor(ItemTierCatalog.GetItemTierDef(fromItem.tier)?.colorIndex ?? ColorCatalog.ColorIndex.Tier1Item),
				isDynamicInspectInfo = true,
				dynamicInspectPickupIndex = PickupCatalog.FindPickupIndex(fromItem.itemIndex),
				isConsumedItem = fromItem.isConsumed
			};
		}

		public static implicit operator InspectInfo(EquipmentDef fromEquip)
		{
			return new InspectInfo
			{
				Visual = fromEquip.pickupIconSprite,
				TitleToken = fromEquip.nameToken,
				DescriptionToken = fromEquip.descriptionToken,
				FlavorToken = fromEquip.loreToken,
				TitleColor = ColorCatalog.GetColor(fromEquip.colorIndex),
				isDynamicInspectInfo = true,
				dynamicInspectPickupIndex = PickupCatalog.FindPickupIndex(fromEquip.equipmentIndex),
				isConsumedItem = fromEquip.isConsumed
			};
		}

		public static implicit operator InspectInfo(MiscPickupDef fromMisc)
		{
			return new InspectInfo
			{
				Visual = fromMisc.visual,
				TitleToken = fromMisc.nameToken,
				DescriptionToken = fromMisc.descriptionToken,
				TitleColor = ColorCatalog.GetColor(fromMisc.darkColor)
			};
		}

		public static implicit operator InspectInfo(InspectDef fromDef)
		{
			if (fromDef != null)
			{
				return fromDef.Info;
			}
			return null;
		}

		public void MarkForceShowInfo()
		{
			ForceShowInfo = true;
		}
	}
	public class InspectPanelController : MonoBehaviour
	{
		[SerializeField]
		private GameObject InspectPanel;

		[SerializeField]
		private UnityEngine.UI.Image InspectVisual;

		[SerializeField]
		private LanguageTextMeshController InspectTitle;

		[SerializeField]
		private TMP_Text InspectTitleText;

		[SerializeField]
		private LanguageTextMeshController InspectDescription;

		[SerializeField]
		private LanguageTextMeshController InspectFlavor;

		[SerializeField]
		private GameObject Sidecar;

		[SerializeField]
		private UnityEngine.UI.Image SidecarInspectImage;

		[SerializeField]
		private List<ItemDef> TestItems;

		[SerializeField]
		private bool isAutopauseCandidate;

		public InspectDef MissingInspectDefFallback;

		public InspectDef UnknownItemDefOverride;

		private InspectInfo SidecarStoredInfo;

		private MPEventSystem eventSystem;

		private void Awake()
		{
			if ((bool)InspectPanel)
			{
				InspectPanel.SetActive(value: false);
			}
			if ((bool)Sidecar)
			{
				Sidecar.SetActive(value: false);
			}
			MPEventSystemLocator component = GetComponent<MPEventSystemLocator>();
			eventSystem = component.eventSystem;
		}

		public void Show(InspectInfo ToShow, bool WithSidecar = false)
		{
			if (eventSystem == null)
			{
				MPEventSystemLocator component = GetComponent<MPEventSystemLocator>();
				eventSystem = component.eventSystem;
			}
			InspectPanel.SetActive(value: false);
			if (ToShow == null)
			{
				ToShow = MissingInspectDefFallback;
			}
			if (ToShow.isConsumedItem)
			{
				ToShow.MarkForceShowInfo();
			}
			if (ToShow.isDynamicInspectInfo && !ToShow.ForceShowInfo && !eventSystem.localUser.userProfile.HasDiscoveredPickup(ToShow.dynamicInspectPickupIndex))
			{
				ToShow.TitleToken = UnknownItemDefOverride.Info.TitleToken;
				ToShow.DescriptionToken = UnknownItemDefOverride.Info.DescriptionToken;
				ToShow.FlavorToken = UnknownItemDefOverride.Info.FlavorToken;
			}
			InspectVisual.sprite = (ToShow.Visual ? ToShow.Visual : MissingInspectDefFallback.Info.Visual);
			InspectTitle.token = ((ToShow.TitleToken.Length > 0) ? ToShow.TitleToken : MissingInspectDefFallback.Info.TitleToken);
			InspectTitleText.color = ToShow.TitleColor;
			if (InspectDescription != null)
			{
				InspectDescription.token = ((ToShow.DescriptionToken.Length > 0) ? ToShow.DescriptionToken : MissingInspectDefFallback.Info.DescriptionToken);
			}
			if (InspectFlavor != null)
			{
				InspectFlavor.token = ((ToShow.FlavorToken.Length > 0) ? ToShow.FlavorToken : MissingInspectDefFallback.Info.FlavorToken);
			}
			InspectPanel.SetActive(value: true);
			if ((bool)Sidecar && (bool)SidecarInspectImage && WithSidecar)
			{
				SidecarStoredInfo = ToShow;
				Sidecar.SetActive(value: true);
				SidecarInspectImage.sprite = ToShow.Visual;
				eventSystem.SetSelectedObject(Sidecar.GetComponentInChildren<HGButton>().gameObject);
			}
			bool useInspectAutopause = eventSystem.localUser.userProfile.useInspectAutopause;
			if (isAutopauseCandidate && useInspectAutopause && RoR2Application.isInSinglePlayer)
			{
				PauseStopController.instance?.Pause(shouldPause: true);
			}
		}

		public void DisplaySidecarInfo()
		{
			Show(SidecarStoredInfo, WithSidecar: true);
		}

		private void OnDisable()
		{
			OnCloseButtonClicked();
		}

		public void ForceEnableInspectPanel()
		{
			if (InspectPanel != null)
			{
				InspectPanel.SetActive(value: true);
			}
		}

		public void OnCloseButtonClicked()
		{
			InspectPanel.SetActive(value: false);
		}
	}
	public class InspectPanelLocator : MonoBehaviour
	{
		public InspectPanelController InspectPanel { get; private set; }

		private void Awake()
		{
			InspectPanel = GetComponentInParent<InspectPanelProvider>().InspectPanel;
		}
	}
	public class InspectPanelProvider : MonoBehaviour
	{
		[SerializeField]
		private InspectPanelController _inspectPanel;

		public InspectPanelController InspectPanel => _inspectPanel;
	}
	[RequireComponent(typeof(RectTransform))]
	public class ItemIcon : MonoBehaviour
	{
		private InspectPanelLocator inspectPanelLocator;

		private UserProfile userProfile;

		public RawImage glowImage;

		public RawImage image;

		public TextMeshProUGUI stackText;

		public SpriteAsNumberManager spriteAsNumberManager;

		public TooltipProvider tooltipProvider;

		private ItemIndex itemIndex;

		private int itemCount;

		public Action OnItemClicked;

		public RectTransform rectTransform { get; private set; }

		public InspectPanelController inspectPanel
		{
			get
			{
				if ((bool)inspectPanelLocator)
				{
					return inspectPanelLocator.InspectPanel;
				}
				return null;
			}
		}

		private void Awake()
		{
			CacheRectTransform();
			inspectPanelLocator = GetComponent<InspectPanelLocator>();
			userProfile = GetComponentInParent<HUD>().localUserViewer.userProfile;
		}

		public void CacheRectTransform()
		{
			if ((object)rectTransform == null)
			{
				rectTransform = (RectTransform)base.transform;
			}
		}

		public void SetItemIndex(ItemIndex newItemIndex, int newItemCount)
		{
			if (itemIndex == newItemIndex && itemCount == newItemCount)
			{
				return;
			}
			itemIndex = newItemIndex;
			itemCount = newItemCount;
			string titleToken = "";
			string bodyToken = "";
			UnityEngine.Color titleColor = UnityEngine.Color.white;
			UnityEngine.Color bodyColor = new UnityEngine.Color(0.6f, 0.6f, 0.6f, 1f);
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if (itemDef != null)
			{
				image.texture = itemDef.pickupIconTexture;
				if (itemCount > 1)
				{
					spriteAsNumberManager.SetItemCount(itemCount);
				}
				else
				{
					spriteAsNumberManager.SetVisible(b: false);
				}
				titleToken = itemDef.nameToken;
				bodyToken = itemDef.pickupToken;
				titleColor = ColorCatalog.GetColor(itemDef.darkColorIndex);
			}
			if ((bool)glowImage)
			{
				glowImage.color = new UnityEngine.Color(titleColor.r, titleColor.g, titleColor.b, 0.75f);
			}
			if ((bool)tooltipProvider)
			{
				tooltipProvider.titleToken = titleToken;
				tooltipProvider.bodyToken = bodyToken;
				tooltipProvider.titleColor = titleColor;
				tooltipProvider.bodyColor = bodyColor;
			}
		}

		public void ItemClicked()
		{
			if (!userProfile.useInspectFeature)
			{
				return;
			}
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if (itemDef != null)
			{
				if ((bool)inspectPanel)
				{
					inspectPanel.Show(itemDef);
				}
				OnItemClicked?.Invoke();
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class ItemInventoryDisplay : UIBehaviour, ILayoutElement
	{
		private struct LayoutValues
		{
			public float width;

			public float height;

			public float iconSize;

			public int iconsPerRow;

			public float rowWidth;

			public int rowCount;

			public UnityEngine.Vector3 iconLocalScale;

			public UnityEngine.Vector3 topLeftCorner;
		}

		private RectTransform rectTransform;

		public GameObject itemIconPrefab;

		[FormerlySerializedAs("iconWidth")]
		public float itemIconPrefabWidth = 64f;

		public float maxIconWidth = 64f;

		public float maxHeight = 128f;

		public float verticalMargin = 8f;

		[SerializeField]
		[HideInInspector]
		private List<ItemIcon> itemIcons;

		private ItemIndex[] itemOrder;

		private int itemOrderCount;

		private int[] itemStacks;

		private float currentIconScale = 1f;

		private float previousWidth;

		private bool updateRequestPending;

		[SerializeField]
		private UnityEvent onItemClicked;

		private Inventory inventory;

		private bool inventoryWasValid;

		private MPEventSystemLocator eventSystemLocator;

		private bool isUninitialized => (object)rectTransform == null;

		public MPEventSystem eventSystem => eventSystemLocator.eventSystem;

		public float minWidth => preferredWidth;

		public float preferredWidth => rectTransform.rect.width;

		public float flexibleWidth => 0f;

		public float minHeight => preferredHeight;

		public float preferredHeight { get; set; }

		public float flexibleHeight => 0f;

		public int layoutPriority => 0;

		public void SetSubscribedInventory([CanBeNull] Inventory newInventory)
		{
			if ((object)inventory != newInventory || (bool)inventory != inventoryWasValid)
			{
				if ((object)inventory != null)
				{
					inventory.onInventoryChanged -= OnInventoryChanged;
					inventory = null;
				}
				inventory = newInventory;
				inventoryWasValid = inventory;
				if ((bool)inventory)
				{
					inventory.onInventoryChanged += OnInventoryChanged;
				}
				OnInventoryChanged();
			}
		}

		private void OnInventoryChanged()
		{
			if (base.isActiveAndEnabled)
			{
				if ((bool)inventory)
				{
					inventory.WriteItemStacks(itemStacks);
					inventory.itemAcquisitionOrder.CopyTo(itemOrder);
					itemOrderCount = inventory.itemAcquisitionOrder.Count;
				}
				else
				{
					Array.Clear(itemStacks, 0, itemStacks.Length);
					itemOrderCount = 0;
				}
				RequestUpdateDisplay();
			}
		}

		public int GetTotalVisibleItemCount()
		{
			int num = 0;
			for (int i = 0; i < itemStacks.Length; i++)
			{
				if (ItemIsVisible((ItemIndex)i))
				{
					num += itemStacks[i];
				}
			}
			return num;
		}

		private static bool ItemIsVisible(ItemIndex itemIndex)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
			if (itemDef != null)
			{
				return !itemDef.hidden;
			}
			return false;
		}

		private void AllocateIcons(int desiredItemCount)
		{
			if (desiredItemCount != itemIcons.Count)
			{
				while (itemIcons.Count > desiredItemCount)
				{
					UnityEngine.Object.Destroy(itemIcons[itemIcons.Count - 1].gameObject);
					itemIcons.RemoveAt(itemIcons.Count - 1);
				}
				CalculateLayoutValues(out var v, desiredItemCount);
				while (itemIcons.Count < desiredItemCount)
				{
					ItemIcon component = UnityEngine.Object.Instantiate(itemIconPrefab, rectTransform).GetComponent<ItemIcon>();
					itemIcons.Add(component);
					component.OnItemClicked = (Action)Delegate.Combine(component.OnItemClicked, (Action)delegate
					{
						onItemClicked?.Invoke();
					});
					LayoutIndividualIcon(in v, itemIcons.Count - 1);
				}
			}
			OnIconCountChanged();
		}

		private float CalculateIconScale(int iconCount)
		{
			int num = (int)rectTransform.rect.width;
			int num2 = (int)maxHeight;
			int num3 = (int)itemIconPrefabWidth;
			int num4 = num3;
			int num5 = num3 / 8;
			int num6 = Math.Max(num / num4, 1);
			int num7 = HGMath.IntDivCeil(iconCount, num6);
			while (num4 * num7 > num2)
			{
				num6++;
				num4 = Math.Min(num / num6, num3);
				num7 = HGMath.IntDivCeil(iconCount, num6);
				if (num4 <= num5)
				{
					num4 = num5;
					break;
				}
			}
			num4 = Math.Min(num4, (int)maxIconWidth);
			return (float)num4 / (float)num3;
		}

		private void OnIconCountChanged()
		{
			float num = CalculateIconScale(itemIcons.Count);
			if (num != currentIconScale)
			{
				currentIconScale = num;
				OnIconScaleChanged();
			}
		}

		private void OnIconScaleChanged()
		{
			LayoutAllIcons();
		}

		private void CalculateLayoutValues(out LayoutValues v, int iconCount)
		{
			float num = CalculateIconScale(itemIcons.Count);
			UnityEngine.Rect rect = rectTransform.rect;
			v.width = rect.width;
			v.iconSize = itemIconPrefabWidth * num;
			v.iconsPerRow = Math.Max((int)v.width / (int)v.iconSize, 1);
			v.rowWidth = (float)v.iconsPerRow * v.iconSize;
			float num2 = (v.width - v.rowWidth) * 0.5f;
			v.rowCount = HGMath.IntDivCeil(itemIcons.Count, v.iconsPerRow);
			v.iconLocalScale = new UnityEngine.Vector3(num, num, 1f);
			v.topLeftCorner = new UnityEngine.Vector3(rect.xMin + num2, rect.yMax - verticalMargin);
			v.height = v.iconSize * (float)v.rowCount + verticalMargin * 2f;
		}

		private void LayoutAllIcons()
		{
			CalculateLayoutValues(out var v, itemIcons.Count);
			int num = itemIcons.Count - (v.rowCount - 1) * v.iconsPerRow;
			int i = 0;
			int num2 = 0;
			for (; i < v.rowCount; i++)
			{
				UnityEngine.Vector3 topLeftCorner = v.topLeftCorner;
				topLeftCorner.y += (float)i * (0f - v.iconSize);
				int num3 = v.iconsPerRow;
				if (i == v.rowCount - 1)
				{
					num3 = num;
				}
				int num4 = 0;
				while (num4 < num3)
				{
					RectTransform obj = itemIcons[num2].rectTransform;
					obj.localScale = v.iconLocalScale;
					obj.localPosition = topLeftCorner;
					topLeftCorner.x += v.iconSize;
					num4++;
					num2++;
				}
			}
		}

		private void LayoutIndividualIcon(in LayoutValues layoutValues, int i)
		{
			int num = i / layoutValues.iconsPerRow;
			int num2 = i - num * layoutValues.iconsPerRow;
			UnityEngine.Vector3 topLeftCorner = layoutValues.topLeftCorner;
			topLeftCorner.x += (float)num2 * layoutValues.iconSize;
			topLeftCorner.y += (float)num * (0f - layoutValues.iconSize);
			RectTransform obj = itemIcons[i].rectTransform;
			obj.localPosition = topLeftCorner;
			obj.localScale = layoutValues.iconLocalScale;
		}

		private void CacheComponents()
		{
			rectTransform = (RectTransform)base.transform;
		}

		protected override void Awake()
		{
			base.Awake();
			CacheComponents();
			itemStacks = ItemCatalog.RequestItemStackArray();
			itemOrder = ItemCatalog.RequestItemOrderBuffer();
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		protected override void OnDestroy()
		{
			SetSubscribedInventory(null);
			ItemCatalog.ReturnItemStackArray(itemStacks);
			itemStacks = null;
			ItemCatalog.ReturnItemOrderBuffer(itemOrder);
			itemOrder = null;
			base.OnDestroy();
		}

		protected override void OnEnable()
		{
			base.OnEnable();
			if ((bool)inventory)
			{
				OnInventoryChanged();
			}
			RequestUpdateDisplay();
			LayoutAllIcons();
		}

		private void RequestUpdateDisplay()
		{
			if (!updateRequestPending)
			{
				updateRequestPending = true;
				RoR2Application.onNextUpdate += UpdateDisplay;
			}
		}

		public void UpdateDisplay()
		{
			updateRequestPending = false;
			if (!this || !base.isActiveAndEnabled)
			{
				return;
			}
			ItemIndex[] array = ItemCatalog.RequestItemOrderBuffer();
			int num = 0;
			for (int i = 0; i < itemOrderCount; i++)
			{
				if (ItemIsVisible(itemOrder[i]))
				{
					array[num++] = itemOrder[i];
				}
			}
			AllocateIcons(num);
			for (int j = 0; j < num; j++)
			{
				ItemIndex itemIndex = array[j];
				itemIcons[j].SetItemIndex(itemIndex, itemStacks[(int)itemIndex]);
			}
			ItemCatalog.ReturnItemOrderBuffer(array);
		}

		public void SetItems(List<ItemIndex> newItemOrder, int[] newItemStacks)
		{
			itemOrderCount = newItemOrder.Count;
			for (int i = 0; i < itemOrderCount; i++)
			{
				itemOrder[i] = newItemOrder[i];
			}
			Array.Copy(newItemStacks, itemStacks, itemStacks.Length);
			RequestUpdateDisplay();
		}

		public void SetItems(ItemIndex[] newItemOrder, int newItemOrderCount, int[] newItemStacks)
		{
			itemOrderCount = newItemOrderCount;
			Array.Copy(newItemOrder, itemOrder, itemOrderCount);
			Array.Copy(newItemStacks, itemStacks, itemStacks.Length);
			RequestUpdateDisplay();
		}

		public void ResetItems()
		{
			itemOrderCount = 0;
			Array.Clear(itemStacks, 0, itemStacks.Length);
			RequestUpdateDisplay();
		}

		protected override void OnRectTransformDimensionsChange()
		{
			base.OnRectTransformDimensionsChange();
			if ((bool)rectTransform)
			{
				float width = rectTransform.rect.width;
				if (width != previousWidth)
				{
					previousWidth = width;
					LayoutAllIcons();
				}
			}
		}

		public void CalculateLayoutInputHorizontal()
		{
		}

		public void CalculateLayoutInputVertical()
		{
			if (!isUninitialized)
			{
				CalculateLayoutValues(out var v, itemIcons.Count);
				preferredHeight = v.height;
			}
		}

		protected void OnValidate()
		{
			CacheComponents();
		}

		public bool SelectFirstItemIcon()
		{
			if (itemIcons.Count > 0)
			{
				eventSystem.SetSelectedObject(itemIcons[0].gameObject);
				return true;
			}
			return false;
		}

		public int GetItemCount()
		{
			return itemOrderCount;
		}
	}
	public class LanguageDropdownController : MonoBehaviour
	{
		public MPDropdown dropdown;

		public GameObject stripPrefab;

		private Language[] languages = Array.Empty<Language>();

		private bool isProvidingPlatformOption;

		public void Awake()
		{
			dropdown.onValueChanged.AddListener(OnDropdownValueChanged);
		}

		private void OnEnable()
		{
			SetupDropdownOptions();
		}

		private void SetupDropdownOptions()
		{
			dropdown.ClearOptions();
			languages = Language.GetAllLanguages().ToArray();
			string @string = Language.LanguageConVar.instance.GetString();
			List<TMP_Dropdown.OptionData> list = new List<TMP_Dropdown.OptionData>(languages.Length + 1);
			int num = -1;
			int num2 = -1;
			Language language = Language.FindLanguageByName(Language.GetPlatformLanguageName() ?? "");
			isProvidingPlatformOption = language != null;
			if (isProvidingPlatformOption)
			{
				list.Add(new TMP_Dropdown.OptionData(Language.GetStringFormatted("LANGUAGE_PLATFORM", language.selfName), language.iconSprite));
				num2++;
				if (@string == "platform")
				{
					num = num2;
				}
			}
			for (int i = 0; i < languages.Length; i++)
			{
				num2++;
				Language language2 = languages[i];
				list.Add(new TMP_Dropdown.OptionData(language2.selfName, language2.iconSprite));
				if (Language.currentLanguage == language2)
				{
					num = num2;
				}
			}
			dropdown.AddOptions(list);
			if (num != -1)
			{
				dropdown.SetValueWithoutNotify(num);
			}
		}

		private void OnDropdownValueChanged(int value)
		{
			if (isProvidingPlatformOption)
			{
				if (value == 0)
				{
					Language.LanguageConVar.instance.SetString("platform");
					return;
				}
				value--;
			}
			Language safe = ArrayUtils.GetSafe(languages, value);
			if (safe != null)
			{
				Language.LanguageConVar.instance.SetString(safe.name);
			}
		}
	}
	public class LanguageTextMeshController : MonoBehaviour
	{
		[SerializeField]
		private string _token;

		private string previousToken;

		private string resolvedString;

		private TMP_Text textMeshPro;

		private object[] _formatArgs = Array.Empty<object>();

		public string token
		{
			get
			{
				return _token;
			}
			set
			{
				if (value != previousToken)
				{
					_token = value;
					ResolveString();
					UpdateLabel();
				}
			}
		}

		public object[] formatArgs
		{
			get
			{
				return _formatArgs;
			}
			set
			{
				_formatArgs = value;
				ResolveString();
				UpdateLabel();
			}
		}

		private void OnEnable()
		{
			ResolveString();
			UpdateLabel();
		}

		public void ResolveString()
		{
			previousToken = _token;
			if (formatArgs.Length == 0)
			{
				resolvedString = Language.GetString(_token);
			}
			else
			{
				resolvedString = Language.GetStringFormatted(_token, formatArgs);
			}
		}

		private void CacheComponents()
		{
			textMeshPro = GetComponent<TMP_Text>();
			if (!textMeshPro)
			{
				textMeshPro = GetComponentInChildren<TMP_Text>();
			}
		}

		private void Awake()
		{
			CacheComponents();
		}

		private void OnValidate()
		{
			CacheComponents();
		}

		private void Start()
		{
		}

		private void UpdateLabel()
		{
			if ((bool)textMeshPro)
			{
				textMeshPro.text = resolvedString;
			}
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			Language.onCurrentLanguageChanged += OnCurrentLanguageChanged;
		}

		private static void OnCurrentLanguageChanged()
		{
			LanguageTextMeshController[] array = UnityEngine.Object.FindObjectsOfType<LanguageTextMeshController>();
			foreach (LanguageTextMeshController obj in array)
			{
				obj.ResolveString();
				obj.UpdateLabel();
			}
		}
	}
	public class LeaderboardController : MonoBehaviour
	{
		public GameObject stripPrefab;

		public RectTransform container;

		public GameObject noEntryObject;

		public AnimateImageAlpha animateImageAlpha;

		public RequestType currentRequestType;

		public int entriesPerPage = 16;

		public MPButton nextPageButton;

		public MPButton previousPageButton;

		public MPButton resetPageButton;

		private WeeklyRunScreenController weeklyRunScreenController;

		private LeaderboardManager _currentLeaderboardManager;

		private List<LeaderboardStrip> stripList = new List<LeaderboardStrip>();

		private List<LeaderboardInfo> leaderboardInfoList = new List<LeaderboardInfo>();

		private bool isRequestQueued;

		public bool IsValid => CurrentLeaderboardManager?.IsValid ?? false;

		public bool IsQuerying => CurrentLeaderboardManager?.IsQuerying ?? false;

		public LeaderboardManager CurrentLeaderboardManager
		{
			get
			{
				if (_currentLeaderboardManager == null)
				{
					_currentLeaderboardManager = new SteamLeaderboardManager(this);
				}
				return _currentLeaderboardManager;
			}
		}

		public string currentLeaderboardName { get; private set; }

		public int currentPage { get; private set; }

		private void Update()
		{
			if (CurrentLeaderboardManager != null && CurrentLeaderboardManager.IsValid && !CurrentLeaderboardManager.IsQuerying && isRequestQueued)
			{
				leaderboardInfoList = CurrentLeaderboardManager.GetLeaderboardInfoList();
				Rebuild();
				isRequestQueued = false;
			}
			if ((bool)noEntryObject)
			{
				noEntryObject.SetActive(leaderboardInfoList.Count == 0);
			}
		}

		private void SetStripCount(int newCount)
		{
			while (stripList.Count > newCount)
			{
				UnityEngine.Object.Destroy(stripList[stripList.Count - 1].gameObject);
				stripList.RemoveAt(stripList.Count - 1);
			}
			while (stripList.Count < newCount)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(stripPrefab, container);
				stripList.Add(gameObject.GetComponent<LeaderboardStrip>());
			}
		}

		private void Rebuild()
		{
			int num = Mathf.Min(leaderboardInfoList.Count, entriesPerPage);
			SetStripCount(entriesPerPage);
			for (int i = 0; i < num; i++)
			{
				LeaderboardInfo leaderboardInfo = leaderboardInfoList[i];
				int num2 = Mathf.FloorToInt(leaderboardInfo.timeInSeconds / 60f);
				float num3 = leaderboardInfo.timeInSeconds - (float)(num2 * 60);
				string text = $"{num2:0}:{num3:00.00}";
				LeaderboardStrip leaderboardStrip = stripList[i];
				leaderboardStrip.rankLabel.text = leaderboardInfo.rank.ToString();
				leaderboardStrip.usernameLabel.userId = CurrentLeaderboardManager.GetUserID(leaderboardInfo);
				leaderboardStrip.timeLabel.text = text;
				leaderboardStrip.classIcon.enabled = true;
				if (leaderboardInfo.survivorIndex.HasValue)
				{
					leaderboardStrip.classIcon.texture = SurvivorCatalog.GetSurvivorPortrait(leaderboardInfo.survivorIndex.Value);
				}
				else
				{
					leaderboardStrip.classIcon.enabled = false;
				}
				leaderboardStrip.isMeImage.enabled = string.CompareOrdinal(leaderboardInfo.userID, CurrentLeaderboardManager.GetLocalUserIdString()) == 0;
				leaderboardStrip.usernameLabel.Refresh();
			}
			for (int j = num; j < entriesPerPage; j++)
			{
				stripList[j].rankLabel.text = "";
				stripList[j].usernameLabel.userId = new PlatformID(0uL);
				stripList[j].timeLabel.text = "";
				stripList[j].classIcon.enabled = false;
				stripList[j].isMeImage.enabled = false;
				stripList[j].usernameLabel.Refresh();
			}
		}

		public void SetRequestedInfo(string newLeaderboardName, RequestType newRequestType, int newPage)
		{
			bool flag = currentLeaderboardName != newLeaderboardName;
			if (flag)
			{
				currentLeaderboardName = newLeaderboardName;
				CurrentLeaderboardManager.UpdateLeaderboard();
				newPage = 0;
			}
			bool flag2 = currentRequestType != newRequestType || flag;
			bool flag3 = currentPage != newPage || flag;
			if (flag2)
			{
				currentRequestType = newRequestType;
			}
			if (flag3)
			{
				currentPage = newPage;
			}
			isRequestQueued = flag || flag2 || flag3;
		}

		private void GenerateFakeLeaderboardList(int count)
		{
			leaderboardInfoList.Clear();
			for (int i = 1; i <= count; i++)
			{
				LeaderboardInfo item = default(LeaderboardInfo);
				item.userID = "76561197995890564";
				item.survivorIndex = (SurvivorIndex)UnityEngine.Random.Range(0, SurvivorCatalog.survivorCount - 1);
				item.timeInSeconds = UnityEngine.Random.Range(120f, 600f);
				leaderboardInfoList.Add(item);
			}
		}

		public void SetRequestType(string requestTypeName)
		{
			if (Enum.TryParse<RequestType>(requestTypeName, ignoreCase: false, out var result))
			{
				currentRequestType = result;
			}
		}

		private void SetRequestedInfoAsync(RequestType type)
		{
		}

		public void SetRequestedInfoProcessAsync(LeaderboardInfo[] leaderboardScores)
		{
		}

		private void OrderLeaderboardListByTime(ref List<LeaderboardInfo> leaderboardInfoList)
		{
			leaderboardInfoList.Sort(SortByTime);
		}

		private static int SortByTime(LeaderboardInfo p1, LeaderboardInfo p2)
		{
			return p1.timeInSeconds.CompareTo(p2.timeInSeconds);
		}
	}
	public class LeaderboardStrip : MonoBehaviour
	{
		public TextMeshProUGUI rankLabel;

		public SteamUsernameLabel usernameLabel;

		public RawImage classIcon;

		public UnityEngine.UI.Image isMeImage;

		public TextMeshProUGUI timeLabel;
	}
	[RequireComponent(typeof(RectTransform))]
	public class LerpUIRect : MonoBehaviour
	{
		public enum LerpState
		{
			Entering,
			Holding,
			Leaving
		}

		public UnityEngine.Vector3 startLocalPosition;

		public UnityEngine.Vector3 finalLocalPosition;

		public LerpState lerpState;

		public AnimationCurve enterCurve;

		public float enterDuration;

		public AnimationCurve leavingCurve;

		public float leaveDuration;

		private float stopwatch;

		private RectTransform rectTransform;

		private void Start()
		{
			rectTransform = GetComponent<RectTransform>();
		}

		private void OnDisable()
		{
			lerpState = LerpState.Entering;
			stopwatch = 0f;
			UpdateLerp();
		}

		private void Update()
		{
			stopwatch += Time.deltaTime;
			UpdateLerp();
		}

		private void UpdateLerp()
		{
			switch (lerpState)
			{
			case LerpState.Entering:
			{
				float num = stopwatch / enterDuration;
				float t = enterCurve.Evaluate(num);
				rectTransform.anchoredPosition = UnityEngine.Vector3.LerpUnclamped(startLocalPosition, finalLocalPosition, t);
				if (num >= 1f)
				{
					lerpState = LerpState.Holding;
					stopwatch = 0f;
				}
				break;
			}
			case LerpState.Leaving:
			{
				float num = stopwatch / enterDuration;
				float t = leavingCurve.Evaluate(num);
				rectTransform.anchoredPosition = UnityEngine.Vector3.LerpUnclamped(finalLocalPosition, startLocalPosition, t);
				if (num >= 1f)
				{
					lerpState = LerpState.Holding;
					stopwatch = 0f;
				}
				break;
			}
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class LevelText : MonoBehaviour
	{
		public CharacterBody source;

		public TextMeshProUGUI targetText;

		private uint displayData;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		private void SetDisplayData(uint newDisplayData)
		{
			if (displayData != newDisplayData)
			{
				displayData = newDisplayData;
				uint value = displayData;
				sharedStringBuilder.Clear();
				sharedStringBuilder.AppendUint(value);
				targetText.SetText(sharedStringBuilder);
			}
		}

		private void Update()
		{
			if ((bool)source)
			{
				SetDisplayData(HG.Convert.FloorToUIntClamped(source.level));
			}
		}

		private void OnValidate()
		{
			if (!targetText)
			{
				UnityEngine.Debug.LogError("targetText must be assigned.");
			}
		}
	}
	[RequireComponent(typeof(HudElement))]
	[RequireComponent(typeof(RectTransform))]
	public class LoaderHookCrosshairController : MonoBehaviour
	{
		public float range;

		public UnityEvent onAvailable;

		public UnityEvent onUnavailable;

		public UnityEvent onEnterRange;

		public UnityEvent onExitRange;

		private HudElement hudElement;

		private bool isAvailable;

		private bool inRange;

		private void Awake()
		{
			hudElement = GetComponent<HudElement>();
		}

		private void SetAvailable(bool newIsAvailable)
		{
			if (isAvailable != newIsAvailable)
			{
				isAvailable = newIsAvailable;
				(isAvailable ? onAvailable : onUnavailable).Invoke();
			}
		}

		private void SetInRange(bool newInRange)
		{
			if (inRange != newInRange)
			{
				inRange = newInRange;
				(inRange ? onEnterRange : onExitRange)?.Invoke();
			}
		}

		private void Update()
		{
			if (!hudElement.targetCharacterBody)
			{
				SetAvailable(newIsAvailable: false);
				SetInRange(newInRange: false);
				return;
			}
			SetAvailable(hudElement.targetCharacterBody.skillLocator.secondary.CanExecute());
			bool flag = false;
			if (isAvailable)
			{
				flag = hudElement.targetCharacterBody.inputBank.GetAimRaycast(range, out var _);
			}
			SetInRange(flag);
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	[RequireComponent(typeof(RectTransform))]
	public class LoadoutPanelController : MonoBehaviour
	{
		public struct DisplayData : IEquatable<DisplayData>
		{
			public UserProfile userProfile;

			public BodyIndex bodyIndex;

			public bool Equals(DisplayData other)
			{
				if (userProfile == other.userProfile)
				{
					return bodyIndex == other.bodyIndex;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is DisplayData other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((userProfile != null) ? userProfile.GetHashCode() : 0) * 397) ^ (int)bodyIndex;
			}
		}

		private struct RowData
		{
			public MPButton button;

			public int defIndex;

			public RowData(MPButton _button, int _defIndex)
			{
				button = _button;
				defIndex = _defIndex;
			}
		}

		private class Row : IDisposable
		{
			public List<RowData> rowData = new List<RowData>();

			private LoadoutPanelController owner;

			private UserProfile userProfile;

			private RectTransform rowPanelTransform;

			private RectTransform buttonContainerTransform;

			private RectTransform choiceHighlightRect;

			private UnityEngine.Color primaryColor;

			private UnityEngine.Color complementaryColor;

			private Func<Loadout, int> findCurrentChoice;

			private Row(LoadoutPanelController owner, BodyIndex bodyIndex, string titleToken)
			{
				this.owner = owner;
				userProfile = owner.currentDisplayData.userProfile;
				rowPanelTransform = (RectTransform)UnityEngine.Object.Instantiate(rowPrefab, owner.rowContainer).transform;
				buttonContainerTransform = (RectTransform)rowPanelTransform.Find("ButtonContainer");
				choiceHighlightRect = (RectTransform)rowPanelTransform.Find("ButtonSelectionHighlight, Checkbox");
				UserProfile.onLoadoutChangedGlobal += OnLoadoutChangedGlobal;
				SurvivorCatalog.FindSurvivorDefFromBody(BodyCatalog.GetBodyPrefab(bodyIndex));
				CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndex);
				if (bodyPrefabBodyComponent != null)
				{
					primaryColor = bodyPrefabBodyComponent.bodyColor;
				}
				UnityEngine.Color.RGBToHSV(primaryColor, out var H, out var S, out var V);
				H += 0.5f;
				if (H > 1f)
				{
					H -= 1f;
				}
				complementaryColor = UnityEngine.Color.HSVToRGB(H, S, V);
				RectTransform obj = (RectTransform)rowPanelTransform.Find("SlotLabel");
				obj.GetComponent<LanguageTextMeshController>().token = titleToken;
				obj.GetComponent<HGTextMeshProUGUI>().color = primaryColor;
			}

			private void OnLoadoutChangedGlobal(UserProfile userProfile)
			{
				if (userProfile == this.userProfile)
				{
					UpdateHighlightedChoice();
				}
			}

			public static Row FromSkillSlot(LoadoutPanelController owner, BodyIndex bodyIndex, int skillSlotIndex, GenericSkill skillSlot)
			{
				SkillFamily skillFamily = skillSlot.skillFamily;
				SkillLocator component = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndex).GetComponent<SkillLocator>();
				bool addWIPIcons = false;
				string titleToken;
				switch (component.FindSkillSlot(skillSlot))
				{
				case SkillSlot.None:
					titleToken = "LOADOUT_SKILL_MISC";
					addWIPIcons = false;
					break;
				case SkillSlot.Primary:
					titleToken = "LOADOUT_SKILL_PRIMARY";
					addWIPIcons = false;
					break;
				case SkillSlot.Secondary:
					titleToken = "LOADOUT_SKILL_SECONDARY";
					break;
				case SkillSlot.Utility:
					titleToken = "LOADOUT_SKILL_UTILITY";
					break;
				case SkillSlot.Special:
					titleToken = "LOADOUT_SKILL_SPECIAL";
					break;
				default:
					throw new ArgumentOutOfRangeException();
				}
				Row row = new Row(owner, bodyIndex, titleToken);
				for (int i = 0; i < skillFamily.variants.Length; i++)
				{
					ref SkillFamily.Variant reference = ref skillFamily.variants[i];
					uint skillVariantIndexToAssign = (uint)i;
					row.AddButton(owner, reference.skillDef.icon, reference.skillDef.skillNameToken, reference.skillDef.skillDescriptionToken, row.primaryColor, delegate
					{
						Loadout loadout2 = new Loadout();
						row.userProfile.CopyLoadout(loadout2);
						loadout2.bodyLoadoutManager.SetSkillVariant(bodyIndex, skillSlotIndex, skillVariantIndexToAssign);
						row.userProfile.SetLoadout(loadout2);
					}, reference.unlockableDef?.cachedName ?? "", reference.viewableNode, isWIP: false, (int)skillVariantIndexToAssign);
				}
				row.findCurrentChoice = (Loadout loadout) => (int)loadout.bodyLoadoutManager.GetSkillVariant(bodyIndex, skillSlotIndex);
				row.FinishSetup(addWIPIcons);
				return row;
			}

			public static Row FromSkin(LoadoutPanelController owner, BodyIndex bodyIndex)
			{
				Row row = new Row(owner, bodyIndex, "LOADOUT_SKIN");
				LocalUser user = owner.eventSystemLocator.eventSystem?.localUser;
				SkinDef[] bodySkins = BodyCatalog.GetBodySkins(bodyIndex);
				for (int i = 0; i < bodySkins.Length; i++)
				{
					SkinDef skinDef = bodySkins[i];
					if (EntitlementManager.localUserEntitlementTracker.UserHasEntitlementForUnlockable(user, skinDef.unlockableDef))
					{
						uint skinToAssign = (uint)i;
						ViewablesCatalog.Node viewableNode = ViewablesCatalog.FindNode($"/Loadout/Bodies/{BodyCatalog.GetBodyName(bodyIndex)}/Skins/{skinDef.name}");
						row.AddButton(owner, skinDef.icon, skinDef.nameToken, string.Empty, row.primaryColor, delegate
						{
							Loadout loadout2 = new Loadout();
							row.userProfile.CopyLoadout(loadout2);
							loadout2.bodyLoadoutManager.SetSkinIndex(bodyIndex, skinToAssign);
							row.userProfile.SetLoadout(loadout2);
						}, skinDef.unlockableDef?.cachedName ?? "", viewableNode, isWIP: false, i);
					}
				}
				row.findCurrentChoice = (Loadout loadout) => (int)loadout.bodyLoadoutManager.GetSkinIndex(bodyIndex);
				row.FinishSetup();
				return row;
			}

			private void FinishSetup(bool addWIPIcons = false)
			{
				if (addWIPIcons)
				{
					Sprite icon = LegacyResourcesAPI.Load<Sprite>("Textures/MiscIcons/texWIPIcon");
					for (int i = rowData.Count; i < minimumEntriesPerRow; i++)
					{
						AddButton(owner, icon, "TOOLTIP_WIP_CONTENT_NAME", "TOOLTIP_WIP_CONTENT_DESCRIPTION", ColorCatalog.GetColor(ColorCatalog.ColorIndex.WIP), delegate
						{
						}, "", null, isWIP: true);
					}
				}
				RectTransform rectTransform = (RectTransform)rowPanelTransform.Find("ButtonContainer/Spacer");
				if ((bool)rectTransform)
				{
					rectTransform.SetAsLastSibling();
				}
				UpdateHighlightedChoice();
			}

			private void SetButtonColorMultiplier(int i, float f)
			{
				MPButton button = rowData[i].button;
				ColorBlock colors = button.colors;
				colors.colorMultiplier = f;
				button.colors = colors;
			}

			private void UpdateHighlightedChoice()
			{
				Loadout loadout = new Loadout();
				userProfile?.CopyLoadout(loadout);
				int num = findCurrentChoice(loadout);
				for (int i = 0; i < rowData.Count; i++)
				{
					ColorBlock colors = rowData[i].button.colors;
					colors.colorMultiplier = 0.5f;
					rowData[i].button.colors = colors;
					SetButtonColorMultiplier(i, 0.5f);
					if (num == rowData[i].defIndex)
					{
						choiceHighlightRect.SetParent((RectTransform)rowData[i].button.transform, worldPositionStays: false);
						SetButtonColorMultiplier(i, 1f);
					}
				}
			}

			private void AddButton(LoadoutPanelController owner, Sprite icon, string titleToken, string bodyToken, UnityEngine.Color tooltipColor, UnityAction callback, string unlockableName, ViewablesCatalog.Node viewableNode, bool isWIP = false, int defIndex = -1)
			{
				HGButton component = UnityEngine.Object.Instantiate(loadoutButtonPrefab, buttonContainerTransform).GetComponent<HGButton>();
				component.updateTextOnHover = true;
				component.hoverLanguageTextMeshController = owner.hoverTextDescription;
				component.requiredTopLayer = owner.requiredUILayerKey;
				string text = "";
				TooltipProvider component2 = component.GetComponent<TooltipProvider>();
				UserProfile obj = userProfile;
				string @string;
				string text2;
				UnityEngine.Color color;
				if (obj != null && obj.HasUnlockable(unlockableName))
				{
					component.onClick.AddListener(callback);
					component.interactable = true;
					if (viewableNode != null)
					{
						ViewableTag component3 = component.GetComponent<ViewableTag>();
						component3.viewableName = viewableNode.fullName;
						component3.Refresh();
					}
					@string = Language.GetString(titleToken);
					text2 = Language.GetString(bodyToken);
					color = tooltipColor;
				}
				else
				{
					UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(unlockableName);
					icon = lockedIcon;
					component.interactable = true;
					component.disableGamepadClick = true;
					component.disablePointerClick = true;
					@string = Language.GetString("UNIDENTIFIED");
					text2 = unlockableDef.getHowToUnlockString();
					color = UnityEngine.Color.gray;
				}
				if (isWIP)
				{
					component.interactable = false;
				}
				component2.titleColor = color;
				component2.overrideTitleText = @string;
				component2.overrideBodyText = text2;
				color.a = 0.2f;
				text = Language.GetStringFormatted("LOGBOOK_HOVER_DESCRIPTION_FORMAT", @string, text2, ColorUtility.ToHtmlStringRGBA(color));
				component.hoverToken = text;
				((UnityEngine.UI.Image)component.targetGraphic).sprite = icon;
				rowData.Add(new RowData(component, defIndex));
			}

			public void Dispose()
			{
				UserProfile.onLoadoutChangedGlobal -= OnLoadoutChangedGlobal;
				for (int num = rowData.Count - 1; num >= 0; num--)
				{
					UnityEngine.Object.Destroy(rowData[num].button.gameObject);
				}
				UnityEngine.Object.Destroy(rowPanelTransform.gameObject);
			}
		}

		public UILayerKey requiredUILayerKey;

		public LanguageTextMeshController hoverTextDescription;

		private DisplayData currentDisplayData = new DisplayData
		{
			userProfile = null,
			bodyIndex = BodyIndex.None
		};

		private UIElementAllocator<RectTransform> buttonAllocator;

		private readonly List<Row> rows = new List<Row>();

		public static int minimumEntriesPerRow = 2;

		private MPEventSystemLocator eventSystemLocator;

		private UIElementAllocator<RectTransform> rowAllocator;

		private static GameObject loadoutButtonPrefab;

		private static GameObject rowPrefab;

		private static Sprite lockedIcon;

		private RectTransform rowContainer => (RectTransform)base.transform;

		public void SetDisplayData(DisplayData displayData)
		{
			if (!displayData.Equals(currentDisplayData))
			{
				currentDisplayData = displayData;
				Rebuild();
			}
		}

		private void OnEnable()
		{
			UpdateDisplayData();
		}

		private void Update()
		{
			UpdateDisplayData();
		}

		private void UpdateDisplayData()
		{
			UserProfile userProfile = eventSystemLocator.eventSystem?.localUser?.userProfile;
			NetworkUser networkUser = eventSystemLocator.eventSystem?.localUser?.currentNetworkUser;
			BodyIndex bodyIndex = (networkUser ? networkUser.bodyIndexPreference : BodyIndex.None);
			SetDisplayData(new DisplayData
			{
				userProfile = userProfile,
				bodyIndex = bodyIndex
			});
		}

		private void DestroyRows()
		{
			for (int num = rows.Count - 1; num >= 0; num--)
			{
				rows[num].Dispose();
			}
			rows.Clear();
		}

		private void Rebuild()
		{
			DestroyRows();
			CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(currentDisplayData.bodyIndex);
			if (!bodyPrefabBodyComponent)
			{
				return;
			}
			List<GenericSkill> gameObjectComponents = GetComponentsCache<GenericSkill>.GetGameObjectComponents(bodyPrefabBodyComponent.gameObject);
			int i = 0;
			for (int count = gameObjectComponents.Count; i < count; i++)
			{
				GenericSkill skillSlot = gameObjectComponents[i];
				rows.Add(Row.FromSkillSlot(this, currentDisplayData.bodyIndex, i, skillSlot));
			}
			_ = BodyCatalog.GetBodySkins(currentDisplayData.bodyIndex).Length;
			if (true)
			{
				rows.Add(Row.FromSkin(this, currentDisplayData.bodyIndex));
			}
			int count2 = rows.Count;
			for (int j = 0; j < count2; j++)
			{
				int count3 = rows[j].rowData.Count;
				for (int k = 0; k < count3; k++)
				{
					UnityEngine.UI.Navigation navigation = rows[j].rowData[k].button.navigation;
					navigation.mode = UnityEngine.UI.Navigation.Mode.Explicit;
					navigation.selectOnLeft = null;
					navigation.selectOnRight = null;
					navigation.selectOnUp = null;
					navigation.selectOnDown = null;
					if (count3 > 1)
					{
						int index = (k + count3 - 1) % count3;
						navigation.selectOnLeft = rows[j].rowData[index].button;
						int index2 = (k + count3 + 1) % count3;
						navigation.selectOnRight = rows[j].rowData[index2].button;
					}
					if (count2 > 1)
					{
						if (j != 0)
						{
							int num = rows[j - 1].rowData.Count - 1;
							int index3 = ((num < k) ? num : k);
							navigation.selectOnUp = rows[j - 1].rowData[index3].button;
						}
						if (j != count2 - 1)
						{
							int num2 = rows[j + 1].rowData.Count - 1;
							int index4 = ((num2 < k) ? num2 : k);
							navigation.selectOnDown = rows[j + 1].rowData[index4].button;
						}
					}
					rows[j].rowData[k].button.navigation = navigation;
				}
			}
		}

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			EntitlementManager.onEntitlementsUpdated += OnEntitlementsUpdated;
		}

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/UI/Loadout/LoadoutButton");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				loadoutButtonPrefab = x.Result;
			};
			asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/UI/Loadout/Row");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				rowPrefab = x.Result;
			};
			AsyncOperationHandle<Sprite> asyncOperationHandle2 = LegacyResourcesAPI.LoadAsync<Sprite>("Textures/MiscIcons/texUnlockIcon");
			asyncOperationHandle2.Completed += delegate(AsyncOperationHandle<Sprite> x)
			{
				lockedIcon = x.Result;
			};
		}

		private void OnDestroy()
		{
			EntitlementManager.onEntitlementsUpdated -= OnEntitlementsUpdated;
			DestroyRows();
		}

		private void OnEntitlementsUpdated()
		{
			Rebuild();
		}
	}
	public class LobbyUserList : MonoBehaviour
	{
		public struct LobbyStateChoice
		{
			public LobbyType lobbyType;

			public string token;
		}

		public TextMeshProUGUI lobbyStateText;

		public GameObject lobbyControlPanel;

		public GameObject contentArea;

		public RectTransform playerListContainer;

		[Tooltip("The panel which acts as a container for UI that's only valid if there's an active lobby, like the lobby type or the copy-ID-to-clipboard button.")]
		public MPButton createLobbyButton;

		public MPButton leaveLobbyButton;

		public MPButton copyLobbyButton;

		public MPButton joinLobbyButton;

		public MPDropdown lobbyTypeDropdown;

		public bool shouldShowContentAreaByDefault = true;

		public bool isPauseMenu;

		private List<LobbyUserListElement> userList = new List<LobbyUserListElement>();

		public static readonly LobbyStateChoice[] lobbyStateChoices = new LobbyStateChoice[3]
		{
			new LobbyStateChoice
			{
				lobbyType = LobbyType.Private,
				token = "STEAM_LOBBY_PRIVATE"
			},
			new LobbyStateChoice
			{
				lobbyType = LobbyType.FriendsOnly,
				token = "STEAM_LOBBY_FRIENDSONLY"
			},
			new LobbyStateChoice
			{
				lobbyType = LobbyType.Public,
				token = "STEAM_LOBBY_PUBLIC"
			}
		};

		private static readonly List<string> optionsBuffer = new List<string>();

		public int NumberOfParticipants { get; private set; }

		private bool isInLobby => PlatformSystems.lobbyManager.isInLobby;

		private void Awake()
		{
			if (isPauseMenu && !PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.Voice))
			{
				base.gameObject.SetActive(value: false);
			}
			lobbyTypeDropdown.onValueChanged.AddListener(OnLobbyStateDropdownValueChanged);
		}

		private void OnEnable()
		{
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyChanged = (Action)Delegate.Combine(lobbyManager.onLobbyChanged, new Action(OnLobbyChanged));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyDataUpdated = (Action)Delegate.Combine(lobbyManager2.onLobbyDataUpdated, new Action(RebuildPlayers));
			LobbyManager lobbyManager3 = PlatformSystems.lobbyManager;
			lobbyManager3.onLobbyStateChanged = (Action)Delegate.Combine(lobbyManager3.onLobbyStateChanged, new Action(OnLobbyStateChanged));
			LobbyManager lobbyManager4 = PlatformSystems.lobbyManager;
			lobbyManager4.onLobbyMemberDataUpdated = (Action<PlatformID>)Delegate.Combine(lobbyManager4.onLobbyMemberDataUpdated, new Action<PlatformID>(OnLobbyMemberDataUpdated));
			LobbyManager lobbyManager5 = PlatformSystems.lobbyManager;
			lobbyManager5.onPlayerCountUpdated = (Action)Delegate.Combine(lobbyManager5.onPlayerCountUpdated, new Action(RebuildPlayers));
			ToggleMPLobbyFeatures(PlatformSystems.lobbyManager.GetPlatformMPLobbyFeatureFlags());
			if (isPauseMenu)
			{
				if (!isInLobby)
				{
					base.gameObject.SetActive(value: false);
				}
				else
				{
					createLobbyButton.gameObject.SetActive(value: false);
					leaveLobbyButton.gameObject.SetActive(value: false);
					copyLobbyButton.gameObject.SetActive(value: false);
					joinLobbyButton.gameObject.SetActive(value: false);
					lobbyTypeDropdown.gameObject.SetActive(value: false);
					lobbyTypeDropdown.interactable = false;
				}
			}
			RebuildLobbyStateDropdownOptions();
			Refresh();
		}

		private void OnDisable()
		{
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyChanged = (Action)Delegate.Remove(lobbyManager.onLobbyChanged, new Action(OnLobbyChanged));
			LobbyManager lobbyManager2 = PlatformSystems.lobbyManager;
			lobbyManager2.onLobbyDataUpdated = (Action)Delegate.Remove(lobbyManager2.onLobbyDataUpdated, new Action(RebuildPlayers));
			LobbyManager lobbyManager3 = PlatformSystems.lobbyManager;
			lobbyManager3.onLobbyStateChanged = (Action)Delegate.Remove(lobbyManager3.onLobbyStateChanged, new Action(OnLobbyStateChanged));
			LobbyManager lobbyManager4 = PlatformSystems.lobbyManager;
			lobbyManager4.onLobbyMemberDataUpdated = (Action<PlatformID>)Delegate.Remove(lobbyManager4.onLobbyMemberDataUpdated, new Action<PlatformID>(OnLobbyMemberDataUpdated));
			LobbyManager lobbyManager5 = PlatformSystems.lobbyManager;
			lobbyManager5.onPlayerCountUpdated = (Action)Delegate.Remove(lobbyManager5.onPlayerCountUpdated, new Action(RebuildPlayers));
		}

		private void Update()
		{
			Refresh();
		}

		private void ToggleMPLobbyFeatures(MPLobbyFeatures lobbyFlags)
		{
			Toggle(createLobbyButton, lobbyFlags.HasFlag(MPLobbyFeatures.CreateLobby));
			Toggle(leaveLobbyButton, lobbyFlags.HasFlag(MPLobbyFeatures.LeaveLobby));
			Toggle(copyLobbyButton, lobbyFlags.HasFlag(MPLobbyFeatures.Clipboard));
			Toggle(joinLobbyButton, lobbyFlags.HasFlag(MPLobbyFeatures.Clipboard));
		}

		private void Toggle(MonoBehaviour component, bool val)
		{
			if ((bool)component)
			{
				component.gameObject.SetActive(val);
			}
		}

		public void DisplayContent(bool display)
		{
			if ((bool)contentArea)
			{
				contentArea.SetActive(display);
			}
		}

		public void Refresh()
		{
			if (PlatformSystems.lobbyManager.HasMPLobbyUI() || PlatformSystems.lobbyManager.HasMPFeatures())
			{
				if (lobbyControlPanel.activeSelf != isInLobby)
				{
					lobbyControlPanel.SetActive(isInLobby);
				}
				if (!isPauseMenu)
				{
					if ((bool)createLobbyButton && PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.CreateLobby) && createLobbyButton.gameObject.activeSelf == isInLobby)
					{
						createLobbyButton.gameObject.SetActive(!isInLobby);
					}
					if ((bool)leaveLobbyButton && PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.LeaveLobby) && leaveLobbyButton.gameObject.activeSelf != isInLobby)
					{
						leaveLobbyButton.gameObject.SetActive(isInLobby);
					}
					if ((bool)copyLobbyButton && PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.Clipboard))
					{
						if (PlatformSystems.ShouldUseEpicOnlineSystems && PlatformSystems.lobbyManager.currentLobbyType == LobbyType.Private)
						{
							copyLobbyButton.interactable = false;
							copyLobbyButton.gameObject.SetActive(value: true);
						}
						else
						{
							copyLobbyButton.interactable = isInLobby;
							copyLobbyButton.gameObject.SetActive(isInLobby);
						}
					}
					if (lobbyControlPanel.activeInHierarchy && PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.LobbyDropdownOptions))
					{
						lobbyTypeDropdown.interactable = PlatformSystems.lobbyManager.ownsLobby;
						LobbyType currentLobbyType = PlatformSystems.lobbyManager.currentLobbyType;
						for (int i = 0; i < lobbyStateChoices.Length; i++)
						{
							if (currentLobbyType == lobbyStateChoices[i].lobbyType)
							{
								lobbyTypeDropdown.SetValueWithoutNotify(i);
								break;
							}
						}
					}
				}
			}
			RebuildPlayers();
		}

		private void RebuildLobbyStateDropdownOptions()
		{
			if (PlatformSystems.lobbyManager.HasMPLobbyUI() && !isPauseMenu)
			{
				for (int i = 0; i < lobbyStateChoices.Length; i++)
				{
					optionsBuffer.Add(Language.GetString(lobbyStateChoices[i].token));
				}
				lobbyTypeDropdown.ClearOptions();
				lobbyTypeDropdown.AddOptions(optionsBuffer);
				optionsBuffer.Clear();
			}
		}

		private void OnLobbyStateDropdownValueChanged(int newValue)
		{
			if (isInLobby && !isPauseMenu)
			{
				PlatformSystems.lobbyManager.currentLobbyType = lobbyStateChoices[newValue].lobbyType;
				Refresh();
			}
		}

		public void ClearUserList()
		{
			while (userList.Count > 0)
			{
				int index = userList.Count - 1;
				UnityEngine.Object.Destroy(userList[index].gameObject);
				userList.RemoveAt(index);
			}
		}

		public void RebuildPlayers()
		{
			bool num = isInLobby;
			PlatformID[] lobbyMembers = PlatformSystems.lobbyManager.GetLobbyMembers();
			int num2 = ((!isPauseMenu) ? 1 : 0);
			int num3 = Math.Min(num ? (lobbyMembers.Length + num2) : 0, RoR2Application.maxPlayers);
			while (userList.Count > num3)
			{
				int index = userList.Count - 1;
				UnityEngine.Object.Destroy(userList[index].gameObject);
				userList.RemoveAt(index);
			}
			while (userList.Count < num3)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/LobbyUserListElement"), playerListContainer);
				gameObject.SetActive(value: true);
				SocialUserIcon componentInChildren = gameObject.GetComponentInChildren<SocialUserIcon>();
				VoiceIcon componentInChildren2 = gameObject.GetComponentInChildren<VoiceIcon>();
				SteamUsernameLabel componentInChildren3 = gameObject.GetComponentInChildren<SteamUsernameLabel>();
				ChildLocator component = gameObject.GetComponent<ChildLocator>();
				userList.Add(new LobbyUserListElement
				{
					gameObject = gameObject,
					userIcon = componentInChildren,
					voiceIcon = componentInChildren2,
					usernameLabel = componentInChildren3,
					elementChildLocator = component
				});
			}
			if (lobbyMembers != null)
			{
				int i;
				for (i = 0; i < lobbyMembers.Length && i < userList.Count; i++)
				{
					userList[i].SetUser(lobbyMembers[i], i);
				}
				for (; i < num3; i++)
				{
					userList[i].SetUser(default(PlatformID), 0);
				}
			}
		}

		private void UpdateUser(PlatformID userId)
		{
			for (int i = 0; i < userList.Count; i++)
			{
				if (userList[i].id == userId)
				{
					userList[i].Refresh(shouldForceRefresh: true);
				}
			}
		}

		private void OnLobbyStateChanged()
		{
			lobbyTypeDropdown.interactable = PlatformSystems.lobbyManager.ownsLobby;
			Refresh();
		}

		private void OnLobbyMemberDataUpdated(PlatformID steamId)
		{
			UpdateUser(steamId);
		}

		private void OnLobbyChanged()
		{
			Refresh();
		}
	}
	internal class LobbyUserListElement
	{
		public PlatformID id;

		public GameObject gameObject;

		public SocialUserIcon userIcon;

		public SteamUsernameLabel usernameLabel;

		public VoiceIcon voiceIcon;

		public ChildLocator elementChildLocator;

		public void SetUser(PlatformID playerUserID, int subPlayerIndex)
		{
			id = playerUserID;
			userIcon.RefreshWithUser(playerUserID);
			usernameLabel.userId = playerUserID;
			usernameLabel.subPlayerIndex = subPlayerIndex;
			Refresh();
		}

		public void Refresh(bool shouldForceRefresh = false)
		{
			if (id == default(PlatformID))
			{
				elementChildLocator.FindChild("UserIcon").gameObject.SetActive(value: false);
				elementChildLocator.FindChild("InviteButton").gameObject.SetActive(PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.Invite));
				elementChildLocator.FindChild("VoiceButton").gameObject.SetActive(value: false);
				elementChildLocator.FindChild("LobbyLeaderCrown").gameObject.SetActive(value: false);
			}
			else
			{
				elementChildLocator.FindChild("UserIcon").gameObject.SetActive(value: true);
				elementChildLocator.FindChild("InviteButton").gameObject.SetActive(value: false);
				elementChildLocator.FindChild("LobbyLeaderCrown").gameObject.SetActive(value: false);
			}
			userIcon.Refresh(shouldForceRefresh);
			usernameLabel.Refresh();
			voiceIcon?.Refresh();
			RefreshCrownAndPromoteButton();
		}

		private void RefreshCrownAndPromoteButton()
		{
			bool flag = PlatformSystems.lobbyManager.IsLobbyOwner(id) || (PlatformSystems.lobbyManager.GetLobbyMemberCount() == 1 && id != default(PlatformID));
			elementChildLocator.FindChild("LobbyLeaderCrown").gameObject.SetActive(flag);
			if (!elementChildLocator)
			{
				return;
			}
			bool flag2 = PlatformSystems.lobbyManager.ShouldShowPromoteButton() && !flag && PlatformSystems.lobbyManager.ownsLobby && id != default(PlatformID) && !NetworkSession.instance;
			GameObject gameObject = elementChildLocator.FindChild("PromoteButton").gameObject;
			if (!gameObject)
			{
				return;
			}
			gameObject.SetActive(flag2);
			if (!flag2)
			{
				return;
			}
			MPButton component = gameObject.GetComponent<MPButton>();
			if ((bool)component)
			{
				component.onClick.RemoveAllListeners();
				component.onClick.AddListener(delegate
				{
					Console.instance.SubmitCmd(null, string.Format(CultureInfo.InvariantCulture, "steam_lobby_assign_owner {0}", id));
				});
			}
		}
	}
	public class LocalUserSignInCardController : MonoBehaviour
	{
		public TextMeshProUGUI nameLabel;

		public TextMeshProUGUI promptLabel;

		public UnityEngine.UI.Image cardImage;

		public Sprite playerCardNone;

		public Sprite playerCardKBM;

		public Sprite playerCardController;

		public UnityEngine.Color unselectedColor;

		public UnityEngine.Color selectedColor;

		private UserProfileListController userProfileSelectionList;

		public GameObject userProfileSelectionListPrefab;

		private Player _rewiredPlayer;

		private UserProfile _requestedUserProfile;

		public Player rewiredPlayer
		{
			get
			{
				return _rewiredPlayer;
			}
			set
			{
				if (_rewiredPlayer != value)
				{
					_rewiredPlayer = value;
					if (_rewiredPlayer == null)
					{
						requestedUserProfile = null;
					}
				}
			}
		}

		public UserProfile requestedUserProfile
		{
			get
			{
				return _requestedUserProfile;
			}
			private set
			{
				if (_requestedUserProfile != value)
				{
					if (_requestedUserProfile != null)
					{
						_requestedUserProfile.isClaimed = false;
					}
					_requestedUserProfile = value;
					if (_requestedUserProfile != null)
					{
						_requestedUserProfile.isClaimed = true;
					}
				}
			}
		}

		private void Update()
		{
			if (requestedUserProfile != null != (bool)userProfileSelectionList)
			{
				if (!userProfileSelectionList)
				{
					GameObject gameObject = UnityEngine.Object.Instantiate(userProfileSelectionListPrefab, base.transform);
					userProfileSelectionList = gameObject.GetComponent<UserProfileListController>();
					userProfileSelectionList.GetComponent<MPEventSystemProvider>().eventSystem = MPEventSystemManager.FindEventSystem(rewiredPlayer);
					userProfileSelectionList.onProfileSelected += OnUserSelectedUserProfile;
				}
				else
				{
					UnityEngine.Object.Destroy(userProfileSelectionList.gameObject);
					userProfileSelectionList = null;
				}
			}
			if (rewiredPlayer != null)
			{
				cardImage.color = selectedColor;
				nameLabel.gameObject.SetActive(value: true);
				if (requestedUserProfile == null)
				{
					cardImage.sprite = playerCardNone;
					nameLabel.text = "";
					promptLabel.text = "...";
				}
				else
				{
					cardImage.sprite = playerCardKBM;
					nameLabel.text = requestedUserProfile.name;
					promptLabel.text = "";
				}
			}
			else
			{
				nameLabel.gameObject.SetActive(value: false);
				promptLabel.text = "Press 'Start'";
				cardImage.color = unselectedColor;
				cardImage.sprite = playerCardNone;
			}
		}

		private void OnUserSelectedUserProfile(UserProfile userProfile)
		{
			requestedUserProfile = userProfile;
		}
	}
	public class LocalUserSignInController : MonoBehaviour
	{
		public GameObject localUserCardPrefab;

		private readonly List<LocalUserSignInCardController> cards = new List<LocalUserSignInCardController>();

		private void Start()
		{
			LocalUserSignInCardController[] componentsInChildren = GetComponentsInChildren<LocalUserSignInCardController>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				cards.Add(componentsInChildren[i]);
			}
		}

		public bool AreAllCardsReady()
		{
			return cards.Any((LocalUserSignInCardController v) => v.rewiredPlayer != null && v.requestedUserProfile == null);
		}

		private void DoSignIn()
		{
			LocalUserManager.LocalUserInitializationInfo[] array = new LocalUserManager.LocalUserInitializationInfo[cards.Count((LocalUserSignInCardController v) => v.rewiredPlayer != null)];
			int index = 0;
			for (int i = 0; i < cards.Count; i++)
			{
				if (cards[i].rewiredPlayer != null)
				{
					array[index++] = new LocalUserManager.LocalUserInitializationInfo
					{
						player = cards[index].rewiredPlayer,
						profile = cards[index].requestedUserProfile
					};
				}
			}
			LocalUserManager.SetLocalUsers(array);
		}

		private LocalUserSignInCardController FindCardAssociatedWithRewiredPlayer(Player rewiredPlayer)
		{
			for (int i = 0; i < cards.Count; i++)
			{
				if (cards[i].rewiredPlayer == rewiredPlayer)
				{
					return cards[i];
				}
			}
			return null;
		}

		private LocalUserSignInCardController FindCardWithoutRewiredPlayer()
		{
			for (int i = 0; i < cards.Count; i++)
			{
				if (cards[i].rewiredPlayer == null)
				{
					return cards[i];
				}
			}
			return null;
		}

		private void Update()
		{
			IList<Player> players = ReInput.players.Players;
			for (int i = 0; i < players.Count; i++)
			{
				Player player = players[i];
				if (player.name == "PlayerMain")
				{
					continue;
				}
				LocalUserSignInCardController localUserSignInCardController = FindCardAssociatedWithRewiredPlayer(player);
				if (localUserSignInCardController == null)
				{
					if (player.GetButtonDown(11))
					{
						LocalUserSignInCardController localUserSignInCardController2 = FindCardWithoutRewiredPlayer();
						if (localUserSignInCardController2 != null)
						{
							localUserSignInCardController2.rewiredPlayer = player;
						}
					}
				}
				else if (player.GetButtonDown(15) || !PlayerHasControllerConnected(player))
				{
					localUserSignInCardController.rewiredPlayer = null;
				}
			}
			_ = LocalUserManager.readOnlyLocalUsersList;
			int num = 4;
			while (cards.Count < num)
			{
				cards.Add(UnityEngine.Object.Instantiate(localUserCardPrefab, base.transform).GetComponent<LocalUserSignInCardController>());
			}
			while (cards.Count > num)
			{
				UnityEngine.Object.Destroy(cards[cards.Count - 1].gameObject);
				cards.RemoveAt(cards.Count - 1);
			}
		}

		private static bool PlayerHasControllerConnected(Player player)
		{
			using (IEnumerator<Controller> enumerator = player.controllers.Controllers.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					_ = enumerator.Current;
					return true;
				}
			}
			return false;
		}
	}
	[RequireComponent(typeof(RectTransform))]
	[ExecuteInEditMode]
	public class MainUIArea : MonoBehaviour
	{
		private RectTransform rectTransform;

		private RectTransform parentRectTransform;

		private void Awake()
		{
			rectTransform = GetComponent<RectTransform>();
			parentRectTransform = rectTransform.parent.GetComponent<RectTransform>();
		}

		private void Update()
		{
			UnityEngine.Rect rect = parentRectTransform.rect;
			float num = rect.width * 0.05f;
			float num2 = rect.height * 0.05f;
			rectTransform.offsetMin = new UnityEngine.Vector2(num, num2);
			rectTransform.offsetMax = new UnityEngine.Vector2(0f - num, 0f - num2);
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class MinSizeFromParentLayoutElement : MonoBehaviour, ILayoutElement
	{
		public bool useParentWidthAsMinWidth = true;

		public bool useParentHeightAsMinHeight = true;

		[SerializeField]
		private int _layoutPriority = 1;

		public float minWidth { get; protected set; } = -1f;


		public float preferredWidth { get; } = -1f;


		public float flexibleWidth { get; } = -1f;


		public float minHeight { get; protected set; } = -1f;


		public float preferredHeight { get; } = -1f;


		public float flexibleHeight { get; } = -1f;


		public int layoutPriority
		{
			get
			{
				return _layoutPriority;
			}
			set
			{
				_layoutPriority = value;
			}
		}

		public void CalculateLayoutInputHorizontal()
		{
			if (!useParentWidthAsMinWidth)
			{
				minWidth = -1f;
				return;
			}
			RectTransform rectTransform = base.transform.parent as RectTransform;
			minWidth = (rectTransform ? rectTransform.rect.width : (-1f));
		}

		public void CalculateLayoutInputVertical()
		{
			if (!useParentHeightAsMinHeight)
			{
				minHeight = -1f;
				return;
			}
			RectTransform rectTransform = base.transform.parent as RectTransform;
			minHeight = (rectTransform ? rectTransform.rect.height : (-1f));
		}
	}
	[RequireComponent(typeof(RectTransform))]
	[RequireComponent(typeof(RawImage))]
	public class ModelPanel : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IScrollHandler, IEndDragHandler
	{
		private class CameraFramingCalculator
		{
			private GameObject modelInstance;

			private Transform root;

			private readonly List<Transform> boneList = new List<Transform>();

			private HurtBoxGroup hurtBoxGroup;

			private HurtBox[] hurtBoxes = Array.Empty<HurtBox>();

			public UnityEngine.Vector3 outputPivotPoint;

			public UnityEngine.Vector3 outputCameraPosition;

			public float outputMinDistance;

			public float outputMaxDistance;

			public UnityEngine.Quaternion outputCameraRotation;

			private static void GenerateBoneList(Transform rootBone, List<Transform> boneList)
			{
				boneList.AddRange(rootBone.gameObject.GetComponentsInChildren<Transform>());
			}

			public CameraFramingCalculator(GameObject modelInstance)
			{
				this.modelInstance = modelInstance;
				root = modelInstance.transform;
				GenerateBoneList(root, boneList);
				hurtBoxGroup = modelInstance.GetComponent<HurtBoxGroup>();
				if ((bool)hurtBoxGroup)
				{
					hurtBoxes = hurtBoxGroup.hurtBoxes;
				}
			}

			private bool FindBestEyePoint(out UnityEngine.Vector3 result, out float approximateEyeRadius)
			{
				approximateEyeRadius = 1f;
				IEnumerable<Transform> source = boneList.Where(FirstChoice);
				if (!source.Any())
				{
					source = boneList.Where(SecondChoice);
				}
				UnityEngine.Vector3[] array = source.Select((Transform bone) => bone.position).ToArray();
				result = Vector3Utils.AveragePrecise(array);
				for (int i = 0; i < array.Length; i++)
				{
					float magnitude = (array[i] - result).magnitude;
					if (magnitude > approximateEyeRadius)
					{
						approximateEyeRadius = magnitude;
					}
				}
				return array.Length != 0;
				static bool FirstChoice(Transform bone)
				{
					if ((bool)bone.GetComponent<SkinnedMeshRenderer>())
					{
						return false;
					}
					string name = bone.name;
					if (name.Equals("eye", StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
					if (name.Equals("eyeball.1", StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
					return false;
				}
				static bool SecondChoice(Transform bone)
				{
					if ((bool)bone.GetComponent<SkinnedMeshRenderer>())
					{
						return false;
					}
					return bone.name.ToLower().Contains("eye");
				}
			}

			private bool FindBestHeadPoint(string searchName, out UnityEngine.Vector3 result, out float approximateRadius)
			{
				Transform[] array = boneList.Where((Transform bone) => string.Equals(bone.name, searchName, StringComparison.OrdinalIgnoreCase)).ToArray();
				if (array.Length == 0)
				{
					array = boneList.Where((Transform bone) => bone.name.ToLower(CultureInfo.InvariantCulture).Contains(searchName)).ToArray();
				}
				if (array.Length != 0)
				{
					foreach (Transform bone2 in array)
					{
						if (TryCalcBoneBounds(bone2, 0.2f, out var bounds, out approximateRadius))
						{
							result = bounds.center;
							return true;
						}
					}
				}
				result = UnityEngine.Vector3.zero;
				approximateRadius = 0f;
				return false;
			}

			private static float CalcMagnitudeToFrameSphere(float sphereRadius, float fieldOfView)
			{
				float num = fieldOfView * 0.5f;
				float num2 = 90f;
				return Mathf.Tan((180f - num2 - num) * (MathF.PI / 180f)) * sphereRadius;
			}

			private bool FindBestCenterOfMass(out UnityEngine.Vector3 result, out float approximateRadius)
			{
				_ = from bone in boneList
					select bone.GetComponent<HurtBox>() into hurtBox
					where hurtBox
					select hurtBox;
				if ((bool)hurtBoxGroup && (bool)hurtBoxGroup.mainHurtBox)
				{
					result = hurtBoxGroup.mainHurtBox.transform.position;
					approximateRadius = Util.SphereVolumeToRadius(hurtBoxGroup.mainHurtBox.volume);
					return true;
				}
				result = UnityEngine.Vector3.zero;
				approximateRadius = 1f;
				return false;
			}

			private static float GetWeightForBone(ref BoneWeight boneWeight, int boneIndex)
			{
				if (boneWeight.boneIndex0 == boneIndex)
				{
					return boneWeight.weight0;
				}
				if (boneWeight.boneIndex1 == boneIndex)
				{
					return boneWeight.weight1;
				}
				if (boneWeight.boneIndex2 == boneIndex)
				{
					return boneWeight.weight2;
				}
				if (boneWeight.boneIndex3 == boneIndex)
				{
					return boneWeight.weight3;
				}
				return 0f;
			}

			private static int FindBoneIndex(SkinnedMeshRenderer _skinnedMeshRenderer, Transform _bone)
			{
				Transform[] bones = _skinnedMeshRenderer.bones;
				for (int i = 0; i < bones.Length; i++)
				{
					if (bones[i] == _bone)
					{
						return i;
					}
				}
				return -1;
			}

			private bool TryCalcBoneBounds(Transform bone, float weightThreshold, out Bounds bounds, out float approximateRadius)
			{
				SkinnedMeshRenderer[] componentsInChildren = modelInstance.GetComponentsInChildren<SkinnedMeshRenderer>();
				SkinnedMeshRenderer skinnedMeshRenderer = null;
				Mesh mesh = null;
				int num = -1;
				List<int> list = new List<int>();
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					skinnedMeshRenderer = componentsInChildren[i];
					mesh = skinnedMeshRenderer.sharedMesh;
					if (!mesh)
					{
						continue;
					}
					num = FindBoneIndex(skinnedMeshRenderer, bone);
					if (num != -1)
					{
						BoneWeight[] boneWeights = mesh.boneWeights;
						for (int j = 0; j < boneWeights.Length; j++)
						{
							if (GetWeightForBone(ref boneWeights[j], num) > weightThreshold)
							{
								list.Add(j);
							}
						}
						if (list.Count == 0)
						{
							num = -1;
						}
					}
					if (num != -1)
					{
						break;
					}
				}
				if (num == -1)
				{
					bounds = default(Bounds);
					approximateRadius = 0f;
					return false;
				}
				Mesh mesh2 = new Mesh();
				skinnedMeshRenderer.BakeMesh(mesh2);
				UnityEngine.Vector3[] vertices = mesh2.vertices;
				UnityEngine.Object.Destroy(mesh2);
				if (mesh2.vertexCount != mesh.vertexCount)
				{
					UnityEngine.Debug.LogWarningFormat("Baked mesh vertex count differs from the original mesh vertex count! baked={0} original={1}", mesh2.vertexCount, mesh.vertexCount);
					vertices = mesh.vertices;
				}
				UnityEngine.Vector3[] array = new UnityEngine.Vector3[list.Count];
				Transform transform = skinnedMeshRenderer.transform;
				UnityEngine.Vector3 position = transform.position;
				UnityEngine.Quaternion rotation = transform.rotation;
				for (int k = 0; k < list.Count; k++)
				{
					int num2 = list[k];
					UnityEngine.Vector3 vector = vertices[num2];
					UnityEngine.Vector3 vector2 = position + rotation * vector;
					array[k] = vector2;
				}
				bounds = new Bounds(Vector3Utils.AveragePrecise(array), UnityEngine.Vector3.zero);
				float num3 = 0f;
				for (int l = 0; l < array.Length; l++)
				{
					bounds.Encapsulate(array[l]);
					float num4 = UnityEngine.Vector3.Distance(bounds.center, array[l]);
					if (num4 > num3)
					{
						num3 = num4;
					}
				}
				approximateRadius = num3;
				return true;
			}

			public void GetCharacterThumbnailPosition(float fov)
			{
				ModelPanelParameters component = modelInstance.GetComponent<ModelPanelParameters>();
				if ((bool)component)
				{
					if ((bool)component.focusPointTransform)
					{
						outputPivotPoint = component.focusPointTransform.position;
					}
					if ((bool)component.cameraPositionTransform)
					{
						outputCameraPosition = component.cameraPositionTransform.position;
					}
					outputCameraRotation = Util.QuaternionSafeLookRotation(component.cameraDirection);
					outputMinDistance = component.minDistance;
					outputMaxDistance = component.maxDistance;
					return;
				}
				UnityEngine.Vector3 result = UnityEngine.Vector3.zero;
				float approximateRadius = 1f;
				bool flag = FindBestHeadPoint("head", out result, out approximateRadius);
				if (!flag)
				{
					flag = FindBestHeadPoint("chest", out result, out approximateRadius);
				}
				bool flag2 = false;
				bool flag3 = false;
				float num = 1f;
				float approximateEyeRadius = 1f;
				flag2 = FindBestEyePoint(out var result2, out approximateEyeRadius);
				if (!flag)
				{
					approximateRadius = approximateEyeRadius;
				}
				if (flag2)
				{
					result = result2;
				}
				if (!flag && !flag2)
				{
					flag3 = FindBestCenterOfMass(out result, out approximateRadius);
				}
				float num2 = 1f;
				if (Util.GuessRenderBoundsMeshOnly(modelInstance, out var bounds))
				{
					if (flag3)
					{
						approximateRadius = Util.SphereVolumeToRadius(bounds.size.x * bounds.size.y * bounds.size.z);
					}
					Mathf.Max((result.y - bounds.min.y) / bounds.size.y - 0.5f - 0.2f, 0f);
					_ = bounds.center;
					num2 = bounds.size.z / bounds.size.x;
					outputMinDistance = Mathf.Min(bounds.size.x, bounds.size.y, bounds.size.z) * 1f;
					outputMaxDistance = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z) * 2f;
				}
				UnityEngine.Vector3 vector = -root.forward;
				for (int i = 0; i < boneList.Count; i++)
				{
					if (boneList[i].name.Equals("muzzle", StringComparison.OrdinalIgnoreCase))
					{
						UnityEngine.Vector3 vector2 = root.position - boneList[i].position;
						vector2.y = 0f;
						float magnitude = vector2.magnitude;
						if (magnitude > 0.2f)
						{
							vector2 /= magnitude;
							vector = vector2;
							break;
						}
					}
				}
				vector = UnityEngine.Quaternion.Euler(0f, 57.29578f * Mathf.Atan(num2 - 1f) * 1f, 0f) * vector;
				UnityEngine.Vector3 vector3 = -vector * (CalcMagnitudeToFrameSphere(approximateRadius, fov) + num);
				UnityEngine.Vector3 vector4 = result + vector3;
				outputPivotPoint = result;
				outputCameraPosition = vector4;
				outputCameraRotation = Util.QuaternionSafeLookRotation(result - vector4);
			}
		}

		private GameObject _modelPrefab;

		public GameObject modelPostProcessVolumePrefab;

		public UnityEngine.Vector3 modelPostProcessVolumePosition = UnityEngine.Vector3.zero;

		public RenderSettingsState renderSettings;

		public UnityEngine.Color camBackgroundColor = UnityEngine.Color.clear;

		public bool disablePostProcessLayer = true;

		public bool useUnscaledTime;

		private static int isGroundedParamHash = Animator.StringToHash("isGrounded");

		private static int aimPitchCycleParamHash = Animator.StringToHash("aimPitchCycle");

		private static int aimYawCycleParamHash = Animator.StringToHash("aimYawCycle");

		private static int IdleStateHash = Animator.StringToHash("Idle");

		private RectTransform rectTransform;

		private RawImage rawImage;

		private GameObject modelInstance;

		private CameraRigController cameraRigController;

		private ModelCamera modelCamera;

		public GameObject headlightPrefab;

		public GameObject[] lightPrefabs;

		private GameObject modelPostProcessVolumeInstance;

		private UnityEngine.Vector3 postProcessVolumeLocation;

		private Light headlight;

		public float fov = 60f;

		public bool enableGamepadControls;

		public float gamepadZoomSensitivity;

		public float gamepadRotateSensitivity;

		public UILayerKey requiredTopLayer;

		private MPEventSystemLocator mpEventSystemLocator;

		private float zoom = 0.5f;

		private float desiredZoom = 0.5f;

		private float zoomVelocity;

		private float minDistance = 0.5f;

		private float maxDistance = 10f;

		private float orbitPitch;

		private float orbitYaw = 180f;

		private UnityEngine.Vector3 orbitalVelocity = UnityEngine.Vector3.zero;

		private UnityEngine.Vector3 orbitalVelocitySmoothDampVelocity = UnityEngine.Vector3.zero;

		private UnityEngine.Vector2 pan;

		private UnityEngine.Vector2 panVelocity;

		private UnityEngine.Vector2 panVelocitySmoothDampVelocity;

		private UnityEngine.Vector3 pivotPoint = UnityEngine.Vector3.zero;

		private List<Light> lights = new List<Light>();

		private UnityEngine.Vector2 orbitDragPoint;

		private UnityEngine.Vector2 panDragPoint;

		private int orbitDragCount;

		private int panDragCount;

		public GameObject modelPrefab
		{
			get
			{
				return _modelPrefab;
			}
			set
			{
				if (!(_modelPrefab == value))
				{
					DestroyModelInstance();
					_modelPrefab = value;
					BuildModelInstance();
				}
			}
		}

		public RenderTexture renderTexture { get; private set; }

		private void DestroyModelInstance()
		{
			UnityEngine.Object.Destroy(modelInstance);
			modelInstance = null;
		}

		private void BuildModelInstance()
		{
			if (!_modelPrefab || !base.enabled || (bool)modelInstance)
			{
				return;
			}
			modelInstance = UnityEngine.Object.Instantiate(_modelPrefab, modelPostProcessVolumePosition, UnityEngine.Quaternion.identity);
			ModelPanelParameters component = _modelPrefab.GetComponent<ModelPanelParameters>();
			if ((bool)component)
			{
				modelInstance.transform.rotation = component.modelRotation;
			}
			Util.GuessRenderBoundsMeshOnly(modelInstance, out var bounds);
			pivotPoint = bounds.center;
			minDistance = Mathf.Min(bounds.size.x, bounds.size.y, bounds.size.z) * 1f;
			maxDistance = Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z) * 2f;
			Renderer[] componentsInChildren = modelInstance.GetComponentsInChildren<Renderer>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].gameObject.layer = LayerIndex.noDraw.intVal;
			}
			AimAnimator[] componentsInChildren2 = modelInstance.GetComponentsInChildren<AimAnimator>();
			for (int j = 0; j < componentsInChildren2.Length; j++)
			{
				componentsInChildren2[j].inputBank = null;
				componentsInChildren2[j].directionComponent = null;
				componentsInChildren2[j].enabled = false;
			}
			Animator[] componentsInChildren3 = modelInstance.GetComponentsInChildren<Animator>();
			foreach (Animator obj in componentsInChildren3)
			{
				obj.SetBool(isGroundedParamHash, value: true);
				obj.SetFloat(aimPitchCycleParamHash, 0.5f);
				obj.SetFloat(aimYawCycleParamHash, 0.5f);
				obj.Play(IdleStateHash);
				obj.Update(0f);
				obj.updateMode = AnimatorUpdateMode.UnscaledTime;
			}
			IKSimpleChain[] componentsInChildren4 = modelInstance.GetComponentsInChildren<IKSimpleChain>();
			for (int l = 0; l < componentsInChildren4.Length; l++)
			{
				componentsInChildren4[l].enabled = false;
			}
			DitherModel[] componentsInChildren5 = modelInstance.GetComponentsInChildren<DitherModel>();
			for (int m = 0; m < componentsInChildren5.Length; m++)
			{
				componentsInChildren5[m].enabled = false;
			}
			PrintController[] componentsInChildren6 = modelInstance.GetComponentsInChildren<PrintController>();
			for (int m = 0; m < componentsInChildren6.Length; m++)
			{
				componentsInChildren6[m].enabled = false;
			}
			LightIntensityCurve[] componentsInChildren7 = modelInstance.GetComponentsInChildren<LightIntensityCurve>();
			foreach (LightIntensityCurve lightIntensityCurve in componentsInChildren7)
			{
				if (!lightIntensityCurve.loop)
				{
					lightIntensityCurve.enabled = false;
				}
			}
			AkEvent[] componentsInChildren8 = modelInstance.GetComponentsInChildren<AkEvent>();
			for (int m = 0; m < componentsInChildren8.Length; m++)
			{
				componentsInChildren8[m].enabled = false;
			}
			TemporaryOverlay[] componentsInChildren9 = modelInstance.GetComponentsInChildren<TemporaryOverlay>();
			for (int m = 0; m < componentsInChildren9.Length; m++)
			{
				UnityEngine.Object.Destroy(componentsInChildren9[m]);
			}
			ParticleSystem[] componentsInChildren10 = modelInstance.GetComponentsInChildren<ParticleSystem>();
			for (int m = 0; m < componentsInChildren10.Length; m++)
			{
				ParticleSystem.MainModule main = componentsInChildren10[m].main;
				main.useUnscaledTime = true;
			}
			desiredZoom = 0.5f;
			zoom = desiredZoom;
			zoomVelocity = 0f;
			ResetOrbitAndPan();
		}

		private void ResetOrbitAndPan()
		{
			orbitPitch = 0f;
			orbitYaw = 0f;
			orbitalVelocity = UnityEngine.Vector3.zero;
			orbitalVelocitySmoothDampVelocity = UnityEngine.Vector3.zero;
			pan = UnityEngine.Vector2.zero;
			panVelocity = UnityEngine.Vector2.zero;
			panVelocitySmoothDampVelocity = UnityEngine.Vector2.zero;
		}

		private void Awake()
		{
			modelPostProcessVolumeInstance = UnityEngine.Object.Instantiate(modelPostProcessVolumePrefab, modelPostProcessVolumePosition, UnityEngine.Quaternion.identity);
			rectTransform = GetComponent<RectTransform>();
			rawImage = GetComponent<RawImage>();
			mpEventSystemLocator = GetComponent<MPEventSystemLocator>();
			cameraRigController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/Main Camera")).GetComponent<CameraRigController>();
			cameraRigController.gameObject.name = "ModelCamera";
			cameraRigController.uiCam.gameObject.SetActive(value: false);
			cameraRigController.createHud = false;
			cameraRigController.enableFading = false;
			cameraRigController.enableMusic = false;
			GameObject gameObject = cameraRigController.sceneCam.gameObject;
			modelCamera = gameObject.AddComponent<ModelCamera>();
			cameraRigController.transform.position = modelPostProcessVolumeInstance.transform.position - UnityEngine.Vector3.forward * 10f;
			cameraRigController.transform.forward = UnityEngine.Vector3.forward;
			CameraResolutionScaler component = gameObject.GetComponent<CameraResolutionScaler>();
			if ((bool)component)
			{
				component.enabled = false;
			}
			Camera sceneCam = cameraRigController.sceneCam;
			sceneCam.backgroundColor = UnityEngine.Color.clear;
			sceneCam.clearFlags = CameraClearFlags.Color;
			if (disablePostProcessLayer)
			{
				PostProcessLayer component2 = sceneCam.GetComponent<PostProcessLayer>();
				if ((bool)component2)
				{
					component2.enabled = false;
				}
			}
			UnityEngine.Vector3 eulerAngles = cameraRigController.transform.eulerAngles;
			orbitPitch = eulerAngles.x;
			orbitYaw = eulerAngles.y;
			modelCamera.attachedCamera.backgroundColor = camBackgroundColor;
			modelCamera.attachedCamera.clearFlags = CameraClearFlags.Color;
			modelCamera.attachedCamera.cullingMask = LayerIndex.manualRender.mask;
			if ((bool)headlightPrefab)
			{
				headlight = UnityEngine.Object.Instantiate(headlightPrefab, modelCamera.transform).GetComponent<Light>();
				if ((bool)headlight)
				{
					headlight.gameObject.SetActive(value: true);
					modelCamera.AddLight(headlight);
				}
			}
			for (int i = 0; i < lightPrefabs.Length; i++)
			{
				GameObject obj = UnityEngine.Object.Instantiate(lightPrefabs[i]);
				Light component3 = obj.GetComponent<Light>();
				obj.SetActive(value: true);
				lights.Add(component3);
				modelCamera.AddLight(component3);
			}
		}

		public void Start()
		{
			BuildRenderTexture();
			desiredZoom = 0.5f;
			zoom = desiredZoom;
			zoomVelocity = 0f;
		}

		private void OnDestroy()
		{
			UnityEngine.Object.Destroy(renderTexture);
			if ((bool)modelPostProcessVolumeInstance)
			{
				UnityEngine.Object.Destroy(modelPostProcessVolumeInstance);
			}
			if ((bool)cameraRigController)
			{
				UnityEngine.Object.Destroy(cameraRigController.gameObject);
			}
			foreach (Light light in lights)
			{
				UnityEngine.Object.Destroy(light.gameObject);
			}
		}

		private void OnDisable()
		{
			DestroyModelInstance();
		}

		private void OnEnable()
		{
			BuildModelInstance();
		}

		public void Update()
		{
			UpdateForModelViewer(Time.unscaledDeltaTime);
			if (enableGamepadControls && (!requiredTopLayer || requiredTopLayer.representsTopLayer) && mpEventSystemLocator.eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad && (bool)mpEventSystemLocator.eventSystem)
			{
				float axis = mpEventSystemLocator.eventSystem.player.GetAxis(16);
				float axis2 = mpEventSystemLocator.eventSystem.player.GetAxis(17);
				bool button = mpEventSystemLocator.eventSystem.player.GetButton(29);
				bool button2 = mpEventSystemLocator.eventSystem.player.GetButton(30);
				UnityEngine.Vector3 zero = UnityEngine.Vector3.zero;
				zero.y = (0f - axis) * gamepadRotateSensitivity;
				zero.x = axis2 * gamepadRotateSensitivity;
				orbitalVelocity = zero;
				if (button != button2)
				{
					desiredZoom = Mathf.Clamp01(desiredZoom + (button ? 0.1f : (-0.1f)) * Time.deltaTime * gamepadZoomSensitivity);
				}
			}
		}

		public void LateUpdate()
		{
			modelCamera.attachedCamera.aspect = (float)renderTexture.width / (float)renderTexture.height;
			cameraRigController.baseFov = fov;
			modelCamera.renderSettings = renderSettings;
			modelCamera.RenderItem(modelInstance, renderTexture);
		}

		private void OnRectTransformDimensionsChange()
		{
			BuildRenderTexture();
		}

		private void BuildRenderTexture()
		{
			if (!rectTransform)
			{
				return;
			}
			UnityEngine.Vector3[] fourCornersArray = new UnityEngine.Vector3[4];
			rectTransform.GetLocalCorners(fourCornersArray);
			UnityEngine.Vector2 size = rectTransform.rect.size;
			int num = Mathf.FloorToInt(size.x);
			int num2 = Mathf.FloorToInt(size.y);
			if (!renderTexture || renderTexture.width != num || renderTexture.height != num2)
			{
				UnityEngine.Object.Destroy(renderTexture);
				renderTexture = null;
				if (num > 0 && num2 > 0)
				{
					RenderTextureDescriptor desc = new RenderTextureDescriptor(num, num2, RenderTextureFormat.ARGB32);
					desc.sRGB = true;
					renderTexture = new RenderTexture(desc);
					renderTexture.useMipMap = false;
					renderTexture.filterMode = FilterMode.Bilinear;
				}
				rawImage.texture = renderTexture;
			}
		}

		private void UpdateForModelViewer(float deltaTime)
		{
			zoom = Mathf.SmoothDamp(zoom, desiredZoom, ref zoomVelocity, 0.1f, 10f, deltaTime);
			orbitPitch %= 360f;
			if (orbitPitch < -180f)
			{
				orbitPitch += 360f;
			}
			else if (orbitPitch > 180f)
			{
				orbitPitch -= 360f;
			}
			orbitPitch = Mathf.Clamp(orbitPitch + orbitalVelocity.x * deltaTime, -89f, 89f);
			orbitYaw += orbitalVelocity.y * deltaTime;
			orbitalVelocity = UnityEngine.Vector3.SmoothDamp(orbitalVelocity, UnityEngine.Vector3.zero, ref orbitalVelocitySmoothDampVelocity, 0.25f, 2880f, deltaTime);
			if (orbitDragCount > 0)
			{
				orbitalVelocity = UnityEngine.Vector3.zero;
				orbitalVelocitySmoothDampVelocity = UnityEngine.Vector3.zero;
			}
			pan += panVelocity * deltaTime;
			panVelocity = UnityEngine.Vector2.SmoothDamp(panVelocity, UnityEngine.Vector2.zero, ref panVelocitySmoothDampVelocity, 0.25f, 100f, deltaTime);
			if (panDragCount > 0)
			{
				panVelocity = UnityEngine.Vector2.zero;
				panVelocitySmoothDampVelocity = UnityEngine.Vector2.zero;
			}
			UnityEngine.Quaternion quaternion = UnityEngine.Quaternion.Euler(orbitPitch, orbitYaw, 0f);
			cameraRigController.transform.forward = quaternion * UnityEngine.Vector3.forward;
			UnityEngine.Vector3 forward = cameraRigController.transform.forward;
			UnityEngine.Vector3 position = pivotPoint + forward * (0f - Mathf.LerpUnclamped(minDistance, maxDistance, zoom)) + cameraRigController.transform.up * pan.y + cameraRigController.transform.right * pan.x;
			cameraRigController.transform.position = position;
		}

		public void SetAnglesForCharacterThumbnailForSeconds(float time, bool setZoom = false)
		{
			SetAnglesForCharacterThumbnail(setZoom);
			float t = time;
			Action func = null;
			func = delegate
			{
				t -= (useUnscaledTime ? Time.fixedUnscaledDeltaTime : Time.deltaTime);
				if ((bool)this)
				{
					SetAnglesForCharacterThumbnail(setZoom);
				}
				if (t <= 0f)
				{
					RoR2Application.onUpdate -= func;
				}
			};
			RoR2Application.onUpdate += func;
		}

		public void SetAnglesForCharacterThumbnail(bool setZoom = false)
		{
			if ((bool)modelInstance)
			{
				CameraFramingCalculator cameraFramingCalculator = new CameraFramingCalculator(modelInstance);
				cameraFramingCalculator.GetCharacterThumbnailPosition(fov);
				pivotPoint = cameraFramingCalculator.outputPivotPoint;
				minDistance = cameraFramingCalculator.outputMinDistance;
				maxDistance = cameraFramingCalculator.outputMaxDistance;
				ResetOrbitAndPan();
				UnityEngine.Vector3 eulerAngles = cameraFramingCalculator.outputCameraRotation.eulerAngles;
				orbitPitch = eulerAngles.x;
				orbitYaw = eulerAngles.y;
				if (setZoom)
				{
					zoom = Util.Remap(UnityEngine.Vector3.Distance(cameraFramingCalculator.outputCameraPosition, cameraFramingCalculator.outputPivotPoint), minDistance, maxDistance, 0f, 1f);
					desiredZoom = zoom;
				}
				zoomVelocity = 0f;
			}
		}

		public void OnBeginDrag(PointerEventData eventData)
		{
			if (eventData.button == PointerEventData.InputButton.Right)
			{
				orbitDragCount++;
				if (orbitDragCount == 1)
				{
					orbitDragPoint = eventData.pressPosition;
				}
			}
			else if (eventData.button == PointerEventData.InputButton.Left)
			{
				panDragCount++;
				if (panDragCount == 1)
				{
					panDragPoint = eventData.pressPosition;
				}
			}
		}

		public void OnEndDrag(PointerEventData eventData)
		{
			if (eventData.button == PointerEventData.InputButton.Right)
			{
				orbitDragCount--;
			}
			else if (eventData.button == PointerEventData.InputButton.Left)
			{
				panDragCount--;
			}
			OnDrag(eventData);
		}

		public void OnDrag(PointerEventData eventData)
		{
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			if (eventData.button == PointerEventData.InputButton.Right)
			{
				UnityEngine.Vector2 vector = eventData.position - orbitDragPoint;
				orbitDragPoint = eventData.position;
				float num = 0.5f / unscaledDeltaTime;
				orbitalVelocity = new UnityEngine.Vector3((0f - vector.y) * num * 0.5f, vector.x * num, 0f);
			}
			else
			{
				UnityEngine.Vector2 vector2 = eventData.position - panDragPoint;
				panDragPoint = eventData.position;
				float num2 = -0.01f;
				panVelocity = vector2 * num2 / unscaledDeltaTime;
			}
		}

		public void OnScroll(PointerEventData eventData)
		{
			desiredZoom = Mathf.Clamp01(desiredZoom + eventData.scrollDelta.y * -0.05f);
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class MoneyText : MonoBehaviour
	{
		public TextMeshProUGUI targetText;

		public FlashPanel flashPanel;

		private int displayAmount;

		private float updateTimer;

		private float coinSoundCooldown;

		public int targetValue;

		public string sound = "Play_UI_coin";

		public void Update()
		{
			coinSoundCooldown -= Time.deltaTime;
			if (!targetText)
			{
				return;
			}
			if (updateTimer <= 0f)
			{
				int num = 0;
				if (displayAmount != targetValue)
				{
					num = Math.DivRem(targetValue - displayAmount, 3, out var result);
					if (result != 0)
					{
						num += Math.Sign(result);
					}
					if (num > 0)
					{
						if (coinSoundCooldown <= 0f)
						{
							coinSoundCooldown = 0.025f;
							Util.PlaySound(sound, RoR2Application.instance.gameObject);
						}
						if ((bool)flashPanel)
						{
							flashPanel.Flash();
						}
					}
					displayAmount += num;
				}
				float num2 = Mathf.Min(0.5f / (float)num, 0.25f);
				targetText.text = TextSerialization.ToStringNumeric(displayAmount);
				updateTimer = num2;
			}
			updateTimer -= Time.deltaTime;
		}
	}
	public class MoonBatteryMissionObjectiveTracker : ObjectivePanelController.ObjectiveTracker
	{
		private int numChargedBatteries = -1;

		protected override string GenerateString()
		{
			MoonBatteryMissionController moonBatteryMissionController = (MoonBatteryMissionController)sourceDescriptor.source;
			numChargedBatteries = moonBatteryMissionController.numChargedBatteries;
			return string.Format(Language.GetString(moonBatteryMissionController.objectiveToken), numChargedBatteries, moonBatteryMissionController.numRequiredBatteries);
		}

		protected override bool IsDirty()
		{
			return ((MoonBatteryMissionController)sourceDescriptor.source).numChargedBatteries != numChargedBatteries;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class MPButton : Button
	{
		private MPEventSystemLocator eventSystemLocator;

		public bool allowAllEventSystems;

		[FormerlySerializedAs("pointerClickOnly")]
		public bool submitOnPointerUp;

		public bool selectOnPointerEnter = true;

		public bool disablePointerClick;

		public bool disableGamepadClick;

		public bool useBaseGamepadClick;

		private static bool isIgnore;

		public UILayerKey requiredTopLayer;

		public UnityEvent onFindSelectableLeft;

		public UnityEvent onFindSelectableRight;

		public UnityEvent onSelect;

		public UnityEvent onDeselect;

		public bool defaultFallbackButton;

		private static bool autonavigationFindInProgress;

		private bool inPointerUp;

		public MPEventSystem eventSystem => eventSystemLocator.eventSystem;

		protected override void Awake()
		{
			base.Awake();
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		public void Update()
		{
			if (eventSystem == null || eventSystem.player == null || isIgnore)
			{
				return;
			}
			if (!disableGamepadClick && eventSystem.player.GetButtonDown(14) && eventSystem.currentSelectedGameObject == base.gameObject && !useBaseGamepadClick)
			{
				InvokeClick();
			}
			if (!(eventSystem == null) && eventSystem.player != null && defaultFallbackButton && eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad && eventSystem.currentSelectedGameObject == null && CanBeSelected())
			{
				if (eventSystem == EventSystem.current)
				{
					Select();
				}
				else
				{
					eventSystem.SetSelectedGameObject(base.gameObject);
				}
			}
		}

		public void InvokeClick()
		{
			base.onClick?.Invoke();
		}

		private Selectable FilterSelectable(Selectable selectable)
		{
			if ((bool)selectable)
			{
				MPEventSystemLocator component = selectable.GetComponent<MPEventSystemLocator>();
				if (!component || component.eventSystem != eventSystemLocator.eventSystem)
				{
					selectable = null;
				}
				MPButton mPButton = selectable?.GetComponent<MPButton>();
				if ((bool)mPButton && !mPButton.CanBeSelected())
				{
					selectable = null;
				}
			}
			return selectable;
		}

		public override bool IsInteractable()
		{
			if (base.IsInteractable())
			{
				if (autonavigationFindInProgress)
				{
					return CanBeSelected();
				}
				return true;
			}
			return false;
		}

		public static void BlockMPButton()
		{
			isIgnore = true;
		}

		public static void UnblockMPButton()
		{
			isIgnore = false;
		}

		public bool CanBeSelected()
		{
			if (base.gameObject.activeInHierarchy)
			{
				if ((bool)requiredTopLayer)
				{
					return requiredTopLayer.representsTopLayer;
				}
				return true;
			}
			return false;
		}

		public bool InputModuleIsAllowed(BaseInputModule inputModule)
		{
			if (allowAllEventSystems)
			{
				return true;
			}
			EventSystem eventSystem = this.eventSystem;
			if ((bool)eventSystem)
			{
				return inputModule == eventSystem.currentInputModule;
			}
			return false;
		}

		private void AttemptSelection(PointerEventData eventData)
		{
			if ((bool)eventSystem && eventSystem.currentInputModule == eventData.currentInputModule)
			{
				eventSystem.SetSelectedGameObject(base.gameObject, eventData);
			}
		}

		public override void OnSelect(BaseEventData eventData)
		{
			onSelect?.Invoke();
			base.OnSelect(eventData);
		}

		public override void OnDeselect(BaseEventData eventData)
		{
			onDeselect?.Invoke();
			base.OnDeselect(eventData);
		}

		public override Selectable FindSelectableOnDown()
		{
			using (new ScopedReset<bool>(() => autonavigationFindInProgress, delegate(bool val)
			{
				autonavigationFindInProgress = val;
			}, tempVal: true))
			{
				return FilterSelectable(base.FindSelectableOnDown());
			}
		}

		public override Selectable FindSelectableOnLeft()
		{
			using (new ScopedReset<bool>(() => autonavigationFindInProgress, delegate(bool val)
			{
				autonavigationFindInProgress = val;
			}, tempVal: true))
			{
				onFindSelectableLeft?.Invoke();
				return FilterSelectable(base.FindSelectableOnLeft());
			}
		}

		public override Selectable FindSelectableOnRight()
		{
			using (new ScopedReset<bool>(() => autonavigationFindInProgress, delegate(bool val)
			{
				autonavigationFindInProgress = val;
			}, tempVal: true))
			{
				onFindSelectableRight?.Invoke();
				return FilterSelectable(base.FindSelectableOnRight());
			}
		}

		public override Selectable FindSelectableOnUp()
		{
			using (new ScopedReset<bool>(() => autonavigationFindInProgress, delegate(bool val)
			{
				autonavigationFindInProgress = val;
			}, tempVal: true))
			{
				return FilterSelectable(base.FindSelectableOnUp());
			}
		}

		public override void OnPointerEnter(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				base.OnPointerEnter(eventData);
				if (selectOnPointerEnter)
				{
					AttemptSelection(eventData);
				}
			}
		}

		public override void OnPointerExit(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				if ((bool)eventSystem && base.gameObject == eventSystem.currentSelectedGameObject)
				{
					base.enabled = false;
					base.enabled = true;
				}
				base.OnPointerExit(eventData);
			}
		}

		public override void OnPointerClick(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule) && !disablePointerClick)
			{
				base.OnPointerClick(eventData);
			}
		}

		public override void OnPointerUp(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule) && !disablePointerClick)
			{
				inPointerUp = true;
				base.OnPointerUp(eventData);
				inPointerUp = false;
			}
		}

		public override void OnPointerDown(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule) && !disablePointerClick)
			{
				if (IsInteractable() && base.navigation.mode != 0)
				{
					AttemptSelection(eventData);
				}
				base.OnPointerDown(eventData);
			}
		}

		public override void OnSubmit(BaseEventData eventData)
		{
			if ((!submitOnPointerUp || inPointerUp) && !disableGamepadClick)
			{
				base.OnSubmit(eventData);
			}
		}

		public void SetFallback(bool fallbackButton)
		{
		}
	}
	public struct MPControlHelper
	{
		private readonly MPEventSystemLocator eventSystemLocator;

		private readonly Selectable owner;

		private readonly GameObject gameObject;

		private readonly bool allowAllEventSystems;

		private readonly bool disablePointerClick;

		public MPEventSystem eventSystem => eventSystemLocator.eventSystem;

		public MPControlHelper(Selectable owner, MPEventSystemLocator eventSystemLocator, bool allowAllEventSystems, bool disablePointerClick)
		{
			this.owner = owner;
			this.eventSystemLocator = eventSystemLocator;
			gameObject = this.owner.gameObject;
			this.allowAllEventSystems = allowAllEventSystems;
			this.disablePointerClick = disablePointerClick;
		}

		public Selectable FilterSelectable(Selectable selectable)
		{
			if ((bool)selectable)
			{
				MPEventSystemLocator component = selectable.GetComponent<MPEventSystemLocator>();
				if (!component || component.eventSystem != eventSystemLocator.eventSystem)
				{
					selectable = null;
				}
			}
			return selectable;
		}

		public bool InputModuleIsAllowed(BaseInputModule inputModule)
		{
			if (allowAllEventSystems)
			{
				return true;
			}
			EventSystem eventSystem = this.eventSystem;
			if ((bool)eventSystem)
			{
				return inputModule == eventSystem.currentInputModule;
			}
			return false;
		}

		private void AttemptSelection(PointerEventData eventData)
		{
			if ((bool)eventSystem && eventSystem.currentInputModule == eventData.currentInputModule)
			{
				eventSystem.SetSelectedGameObject(gameObject, eventData);
			}
		}

		public Selectable FindSelectableOnDown(Func<Selectable> baseMethod)
		{
			return FilterSelectable(baseMethod());
		}

		public Selectable FindSelectableOnLeft(Func<Selectable> baseMethod)
		{
			return FilterSelectable(baseMethod());
		}

		public Selectable FindSelectableOnRight(Func<Selectable> baseMethod)
		{
			return FilterSelectable(baseMethod());
		}

		public Selectable FindSelectableOnUp(Func<Selectable> baseMethod)
		{
			return FilterSelectable(baseMethod());
		}

		public void OnPointerEnter(PointerEventData eventData, Action<PointerEventData> baseMethod)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				baseMethod(eventData);
				AttemptSelection(eventData);
			}
		}

		public void OnPointerExit(PointerEventData eventData, Action<PointerEventData> baseMethod)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				if ((bool)eventSystem && owner.gameObject == eventSystem.currentSelectedGameObject)
				{
					owner.enabled = false;
					owner.enabled = true;
				}
				baseMethod(eventData);
			}
		}

		public void OnPointerClick(PointerEventData eventData, Action<PointerEventData> baseMethod)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule) && !disablePointerClick)
			{
				baseMethod(eventData);
			}
		}

		public void OnPointerUp(PointerEventData eventData, Action<PointerEventData> baseMethod, ref bool inPointerUp)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule) && !disablePointerClick)
			{
				inPointerUp = true;
				baseMethod(eventData);
				inPointerUp = false;
			}
		}

		public void OnPointerDown(PointerEventData eventData, Action<PointerEventData> baseMethod, ref bool inPointerUp)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule) && !disablePointerClick)
			{
				if (owner.IsInteractable() && owner.navigation.mode != 0)
				{
					AttemptSelection(eventData);
				}
				baseMethod(eventData);
			}
		}

		public void OnSubmit(BaseEventData eventData, Action<BaseEventData> baseMethod, bool submitOnPointerUp, ref bool inPointerUp)
		{
			if (!submitOnPointerUp || inPointerUp)
			{
				baseMethod(eventData);
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class MPDropdown : TMP_Dropdown
	{
		private MPEventSystemLocator eventSystemLocator;

		protected bool isPointerInside;

		public bool allowAllEventSystems;

		private SelectionState previousState = SelectionState.Disabled;

		protected MPEventSystem eventSystem => eventSystemLocator.eventSystem;

		protected override void Awake()
		{
			base.Awake();
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private Selectable FilterSelectable(Selectable selectable)
		{
			if ((bool)selectable)
			{
				MPEventSystemLocator component = selectable.GetComponent<MPEventSystemLocator>();
				if (!component || component.eventSystem != eventSystemLocator.eventSystem)
				{
					selectable = null;
				}
			}
			return selectable;
		}

		public override Selectable FindSelectableOnDown()
		{
			return FilterSelectable(base.FindSelectableOnDown());
		}

		public override Selectable FindSelectableOnLeft()
		{
			return FilterSelectable(base.FindSelectableOnLeft());
		}

		public override Selectable FindSelectableOnRight()
		{
			return FilterSelectable(base.FindSelectableOnRight());
		}

		public override Selectable FindSelectableOnUp()
		{
			return FilterSelectable(base.FindSelectableOnUp());
		}

		public bool InputModuleIsAllowed(BaseInputModule inputModule)
		{
			if (allowAllEventSystems)
			{
				return true;
			}
			EventSystem eventSystem = this.eventSystem;
			if ((bool)eventSystem)
			{
				return inputModule == eventSystem.currentInputModule;
			}
			return false;
		}

		private void AttemptSelection(PointerEventData eventData)
		{
			if ((bool)eventSystem && eventSystem.currentInputModule == eventData.currentInputModule)
			{
				eventSystem.SetSelectedGameObject(base.gameObject, eventData);
			}
		}

		public override void OnPointerEnter(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				isPointerInside = true;
				base.OnPointerEnter(eventData);
				AttemptSelection(eventData);
			}
		}

		public override void OnPointerExit(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				if ((bool)eventSystem && base.gameObject == eventSystem.currentSelectedGameObject)
				{
					base.enabled = false;
					base.enabled = true;
				}
				isPointerInside = false;
				base.OnPointerExit(eventData);
			}
		}

		public override void OnPointerClick(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				base.OnPointerClick(eventData);
			}
		}

		public override void OnPointerUp(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				base.OnPointerUp(eventData);
			}
		}

		public override void OnPointerDown(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				if (IsInteractable() && base.navigation.mode != 0)
				{
					AttemptSelection(eventData);
				}
				base.OnPointerDown(eventData);
			}
		}

		protected override void OnDisable()
		{
			base.OnDisable();
			isPointerInside = false;
		}

		protected override void DoStateTransition(SelectionState state, bool instant)
		{
			base.DoStateTransition(state, instant);
			if (previousState != state)
			{
				if (state == SelectionState.Highlighted)
				{
					Util.PlaySound("Play_UI_menuHover", RoR2Application.instance.gameObject);
				}
				previousState = state;
			}
		}
	}
	[RequireComponent(typeof(RewiredStandaloneInputModule))]
	public class MPEventSystem : EventSystem
	{
		public enum InputSource
		{
			MouseAndKeyboard,
			Gamepad
		}

		private struct PushInfo
		{
			public int index;

			public UnityEngine.Vector2 position;

			public UnityEngine.Vector2 pushVector;
		}

		private static readonly List<MPEventSystem> instancesList;

		public static ReadOnlyCollection<MPEventSystem> readOnlyInstancesList;

		public int playerSlot = -1;

		[NonSerialized]
		public bool allowCursorPush = true;

		[NonSerialized]
		public bool isCombinedEventSystem;

		[HideInInspector]
		public MPButton currentSelectedButton;

		private CursorIndicatorController cursorIndicatorController;

		[NotNull]
		public Player player;

		[CanBeNull]
		public LocalUser localUser;

		public TooltipProvider currentTooltipProvider;

		public TooltipController currentTooltip;

		private static PushInfo[] pushInfos;

		private const float radius = 24f;

		private const float invRadius = 1f / 24f;

		private const float radiusSqr = 576f;

		private const float pushFactor = 10f;

		public static int activeCount { get; private set; }

		public int cursorOpenerCount { get; set; }

		public int cursorOpenerForGamepadCount { get; set; }

		public bool isHovering
		{
			get
			{
				if ((bool)base.currentInputModule)
				{
					return ((MPInputModule)base.currentInputModule).isHovering;
				}
				return false;
			}
		}

		public bool isCursorVisible => cursorIndicatorController.gameObject.activeInHierarchy;

		public InputSource currentInputSource { get; private set; } = InputSource.Gamepad;


		public InputMapperHelper inputMapperHelper { get; private set; }

		public static MPEventSystem FindByPlayer(Player player)
		{
			foreach (MPEventSystem instances in instancesList)
			{
				if (instances.player == player)
				{
					return instances;
				}
			}
			return null;
		}

		public static void RefreshAllControllerGlyphs()
		{
			foreach (MPEventSystem instances in instancesList)
			{
				if (instances.isActiveAndEnabled)
				{
					instances.RefreshControlGlyphs();
				}
			}
		}

		public void RefreshControlGlyphs()
		{
			OnLastActiveControllerChanged(player, player.controllers.GetLastActiveController());
		}

		protected override void Update()
		{
			EventSystem eventSystem = EventSystem.current;
			EventSystem.current = this;
			base.Update();
			EventSystem.current = eventSystem;
			ValidateCurrentSelectedGameobject();
			if (player.GetButtonDown(25) && (PauseScreenController.instancesList.Count == 0 || SimpleDialogBox.instancesList.Count == 0))
			{
				if (!PauseManager.isPaused)
				{
					PauseManager.PausingPlayerID = player.id;
				}
				if (PauseManager.PausingPlayerID == player.id)
				{
					Console.instance.SubmitCmd(null, "pause");
				}
			}
		}

		protected override void Awake()
		{
			base.Awake();
			instancesList.Add(this);
			cursorIndicatorController = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/CursorIndicator"), base.transform).GetComponent<CursorIndicatorController>();
			inputMapperHelper = new InputMapperHelper(this);
		}

		private void ValidateCurrentSelectedGameobject()
		{
			if ((bool)base.currentSelectedGameObject)
			{
				MPButton mPButton = (currentSelectedButton = base.currentSelectedGameObject.GetComponent<MPButton>());
				if ((bool)mPButton && (!mPButton.CanBeSelected() || (currentInputSource == InputSource.Gamepad && mPButton.navigation.mode == UnityEngine.UI.Navigation.Mode.None)))
				{
					SetSelectedGameObject(null);
					currentSelectedButton = null;
				}
			}
			else
			{
				currentSelectedButton = null;
			}
		}

		public void SetSelectedObject(GameObject o)
		{
			SetSelectedGameObject(o);
		}

		private static void OnActiveSceneChanged(Scene scene1, Scene scene2)
		{
			RecenterCursors();
		}

		private static void RecenterCursors()
		{
			foreach (MPEventSystem instances in instancesList)
			{
				if (instances.currentInputSource == InputSource.Gamepad && (bool)instances.currentInputModule)
				{
					((MPInput)instances.currentInputModule.input).CenterCursor();
				}
			}
		}

		protected override void OnDestroy()
		{
			player.controllers.RemoveLastActiveControllerChangedDelegate(OnLastActiveControllerChanged);
			instancesList.Remove(this);
			inputMapperHelper.Dispose();
			base.OnDestroy();
		}

		protected override void Start()
		{
			base.Start();
			SetCursorIndicatorEnabled(cursorIndicatorEnabled: false);
			if ((bool)base.currentInputModule && (bool)base.currentInputModule.input)
			{
				((MPInput)base.currentInputModule.input).CenterCursor();
			}
			player.controllers.AddLastActiveControllerChangedDelegate(OnLastActiveControllerChanged);
			OnLastActiveControllerChanged(player, player.controllers.GetLastActiveController());
		}

		protected override void OnEnable()
		{
			base.OnEnable();
			activeCount++;
		}

		protected override void OnDisable()
		{
			SetCursorIndicatorEnabled(cursorIndicatorEnabled: false);
			base.OnDisable();
			if (activeCount > 0)
			{
				activeCount--;
			}
		}

		protected void LateUpdate()
		{
			bool flag = false;
			if ((bool)base.currentInputModule && (bool)base.currentInputModule.input)
			{
				flag = ((currentInputSource != InputSource.Gamepad) ? (cursorOpenerCount > 0) : (cursorOpenerForGamepadCount > 0));
			}
			SetCursorIndicatorEnabled(flag);
			MPInputModule mPInputModule = base.currentInputModule as MPInputModule;
			if (flag)
			{
				CursorIndicatorController.CursorSet cursorSet = cursorIndicatorController.noneCursorSet;
				switch (currentInputSource)
				{
				case InputSource.MouseAndKeyboard:
					cursorSet = cursorIndicatorController.mouseCursorSet;
					break;
				case InputSource.Gamepad:
					cursorSet = cursorIndicatorController.gamepadCursorSet;
					break;
				}
				cursorIndicatorController.SetCursor(cursorSet, (!isHovering) ? CursorIndicatorController.CursorImage.Pointer : CursorIndicatorController.CursorImage.Hover, GetColor());
				cursorIndicatorController.SetPosition(mPInputModule.input.mousePosition);
			}
		}

		private void OnLastActiveControllerChanged(Player player, Controller controller)
		{
			if (controller != null)
			{
				switch (controller.type)
				{
				case ControllerType.Keyboard:
					currentInputSource = InputSource.MouseAndKeyboard;
					break;
				case ControllerType.Mouse:
					currentInputSource = InputSource.MouseAndKeyboard;
					break;
				case ControllerType.Joystick:
					currentInputSource = InputSource.Gamepad;
					break;
				}
				if (InputBindingDisplayController.onBindingsChanged != null && controller != null)
				{
					InputBindingDisplayController.onBindingsChanged();
				}
			}
		}

		private void SetCursorIndicatorEnabled(bool cursorIndicatorEnabled)
		{
			if (cursorIndicatorController.gameObject.activeSelf != cursorIndicatorEnabled)
			{
				cursorIndicatorController.gameObject.SetActive(cursorIndicatorEnabled);
				if (cursorIndicatorEnabled)
				{
					((MPInput)((MPInputModule)base.currentInputModule).input).CenterCursor();
				}
			}
		}

		public UnityEngine.Color GetColor()
		{
			if (activeCount <= 1)
			{
				return UnityEngine.Color.white;
			}
			return ColorCatalog.GetMultiplayerColor(playerSlot);
		}

		public bool GetCursorPosition(out UnityEngine.Vector2 position)
		{
			if ((bool)base.currentInputModule)
			{
				position = base.currentInputModule.input.mousePosition;
				return true;
			}
			position = UnityEngine.Vector2.zero;
			return false;
		}

		public UnityEngine.Rect GetScreenRect()
		{
			CameraRigController cameraRigController = localUser?.cameraRigController;
			if (!cameraRigController)
			{
				return new UnityEngine.Rect(0f, 0f, Screen.width, Screen.height);
			}
			return cameraRigController.viewport;
		}

		private static UnityEngine.Vector2 RandomOnCircle()
		{
			float value = UnityEngine.Random.value;
			return new UnityEngine.Vector2(Mathf.Cos(value * MathF.PI * 2f), Mathf.Sin(value * MathF.PI * 2f));
		}

		private static UnityEngine.Vector2 CalculateCursorPushVector(UnityEngine.Vector2 positionA, UnityEngine.Vector2 positionB)
		{
			UnityEngine.Vector2 vector = positionA - positionB;
			if (vector == UnityEngine.Vector2.zero)
			{
				vector = RandomOnCircle();
			}
			float sqrMagnitude = vector.sqrMagnitude;
			if (sqrMagnitude >= 576f)
			{
				return UnityEngine.Vector2.zero;
			}
			float num = Mathf.Sqrt(sqrMagnitude);
			float num2 = num * (1f / 24f);
			float num3 = 1f - num2;
			return vector / num * num3 * 10f * 0.5f;
		}

		private static void PushCursorsApart()
		{
			if (activeCount <= 1)
			{
				return;
			}
			int count = instancesList.Count;
			if (pushInfos.Length < activeCount)
			{
				pushInfos = new PushInfo[activeCount];
			}
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				if (instancesList[i].enabled)
				{
					instancesList[i].GetCursorPosition(out var position);
					pushInfos[num++] = new PushInfo
					{
						index = i,
						position = position
					};
				}
			}
			for (int j = 0; j < activeCount; j++)
			{
				PushInfo pushInfo = pushInfos[j];
				for (int k = j + 1; k < activeCount; k++)
				{
					PushInfo pushInfo2 = pushInfos[k];
					UnityEngine.Vector2 vector = CalculateCursorPushVector(pushInfo.position, pushInfo2.position);
					pushInfo.pushVector += vector;
					pushInfo2.pushVector -= vector;
					pushInfos[k] = pushInfo2;
				}
				pushInfos[j] = pushInfo;
			}
			for (int l = 0; l < activeCount; l++)
			{
				PushInfo pushInfo3 = pushInfos[l];
				MPEventSystem mPEventSystem = instancesList[pushInfo3.index];
				if (mPEventSystem.allowCursorPush && (bool)mPEventSystem.currentInputModule)
				{
					((MPInput)mPEventSystem.currentInputModule.input).internalMousePosition += pushInfo3.pushVector;
				}
			}
		}

		static MPEventSystem()
		{
			instancesList = new List<MPEventSystem>();
			readOnlyInstancesList = new ReadOnlyCollection<MPEventSystem>(instancesList);
			pushInfos = Array.Empty<PushInfo>();
			RoR2Application.onUpdate += PushCursorsApart;
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
		}
	}
	public class MPInputSource : IMouseInputSource
	{
		public int playerId { get; }

		public bool enabled { get; }

		public bool locked { get; }

		public int buttonCount { get; }

		public UnityEngine.Vector2 screenPosition { get; }

		public UnityEngine.Vector2 screenPositionDelta { get; }

		public UnityEngine.Vector2 wheelDelta { get; }

		public bool GetButtonDown(int button)
		{
			throw new NotImplementedException();
		}

		public bool GetButtonUp(int button)
		{
			throw new NotImplementedException();
		}

		public bool GetButton(int button)
		{
			throw new NotImplementedException();
		}
	}
	public class MPEventSystemLocator : MonoBehaviour
	{
		private MPEventSystemProvider _eventSystemProvider;

		private MPEventSystem _eventSystem;

		public MPEventSystemProvider eventSystemProvider
		{
			get
			{
				return _eventSystemProvider;
			}
			internal set
			{
				if ((object)_eventSystemProvider != value)
				{
					_eventSystemProvider?.RemoveListener(this);
					_eventSystemProvider = value;
					_eventSystemProvider?.AddListener(this);
				}
			}
		}

		public MPEventSystem eventSystem
		{
			get
			{
				return _eventSystem;
			}
			internal set
			{
				if ((object)_eventSystem != value)
				{
					if ((object)_eventSystem != null)
					{
						OnEventSystemLost(_eventSystem);
					}
					_eventSystem = value;
					if ((object)_eventSystem != null)
					{
						OnEventSystemDiscovered(_eventSystem);
					}
				}
			}
		}

		public event Action<MPEventSystem> onEventSystemDiscovered;

		public event Action<MPEventSystem> onEventSystemLost;

		private void Awake()
		{
			eventSystemProvider = GetComponentInParent<MPEventSystemProvider>();
		}

		private void OnDestroy()
		{
			eventSystemProvider = null;
		}

		private void OnEventSystemDiscovered(MPEventSystem discoveredEventSystem)
		{
			this.onEventSystemDiscovered?.Invoke(discoveredEventSystem);
		}

		private void OnEventSystemLost(MPEventSystem lostEventSystem)
		{
			this.onEventSystemLost?.Invoke(lostEventSystem);
		}

		internal void OnProviderDestroyed(MPEventSystemProvider destroyedEventSystemProvider)
		{
			if ((object)destroyedEventSystemProvider == eventSystemProvider)
			{
				eventSystemProvider = null;
			}
		}
	}
	public class MPEventSystemProvider : MonoBehaviour
	{
		[FormerlySerializedAs("eventSystem")]
		[SerializeField]
		private MPEventSystem _eventSystem;

		public bool fallBackToMainEventSystem = true;

		public bool fallBackToPlayer2EventSystem;

		public bool fallBackToPlayer3EventSystem;

		public bool fallBackToPlayer4EventSystem;

		private MPEventSystem _resolvedEventSystem;

		private List<MPEventSystemLocator> listeners = new List<MPEventSystemLocator>();

		public MPEventSystem eventSystem
		{
			get
			{
				return _eventSystem;
			}
			set
			{
				if ((object)_eventSystem != value)
				{
					_eventSystem = value;
					ResolveEventSystem();
				}
			}
		}

		public MPEventSystem resolvedEventSystem
		{
			get
			{
				return _resolvedEventSystem;
			}
			private set
			{
				if ((object)_resolvedEventSystem != value)
				{
					_resolvedEventSystem = value;
					for (int num = listeners.Count - 1; num >= 0; num--)
					{
						listeners[num].eventSystem = _resolvedEventSystem;
					}
				}
			}
		}

		private void Awake()
		{
			ResolveEventSystem();
		}

		private void OnEnable()
		{
			ResolveEventSystem();
		}

		private void OnDisable()
		{
			resolvedEventSystem = null;
		}

		private void OnDestroy()
		{
			for (int num = listeners.Count - 1; num >= 0; num--)
			{
				listeners[num].OnProviderDestroyed(this);
			}
		}

		private void Update()
		{
			ResolveEventSystem();
		}

		private void ResolveEventSystem()
		{
			if ((bool)eventSystem)
			{
				resolvedEventSystem = eventSystem;
			}
			else if (fallBackToMainEventSystem)
			{
				resolvedEventSystem = MPEventSystemManager.primaryEventSystem;
			}
			else if (fallBackToPlayer2EventSystem)
			{
				resolvedEventSystem = MPEventSystem.FindByPlayer(LocalUserManager.FindLocalUserByPlayerName("Player2")?.inputPlayer ?? null);
			}
			else if (fallBackToPlayer3EventSystem)
			{
				resolvedEventSystem = MPEventSystem.FindByPlayer(LocalUserManager.FindLocalUserByPlayerName("Player3")?.inputPlayer ?? null);
			}
			else if (fallBackToPlayer4EventSystem)
			{
				resolvedEventSystem = MPEventSystem.FindByPlayer(LocalUserManager.FindLocalUserByPlayerName("Player4")?.inputPlayer ?? null);
			}
		}

		internal void AddListener(MPEventSystemLocator listener)
		{
			listeners.Add(listener);
			listener.eventSystem = resolvedEventSystem;
		}

		internal void RemoveListener(MPEventSystemLocator listener)
		{
			listener.eventSystem = null;
			listeners.Remove(listener);
		}
	}
	[RequireComponent(typeof(MPInput))]
	public class MPInputModule : RewiredStandaloneInputModule
	{
		private delegate bool ShouldStartDragDelegate(UnityEngine.Vector2 pressPos, UnityEngine.Vector2 currentPos, float threshold, bool useDragThreshold);

		private MouseState m_MouseState;

		private static readonly FieldInfo m_MouseStateField = typeof(RewiredPointerInputModule).GetField("m_MouseState", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly ShouldStartDragDelegate ShouldStartDrag = (ShouldStartDragDelegate)typeof(RewiredPointerInputModule).GetMethod("ShouldStartDrag", BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate(typeof(ShouldStartDragDelegate));

		public bool isHovering;

		private bool useCursor => ((MPEventSystem)base.eventSystem).isCursorVisible;

		protected override void Awake()
		{
			m_InputOverride = GetComponent<MPInput>();
			m_MouseState = (MouseState)m_MouseStateField.GetValue(this);
			base.Awake();
		}

		protected override void Start()
		{
			base.Start();
			ClearMouseInputSources();
			AddMouseInputSource((MPInput)m_InputOverride);
		}

		protected void UpdateHover(List<RaycastResult> raycastResults)
		{
			isHovering = false;
			if (!useCursor)
			{
				return;
			}
			foreach (RaycastResult raycastResult in raycastResults)
			{
				if ((bool)raycastResult.gameObject)
				{
					Selectable componentInParent = raycastResult.gameObject.GetComponentInParent<Selectable>();
					if (componentInParent != null && IsHoverable(componentInParent))
					{
						isHovering = true;
						break;
					}
				}
			}
			bool IsHoverable(Selectable selectable)
			{
				MPButton mPButton = selectable as MPButton;
				if (!mPButton)
				{
					return true;
				}
				return mPButton.InputModuleIsAllowed(this);
			}
		}

		protected override MouseState GetMousePointerEventData(int playerId, int mouseIndex)
		{
			IMouseInputSource mouseInputSource = GetMouseInputSource(playerId, mouseIndex);
			if (mouseInputSource == null)
			{
				return null;
			}
			PlayerPointerEventData data;
			bool pointerData = GetPointerData(playerId, mouseIndex, -1, out data, create: true, PointerEventType.Mouse);
			data.Reset();
			if (pointerData)
			{
				data.position = base.input.mousePosition;
			}
			UnityEngine.Vector2 mousePosition = base.input.mousePosition;
			if (mouseInputSource.locked)
			{
				data.position = new UnityEngine.Vector2(-1f, -1f);
				data.delta = UnityEngine.Vector2.zero;
			}
			else
			{
				data.delta = mousePosition - data.position;
				data.position = mousePosition;
			}
			data.scrollDelta = mouseInputSource.wheelDelta;
			data.button = PointerEventData.InputButton.Left;
			base.eventSystem.RaycastAll(data, m_RaycastResultCache);
			RaycastResult pointerCurrentRaycast = BaseInputModule.FindFirstRaycast(m_RaycastResultCache);
			data.pointerCurrentRaycast = pointerCurrentRaycast;
			UpdateHover(m_RaycastResultCache);
			m_RaycastResultCache.Clear();
			GetPointerData(playerId, mouseIndex, -2, out var data2, create: true, PointerEventType.Mouse);
			CopyFromTo(data, data2);
			data2.button = PointerEventData.InputButton.Right;
			GetPointerData(playerId, mouseIndex, -3, out var data3, create: true, PointerEventType.Mouse);
			CopyFromTo(data, data3);
			data3.button = PointerEventData.InputButton.Middle;
			for (int i = 3; i < mouseInputSource.buttonCount; i++)
			{
				GetPointerData(playerId, mouseIndex, -2147483520 + i, out var data4, create: true, PointerEventType.Mouse);
				CopyFromTo(data, data4);
				data4.button = (PointerEventData.InputButton)(-1);
			}
			m_MouseState.SetButtonState(0, StateForMouseButton(playerId, mouseIndex, 0), data);
			m_MouseState.SetButtonState(1, StateForMouseButton(playerId, mouseIndex, 1), data2);
			m_MouseState.SetButtonState(2, StateForMouseButton(playerId, mouseIndex, 2), data3);
			for (int j = 3; j < mouseInputSource.buttonCount; j++)
			{
				GetPointerData(playerId, mouseIndex, -2147483520 + j, out var data5, create: false, PointerEventType.Mouse);
				m_MouseState.SetButtonState(j, StateForMouseButton(playerId, mouseIndex, j), data5);
			}
			return m_MouseState;
		}

		protected override void ProcessMove(PlayerPointerEventData pointerEvent)
		{
			GameObject newEnterTarget = ((!useCursor) ? null : pointerEvent.pointerCurrentRaycast.gameObject);
			HandlePointerExitAndEnter(pointerEvent, newEnterTarget);
		}

		protected override void ProcessDrag(PlayerPointerEventData pointerEvent)
		{
			if (!pointerEvent.IsPointerMoving() || !useCursor || pointerEvent.pointerDrag == null)
			{
				return;
			}
			if (!pointerEvent.dragging && ShouldStartDrag(pointerEvent.pressPosition, pointerEvent.position, base.eventSystem.pixelDragThreshold, pointerEvent.useDragThreshold))
			{
				ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
				pointerEvent.dragging = true;
			}
			if (pointerEvent.dragging)
			{
				if (pointerEvent.pointerPress != pointerEvent.pointerDrag)
				{
					ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
					pointerEvent.eligibleForClick = false;
					pointerEvent.pointerPress = null;
					pointerEvent.rawPointerPress = null;
				}
				ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler);
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class MPScrollbar : Scrollbar
	{
		public bool allowAllEventSystems;

		private MPEventSystemLocator eventSystemLocator;

		private RectTransform viewPortRectTransform;

		private EventSystem eventSystem => eventSystemLocator.eventSystem;

		protected override void Awake()
		{
			base.Awake();
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private Selectable FilterSelectable(Selectable selectable)
		{
			if ((bool)selectable)
			{
				MPEventSystemLocator component = selectable.GetComponent<MPEventSystemLocator>();
				if (!component || component.eventSystem != eventSystemLocator.eventSystem)
				{
					selectable = null;
				}
			}
			return selectable;
		}

		public bool InputModuleIsAllowed(BaseInputModule inputModule)
		{
			if (allowAllEventSystems)
			{
				return true;
			}
			EventSystem eventSystem = this.eventSystem;
			if ((bool)eventSystem)
			{
				return inputModule == eventSystem.currentInputModule;
			}
			return false;
		}

		public override Selectable FindSelectableOnDown()
		{
			return FilterSelectable(base.FindSelectableOnDown());
		}

		public override Selectable FindSelectableOnLeft()
		{
			return FilterSelectable(base.FindSelectableOnLeft());
		}

		public override Selectable FindSelectableOnRight()
		{
			return FilterSelectable(base.FindSelectableOnRight());
		}

		public override Selectable FindSelectableOnUp()
		{
			return FilterSelectable(base.FindSelectableOnUp());
		}

		public override void OnPointerUp(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				if ((bool)eventSystem && base.gameObject == eventSystem.currentSelectedGameObject)
				{
					base.enabled = false;
					base.enabled = true;
				}
				base.OnPointerUp(eventData);
			}
		}

		public override void OnSelect(BaseEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				base.OnSelect(eventData);
			}
		}

		public override void OnDeselect(BaseEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				base.OnDeselect(eventData);
			}
		}

		public override void OnPointerEnter(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				base.OnPointerEnter(eventData);
			}
		}

		public override void OnPointerExit(PointerEventData eventData)
		{
			if (InputModuleIsAllowed(eventData.currentInputModule))
			{
				base.OnPointerExit(eventData);
			}
		}

		public override void OnPointerDown(PointerEventData eventData)
		{
			if (eventData.button == PointerEventData.InputButton.Left)
			{
				if (IsInteractable() && base.navigation.mode != 0)
				{
					eventSystem.SetSelectedGameObject(base.gameObject, eventData);
				}
				base.OnPointerDown(eventData);
			}
		}

		public override void Select()
		{
			if (!eventSystem.alreadySelecting)
			{
				eventSystem.SetSelectedGameObject(base.gameObject);
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class MPToggle : Toggle
	{
		private MPControlHelper mpControlHelper;

		public bool allowAllEventSystems;

		public bool disablePointerClick;

		public Graphic hoverGraphic;

		private bool inPointerUp;

		protected override void Awake()
		{
			base.Awake();
			mpControlHelper = new MPControlHelper(this, GetComponent<MPEventSystemLocator>(), allowAllEventSystems, disablePointerClick);
		}

		private void LateUpdate()
		{
			if ((bool)hoverGraphic)
			{
				bool flag = base.currentSelectionState == SelectionState.Highlighted;
				if (hoverGraphic.enabled != flag)
				{
					hoverGraphic.enabled = flag;
				}
			}
		}

		public override void OnPointerEnter(PointerEventData eventData)
		{
			mpControlHelper.OnPointerEnter(eventData, base.OnPointerEnter);
		}

		public override void OnPointerExit(PointerEventData eventData)
		{
			mpControlHelper.OnPointerExit(eventData, base.OnPointerExit);
		}

		public override void OnPointerClick(PointerEventData eventData)
		{
			mpControlHelper.OnPointerClick(eventData, base.OnPointerClick);
		}

		public override void OnPointerUp(PointerEventData eventData)
		{
			mpControlHelper.OnPointerUp(eventData, base.OnPointerUp, ref inPointerUp);
		}

		public override void OnPointerDown(PointerEventData eventData)
		{
			mpControlHelper.OnPointerDown(eventData, base.OnPointerDown, ref inPointerUp);
		}

		public override Selectable FindSelectableOnDown()
		{
			return mpControlHelper.FindSelectableOnDown(base.FindSelectableOnDown);
		}

		public override Selectable FindSelectableOnLeft()
		{
			return mpControlHelper.FindSelectableOnLeft(base.FindSelectableOnLeft);
		}

		public override Selectable FindSelectableOnRight()
		{
			return mpControlHelper.FindSelectableOnRight(base.FindSelectableOnRight);
		}

		public override Selectable FindSelectableOnUp()
		{
			return mpControlHelper.FindSelectableOnUp(base.FindSelectableOnUp);
		}
	}
	public class Nameplate : MonoBehaviour
	{
		public TextMeshPro label;

		private CharacterBody body;

		public GameObject aliveObject;

		public GameObject deadObject;

		public SpriteRenderer criticallyHurtSpriteRenderer;

		public SpriteRenderer[] coloredSprites;

		public UnityEngine.Color baseColor;

		public UnityEngine.Color combatColor;

		public void SetBody(CharacterBody body)
		{
			this.body = body;
		}

		private void LateUpdate()
		{
			string text = "";
			UnityEngine.Color color = baseColor;
			bool flag = true;
			bool flag2 = false;
			bool flag3 = false;
			if ((bool)body)
			{
				text = body.GetDisplayName();
				flag = body.healthComponent.alive;
				flag2 = !body.outOfCombat || !body.outOfDanger;
				flag3 = body.healthComponent.isHealthLow;
				CharacterMaster master = body.master;
				if ((bool)master)
				{
					PlayerCharacterMasterController component = master.GetComponent<PlayerCharacterMasterController>();
					if ((bool)component)
					{
						GameObject networkUserObject = component.networkUserObject;
						if ((bool)networkUserObject)
						{
							NetworkUser component2 = networkUserObject.GetComponent<NetworkUser>();
							if ((bool)component2)
							{
								text = component2.userName;
							}
						}
					}
					else
					{
						text = Language.GetString(body.baseNameToken);
					}
				}
			}
			color = (flag2 ? combatColor : baseColor);
			aliveObject.SetActive(flag);
			deadObject.SetActive(!flag);
			if ((bool)criticallyHurtSpriteRenderer)
			{
				criticallyHurtSpriteRenderer.enabled = flag3 && flag;
				criticallyHurtSpriteRenderer.color = HealthBar.GetCriticallyHurtColor();
			}
			if ((bool)label)
			{
				label.text = text;
				label.color = color;
			}
			SpriteRenderer[] array = coloredSprites;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].color = color;
			}
		}
	}
	public class NotificationUIController : MonoBehaviour
	{
		[SerializeField]
		private HUD hud;

		[SerializeField]
		private GameObject genericNotificationPrefab;

		[SerializeField]
		private GameObject genericTransformationNotificationPrefab;

		[SerializeField]
		private GameObject contagiousVoidTransformationNotificationPrefab;

		[SerializeField]
		private GameObject suppressedTransformationNotificationPrefab;

		[SerializeField]
		private GameObject cloverVoidTransformationNotificationPrefab;

		[SerializeField]
		private GameObject lunarSunTransformationNotificationPrefab;

		[SerializeField]
		private GameObject regeneratingScrapRegenTransformationNotificationPrefab;

		[SerializeField]
		private GameObject LowerPricedChestsRegenTransformationNotificationPrefab;

		[SerializeField]
		private GameObject teleportOnLowHealthRegenTransformationNotificationPrefab;

		private GenericNotification currentNotification;

		private CharacterMasterNotificationQueue notificationQueue;

		private CharacterMaster targetMaster;

		public void OnEnable()
		{
			CharacterMaster.onCharacterMasterLost += OnCharacterMasterLost;
		}

		public void OnDisable()
		{
			CharacterMaster.onCharacterMasterLost -= OnCharacterMasterLost;
			CleanUpCurrentMaster();
		}

		public void Update()
		{
			if (hud.targetMaster != targetMaster)
			{
				SetTargetMaster(hud.targetMaster);
			}
			if ((bool)currentNotification && (bool)notificationQueue)
			{
				currentNotification.SetNotificationT(notificationQueue.GetCurrentNotificationT());
			}
		}

		private void SetUpNotification(CharacterMasterNotificationQueue.NotificationInfo notificationInfo)
		{
			object previousData;
			if (notificationInfo.transformation != null)
			{
				GameObject lowerPricedChestsRegenTransformationNotificationPrefab = genericTransformationNotificationPrefab;
				switch (notificationInfo.transformation.transformationType)
				{
				case CharacterMasterNotificationQueue.TransformationType.CloverVoid:
					if ((bool)cloverVoidTransformationNotificationPrefab)
					{
						lowerPricedChestsRegenTransformationNotificationPrefab = cloverVoidTransformationNotificationPrefab;
					}
					break;
				case CharacterMasterNotificationQueue.TransformationType.ContagiousVoid:
					if ((bool)contagiousVoidTransformationNotificationPrefab)
					{
						lowerPricedChestsRegenTransformationNotificationPrefab = contagiousVoidTransformationNotificationPrefab;
					}
					break;
				case CharacterMasterNotificationQueue.TransformationType.Suppressed:
					if ((bool)suppressedTransformationNotificationPrefab)
					{
						lowerPricedChestsRegenTransformationNotificationPrefab = suppressedTransformationNotificationPrefab;
					}
					break;
				case CharacterMasterNotificationQueue.TransformationType.LunarSun:
					if ((bool)lunarSunTransformationNotificationPrefab)
					{
						lowerPricedChestsRegenTransformationNotificationPrefab = lunarSunTransformationNotificationPrefab;
					}
					break;
				case CharacterMasterNotificationQueue.TransformationType.RegeneratingScrapRegen:
					if ((bool)regeneratingScrapRegenTransformationNotificationPrefab)
					{
						lowerPricedChestsRegenTransformationNotificationPrefab = regeneratingScrapRegenTransformationNotificationPrefab;
					}
					break;
				case CharacterMasterNotificationQueue.TransformationType.SaleStarRegen:
					if ((bool)LowerPricedChestsRegenTransformationNotificationPrefab)
					{
						lowerPricedChestsRegenTransformationNotificationPrefab = LowerPricedChestsRegenTransformationNotificationPrefab;
					}
					break;
				case CharacterMasterNotificationQueue.TransformationType.TeleportOnLowHealthRegen:
					if ((bool)teleportOnLowHealthRegenTransformationNotificationPrefab)
					{
						lowerPricedChestsRegenTransformationNotificationPrefab = teleportOnLowHealthRegenTransformationNotificationPrefab;
					}
					break;
				}
				currentNotification = UnityEngine.Object.Instantiate(lowerPricedChestsRegenTransformationNotificationPrefab).GetComponent<GenericNotification>();
				previousData = notificationInfo.transformation.previousData;
				if (!(previousData is ItemDef previousItem))
				{
					if (previousData is EquipmentDef previousEquipment)
					{
						currentNotification.SetPreviousEquipment(previousEquipment);
					}
				}
				else
				{
					currentNotification.SetPreviousItem(previousItem);
				}
			}
			else
			{
				currentNotification = UnityEngine.Object.Instantiate(genericNotificationPrefab).GetComponent<GenericNotification>();
			}
			previousData = notificationInfo.data;
			if (!(previousData is ItemDef item))
			{
				if (!(previousData is EquipmentDef equipment))
				{
					if (previousData is ArtifactDef artifact)
					{
						currentNotification.SetArtifact(artifact);
					}
				}
				else
				{
					currentNotification.SetEquipment(equipment);
				}
			}
			else
			{
				currentNotification.SetItem(item);
			}
			currentNotification.GetComponent<RectTransform>().SetParent(GetComponent<RectTransform>(), worldPositionStays: false);
		}

		private void OnCurrentNotificationChanged(CharacterMasterNotificationQueue notificationQueue)
		{
			ShowCurrentNotification(notificationQueue);
		}

		private void ShowCurrentNotification(CharacterMasterNotificationQueue notificationQueue)
		{
			DestroyCurrentNotification();
			CharacterMasterNotificationQueue.NotificationInfo notificationInfo = notificationQueue.GetCurrentNotification();
			if (notificationInfo != null)
			{
				SetUpNotification(notificationInfo);
			}
		}

		private void DestroyCurrentNotification()
		{
			if ((bool)currentNotification)
			{
				UnityEngine.Object.Destroy(currentNotification.gameObject);
				currentNotification = null;
			}
		}

		private void SetTargetMaster(CharacterMaster newMaster)
		{
			DestroyCurrentNotification();
			CleanUpCurrentMaster();
			targetMaster = newMaster;
			if ((bool)newMaster)
			{
				notificationQueue = CharacterMasterNotificationQueue.GetNotificationQueueForMaster(newMaster);
				notificationQueue.onCurrentNotificationChanged += OnCurrentNotificationChanged;
				ShowCurrentNotification(notificationQueue);
			}
		}

		private void OnCharacterMasterLost(CharacterMaster master)
		{
			if ((object)master == targetMaster)
			{
				CleanUpCurrentMaster();
			}
		}

		private void CleanUpCurrentMaster()
		{
			if ((bool)notificationQueue)
			{
				notificationQueue.onCurrentNotificationChanged -= OnCurrentNotificationChanged;
			}
			notificationQueue = null;
			targetMaster = null;
		}
	}
	public class ObjectivePanelController : MonoBehaviour
	{
		public struct ObjectiveSourceDescriptor : IEquatable<ObjectiveSourceDescriptor>
		{
			public UnityEngine.Object source;

			public CharacterMaster master;

			public Type objectiveType;

			public override int GetHashCode()
			{
				return (((((source != null) ? source.GetHashCode() : 0) * 397) ^ ((master != null) ? master.GetHashCode() : 0)) * 397) ^ ((objectiveType != null) ? objectiveType.GetHashCode() : 0);
			}

			public static bool Equals(ObjectiveSourceDescriptor a, ObjectiveSourceDescriptor b)
			{
				if (a.source == b.source && a.master == b.master)
				{
					return a.objectiveType == b.objectiveType;
				}
				return false;
			}

			public bool Equals(ObjectiveSourceDescriptor other)
			{
				if (source == other.source && master == other.master)
				{
					return objectiveType == other.objectiveType;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is ObjectiveSourceDescriptor)
				{
					return Equals((ObjectiveSourceDescriptor)obj);
				}
				return false;
			}
		}

		public class ObjectiveTracker
		{
			public ObjectiveSourceDescriptor sourceDescriptor;

			public ObjectivePanelController owner;

			public bool isRelevant;

			public bool isPrimary;

			public bool isTutorialCrossfading;

			public bool useLayoutAnimation;

			protected UnityEngine.UI.Image checkbox;

			protected TextMeshProUGUI label;

			protected string cachedString;

			protected string baseToken = "";

			protected bool retired;

			protected bool lastRetiredState;

			public GameObject stripObject { get; private set; }

			protected virtual bool shouldConsiderComplete => retired;

			public void SetStrip(GameObject stripObject)
			{
				this.stripObject = stripObject;
				label = stripObject.transform.Find("Label").GetComponent<TextMeshProUGUI>();
				checkbox = label.transform.Find("Checkbox").GetComponent<UnityEngine.UI.Image>();
				UpdateStrip();
			}

			public string GetString()
			{
				if (IsDirty())
				{
					cachedString = GenerateString();
				}
				return cachedString;
			}

			protected virtual string GenerateString()
			{
				return Language.GetString(baseToken);
			}

			protected virtual bool IsDirty()
			{
				return cachedString == null;
			}

			public void Retire()
			{
				retired = true;
				OnRetired();
				UpdateStrip();
			}

			protected virtual void OnRetired()
			{
			}

			public virtual void UpdateStrip()
			{
				if ((bool)label && GetString() != label.text)
				{
					label.text = GetString();
					label.color = (retired ? UnityEngine.Color.gray : UnityEngine.Color.white);
					if (retired)
					{
						label.fontStyle |= FontStyles.Strikethrough;
					}
				}
				if ((bool)checkbox)
				{
					bool flag = shouldConsiderComplete;
					if (flag != lastRetiredState)
					{
						checkbox.sprite = (flag ? owner.checkboxSuccessSprite : owner.checkboxActiveSprite);
						checkbox.color = (flag ? UnityEngine.Color.yellow : UnityEngine.Color.white);
						lastRetiredState = flag;
					}
				}
			}

			public static ObjectiveTracker Instantiate(ObjectiveSourceDescriptor sourceDescriptor)
			{
				if (sourceDescriptor.objectiveType != null && sourceDescriptor.objectiveType.IsSubclassOf(typeof(ObjectiveTracker)))
				{
					ObjectiveTracker obj = (ObjectiveTracker)Activator.CreateInstance(sourceDescriptor.objectiveType);
					obj.sourceDescriptor = sourceDescriptor;
					return obj;
				}
				UnityEngine.Debug.LogFormat("Bad objectiveType {0}", sourceDescriptor.objectiveType?.FullName);
				return null;
			}
		}

		private class FindTeleporterObjectiveTracker : ObjectiveTracker
		{
			public FindTeleporterObjectiveTracker()
			{
				baseToken = "OBJECTIVE_FIND_TELEPORTER";
				isPrimary = true;
			}
		}

		private class ActivateGoldshoreBeaconTracker : ObjectiveTracker
		{
			private int cachedActiveBeaconCount = -1;

			private int cachedRequiredBeaconCount = -1;

			private GoldshoresMissionController missionController => sourceDescriptor.source as GoldshoresMissionController;

			public ActivateGoldshoreBeaconTracker()
			{
				baseToken = "OBJECTIVE_GOLDSHORES_ACTIVATE_BEACONS";
			}

			private bool UpdateCachedValues()
			{
				int beaconsActive = missionController.beaconsActive;
				int beaconCount = missionController.beaconCount;
				if (beaconsActive != cachedActiveBeaconCount || beaconCount != cachedRequiredBeaconCount)
				{
					cachedActiveBeaconCount = beaconsActive;
					cachedRequiredBeaconCount = beaconCount;
					return true;
				}
				return false;
			}

			protected override string GenerateString()
			{
				UpdateCachedValues();
				return string.Format(Language.GetString(baseToken), cachedActiveBeaconCount, cachedRequiredBeaconCount);
			}

			protected override bool IsDirty()
			{
				if (!(sourceDescriptor.source as GoldshoresMissionController))
				{
					return true;
				}
				return UpdateCachedValues();
			}
		}

		private class ClearArena : ObjectiveTracker
		{
			public ClearArena()
			{
				baseToken = "OBJECTIVE_CLEAR_ARENA";
			}

			protected override string GenerateString()
			{
				ArenaMissionController instance = ArenaMissionController.instance;
				return string.Format(Language.GetString(baseToken), instance.clearedRounds, instance.totalRoundsMax);
			}

			protected override bool IsDirty()
			{
				return true;
			}
		}

		private class DestroyTimeCrystals : ObjectiveTracker
		{
			public DestroyTimeCrystals()
			{
				baseToken = "OBJECTIVE_WEEKLYRUN_DESTROY_CRYSTALS";
			}

			protected override string GenerateString()
			{
				WeeklyRun weeklyRun = Run.instance as WeeklyRun;
				return string.Format(Language.GetString(baseToken), weeklyRun.crystalsKilled, weeklyRun.crystalsRequiredToKill);
			}

			protected override bool IsDirty()
			{
				return true;
			}
		}

		private class FinishTeleporterObjectiveTracker : ObjectiveTracker
		{
			public FinishTeleporterObjectiveTracker()
			{
				baseToken = "OBJECTIVE_FINISH_TELEPORTER";
			}
		}

		private class ObjectiveStripAnimation
		{
			public enum StripAnimationType
			{
				Enter,
				Exit
			}

			public float percentComplete;

			public readonly ObjectiveTracker objectiveTracker;

			protected readonly LayoutElement layoutElement;

			protected readonly CanvasGroup canvasGroup;

			protected readonly ObjectiveStripAnimationParams AnimParams;

			protected readonly StripAnimationType _animationType;

			public StripAnimationType AnimationType => _animationType;

			protected ObjectiveStripAnimation(ObjectiveTracker objectiveTracker, StripAnimationType animType)
			{
				_animationType = animType;
				if ((bool)objectiveTracker.stripObject)
				{
					this.objectiveTracker = objectiveTracker;
					layoutElement = objectiveTracker.stripObject.GetComponent<LayoutElement>();
					canvasGroup = objectiveTracker.stripObject.GetComponent<CanvasGroup>();
					AnimParams = objectiveTracker.stripObject.GetComponent<ObjectiveStripAnimationParams>();
				}
			}

			public virtual void SetPercentComplete(float newPercentComplete)
			{
				percentComplete = newPercentComplete;
			}
		}

		private class StripExitAnimation : ObjectiveStripAnimation
		{
			protected readonly float originalHeight;

			protected float alphaStartPercent;

			protected float alphaEndPercent;

			protected float heightStartPercent;

			protected float heightEndPercent;

			public StripExitAnimation(ObjectiveTracker objectiveTracker)
				: base(objectiveTracker, StripAnimationType.Exit)
			{
				alphaStartPercent = AnimParams.GetParam("exitAlphaStartPercent", 0.5f);
				alphaEndPercent = AnimParams.GetParam("exitAlphaEndPercent", 0.75f);
				heightStartPercent = AnimParams.GetParam("exitHeightStartPercent", 0.75f);
				heightEndPercent = AnimParams.GetParam("exitHeightEndPercent", 1f);
				if ((bool)objectiveTracker.stripObject)
				{
					originalHeight = layoutElement.minHeight;
				}
			}

			public override void SetPercentComplete(float newPercentComplete)
			{
				base.SetPercentComplete(newPercentComplete);
				if ((bool)objectiveTracker.stripObject)
				{
					float alpha = Mathf.Clamp01(Util.Remap(percentComplete, alphaStartPercent, alphaEndPercent, 1f, 0f));
					canvasGroup.alpha = alpha;
					float num = Mathf.Clamp01(Util.Remap(percentComplete, heightStartPercent, heightEndPercent, 1f, 0f));
					num *= num;
					layoutElement.minHeight = num * originalHeight;
					layoutElement.preferredHeight = layoutElement.minHeight;
					layoutElement.flexibleHeight = 0f;
				}
			}
		}

		private class StripEnterAnimation : ObjectiveStripAnimation
		{
			private readonly float finalHeight;

			private readonly bool useLayoutAnimation;

			protected float alphaStartPercent;

			protected float alphaEndPercent;

			protected float heightStartPercent;

			protected float heightEndPercent;

			public StripEnterAnimation(ObjectiveTracker objectiveTracker)
				: base(objectiveTracker, StripAnimationType.Enter)
			{
				alphaStartPercent = AnimParams.GetParam("enterAlphaStartPercent", 0.25f);
				alphaEndPercent = AnimParams.GetParam("enterAlphaEndPercent", 0.5f);
				heightStartPercent = AnimParams.GetParam("enterHeightStartPercent", 0f);
				heightEndPercent = AnimParams.GetParam("enterHeightEndPercent", 0.25f);
				if ((bool)objectiveTracker.stripObject)
				{
					useLayoutAnimation = objectiveTracker.useLayoutAnimation;
					finalHeight = layoutElement.minHeight;
				}
			}

			public override void SetPercentComplete(float newPercentComplete)
			{
				base.SetPercentComplete(newPercentComplete);
				if ((bool)objectiveTracker.stripObject)
				{
					float alpha = Mathf.Clamp01(Util.Remap(percentComplete, alphaStartPercent, alphaEndPercent, 0f, 1f));
					canvasGroup.alpha = alpha;
					if (useLayoutAnimation)
					{
						float num = Mathf.Clamp01(Util.Remap(percentComplete, heightStartPercent, heightEndPercent, 0f, 1f));
						num *= num;
						layoutElement.minHeight = num * finalHeight;
						layoutElement.preferredHeight = layoutElement.minHeight;
						layoutElement.flexibleHeight = 0f;
					}
				}
			}
		}

		private class StripTutorialCrossfade : StripEnterAnimation
		{
			private readonly float _targetX;

			private readonly RectTransform rect;

			private readonly float maxHorizontal;

			private readonly float crossfadeStartPercent;

			private readonly float crossfadeEndPercent;

			public StripTutorialCrossfade(ObjectiveTracker objectiveTracker)
				: base(objectiveTracker)
			{
				if ((bool)objectiveTracker.stripObject && objectiveTracker.stripObject.transform is RectTransform rectTransform)
				{
					rect = rectTransform;
					_targetX = rectTransform.localPosition.x;
					maxHorizontal = AnimParams.GetParam("maxHorizontalLerp", -50f);
					crossfadeStartPercent = AnimParams.GetParam("crossfadeStartPercent", 0.25f);
					crossfadeEndPercent = AnimParams.GetParam("crossfadeEndPercent", 0.5f);
					alphaStartPercent = AnimParams.GetParam("crossfadeAlphaStartPercent", 0f);
					alphaEndPercent = AnimParams.GetParam("crossfadeAlphaEndPercent", 0.25f);
				}
			}

			public override void SetPercentComplete(float newPercentComplete)
			{
				base.SetPercentComplete(newPercentComplete);
				if ((bool)rect)
				{
					float num = Mathf.Clamp01(Util.Remap(percentComplete, crossfadeStartPercent, crossfadeEndPercent, 1f, 0f));
					float x = _targetX + maxHorizontal * num;
					UnityEngine.Vector3 localPosition = rect.localPosition;
					localPosition.x = x;
					rect.localPosition = localPosition;
				}
			}
		}

		public RectTransform objectiveTrackerContainer;

		public GameObject objectiveTrackerPrefab;

		public Sprite checkboxActiveSprite;

		public Sprite checkboxSuccessSprite;

		public Sprite checkboxFailSprite;

		private CharacterMaster currentMaster;

		private readonly List<ObjectiveTracker> objectiveTrackers = new List<ObjectiveTracker>();

		private Dictionary<ObjectiveSourceDescriptor, ObjectiveTracker> objectiveSourceToTrackerDictionary = new Dictionary<ObjectiveSourceDescriptor, ObjectiveTracker>(EqualityComparer<ObjectiveSourceDescriptor>.Default);

		private readonly List<ObjectiveSourceDescriptor> objectiveSourceDescriptors = new List<ObjectiveSourceDescriptor>();

		private readonly List<ObjectiveStripAnimation> objectiveStripAnimations = new List<ObjectiveStripAnimation>();

		public static event Action<CharacterMaster, List<ObjectiveSourceDescriptor>> collectObjectiveSources;

		public void SetCurrentMaster(CharacterMaster newMaster)
		{
			if (!(newMaster == currentMaster))
			{
				for (int num = objectiveTrackers.Count - 1; num >= 0; num--)
				{
					UnityEngine.Object.Destroy(objectiveTrackers[num].stripObject);
				}
				objectiveTrackers.Clear();
				objectiveSourceToTrackerDictionary.Clear();
				currentMaster = newMaster;
				RefreshObjectiveTrackers();
			}
		}

		public bool GetPrimaryObjectiveTracker(out ObjectiveTracker primaryObjectiveTracker)
		{
			int num = objectiveTrackers.FindIndex((ObjectiveTracker tracker) => tracker.isPrimary);
			if (num >= 0)
			{
				primaryObjectiveTracker = objectiveTrackers[num];
				return true;
			}
			primaryObjectiveTracker = null;
			return false;
		}

		private void AddObjectiveTracker(ObjectiveTracker objectiveTracker)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(objectiveTrackerPrefab, objectiveTrackerContainer);
			gameObject.SetActive(value: true);
			objectiveTracker.owner = this;
			objectiveTracker.SetStrip(gameObject);
			objectiveTrackers.Add(objectiveTracker);
			objectiveSourceToTrackerDictionary.Add(objectiveTracker.sourceDescriptor, objectiveTracker);
			if (objectiveTracker.isTutorialCrossfading)
			{
				TutorialObjectiveCrossfadeHelper component = gameObject.GetComponent<TutorialObjectiveCrossfadeHelper>();
				if ((object)component != null)
				{
					CanvasGroup component2 = gameObject.GetComponent<CanvasGroup>();
					if ((object)component2 != null)
					{
						component2.alpha = 0f;
					}
					component.FinishCrossfadeAction = delegate
					{
						AddAnimation(new StripTutorialCrossfade(objectiveTracker));
					};
				}
			}
			else
			{
				AddAnimation(new StripEnterAnimation(objectiveTracker));
			}
		}

		private void RemoveObjectiveTracker(ObjectiveTracker objectiveTracker)
		{
			objectiveTrackers.Remove(objectiveTracker);
			objectiveSourceToTrackerDictionary.Remove(objectiveTracker.sourceDescriptor);
			objectiveTracker.Retire();
			AddAnimation(new StripExitAnimation(objectiveTracker));
		}

		private void RefreshObjectiveTrackers()
		{
			foreach (ObjectiveTracker objectiveTracker2 in objectiveTrackers)
			{
				objectiveTracker2.isRelevant = false;
			}
			if ((bool)currentMaster)
			{
				GetObjectiveSources(currentMaster, objectiveSourceDescriptors);
				foreach (ObjectiveSourceDescriptor objectiveSourceDescriptor in objectiveSourceDescriptors)
				{
					if (objectiveSourceToTrackerDictionary.TryGetValue(objectiveSourceDescriptor, out var value))
					{
						value.isRelevant = true;
						continue;
					}
					ObjectiveTracker objectiveTracker = ObjectiveTracker.Instantiate(objectiveSourceDescriptor);
					objectiveTracker.isRelevant = true;
					bool isTutorialEnabled = TutorialManager.isTutorialEnabled;
					objectiveTracker.isTutorialCrossfading = objectiveTracker.isPrimary && isTutorialEnabled && (bool)Run.instance && Run.instance.stageClearCount == 0;
					AddObjectiveTracker(objectiveTracker);
				}
			}
			for (int num = objectiveTrackers.Count - 1; num >= 0; num--)
			{
				if (!objectiveTrackers[num].isRelevant)
				{
					RemoveObjectiveTracker(objectiveTrackers[num]);
				}
			}
			foreach (ObjectiveTracker objectiveTracker3 in objectiveTrackers)
			{
				objectiveTracker3.UpdateStrip();
			}
		}

		private void GetObjectiveSources(CharacterMaster master, [NotNull] List<ObjectiveSourceDescriptor> output)
		{
			output.Clear();
			WeeklyRun weeklyRun = Run.instance as WeeklyRun;
			if ((bool)weeklyRun && weeklyRun.crystalsRequiredToKill > weeklyRun.crystalsKilled)
			{
				output.Add(new ObjectiveSourceDescriptor
				{
					source = Run.instance,
					master = master,
					objectiveType = typeof(DestroyTimeCrystals)
				});
			}
			TeleporterInteraction instance = TeleporterInteraction.instance;
			if ((bool)instance)
			{
				Type type = null;
				if (instance.isCharged && !instance.isInFinalSequence)
				{
					type = typeof(FinishTeleporterObjectiveTracker);
				}
				else if (instance.isIdle)
				{
					type = typeof(FindTeleporterObjectiveTracker);
				}
				if (type != null)
				{
					output.Add(new ObjectiveSourceDescriptor
					{
						source = instance,
						master = master,
						objectiveType = type
					});
				}
			}
			if ((bool)GoldshoresMissionController.instance)
			{
				Type type2 = GoldshoresMissionController.instance.entityStateMachine.state.GetType();
				if ((type2 == typeof(ActivateBeacons) || type2 == typeof(GoldshoresBossfight)) && GoldshoresMissionController.instance.beaconsActive < GoldshoresMissionController.instance.beaconCount)
				{
					output.Add(new ObjectiveSourceDescriptor
					{
						source = GoldshoresMissionController.instance,
						master = master,
						objectiveType = typeof(ActivateGoldshoreBeaconTracker)
					});
				}
			}
			if ((bool)ArenaMissionController.instance && ArenaMissionController.instance.clearedRounds < ArenaMissionController.instance.totalRoundsMax)
			{
				output.Add(new ObjectiveSourceDescriptor
				{
					source = ArenaMissionController.instance,
					master = master,
					objectiveType = typeof(ClearArena)
				});
			}
			ObjectivePanelController.collectObjectiveSources?.Invoke(master, output);
		}

		private void Update()
		{
			RefreshObjectiveTrackers();
			RunObjectiveAnimations();
		}

		private void AddAnimation(ObjectiveStripAnimation newAnimation)
		{
			if (newAnimation.AnimationType == ObjectiveStripAnimation.StripAnimationType.Exit)
			{
				for (int num = objectiveStripAnimations.Count - 1; num >= 0; num--)
				{
					ObjectiveStripAnimation objectiveStripAnimation = objectiveStripAnimations[num];
					if (objectiveStripAnimation.AnimationType == ObjectiveStripAnimation.StripAnimationType.Enter && objectiveStripAnimation.objectiveTracker == newAnimation.objectiveTracker)
					{
						objectiveStripAnimations.RemoveAt(num);
					}
				}
			}
			objectiveStripAnimations.Add(newAnimation);
		}

		private void RunObjectiveAnimations()
		{
			float deltaTime = Time.deltaTime;
			float num = 7f;
			float num2 = deltaTime / num;
			for (int num3 = objectiveStripAnimations.Count - 1; num3 >= 0; num3--)
			{
				ObjectiveStripAnimation objectiveStripAnimation = objectiveStripAnimations[num3];
				float num4 = Mathf.Min(objectiveStripAnimation.percentComplete + num2, 1f);
				objectiveStripAnimation.SetPercentComplete(num4);
				if (num4 >= 1f)
				{
					if (objectiveStripAnimation.AnimationType == ObjectiveStripAnimation.StripAnimationType.Exit)
					{
						UnityEngine.Object.Destroy(objectiveStripAnimation.objectiveTracker.stripObject);
					}
					objectiveStripAnimations.RemoveAt(num3);
				}
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemProvider))]
	[RequireComponent(typeof(RectTransform))]
	public class PauseScreenController : MonoBehaviour
	{
		public static readonly List<PauseScreenController> instancesList = new List<PauseScreenController>();

		[SerializeField]
		private MPEventSystemProvider eventSystemProvider;

		[Tooltip("The main panel to which any submenus will be parented.")]
		public RectTransform rootPanel;

		[Tooltip("The minimal pause panel which will appear during a multiplayer pause.")]
		public RectTransform pausePanel;

		[Tooltip("The panel that contains the blur and controls.")]
		public RectTransform gameMenuPanel;

		[Tooltip("The panel which contains the main controls. This will be disabled while in a submenu.")]
		public RectTransform mainPanel;

		public GameObject settingsPanelPrefab;

		private GameObject submenuObject;

		public GameObject logbookPrefab;

		public GameObject resumeGameplayObject;

		public GameObject exitGameButton;

		public GameObject devCheatMenuPrefab;

		[SerializeField]
		private GameObject pauseButtonObject;

		private HGButton pauseButton;

		[SerializeField]
		private GameObject inventoryButtonObject;

		[SerializeField]
		private LanguageTextMeshController pauseLabel;

		[SerializeField]
		private HGButton resumeButton;

		[SerializeField]
		private float resumeButtonTimer = 1f;

		private bool _shouldResumeOnDisable = true;

		public LocalUser localUser;

		private static bool paused = false;

		public static bool pauseScreenUp = false;

		public static int storedHUDSize = -1;

		public bool isMinimallyPause => pausePanel.gameObject.activeSelf;

		private void Awake()
		{
			UpdateEventSystemProvider();
			pauseButton = pauseButtonObject.GetComponent<HGButton>();
			if (!NetworkServer.dontListen && (bool)PauseStopController.instance && PauseStopController.instance.allowMultiplayerPause)
			{
				pauseButtonObject.SetActive(value: true);
			}
			if ((bool)PauseStopController.instance && PauseStopController.instance.isPaused)
			{
				pauseButton.interactable = false;
			}
		}

		public void UpdateEventSystemProvider()
		{
			MPEventSystemProvider component = GetComponent<MPEventSystemProvider>();
			component.fallBackToMainEventSystem = false;
			component.fallBackToPlayer2EventSystem = false;
			component.fallBackToPlayer3EventSystem = false;
			component.fallBackToPlayer4EventSystem = false;
			switch (PauseManager.PausingPlayerID)
			{
			case 0:
				component.fallBackToMainEventSystem = true;
				localUser = LocalUserManager.FindLocalUserByPlayerName("PlayerMain");
				break;
			case 1:
				component.fallBackToPlayer2EventSystem = true;
				localUser = LocalUserManager.FindLocalUserByPlayerName("Player2");
				break;
			case 2:
				component.fallBackToPlayer3EventSystem = true;
				localUser = LocalUserManager.FindLocalUserByPlayerName("Player3");
				break;
			case 3:
				component.fallBackToPlayer4EventSystem = true;
				localUser = LocalUserManager.FindLocalUserByPlayerName("Player4");
				break;
			default:
				component.fallBackToMainEventSystem = true;
				localUser = LocalUserManager.FindLocalUserByPlayerName("PlayerMain");
				break;
			}
			localUser.pauseScreenController = this;
		}

		public void GameplayResumed()
		{
			resumeGameplayObject.SetActive(value: true);
		}

		private void Start()
		{
			if (!PauseStopController.instance || !PauseStopController.instance.canControlPause)
			{
				pauseButton.interactable = false;
			}
		}

		public static GameObject InstantiatePauseScreen(bool shouldPauseStop)
		{
			if (instancesList.Count != 0)
			{
				return null;
			}
			GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/PauseScreen"), RoR2Application.instance.transform);
			PauseScreenController component = obj.GetComponent<PauseScreenController>();
			instancesList.Add(component);
			HUD.SetScoreboardActive(component.localUser, isActive: false, EScoreboardDeactivateReturnContext.Game);
			if (NetworkServer.dontListen)
			{
				PauseStopController instance = PauseStopController.instance;
				if ((object)instance == null)
				{
					return obj;
				}
				instance.Pause(shouldPauseStop);
			}
			return obj;
		}

		public static GameObject InstantiateMinimalPauseScreen()
		{
			if (instancesList.Count != 0)
			{
				return null;
			}
			GameObject obj = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/PauseScreen"), RoR2Application.instance.transform);
			PauseScreenController component = obj.GetComponent<PauseScreenController>();
			component.pausePanel.gameObject.SetActive(value: true);
			component.gameMenuPanel.gameObject.SetActive(value: false);
			HUD.SetScoreboardActive(component.localUser, isActive: false, EScoreboardDeactivateReturnContext.Game);
			instancesList.Add(component);
			return obj;
		}

		public void DestroyPauseScreen(bool shouldResumeOnDisable)
		{
			_shouldResumeOnDisable = shouldResumeOnDisable;
			UnityEngine.Object.Destroy(base.gameObject);
		}

		public void OpenGameMenu()
		{
			if (isMinimallyPause)
			{
				pausePanel.gameObject.SetActive(value: false);
				gameMenuPanel.gameObject.SetActive(value: true);
			}
		}

		private void OnEnable()
		{
			if (instancesList.Count == 0)
			{
				pauseScreenUp = true;
				UserProfile userProfile = NetworkUser.readOnlyLocalPlayersList[0]?.localUser?.userProfile;
				if (userProfile != null)
				{
					storedHUDSize = userProfile.hudSizeMode;
				}
			}
			if (!Run.instance || ((bool)Run.instance && !Run.instance.isRunning))
			{
				inventoryButtonObject.SetActive(value: false);
			}
			PauseManager.onPauseStartGlobal = (Action)Delegate.Combine(PauseManager.onPauseStartGlobal, new Action(OnPauseStart));
			PauseManager.onPauseEndGlobal = (Action)Delegate.Combine(PauseManager.onPauseEndGlobal, new Action(OnPauseEnd));
			PauseManager.isPaused = true;
		}

		private void OnDisable()
		{
			PauseManager.onPauseStartGlobal = (Action)Delegate.Remove(PauseManager.onPauseStartGlobal, new Action(OnPauseStart));
			PauseManager.onPauseEndGlobal = (Action)Delegate.Remove(PauseManager.onPauseEndGlobal, new Action(OnPauseEnd));
			if (localUser != null && localUser.pauseScreenController == this)
			{
				localUser.pauseScreenController = null;
			}
			instancesList.Remove(this);
			if (instancesList.Count == 0)
			{
				UpdateHudIfNecessary();
				if (!_shouldResumeOnDisable)
				{
					_shouldResumeOnDisable = true;
					return;
				}
				PauseManager.isPaused = false;
				PauseStopController.instance?.Pause(shouldPause: false);
			}
		}

		private void UpdateHudIfNecessary()
		{
			UserProfile userProfile = null;
			if (NetworkUser.readOnlyLocalPlayersList != null && NetworkUser.readOnlyLocalPlayersList.Count > 0)
			{
				userProfile = NetworkUser.readOnlyLocalPlayersList[0]?.localUser?.userProfile;
			}
			if (userProfile != null && userProfile.hudSizeMode != storedHUDSize)
			{
				CameraRigController.OnChangeHUD?.Invoke();
				storedHUDSize = userProfile.hudSizeMode;
			}
		}

		private void OnPauseStart()
		{
			pauseButton.interactable = false;
			pauseLabel.token = "PAUSE_PAUSED";
			if (!NetworkServer.dontListen)
			{
				resumeButton.interactable = false;
				StartCoroutine(EnableResumeButton(resumeButtonTimer));
			}
			resumeGameplayObject.SetActive(value: false);
		}

		private void OnPauseEnd()
		{
			if ((bool)PauseStopController.instance && PauseStopController.instance.canControlPause)
			{
				pauseButton.interactable = true;
				pauseScreenUp = false;
				if (paused)
				{
					paused = false;
					if (PauseManager.onPauseEndGlobal != null)
					{
						PauseManager.onPauseEndGlobal();
					}
				}
				UpdateHudIfNecessary();
			}
			resumeButton.interactable = true;
			pauseLabel.token = "PAUSE_PAUSE";
		}

		public void OpenSettingsMenu()
		{
			UnityEngine.Object.Destroy(submenuObject);
			submenuObject = UnityEngine.Object.Instantiate(settingsPanelPrefab, rootPanel);
			if (eventSystemProvider != null)
			{
				submenuObject.GetComponent<HGHeaderNavigationController>().isPrimaryPlayer = eventSystemProvider.fallBackToMainEventSystem;
			}
			pausePanel.gameObject.SetActive(value: false);
			gameMenuPanel.gameObject.SetActive(value: true);
			mainPanel.gameObject.SetActive(value: false);
		}

		public void OpenDevCheatMenu()
		{
			UnityEngine.Object.Destroy(submenuObject);
			submenuObject = UnityEngine.Object.Instantiate(devCheatMenuPrefab, rootPanel);
			mainPanel.gameObject.SetActive(value: false);
		}

		public void OpenScoreboard()
		{
			if (HUD.SetScoreboardActive(localUser, isActive: true, EScoreboardDeactivateReturnContext.Pause, shouldForceScoreboardToggle: true))
			{
				PauseManager.ClosePauseScreen(shouldResume: false);
			}
		}

		public void OpenLogbook()
		{
			UnityEngine.Object.Destroy(submenuObject);
			submenuObject = UnityEngine.Object.Instantiate(logbookPrefab, rootPanel);
			if (submenuObject.transform is RectTransform rectTransform)
			{
				rectTransform.anchorMin = new UnityEngine.Vector2(0f, 0f);
				rectTransform.anchorMax = new UnityEngine.Vector2(1f, 1f);
				rectTransform.localScale = new UnityEngine.Vector3(1f, 1f, 1f);
			}
			pausePanel.gameObject.SetActive(value: false);
			gameMenuPanel.gameObject.SetActive(value: true);
			mainPanel.gameObject.SetActive(value: false);
		}

		public void ServerPauseGameButton()
		{
			PauseStopController.instance?.Pause(shouldPause: true);
		}

		public void Update()
		{
			if (!submenuObject && !isMinimallyPause)
			{
				mainPanel.gameObject.SetActive(value: true);
			}
			if (!NetworkManager.singleton.isNetworkActive)
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		private IEnumerator EnableResumeButton(float delay)
		{
			yield return new WaitForSecondsRealtime(delay);
			resumeButton.interactable = true;
		}
	}
	public class PickerPanelSizeAdjuster : MonoBehaviour
	{
		[SerializeField]
		private PickupPickerPanel pickerPanel;

		[SerializeField]
		private RectTransform rectToAdjust;

		[Tooltip("How many rows can we have before we begin to adjust")]
		[SerializeField]
		private int minRows = 5;

		[SerializeField]
		[Tooltip("After this many rows, we will not adjust the size any higher")]
		private int maxRows = 7;

		[Tooltip("How much should we adjust the window for each new row")]
		[SerializeField]
		private float adjustmentPerRow;

		[SerializeField]
		[Tooltip("This will be set automatically")]
		private float objectHeight;

		private bool capturedDefaults;

		private void Awake()
		{
			PickupPickerPanel pickupPickerPanel = pickerPanel;
			pickupPickerPanel.OnPanelSetupComplete = (Action)Delegate.Combine(pickupPickerPanel.OnPanelSetupComplete, new Action(AdjustPickerPanelSize));
		}

		private void CaptureDefaults()
		{
			if (capturedDefaults)
			{
				return;
			}
			RectTransform buttonContainer = pickerPanel.buttonContainer;
			if (buttonContainer != null && buttonContainer.childCount > 0)
			{
				RectTransform component = buttonContainer.GetChild(0).GetComponent<RectTransform>();
				if (component != null)
				{
					objectHeight = component.rect.height;
				}
			}
			capturedDefaults = true;
		}

		private void AdjustPickerPanelSize()
		{
			int num = Mathf.Max(1, pickerPanel.maxColumnCount);
			int value = pickerPanel.buttonContainer.childCount / num;
			value = Mathf.Clamp(value, minRows, maxRows) - minRows;
			rectToAdjust.ForceUpdateRectTransforms();
			CaptureDefaults();
			if (value > 0)
			{
				float num2 = adjustmentPerRow / 2f * (float)value;
				UnityEngine.Vector2 offsetMin = rectToAdjust.offsetMin;
				rectToAdjust.offsetMin = new UnityEngine.Vector2(offsetMin.x, offsetMin.y - num2);
				offsetMin = rectToAdjust.offsetMax;
				rectToAdjust.offsetMax = new UnityEngine.Vector2(offsetMin.x, offsetMin.y + num2);
			}
		}
	}
	[Serializable]
	public class PickupPickerEvent : UnityEvent<MPButton, PickupDef>
	{
	}
	[RequireComponent(typeof(RectTransform))]
	public class PickupPickerPanel : MonoBehaviour
	{
		public GridLayoutGroup gridlayoutGroup;

		public RectTransform buttonContainer;

		public GameObject buttonPrefab;

		public UnityEngine.UI.Image[] coloredImages;

		public UnityEngine.UI.Image[] darkColoredImages;

		public int maxColumnCount;

		private UIElementAllocator<MPButton> buttonAllocator;

		[SerializeField]
		private bool shouldRemoveChoice;

		[SerializeField]
		private bool needsNetworking;

		[SerializeField]
		private NetworkMultiOptionPickupPicker networkMultiOptionPickupPicker;

		[Header("Events")]
		public PickupPickerEvent pickupSelected;

		public PickupPickerEvent pickupBaseContentReady;

		private PickupPickerController.Option[] pickupOptions;

		public Action OnPanelSetupComplete;

		public PickupPickerController pickerController { get; set; }

		private void Awake()
		{
			buttonAllocator = new UIElementAllocator<MPButton>(buttonContainer, buttonPrefab);
			buttonAllocator.onCreateElement = OnCreateButton;
			gridlayoutGroup.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
			gridlayoutGroup.constraintCount = maxColumnCount;
			ScoreboardController.onScoreboardOpen += DestroyIt;
		}

		private void OnDestroy()
		{
			ScoreboardController.onScoreboardOpen -= DestroyIt;
		}

		private void DestroyIt()
		{
			UnityEngine.Object.Destroy(base.gameObject);
		}

		private void OnCreateButton(int index, MPButton button)
		{
			button.onClick.AddListener(delegate
			{
				pickerController.SubmitChoice(index);
				if (pickerController.multiOptionsAvailable || shouldRemoveChoice)
				{
					RemovePickupButtonAvailability(index);
				}
			});
			button.onSelect.AddListener(delegate
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupOptions[index].pickupIndex);
				pickupSelected?.Invoke(button, pickupDef);
			});
		}

		public void RemovePickupButtonAvailability(int pickupOption)
		{
			Sprite sprite = LegacyResourcesAPI.Load<Sprite>("Textures/MiscIcons/texUnlockIcon");
			pickupOptions[pickupOption].available = false;
			MPButton mPButton = buttonAllocator.elements[pickupOption];
			UnityEngine.UI.Image component = mPButton.GetComponent<ChildLocator>().FindChild("Icon").GetComponent<UnityEngine.UI.Image>();
			component.color = UnityEngine.Color.gray;
			component.sprite = sprite;
			mPButton.interactable = false;
		}

		public void SetPickupOptions(PickupPickerController.Option[] options)
		{
			pickupOptions = options;
			buttonAllocator.AllocateElements(options.Length);
			ReadOnlyCollection<MPButton> elements = buttonAllocator.elements;
			Sprite sprite = LegacyResourcesAPI.Load<Sprite>("Textures/MiscIcons/texUnlockIcon");
			if (options.Length != 0)
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(options[0].pickupIndex);
				UnityEngine.Color baseColor = pickupDef.baseColor;
				UnityEngine.Color darkColor = pickupDef.darkColor;
				UnityEngine.UI.Image[] array = coloredImages;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].color *= baseColor;
				}
				array = darkColoredImages;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].color *= darkColor;
				}
			}
			for (int j = 0; j < options.Length; j++)
			{
				MPButton mPButton = elements[j];
				int num = j - j % maxColumnCount;
				int num2 = j % maxColumnCount;
				int num3 = num2 - maxColumnCount;
				int num4 = num2 - 1;
				int num5 = num2 + 1;
				int num6 = num2 + maxColumnCount;
				UnityEngine.UI.Navigation navigation = mPButton.navigation;
				navigation.mode = UnityEngine.UI.Navigation.Mode.Explicit;
				if (num4 >= 0)
				{
					MPButton selectOnLeft = elements[num + num4];
					navigation.selectOnLeft = selectOnLeft;
				}
				if (num5 < maxColumnCount && num + num5 < options.Length)
				{
					MPButton selectOnRight = elements[num + num5];
					navigation.selectOnRight = selectOnRight;
				}
				if (num + num3 >= 0)
				{
					MPButton selectOnUp = elements[num + num3];
					navigation.selectOnUp = selectOnUp;
				}
				if (num + num6 < options.Length)
				{
					MPButton selectOnDown = elements[num + num6];
					navigation.selectOnDown = selectOnDown;
				}
				mPButton.navigation = navigation;
				ref PickupPickerController.Option reference = ref options[j];
				PickupDef pickupDef2 = PickupCatalog.GetPickupDef(reference.pickupIndex);
				UnityEngine.UI.Image component = mPButton.GetComponent<ChildLocator>().FindChild("Icon").GetComponent<UnityEngine.UI.Image>();
				if (reference.available)
				{
					component.color = UnityEngine.Color.white;
					component.sprite = pickupDef2?.iconSprite;
					mPButton.interactable = true;
				}
				else
				{
					component.color = UnityEngine.Color.gray;
					component.sprite = sprite;
					mPButton.interactable = false;
				}
				pickupBaseContentReady?.Invoke(mPButton, pickupDef2);
			}
			OnPanelSetupComplete?.Invoke();
		}
	}
	public class PieChartLegend : MonoBehaviour
	{
		[SerializeField]
		private PieChartMeshController _source;

		public RectTransform container;

		public GameObject stripPrefab;

		private UIElementAllocator<ChildLocator> stripAllocator;

		private PieChartMeshController _subscribedSource;

		public PieChartMeshController source
		{
			get
			{
				return _source;
			}
			set
			{
				if ((object)_source != value)
				{
					_source = value;
					subscribedSource = source;
				}
			}
		}

		private PieChartMeshController subscribedSource
		{
			get
			{
				return _subscribedSource;
			}
			set
			{
				if ((object)_subscribedSource != value)
				{
					if ((bool)_subscribedSource)
					{
						_subscribedSource.onRebuilt -= OnSourceUpdated;
					}
					_subscribedSource = value;
					if ((bool)_subscribedSource)
					{
						_subscribedSource.onRebuilt += OnSourceUpdated;
					}
				}
			}
		}

		private void Awake()
		{
			InitStripAllocator();
			subscribedSource = source;
		}

		private void OnDestroy()
		{
			subscribedSource = null;
		}

		private void OnValidate()
		{
			InitStripAllocator();
			subscribedSource = source;
			Invoke("Rebuild", 0f);
		}

		private void InitStripAllocator()
		{
			if (stripAllocator != null && (stripAllocator.containerTransform != container || stripAllocator.elementPrefab != stripPrefab))
			{
				stripAllocator.AllocateElements(0);
				stripAllocator = null;
			}
			if (stripAllocator == null)
			{
				stripAllocator = new UIElementAllocator<ChildLocator>(container, stripPrefab, markElementsUnsavable: true, acquireExistingChildren: true);
			}
		}

		private void Rebuild()
		{
			if (!source || !stripAllocator.containerTransform || !stripAllocator.elementPrefab)
			{
				stripAllocator.AllocateElements(0);
				return;
			}
			int num = 0;
			for (int i = 0; i < source.sliceCount; i++)
			{
				if (!(source.GetSliceInfo(i).weight / source.totalSliceWeight <= source.minimumRequiredWeightToDisplay) || num < 16)
				{
					num++;
				}
			}
			int maxSlices = _source.MaxSlices;
			stripAllocator.AllocateElements((num > maxSlices) ? maxSlices : num);
			ReadOnlyCollection<ChildLocator> elements = stripAllocator.elements;
			int j = 0;
			int num2 = num;
			int num3 = 0;
			for (; j < num2 && j < elements.Count; j++)
			{
				PieChartMeshController.SliceInfo sliceInfo = source.GetSliceInfo(j);
				if (source.GetSliceInfo(j).weight / source.totalSliceWeight <= source.minimumRequiredWeightToDisplay && num3 >= 16)
				{
					continue;
				}
				num3++;
				ChildLocator childLocator = elements[j];
				Graphic graphic = childLocator.FindChild("ColorBox")?.GetComponent<Graphic>();
				TMP_Text tMP_Text = childLocator.FindChild("Label")?.GetComponent<TMP_Text>();
				bool flag = num >= maxSlices && j == maxSlices - 1;
				if ((bool)graphic)
				{
					graphic.color = sliceInfo.color;
					graphic.gameObject.SetActive(!flag);
				}
				if ((bool)tMP_Text)
				{
					if (flag)
					{
						tMP_Text.SetText("...");
						break;
					}
					tMP_Text.SetText(sliceInfo.tooltipContent.GetTitleText());
				}
			}
		}

		private void OnSourceUpdated()
		{
			Rebuild();
		}
	}
	[ExecuteAlways]
	public class PieChartMeshController : MonoBehaviour
	{
		[Serializable]
		public struct SliceInfo : IEquatable<SliceInfo>
		{
			[UnityEngine.Min(0f)]
			public float weight;

			public UnityEngine.Color color;

			public TooltipContent tooltipContent;

			public bool Equals(SliceInfo other)
			{
				if (weight.Equals(other.weight) && color.Equals(other.color))
				{
					return tooltipContent.Equals(other.tooltipContent);
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is SliceInfo other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((weight.GetHashCode() * 397) ^ color.GetHashCode()) * 397) ^ tooltipContent.GetHashCode();
			}

			public static bool operator ==(SliceInfo left, SliceInfo right)
			{
				return left.Equals(right);
			}

			public static bool operator !=(SliceInfo left, SliceInfo right)
			{
				return !left.Equals(right);
			}
		}

		public RectTransform container;

		public GameObject slicePrefab;

		[Range(0f, 1f)]
		public float normalizedInnerRadius;

		[Tooltip("The minimum value required to display percentage and show an entry in the legend.")]
		public float minimumRequiredWeightToDisplay = 0.03f;

		public Texture texture;

		public Material material;

		[ColorUsage(true, true)]
		public UnityEngine.Color color;

		public float uTile = 1f;

		public bool individualSegmentUMapping;

		[SerializeField]
		private int maxSlices = 16;

		[SerializeField]
		private SliceInfo[] sliceInfos = Array.Empty<SliceInfo>();

		private int totalSliceCount;

		private UIElementAllocator<RadialSliceGraphic> sliceAllocator;

		private bool slicesDirty = true;

		public int MaxSlices => maxSlices;

		public float totalSliceWeight { get; private set; }

		public int sliceCount => sliceInfos.Length;

		public event Action onRebuilt;

		private void Awake()
		{
			InitSliceAllocator();
		}

		private void Update()
		{
			if (slicesDirty)
			{
				slicesDirty = false;
				RebuildSlices();
			}
		}

		private void OnValidate()
		{
			InitSliceAllocator();
			slicesDirty = true;
		}

		private void InitSliceAllocator()
		{
			sliceAllocator = new UIElementAllocator<RadialSliceGraphic>(container, slicePrefab, markElementsUnsavable: true, acquireExistingChildren: true);
		}

		public void SetSlices([NotNull] SliceInfo[] newSliceInfos)
		{
			if (!ArrayUtils.SequenceEquals(sliceInfos, newSliceInfos))
			{
				Array.Resize(ref sliceInfos, newSliceInfos.Length);
				Array.Copy(newSliceInfos, sliceInfos, sliceInfos.Length);
				slicesDirty = true;
			}
		}

		private void RebuildSlices()
		{
			totalSliceWeight = 0f;
			totalSliceCount = 0;
			for (int i = 0; i < sliceInfos.Length; i++)
			{
				float weight = sliceInfos[i].weight;
				if (!(weight <= 0f))
				{
					totalSliceCount++;
					totalSliceWeight += weight;
				}
			}
			sliceAllocator.AllocateElements(totalSliceCount);
			Radians left = new Radians(MathF.PI / 2f);
			float num = 0f;
			ReadOnlyCollection<RadialSliceGraphic> elements = sliceAllocator.elements;
			int num2 = 0;
			int num3 = 0;
			int count = elements.Count;
			while (num3 < count)
			{
				ref SliceInfo reference = ref sliceInfos[num2++];
				if (reference.weight <= 0f)
				{
					continue;
				}
				float num4 = reference.weight / totalSliceWeight;
				Radians right = new Radians(num4 * (MathF.PI * 2f));
				Radians radians = left - right;
				Radians left2 = new Radians(MathF.PI * 2f);
				float num5 = num - num4 * uTile;
				RadialSliceGraphic radialSliceGraphic = elements[num3++];
				RadialSliceGraphic.DisplayData newDisplayData = new RadialSliceGraphic.DisplayData
				{
					start = left,
					end = radians,
					startU = (individualSegmentUMapping ? 0f : num),
					endU = (individualSegmentUMapping ? uTile : num5),
					normalizedInnerRadius = normalizedInnerRadius
				};
				float right2 = 720f;
				newDisplayData.maxQuadWidth = left2 / right2;
				newDisplayData.material = material;
				newDisplayData.texture = texture;
				newDisplayData.color = reference.color * color;
				radialSliceGraphic.SetDisplayData(in newDisplayData);
				TooltipProvider component = radialSliceGraphic.GetComponent<TooltipProvider>();
				if ((bool)component)
				{
					component.SetContent(reference.tooltipContent);
				}
				ChildLocator component2 = radialSliceGraphic.GetComponent<ChildLocator>();
				if ((bool)component2)
				{
					Transform transform = component2.FindChild("SliceCenterStickerLabel");
					if ((bool)transform)
					{
						transform.GetComponent<TMP_Text>().SetText((num4 >= minimumRequiredWeightToDisplay) ? Language.GetStringFormatted("PERCENT_FORMAT", num4) : string.Empty);
					}
				}
				left = radians;
				num = num5;
			}
			this.onRebuilt?.Invoke();
		}

		public SliceInfo GetSliceInfo(int i)
		{
			return sliceInfos[i];
		}
	}
	public class PingIndicator : MonoBehaviour
	{
		public enum PingType
		{
			Default,
			Enemy,
			Interactable,
			Count
		}

		public PositionIndicator positionIndicator;

		public TextMeshPro pingText;

		public Highlight pingHighlight;

		public ObjectScaleCurve pingObjectScaleCurve;

		public GameObject positionIndicatorRoot;

		public UnityEngine.Color textBaseColor;

		public GameObject[] defaultPingGameObjects;

		public UnityEngine.Color defaultPingColor;

		public float defaultPingDuration;

		public GameObject[] enemyPingGameObjects;

		public UnityEngine.Color enemyPingColor;

		public float enemyPingDuration;

		public GameObject[] interactablePingGameObjects;

		public UnityEngine.Color interactablePingColor;

		public float interactablePingDuration;

		public static List<PingIndicator> instancesList = new List<PingIndicator>();

		private PingType pingType;

		private UnityEngine.Color pingColor;

		private float pingDuration;

		private PurchaseInteraction pingTargetPurchaseInteraction;

		private HalcyoniteShrineInteractable halcyonShrine;

		private Transform targetTransformToFollow;

		private float fixedTimer;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		public UnityEngine.Vector3 pingOrigin { get; set; }

		public UnityEngine.Vector3 pingNormal { get; set; }

		public GameObject pingOwner { get; set; }

		public GameObject pingTarget { get; set; }

		public static Sprite GetInteractableIcon(GameObject gameObject)
		{
			PingInfoProvider component = gameObject.GetComponent<PingInfoProvider>();
			if ((bool)component && (bool)component.pingIconOverride)
			{
				return component.pingIconOverride;
			}
			string path = "Textures/MiscIcons/texMysteryIcon";
			if ((bool)gameObject.GetComponent<BarrelInteraction>())
			{
				path = "Textures/MiscIcons/texBarrelIcon";
			}
			else if (gameObject.name.Contains("Shrine"))
			{
				path = "Textures/MiscIcons/texShrineIconOutlined";
			}
			else if ((bool)gameObject.GetComponent<GenericPickupController>() || (bool)gameObject.GetComponent<PickupPickerController>())
			{
				path = "Textures/MiscIcons/texLootIconOutlined";
			}
			else if ((bool)gameObject.GetComponent<SummonMasterBehavior>())
			{
				path = "Textures/MiscIcons/texDroneIconOutlined";
			}
			else if ((bool)gameObject.GetComponent<TeleporterInteraction>())
			{
				path = "Textures/MiscIcons/texTeleporterIconOutlined";
			}
			else
			{
				PortalStatueBehavior component2 = gameObject.GetComponent<PortalStatueBehavior>();
				if ((bool)component2 && component2.portalType == PortalStatueBehavior.PortalType.Shop)
				{
					path = "Textures/MiscIcons/texMysteryIcon";
				}
				else
				{
					PurchaseInteraction component3 = gameObject.GetComponent<PurchaseInteraction>();
					if ((bool)component3 && component3.costType == CostTypeIndex.LunarCoin)
					{
						path = "Textures/MiscIcons/texMysteryIcon";
					}
					else if ((bool)component3 || (bool)gameObject.GetComponent<TimedChestController>())
					{
						path = "Textures/MiscIcons/texInventoryIconOutlined";
					}
				}
			}
			return LegacyResourcesAPI.Load<Sprite>(path);
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		[Conditional("ENABLE_PING_NAME_REPORTER")]
		private static void GenerateDebugMessageInChat(GameObject pingTarget)
		{
			if (pingTarget == null || !pingTarget)
			{
				return;
			}
			CharacterBody component = pingTarget.GetComponent<CharacterBody>();
			if ((bool)component)
			{
				Chat.AddMessage("Debug: you pinged '" + component.gameObject.name.Replace("(Clone)", "") + "'");
				return;
			}
			if (pingTarget.TryGetComponent<IInspectable>(out var component2))
			{
				PickupDef pickupDef = PickupCatalog.GetPickupDef(component2.GetInspectInfoProvider().GetInfo().dynamicInspectPickupIndex);
				if (pickupDef != null)
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(pickupDef.itemIndex);
					if (pickupDef.displayPrefab != null)
					{
						Chat.AddMessage("Debug: you pinged '" + pickupDef.displayPrefab.gameObject.name + " ' (item name: " + ((itemDef != null) ? itemDef.name : "unknown") + "')");
						return;
					}
				}
			}
			Chat.AddMessage("Debug: you pinged '" + pingTarget.gameObject.name);
		}

		public void RebuildPing()
		{
			pingHighlight.enabled = false;
			base.transform.rotation = Util.QuaternionSafeLookRotation(pingNormal);
			base.transform.position = (pingTarget ? pingTarget.transform.position : pingOrigin);
			base.transform.localScale = UnityEngine.Vector3.one;
			positionIndicator.targetTransform = (pingTarget ? pingTarget.transform : null);
			positionIndicator.defaultPosition = base.transform.position;
			IDisplayNameProvider displayNameProvider = (pingTarget ? pingTarget.GetComponentInParent<IDisplayNameProvider>() : null);
			CharacterBody characterBody = null;
			ModelLocator modelLocator = null;
			pingType = PingType.Default;
			pingObjectScaleCurve.enabled = false;
			pingObjectScaleCurve.enabled = true;
			GameObject[] array = defaultPingGameObjects;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetActive(value: false);
			}
			array = enemyPingGameObjects;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetActive(value: false);
			}
			array = interactablePingGameObjects;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetActive(value: false);
			}
			if ((bool)pingTarget)
			{
				UnityEngine.Debug.LogFormat("Ping target {0}", pingTarget);
				modelLocator = pingTarget.GetComponent<ModelLocator>();
				if (displayNameProvider != null)
				{
					characterBody = pingTarget.GetComponent<CharacterBody>();
					if ((bool)characterBody)
					{
						pingType = PingType.Enemy;
						targetTransformToFollow = characterBody.coreTransform;
					}
					else
					{
						pingType = PingType.Interactable;
					}
				}
			}
			string ownerName = GetOwnerName();
			string text = (((MonoBehaviour)displayNameProvider) ? Util.GetBestBodyName(((MonoBehaviour)displayNameProvider).gameObject) : "");
			_ = pingTarget != null;
			pingText.enabled = true;
			pingText.text = ownerName;
			switch (pingType)
			{
			case PingType.Default:
			{
				pingColor = defaultPingColor;
				pingDuration = defaultPingDuration;
				pingHighlight.isOn = false;
				array = defaultPingGameObjects;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(value: true);
				}
				Chat.AddMessage(string.Format(Language.GetString("PLAYER_PING_DEFAULT"), ownerName));
				break;
			}
			case PingType.Enemy:
			{
				pingColor = enemyPingColor;
				pingDuration = enemyPingDuration;
				array = enemyPingGameObjects;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(value: true);
				}
				if (!modelLocator)
				{
					break;
				}
				Transform modelTransform = modelLocator.modelTransform;
				if ((bool)modelTransform)
				{
					CharacterModel component4 = modelTransform.GetComponent<CharacterModel>();
					if ((bool)component4)
					{
						bool flag = false;
						CharacterModel.RendererInfo[] baseRendererInfos = component4.baseRendererInfos;
						for (int i = 0; i < baseRendererInfos.Length; i++)
						{
							CharacterModel.RendererInfo rendererInfo = baseRendererInfos[i];
							if (!rendererInfo.ignoreOverlays && !flag)
							{
								pingHighlight.highlightColor = Highlight.HighlightColor.teleporter;
								pingHighlight.targetRenderer = rendererInfo.renderer;
								pingHighlight.strength = 1f;
								pingHighlight.isOn = true;
								pingHighlight.enabled = true;
								flag = true;
								break;
							}
						}
					}
				}
				Chat.AddMessage(string.Format(Language.GetString("PLAYER_PING_ENEMY"), ownerName, text));
				break;
			}
			case PingType.Interactable:
			{
				pingColor = interactablePingColor;
				pingDuration = interactablePingDuration;
				pingTargetPurchaseInteraction = pingTarget.GetComponent<PurchaseInteraction>();
				halcyonShrine = pingTarget.GetComponent<HalcyoniteShrineInteractable>();
				Sprite interactableIcon = GetInteractableIcon(pingTarget);
				SpriteRenderer component = interactablePingGameObjects[0].GetComponent<SpriteRenderer>();
				ShopTerminalBehavior component2 = pingTarget.GetComponent<ShopTerminalBehavior>();
				TeleporterInteraction component3 = pingTarget.GetComponent<TeleporterInteraction>();
				if ((bool)component2)
				{
					PickupIndex pickupIndex = component2.CurrentPickupIndex();
					text = string.Format(CultureInfo.InvariantCulture, "{0} ({1})", text, (component2.pickupIndexIsHidden || !component2.pickupDisplay) ? "?" : Language.GetString(PickupCatalog.GetPickupDef(pickupIndex)?.nameToken ?? PickupCatalog.invalidPickupToken));
				}
				else if ((bool)component3)
				{
					pingDuration = 30f;
					pingText.enabled = false;
					component3.PingTeleporter(ownerName, this);
				}
				else if (!pingTarget.gameObject.name.Contains("Shrine") && ((bool)pingTarget.GetComponent<GenericPickupController>() || (bool)pingTarget.GetComponent<PickupPickerController>()))
				{
					pingDuration = 60f;
				}
				array = interactablePingGameObjects;
				for (int i = 0; i < array.Length; i++)
				{
					array[i].SetActive(value: true);
				}
				Renderer renderer = null;
				renderer = ((!modelLocator) ? pingTarget.GetComponentInChildren<Renderer>() : modelLocator.modelTransform.GetComponentInChildren<Renderer>());
				if ((bool)renderer)
				{
					pingHighlight.highlightColor = Highlight.HighlightColor.interactive;
					pingHighlight.targetRenderer = renderer;
					pingHighlight.strength = 1f;
					pingHighlight.isOn = true;
					pingHighlight.enabled = true;
				}
				component.sprite = interactableIcon;
				component.enabled = !component3;
				if ((bool)pingTargetPurchaseInteraction && pingTargetPurchaseInteraction.costType != 0)
				{
					sharedStringBuilder.Clear();
					CostTypeDef costTypeDef = CostTypeCatalog.GetCostTypeDef(pingTargetPurchaseInteraction.costType);
					int num = pingTargetPurchaseInteraction.cost;
					if (pingTargetPurchaseInteraction.costType.Equals(CostTypeIndex.Money) && TeamManager.LongstandingSolitudesInParty() > 0)
					{
						num *= TeamManager.LongstandingSolitudesInParty() + 1;
					}
					costTypeDef.BuildCostStringStyled(num, sharedStringBuilder, forWorldDisplay: false);
					Chat.AddMessage(string.Format(Language.GetString("PLAYER_PING_INTERACTABLE_WITH_COST"), ownerName, text, sharedStringBuilder.ToString()));
				}
				else
				{
					Chat.AddMessage(string.Format(Language.GetString("PLAYER_PING_INTERACTABLE"), ownerName, text));
				}
				break;
			}
			}
			pingText.color = textBaseColor * pingColor;
			fixedTimer = pingDuration;
		}

		public string GetOwnerName()
		{
			if (!pingOwner)
			{
				return "";
			}
			return Util.GetBestMasterName(pingOwner.GetComponent<CharacterMaster>());
		}

		public void DestroyPing()
		{
			if ((bool)pingTarget)
			{
				pingTarget.GetComponent<TeleporterInteraction>()?.CancelTeleporterPing(this);
			}
			UnityEngine.Object.Destroy(base.gameObject);
		}

		private void Update()
		{
			if (pingType == PingType.Interactable && (bool)pingTargetPurchaseInteraction && !pingTargetPurchaseInteraction.available && !halcyonShrine)
			{
				DestroyPing();
			}
			fixedTimer -= Time.deltaTime;
			if (fixedTimer <= 0f)
			{
				DestroyPing();
			}
		}

		private void LateUpdate()
		{
			if (!pingTarget)
			{
				if ((object)pingTarget != null)
				{
					DestroyPing();
				}
			}
			else if ((bool)targetTransformToFollow)
			{
				base.transform.SetPositionAndRotation(targetTransformToFollow.position, targetTransformToFollow.rotation);
			}
		}
	}
	public class PlayerCountText : MonoBehaviour
	{
		public Text targetText;

		private void Update()
		{
			if ((bool)targetText)
			{
				targetText.text = $"{NetworkUser.readOnlyInstancesList.Count}/{NetworkManager.singleton.maxConnections}";
			}
		}
	}
	[RequireComponent(typeof(Canvas))]
	[RequireComponent(typeof(RectTransform))]
	public class PointViewer : MonoBehaviour, ILayoutGroup, ILayoutController
	{
		private struct ElementInfo
		{
			public Transform targetTransform;

			public UnityEngine.Vector3 targetLastKnownPosition;

			public float targetWorldDiameter;

			public float targetWorldVerticalOffset;

			public bool scaleWithDistance;

			public GameObject elementInstance;

			public RectTransform elementRectTransform;

			public CanvasGroup elementCanvasGroup;
		}

		public struct AddElementRequest
		{
			public GameObject elementPrefab;

			public Transform target;

			public float targetWorldVerticalOffset;

			public float targetWorldDiameter;

			public bool scaleWithDistance;

			public float targetWorldRadius
			{
				get
				{
					return targetWorldDiameter * 0.5f;
				}
				set
				{
					targetWorldDiameter = value * 2f;
				}
			}
		}

		private UICamera uiCamController;

		private Camera sceneCam;

		private StructAllocator<ElementInfo> elementInfoAllocator = new StructAllocator<ElementInfo>(16u);

		private Dictionary<UnityObjectWrapperKey<GameObject>, StructAllocator<ElementInfo>.Ptr> elementToElementInfo = new Dictionary<UnityObjectWrapperKey<GameObject>, StructAllocator<ElementInfo>.Ptr>();

		protected RectTransform rectTransform { get; private set; }

		protected Canvas canvas { get; private set; }

		private void Awake()
		{
			rectTransform = (RectTransform)base.transform;
			canvas = GetComponent<Canvas>();
		}

		private void Start()
		{
			FindCamera();
		}

		private void Update()
		{
			SetDirty();
		}

		public GameObject AddElement(AddElementRequest request)
		{
			if (!request.target || !request.elementPrefab)
			{
				return null;
			}
			GameObject gameObject = UnityEngine.Object.Instantiate(request.elementPrefab, rectTransform);
			StructAllocator<ElementInfo>.Ptr ptr = elementInfoAllocator.Alloc();
			ref ElementInfo @ref = ref elementInfoAllocator.GetRef(ptr);
			@ref.targetTransform = request.target;
			@ref.targetWorldVerticalOffset = request.targetWorldVerticalOffset;
			@ref.targetWorldDiameter = request.targetWorldDiameter;
			@ref.targetLastKnownPosition = request.target.position;
			@ref.scaleWithDistance = request.scaleWithDistance;
			@ref.elementInstance = gameObject;
			@ref.elementRectTransform = (RectTransform)gameObject.transform;
			@ref.elementCanvasGroup = gameObject.GetComponent<CanvasGroup>();
			elementToElementInfo.Add(gameObject, ptr);
			return gameObject;
		}

		public void RemoveElement(GameObject elementInstance)
		{
			if (elementToElementInfo.TryGetValue(elementInstance, out var value))
			{
				elementToElementInfo.Remove(elementInstance);
				elementInfoAllocator.Free(in value);
				UnityEngine.Object.Destroy(elementInstance);
			}
		}

		public void RemoveAll()
		{
			foreach (KeyValuePair<UnityObjectWrapperKey<GameObject>, StructAllocator<ElementInfo>.Ptr> item in elementToElementInfo)
			{
				GameObject obj = item.Key;
				StructAllocator<ElementInfo>.Ptr ptr = item.Value;
				elementInfoAllocator.Free(in ptr);
				UnityEngine.Object.Destroy(obj);
			}
			elementToElementInfo.Clear();
		}

		private void FindCamera()
		{
			uiCamController = canvas.rootCanvas.worldCamera.GetComponent<UICamera>();
			sceneCam = (uiCamController ? uiCamController.cameraRigController.sceneCam : null);
		}

		private void SetDirty()
		{
			if (base.isActiveAndEnabled && !CanvasUpdateRegistry.IsRebuildingLayout())
			{
				LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
			}
		}

		protected void UpdateAllElementPositions()
		{
			if (!uiCamController || !sceneCam)
			{
				return;
			}
			Camera camera = uiCamController.camera;
			UnityEngine.Vector2 size = rectTransform.rect.size;
			float num = sceneCam.fieldOfView * (MathF.PI / 180f);
			float num2 = 1f / num;
			foreach (KeyValuePair<UnityObjectWrapperKey<GameObject>, StructAllocator<ElementInfo>.Ptr> item in elementToElementInfo)
			{
				_ = (GameObject)item.Key;
				StructAllocator<ElementInfo>.Ptr value = item.Value;
				ref ElementInfo @ref = ref elementInfoAllocator.GetRef(value);
				if ((bool)@ref.targetTransform)
				{
					@ref.targetLastKnownPosition = @ref.targetTransform.position;
				}
				UnityEngine.Vector3 targetLastKnownPosition = @ref.targetLastKnownPosition;
				targetLastKnownPosition.y += @ref.targetWorldVerticalOffset;
				UnityEngine.Vector3 position = sceneCam.WorldToViewportPoint(targetLastKnownPosition);
				float z = position.z;
				UnityEngine.Vector3 vector = camera.ViewportToScreenPoint(position);
				RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, vector, camera, out var localPoint);
				UnityEngine.Vector3 localPosition = localPoint;
				localPosition.z = ((z >= 0f) ? 0f : (-1f));
				@ref.elementRectTransform.localPosition = localPosition;
				if (@ref.scaleWithDistance)
				{
					float num3 = @ref.targetWorldDiameter * num2 / z;
					@ref.elementRectTransform.sizeDelta = num3 * size;
				}
			}
		}

		public void SetLayoutHorizontal()
		{
			UpdateAllElementPositions();
		}

		public void SetLayoutVertical()
		{
		}
	}
	[RequireComponent(typeof(TextMeshProUGUI))]
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class ProfileNameLabel : MonoBehaviour
	{
		public string token;

		private MPEventSystemLocator eventSystemLocator;

		private TextMeshProUGUI label;

		private string currentUserName;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			label = GetComponent<TextMeshProUGUI>();
		}

		private void LateUpdate()
		{
			string text = PlatformSystems.userManager.GetUserName() ?? string.Empty;
			if (text != currentUserName)
			{
				currentUserName = text;
				label.text = Language.GetStringFormatted(token, currentUserName);
			}
		}
	}
	public class RadialSliceGraphic : MaskableGraphic
	{
		public struct DisplayData : IEquatable<DisplayData>
		{
			public Radians start;

			public Radians end;

			public float startU;

			public float endU;

			public Material material;

			public Texture texture;

			public UnityEngine.Color color;

			public float normalizedInnerRadius;

			public Radians maxQuadWidth;

			public override bool Equals(object obj)
			{
				if (obj == null)
				{
					return false;
				}
				if (obj is DisplayData other)
				{
					return Equals(other);
				}
				return false;
			}

			public static bool operator ==(DisplayData left, DisplayData right)
			{
				return left.Equals(right);
			}

			public static bool operator !=(DisplayData left, DisplayData right)
			{
				return !left.Equals(right);
			}

			public bool Equals(DisplayData other)
			{
				if (start.Equals(other.start) && end.Equals(other.end) && startU.Equals(other.startU) && endU.Equals(other.endU) && object.Equals(material, other.material) && object.Equals(texture, other.texture) && color.Equals(other.color) && normalizedInnerRadius.Equals(other.normalizedInnerRadius))
				{
					return maxQuadWidth.Equals(other.maxQuadWidth);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (((((((((((((((start.GetHashCode() * 397) ^ end.GetHashCode()) * 397) ^ startU.GetHashCode()) * 397) ^ endU.GetHashCode()) * 397) ^ ((material != null) ? material.GetHashCode() : 0)) * 397) ^ ((texture != null) ? texture.GetHashCode() : 0)) * 397) ^ color.GetHashCode()) * 397) ^ normalizedInnerRadius.GetHashCode()) * 397) ^ maxQuadWidth.GetHashCode();
			}
		}

		public RectTransform sliceCenterSticker;

		private static readonly DisplayData defaultDisplayData;

		private DisplayData displayData = defaultDisplayData;

		private float currentRadius;

		public override Texture mainTexture
		{
			get
			{
				if (!displayData.texture)
				{
					if (!displayData.material)
					{
						return null;
					}
					return displayData.material.mainTexture;
				}
				return displayData.texture;
			}
		}

		protected RadialSliceGraphic()
		{
			base.useLegacyMeshGeneration = false;
		}

		public void SetDisplayData(in DisplayData newDisplayData)
		{
			if (!(newDisplayData == displayData))
			{
				displayData = newDisplayData;
				UpdateDisplayData();
			}
		}

		private void UpdateDisplayData()
		{
			if (material != displayData.material)
			{
				material = displayData.material;
			}
			if (color != displayData.color)
			{
				color = displayData.color;
			}
			base.SetVerticesDirty();
		}

		private static UnityEngine.Vector2 GetDirection(Radians radians)
		{
			return new UnityEngine.Vector2(Mathf.Cos((float)radians), Mathf.Sin((float)radians));
		}

		protected override void OnPopulateMesh(VertexHelper vh)
		{
			vh.Clear();
			UnityEngine.Rect rect = base.rectTransform.rect;
			currentRadius = Mathf.Min(rect.width, rect.height) * 0.5f;
			float outerRadius = currentRadius;
			float innerRadius = outerRadius * displayData.normalizedInnerRadius;
			Radians right = displayData.start;
			Radians left = displayData.end;
			float a = displayData.startU;
			float b = displayData.endU;
			if (left < right)
			{
				Util.Swap(ref right, ref left);
				Util.Swap(ref a, ref b);
			}
			Radians radians = left - right;
			if (!((float)radians <= 0f) && !((float)displayData.maxQuadWidth <= 0f))
			{
				int right2 = Mathf.CeilToInt((float)radians / (float)displayData.maxQuadWidth);
				Radians right3 = radians / right2;
				float num = 1f / (float)right2;
				float num2 = b - a;
				float quadStartU2 = a;
				UnityEngine.Vector2 startDirection2 = GetDirection(right);
				UnityEngine.Color color2 = color * displayData.color;
				for (int i = 0; i < right2; i++)
				{
					int left2 = i + 1;
					Radians right4 = left2 * right3;
					UnityEngine.Vector2 endDirection2 = GetDirection(right + right4);
					float num3 = a + num2 * ((float)(i + 1) * num);
					AddQuad(in startDirection2, in endDirection2, in color2, quadStartU2, num3);
					startDirection2 = endDirection2;
					quadStartU2 = num3;
				}
			}
			void AddQuad(in UnityEngine.Vector2 startDirection, in UnityEngine.Vector2 endDirection, in UnityEngine.Color color, float quadStartU, float quadEndU)
			{
				int currentVertCount = vh.currentVertCount;
				vh.AddVert(startDirection * innerRadius, color, new UnityEngine.Vector2(quadStartU, 0f));
				vh.AddVert(startDirection * outerRadius, color, new UnityEngine.Vector2(quadStartU, 1f));
				vh.AddVert(endDirection * outerRadius, color, new UnityEngine.Vector2(quadEndU, 1f));
				vh.AddVert(endDirection * innerRadius, color, new UnityEngine.Vector2(quadEndU, 0f));
				vh.AddTriangle(currentVertCount, currentVertCount + 1, currentVertCount + 2);
				vh.AddTriangle(currentVertCount + 2, currentVertCount + 3, currentVertCount);
			}
		}

		public override bool Raycast(UnityEngine.Vector2 sp, Camera eventCamera)
		{
			if (!base.Raycast(sp, eventCamera))
			{
				return false;
			}
			if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(base.rectTransform, sp, eventCamera, out var localPoint))
			{
				return false;
			}
			UnityEngine.Color white = UnityEngine.Color.white;
			bool result = PointInArc(localPoint, displayData.start, displayData.end, displayData.normalizedInnerRadius * currentRadius, currentRadius);
			color = white;
			return result;
		}

		private static bool PointInArc(UnityEngine.Vector2 point, Radians arcStart, Radians arcEnd, float arcInnerRadius, float arcOuterRadius)
		{
			Radians left = arcStart + arcEnd;
			float right = 0.5f;
			UnityEngine.Vector2 direction = GetDirection(left * right);
			Radians radians = (arcEnd - arcStart).absolute;
			UnityEngine.Vector2 normalized = point.normalized;
			float num = UnityEngine.Vector2.Dot(direction, normalized);
			float num2 = Mathf.Cos((float)radians * 0.5f);
			if (num < num2)
			{
				return false;
			}
			float sqrMagnitude = point.sqrMagnitude;
			if (sqrMagnitude < arcInnerRadius * arcInnerRadius)
			{
				return false;
			}
			if (sqrMagnitude > arcOuterRadius * arcOuterRadius)
			{
				return false;
			}
			return true;
		}

		public override void GraphicUpdateComplete()
		{
			base.GraphicUpdateComplete();
			if ((bool)sliceCenterSticker)
			{
				float floatValue = Mathf.LerpAngle((float)displayData.start, (float)displayData.end, 0.5f);
				Radians radians = (Radians)floatValue;
				float num = Mathf.Lerp(displayData.normalizedInnerRadius, 1f, 0.5f) * currentRadius;
				UnityEngine.Vector3 localPosition = new UnityEngine.Vector3(radians.cos * num, radians.sin * num);
				sliceCenterSticker.localPosition = localPosition;
			}
		}

		static RadialSliceGraphic()
		{
			DisplayData displayData = new DisplayData
			{
				color = UnityEngine.Color.white,
				start = Radians.FromRevolutions(0f),
				end = Radians.FromRevolutions(-0.4f),
				startU = 0f,
				endU = 1f
			};
			float floatValue = MathF.PI / 10f;
			displayData.maxQuadWidth = (Radians)floatValue;
			displayData.normalizedInnerRadius = 0.2f;
			defaultDisplayData = displayData;
		}
	}
	public class RectTransformDimensionsChangeEvent : MonoBehaviour
	{
		public event Action onRectTransformDimensionsChange;

		private void OnRectTransformDimensionsChange()
		{
			if (this.onRectTransformDimensionsChange != null)
			{
				this.onRectTransformDimensionsChange();
			}
		}
	}
	public class ResolutionControl : BaseSettingsControl
	{
		private class ResolutionOption
		{
			public Vector2Int size;

			public readonly List<int> supportedRefreshRates = new List<int>();

			public string GenerateDisplayString()
			{
				return $"{size.x}x{size.y}";
			}
		}

		public MPDropdown resolutionDropdown;

		public MPDropdown refreshRateDropdown;

		private Resolution[] resolutions;

		private ResolutionOption[] resolutionOptions = Array.Empty<ResolutionOption>();

		private static Vector2Int ResolutionToVector2Int(Resolution resolution)
		{
			return new Vector2Int(resolution.width, resolution.height);
		}

		private ResolutionOption GetCurrentSelectedResolutionOption()
		{
			if (resolutionDropdown.value >= 0)
			{
				return resolutionOptions[resolutionDropdown.value];
			}
			return null;
		}

		private void GenerateResolutionOptions()
		{
			Resolution[] array = Screen.resolutions;
			resolutionOptions = (from v in array.Select(ResolutionToVector2Int).Distinct()
				select new ResolutionOption
				{
					size = v
				}).ToArray();
			ResolutionOption[] array2 = resolutionOptions;
			foreach (ResolutionOption resolutionOption in array2)
			{
				Resolution[] array3 = array;
				for (int j = 0; j < array3.Length; j++)
				{
					Resolution resolution = array3[j];
					if (ResolutionToVector2Int(resolution) == resolutionOption.size)
					{
						resolutionOption.supportedRefreshRates.Add(resolution.refreshRate);
					}
				}
			}
			List<TMP_Dropdown.OptionData> list = new List<TMP_Dropdown.OptionData>();
			array2 = resolutionOptions;
			foreach (ResolutionOption resolutionOption2 in array2)
			{
				list.Add(new TMP_Dropdown.OptionData
				{
					text = resolutionOption2.GenerateDisplayString()
				});
			}
			resolutionDropdown.ClearOptions();
			resolutionDropdown.AddOptions(list);
			int value = -1;
			Vector2Int vector2Int = ResolutionToVector2Int(Screen.currentResolution);
			for (int k = 0; k < resolutionOptions.Length; k++)
			{
				if (vector2Int == resolutionOptions[k].size)
				{
					value = k;
					break;
				}
			}
			resolutionDropdown.value = value;
		}

		private void GenerateRefreshRateOptions()
		{
			refreshRateDropdown.ClearOptions();
			ResolutionOption currentSelectedResolutionOption = GetCurrentSelectedResolutionOption();
			if (currentSelectedResolutionOption == null)
			{
				return;
			}
			List<TMP_Dropdown.OptionData> list = new List<TMP_Dropdown.OptionData>();
			foreach (int supportedRefreshRate in currentSelectedResolutionOption.supportedRefreshRates)
			{
				list.Add(new TMP_Dropdown.OptionData(supportedRefreshRate + "Hz"));
			}
			refreshRateDropdown.AddOptions(list);
			int num = currentSelectedResolutionOption.supportedRefreshRates.IndexOf(Screen.currentResolution.refreshRate);
			if (num == -1)
			{
				num = currentSelectedResolutionOption.supportedRefreshRates.Count - 1;
			}
			refreshRateDropdown.value = num;
		}

		protected new void Awake()
		{
			base.Awake();
			resolutionDropdown.onValueChanged.AddListener(OnResolutionDropdownValueChanged);
			refreshRateDropdown.onValueChanged.AddListener(OnRefreshRateDropdownValueChanged);
		}

		protected new void OnEnable()
		{
			base.OnEnable();
			GenerateResolutionOptions();
			GenerateRefreshRateOptions();
		}

		private void OnResolutionDropdownValueChanged(int newValue)
		{
			if (newValue >= 0)
			{
				GenerateRefreshRateOptions();
			}
		}

		private void OnRefreshRateDropdownValueChanged(int newValue)
		{
			_ = 0;
		}

		public void SubmitCurrentValue()
		{
			if (resolutionDropdown.value != -1 && refreshRateDropdown.value != -1)
			{
				ResolutionOption resolutionOption = resolutionOptions[resolutionDropdown.value];
				SubmitSetting(string.Format(CultureInfo.InvariantCulture, "{0}x{1}x{2}", resolutionOption.size.x, resolutionOption.size.y, resolutionOption.supportedRefreshRates[refreshRateDropdown.value]));
			}
		}
	}
	public class RuleBookViewer : MonoBehaviour
	{
		[Tooltip("The prefab to use for categories.")]
		public GameObject categoryPrefab;

		public RectTransform categoryContainer;

		private UIElementAllocator<RuleCategoryController> categoryElementAllocator;

		private RuleChoiceMask cachedRuleChoiceMask;

		private RuleBook cachedRuleBook;

		private void Awake()
		{
			cachedRuleBook = new RuleBook();
			cachedRuleChoiceMask = new RuleChoiceMask();
		}

		private void Start()
		{
			categoryElementAllocator = new UIElementAllocator<RuleCategoryController>(categoryContainer, categoryPrefab);
			AllocateCategories(RuleCatalog.categoryCount);
		}

		private void Update()
		{
			if ((bool)PreGameController.instance)
			{
				SetData(PreGameController.instance.resolvedRuleChoiceMask, PreGameController.instance.readOnlyRuleBook);
			}
		}

		private void AllocateCategories(int desiredCount)
		{
			categoryElementAllocator.AllocateElements(desiredCount);
		}

		private void SetData(RuleChoiceMask choiceAvailability, RuleBook ruleBook)
		{
			if (!choiceAvailability.Equals(cachedRuleChoiceMask) || !ruleBook.Equals(cachedRuleBook))
			{
				cachedRuleChoiceMask.Copy(choiceAvailability);
				cachedRuleBook.Copy(ruleBook);
				for (int i = 0; i < RuleCatalog.categoryCount; i++)
				{
					RuleCategoryController ruleCategoryController = categoryElementAllocator.elements[i];
					ruleCategoryController.SetData(RuleCatalog.GetCategoryDef(i), cachedRuleChoiceMask, cachedRuleBook);
					ruleCategoryController.gameObject.SetActive(!ruleCategoryController.shouldHide);
				}
			}
		}
	}
	public class RuleBookViewerStrip : MonoBehaviour
	{
		public GameObject choicePrefab;

		public GameObject tutorialPrefab;

		public RectTransform choiceContainer;

		public RectTransform.Axis movementAxis = RectTransform.Axis.Vertical;

		public float movementDuration = 0.1f;

		public readonly List<RuleChoiceController> choiceControllers = new List<RuleChoiceController>();

		public int currentDisplayChoiceIndex;

		private float velocity;

		private float currentPosition;

		private RuleChoiceController CreateChoice()
		{
			GameObject obj = UnityEngine.Object.Instantiate(choicePrefab, choiceContainer);
			obj.SetActive(value: true);
			RuleChoiceController component = obj.GetComponent<RuleChoiceController>();
			component.strip = this;
			return component;
		}

		private void DestroyChoice(RuleChoiceController choiceController)
		{
			UnityEngine.Object.Destroy(choiceController.gameObject);
		}

		public void SetData(List<RuleChoiceDef> newChoices, int choiceIndex)
		{
			AllocateChoices(newChoices.Count);
			int num = currentDisplayChoiceIndex;
			int count = newChoices.Count;
			bool canVote = count > 1;
			for (int i = 0; i < count; i++)
			{
				choiceControllers[i].canVote = canVote;
				choiceControllers[i].SetChoice(newChoices[i]);
				if (newChoices[i].localIndex == choiceIndex)
				{
					bool flag = false;
					if (choiceIndex < newChoices.Count && (bool)PreGameController.instance && PreGameController.GameModeConVar.instance != null)
					{
						num = i;
						flag = newChoices[choiceIndex].difficultyIndex == DifficultyIndex.Easy && RoR2Application.isInSinglePlayer && PreGameController.GameModeConVar.instance.GetString() == "ClassicRun";
					}
					tutorialPrefab.SetActive(flag);
					if (!flag)
					{
						Console.instance.SubmitCmd(null, "enable_tutorial 0");
					}
				}
			}
			currentDisplayChoiceIndex = num;
		}

		private void AllocateChoices(int desiredCount)
		{
			while (choiceControllers.Count > desiredCount)
			{
				int index = choiceControllers.Count - 1;
				DestroyChoice(choiceControllers[index]);
				choiceControllers.RemoveAt(index);
			}
			while (choiceControllers.Count < desiredCount)
			{
				choiceControllers.Add(CreateChoice());
			}
		}

		public void Update()
		{
			if (choiceControllers.Count != 0)
			{
				if (currentDisplayChoiceIndex >= choiceControllers.Count)
				{
					currentDisplayChoiceIndex = choiceControllers.Count - 1;
				}
				UnityEngine.Vector3 localPosition = choiceControllers[currentDisplayChoiceIndex].transform.localPosition;
				float target = 0f;
				switch (movementAxis)
				{
				case RectTransform.Axis.Horizontal:
					target = 0f - localPosition.x;
					break;
				case RectTransform.Axis.Vertical:
					target = 0f - localPosition.y;
					break;
				}
				currentPosition = Mathf.SmoothDamp(currentPosition, target, ref velocity, movementDuration);
				UpdatePosition();
			}
		}

		private void OnEnable()
		{
			UpdatePosition();
		}

		private void UpdatePosition()
		{
			UnityEngine.Vector3 localPosition = choiceContainer.localPosition;
			switch (movementAxis)
			{
			case RectTransform.Axis.Horizontal:
				localPosition.x = currentPosition;
				break;
			case RectTransform.Axis.Vertical:
				localPosition.y = currentPosition;
				break;
			}
			if ((bool)choiceContainer && localPosition.x != float.NaN && localPosition.y != float.NaN && localPosition.z != float.NaN)
			{
				choiceContainer.localPosition = localPosition;
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class RuleCategoryController : MonoBehaviour
	{
		[Header("Header")]
		public UnityEngine.UI.Image[] headerColorImages;

		public LanguageTextMeshController categoryHeaderLanguageController;

		public GameObject tipPrefab;

		public RectTransform tipContainer;

		public GameObject editCategoryButtonObject;

		[Header("Rules, Strip")]
		public GameObject stripPrefab;

		public RectTransform stripContainer;

		public RectTransform framePanel;

		[Header("Rules, Grid +  Popout Panel")]
		public RectTransform voteResultGridContainer;

		public RectTransform voteResultIconPrefab;

		public RectTransform popoutPanelIconPrefab;

		public GameObject popoutPanelPrefab;

		public RectTransform popoutPanelContainer;

		public bool displayOnlyNonDefaultResults;

		private MPEventSystemLocator eventSystemLocator;

		private readonly List<RuleDef> rulesToDisplay = new List<RuleDef>(RuleCatalog.ruleCount);

		private RuleCatalog.RuleCategoryType ruleCategoryType;

		private GameObject tipObject;

		private HGPopoutPanel popoutPanelInstance;

		private UIElementAllocator<RectTransform> voteStripAllocator;

		private UIElementAllocator<RuleChoiceController> voteResultIconAllocator;

		private UIElementAllocator<RuleChoiceController> popoutButtonIconAllocator;

		private GameObject popoutRandomButtonContainer;

		private MPButton popoutRandomButton;

		private RuleChoiceMask cachedAvailability;

		private RuleCategoryDef currentCategory;

		public RectTransform popoutPanelContentContainer => popoutPanelInstance.popoutPanelContentContainer;

		public LanguageTextMeshController popoutPanelTitleText => popoutPanelInstance.popoutPanelTitleText;

		public LanguageTextMeshController popoutPanelSubtitleText => popoutPanelInstance.popoutPanelSubtitleText;

		public LanguageTextMeshController popoutPanelDescriptionText => popoutPanelInstance.popoutPanelDescriptionText;

		public bool shouldHide
		{
			get
			{
				if ((!isEmpty || (bool)tipObject) && currentCategory != null)
				{
					return currentCategory.isHidden;
				}
				return true;
			}
		}

		public bool isEmpty
		{
			get
			{
				if (voteStripAllocator.elements.Count == 0)
				{
					return voteResultIconAllocator.elements.Count == 0;
				}
				return false;
			}
		}

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			cachedAvailability = new RuleChoiceMask();
			if ((bool)popoutPanelPrefab && (bool)popoutPanelContainer && (bool)editCategoryButtonObject)
			{
				popoutPanelInstance = UnityEngine.Object.Instantiate(popoutPanelPrefab, popoutPanelContainer).GetComponent<HGPopoutPanel>();
				ChildLocator component = popoutPanelInstance.GetComponent<ChildLocator>();
				popoutRandomButtonContainer = component?.FindChild("RandomButtonContainer")?.gameObject;
				popoutRandomButton = component?.FindChild("RandomButton")?.GetComponent<HGButton>();
				if ((bool)popoutRandomButton)
				{
					popoutRandomButton.onClick.AddListener(SetRandomVotes);
				}
				editCategoryButtonObject.GetComponent<HGButton>().onClick.AddListener(TogglePopoutPanel);
			}
			voteStripAllocator = new UIElementAllocator<RectTransform>(stripContainer, stripPrefab.gameObject);
			voteResultIconAllocator = new UIElementAllocator<RuleChoiceController>(voteResultGridContainer, voteResultIconPrefab.gameObject);
			popoutButtonIconAllocator = new UIElementAllocator<RuleChoiceController>(popoutPanelContentContainer, popoutPanelIconPrefab.gameObject);
		}

		private void TogglePopoutPanel()
		{
			if ((bool)popoutPanelInstance)
			{
				popoutPanelInstance.gameObject.SetActive(!popoutPanelInstance.gameObject.activeSelf);
			}
		}

		public void SetRandomVotes()
		{
			PreGameRuleVoteController preGameRuleVoteController = PreGameRuleVoteController.FindForUser(eventSystemLocator.eventSystem?.localUser?.currentNetworkUser);
			if (!preGameRuleVoteController)
			{
				return;
			}
			List<RuleChoiceDef> list = new List<RuleChoiceDef>();
			foreach (RuleDef child in currentCategory.children)
			{
				list.Clear();
				foreach (RuleChoiceDef choice in child.choices)
				{
					if (cachedAvailability[choice.globalIndex])
					{
						list.Add(choice);
					}
				}
				int choiceValue = -1;
				if (list.Count > 0 && UnityEngine.Random.value > 0.5f)
				{
					choiceValue = list[UnityEngine.Random.Range(0, list.Count)].localIndex;
				}
				preGameRuleVoteController.SetVote(child.globalIndex, choiceValue);
			}
		}

		private void SetTip(string tipToken)
		{
			if (tipToken == null)
			{
				UnityEngine.Object.Destroy(tipObject);
				tipObject = null;
				return;
			}
			stripContainer.gameObject.SetActive(value: false);
			voteResultGridContainer.gameObject.SetActive(value: false);
			if (!tipObject)
			{
				tipObject = UnityEngine.Object.Instantiate(tipPrefab, tipContainer);
				tipObject.SetActive(value: true);
			}
			tipObject.GetComponentInChildren<LanguageTextMeshController>().token = tipToken;
		}

		private void AllocateStrips(int desiredCount)
		{
			voteStripAllocator.AllocateElements(desiredCount);
			framePanel.SetAsLastSibling();
		}

		private void AllocateResultIcons(int desiredCount)
		{
			voteResultIconAllocator.AllocateElements(desiredCount);
		}

		public void SetData(RuleCategoryDef categoryDef, RuleChoiceMask availability, RuleBook ruleBook)
		{
			currentCategory = categoryDef;
			ruleCategoryType = categoryDef.ruleCategoryType;
			cachedAvailability.Copy(availability);
			rulesToDisplay.Clear();
			bool active = false;
			List<RuleDef> children = categoryDef.children;
			for (int i = 0; i < children.Count; i++)
			{
				RuleDef ruleDef = children[i];
				bool flag = false;
				int num = ruleDef.AvailableChoiceCount(availability);
				if (!availability[ruleDef.choices[ruleDef.defaultChoiceIndex].globalIndex] && num != 0)
				{
					flag = true;
				}
				if (num > 1)
				{
					flag = true;
					active = true;
				}
				if (ruleDef.globalName == "Difficulty")
				{
					flag = true;
				}
				if (flag || ruleDef.forceLobbyDisplay)
				{
					rulesToDisplay.Add(children[i]);
				}
			}
			UnityEngine.UI.Image[] array = headerColorImages;
			for (int j = 0; j < array.Length; j++)
			{
				array[j].color = categoryDef.color;
			}
			categoryHeaderLanguageController.token = categoryDef.displayToken;
			switch (ruleCategoryType)
			{
			case RuleCatalog.RuleCategoryType.StripVote:
			{
				stripContainer.gameObject.SetActive(value: true);
				voteResultGridContainer.gameObject.SetActive(value: false);
				editCategoryButtonObject.SetActive(value: false);
				AllocateStrips(rulesToDisplay.Count);
				List<RuleChoiceDef> list = new List<RuleChoiceDef>();
				for (int m = 0; m < rulesToDisplay.Count; m++)
				{
					RuleDef ruleDef4 = rulesToDisplay[m];
					list.Clear();
					foreach (RuleChoiceDef choice2 in ruleDef4.choices)
					{
						if (availability[choice2.globalIndex])
						{
							list.Add(choice2);
						}
					}
					voteStripAllocator.elements[m].GetComponent<RuleBookViewerStrip>().SetData(list, ruleBook.GetRuleChoiceIndex(ruleDef4));
				}
				break;
			}
			case RuleCatalog.RuleCategoryType.VoteResultGrid:
			{
				stripContainer.gameObject.SetActive(value: false);
				voteResultGridContainer.gameObject.SetActive(value: true);
				UnityEngine.Color color = categoryDef.color;
				color.a = 0.2f;
				editCategoryButtonObject.SetActive(value: true);
				editCategoryButtonObject.GetComponent<HGButton>().hoverToken = Language.GetStringFormatted("RULE_EDIT_FORMAT", Language.GetString(categoryDef.displayToken), Language.GetString(categoryDef.editToken), ColorUtility.ToHtmlStringRGBA(color));
				int count = rulesToDisplay.Count;
				AllocateResultIcons(count);
				for (int k = 0; k < rulesToDisplay.Count; k++)
				{
					RuleDef ruleDef2 = rulesToDisplay[k];
					RuleChoiceController ruleChoiceController = voteResultIconAllocator.elements[k];
					int ruleChoiceIndex = ruleBook.GetRuleChoiceIndex(ruleDef2);
					RuleChoiceDef choice = ruleDef2.choices[ruleChoiceIndex];
					ruleChoiceController.SetChoice(choice);
				}
				popoutPanelTitleText.token = categoryDef.displayToken;
				popoutPanelSubtitleText.token = categoryDef.subtitleToken;
				popoutButtonIconAllocator.AllocateElements(rulesToDisplay.Count);
				GridLayoutGroup component = popoutPanelContentContainer.GetComponent<GridLayoutGroup>();
				for (int l = 0; l < rulesToDisplay.Count; l++)
				{
					RuleDef ruleDef3 = rulesToDisplay[l];
					bool num2 = ruleDef3.choices.Count == 2;
					bool flag2 = ruleDef3.AvailableChoiceCount(availability) > 1;
					int ruleChoiceIndex2 = ruleBook.GetRuleChoiceIndex(ruleDef3);
					RuleChoiceDef ruleChoiceDef = ruleDef3.choices[ruleChoiceIndex2];
					RuleChoiceController ruleChoiceController2 = popoutButtonIconAllocator.elements[l];
					ruleChoiceController2.displayVoteCounter = false;
					ruleChoiceController2.SetChoice(ruleChoiceDef);
					ruleChoiceController2.cycleThroughOptions = true;
					if (ruleChoiceDef.extraData != null && typeof(ArtifactDef).IsAssignableFrom(ruleChoiceDef.extraData.GetType()) && (bool)((ArtifactDef)ruleChoiceDef.extraData).extraUIDisplayPrefab && popoutPanelInstance.popoutAdditionalInfoContainer != null)
					{
						ruleChoiceController2.targetExtraDisplayInfoContainer = popoutPanelInstance.popoutAdditionalInfoContainer;
					}
					ruleChoiceController2.requiredTopLayer = popoutPanelInstance.GetComponent<UILayerKey>();
					ruleChoiceController2.tooltipProvider.enabled = false;
					ruleChoiceController2.hgButton.updateTextOnHover = true;
					ruleChoiceController2.hgButton.hoverLanguageTextMeshController = popoutPanelDescriptionText;
					if (component != null && rulesToDisplay.Count > 1)
					{
						UnityEngine.UI.Navigation navigation = ruleChoiceController2.hgButton.navigation;
						navigation.mode = UnityEngine.UI.Navigation.Mode.Explicit;
						int index = (l + rulesToDisplay.Count - 1) % rulesToDisplay.Count;
						navigation.selectOnLeft = popoutButtonIconAllocator.elements[index].hgButton;
						int index2 = (l + rulesToDisplay.Count + 1) % rulesToDisplay.Count;
						navigation.selectOnRight = popoutButtonIconAllocator.elements[index2].hgButton;
						if (l - component.constraintCount >= 0)
						{
							navigation.selectOnUp = popoutButtonIconAllocator.elements[l - component.constraintCount].hgButton;
						}
						if (l + component.constraintCount < rulesToDisplay.Count)
						{
							navigation.selectOnDown = popoutButtonIconAllocator.elements[l + component.constraintCount].hgButton;
						}
						ruleChoiceController2.hgButton.navigation = navigation;
					}
					if (num2 && flag2)
					{
						ruleChoiceController2.canVote = true;
					}
					else
					{
						ruleChoiceController2.canVote = false;
					}
				}
				break;
			}
			}
			SetTip(isEmpty ? categoryDef.emptyTipToken : null);
			if ((bool)popoutRandomButtonContainer)
			{
				popoutRandomButtonContainer.SetActive(active);
			}
		}
	}
	public class RuleChoiceController : MonoBehaviour
	{
		private static readonly List<RuleChoiceController> instancesList;

		[HideInInspector]
		public RuleBookViewerStrip strip;

		public HGButton hgButton;

		public UnityEngine.UI.Image image;

		public TooltipProvider tooltipProvider;

		public TextMeshProUGUI voteCounter;

		public GameObject chosenDisplayObject;

		public GameObject disabledDisplayObject;

		public GameObject cantVoteDisplayObject;

		public UILayerKey requiredTopLayer;

		public bool displayVoteCounter = true;

		public bool canVote;

		public GameObject extraDisplayInfo;

		[HideInInspector]
		public GameObject targetExtraDisplayInfoContainer;

		public bool cycleThroughOptions;

		private RuleChoiceDef choiceDef;

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		static RuleChoiceController()
		{
			instancesList = new List<RuleChoiceController>();
			PreGameRuleVoteController.onVotesUpdated += delegate
			{
				foreach (RuleChoiceController instances in instancesList)
				{
					instances.UpdateFromVotes();
				}
			};
		}

		private void Start()
		{
			UpdateFromVotes();
			UpdateChoiceDisplay(choiceDef);
			if ((bool)requiredTopLayer && (bool)hgButton)
			{
				hgButton.requiredTopLayer = requiredTopLayer;
			}
		}

		public void UpdateFromVotes()
		{
			int num = PreGameRuleVoteController.votesForEachChoice[choiceDef.globalIndex];
			bool isInSinglePlayer = RoR2Application.isInSinglePlayer;
			if ((bool)voteCounter)
			{
				if (displayVoteCounter && num > 0 && !isInSinglePlayer)
				{
					voteCounter.enabled = true;
					voteCounter.text = num.ToString();
				}
				else
				{
					voteCounter.enabled = false;
				}
			}
			bool flag = false;
			NetworkUser networkUser = FindNetworkUser();
			if ((bool)networkUser)
			{
				PreGameRuleVoteController preGameRuleVoteController = PreGameRuleVoteController.FindForUser(networkUser);
				if ((bool)preGameRuleVoteController)
				{
					flag = preGameRuleVoteController.IsChoiceVoted(choiceDef);
				}
			}
			bool flag2 = choiceDef.globalName.Contains(".Off");
			if ((bool)chosenDisplayObject)
			{
				chosenDisplayObject.SetActive(flag && !flag2);
			}
			if ((bool)disabledDisplayObject)
			{
				disabledDisplayObject.SetActive(flag && flag2);
			}
			if ((bool)cantVoteDisplayObject)
			{
				cantVoteDisplayObject.SetActive(!canVote);
			}
		}

		public void SetChoice([NotNull] RuleChoiceDef newChoiceDef)
		{
			if (newChoiceDef != choiceDef)
			{
				choiceDef = newChoiceDef;
				UpdateChoiceDisplay(choiceDef);
				UpdateFromVotes();
			}
		}

		private void UpdateChoiceDisplay(RuleChoiceDef displayChoiceDef)
		{
			base.gameObject.name = "Choice (" + displayChoiceDef.globalName + ")";
			image.sprite = displayChoiceDef.sprite;
			bool flag = displayChoiceDef.extraData != null && displayChoiceDef.extraData.GetType() == typeof(ArtifactDef);
			if ((bool)tooltipProvider)
			{
				if (displayChoiceDef.tooltipNameToken == null)
				{
					UnityEngine.Debug.LogErrorFormat("Rule choice {0} .tooltipNameToken is null", displayChoiceDef.globalName);
				}
				if (displayChoiceDef.tooltipBodyToken == null)
				{
					UnityEngine.Debug.LogErrorFormat("Rule choice {0} .tooltipBodyToken is null", displayChoiceDef.tooltipBodyToken);
				}
				tooltipProvider.overrideTitleText = displayChoiceDef.getTooltipName(displayChoiceDef);
				tooltipProvider.titleColor = displayChoiceDef.tooltipNameColor;
				tooltipProvider.bodyToken = displayChoiceDef.tooltipBodyToken;
				tooltipProvider.bodyColor = displayChoiceDef.tooltipBodyColor;
				if (flag)
				{
					ArtifactDef artifactDef = (ArtifactDef)displayChoiceDef.extraData;
					if ((bool)artifactDef)
					{
						tooltipProvider.extraUIDisplayPrefab = artifactDef.extraUIDisplayPrefab;
					}
				}
			}
			if (!hgButton)
			{
				return;
			}
			if (hgButton.updateTextOnHover && (bool)hgButton.hoverLanguageTextMeshController)
			{
				string @string = Language.GetString(displayChoiceDef.tooltipNameToken);
				string string2 = Language.GetString(displayChoiceDef.tooltipBodyToken);
				UnityEngine.Color tooltipNameColor = displayChoiceDef.tooltipNameColor;
				tooltipNameColor.a = 0.2f;
				string stringFormatted = Language.GetStringFormatted("RULE_DESCRIPTION_FORMAT", @string, string2, ColorUtility.ToHtmlStringRGBA(tooltipNameColor));
				hgButton.hoverToken = stringFormatted;
				hgButton.hoverLanguageTextMeshController.token = stringFormatted;
				if (flag)
				{
					ArtifactDef artifactDef2 = (ArtifactDef)displayChoiceDef.extraData;
					if ((bool)artifactDef2 && (bool)artifactDef2.extraUIDisplayPrefab && (bool)targetExtraDisplayInfoContainer && !extraDisplayInfo)
					{
						extraDisplayInfo = UnityEngine.Object.Instantiate(artifactDef2.extraUIDisplayPrefab, targetExtraDisplayInfoContainer.transform);
						extraDisplayInfo.transform.SetSiblingIndex(targetExtraDisplayInfoContainer.transform.childCount);
						extraDisplayInfo.SetActive(value: false);
						hgButton.onSelect.AddListener(OnSelected);
						hgButton.onDeselect.AddListener(OnDeselected);
						targetExtraDisplayInfoContainer.SetActive(value: true);
						if (chosenDisplayObject.activeInHierarchy)
						{
							extraDisplayInfo.SetActive(value: true);
						}
					}
				}
			}
			hgButton.uiClickSoundOverride = choiceDef.selectionUISound;
		}

		private void OnSelected()
		{
			if ((bool)extraDisplayInfo)
			{
				extraDisplayInfo.SetActive(value: true);
			}
		}

		private void OnDeselected()
		{
			if ((bool)extraDisplayInfo && !chosenDisplayObject.activeInHierarchy)
			{
				extraDisplayInfo.SetActive(value: false);
			}
		}

		private NetworkUser FindNetworkUser()
		{
			return ((MPEventSystem)EventSystem.current).localUser?.currentNetworkUser;
		}

		public void OnClick()
		{
			if (!canVote)
			{
				return;
			}
			NetworkUser networkUser = FindNetworkUser();
			if (!networkUser)
			{
				return;
			}
			PreGameRuleVoteController preGameRuleVoteController = PreGameRuleVoteController.FindForUser(networkUser);
			if (!preGameRuleVoteController)
			{
				return;
			}
			RuleChoiceDef ruleChoiceDef;
			RuleChoiceDef ruleChoiceDef2 = (ruleChoiceDef = choiceDef);
			RuleDef ruleDef = ruleChoiceDef2.ruleDef;
			int count = ruleDef.choices.Count;
			int localIndex = ruleChoiceDef2.localIndex;
			bool flag = false;
			UnityEngine.Debug.LogFormat("maxRuleCount={0}, currentChoiceIndex={1}", count, localIndex);
			if (cycleThroughOptions)
			{
				localIndex = (preGameRuleVoteController.IsChoiceVoted(choiceDef) ? (localIndex + 1) : 0);
				if (localIndex > count - 1)
				{
					localIndex = ruleDef.defaultChoiceIndex;
					flag = true;
				}
				ruleChoiceDef = ruleDef.choices[localIndex];
			}
			else if (preGameRuleVoteController.IsChoiceVoted(choiceDef))
			{
				flag = true;
			}
			SetChoice(ruleChoiceDef);
			preGameRuleVoteController.SetVote(ruleChoiceDef.ruleDef.globalIndex, flag ? (-1) : ruleChoiceDef.localIndex);
		}
	}
	public class RunTimerUIController : MonoBehaviour
	{
		public TimerText runStopwatchTimerTextController;

		public SpriteAsNumberManager spriteAsNumberManager;

		private void Start()
		{
			if ((bool)runStopwatchTimerTextController && runStopwatchTimerTextController.TryGetComponent<HGTextMeshProUGUI>(out var component))
			{
				component.enabled = true;
			}
			if ((bool)spriteAsNumberManager)
			{
				spriteAsNumberManager.gameObject.SetActive(value: false);
			}
		}

		private void Update()
		{
			if ((bool)runStopwatchTimerTextController)
			{
				runStopwatchTimerTextController.seconds = (Run.instance ? Run.instance.GetRunStopwatch() : 0f);
			}
			else if ((bool)spriteAsNumberManager)
			{
				spriteAsNumberManager.SetTimerValue(Run.instance ? ((int)Run.instance.GetRunStopwatch()) : 0);
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	[ExecuteAlways]
	public class ScaleToFitParentRect : MonoBehaviour, ILayoutSelfController, ILayoutController
	{
		private RectTransform rectTransform;

		private RectTransform parentRectTransform;

		public bool fitToWidth = true;

		public bool fitToHeight = true;

		public bool stretchUnfittedAxis;

		public UnityEngine.Vector2 referenceSize = UnityEngine.Vector2.zero;

		private UnityEngine.Vector2 parentSize = UnityEngine.Vector2.zero;

		private UnityEngine.Vector2 postScaleStretchSize = UnityEngine.Vector2.zero;

		private float desiredScale = 1f;

		public bool autoReferenceSize = true;

		private bool inApply;

		private void CacheComponents()
		{
			rectTransform = (RectTransform)base.transform;
		}

		private void Awake()
		{
			CacheComponents();
			parentRectTransform = rectTransform.parent as RectTransform;
		}

		private void Start()
		{
		}

		private void OnTransformParentChanged()
		{
			parentRectTransform = rectTransform.parent as RectTransform;
		}

		private void RecalculateScale()
		{
			if ((bool)parentRectTransform)
			{
				parentSize = parentRectTransform.rect.size;
				float a = parentSize.x / referenceSize.x;
				float b = parentSize.y / referenceSize.y;
				if (fitToWidth && fitToHeight)
				{
					desiredScale = Mathf.Min(a, b);
				}
				else if (fitToWidth)
				{
					desiredScale = a;
				}
				else if (fitToHeight)
				{
					desiredScale = b;
				}
				else
				{
					desiredScale = 1f;
				}
				postScaleStretchSize = parentSize / desiredScale;
				if (float.IsNaN(postScaleStretchSize.x))
				{
					postScaleStretchSize.x = 1f;
				}
				if (float.IsNaN(postScaleStretchSize.y))
				{
					postScaleStretchSize.y = 1f;
				}
			}
		}

		private void OnRectTransformDimensionsChange()
		{
			if (!inApply)
			{
				Apply();
			}
		}

		public void SetLayoutHorizontal()
		{
			RecalculateScale();
			UnityEngine.Vector3 localScale = rectTransform.localScale;
			if (localScale.x != desiredScale)
			{
				localScale.x = desiredScale;
				rectTransform.localScale = localScale;
			}
			if (stretchUnfittedAxis && !fitToWidth && rectTransform.rect.width != postScaleStretchSize.x)
			{
				rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, postScaleStretchSize.x);
			}
		}

		public void SetLayoutVertical()
		{
			RecalculateScale();
			UnityEngine.Vector3 localScale = rectTransform.localScale;
			if (localScale.y != desiredScale)
			{
				localScale.y = desiredScale;
				rectTransform.localScale = localScale;
			}
			if (stretchUnfittedAxis && !fitToHeight && rectTransform.rect.height != postScaleStretchSize.y)
			{
				rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, postScaleStretchSize.y);
			}
		}

		public void Apply()
		{
			if (!base.enabled || (object)rectTransform == null)
			{
				return;
			}
			RecalculateScale();
			inApply = true;
			UnityEngine.Vector3 localScale = rectTransform.localScale;
			if (localScale.x != desiredScale && desiredScale != 0f)
			{
				localScale.x = desiredScale;
				localScale.y = desiredScale;
				rectTransform.localScale = localScale;
			}
			if (stretchUnfittedAxis)
			{
				UnityEngine.Rect rect = rectTransform.rect;
				if (!fitToWidth && rect.width != postScaleStretchSize.x)
				{
					rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, postScaleStretchSize.x);
				}
				if (!fitToWidth && rect.height != postScaleStretchSize.y)
				{
					rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, postScaleStretchSize.y);
				}
			}
			inApply = false;
		}

		private void OnValidate()
		{
			CacheComponents();
			parentRectTransform = rectTransform.parent as RectTransform;
			if (autoReferenceSize)
			{
				referenceSize = rectTransform.rect.size;
			}
			Apply();
		}
	}
	public class ScoreboardController : MonoBehaviour
	{
		public GameObject stripPrefab;

		public RectTransform container;

		private MPEventSystem eventSystem;

		[SerializeField]
		private ItemInventoryDisplay suppressedItemDisplay;

		private UIElementAllocator<ScoreboardStrip> stripAllocator;

		public static event UnityAction onScoreboardOpen;

		private void Awake()
		{
			stripAllocator = new UIElementAllocator<ScoreboardStrip>(container, stripPrefab);
			eventSystem = GetComponent<MPEventSystemLocator>().eventSystem;
		}

		private void SetStripCount(int newCount)
		{
			stripAllocator.AllocateElements(newCount);
		}

		private void Rebuild()
		{
			List<PlayerCharacterMasterController> list = PlayerCharacterMasterController.instances.Where((PlayerCharacterMasterController x) => x.gameObject.activeInHierarchy && x.master.GetBody() != null && Util.GetBestMasterName(x.master) != null).ToList();
			SetStripCount(list.Count);
			for (int i = 0; i < list.Count; i++)
			{
				stripAllocator.elements[i].SetMaster(list[i].master);
			}
		}

		private void PlayerEventToRebuild(PlayerCharacterMasterController playerCharacterMasterController)
		{
			UnityEngine.Debug.LogError("ScoreboardController PlayerEventToRebuild call");
			Rebuild();
		}

		private void OnEnable()
		{
			if ((bool)SuppressedItemManager.suppressedInventory)
			{
				suppressedItemDisplay?.SetSubscribedInventory(SuppressedItemManager.suppressedInventory);
				SuppressedItemManager.suppressedInventory.onInventoryChanged += OnInventoryChanged;
			}
			OnInventoryChanged();
			PlayerCharacterMasterController.onPlayerAdded += PlayerEventToRebuild;
			PlayerCharacterMasterController.onPlayerRemoved += PlayerEventToRebuild;
			Rebuild();
			ScoreboardController.onScoreboardOpen?.Invoke();
		}

		private void OnDisable()
		{
			if ((bool)SuppressedItemManager.suppressedInventory)
			{
				suppressedItemDisplay?.SetSubscribedInventory(null);
				SuppressedItemManager.suppressedInventory.onInventoryChanged -= OnInventoryChanged;
			}
			PlayerCharacterMasterController.onPlayerRemoved -= PlayerEventToRebuild;
			PlayerCharacterMasterController.onPlayerAdded -= PlayerEventToRebuild;
		}

		private void OnInventoryChanged()
		{
			suppressedItemDisplay?.gameObject?.SetActive(SuppressedItemManager.HasAnyItemBeenSuppressed());
		}

		public void SelectFirstScoreboardStrip()
		{
			eventSystem.SetSelectedObject(stripAllocator.elements[0].gameObject);
		}
	}
	public class ScoreboardStrip : MonoBehaviour
	{
		public ItemInventoryDisplay itemInventoryDisplay;

		public UnityEngine.UI.Image nameFocusHighlight;

		public EquipmentIcon equipmentIcon;

		public SocialUserIcon userAvatar;

		public TextMeshProUGUI nameLabel;

		public RawImage classIcon;

		public TextMeshProUGUI moneyText;

		public TextMeshProUGUI itemCountText;

		public MPEventSystemLocator eventSystemLocator;

		private CharacterMaster master;

		private CharacterBody userBody;

		private PlayerCharacterMasterController userPlayerCharacterMasterController;

		private uint previousMoney = uint.MaxValue;

		private int previousItemCount = int.MaxValue;

		public void SetMaster(CharacterMaster newMaster)
		{
			userBody = null;
			master = newMaster;
			if ((bool)master)
			{
				userBody = master.GetBody();
				userPlayerCharacterMasterController = master.GetComponent<PlayerCharacterMasterController>();
				itemInventoryDisplay.SetSubscribedInventory(master.inventory);
				equipmentIcon.targetInventory = master.inventory;
				UpdateMoneyText();
				UpdateItemCountText();
			}
			if ((bool)userAvatar && userAvatar.isActiveAndEnabled)
			{
				userAvatar.SetFromMaster(newMaster);
			}
			nameLabel.text = Util.GetBestMasterName(master);
			classIcon.texture = FindMasterPortrait();
		}

		private void UpdateMoneyText()
		{
			if ((bool)master && master.money != previousMoney)
			{
				previousMoney = master.money;
				moneyText.text = $"${previousMoney}";
			}
		}

		private void UpdateItemCountText()
		{
			int totalVisibleItemCount = itemInventoryDisplay.GetTotalVisibleItemCount();
			if ((bool)master && (bool)itemInventoryDisplay && totalVisibleItemCount != previousItemCount)
			{
				previousItemCount = totalVisibleItemCount;
				itemCountText.text = previousItemCount.ToString();
			}
		}

		private void Update()
		{
			UpdateMoneyText();
			UpdateItemCountText();
		}

		private Texture FindMasterPortrait()
		{
			if ((bool)userBody)
			{
				return userBody.portraitIcon;
			}
			if ((bool)master)
			{
				GameObject bodyPrefab = master.bodyPrefab;
				if ((bool)bodyPrefab)
				{
					CharacterBody component = bodyPrefab.GetComponent<CharacterBody>();
					if ((bool)component)
					{
						return component.portraitIcon;
					}
				}
			}
			return null;
		}

		public void SelectFirstItem()
		{
			if (!itemInventoryDisplay.SelectFirstItemIcon())
			{
				equipmentIcon.TrySelect();
			}
		}

		public void EnterStrip()
		{
			SelectFirstItem();
		}

		public void GetPlayerCard()
		{
		}

		public void OnNavItemFocused(UnityEngine.UI.Image image)
		{
			image.color = UnityEngine.Color.yellow;
		}

		public void NavItemUnfocused(UnityEngine.UI.Image image)
		{
			image.color = UnityEngine.Color.black;
		}

		private void ResetNavIndicators()
		{
			itemInventoryDisplay.GetComponent<UnityEngine.UI.Image>().color = UnityEngine.Color.black;
			nameFocusHighlight.color = UnityEngine.Color.black;
		}

		private void OnDisable()
		{
			ResetNavIndicators();
		}
	}
	public class ScrapperInfoPanelHelper : MonoBehaviour
	{
		[SerializeField]
		public InspectPanelController inspectPanelController;

		[SerializeField]
		public UnityEngine.UI.Image correspondingScrapImage;

		private MPEventSystem eventSystem;

		private Inventory cachedBodyInventory;

		private void Awake()
		{
			MPEventSystemLocator component = GetComponent<MPEventSystemLocator>();
			eventSystem = component.eventSystem;
			if (eventSystem != null && eventSystem.localUser != null && eventSystem.localUser.cachedBody != null)
			{
				cachedBodyInventory = eventSystem.localUser.cachedBody.inventory;
			}
		}

		private void Update()
		{
			if (eventSystem.player.GetButtonDown(15))
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}

		public void ShowInfo(MPButton button, PickupDef pickupDef)
		{
			inspectPanelController.Show(pickupDef);
			PickupDef pickupDef2 = PickupCatalog.GetPickupDef(PickupCatalog.FindScrapIndexForItemTier(pickupDef.itemTier));
			if (pickupDef2 != null)
			{
				correspondingScrapImage.sprite = pickupDef2.iconSprite;
			}
		}

		public void AddQuantityToPickerButton(MPButton button, PickupDef pickupDef)
		{
			if (!cachedBodyInventory)
			{
				return;
			}
			int itemCount = cachedBodyInventory.GetItemCount(pickupDef.itemIndex);
			TextMeshProUGUI textMeshProUGUI = button.GetComponent<ChildLocator>().FindChildComponent<TextMeshProUGUI>("Quantity");
			if ((bool)textMeshProUGUI)
			{
				if (itemCount > 1)
				{
					textMeshProUGUI.SetText($"{itemCount}");
				}
				else
				{
					textMeshProUGUI.gameObject.SetActive(value: false);
				}
			}
		}
	}
	[RequireComponent(typeof(ScrollRect))]
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class ScrollToSelection : MonoBehaviour
	{
		private ScrollRect scrollRect;

		private MPEventSystemLocator eventSystemLocator;

		private UnityEngine.Vector3[] targetWorldCorners = new UnityEngine.Vector3[4];

		private UnityEngine.Vector3[] viewPortWorldCorners = new UnityEngine.Vector3[4];

		private GameObject lastSelectedObject;

		private EventSystem eventSystem => eventSystemLocator.eventSystem;

		private void Awake()
		{
			scrollRect = GetComponent<ScrollRect>();
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private void Update()
		{
			GameObject gameObject = (eventSystem ? eventSystem.currentSelectedGameObject : null);
			if (lastSelectedObject != gameObject)
			{
				if ((bool)gameObject && gameObject.transform.IsChildOf(base.transform))
				{
					ScrollToRect((RectTransform)gameObject.transform);
				}
				lastSelectedObject = gameObject;
			}
		}

		private void ScrollToRect(RectTransform targetRectTransform)
		{
			targetRectTransform.GetWorldCorners(targetWorldCorners);
			((RectTransform)base.transform).GetWorldCorners(viewPortWorldCorners);
			if (scrollRect.vertical && (bool)scrollRect.verticalScrollbar)
			{
				float y = targetWorldCorners[1].y;
				float y2 = targetWorldCorners[0].y;
				float y3 = viewPortWorldCorners[1].y;
				float y4 = viewPortWorldCorners[0].y;
				float num = y - y3;
				float num2 = y2 - y4;
				float num3 = y3 - y4;
				if (num > 0f)
				{
					scrollRect.verticalScrollbar.value += num / num3;
				}
				if (num2 < 0f)
				{
					scrollRect.verticalScrollbar.value += num2 / num3;
				}
			}
			if (scrollRect.horizontal && (bool)scrollRect.horizontalScrollbar)
			{
				float y5 = targetWorldCorners[2].y;
				float y6 = targetWorldCorners[0].y;
				float y7 = viewPortWorldCorners[2].y;
				float y8 = viewPortWorldCorners[0].y;
				float num4 = y5 - y7;
				float num5 = y6 - y8;
				float num6 = y7 - y8;
				if (num4 > 0f)
				{
					scrollRect.horizontalScrollbar.value += num4 / num6;
				}
				if (num5 < 0f)
				{
					scrollRect.horizontalScrollbar.value += num5 / num6;
				}
			}
		}
	}
	[Obsolete("Use the options in HGButton instead.")]
	public class SelectableDescriptionUpdater : MonoBehaviour, ISelectHandler, IEventSystemHandler, IDeselectHandler, IPointerEnterHandler, IPointerExitHandler
	{
		public LanguageTextMeshController languageTextMeshController;

		public string selectableDescriptionToken;

		public void OnPointerExit(PointerEventData eventData)
		{
			languageTextMeshController.token = "";
		}

		public void OnDeselect(BaseEventData eventData)
		{
			languageTextMeshController.token = "";
		}

		public void OnPointerEnter(PointerEventData eventData)
		{
			languageTextMeshController.token = selectableDescriptionToken;
		}

		public void OnSelect(BaseEventData eventData)
		{
			languageTextMeshController.token = selectableDescriptionToken;
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class ServerBrowserController : MonoBehaviour
	{
	}
	[RequireComponent(typeof(RectTransform))]
	public class ServerBrowserStripController : MonoBehaviour
	{
		private RectTransform rectTransform;

		public HGTextMeshProUGUI nameLabel;

		public HGTextMeshProUGUI addressLabel;

		public HGTextMeshProUGUI playerCountLabel;

		public HGTextMeshProUGUI latencyLabel;

		private void Awake()
		{
			rectTransform = (RectTransform)base.transform;
		}
	}
	[RequireComponent(typeof(TextMeshProUGUI))]
	public class SetLabelTextToMainUserProfileName : MonoBehaviour
	{
		private TextMeshProUGUI label;

		private void Awake()
		{
			label = GetComponent<TextMeshProUGUI>();
		}

		private void OnEnable()
		{
			Apply();
		}

		private void Apply()
		{
			if (LocalUserManager.FindLocalUser(0) != null)
			{
				string userName = PlatformSystems.userManager.GetUserName();
				label.text = userName;
			}
			else
			{
				label.text = string.Format(Language.GetString("TITLE_PROFILE"), "");
			}
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			Language.onCurrentLanguageChanged += OnCurrentLanguageChanged;
			LocalUserManager.onUserSignIn += OnUserSignedIn;
			UserManager.OnUserStateChanged += OnCurrentLanguageChanged;
		}

		private static void OnUserSignedIn(LocalUser obj)
		{
			OnCurrentLanguageChanged();
		}

		private static void OnCurrentLanguageChanged()
		{
			SetLabelTextToMainUserProfileName[] array = UnityEngine.Object.FindObjectsOfType<SetLabelTextToMainUserProfileName>();
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Apply();
			}
		}
	}
	public class SettingsPanelController : MonoBehaviour
	{
		[FormerlySerializedAs("carouselControllers")]
		private BaseSettingsControl[] settingsControllers;

		public MPButton revertButton;

		private static string viewableName = "Settings";

		public bool usedForFriendsBrowser;

		public static bool settingsPanelOpen = false;

		public GameObject[] ensureElementsEnabled;

		private bool useEnsure;

		private string confirmControllerDefaultsTitleToken = "OPTION_DEFAULT_SETTINGS";

		private string confirmControllerDefaultsDescriptionToken = "";

		private bool wasRemapping;

		private MPEventSystemLocator eventSystemLocator;

		protected MPEventSystem eventSystem => eventSystemLocator?.eventSystem;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			ViewablesCatalog.AddNodeToRoot(new ViewablesCatalog.Node(viewableName, isFolder: false)
			{
				shouldShowUnviewed = CheckViewable
			});
		}

		private static bool CheckViewable(UserProfile userProfile)
		{
			return !userProfile.HasViewedViewable("/" + viewableName);
		}

		private void Start()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			settingsControllers = GetComponentsInChildren<BaseSettingsControl>();
		}

		public void ConfirmControllerDefaults()
		{
			SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create(eventSystem);
			simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair(confirmControllerDefaultsTitleToken);
			simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair(confirmControllerDefaultsDescriptionToken);
			simpleDialogBox.AddActionButton(RevertChanges, "DIALOG_OPTION_YES", true);
			simpleDialogBox.AddCancelButton("CANCEL");
		}

		private void UpdateResetToDefaults()
		{
			if (SimpleDialogBox.instancesList.Count < 1 && !wasRemapping && !InputMapperHelper.anyRemapperListening && eventSystem != null && eventSystem.currentInputSource == MPEventSystem.InputSource.Gamepad && eventSystem.player.GetButtonDown(31))
			{
				ConfirmControllerDefaults();
			}
			wasRemapping = InputMapperHelper.anyRemapperListening;
		}

		private void Update()
		{
			if (settingsControllers == null)
			{
				return;
			}
			bool interactable = false;
			for (int i = 0; i < settingsControllers.Length; i++)
			{
				BaseSettingsControl baseSettingsControl = settingsControllers[i];
				if ((bool)baseSettingsControl && baseSettingsControl.hasBeenChanged)
				{
					interactable = true;
				}
			}
			if ((bool)revertButton)
			{
				revertButton.interactable = interactable;
			}
			if (!usedForFriendsBrowser)
			{
				UpdateResetToDefaults();
			}
		}

		public void RevertChanges()
		{
			if (base.isActiveAndEnabled)
			{
				BaseSettingsControl[] componentsInChildren = GetComponentsInChildren<BaseSettingsControl>();
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].ResetToDefault();
				}
				DefaultSettings component = GetComponent<DefaultSettings>();
				if ((bool)component)
				{
					component.RestoreDefaultControllerSettings(eventSystem.player);
				}
			}
		}

		private void OnEnable()
		{
			settingsPanelOpen = true;
			bool active = useEnsure;
			GameObject[] array = ensureElementsEnabled;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetActive(active);
			}
		}

		private void OnDisable()
		{
			if (GetHaveOptionsChanged(forSpecificSource: true))
			{
				Console.instance?.SaveArchiveConVars();
			}
			if ((InputMapperHelper.anyRemapperListening || GetHaveOptionsChanged(forSpecificSource: true, BaseSettingsControl.SettingSource.UserProfilePref)) && settingsControllers != null)
			{
				UserProfile currentUserProfile = settingsControllers[0].GetCurrentUserProfile();
				if (currentUserProfile != null)
				{
					PlatformSystems.saveSystem.RequestSave(currentUserProfile);
				}
			}
			settingsPanelOpen = false;
			GameObject[] array = ensureElementsEnabled;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].SetActive(value: false);
			}
		}

		private bool GetHaveOptionsChanged(bool forSpecificSource = false, BaseSettingsControl.SettingSource source = BaseSettingsControl.SettingSource.ConVar)
		{
			if (settingsControllers == null)
			{
				return false;
			}
			for (int i = 0; i < settingsControllers.Length; i++)
			{
				BaseSettingsControl baseSettingsControl = settingsControllers[i];
				if (baseSettingsControl.hasBeenChanged && (!forSpecificSource || baseSettingsControl.settingSource == source))
				{
					return true;
				}
			}
			return false;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class SettingsSlider : BaseSettingsControl
	{
		public Slider slider;

		public HGTextMeshProUGUI valueText;

		public float minValue;

		public float maxValue;

		[Tooltip("When this setting is turned 'on' as part of a subsection, set the value to defaultEnabledValue. maxValue is used otherwise ")]
		public bool overrideDefaultEnabledValue;

		public float defaultEnabledValue = 1f;

		public string formatString = "{0:0.00}";

		private bool listenerAdded;

		private MPEventSystemLocator systemLocator;

		private MPInputModule inputModule;

		private float sliderSpeed = 1f;

		private float prevTimestamp;

		private float accumulatedTime;

		private float prevDirection;

		private const float timePerSpeedLevel = 1f;

		private const float boostPerSpeedLevel = 4f;

		private const float maxSpeedLevel = 10f;

		protected new void Awake()
		{
			base.Awake();
			if ((bool)slider)
			{
				slider.minValue = minValue;
				slider.maxValue = maxValue;
				if (!listenerAdded)
				{
					slider.onValueChanged.AddListener(OnSliderValueChanged);
				}
			}
			listenerAdded = true;
			systemLocator = GetComponent<MPEventSystemLocator>();
		}

		private new void OnEnable()
		{
			UpdateControls();
			if ((bool)slider)
			{
				slider.minValue = minValue;
				slider.maxValue = maxValue;
				if (!listenerAdded)
				{
					slider.onValueChanged.AddListener(OnSliderValueChanged);
				}
			}
			listenerAdded = true;
		}

		private void OnSliderValueChanged(float newValue)
		{
			if (!base.inUpdateControls)
			{
				SubmitSetting(TextSerialization.ToStringInvariant(newValue));
			}
		}

		private void OnInputFieldSubmit(string newString)
		{
			if (!base.inUpdateControls && TextSerialization.TryParseInvariant(newString, out float result))
			{
				SubmitSetting(TextSerialization.ToStringInvariant(result));
			}
		}

		public override void SetSettingState(bool turnedOn)
		{
			if (!turnedOn && !Mathf.Approximately(slider.value, minValue))
			{
				defaultEnabledValue = slider.value;
			}
			slider.value = ((!turnedOn) ? minValue : (overrideDefaultEnabledValue ? defaultEnabledValue : maxValue));
		}

		public override bool IsSettingEnabled()
		{
			return slider.normalizedValue > 0f;
		}

		protected override void OnUpdateControls()
		{
			base.OnUpdateControls();
			if (TextSerialization.TryParseInvariant(GetCurrentValue(), out float result))
			{
				float num = Mathf.Clamp(result, minValue, maxValue);
				if ((bool)slider)
				{
					slider.value = num;
				}
				if ((bool)valueText)
				{
					valueText.text = string.Format(CultureInfo.InvariantCulture, formatString, num);
				}
			}
		}

		private float CalculateSliderSpeed(float deltaTime, float direction)
		{
			if (inputModule == null)
			{
				inputModule = systemLocator.eventSystem.GetComponent<MPInputModule>();
			}
			float num = 1.5f / inputModule.inputActionsPerSecond;
			if (deltaTime <= num * 2f && direction == prevDirection)
			{
				accumulatedTime += deltaTime;
			}
			else
			{
				accumulatedTime = 0f;
			}
			prevDirection = direction;
			return Mathf.Min(10f, 1f + Mathf.Floor(accumulatedTime / 1f) * 4f);
		}

		public void MoveSlider(float delta)
		{
			float timeSinceLevelLoad = Time.timeSinceLevelLoad;
			float deltaTime = timeSinceLevelLoad - prevTimestamp;
			prevTimestamp = timeSinceLevelLoad;
			sliderSpeed = CalculateSliderSpeed(deltaTime, Mathf.Sign(delta));
			if ((bool)slider)
			{
				slider.normalizedValue += delta * sliderSpeed;
			}
		}
	}
	public class SettingsTextBox : BaseSettingsControl
	{
		public TMP_InputField textbox;

		protected new void OnEnable()
		{
			base.OnEnable();
			textbox?.onValueChanged?.AddListener(OnTextBoxValueChanged);
		}

		protected void OnDisable()
		{
			textbox?.onValueChanged?.RemoveListener(OnTextBoxValueChanged);
		}

		private void OnTextBoxValueChanged(string newValue)
		{
			SubmitSetting(newValue);
		}

		protected override void OnUpdateControls()
		{
			string currentValue = GetCurrentValue();
			textbox?.SetTextWithoutNotify(currentValue);
		}
	}
	public class SettingSubsectionHelper : MonoBehaviour
	{
		[Tooltip("The setting entry responsible for representing the subsection state. Has to be an ON/OFF bool setting")]
		public CarouselController subsectionSettingEntry;

		private void Awake()
		{
			BaseSettingsControl[] componentsInChildren = GetComponentsInChildren<BaseSettingsControl>();
			foreach (BaseSettingsControl obj in componentsInChildren)
			{
				obj.onValueChanged = (UnityAction)Delegate.Combine(obj.onValueChanged, (UnityAction)delegate
				{
					if ((bool)subsectionSettingEntry)
					{
						subsectionSettingEntry.SetSettingState(AreAnyChildSettingsEnabled());
					}
				});
			}
		}

		public void ApplyStateToChildSettings(bool settingEnabled)
		{
			BaseSettingsControl[] componentsInChildren = GetComponentsInChildren<BaseSettingsControl>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].SetSettingState(settingEnabled);
			}
		}

		public bool AreAnyChildSettingsEnabled()
		{
			BaseSettingsControl[] componentsInChildren = GetComponentsInChildren<BaseSettingsControl>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (componentsInChildren[i].IsSettingEnabled())
				{
					return true;
				}
			}
			return false;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class SimpleDialogBox : UIBehaviour
	{
		public struct TokenParamsPair
		{
			public string token;

			public object[] formatParams;

			public TokenParamsPair(string token, params object[] formatParams)
			{
				this.token = token;
				this.formatParams = formatParams;
			}
		}

		public static readonly List<SimpleDialogBox> instancesList = new List<SimpleDialogBox>();

		public GameObject rootObject;

		public GameObject buttonPrefab;

		public RectTransform buttonContainer;

		public TextMeshProUGUI headerLabel;

		public TextMeshProUGUI descriptionLabel;

		private MPButton defaultChoice;

		public object[] descriptionFormatParameters;

		public TokenParamsPair headerToken
		{
			set
			{
				headerLabel.text = GetString(value);
			}
		}

		public TokenParamsPair descriptionToken
		{
			set
			{
				descriptionLabel.text = GetString(value);
			}
		}

		protected override void OnEnable()
		{
			base.OnEnable();
			instancesList.Add(this);
		}

		protected override void OnDisable()
		{
			instancesList.Remove(this);
			base.OnDisable();
		}

		private static string GetString(TokenParamsPair pair)
		{
			string text = Language.GetString(pair.token);
			if (pair.formatParams != null && pair.formatParams.Length != 0)
			{
				text = string.Format(text, pair.formatParams);
			}
			return text;
		}

		private MPButton AddButton(UnityAction callback, string displayToken, params object[] formatParams)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(buttonPrefab, buttonContainer);
			MPButton component = gameObject.GetComponent<MPButton>();
			string text = Language.GetString(displayToken);
			if (formatParams != null && formatParams.Length != 0)
			{
				text = string.Format(text, formatParams);
			}
			gameObject.GetComponentInChildren<TextMeshProUGUI>().text = text;
			component.onClick.AddListener(callback);
			gameObject.SetActive(value: true);
			if (!defaultChoice)
			{
				defaultChoice = component;
			}
			if (buttonContainer.childCount > 1)
			{
				int siblingIndex = gameObject.transform.GetSiblingIndex();
				int num = siblingIndex - 1;
				int num2 = siblingIndex + 1;
				MPButton mPButton = null;
				MPButton mPButton2 = null;
				if (num > 0)
				{
					mPButton = buttonContainer.GetChild(num).GetComponent<MPButton>();
				}
				if (num2 < buttonContainer.childCount)
				{
					mPButton2 = buttonContainer.GetChild(num2).GetComponent<MPButton>();
				}
				if ((bool)mPButton)
				{
					UnityEngine.UI.Navigation navigation = mPButton.navigation;
					navigation.mode = UnityEngine.UI.Navigation.Mode.Explicit;
					navigation.selectOnRight = component;
					mPButton.navigation = navigation;
					UnityEngine.UI.Navigation navigation2 = component.navigation;
					navigation2.mode = UnityEngine.UI.Navigation.Mode.Explicit;
					navigation2.selectOnLeft = mPButton;
					component.navigation = navigation2;
				}
				if ((bool)mPButton2)
				{
					UnityEngine.UI.Navigation navigation3 = mPButton2.navigation;
					navigation3.mode = UnityEngine.UI.Navigation.Mode.Explicit;
					navigation3.selectOnLeft = mPButton;
					mPButton2.navigation = navigation3;
					UnityEngine.UI.Navigation navigation4 = component.navigation;
					navigation4.mode = UnityEngine.UI.Navigation.Mode.Explicit;
					navigation4.selectOnRight = mPButton2;
					component.navigation = navigation4;
				}
			}
			return component;
		}

		public MPButton AddCommandButton(string consoleString, string displayToken, params object[] formatParams)
		{
			return AddButton(delegate
			{
				if (!string.IsNullOrEmpty(consoleString))
				{
					Console.instance.SubmitCmd(null, consoleString, recordSubmit: true);
				}
				UnityEngine.Object.Destroy(rootObject);
			}, displayToken, formatParams);
		}

		public MPButton AddCancelButton(string displayToken, params object[] formatParams)
		{
			return AddButton(delegate
			{
				UnityEngine.Object.Destroy(rootObject);
			}, displayToken, formatParams);
		}

		public MPButton AddActionButton(UnityAction action, string displayToken, bool destroyDialog = true, params object[] formatParams)
		{
			return AddButton(delegate
			{
				action();
				if (destroyDialog)
				{
					UnityEngine.Object.Destroy(rootObject);
				}
			}, displayToken, formatParams);
		}

		protected override void Start()
		{
			base.Start();
			if ((bool)defaultChoice)
			{
				defaultChoice.defaultFallbackButton = true;
			}
		}

		private void Update()
		{
			buttonContainer.gameObject.SetActive(buttonContainer.childCount > 0);
		}

		public static SimpleDialogBox Create(MPEventSystem owner = null)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/SimpleDialogRoot"));
			if ((bool)owner)
			{
				MPEventSystemProvider component = gameObject.GetComponent<MPEventSystemProvider>();
				component.eventSystem = owner;
				component.fallBackToMainEventSystem = false;
				component.eventSystem.SetSelectedGameObject(null);
			}
			return gameObject.transform.GetComponentInChildren<SimpleDialogBox>();
		}
	}
	[RequireComponent(typeof(UnityEngine.UI.Image))]
	public class SimpleSpriteAnimator : MonoBehaviour
	{
		public SimpleSpriteAnimation animation;

		private UnityEngine.UI.Image target;

		private int frame;

		private int tick;

		private float tickStopwatch;

		private void Awake()
		{
			target = GetComponent<UnityEngine.UI.Image>();
		}

		private void FixedUpdate()
		{
			if ((bool)animation && animation.frames.Length != 0)
			{
				tickStopwatch += Time.fixedDeltaTime;
				float num = 1f / animation.frameRate;
				if (tickStopwatch > num)
				{
					tickStopwatch -= num;
					Tick();
				}
			}
		}

		private void Tick()
		{
			tick++;
			if (frame >= animation.frames.Length)
			{
				frame = 0;
				tick = 0;
			}
			if (animation.frames[frame].duration <= tick)
			{
				frame++;
				if (frame >= animation.frames.Length)
				{
					frame = 0;
					tick = 0;
				}
				ref SimpleSpriteAnimation.Frame reference = ref animation.frames[frame];
				target.sprite = reference.sprite;
			}
		}
	}
	public class SkillIcon : MonoBehaviour
	{
		public SkillSlot targetSkillSlot;

		public PlayerCharacterMasterController playerCharacterMasterController;

		public GenericSkill targetSkill;

		public UnityEngine.UI.Image iconImage;

		public RawImage cooldownRemapPanel;

		public TextMeshProUGUI cooldownText;

		public TextMeshProUGUI stockText;

		public GameObject flashPanelObject;

		public GameObject isReadyPanelObject;

		public Animator animator;

		public string animatorStackString;

		public bool wasReady;

		public int previousStock;

		public TooltipProvider tooltipProvider;

		public int previousCoolDownInt;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		private int previousSkillIndex = -1;

		private bool skillChanged;

		private void CheckAndRegisterSkillChange()
		{
			if (targetSkill.skillDef.skillIndex != previousSkillIndex)
			{
				skillChanged = previousSkillIndex != -1;
				previousStock = -1;
				previousSkillIndex = targetSkill.skillDef.skillIndex;
			}
		}

		private void Update()
		{
			if ((bool)targetSkill)
			{
				CheckAndRegisterSkillChange();
				if ((bool)tooltipProvider)
				{
					UnityEngine.Color bodyColor = targetSkill.characterBody.bodyColor;
					SurvivorCatalog.GetSurvivorIndexFromBodyIndex(targetSkill.characterBody.bodyIndex);
					UnityEngine.Color.RGBToHSV(bodyColor, out var H, out var S, out var V);
					V = ((V > 0.7f) ? 0.7f : V);
					bodyColor = UnityEngine.Color.HSVToRGB(H, S, V);
					tooltipProvider.titleColor = bodyColor;
					tooltipProvider.titleToken = targetSkill.skillNameToken;
					tooltipProvider.bodyToken = targetSkill.skillDescriptionToken;
				}
				float cooldownRemaining = targetSkill.cooldownRemaining;
				float num = targetSkill.CalculateFinalRechargeInterval();
				int stock = targetSkill.stock;
				bool flag = stock > 0 || cooldownRemaining == 0f;
				bool flag2 = targetSkill.IsReady();
				bool flag3 = targetSkill.maxStock > 1 && !targetSkill.skillDef.hideStockCount;
				if (previousStock < stock && !skillChanged)
				{
					Util.PlaySound("Play_UI_cooldownRefresh", RoR2Application.instance.gameObject);
				}
				if ((bool)animator)
				{
					if (flag3)
					{
						animator.SetBool(animatorStackString, value: true);
					}
					else
					{
						animator.SetBool(animatorStackString, value: false);
					}
				}
				if ((bool)isReadyPanelObject)
				{
					isReadyPanelObject.SetActive(flag2);
				}
				if (!wasReady && flag && (bool)flashPanelObject)
				{
					flashPanelObject.SetActive(value: true);
				}
				if ((bool)cooldownText)
				{
					if (flag)
					{
						cooldownText.gameObject.SetActive(value: false);
					}
					else
					{
						int num2 = Mathf.CeilToInt(cooldownRemaining);
						if (previousCoolDownInt != num2)
						{
							previousCoolDownInt = num2;
							sharedStringBuilder.Clear();
							sharedStringBuilder.AppendInt(num2);
							cooldownText.SetText(sharedStringBuilder);
							cooldownText.gameObject.SetActive(value: true);
						}
					}
				}
				if ((bool)iconImage)
				{
					iconImage.enabled = true;
					iconImage.color = (flag2 ? UnityEngine.Color.white : UnityEngine.Color.gray);
					iconImage.sprite = targetSkill.icon;
				}
				if ((bool)cooldownRemapPanel)
				{
					float num3 = 1f;
					if (num >= Mathf.Epsilon)
					{
						num3 = 1f - cooldownRemaining / num;
					}
					float num4 = num3;
					cooldownRemapPanel.enabled = num4 < 1f;
					cooldownRemapPanel.color = new UnityEngine.Color(1f, 1f, 1f, num3);
				}
				if ((bool)stockText)
				{
					if (flag3)
					{
						if (previousStock != stock)
						{
							stockText.gameObject.SetActive(value: true);
							sharedStringBuilder.Clear();
							sharedStringBuilder.AppendInt(stock);
							stockText.SetText(sharedStringBuilder);
						}
					}
					else
					{
						stockText.gameObject.SetActive(value: false);
					}
				}
				wasReady = flag;
				previousStock = stock;
				skillChanged = false;
			}
			else
			{
				if ((bool)tooltipProvider)
				{
					tooltipProvider.bodyColor = UnityEngine.Color.gray;
					tooltipProvider.titleToken = "";
					tooltipProvider.bodyToken = "";
				}
				if ((bool)cooldownText)
				{
					cooldownText.gameObject.SetActive(value: false);
				}
				if ((bool)stockText)
				{
					stockText.gameObject.SetActive(value: false);
				}
				if ((bool)iconImage)
				{
					iconImage.enabled = false;
					iconImage.sprite = null;
				}
			}
		}
	}
	[RequireComponent(typeof(HudElement))]
	public class SniperRangeIndicator : MonoBehaviour
	{
		public TextMeshProUGUI label;

		private HudElement hudElement;

		private void Awake()
		{
			hudElement = GetComponent<HudElement>();
		}

		private void FixedUpdate()
		{
			float num = float.PositiveInfinity;
			if ((bool)hudElement.targetCharacterBody)
			{
				InputBankTest component = hudElement.targetCharacterBody.GetComponent<InputBankTest>();
				if ((bool)component)
				{
					Ray ray = new Ray(component.aimOrigin, component.aimDirection);
					RaycastHit hitInfo = default(RaycastHit);
					if (Util.CharacterRaycast(hudElement.targetCharacterBody.gameObject, ray, out hitInfo, float.PositiveInfinity, (int)LayerIndex.world.mask | (int)LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal))
					{
						num = hitInfo.distance;
					}
				}
			}
			label.text = "Dis: " + ((num > 999f) ? "999m" : $"{Mathf.FloorToInt(num):D3}m");
		}
	}
	[RequireComponent(typeof(HudElement))]
	public class SniperScopeChargeIndicatorController : MonoBehaviour
	{
		private GameObject sourceGameObject;

		private HudElement hudElement;

		public UnityEngine.UI.Image image;

		private void Awake()
		{
			hudElement = GetComponent<HudElement>();
		}

		private void FixedUpdate()
		{
			float fillAmount = 0f;
			if ((bool)hudElement.targetCharacterBody)
			{
				SkillLocator component = hudElement.targetCharacterBody.GetComponent<SkillLocator>();
				if ((bool)component && (bool)component.secondary)
				{
					EntityStateMachine stateMachine = component.secondary.stateMachine;
					if ((bool)stateMachine && stateMachine.state is ScopeSniper scopeSniper)
					{
						fillAmount = scopeSniper.charge;
					}
				}
			}
			if ((bool)image)
			{
				image.fillAmount = fillAmount;
			}
		}
	}
	[RequireComponent(typeof(PointViewer))]
	public class SniperTargetViewer : MonoBehaviour
	{
		public GameObject visualizerPrefab;

		private PointViewer pointViewer;

		private HUD hud;

		private Dictionary<UnityObjectWrapperKey<HurtBox>, GameObject> hurtBoxToVisualizer = new Dictionary<UnityObjectWrapperKey<HurtBox>, GameObject>();

		private List<HurtBox> displayedTargets = new List<HurtBox>();

		private List<HurtBox> previousDisplayedTargets = new List<HurtBox>();

		private void Awake()
		{
			pointViewer = GetComponent<PointViewer>();
			OnTransformParentChanged();
		}

		private void OnTransformParentChanged()
		{
			hud = GetComponentInParent<HUD>();
		}

		private void OnDisable()
		{
			SetDisplayedTargets(Array.Empty<HurtBox>());
			hurtBoxToVisualizer.Clear();
		}

		private void Update()
		{
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			if ((bool)hud && (bool)hud.targetMaster)
			{
				TeamIndex teamIndex = hud.targetMaster.teamIndex;
				IReadOnlyList<HurtBox> readOnlySniperTargetsList = HurtBox.readOnlySniperTargetsList;
				int i = 0;
				for (int count = readOnlySniperTargetsList.Count; i < count; i++)
				{
					HurtBox hurtBox = readOnlySniperTargetsList[i];
					if ((bool)hurtBox.healthComponent && hurtBox.healthComponent.alive && FriendlyFireManager.ShouldDirectHitProceed(hurtBox.healthComponent, teamIndex) && (object)hurtBox.healthComponent.body != hud.targetMaster.GetBody())
					{
						list.Add(hurtBox);
					}
				}
			}
			SetDisplayedTargets(list);
			list = CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}

		private void OnTargetDiscovered(HurtBox hurtBox)
		{
			if (!hurtBoxToVisualizer.ContainsKey(hurtBox))
			{
				GameObject value = pointViewer.AddElement(new PointViewer.AddElementRequest
				{
					elementPrefab = visualizerPrefab,
					target = hurtBox.transform,
					targetWorldVerticalOffset = 0f,
					targetWorldRadius = HurtBox.sniperTargetRadius,
					scaleWithDistance = true
				});
				hurtBoxToVisualizer.Add(hurtBox, value);
			}
			else
			{
				UnityEngine.Debug.LogWarning($"Already discovered hurtbox: {hurtBox}");
			}
		}

		private void OnTargetLost(HurtBox hurtBox)
		{
			if (hurtBoxToVisualizer.TryGetValue(hurtBox, out var value))
			{
				pointViewer.RemoveElement(value);
			}
		}

		private void SetDisplayedTargets(IReadOnlyList<HurtBox> newDisplayedTargets)
		{
			Util.Swap(ref displayedTargets, ref previousDisplayedTargets);
			displayedTargets.Clear();
			ListUtils.AddRange(displayedTargets, newDisplayedTargets);
			List<HurtBox> list = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			List<HurtBox> list2 = CollectionPool<HurtBox, List<HurtBox>>.RentCollection();
			ListUtils.FindExclusiveEntriesByReference(displayedTargets, previousDisplayedTargets, list, list2);
			foreach (HurtBox item in list2)
			{
				OnTargetLost(item);
			}
			foreach (HurtBox item2 in list)
			{
				OnTargetDiscovered(item2);
			}
			list2 = CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list2);
			list = CollectionPool<HurtBox, List<HurtBox>>.ReturnCollection(list);
		}
	}
	[RequireComponent(typeof(TextMeshProUGUI))]
	public class SocialUsernameLabel : MonoBehaviour
	{
		protected TextMeshProUGUI textMeshComponent;

		private PlatformID _userId;

		public int subPlayerIndex;

		public PlatformID userId
		{
			get
			{
				return _userId;
			}
			set
			{
				_userId = value;
			}
		}

		private void Awake()
		{
			textMeshComponent = GetComponent<TextMeshProUGUI>();
		}

		public virtual void Refresh()
		{
			if (textMeshComponent != null)
			{
				textMeshComponent.text = PlatformSystems.lobbyManager.GetUserDisplayName(_userId);
			}
		}
	}
	public class SpectatorLabel : MonoBehaviour
	{
		public HUD hud;

		public HGTextMeshProUGUI label;

		public GameObject labelRoot;

		private GameObject cachedTarget;

		private HudElement hudElement;

		private void Awake()
		{
			labelRoot.SetActive(value: false);
		}

		private void Update()
		{
			UpdateLabel();
		}

		private void UpdateLabel()
		{
			CameraRigController cameraRigController = hud.cameraRigController;
			GameObject gameObject = null;
			GameObject gameObject2 = null;
			if ((bool)cameraRigController)
			{
				gameObject = cameraRigController.target;
				gameObject2 = cameraRigController.localUserViewer.cachedBodyObject;
			}
			if ((object)gameObject == gameObject2 || !(gameObject != null))
			{
				labelRoot.SetActive(value: false);
				cachedTarget = null;
				return;
			}
			labelRoot.SetActive(value: true);
			if ((object)cachedTarget != gameObject)
			{
				string text = (gameObject ? Util.GetBestBodyName(gameObject) : "");
				label.SetText(Language.GetStringFormatted("SPECTATING_NAME_FORMAT", text));
				cachedTarget = gameObject;
			}
		}
	}
	public class StageCountDisplay : MonoBehaviour
	{
		public TextMeshProUGUI text;

		private int lastStage = -1;

		private void Update()
		{
			if (!(Run.instance != null))
			{
				return;
			}
			int num = Run.instance.stageClearCount + 1;
			if (num != lastStage)
			{
				string text = "-";
				if ((bool)Run.instance)
				{
					text = num.ToString();
				}
				this.text.text = Language.GetStringFormatted("STAGE_COUNT_FORMAT", text);
				lastStage = num;
			}
		}
	}
	[RequireComponent(typeof(UnityEngine.UI.Image))]
	public class StageFadeTransitionController : MonoBehaviour
	{
		private UnityEngine.UI.Image fadeImage;

		private float startEngineTime;

		private const float transitionDuration = 0.5f;

		private void Awake()
		{
			fadeImage = GetComponent<UnityEngine.UI.Image>();
			UnityEngine.Color color = fadeImage.color;
			color.a = 1f;
			fadeImage.color = color;
		}

		private void Start()
		{
			UnityEngine.Color color = fadeImage.color;
			color.a = 1f;
			fadeImage.color = color;
			fadeImage.CrossFadeColor(UnityEngine.Color.black, 0.5f, ignoreTimeScale: false, useAlpha: true);
			startEngineTime = Time.time;
		}

		private void Update()
		{
			if ((bool)Stage.instance)
			{
				Run.FixedTimeStamp stageAdvanceTime = Stage.instance.stageAdvanceTime;
				float num = Time.time - startEngineTime;
				float a = 0f;
				float b = 0f;
				if (num < 0.5f)
				{
					a = 1f - Mathf.Clamp01((Time.time - startEngineTime) / 0.5f);
				}
				if (!stageAdvanceTime.isInfinity)
				{
					float num2 = Stage.instance.stageAdvanceTime - 0.25f - Run.FixedTimeStamp.now;
					b = 1f - Mathf.Clamp01(num2 / 0.5f);
				}
				UnityEngine.Color color = fadeImage.color;
				color.a = Mathf.Max(a, b);
				fadeImage.color = color;
			}
		}
	}
	[RequireComponent(typeof(TextMeshProUGUI))]
	public class SteamBuildIdLabel : MonoBehaviour
	{
		private void Start()
		{
			string text = "ver. " + RoR2Application.GetBuildId();
			if (!string.IsNullOrEmpty("290"))
			{
				text += "#290";
			}
			if (Client.Instance != null)
			{
				string betaName = Client.Instance.BetaName;
				if (!string.IsNullOrEmpty(betaName))
				{
					text = text + "[" + betaName + "]";
				}
				GetComponent<TextMeshProUGUI>().text = text;
			}
			else
			{
				UnityEngine.Object.Destroy(base.gameObject);
			}
		}
	}
	public class SteamJoinClipboardLobby : MonoBehaviour
	{
		public TextMeshProUGUI buttonText;

		public TextMeshProUGUI resultTextComponent;

		public MPButton mpButton;

		private PlatformID clipboardLobbyID;

		private const float resultTextDuration = 4f;

		protected float resultTextTimer;

		private static SteamJoinClipboardLobby instance;

		public bool validClipboardLobbyID { get; private set; }

		private void OnEnable()
		{
			SingletonHelper.Assign(ref instance, this);
		}

		private void OnDisable()
		{
			SingletonHelper.Unassign(ref instance, this);
		}

		[SystemInitializer(new Type[] { })]
		public static void Init()
		{
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyJoined = (Action<bool>)Delegate.Combine(lobbyManager.onLobbyJoined, new Action<bool>(OnLobbyJoined));
		}

		private static void OnLobbyJoined(bool success)
		{
			if ((bool)instance && (bool)instance.resultTextComponent)
			{
				instance.resultTextTimer = 4f;
				instance.resultTextComponent.enabled = true;
				instance.resultTextComponent.SetText(Language.GetString(success ? "STEAM_JOIN_LOBBY_CLIPBOARD_SUCCESS" : "STEAM_JOIN_LOBBY_CLIPBOARD_FAIL"));
			}
		}

		private static bool IsLobbyIdValid(PlatformID lobbyId)
		{
			return lobbyId != PlatformID.nil;
		}

		private static PlatformID FetchClipboardLobbyId()
		{
			if (PlatformSystems.EgsToggleConVar.value == 1)
			{
				return FetchClipboardLobbyIdEGS();
			}
			return FetchClipboardLobbyIdSTEAM();
		}

		private static PlatformID FetchClipboardLobbyIdSTEAM()
		{
			if (PlatformID.TryParse(GUIUtility.systemCopyBuffer, out var result))
			{
				PlatformID platformID = new PlatformID(Client.Instance?.Lobby.CurrentLobby ?? PlatformID.nil.ID);
				if (result.isLobby && platformID != result)
				{
					return result;
				}
			}
			return PlatformID.nil;
		}

		private static PlatformID FetchClipboardLobbyIdEGS()
		{
			string systemCopyBuffer = GUIUtility.systemCopyBuffer;
			if ((PlatformSystems.lobbyManager as EOSLobbyManager).CurrentLobbyId != systemCopyBuffer && systemCopyBuffer != string.Empty)
			{
				return new PlatformID(systemCopyBuffer);
			}
			return PlatformID.nil;
		}

		private void OnApplicationFocus(bool hasFocus)
		{
			if (!hasFocus)
			{
				return;
			}
			clipboardLobbyID = FetchClipboardLobbyId();
			validClipboardLobbyID = IsLobbyIdValid(clipboardLobbyID);
			if (mpButton != null)
			{
				mpButton.interactable = validClipboardLobbyID;
			}
			if (resultTextComponent != null)
			{
				if (resultTextTimer > 0f)
				{
					resultTextTimer -= Time.fixedDeltaTime;
					resultTextComponent.enabled = true;
				}
				else
				{
					resultTextComponent.enabled = false;
				}
			}
		}

		public void TryToJoinClipboardLobby()
		{
			clipboardLobbyID = FetchClipboardLobbyId();
			Console.instance.SubmitCmd(null, string.Format(CultureInfo.InvariantCulture, "steam_lobby_join {0}", clipboardLobbyID.ToString()), recordSubmit: true);
		}
	}
	public class SteamLobbyOwnerFilter : MonoBehaviour
	{
		public Button[] buttonsToFilter;

		public GameObject[] objectsToFilter;

		private bool wasOn;

		private void Start()
		{
			Refresh(forceRefresh: true);
		}

		private void Update()
		{
			Refresh();
		}

		private void Refresh(bool forceRefresh = false)
		{
			bool ownsLobby = PlatformSystems.lobbyManager.ownsLobby;
			if (ownsLobby != wasOn || forceRefresh)
			{
				for (int i = 0; i < objectsToFilter.Length; i++)
				{
					objectsToFilter[i].SetActive(ownsLobby);
				}
				for (int j = 0; j < buttonsToFilter.Length; j++)
				{
					buttonsToFilter[j].interactable = ownsLobby;
				}
			}
			wasOn = ownsLobby;
		}
	}
	[RequireComponent(typeof(LanguageTextMeshController))]
	public class SteamLobbyStatusText : MonoBehaviour
	{
		private LanguageTextMeshController languageTextMeshController;

		private void Start()
		{
			languageTextMeshController = GetComponent<LanguageTextMeshController>();
		}

		private void Update()
		{
			LobbyType currentLobbyType = PlatformSystems.lobbyManager.currentLobbyType;
			if (currentLobbyType == LobbyType.Error)
			{
				return;
			}
			for (int i = 0; i < LobbyUserList.lobbyStateChoices.Length; i++)
			{
				if (currentLobbyType == LobbyUserList.lobbyStateChoices[i].lobbyType)
				{
					languageTextMeshController.token = LobbyUserList.lobbyStateChoices[i].token;
					break;
				}
			}
		}
	}
	public class SteamUsernameLabel : SocialUsernameLabel
	{
	}
	[RequireComponent(typeof(TMP_InputField))]
	public class SubmitInputFieldOnEnterKey : MonoBehaviour
	{
		private TMP_InputField inputField;

		private void Awake()
		{
			inputField = GetComponent<TMP_InputField>();
		}

		private void Update()
		{
			if (inputField.isFocused && inputField.text != "")
			{
				Input.GetKeyDown(KeyCode.Return);
			}
		}
	}
	[RequireComponent(typeof(HGButton))]
	public class SurvivorIconController : MonoBehaviour
	{
		public EclipseRunScreenController eclipseRunScreenController;

		private SurvivorIndex _survivorIndex = SurvivorIndex.None;

		private SurvivorDef _survivorDef;

		private BodyIndex survivorBodyIndex = BodyIndex.None;

		private CharacterBody survivorBodyPrefabBodyComponent;

		private bool survivorIsUnlocked;

		private bool survivorRequiredExpansionEnabled;

		private bool survivorRequiredEntitlementAvailable;

		private bool shouldRebuild = true;

		private bool isCurrentChoice;

		public RawImage survivorIcon;

		public GameObject survivorIsSelectedEffect;

		public ViewableTag viewableTag;

		public ViewableTag loadoutViewableTag;

		public ViewableTrigger viewableTrigger;

		public TooltipProvider tooltipProvider;

		public CharacterSelectBarController characterSelectBarController { get; set; }

		public SurvivorIndex survivorIndex
		{
			get
			{
				return _survivorIndex;
			}
			set
			{
				survivorDef = SurvivorCatalog.GetSurvivorDef(value);
			}
		}

		public SurvivorDef survivorDef
		{
			get
			{
				return _survivorDef;
			}
			set
			{
				if ((object)_survivorDef != value)
				{
					_survivorDef = value;
					_survivorIndex = (_survivorDef ? _survivorDef.survivorIndex : SurvivorIndex.None);
					survivorBodyIndex = (_survivorDef ? BodyCatalog.FindBodyIndex(_survivorDef.bodyPrefab) : BodyIndex.None);
					survivorBodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(survivorBodyIndex);
					shouldRebuild = true;
					UpdateAvailability();
				}
			}
		}

		public bool survivorIsAvailable { get; private set; }

		public HGButton hgButton { get; private set; }

		private void Awake()
		{
			hgButton = GetComponent<HGButton>();
		}

		private void Update()
		{
			isCurrentChoice = (object)characterSelectBarController.pickedIcon == this;
			UpdateAvailability();
			if (shouldRebuild)
			{
				shouldRebuild = false;
				Rebuild();
			}
			hgButton.interactable = true;
			survivorIsSelectedEffect.SetActive(isCurrentChoice);
		}

		private LocalUser GetLocalUser()
		{
			return ((MPEventSystem)EventSystem.current).localUser;
		}

		private void SetBoolAndMarkDirtyIfChanged(ref bool oldValue, bool newValue)
		{
			if (oldValue != newValue)
			{
				oldValue = newValue;
				shouldRebuild = true;
			}
		}

		private void UpdateAvailability()
		{
			SetBoolAndMarkDirtyIfChanged(ref survivorIsUnlocked, SurvivorCatalog.SurvivorIsUnlockedOnThisClient(survivorIndex));
			SetBoolAndMarkDirtyIfChanged(ref survivorRequiredEntitlementAvailable, survivorDef.CheckUserHasRequiredEntitlement(GetLocalUser()));
			SetBoolAndMarkDirtyIfChanged(ref survivorRequiredExpansionEnabled, survivorDef.CheckRequiredExpansionEnabled());
			survivorRequiredExpansionEnabled = survivorRequiredExpansionEnabled || ExpansionRequirementComponent.ignoreExpansionDisablingForPlayerControlled;
			survivorIsAvailable = survivorIsUnlocked && survivorRequiredExpansionEnabled && survivorRequiredEntitlementAvailable;
		}

		private void Rebuild()
		{
			string viewableName = "";
			string viewableName2 = "";
			Texture texture = null;
			string text = "";
			UnityEngine.Color titleColor = UnityEngine.Color.clear;
			string overrideBodyText = "";
			if (survivorDef != null)
			{
				UnlockableDef unlockableDef = survivorDef.unlockableDef;
				if ((bool)survivorBodyPrefabBodyComponent)
				{
					texture = survivorBodyPrefabBodyComponent.portraitIcon;
					viewableName = string.Format(CultureInfo.InvariantCulture, "/Survivors/{0}", survivorDef.cachedName);
					viewableName2 = string.Format(CultureInfo.InvariantCulture, "/Loadout/Bodies/{0}/", BodyCatalog.GetBodyName(survivorBodyPrefabBodyComponent.bodyIndex));
					if (!survivorIsAvailable)
					{
						text = "UNIDENTIFIED";
						titleColor = UnityEngine.Color.gray;
						if (!survivorRequiredEntitlementAvailable)
						{
							overrideBodyText = Language.GetStringFormatted("EXPANSION_PURCHASED_REQUIRED_FORMAT", Language.GetString(survivorDef.GetRequiredEntitlement().nameToken));
						}
						else if (!survivorRequiredExpansionEnabled)
						{
							overrideBodyText = Language.GetStringFormatted("EXPANSION_ENABLED_REQUIRED_FORMAT", Language.GetString(survivorDef.GetRequiredExpansion().nameToken));
						}
						else if (!survivorIsUnlocked && (bool)unlockableDef)
						{
							overrideBodyText = unlockableDef.getHowToUnlockString();
						}
					}
				}
			}
			if ((bool)survivorIcon)
			{
				survivorIcon.texture = texture;
				survivorIcon.color = (survivorIsAvailable ? UnityEngine.Color.white : UnityEngine.Color.black);
			}
			if ((bool)viewableTag)
			{
				viewableTag.viewableName = viewableName;
				viewableTag.Refresh();
			}
			if ((bool)loadoutViewableTag)
			{
				loadoutViewableTag.viewableName = viewableName2;
				loadoutViewableTag.Refresh();
			}
			if ((bool)viewableTrigger)
			{
				viewableTrigger.viewableName = viewableName;
			}
			if ((bool)tooltipProvider)
			{
				tooltipProvider.enabled = text != "";
				tooltipProvider.titleToken = text;
				tooltipProvider.titleColor = titleColor;
				tooltipProvider.overrideBodyText = overrideBodyText;
			}
			hgButton.disableGamepadClick = !survivorIsAvailable;
			hgButton.disablePointerClick = !survivorIsAvailable;
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class TimerText : MonoBehaviour
	{
		[FormerlySerializedAs("targetText")]
		public TextMeshProUGUI targetLabel;

		[SerializeField]
		private TimerStringFormatter _format;

		[SerializeField]
		private double _seconds;

		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		private int currentMinutes = -1;

		private int currentSeconds = -1;

		public TimerStringFormatter format
		{
			get
			{
				return _format;
			}
			set
			{
				if (!(_format == value))
				{
					_format = value;
					Rebuild();
				}
			}
		}

		public double seconds
		{
			get
			{
				return _seconds;
			}
			set
			{
				if (_seconds != value)
				{
					_seconds = value;
					Rebuild();
				}
			}
		}

		private void Awake()
		{
			Rebuild();
		}

		private void Rebuild()
		{
			if ((bool)targetLabel)
			{
				sharedStringBuilder.Clear();
				if ((bool)format)
				{
					format.AppendToStringBuilder(seconds, sharedStringBuilder);
				}
				targetLabel.SetText(sharedStringBuilder);
			}
		}

		private void OnValidate()
		{
			Rebuild();
			if (!targetLabel)
			{
				UnityEngine.Debug.LogErrorFormat(this, "TimerText does not specify a target label.");
			}
		}
	}
	public class TooltipController : MonoBehaviour
	{
		private static readonly List<TooltipController> instancesList = new List<TooltipController>();

		[NonSerialized]
		public MPEventSystem owner;

		private bool _isGamepadTooltip;

		private UnityEngine.Vector2 _gamepadTooltipPosition;

		public RectTransform tooltipCenterTransform;

		public RectTransform tooltipFlipTransform;

		public UnityEngine.UI.Image colorHighlightImage;

		public TextMeshProUGUI titleLabel;

		public TextMeshProUGUI bodyLabel;

		public Transform extraUIPos;

		private UICamera uiCamera;

		private void SetTooltipProvider(TooltipProvider provider)
		{
			titleLabel.text = provider.titleText;
			titleLabel.richText = !provider.disableTitleRichText;
			bodyLabel.text = provider.bodyText;
			bodyLabel.richText = !provider.disableBodyRichText;
			colorHighlightImage.color = provider.titleColor;
			if (provider.extraUIDisplayPrefab != null)
			{
				UnityEngine.Object.Instantiate(provider.extraUIDisplayPrefab, extraUIPos).transform.SetSiblingIndex(bodyLabel.transform.parent.GetSiblingIndex() + 1);
			}
		}

		private static UICamera FindUICamera(MPEventSystem mpEventSystem)
		{
			foreach (UICamera readOnlyInstances in UICamera.readOnlyInstancesList)
			{
				if (readOnlyInstances.GetAssociatedEventSystem() as MPEventSystem == mpEventSystem)
				{
					return readOnlyInstances;
				}
			}
			return null;
		}

		private void Awake()
		{
			instancesList.Add(this);
		}

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

		private void LateUpdate()
		{
			if ((bool)owner)
			{
				UnityEngine.Vector2 position;
				if (_isGamepadTooltip)
				{
					tooltipCenterTransform.position = _gamepadTooltipPosition;
				}
				else if (owner.GetCursorPosition(out position))
				{
					tooltipCenterTransform.position = position;
				}
			}
		}

		public static void RemoveTooltip(TooltipProvider tooltipProvider)
		{
			if (tooltipProvider.userCount <= 0)
			{
				return;
			}
			foreach (MPEventSystem readOnlyInstances in MPEventSystem.readOnlyInstancesList)
			{
				RemoveTooltip(readOnlyInstances, tooltipProvider);
			}
		}

		public static void RemoveTooltip(MPEventSystem eventSystem, TooltipProvider tooltipProvider)
		{
			if (eventSystem.currentTooltipProvider == tooltipProvider)
			{
				SetTooltip(eventSystem, null, UnityEngine.Vector3.zero);
			}
		}

		public static void SetTooltip(MPEventSystem eventSystem, TooltipProvider newTooltipProvider, UnityEngine.Vector2 tooltipPosition, RectTransform rectTransformToDisplayAt = null)
		{
			if (eventSystem.currentTooltipProvider != newTooltipProvider)
			{
				if ((bool)eventSystem.currentTooltip)
				{
					UnityEngine.Object.Destroy(eventSystem.currentTooltip.gameObject);
					eventSystem.currentTooltip = null;
				}
				if ((bool)eventSystem.currentTooltipProvider)
				{
					eventSystem.currentTooltipProvider.userCount--;
				}
				eventSystem.currentTooltipProvider = newTooltipProvider;
				if ((bool)newTooltipProvider && (!string.IsNullOrEmpty(newTooltipProvider.titleText) || !string.IsNullOrEmpty(newTooltipProvider.bodyText)))
				{
					newTooltipProvider.userCount++;
					GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Tooltip"));
					eventSystem.currentTooltip = gameObject.GetComponent<TooltipController>();
					eventSystem.currentTooltip.owner = eventSystem;
					eventSystem.currentTooltip.uiCamera = FindUICamera(eventSystem);
					eventSystem.currentTooltip.SetTooltipProvider(eventSystem.currentTooltipProvider);
					gameObject.GetComponent<Canvas>().worldCamera = eventSystem.currentTooltip.uiCamera?.camera;
				}
			}
			if (!eventSystem.currentTooltip)
			{
				return;
			}
			UnityEngine.Vector2 vector = UnityEngine.Vector2.zero;
			UICamera uICamera = eventSystem.currentTooltip.uiCamera;
			Camera camera = Camera.main;
			if ((bool)uICamera)
			{
				camera = uICamera.camera;
			}
			if ((bool)camera)
			{
				UnityEngine.Vector2 gamepadTooltipPosition = tooltipPosition;
				if (rectTransformToDisplayAt != null)
				{
					Camera worldCamera = rectTransformToDisplayAt.gameObject.GetComponentInParent<Canvas>().worldCamera;
					UnityEngine.Vector3 position = rectTransformToDisplayAt.TransformPoint(rectTransformToDisplayAt.rect.center);
					gamepadTooltipPosition = worldCamera.WorldToScreenPoint(position);
					eventSystem.currentTooltip._gamepadTooltipPosition = gamepadTooltipPosition;
				}
				UnityEngine.Vector3 vector2 = camera.ScreenToViewportPoint(new UnityEngine.Vector3(gamepadTooltipPosition.x, gamepadTooltipPosition.y, 0f));
				vector = new UnityEngine.Vector2(vector2.x, vector2.y);
			}
			UnityEngine.Vector2 vector3 = new UnityEngine.Vector2(0f, 0f);
			vector3.x = ((vector.x > 0.5f) ? 1f : 0f);
			vector3.y = ((vector.y > 0.5f) ? 1f : 0f);
			eventSystem.currentTooltip.tooltipFlipTransform.anchorMin = vector3;
			eventSystem.currentTooltip.tooltipFlipTransform.anchorMax = vector3;
			eventSystem.currentTooltip.tooltipFlipTransform.pivot = vector3;
			eventSystem.currentTooltip._isGamepadTooltip = rectTransformToDisplayAt != null;
		}
	}
	[Serializable]
	public struct TooltipContent : IEquatable<TooltipContent>
	{
		public string titleToken;

		public string overrideTitleText;

		public UnityEngine.Color titleColor;

		public string bodyToken;

		public string overrideBodyText;

		public UnityEngine.Color bodyColor;

		public bool disableTitleRichText;

		public bool disableBodyRichText;

		public bool Equals(TooltipContent other)
		{
			if (string.Equals(titleToken, other.titleToken) && string.Equals(overrideTitleText, other.overrideTitleText) && titleColor.Equals(other.titleColor) && string.Equals(bodyToken, other.bodyToken) && string.Equals(overrideBodyText, other.overrideBodyText) && bodyColor.Equals(other.bodyColor) && disableTitleRichText == other.disableTitleRichText)
			{
				return disableBodyRichText == other.disableBodyRichText;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj == null)
			{
				return false;
			}
			if (obj is TooltipContent other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((((((((((((((titleToken != null) ? titleToken.GetHashCode() : 0) * 397) ^ ((overrideTitleText != null) ? overrideTitleText.GetHashCode() : 0)) * 397) ^ titleColor.GetHashCode()) * 397) ^ ((bodyToken != null) ? bodyToken.GetHashCode() : 0)) * 397) ^ ((overrideBodyText != null) ? overrideBodyText.GetHashCode() : 0)) * 397) ^ bodyColor.GetHashCode()) * 397) ^ disableTitleRichText.GetHashCode()) * 397) ^ disableBodyRichText.GetHashCode();
		}

		public static bool operator ==(TooltipContent left, TooltipContent right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(TooltipContent left, TooltipContent right)
		{
			return !left.Equals(right);
		}

		[NotNull]
		public string GetTitleText()
		{
			if (!string.IsNullOrEmpty(overrideTitleText))
			{
				return overrideTitleText;
			}
			if (!string.IsNullOrEmpty(titleToken))
			{
				return Language.GetString(titleToken);
			}
			return string.Empty;
		}

		[NotNull]
		public string GetBodyText()
		{
			if (!string.IsNullOrEmpty(overrideBodyText))
			{
				return overrideBodyText;
			}
			if (!string.IsNullOrEmpty(bodyToken))
			{
				return Language.GetString(bodyToken);
			}
			return string.Empty;
		}
	}
	[Flags]
	public enum RequiredInspectStateForNavigationTooltip
	{
		InspectOff = 1,
		InspectOn = 2
	}
	public class TooltipProvider : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, ISelectHandler, IDeselectHandler
	{
		public string titleToken = "";

		public UnityEngine.Color titleColor = UnityEngine.Color.clear;

		public string bodyToken = "";

		public UnityEngine.Color bodyColor;

		public GameObject extraUIDisplayPrefab;

		public bool AllowTooltipOnNavigationSelect;

		public RequiredInspectStateForNavigationTooltip RequiredInspectStateForNavigationTooltip = RequiredInspectStateForNavigationTooltip.InspectOff | RequiredInspectStateForNavigationTooltip.InspectOn;

		public string overrideTitleText = "";

		public string overrideBodyText = "";

		public bool disableTitleRichText;

		public bool disableBodyRichText;

		[NonSerialized]
		public int userCount;

		private static readonly UnityEngine.Color playerColor = new Color32(242, 65, 65, byte.MaxValue);

		private bool tooltipIsAvailable => titleColor != UnityEngine.Color.clear;

		public string titleText
		{
			get
			{
				if (!string.IsNullOrEmpty(overrideTitleText))
				{
					return overrideTitleText;
				}
				if (titleToken == null)
				{
					return null;
				}
				return Language.GetString(titleToken);
			}
		}

		public string bodyText
		{
			get
			{
				if (!string.IsNullOrEmpty(overrideBodyText))
				{
					return overrideBodyText;
				}
				if (bodyToken == null)
				{
					return null;
				}
				return Language.GetString(bodyToken);
			}
		}

		private bool InspectState => ((EventSystem.current as MPEventSystem)?.localUser?.userProfile?.useInspectFeature).GetValueOrDefault();

		private bool CanShowNavigationTooltip
		{
			get
			{
				if ((RequiredInspectStateForNavigationTooltip & RequiredInspectStateForNavigationTooltip.InspectOn) > (RequiredInspectStateForNavigationTooltip)0 && InspectState)
				{
					return true;
				}
				if ((RequiredInspectStateForNavigationTooltip & RequiredInspectStateForNavigationTooltip.InspectOff) > (RequiredInspectStateForNavigationTooltip)0 && !InspectState)
				{
					return true;
				}
				return false;
			}
		}

		public void SetContent(TooltipContent tooltipContent)
		{
			titleToken = tooltipContent.titleToken;
			overrideTitleText = tooltipContent.overrideTitleText;
			titleColor = tooltipContent.titleColor;
			bodyToken = tooltipContent.bodyToken;
			overrideBodyText = tooltipContent.overrideBodyText;
			bodyColor = tooltipContent.bodyColor;
			disableTitleRichText = tooltipContent.disableTitleRichText;
			disableBodyRichText = tooltipContent.disableBodyRichText;
		}

		private void OnDisable()
		{
			TooltipController.RemoveTooltip(this);
		}

		void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
		{
			MPEventSystem mPEventSystem = EventSystem.current as MPEventSystem;
			if (mPEventSystem != null && tooltipIsAvailable)
			{
				TooltipController.SetTooltip(mPEventSystem, this, eventData.position);
			}
		}

		void IPointerExitHandler.OnPointerExit(PointerEventData eventData)
		{
			MPEventSystem mPEventSystem = EventSystem.current as MPEventSystem;
			if (mPEventSystem != null && tooltipIsAvailable)
			{
				TooltipController.RemoveTooltip(mPEventSystem, this);
			}
		}

		public void OnSelect(BaseEventData eventData)
		{
			MPEventSystem mPEventSystem = EventSystem.current as MPEventSystem;
			if (AllowTooltipOnNavigationSelect && CanShowNavigationTooltip && mPEventSystem != null && tooltipIsAvailable)
			{
				RectTransform rectTransform = base.transform as RectTransform;
				TooltipController.SetTooltip(mPEventSystem, this, rectTransform.position, rectTransform);
			}
		}

		public void OnDeselect(BaseEventData eventData)
		{
			MPEventSystem mPEventSystem = EventSystem.current as MPEventSystem;
			if (AllowTooltipOnNavigationSelect && CanShowNavigationTooltip && mPEventSystem != null && tooltipIsAvailable)
			{
				TooltipController.RemoveTooltip(mPEventSystem, this);
			}
		}

		public static TooltipContent GetPlayerNameTooltipContent(string userName)
		{
			string stringFormatted = Language.GetStringFormatted("PLAYER_NAME_TOOLTIP_FORMAT", userName);
			TooltipContent result = default(TooltipContent);
			result.overrideTitleText = stringFormatted;
			result.disableTitleRichText = true;
			result.titleColor = playerColor;
			return result;
		}
	}
	[ExecuteAlways]
	public class TypewriteTextController : MonoBehaviour
	{
		[Serializable]
		private struct TimedTextChunk
		{
			public TextMeshProUGUI label;

			public int startCharIndex;

			public int endCharIndex;

			public float startTime;

			public float duration;

			public float interval;
		}

		[UnityEngine.Min(0f)]
		[Tooltip("How long to delay before beginning to reveal characters. 0 is no delay.")]
		public float initialDelay;

		[Tooltip("How long to delay between individual characters. 0 is no delay.")]
		[UnityEngine.Min(0f)]
		public float delayBetweenKeys = 0.1f;

		[Tooltip("How long to delay between sentences. 0 is no delay.")]
		[UnityEngine.Min(0f)]
		public float delayBetweenSentences;

		[Tooltip("How long to delay between line breaks.")]
		[UnityEngine.Min(0f)]
		public float delayBetweenNewLines;

		[UnityEngine.Min(0f)]
		[Tooltip("How long to delay between labels. 0 is no delay.")]
		public float delayBetweenTexts = 1f;

		[FormerlySerializedAs("textMeshProUGui")]
		[Tooltip("The labels to control.")]
		public TextMeshProUGUI[] labels;

		[Tooltip("The sound to play for each character typed.")]
		public string soundString;

		[Tooltip("Whether or not to fade out the label once typing is finished.")]
		public bool fadeOutAfterCompletion;

		[Tooltip("How long to wait after typing is finished to begin fading out.")]
		[UnityEngine.Min(0f)]
		public float fadeOutDelay;

		[Tooltip("How long it takes to fade out once fading begins.")]
		[UnityEngine.Min(0f)]
		public float fadeOutDuration;

		[Tooltip("The current simulation time of this object. You'll probably want to make sure this is set to zero when saving if you preview the animation in-editor.")]
		[UnityEngine.Min(0f)]
		public float stopwatch;

		[Tooltip("Whether or not to disable the attached GameObject when fading is complete.")]
		public bool disableObjectOnFadeEnd = true;

		[Tooltip("Whether or not to start playing the animation immediately.")]
		public bool playOnStart = true;

		[Tooltip("How long (in seconds) it should take to complete this animation if nonzero. Mainly useful for achieving consistent timings with different languages.")]
		public float timeToFit;

		[Tooltip("Whether or not timeToFit includes fade values.")]
		public bool includeFadeoutInTimeToFit;

		[Tooltip("Event called when typing has finished.")]
		public UnityEvent onFinishTyping;

		[Tooltip("Event called when fadeout has begun. Note that this is distinctly different from the finish typing timing as we can have a delay before begin fade.")]
		public UnityEvent onBeginFade;

		[Tooltip("Event called when fadeout has finished.")]
		public UnityEvent onFinishFade;

		private TimedTextChunk[] textChunks = Array.Empty<TimedTextChunk>();

		private float totalTypingDuration;

		private float totalFadingDuration;

		private float typingTimeScale;

		private float fadingTimeScale;

		private int totalCharacterCount;

		private int totalRevealedCharacterCount;

		private bool isPlayingAnimation;

		private bool isDoneTyping;

		private bool isFadeStarted;

		private bool isDoneFading;

		private bool isEnginePlaying;

		private static readonly char[] sentenceTerminators = new char[4] { '.', '?', '!', '。' };

		private static readonly List<TimedTextChunk> sharedChunkBuilder = new List<TimedTextChunk>();

		private static TMP_Asset bombadierTextAsset;

		private void Start()
		{
			isEnginePlaying = Application.IsPlaying(this);
			if (isEnginePlaying && playOnStart)
			{
				StartTyping();
			}
		}

		private void Update()
		{
			float num = Time.deltaTime;
			if (!isEnginePlaying)
			{
				num = Time.unscaledDeltaTime;
			}
			if (isPlayingAnimation)
			{
				stopwatch += num;
			}
			SetTime(stopwatch);
		}

		private static bool IsEndOfSentence(TMP_TextInfo textInfo, in TMP_CharacterInfo characterInfo)
		{
			char character = characterInfo.character;
			if (Array.IndexOf(sentenceTerminators, character) != -1)
			{
				if (character == '.' && characterInfo.index + 1 < textInfo.characterCount)
				{
					char character2 = textInfo.characterInfo[characterInfo.index + 1].character;
					if (!char.IsLetter(character2))
					{
						char.IsWhiteSpace(character2);
					}
					return true;
				}
				return true;
			}
			return false;
		}

		private void GenerateTimingInfo()
		{
			UpdateAllLabelTextInfo();
			TimedTextChunk currentTimedTextChunk = default(TimedTextChunk);
			bool flag = delayBetweenSentences > 0f;
			bool flag2 = delayBetweenTexts > 0f;
			bool flag3 = delayBetweenNewLines > 0f;
			totalCharacterCount = 0;
			for (int i = 0; i < labels.Length; i++)
			{
				TextMeshProUGUI textMeshProUGUI = labels[i];
				if (!textMeshProUGUI)
				{
					continue;
				}
				TMP_TextInfo textInfo = textMeshProUGUI.textInfo;
				StartNewChunk(textMeshProUGUI, delayBetweenKeys);
				totalCharacterCount += textInfo.characterCount;
				if (flag2 && i > 0)
				{
					currentTimedTextChunk.duration = delayBetweenTexts;
					StartNewChunk(textMeshProUGUI, delayBetweenKeys);
				}
				else if (i == 0)
				{
					currentTimedTextChunk.duration = initialDelay;
					StartNewChunk(textMeshProUGUI, delayBetweenKeys);
				}
				int num = Math.Min(textInfo.characterCount, textInfo.characterInfo.Length);
				while (currentTimedTextChunk.endCharIndex < num)
				{
					ref TMP_CharacterInfo reference = ref textInfo.characterInfo[currentTimedTextChunk.endCharIndex];
					if (flag && IsEndOfSentence(textInfo, in reference))
					{
						StartNewChunk(textMeshProUGUI, delayBetweenSentences);
						currentTimedTextChunk.endCharIndex++;
						StartNewChunk(textMeshProUGUI, delayBetweenKeys);
					}
					else if (flag3 && reference.character == '\n')
					{
						StartNewChunk(textMeshProUGUI, delayBetweenNewLines);
						currentTimedTextChunk.endCharIndex++;
						StartNewChunk(textMeshProUGUI, delayBetweenKeys);
					}
					currentTimedTextChunk.endCharIndex++;
				}
			}
			StartNewChunk(null, 0f);
			textChunks = sharedChunkBuilder.ToArray();
			sharedChunkBuilder.Clear();
			totalTypingDuration = 0f;
			if (textChunks.Length != 0)
			{
				ref TimedTextChunk reference2 = ref textChunks[textChunks.Length - 1];
				totalTypingDuration = reference2.startTime + reference2.duration;
			}
			totalFadingDuration = fadeOutDelay + fadeOutDuration;
			typingTimeScale = 1f;
			fadingTimeScale = 1f;
			if (timeToFit > 0f)
			{
				if (includeFadeoutInTimeToFit)
				{
					fadingTimeScale = (typingTimeScale = (totalTypingDuration + fadeOutDelay + fadeOutDuration) / timeToFit);
				}
				else
				{
					typingTimeScale = totalTypingDuration / timeToFit;
				}
			}
			void StartNewChunk(TextMeshProUGUI label, float interval)
			{
				if (currentTimedTextChunk.endCharIndex != currentTimedTextChunk.startCharIndex)
				{
					currentTimedTextChunk.duration = (float)(currentTimedTextChunk.endCharIndex - currentTimedTextChunk.startCharIndex) * currentTimedTextChunk.interval;
				}
				if (currentTimedTextChunk.duration > 0f)
				{
					sharedChunkBuilder.Add(currentTimedTextChunk);
				}
				float startTime = currentTimedTextChunk.startTime + currentTimedTextChunk.duration;
				int num2 = currentTimedTextChunk.endCharIndex;
				if ((object)label != currentTimedTextChunk.label)
				{
					num2 = 0;
				}
				currentTimedTextChunk = new TimedTextChunk
				{
					label = label,
					startTime = startTime,
					duration = 0f,
					startCharIndex = num2,
					endCharIndex = num2,
					interval = interval
				};
			}
		}

		[ContextMenu("Start preview")]
		public void StartTyping()
		{
			GenerateTimingInfo();
			isPlayingAnimation = true;
			isFadeStarted = false;
			stopwatch = 0f;
			SetTime(stopwatch);
		}

		private void UpdateAllLabelTextInfo()
		{
			for (int i = 0; i < labels.Length; i++)
			{
				TextMeshProUGUI textMeshProUGUI = labels[i];
				if ((bool)textMeshProUGUI)
				{
					textMeshProUGUI.ForceMeshUpdate(ignoreActiveState: true);
				}
			}
		}

		public void SetTime(float t)
		{
			float num = totalTypingDuration / typingTimeScale;
			float typingTime = Mathf.Clamp(t * typingTimeScale, 0f, totalTypingDuration);
			float fadingTime = Mathf.Clamp((t - num) * fadingTimeScale, 0f, totalFadingDuration);
			SetTypingTime(typingTime);
			SetFadingTime(fadingTime);
			if (isDoneTyping && isDoneFading)
			{
				isPlayingAnimation = false;
			}
		}

		private void SetTypingTime(float typingTime)
		{
			bool flag = isDoneTyping;
			isDoneTyping = typingTime >= totalTypingDuration;
			int newTotalRevealedCharacterCount = 0;
			TextMeshProUGUI currentLabel = null;
			int currentLabelRevealedCharacterCount = 0;
			bool isPlaying = isEnginePlaying;
			int i;
			for (i = 0; i < textChunks.Length; i++)
			{
				ref TimedTextChunk reference = ref textChunks[i];
				if (!(reference.startTime <= typingTime))
				{
					break;
				}
				float num = reference.startTime + reference.duration;
				if (typingTime < num)
				{
					float t = Mathf.InverseLerp(reference.startTime, num, typingTime);
					int newRevealedCharacterCount2 = Mathf.CeilToInt(Mathf.Lerp(reference.startCharIndex, reference.endCharIndex, t));
					UpdateCurrentLabel(reference.label, newRevealedCharacterCount2);
					break;
				}
				UpdateCurrentLabel(reference.label, reference.endCharIndex);
			}
			for (i++; i < textChunks.Length; i++)
			{
				ref TimedTextChunk reference2 = ref textChunks[i];
				if ((object)currentLabel != reference2.label)
				{
					UpdateCurrentLabel(reference2.label, 0);
				}
			}
			UpdateCurrentLabel(null, 0);
			if (newTotalRevealedCharacterCount > totalRevealedCharacterCount && soundString.Length > 0 && isEnginePlaying)
			{
				Util.PlaySound(soundString, RoR2Application.instance.gameObject);
			}
			totalRevealedCharacterCount = newTotalRevealedCharacterCount;
			isDoneTyping = totalRevealedCharacterCount >= totalCharacterCount;
			if (!flag && isDoneTyping && isEnginePlaying)
			{
				onFinishTyping?.Invoke();
			}
			void UpdateCurrentLabel(TextMeshProUGUI newCurrentLabel, int newRevealedCharacterCount)
			{
				if ((object)currentLabel != newCurrentLabel && (object)currentLabel != null)
				{
					currentLabel.maxVisibleCharacters = currentLabelRevealedCharacterCount;
					if (currentLabelRevealedCharacterCount == 0)
					{
						if (currentLabel.enabled && isPlaying)
						{
							currentLabel.enabled = false;
						}
					}
					else
					{
						if (!currentLabel.enabled)
						{
							currentLabel.enabled = true;
						}
						newTotalRevealedCharacterCount += currentLabelRevealedCharacterCount;
					}
				}
				currentLabel = newCurrentLabel;
				currentLabelRevealedCharacterCount = newRevealedCharacterCount;
			}
		}

		private void SetFadingTime(float fadingTime)
		{
			bool flag = isDoneFading;
			isDoneFading = fadingTime >= totalFadingDuration;
			if (!fadeOutAfterCompletion)
			{
				return;
			}
			float num = 1f;
			float num2 = Mathf.Clamp01((fadingTime - fadeOutDelay) / fadeOutDuration);
			num = 1f - num2;
			if (!isFadeStarted && num2 > 0f)
			{
				isFadeStarted = true;
				onBeginFade?.Invoke();
			}
			SetLabelAlpha(num);
			if (isDoneFading && !flag && isEnginePlaying)
			{
				onFinishFade?.Invoke();
				if (disableObjectOnFadeEnd)
				{
					base.gameObject.SetActive(value: false);
				}
			}
		}

		private void SetLabelAlpha(float alpha)
		{
			for (int i = 0; i < labels.Length; i++)
			{
				TextMeshProUGUI textMeshProUGUI = labels[i];
				if ((bool)textMeshProUGUI)
				{
					UnityEngine.Color color = textMeshProUGUI.color;
					if (!color.a.Equals(alpha))
					{
						color.a = alpha;
						textMeshProUGUI.color = color;
					}
				}
			}
		}

		private bool IsBeingEdited()
		{
			return false;
		}

		private void OnValidate()
		{
			if (IsBeingEdited() && !isPlayingAnimation)
			{
				GenerateTimingInfo();
			}
		}

		public static void PreLoadIntroTextFontAsync()
		{
			AsyncOperationHandle<TMP_Asset> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<TMP_Asset>("f21195c48014a93438e659dcc42b869e");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<TMP_Asset> result)
			{
				if (!(result.Result == null))
				{
					bombadierTextAsset = result.Result;
				}
			};
		}
	}
	public class UIInputPassthrough : MonoBehaviour
	{
		[FormerlySerializedAs("FilterAllButMovement")]
		[SerializeField]
		public bool OnlyAllowMovement = true;
	}
	public class UIJuice : MonoBehaviour
	{
		[Header("Transition Settings")]
		public CanvasGroup canvasGroup;

		public RectTransform panningRect;

		public float transitionDuration;

		public float panningMagnitude;

		public bool destroyOnEndOfTransition;

		public bool disableAndResetOnEndOfTransition;

		private float transitionStopwatch;

		private float transitionEndAlpha;

		private float transitionStartAlpha;

		private float originalAlpha;

		private UnityEngine.Vector2 transitionStartPosition;

		private UnityEngine.Vector2 transitionEndPosition;

		private UnityEngine.Vector2 originalPosition;

		private UnityEngine.Vector2 transitionStartSize;

		private UnityEngine.Vector2 transitionEndSize;

		private UnityEngine.Vector3 originalSize;

		private bool wasTransition;

		private bool hasInitialized;

		private void Awake()
		{
			InitializeFirstTimeInfo();
		}

		private void Update()
		{
			transitionStopwatch = Mathf.Min(transitionStopwatch + Time.unscaledDeltaTime, transitionDuration);
			ProcessTransition();
		}

		private void ProcessTransition()
		{
			InitializeFirstTimeInfo();
			bool flag = transitionStopwatch < transitionDuration;
			if (flag || flag != wasTransition)
			{
				if (flag)
				{
					AnimationCurve animationCurve = AnimationCurve.EaseInOut(0f, transitionStartAlpha, 1f, transitionEndAlpha);
					if ((bool)canvasGroup)
					{
						canvasGroup.alpha = animationCurve.Evaluate(transitionStopwatch / transitionDuration);
					}
					AnimationCurve animationCurve2 = new AnimationCurve();
					Keyframe key = new Keyframe(0f, 0f, 3f, 3f);
					Keyframe key2 = new Keyframe(1f, 1f, 0f, 0f);
					animationCurve2.AddKey(key);
					animationCurve2.AddKey(key2);
					UnityEngine.Vector2 anchoredPosition = UnityEngine.Vector2.Lerp(transitionStartPosition, transitionEndPosition, animationCurve2.Evaluate(transitionStopwatch / transitionDuration));
					UnityEngine.Vector2 sizeDelta = UnityEngine.Vector2.Lerp(transitionStartSize, transitionEndSize, animationCurve2.Evaluate(transitionStopwatch / transitionDuration));
					if ((bool)panningRect)
					{
						panningRect.anchoredPosition = anchoredPosition;
						panningRect.sizeDelta = sizeDelta;
					}
				}
				else
				{
					if ((bool)canvasGroup)
					{
						canvasGroup.alpha = transitionEndAlpha;
					}
					if ((bool)panningRect)
					{
						panningRect.anchoredPosition = transitionEndPosition;
						panningRect.sizeDelta = transitionEndSize;
					}
					if (destroyOnEndOfTransition)
					{
						UnityEngine.Object.Destroy(base.gameObject);
					}
					else if (disableAndResetOnEndOfTransition)
					{
						InitializeFirstTimeInfo();
						transitionStopwatch = 0f;
						base.gameObject.SetActive(value: false);
					}
				}
			}
			wasTransition = flag;
		}

		public void TransitionScaleUpWidth()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartSize = new UnityEngine.Vector2(0f, transitionEndSize.y * 0.8f);
				transitionEndSize = originalSize;
			}
			BeginTransition();
		}

		public void TransitionPanFromLeft()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = new UnityEngine.Vector2(-1f, 0f) * panningMagnitude;
				transitionEndPosition = originalPosition;
			}
			BeginTransition();
		}

		public void TransitionPanToLeft()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = originalPosition;
				transitionEndPosition = new UnityEngine.Vector2(-1f, 0f) * panningMagnitude;
			}
			BeginTransition();
		}

		public void TransitionPanFromRight()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = new UnityEngine.Vector2(1f, 0f) * panningMagnitude;
				transitionEndPosition = originalPosition;
			}
			BeginTransition();
		}

		public void TransitionPanToRight()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = originalPosition;
				transitionEndPosition = new UnityEngine.Vector2(1f, 0f) * panningMagnitude;
			}
			BeginTransition();
		}

		public void TransitionPanFromTop()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = new UnityEngine.Vector2(0f, 1f) * panningMagnitude;
				transitionEndPosition = originalPosition;
			}
			BeginTransition();
		}

		public void TransitionPanToTop()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = originalPosition;
				transitionEndPosition = new UnityEngine.Vector2(0f, 1f) * panningMagnitude;
			}
			BeginTransition();
		}

		public void TransitionPanFromBottom()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = new UnityEngine.Vector2(0f, -1f) * panningMagnitude;
				transitionEndPosition = originalPosition;
			}
			BeginTransition();
		}

		public void TransitionPanToBottom()
		{
			InitializeFirstTimeInfo();
			if ((bool)panningRect)
			{
				transitionStartPosition = originalPosition;
				transitionEndPosition = new UnityEngine.Vector2(0f, -1f) * panningMagnitude;
			}
			BeginTransition();
		}

		public void TransitionAlphaFadeIn()
		{
			InitializeFirstTimeInfo();
			transitionStartAlpha = 0f;
			transitionEndAlpha = originalAlpha;
			BeginTransition();
		}

		public void TransitionAlphaFadeOut()
		{
			InitializeFirstTimeInfo();
			transitionStartAlpha = originalAlpha;
			transitionEndAlpha = 0f;
			BeginTransition();
		}

		public void DestroyOnEndOfTransition(bool set)
		{
			destroyOnEndOfTransition = set;
		}

		public void DisableAndResetOnEndOfTransition(bool set)
		{
			disableAndResetOnEndOfTransition = set;
		}

		private void BeginTransition()
		{
			transitionStopwatch = 0f;
			ProcessTransition();
		}

		private void InitializeFirstTimeInfo()
		{
			if (!hasInitialized)
			{
				if ((bool)panningRect)
				{
					originalPosition = panningRect.anchoredPosition;
					originalSize = panningRect.sizeDelta;
				}
				if ((bool)canvasGroup)
				{
					originalAlpha = canvasGroup.alpha;
					transitionEndAlpha = originalAlpha;
					transitionStartAlpha = originalAlpha;
				}
				hasInitialized = true;
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class UILayerKey : MonoBehaviour, IUILayerKeyProvider
	{
		public UILayer layer;

		public UnityEvent onBeginRepresentTopLayer;

		public UnityEvent onEndRepresentTopLayer;

		private MPEventSystemLocator eventSystemLocator;

		private MPEventSystem _eventSystem;

		private static readonly Dictionary<MPEventSystem, UILayerKey> topLayerRepresentations = new Dictionary<MPEventSystem, UILayerKey>();

		public bool representsTopLayer { get; private set; }

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			_eventSystem = eventSystemLocator.eventSystem;
		}

		private void Start()
		{
		}

		private void OnEnable()
		{
			InstanceTracker.Add(this);
			if ((bool)_eventSystem)
			{
				RefreshTopLayerForEventSystem(_eventSystem);
			}
		}

		private void OnDisable()
		{
			InstanceTracker.Remove(this);
			if ((bool)_eventSystem)
			{
				RefreshTopLayerForEventSystem(_eventSystem);
			}
		}

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			MPEventSystemManager.availability.CallWhenAvailable(delegate
			{
				ReadOnlyCollection<MPEventSystem> readOnlyInstancesList = MPEventSystem.readOnlyInstancesList;
				for (int i = 0; i < readOnlyInstancesList.Count; i++)
				{
					topLayerRepresentations[readOnlyInstancesList[i]] = null;
				}
			});
			RoR2Application.onLateUpdate += StaticLateUpdate;
		}

		private static void StaticLateUpdate()
		{
			ReadOnlyCollection<MPEventSystem> readOnlyInstancesList = MPEventSystem.readOnlyInstancesList;
			for (int i = 0; i < readOnlyInstancesList.Count; i++)
			{
				RefreshTopLayerForEventSystem(readOnlyInstancesList[i]);
			}
		}

		private static void RefreshTopLayerForEventSystem(MPEventSystem eventSystem)
		{
			int num = int.MinValue;
			UILayerKey uILayerKey = null;
			if (!topLayerRepresentations.ContainsKey(eventSystem))
			{
				return;
			}
			UILayerKey uILayerKey2 = topLayerRepresentations[eventSystem];
			List<UILayerKey> instancesList = InstanceTracker.GetInstancesList<UILayerKey>();
			for (int i = 0; i < instancesList.Count; i++)
			{
				UILayerKey uILayerKey3 = instancesList[i];
				if (!(uILayerKey3.eventSystemLocator.eventSystem != eventSystem) && uILayerKey3.layer.priority > num)
				{
					uILayerKey = uILayerKey3;
					num = uILayerKey3.layer.priority;
				}
			}
			if ((object)uILayerKey != uILayerKey2)
			{
				if ((bool)uILayerKey2)
				{
					uILayerKey2.onEndRepresentTopLayer.Invoke();
					uILayerKey2.representsTopLayer = false;
				}
				UILayerKey uILayerKey5 = (topLayerRepresentations[eventSystem] = uILayerKey);
				uILayerKey2 = uILayerKey5;
				if ((bool)uILayerKey2)
				{
					uILayerKey2.representsTopLayer = true;
					uILayerKey2.onBeginRepresentTopLayer.Invoke();
				}
			}
		}

		public UILayerKey GetUILayerKey()
		{
			return this;
		}
	}
	public interface IUILayerKeyProvider
	{
		UILayerKey GetUILayerKey();
	}
	public class UILayerKeyProxy : MonoBehaviour, IUILayerKeyProvider
	{
		public UILayerKey ProxiedLayer;

		public UILayerKey GetUILayerKey()
		{
			return ProxiedLayer;
		}
	}
	[RequireComponent(typeof(HGButton))]
	public class UILayerSetFromParent : MonoBehaviour
	{
		private UILayerKey FoundLayer;

		[SerializeField]
		private UILayer layerToFind;

		private void Awake()
		{
			HGButton component = GetComponent<HGButton>();
			if ((object)component == null)
			{
				return;
			}
			IUILayerKeyProvider[] componentsInParent = base.gameObject.GetComponentsInParent<IUILayerKeyProvider>();
			for (int i = 0; i < componentsInParent.Length; i++)
			{
				UILayerKey uILayerKey = componentsInParent[i].GetUILayerKey();
				if ((object)uILayerKey.layer == layerToFind)
				{
					FoundLayer = uILayerKey;
					component.requiredTopLayer = uILayerKey;
					break;
				}
			}
		}

		public void SetLayerActive(bool NewActive)
		{
			if ((bool)FoundLayer)
			{
				FoundLayer.enabled = NewActive;
			}
		}
	}
	[RequireComponent(typeof(EventFunctions))]
	[RequireComponent(typeof(Animator))]
	public class UITransitionController : MonoBehaviour
	{
		public enum TransitionStyle
		{
			Instant,
			CanvasGroupAlphaFade,
			SwipeYScale,
			SwipeXScale
		}

		public TransitionStyle transitionIn;

		public TransitionStyle transitionOut;

		public float transitionInSpeed = 1f;

		public float transitionOutSpeed = 1f;

		public bool transitionOutAtEndOfLifetime;

		public float lifetime;

		private float stopwatch;

		private Animator animator;

		private bool done;

		private void Awake()
		{
			animator = GetComponent<Animator>();
			PushMecanimTransitionInParameters();
		}

		private void PushMecanimTransitionInParameters()
		{
			animator.SetFloat("transitionInSpeed", transitionInSpeed);
			switch (transitionIn)
			{
			case TransitionStyle.Instant:
				animator.SetTrigger("InstantIn");
				break;
			case TransitionStyle.CanvasGroupAlphaFade:
				animator.SetTrigger("CanvasGroupAlphaFadeIn");
				break;
			case TransitionStyle.SwipeYScale:
				animator.SetTrigger("SwipeYScaleIn");
				break;
			case TransitionStyle.SwipeXScale:
				animator.SetTrigger("SwipeXScaleIn");
				break;
			}
		}

		private void PushMecanimTransitionOutParameters()
		{
			animator.SetFloat("transitionOutSpeed", transitionOutSpeed);
			switch (transitionOut)
			{
			case TransitionStyle.Instant:
				animator.SetTrigger("InstantOut");
				break;
			case TransitionStyle.CanvasGroupAlphaFade:
				animator.SetTrigger("CanvasGroupAlphaFadeOut");
				break;
			case TransitionStyle.SwipeYScale:
				animator.SetTrigger("SwipeYScaleOut");
				break;
			case TransitionStyle.SwipeXScale:
				animator.SetTrigger("SwipeXScaleOut");
				break;
			}
		}

		private void Update()
		{
			if (transitionOutAtEndOfLifetime && !done)
			{
				stopwatch += Time.deltaTime;
				if (stopwatch >= lifetime)
				{
					PushMecanimTransitionOutParameters();
					done = true;
				}
			}
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class UserProfileListController : MonoBehaviour
	{
		public delegate void ProfileSelectedDelegate(UserProfile userProfile);

		public GameObject elementPrefab;

		public RectTransform contentRect;

		[Tooltip("Whether or not \"default\" profile appears as a selectable option.")]
		public bool allowDefault = true;

		private MPEventSystemLocator eventSystemLocator;

		private readonly List<UserProfileListElementController> elementsList = new List<UserProfileListElementController>();

		private EventSystem eventSystem => eventSystemLocator.eventSystem;

		public event ProfileSelectedDelegate onProfileSelected;

		public event Action onListRebuilt;

		private void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
		}

		private void OnEnable()
		{
			RebuildElements();
			SaveSystem.onAvailableUserProfilesChanged += RebuildElements;
		}

		private void OnDisable()
		{
			SaveSystem.onAvailableUserProfilesChanged -= RebuildElements;
		}

		private void RebuildElements()
		{
			foreach (Transform item in contentRect)
			{
				UnityEngine.Object.Destroy(item.gameObject);
			}
			elementsList.Clear();
			List<string> availableProfileNames = PlatformSystems.saveSystem.GetAvailableProfileNames();
			for (int i = 0; i < availableProfileNames.Count; i++)
			{
				if (allowDefault || !availableProfileNames[i].Equals("default", StringComparison.OrdinalIgnoreCase))
				{
					GameObject obj = UnityEngine.Object.Instantiate(elementPrefab, contentRect);
					UserProfileListElementController component = obj.GetComponent<UserProfileListElementController>();
					MPButton component2 = obj.GetComponent<MPButton>();
					component.listController = this;
					component.userProfile = PlatformSystems.saveSystem.GetProfile(availableProfileNames[i]);
					elementsList.Add(component);
					obj.SetActive(value: true);
					if (i == 0)
					{
						component2.defaultFallbackButton = true;
					}
				}
			}
			if (this.onListRebuilt != null)
			{
				this.onListRebuilt();
			}
		}

		public ReadOnlyCollection<UserProfileListElementController> GetReadOnlyElementsList()
		{
			return new ReadOnlyCollection<UserProfileListElementController>(elementsList);
		}

		public void SendProfileSelection(UserProfile userProfile)
		{
			this.onProfileSelected?.Invoke(userProfile);
		}
	}
	[RequireComponent(typeof(MPButton))]
	public class UserProfileListElementController : MonoBehaviour
	{
		public TextMeshProUGUI nameLabel;

		private MPButton button;

		public TextMeshProUGUI playTimeLabel;

		[NonSerialized]
		public UserProfileListController listController;

		private UserProfile _userProfile;

		public UserProfile userProfile
		{
			get
			{
				return _userProfile;
			}
			set
			{
				if (_userProfile != value)
				{
					_userProfile = value;
					string sourceText = "???";
					uint num = 0u;
					if (_userProfile != null)
					{
						sourceText = _userProfile.name;
						num = _userProfile.totalLoginSeconds;
					}
					if ((bool)nameLabel)
					{
						nameLabel.SetText(sourceText);
					}
					if ((bool)playTimeLabel)
					{
						TimeSpan timeSpan = TimeSpan.FromSeconds(num);
						playTimeLabel.SetText($"{(uint)timeSpan.TotalHours}:{(uint)timeSpan.Minutes:D2}");
					}
				}
			}
		}

		private void Awake()
		{
			button = GetComponent<MPButton>();
			button.onClick.AddListener(InformListControllerOfSelection);
		}

		private void InformListControllerOfSelection()
		{
			if (!userProfile.isCorrupted)
			{
				listController.SendProfileSelection(userProfile);
			}
		}
	}
	public class ViewableTag : MonoBehaviour
	{
		public enum ViewableVisualStyle
		{
			Button,
			Icon
		}

		private static readonly List<ViewableTag> instancesList = new List<ViewableTag>();

		[SerializeField]
		[FormerlySerializedAs("viewableName")]
		[Tooltip("The path of the viewable that determines whether or not the \"NEW\" tag is activated.")]
		private string _viewableName;

		[Tooltip("Marks the named viewable as viewed when this component is disabled.")]
		public bool markAsViewedOnDisable;

		public bool markAsViewedOnHover;

		public bool markAsViewedOnClick;

		public ViewableVisualStyle viewableVisualStyle;

		public static readonly BoolConVar viewablesWarnUndefined = new BoolConVar("viewables_warn_undefined", ConVarFlags.None, "0", "Issues a warning in the console if a viewable is not defined.");

		private static GameObject tagPrefab;

		private GameObject tagInstance;

		private static bool pendingRefreshAll = false;

		public string viewableName
		{
			get
			{
				return _viewableName;
			}
			set
			{
				if (!(_viewableName == value))
				{
					_viewableName = value;
					Refresh();
				}
			}
		}

		private bool Check()
		{
			if (LocalUserManager.readOnlyLocalUsersList.Count == 0)
			{
				return false;
			}
			UserProfile userProfile = LocalUserManager.readOnlyLocalUsersList[0].userProfile;
			ViewablesCatalog.Node node = ViewablesCatalog.FindNode(viewableName ?? "");
			if (node == null)
			{
				if (viewablesWarnUndefined.value)
				{
					UnityEngine.Debug.LogWarningFormat("Viewable {0} is not defined.", viewableName);
				}
				return false;
			}
			return node.shouldShowUnviewed(userProfile);
		}

		private void OnEnable()
		{
			instancesList.Add(this);
			RoR2Application.onNextUpdate += CallRefreshIfStillValid;
			LogBookController.OnViewablesRegistered += CallRefreshIfStillValid;
			if (markAsViewedOnHover && TryGetComponent<HGButton>(out var component))
			{
				component.onSelect.AddListener(OnControllerSelect);
			}
		}

		private void CallRefreshIfStillValid()
		{
			if ((bool)this)
			{
				Refresh();
			}
		}

		public void Refresh()
		{
			bool flag = base.enabled && Check();
			if ((bool)tagInstance != flag)
			{
				if ((bool)tagInstance)
				{
					UnityEngine.Object.Destroy(tagInstance);
					tagInstance = null;
				}
				else
				{
					string childName = viewableVisualStyle.ToString();
					tagInstance = UnityEngine.Object.Instantiate(tagPrefab, base.transform);
					tagInstance.GetComponent<ChildLocator>().FindChild(childName).gameObject.SetActive(value: true);
				}
			}
		}

		private void OnDisable()
		{
			LogBookController.OnViewablesRegistered -= CallRefreshIfStillValid;
			instancesList.Remove(this);
			Refresh();
			if (markAsViewedOnDisable)
			{
				TriggerView();
			}
		}

		private void TriggerView()
		{
			ViewableTrigger.TriggerView(viewableName);
		}

		[InitDuringStartup]
		private static void Init()
		{
			AsyncOperationHandle<GameObject> asyncOperationHandle = LegacyResourcesAPI.LoadAsync<GameObject>("Prefabs/UI/NewViewableTag");
			asyncOperationHandle.Completed += delegate(AsyncOperationHandle<GameObject> x)
			{
				tagPrefab = x.Result;
			};
			UserProfile.onUserProfileViewedViewablesChanged += delegate
			{
				if (!pendingRefreshAll)
				{
					pendingRefreshAll = true;
					RoR2Application.onNextUpdate += delegate
					{
						foreach (ViewableTag instances in instancesList)
						{
							instances.Refresh();
						}
						pendingRefreshAll = false;
					};
				}
			};
		}

		private void OnControllerSelect()
		{
			if (markAsViewedOnHover)
			{
				TriggerView();
			}
		}
	}
	public class ViewableTrigger : MonoBehaviour
	{
		[Tooltip("The name of the viewable to mark as viewed when this component becomes enabled.")]
		public string viewableName;

		private void OnEnable()
		{
			TriggerView(viewableName);
		}

		public static void TriggerView(string viewableName)
		{
			if (string.IsNullOrEmpty(viewableName))
			{
				return;
			}
			foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList)
			{
				readOnlyLocalUsers.userProfile.MarkViewableAsViewed(viewableName);
			}
		}
	}
	public class VoiceChatCardController : MonoBehaviour
	{
	}
	public class VoiceChatNotificationManager : MonoBehaviour
	{
		public GameObject[] chatNameplate = new GameObject[3];

		public VoiceChatCardController[] chatController = new VoiceChatCardController[3];

		private PlatformID[] chatUserList;

		private PlatformID currentChatUser;

		private int frameDelay;

		private bool waitForInitialization;

		private void Awake()
		{
			if (!PlatformSystems.lobbyManager.HasMPLobbyFeature(MPLobbyFeatures.Voice))
			{
				base.gameObject.SetActive(value: false);
				return;
			}
			if (chatNameplate[0] == null)
			{
				HackFixRefrences();
			}
			chatUserList = PlatformSystems.lobbyManager.GetLobbyMembers();
			if (chatUserList == null)
			{
				waitForInitialization = true;
				for (int i = 0; i < 3; i++)
				{
					if (!(chatNameplate[i] == null))
					{
						chatNameplate[i].SetActive(value: false);
					}
				}
				return;
			}
			waitForInitialization = false;
			for (int j = 0; j < chatUserList.Length; j++)
			{
				if (j < 4)
				{
					_ = ref chatUserList[j];
					_ = chatUserList[j] == default(PlatformID);
				}
			}
			for (int k = 0; k < 3; k++)
			{
				if (!(chatNameplate[k] == null))
				{
					chatNameplate[k].SetActive(value: false);
				}
			}
		}

		private void Initialize()
		{
		}

		private void HackFixRefrences()
		{
		}

		private void Update()
		{
		}
	}
	public class VoidRaidCrabHealthBarPipController : MonoBehaviour
	{
		[SerializeField]
		private GameObject pipPrefab;

		[SerializeField]
		private ItemDef minHealthPercentageDef;

		public void InitializePips(PhasedInventorySetter phasedInventory)
		{
			int numPhases = phasedInventory.GetNumPhases();
			for (int i = 0; i < numPhases; i++)
			{
				float num = 0.01f * (float)phasedInventory.GetItemCountForPhase(i, minHealthPercentageDef);
				if (num > 0f)
				{
					RectTransform component = UnityEngine.Object.Instantiate(pipPrefab, base.transform).GetComponent<RectTransform>();
					component.anchorMin = new UnityEngine.Vector2(num, component.anchorMin.y);
					component.anchorMax = new UnityEngine.Vector2(num, component.anchorMax.y);
				}
			}
		}
	}
	public class VoidStageBatteryMissionObjectiveTracker : ObjectivePanelController.ObjectiveTracker
	{
		private int numBatteriesActivated = -1;

		protected override string GenerateString()
		{
			VoidStageMissionController voidStageMissionController = (VoidStageMissionController)sourceDescriptor.source;
			numBatteriesActivated = voidStageMissionController.numBatteriesActivated;
			return string.Format(Language.GetString(voidStageMissionController.batteryObjectiveToken), numBatteriesActivated, voidStageMissionController.numBatteriesSpawned);
		}

		protected override bool IsDirty()
		{
			return ((VoidStageMissionController)sourceDescriptor.source).numBatteriesActivated != numBatteriesActivated;
		}
	}
	public class VoteInfoPanelController : MonoBehaviour
	{
		private struct IndicatorInfo
		{
			public GameObject gameObject;

			public UnityEngine.UI.Image image;

			public TooltipProvider tooltipProvider;
		}

		public GameObject indicatorPrefab;

		public Sprite hasNotVotedSprite;

		public Sprite hasVotedSprite;

		public RectTransform container;

		public GameObject timerPanelObject;

		public TextMeshProUGUI timerLabel;

		public VoteController voteController;

		private readonly List<IndicatorInfo> indicators = new List<IndicatorInfo>();

		private bool votesArePossible => RoR2Application.isInMultiPlayer;

		private void Awake()
		{
			if (!votesArePossible)
			{
				base.gameObject.SetActive(value: false);
			}
		}

		private void AllocateIndicators(int desiredIndicatorCount)
		{
			while (indicators.Count > desiredIndicatorCount)
			{
				int index = indicators.Count - 1;
				UnityEngine.Object.Destroy(indicators[index].gameObject);
				indicators.RemoveAt(index);
			}
			while (indicators.Count < desiredIndicatorCount)
			{
				GameObject gameObject = UnityEngine.Object.Instantiate(indicatorPrefab, container);
				gameObject.SetActive(value: true);
				indicators.Add(new IndicatorInfo
				{
					gameObject = gameObject,
					image = gameObject.GetComponentInChildren<UnityEngine.UI.Image>(),
					tooltipProvider = gameObject.GetComponentInChildren<TooltipProvider>()
				});
			}
			timerPanelObject.transform.SetAsLastSibling();
		}

		public void UpdateElements()
		{
			int num = 0;
			if ((bool)voteController)
			{
				num = voteController.GetVoteCount();
			}
			AllocateIndicators(num);
			for (int i = 0; i < num; i++)
			{
				UserVote vote = voteController.GetVote(i);
				indicators[i].image.sprite = (vote.receivedVote ? hasVotedSprite : hasNotVotedSprite);
				string userName;
				if ((bool)vote.networkUserObject)
				{
					NetworkUser component = vote.networkUserObject.GetComponent<NetworkUser>();
					userName = ((!component) ? Language.GetString("PLAYER_NAME_UNAVAILABLE") : component.GetNetworkPlayerName().GetResolvedName());
				}
				else
				{
					userName = Language.GetString("PLAYER_NAME_DISCONNECTED");
				}
				indicators[i].tooltipProvider.SetContent(TooltipProvider.GetPlayerNameTooltipContent(userName));
			}
			bool flag = (bool)voteController && voteController.timerStartCondition != VoteController.TimerStartCondition.Never && !float.IsInfinity(voteController.timer);
			timerPanelObject.SetActive(flag);
			if (flag)
			{
				float num2 = voteController.timer;
				if (num2 < 0f)
				{
					num2 = 0f;
				}
				int num3 = Mathf.FloorToInt(num2 * (1f / 60f));
				int num4 = (int)num2 - num3 * 60;
				timerLabel.text = $"{num3}:{num4:00}";
			}
		}

		private void Update()
		{
			UpdateElements();
		}
	}
	public class WeeklyRunScreenController : MonoBehaviour
	{
		public LeaderboardController leaderboard;

		public TextMeshProUGUI countdownLabel;

		private uint currentCycle;

		private TimeSpan lastCountdown;

		private float labelFadeValue;

		private bool leaderboardInitiated;

		private void OnEnable()
		{
			currentCycle = WeeklyRun.GetCurrentSeedCycle();
			UpdateLeaderboard();
		}

		private void UpdateLeaderboard()
		{
			leaderboardInitiated = true;
		}

		private void Update()
		{
			uint currentSeedCycle = WeeklyRun.GetCurrentSeedCycle();
			if (currentSeedCycle != currentCycle)
			{
				currentCycle = currentSeedCycle;
				UpdateLeaderboard();
			}
			if (!leaderboardInitiated)
			{
				UpdateLeaderboard();
			}
			TimeSpan timeSpan = WeeklyRun.GetSeedCycleStartDateTime(currentCycle + 1) - WeeklyRun.now;
			string @string = Language.GetString("WEEKLY_RUN_NEXT_CYCLE_COUNTDOWN_FORMAT");
			countdownLabel.text = string.Format(@string, timeSpan.Hours + timeSpan.Days * 24, timeSpan.Minutes, timeSpan.Seconds);
			if (timeSpan != lastCountdown)
			{
				lastCountdown = timeSpan;
				labelFadeValue = 0f;
			}
			labelFadeValue = Mathf.Max(labelFadeValue + Time.deltaTime * 1f, 0f);
			UnityEngine.Color white = UnityEngine.Color.white;
			if (timeSpan.Days == 0 && timeSpan.Hours == 0)
			{
				white.g = labelFadeValue;
				white.b = labelFadeValue;
			}
			countdownLabel.color = white;
		}
	}
	public class EOSLeaderboardManager : LeaderboardManager
	{
		public const string kPrismaticTrialsLeaderboardId = "PrismaticTrials";

		private readonly LeaderboardsInterface _leaderboardsInterface;

		private readonly List<LeaderboardRecord> _currentGlobalLeaderboardList = new List<LeaderboardRecord>();

		private readonly List<LeaderboardUserScore> _currentFriendsLeaderboardList = new List<LeaderboardUserScore>();

		private static bool _isGlobal;

		private static ProductUserId LocalUserId => EOSLoginManager.loggedInProductId;

		private static DateTime StartTime => WeeklyRun.GetSeedCycleStartDateTime();

		private static DateTime EndTime => WeeklyRun.GetSeedCycleEndDateTime();

		public EOSLeaderboardManager(LeaderboardController leaderboardController)
			: base(leaderboardController)
		{
			_leaderboardsInterface = EOSPlatformManager.GetPlatformInterface().GetLeaderboardsInterface();
			QueryLeaderboardDefinitionsOptions options = new QueryLeaderboardDefinitionsOptions
			{
				LocalUserId = LocalUserId
			};
			_leaderboardsInterface.QueryLeaderboardDefinitions(ref options, null, LeaderboardQueryComplete);
			base.IsQuerying = true;
		}

		private void LeaderboardQueryComplete(ref OnQueryLeaderboardDefinitionsCompleteCallbackInfo data)
		{
			base.IsValid = data.ResultCode == Result.Success;
			base.IsQuerying = false;
		}

		internal override void UpdateLeaderboard()
		{
			switch (LeaderboardController.currentRequestType)
			{
			case RequestType.Global:
			case RequestType.GlobalAroundUser:
				QueryLeaderboardRanks();
				_isGlobal = true;
				break;
			case RequestType.Friends:
				QueryFriendsLeaderboard();
				_isGlobal = false;
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			base.IsQuerying = true;
		}

		private void QueryFriendsLeaderboard()
		{
			ProductUserId[] userIds = EOSFriendsManager.FriendsProductUserIds.ToArray();
			QueryLeaderboardUserScoresOptions queryLeaderboardUserScoresOptions = default(QueryLeaderboardUserScoresOptions);
			queryLeaderboardUserScoresOptions.StartTime = StartTime;
			queryLeaderboardUserScoresOptions.EndTime = EndTime;
			queryLeaderboardUserScoresOptions.LocalUserId = LocalUserId;
			queryLeaderboardUserScoresOptions.StatInfo = new UserScoresQueryStatInfo[1]
			{
				new UserScoresQueryStatInfo
				{
					Aggregation = LeaderboardAggregation.Min,
					StatName = "FASTESTWEEKLYRUN"
				}
			};
			queryLeaderboardUserScoresOptions.UserIds = userIds;
			QueryLeaderboardUserScoresOptions options = queryLeaderboardUserScoresOptions;
			_leaderboardsInterface.QueryLeaderboardUserScores(ref options, "FASTESTWEEKLYRUN", FriendsQueryComplete);
		}

		private void FriendsQueryComplete(ref OnQueryLeaderboardUserScoresCompleteCallbackInfo data)
		{
			string text = data.ClientData?.ToString() ?? "";
			GetLeaderboardUserScoreCountOptions getLeaderboardUserScoreCountOptions = default(GetLeaderboardUserScoreCountOptions);
			getLeaderboardUserScoreCountOptions.StatName = text;
			GetLeaderboardUserScoreCountOptions options = getLeaderboardUserScoreCountOptions;
			uint leaderboardUserScoreCount = _leaderboardsInterface.GetLeaderboardUserScoreCount(ref options);
			UpdateFriendsLeaderboardList(text, leaderboardUserScoreCount);
		}

		private void UpdateFriendsLeaderboardList(string leaderboardName, uint leaderboardMax)
		{
			int num = LeaderboardController.currentPage * LeaderboardController.entriesPerPage;
			long num2 = ((num + LeaderboardController.entriesPerPage > leaderboardMax) ? (leaderboardMax - num) : LeaderboardController.entriesPerPage);
			_currentFriendsLeaderboardList.Clear();
			for (int i = num; i < num2; i++)
			{
				GetFriendsLeaderboardEntry(System.Convert.ToUInt32(i), leaderboardName);
			}
		}

		private void GetFriendsLeaderboardEntry(uint leaderboardRecordIndex, string statName)
		{
			CopyLeaderboardUserScoreByIndexOptions copyLeaderboardUserScoreByIndexOptions = default(CopyLeaderboardUserScoreByIndexOptions);
			copyLeaderboardUserScoreByIndexOptions.LeaderboardUserScoreIndex = leaderboardRecordIndex;
			copyLeaderboardUserScoreByIndexOptions.StatName = statName;
			CopyLeaderboardUserScoreByIndexOptions options = copyLeaderboardUserScoreByIndexOptions;
			if (_leaderboardsInterface.CopyLeaderboardUserScoreByIndex(ref options, out var outLeaderboardUserScore) == Result.Success && outLeaderboardUserScore.HasValue)
			{
				LeaderboardUserScore value = outLeaderboardUserScore.Value;
				(PlatformSystems.userManager as UserManagerEOS)?.QueryForDisplayNames(value.UserId, delegate
				{
					base.IsQuerying = false;
				});
				_currentFriendsLeaderboardList.Add(value);
			}
		}

		private void QueryLeaderboardRanks()
		{
			QueryLeaderboardRanksOptions queryLeaderboardRanksOptions = default(QueryLeaderboardRanksOptions);
			queryLeaderboardRanksOptions.LeaderboardId = "PrismaticTrials";
			queryLeaderboardRanksOptions.LocalUserId = LocalUserId;
			QueryLeaderboardRanksOptions options = queryLeaderboardRanksOptions;
			_leaderboardsInterface.QueryLeaderboardRanks(ref options, LeaderboardController.currentLeaderboardName, GlobalQueryComplete);
		}

		private void GlobalQueryComplete(ref OnQueryLeaderboardRanksCompleteCallbackInfo data)
		{
			string leaderboardName = data.ClientData?.ToString() ?? "";
			GetLeaderboardRecordCountOptions options = default(GetLeaderboardRecordCountOptions);
			uint leaderboardRecordCount = _leaderboardsInterface.GetLeaderboardRecordCount(ref options);
			UpdateGlobalLeaderboardList(leaderboardName, leaderboardRecordCount);
		}

		private void UpdateGlobalLeaderboardList(string leaderboardName, uint leaderboardMax)
		{
			int num = LeaderboardController.currentPage * LeaderboardController.entriesPerPage;
			long num2 = ((num + LeaderboardController.entriesPerPage > leaderboardMax) ? (leaderboardMax - num) : LeaderboardController.entriesPerPage);
			_currentGlobalLeaderboardList.Clear();
			for (int i = num; i < num2; i++)
			{
				GetGlobalLeaderboardEntry(System.Convert.ToUInt32(i), leaderboardName);
			}
		}

		private void GetGlobalLeaderboardEntry(uint leaderboardRecordIndex, string leaderboardName)
		{
			CopyLeaderboardRecordByIndexOptions copyLeaderboardRecordByIndexOptions = default(CopyLeaderboardRecordByIndexOptions);
			copyLeaderboardRecordByIndexOptions.LeaderboardRecordIndex = leaderboardRecordIndex;
			CopyLeaderboardRecordByIndexOptions options = copyLeaderboardRecordByIndexOptions;
			if (_leaderboardsInterface.CopyLeaderboardRecordByIndex(ref options, out var outLeaderboardRecord) == Result.Success && outLeaderboardRecord.HasValue)
			{
				LeaderboardRecord value = outLeaderboardRecord.Value;
				(PlatformSystems.userManager as UserManagerEOS)?.QueryForDisplayNames(value.UserId, delegate
				{
					base.IsQuerying = false;
				});
				_currentGlobalLeaderboardList.Add(value);
			}
		}

		internal override List<LeaderboardInfo> GetLeaderboardInfoList()
		{
			if (_isGlobal)
			{
				return _currentGlobalLeaderboardList.Select(delegate(LeaderboardRecord leaderboardRecord)
				{
					LeaderboardInfo result2 = default(LeaderboardInfo);
					result2.rank = System.Convert.ToInt32(leaderboardRecord.Rank);
					result2.survivorIndex = null;
					result2.timeInSeconds = leaderboardRecord.Score;
					result2.userID = leaderboardRecord.UserId.ToString();
					return result2;
				}).ToList();
			}
			_currentFriendsLeaderboardList.Sort((LeaderboardUserScore x, LeaderboardUserScore y) => x.Score.CompareTo(y.Score));
			return _currentFriendsLeaderboardList.Select(delegate(LeaderboardUserScore leaderboardUserScore, int index)
			{
				LeaderboardInfo result = default(LeaderboardInfo);
				result.rank = index + 1;
				result.survivorIndex = null;
				result.timeInSeconds = leaderboardUserScore.Score;
				result.userID = leaderboardUserScore.UserId.ToString();
				return result;
			}).ToList();
		}

		internal override PlatformID GetUserID(LeaderboardInfo leaderboardInfo)
		{
			return new PlatformID(ProductUserId.FromString(leaderboardInfo.userID));
		}

		internal override string GetLocalUserIdString()
		{
			return LocalUserId.ToString();
		}
	}
	public struct LeaderboardInfo
	{
		public int rank;

		public string userID;

		public SurvivorIndex? survivorIndex;

		public float timeInSeconds;
	}
	public enum RequestType
	{
		Global,
		GlobalAroundUser,
		Friends
	}
	public abstract class LeaderboardManager
	{
		protected LeaderboardController LeaderboardController;

		public bool IsValid { get; protected set; }

		public bool IsQuerying { get; protected set; }

		internal abstract void UpdateLeaderboard();

		internal abstract List<LeaderboardInfo> GetLeaderboardInfoList();

		internal abstract PlatformID GetUserID(LeaderboardInfo leaderboardInfo);

		internal abstract string GetLocalUserIdString();

		protected LeaderboardManager(LeaderboardController leaderboardController)
		{
			LeaderboardController = leaderboardController;
		}
	}
	internal static class LeaderboardExtensions
	{
		internal static void SetLeaderboardInfo(this List<LeaderboardInfo> leaderboardInfoList, LeaderboardInfo[] leaderboardInfos)
		{
			leaderboardInfoList.Clear();
			leaderboardInfoList.AddRange(leaderboardInfos);
		}
	}
	public class SteamLeaderboardManager : LeaderboardManager
	{
		private Leaderboard _currentLeaderboard;

		private List<LeaderboardInfo> _leaderboardInfoList = new List<LeaderboardInfo>();

		public SteamLeaderboardManager(LeaderboardController leaderboardController)
			: base(leaderboardController)
		{
			base.IsValid = true;
		}

		internal override List<LeaderboardInfo> GetLeaderboardInfoList()
		{
			return _leaderboardInfoList;
		}

		internal override PlatformID GetUserID(LeaderboardInfo leaderboardInfo)
		{
			return new PlatformID(System.Convert.ToUInt64(leaderboardInfo.userID));
		}

		internal override string GetLocalUserIdString()
		{
			return Client.Instance.SteamId.ToString();
		}

		internal override void UpdateLeaderboard()
		{
			_currentLeaderboard = Client.Instance.GetLeaderboard(LeaderboardController.currentLeaderboardName);
			int num = LeaderboardController.currentPage * LeaderboardController.entriesPerPage - LeaderboardController.entriesPerPage / 2;
			base.IsValid = _currentLeaderboard != null && _currentLeaderboard.IsValid;
			base.IsQuerying = true;
			_currentLeaderboard.FetchScores((Leaderboard.RequestType)LeaderboardController.currentRequestType, num, num + LeaderboardController.entriesPerPage, delegate(Leaderboard.Entry[] entries)
			{
				_leaderboardInfoList.SetLeaderboardInfo(entries.Select(LeaderboardInfoFromSteamLeaderboardEntry).ToArray());
				base.IsQuerying = false;
				base.IsValid = _currentLeaderboard.IsValid;
			}, delegate
			{
			});
		}

		private static LeaderboardInfo LeaderboardInfoFromSteamLeaderboardEntry(Leaderboard.Entry entry)
		{
			SurvivorIndex value = SurvivorIndex.None;
			int num = ((entry.SubScores != null && entry.SubScores.Length >= 1) ? entry.SubScores[1] : 0);
			if (num >= 0 && num < SurvivorCatalog.survivorCount)
			{
				value = (SurvivorIndex)num;
			}
			LeaderboardInfo result = default(LeaderboardInfo);
			result.timeInSeconds = (float)entry.Score * 0.001f;
			result.survivorIndex = value;
			result.userID = entry.SteamId.ToString();
			result.rank = entry.GlobalRank;
			return result;
		}
	}
	public class UIElementAllocator<T> where T : Component
	{
		public delegate void ElementOperationDelegate(int index, T element);

		public readonly RectTransform containerTransform;

		public readonly GameObject elementPrefab;

		public readonly bool markElementsUnsavable;

		[NotNull]
		private List<T> elementControllerComponentsList;

		[NotNull]
		public readonly ReadOnlyCollection<T> elements;

		[CanBeNull]
		public ElementOperationDelegate onCreateElement;

		[CanBeNull]
		public ElementOperationDelegate onDestroyElement;

		public UIElementAllocator([NotNull] RectTransform containerTransform, [NotNull] GameObject elementPrefab, bool markElementsUnsavable = true, bool acquireExistingChildren = false)
		{
			this.containerTransform = containerTransform;
			this.elementPrefab = elementPrefab;
			this.markElementsUnsavable = markElementsUnsavable;
			elementControllerComponentsList = new List<T>();
			elements = new ReadOnlyCollection<T>(elementControllerComponentsList);
			if (!acquireExistingChildren)
			{
				return;
			}
			for (int i = 0; i < containerTransform.childCount; i++)
			{
				T component = containerTransform.GetChild(i).GetComponent<T>();
				if ((bool)component && component.gameObject.activeInHierarchy)
				{
					elementControllerComponentsList.Add(component);
				}
			}
		}

		private void DestroyElementAt(int i)
		{
			T val = elementControllerComponentsList[i];
			onDestroyElement?.Invoke(i, val);
			GameObject gameObject = val.gameObject;
			if (Application.isPlaying)
			{
				UnityEngine.Object.Destroy(gameObject);
			}
			else
			{
				UnityEngine.Object.DestroyImmediate(gameObject);
			}
			elementControllerComponentsList.RemoveAt(i);
		}

		public void AllocateElements(int desiredCount)
		{
			if (desiredCount < 0)
			{
				throw new ArgumentOutOfRangeException();
			}
			if (!containerTransform.gameObject.scene.IsValid())
			{
				return;
			}
			for (int num = elementControllerComponentsList.Count - 1; num >= desiredCount; num--)
			{
				DestroyElementAt(num);
			}
			for (int i = elementControllerComponentsList.Count; i < desiredCount; i++)
			{
				T component = UnityEngine.Object.Instantiate(elementPrefab, containerTransform).GetComponent<T>();
				elementControllerComponentsList.Add(component);
				GameObject gameObject = component.gameObject;
				if (markElementsUnsavable)
				{
					gameObject.hideFlags |= HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild;
				}
				gameObject.SetActive(value: true);
				onCreateElement?.Invoke(i, component);
			}
		}

		public void MoveElementsToContainerEnd()
		{
			int num = containerTransform.childCount - elementControllerComponentsList.Count;
			for (int num2 = elementControllerComponentsList.Count - 1; num2 >= 0; num2--)
			{
				elementControllerComponentsList[num2].transform.SetSiblingIndex(num + num2);
			}
		}
	}
	public class UIElementPairAllocator<T, D> where T : Component where D : new()
	{
		public delegate void ElementOperationDelegate(int index, T element);

		public readonly RectTransform containerTransform;

		public readonly GameObject elementPrefab;

		[NotNull]
		private List<T> elementControllerComponentsList;

		[NotNull]
		public readonly ReadOnlyCollection<T> elements;

		[NotNull]
		private List<D> elementControllerDataList;

		[NotNull]
		public readonly ReadOnlyCollection<D> elementsData;

		[CanBeNull]
		public ElementOperationDelegate onCreateElement;

		[CanBeNull]
		public ElementOperationDelegate onDestroyElement;

		public UIElementPairAllocator([NotNull] RectTransform containerTransform, [NotNull] GameObject elementPrefab)
		{
			this.containerTransform = containerTransform;
			this.elementPrefab = elementPrefab;
			elementControllerComponentsList = new List<T>();
			elements = new ReadOnlyCollection<T>(elementControllerComponentsList);
			elementControllerDataList = new List<D>();
			elementsData = new ReadOnlyCollection<D>(elementControllerDataList);
		}

		public void SetData(D val, int index)
		{
			elementControllerDataList[index] = val;
		}

		public void AllocateElements(int desiredCount)
		{
			if (desiredCount < 0)
			{
				throw new ArgumentOutOfRangeException();
			}
			for (int num = elementControllerComponentsList.Count - 1; num >= desiredCount; num--)
			{
				T val = elementControllerComponentsList[num];
				onDestroyElement?.Invoke(num, val);
				UnityEngine.Object.Destroy(val.gameObject);
				elementControllerComponentsList.RemoveAt(num);
				elementControllerDataList.RemoveAt(num);
			}
			for (int i = elementControllerComponentsList.Count; i < desiredCount; i++)
			{
				T component = UnityEngine.Object.Instantiate(elementPrefab, containerTransform).GetComponent<T>();
				elementControllerComponentsList.Add(component);
				component.gameObject.SetActive(value: true);
				elementControllerDataList.Add(new D());
				onCreateElement?.Invoke(i, component);
			}
		}
	}
}
namespace RoR2.UI.SkinControllers
{
	[ExecuteAlways]
	public abstract class BaseSkinController : MonoBehaviour
	{
		public UISkinData skinData;

		protected abstract void OnSkinUI();

		protected void Awake()
		{
			if ((bool)skinData)
			{
				DoSkinUI();
			}
		}

		private void DoSkinUI()
		{
			if ((bool)skinData)
			{
				OnSkinUI();
			}
		}
	}
	[RequireComponent(typeof(Button))]
	public class ButtonSkinController : BaseSkinController
	{
		private static readonly List<ButtonSkinController> instancesList = new List<ButtonSkinController>();

		private Button button;

		public bool useRecommendedButtonWidth = true;

		public bool useRecommendedButtonHeight = true;

		public bool useRecommendedImage = true;

		public bool useRecommendedMaterial = true;

		public bool useRecommendedAlignment = true;

		public bool useRecommendedLabel = true;

		private LayoutElement layoutElement;

		private void CacheComponents()
		{
			button = GetComponent<Button>();
			layoutElement = GetComponent<LayoutElement>();
		}

		protected new void Awake()
		{
			CacheComponents();
			base.Awake();
		}

		[RuntimeInitializeOnLoadMethod]
		private static void Init()
		{
			RoR2Application.onUpdate += StaticUpdate;
		}

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

		private void OnDisable()
		{
			instancesList.Remove(this);
		}

		private static void StaticUpdate()
		{
			foreach (ButtonSkinController instances in instancesList)
			{
				instances.UpdateLabelStyle(ref instances.skinData.buttonStyle);
			}
		}

		private void UpdateLabelStyle(ref UISkinData.ButtonStyle buttonStyle)
		{
			if (!useRecommendedLabel)
			{
				return;
			}
			TextMeshProUGUI componentInChildren = button.GetComponentInChildren<TextMeshProUGUI>();
			if ((bool)componentInChildren)
			{
				if (button.interactable)
				{
					buttonStyle.interactableTextStyle.Apply(componentInChildren, useRecommendedAlignment);
				}
				else
				{
					buttonStyle.disabledTextStyle.Apply(componentInChildren, useRecommendedAlignment);
				}
			}
		}

		protected override void OnSkinUI()
		{
			ApplyButtonStyle(ref skinData.buttonStyle);
		}

		private void ApplyButtonStyle(ref UISkinData.ButtonStyle buttonStyle)
		{
			if (useRecommendedMaterial)
			{
				button.image.material = buttonStyle.material;
			}
			button.colors = buttonStyle.colors;
			if (useRecommendedImage)
			{
				button.image.sprite = buttonStyle.sprite;
			}
			if (useRecommendedButtonWidth)
			{
				((RectTransform)base.transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, buttonStyle.recommendedWidth);
			}
			if (useRecommendedButtonHeight)
			{
				((RectTransform)base.transform).SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, buttonStyle.recommendedHeight);
			}
			if ((bool)layoutElement)
			{
				if (useRecommendedButtonWidth)
				{
					layoutElement.preferredWidth = buttonStyle.recommendedWidth;
				}
				if (useRecommendedButtonHeight)
				{
					layoutElement.preferredHeight = buttonStyle.recommendedHeight;
				}
			}
			UpdateLabelStyle(ref buttonStyle);
		}

		private void OnValidate()
		{
			CacheComponents();
		}
	}
	[RequireComponent(typeof(TextMeshProUGUI))]
	public class LabelSkinController : BaseSkinController
	{
		public enum LabelType
		{
			Default,
			Header,
			Detail
		}

		public LabelType labelType;

		public bool useRecommendedAlignment = true;

		private TextMeshProUGUI label;

		protected new void Awake()
		{
			label = GetComponent<TextMeshProUGUI>();
			base.Awake();
		}

		protected override void OnSkinUI()
		{
			switch (labelType)
			{
			case LabelType.Default:
				skinData.bodyTextStyle.Apply(label, useRecommendedAlignment);
				break;
			case LabelType.Header:
				skinData.headerTextStyle.Apply(label, useRecommendedAlignment);
				break;
			case LabelType.Detail:
				skinData.detailTextStyle.Apply(label, useRecommendedAlignment);
				break;
			}
		}
	}
	[RequireComponent(typeof(UnityEngine.UI.Image))]
	public class PanelSkinController : BaseSkinController
	{
		public enum PanelType
		{
			Default,
			Header,
			Detail
		}

		public PanelType panelType;

		private UnityEngine.UI.Image image;

		protected new void Awake()
		{
			image = GetComponent<UnityEngine.UI.Image>();
			base.Awake();
		}

		protected override void OnSkinUI()
		{
			switch (panelType)
			{
			case PanelType.Default:
				skinData.mainPanelStyle.Apply(image);
				break;
			case PanelType.Header:
				skinData.headerPanelStyle.Apply(image);
				break;
			case PanelType.Detail:
				skinData.detailPanelStyle.Apply(image);
				break;
			}
		}
	}
	[RequireComponent(typeof(ScrollRect))]
	public class ScrollRectSkinController : BaseSkinController
	{
		private ScrollRect scrollRect;

		protected new void Awake()
		{
			scrollRect = GetComponent<ScrollRect>();
			base.Awake();
		}

		protected override void OnSkinUI()
		{
			UnityEngine.UI.Image component = GetComponent<UnityEngine.UI.Image>();
			if ((bool)component)
			{
				skinData.scrollRectStyle.backgroundPanelStyle.Apply(component);
			}
			if ((bool)scrollRect.verticalScrollbar)
			{
				SkinScrollbar(scrollRect.verticalScrollbar);
			}
			if ((bool)scrollRect.horizontalScrollbar)
			{
				SkinScrollbar(scrollRect.horizontalScrollbar);
			}
		}

		private void SkinScrollbar(Scrollbar scrollbar)
		{
			skinData.scrollRectStyle.scrollbarBackgroundStyle.Apply(scrollbar.GetComponent<UnityEngine.UI.Image>());
			scrollbar.colors = skinData.scrollRectStyle.scrollbarHandleColors;
			scrollbar.handleRect.GetComponent<UnityEngine.UI.Image>().sprite = skinData.scrollRectStyle.scrollbarHandleImage;
		}
	}
}
namespace RoR2.UI.LogBook
{
	public class CategoryDef
	{
		public class NavButtons
		{
			public string scroll = "SUBMENU_SCROLL";

			public string back = "SUBMENU_BACK";

			public string navigate = "LOGBOOK_ZOOMINOUT";

			public string rotate = "LOGBOOK_ROTATE";
		}

		[NotNull]
		public delegate Entry[] BuildEntriesDelegate([CanBeNull] UserProfile viewerProfile);

		[NotNull]
		public string nameToken = string.Empty;

		private GameObject _iconPrefab;

		public UnityEngine.Vector2 iconSize = UnityEngine.Vector2.one;

		public bool fullWidth;

		public Action<GameObject, Entry, EntryStatus, UserProfile> initializeElementGraphics = InitializeDefault;

		public NavButtons navButtons = new NavButtons();

		[CanBeNull]
		public ViewablesCatalog.Node viewableNode;

		public GameObject iconPrefab
		{
			get
			{
				return _iconPrefab;
			}
			[NotNull]
			set
			{
				_iconPrefab = value;
				iconSize = ((RectTransform)_iconPrefab.transform).sizeDelta;
			}
		}

		[NotNull]
		public BuildEntriesDelegate buildEntries { private get; set; }

		public Entry[] BuildEntries([CanBeNull] UserProfile viewerProfile)
		{
			Entry[] array = buildEntries(viewerProfile);
			for (int i = 0; i < array.Length; i++)
			{
				array[i].category = this;
			}
			return array;
		}

		public static void InitializeDefault(GameObject gameObject, Entry entry, EntryStatus status, UserProfile userProfile)
		{
			Texture texture = null;
			Texture texture2 = null;
			UnityEngine.Color color = UnityEngine.Color.white;
			switch (status)
			{
			case EntryStatus.Unimplemented:
				texture = LegacyResourcesAPI.Load<Texture2D>("Textures/MiscIcons/texWIPIcon");
				break;
			case EntryStatus.Locked:
				texture = LegacyResourcesAPI.Load<Texture2D>("Textures/MiscIcons/texUnlockIcon");
				color = UnityEngine.Color.gray;
				break;
			case EntryStatus.Unencountered:
				texture = entry.iconTexture;
				color = UnityEngine.Color.black;
				break;
			case EntryStatus.Available:
				texture = entry.iconTexture;
				texture2 = entry.bgTexture;
				color = UnityEngine.Color.white;
				break;
			case EntryStatus.New:
				texture = entry.iconTexture;
				texture2 = entry.bgTexture;
				color = new UnityEngine.Color(1f, 0.8f, 0.5f, 1f);
				break;
			default:
				throw new ArgumentOutOfRangeException("status", status, null);
			}
			RawImage rawImage = null;
			RawImage rawImage2 = null;
			ChildLocator component = gameObject.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				rawImage = component.FindChild("Icon").GetComponent<RawImage>();
				rawImage2 = component.FindChild("BG").GetComponent<RawImage>();
			}
			else
			{
				rawImage = gameObject.GetComponentInChildren<RawImage>();
			}
			rawImage.texture = texture;
			rawImage.color = color;
			if ((bool)rawImage2)
			{
				if (texture2 != null)
				{
					rawImage2.texture = texture2;
				}
				else
				{
					rawImage2.enabled = false;
				}
			}
			TextMeshProUGUI componentInChildren = gameObject.GetComponentInChildren<TextMeshProUGUI>();
			if ((bool)componentInChildren)
			{
				if (status >= EntryStatus.Available)
				{
					componentInChildren.text = entry.GetDisplayName(userProfile);
				}
				else
				{
					componentInChildren.text = Language.GetString("UNIDENTIFIED");
				}
			}
		}

		public static void InitializeChallenge(GameObject gameObject, Entry entry, EntryStatus status, UserProfile userProfile)
		{
			TextMeshProUGUI textMeshProUGUI = null;
			TextMeshProUGUI textMeshProUGUI2 = null;
			RawImage rawImage = null;
			AchievementDef achievementDef = (AchievementDef)entry.extraData;
			float achievementProgress = AchievementManager.GetUserAchievementManager(LocalUserManager.readOnlyLocalUsersList.FirstOrDefault((LocalUser v) => v.userProfile == userProfile)).GetAchievementProgress(achievementDef);
			HGButton component = gameObject.GetComponent<HGButton>();
			if ((bool)component)
			{
				component.disablePointerClick = true;
				component.disableGamepadClick = true;
			}
			ChildLocator component2 = gameObject.GetComponent<ChildLocator>();
			if ((bool)component2)
			{
				textMeshProUGUI = component2.FindChild("DescriptionLabel").GetComponent<TextMeshProUGUI>();
				textMeshProUGUI2 = component2.FindChild("NameLabel").GetComponent<TextMeshProUGUI>();
				rawImage = component2.FindChild("RewardImage").GetComponent<RawImage>();
				textMeshProUGUI2.text = Language.GetString(achievementDef.nameToken);
				textMeshProUGUI.text = Language.GetString(achievementDef.descriptionToken);
			}
			Texture texture = null;
			UnityEngine.Color color = UnityEngine.Color.white;
			switch (status)
			{
			case EntryStatus.Unimplemented:
				texture = LegacyResourcesAPI.Load<Texture2D>("Textures/MiscIcons/texWIPIcon");
				break;
			case EntryStatus.Locked:
				texture = LegacyResourcesAPI.Load<Texture2D>("Textures/MiscIcons/texUnlockIcon");
				color = UnityEngine.Color.black;
				textMeshProUGUI2.text = Language.GetString("UNIDENTIFIED");
				textMeshProUGUI.text = Language.GetString("UNIDENTIFIED_DESCRIPTION");
				component2.FindChild("CantBeAchieved").gameObject.SetActive(value: true);
				break;
			case EntryStatus.Unencountered:
				texture = LegacyResourcesAPI.Load<Texture2D>("Textures/MiscIcons/texUnlockIcon");
				color = UnityEngine.Color.gray;
				component2.FindChild("ProgressTowardsUnlocking").GetComponent<UnityEngine.UI.Image>().fillAmount = achievementProgress;
				break;
			case EntryStatus.Available:
				texture = entry.iconTexture;
				color = UnityEngine.Color.white;
				component2.FindChild("HasBeenUnlocked").gameObject.SetActive(value: true);
				break;
			case EntryStatus.New:
				texture = entry.iconTexture;
				color = new UnityEngine.Color(1f, 0.8f, 0.5f, 1f);
				component2.FindChild("HasBeenUnlocked").gameObject.SetActive(value: true);
				break;
			case EntryStatus.None:
				component2.FindChild("RewardImageContainer").gameObject.SetActive(value: true);
				textMeshProUGUI2.text = "";
				textMeshProUGUI.text = "";
				break;
			default:
				throw new ArgumentOutOfRangeException("status", status, null);
			}
			if (texture != null)
			{
				rawImage.texture = texture;
				rawImage.color = color;
			}
			else
			{
				rawImage.enabled = false;
			}
		}

		public static void InitializeMorgue(GameObject gameObject, Entry entry, EntryStatus status, UserProfile userProfile)
		{
			RunReport runReport = entry.extraData as RunReport;
			GameEndingDef gameEnding = runReport.gameEnding;
			ChildLocator component = gameObject.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				TextMeshProUGUI component2 = component.FindChild("DescriptionLabel").GetComponent<TextMeshProUGUI>();
				TextMeshProUGUI component3 = component.FindChild("NameLabel").GetComponent<TextMeshProUGUI>();
				RawImage component4 = component.FindChild("IconImage").GetComponent<RawImage>();
				UnityEngine.UI.Image component5 = component.FindChild("BackgroundImage").GetComponent<UnityEngine.UI.Image>();
				Texture iconTexture = entry.iconTexture;
				component3.text = entry.GetDisplayName(userProfile);
				component2.text = Language.GetString(runReport.gameEnding?.endingTextToken ?? string.Empty);
				component2.color = gameEnding?.foregroundColor ?? UnityEngine.Color.white;
				component5.color = gameEnding?.backgroundColor ?? UnityEngine.Color.black;
				if (iconTexture != null)
				{
					component4.texture = iconTexture;
				}
				else
				{
					component4.enabled = false;
				}
			}
		}

		public static void InitializeStats(GameObject gameObject, Entry entry, EntryStatus status, UserProfile userProfile)
		{
			UserProfile userProfile2 = entry.extraData as UserProfile;
			ChildLocator component = gameObject.GetComponent<ChildLocator>();
			if ((bool)component)
			{
				TextMeshProUGUI component2 = component.FindChild("NameLabel").GetComponent<TextMeshProUGUI>();
				TextMeshProUGUI component3 = component.FindChild("TimeLabel").GetComponent<TextMeshProUGUI>();
				TextMeshProUGUI component4 = component.FindChild("CompletionLabel").GetComponent<TextMeshProUGUI>();
				RawImage component5 = component.FindChild("IconImage").GetComponent<RawImage>();
				component.FindChild("BackgroundImage").GetComponent<UnityEngine.UI.Image>();
				Texture iconTexture = entry.iconTexture;
				IntFraction value = new GameCompletionStatsHelper().GetTotalCompletion(userProfile2);
				float num = (float)value;
				string text = $"{num:0%}";
				TimeSpan timeSpan = TimeSpan.FromSeconds(userProfile2.totalLoginSeconds);
				string text2 = $"{(uint)timeSpan.TotalHours}:{(uint)timeSpan.Minutes:D2}";
				component2.text = entry.GetDisplayName(userProfile2);
				component3.text = text2;
				component4.text = text;
				if (iconTexture != null)
				{
					component5.texture = iconTexture;
				}
				else
				{
					component5.enabled = false;
				}
			}
		}
	}
	public class Entry
	{
		public delegate EntryStatus GetStatusDelegate(in Entry entry, [NotNull] UserProfile viewerProfile);

		public delegate TooltipContent GetTooltipContentDelegate(in Entry entry, UserProfile viewerProfile, EntryStatus entryStatus);

		[NotNull]
		public delegate string GetDisplayNameDelegate(in Entry entry, [NotNull] UserProfile viewerProfile);

		public delegate bool IsWIPDelegate(in Entry entry);

		public string nameToken;

		public CategoryDef category;

		public Texture iconTexture;

		public Texture bgTexture;

		public UnityEngine.Color color;

		public GameObject modelPrefab;

		public object extraData;

		public Action<PageBuilder> pageBuilderMethod;

		[CanBeNull]
		public ViewablesCatalog.Node viewableNode;

		[NotNull]
		public GetStatusDelegate getStatusImplementation { private get; set; } = GetStatusDefault;


		public GetTooltipContentDelegate getTooltipContentImplementation { private get; set; } = GetTooltipContentDefault;


		[NotNull]
		public GetDisplayNameDelegate getDisplayNameImplementation { private get; set; } = GetDisplayNameDefault;


		[NotNull]
		public GetDisplayNameDelegate getCategoryDisplayNameImplementation { private get; set; } = GetCategoryDisplayNameDefault;


		[NotNull]
		public IsWIPDelegate isWIPImplementation { private get; set; } = IsWIPReturnFalse;


		public bool isWip => isWIPImplementation(in this);

		public static EntryStatus GetStatusDefault(in Entry entry, [NotNull] UserProfile viewerProfile)
		{
			return EntryStatus.Unimplemented;
		}

		public EntryStatus GetStatus([NotNull] UserProfile viewerProfile)
		{
			return getStatusImplementation(in this, viewerProfile);
		}

		public static TooltipContent GetTooltipContentDefault(in Entry entry, [NotNull] UserProfile viewerProfile, EntryStatus entryStatus)
		{
			TooltipContent result = default(TooltipContent);
			result.overrideTitleText = entry.GetDisplayName(viewerProfile);
			result.overrideBodyText = entry.GetCategoryDisplayName(viewerProfile);
			return result;
		}

		public TooltipContent GetTooltipContent([NotNull] UserProfile viewerProfile, EntryStatus entryStatus)
		{
			return getTooltipContentImplementation(in this, viewerProfile, entryStatus);
		}

		[NotNull]
		public static string GetDisplayNameDefault(in Entry entry, [NotNull] UserProfile viewerProfile)
		{
			return Language.GetString(entry.nameToken ?? string.Empty);
		}

		[NotNull]
		public string GetDisplayName([NotNull] UserProfile viewerProfile)
		{
			return getDisplayNameImplementation(in this, viewerProfile);
		}

		[NotNull]
		public static string GetCategoryDisplayNameDefault(in Entry entry, [NotNull] UserProfile viewerProfile)
		{
			return Language.GetString(entry.category?.nameToken ?? string.Empty);
		}

		[NotNull]
		public string GetCategoryDisplayName([NotNull] UserProfile viewerProfile)
		{
			return getCategoryDisplayNameImplementation(in this, viewerProfile);
		}

		private static bool IsWIPReturnFalse(in Entry entry)
		{
			return false;
		}
	}
	public enum EntryStatus
	{
		None,
		Unimplemented,
		Locked,
		Unencountered,
		Available,
		New
	}
	public class LogBookController : MonoBehaviour
	{
		private class NavigationPageInfo
		{
			public CategoryDef categoryDef;

			public Entry[] entries;

			public int index;

			public int indexInCategory;
		}

		private class LogBookState : EntityState
		{
			protected LogBookController logBookController;

			protected float unscaledAge;

			public override void OnEnter()
			{
				base.OnEnter();
				logBookController = GetComponent<LogBookController>();
			}

			public override void Update()
			{
				base.Update();
				unscaledAge += Time.unscaledDeltaTime;
			}
		}

		private class FadeState : LogBookState
		{
			private CanvasGroup canvasGroup;

			public float duration = 0.5f;

			public float endValue;

			public override void OnEnter()
			{
				base.OnEnter();
				canvasGroup = GetComponent<CanvasGroup>();
				if ((bool)canvasGroup)
				{
					canvasGroup.alpha = 0f;
				}
			}

			public override void OnExit()
			{
				if ((bool)canvasGroup)
				{
					canvasGroup.alpha = endValue;
				}
				base.OnExit();
			}

			public override void Update()
			{
				if ((bool)canvasGroup)
				{
					canvasGroup.alpha = unscaledAge / duration;
					if (canvasGroup.alpha >= 1f)
					{
						outer.SetNextState(new EntityStates.Idle());
					}
				}
				base.Update();
			}
		}

		private class ChangeEntriesPageState : LogBookState
		{
			private int oldPageIndex;

			public NavigationPageInfo newNavigationPageInfo;

			public float duration = 0.1f;

			public UnityEngine.Vector2 moveDirection;

			private GameObject oldPage;

			private GameObject newPage;

			private UnityEngine.Vector2 oldPageTargetPosition;

			private UnityEngine.Vector2 newPageTargetPosition;

			private UnityEngine.Vector2 containerSize = UnityEngine.Vector2.zero;

			public override void OnEnter()
			{
				base.OnEnter();
				if ((bool)logBookController)
				{
					oldPageIndex = logBookController.currentPageIndex;
					oldPage = logBookController.currentEntriesPageObject;
					newPage = logBookController.BuildEntriesPage(newNavigationPageInfo);
					containerSize = logBookController.entryPageContainer.rect.size;
				}
				SetPagePositions(0f);
			}

			public override void OnExit()
			{
				base.OnExit();
				EntityState.Destroy(oldPage);
				if ((bool)logBookController)
				{
					logBookController.currentEntriesPageObject = newPage;
					logBookController.currentPageIndex = newNavigationPageInfo.indexInCategory;
				}
			}

			private void SetPagePositions(float t)
			{
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(containerSize.x * (0f - moveDirection.x), containerSize.y * moveDirection.y);
				UnityEngine.Vector2 vector2 = vector * t;
				if ((bool)oldPage)
				{
					oldPage.transform.localPosition = vector2;
				}
				if ((bool)newPage)
				{
					newPage.transform.localPosition = vector2 - vector;
				}
			}

			public override void Update()
			{
				base.Update();
				float num = Mathf.Clamp01(unscaledAge / duration);
				SetPagePositions(num);
				if (num == 1f)
				{
					outer.SetNextState(new EntityStates.Idle());
				}
			}
		}

		private class ChangeCategoryState : LogBookState
		{
			private int oldCategoryIndex;

			public int newCategoryIndex;

			public bool goToLastPage;

			public float duration = 0.1f;

			private GameObject oldPage;

			private GameObject newPage;

			private UnityEngine.Vector2 oldPageTargetPosition;

			private UnityEngine.Vector2 newPageTargetPosition;

			private UnityEngine.Vector2 moveDirection;

			private UnityEngine.Vector2 containerSize = UnityEngine.Vector2.zero;

			private NavigationPageInfo[] newNavigationPages;

			private int destinationPageIndex;

			private NavigationPageInfo newNavigationPageInfo;

			private int frame;

			public override void OnEnter()
			{
				base.OnEnter();
				if ((bool)logBookController)
				{
					oldCategoryIndex = logBookController.currentCategoryIndex;
					oldPage = logBookController.currentEntriesPageObject;
					newNavigationPages = logBookController.GetCategoryPages(newCategoryIndex);
					destinationPageIndex = newNavigationPages[0].index;
					if (goToLastPage)
					{
						destinationPageIndex = newNavigationPages[newNavigationPages.Length - 1].index;
						UnityEngine.Debug.LogFormat("goToLastPage=true destinationPageIndex={0}", destinationPageIndex);
					}
					newNavigationPageInfo = logBookController.allNavigationPages[destinationPageIndex];
					newPage = logBookController.BuildEntriesPage(newNavigationPageInfo);
					containerSize = logBookController.entryPageContainer.rect.size;
					moveDirection = new UnityEngine.Vector2(Mathf.Sign(newCategoryIndex - oldCategoryIndex), 0f);
				}
				SetPagePositions(0f);
			}

			public override void OnExit()
			{
				EntityState.Destroy(oldPage);
				if ((bool)logBookController)
				{
					logBookController.currentEntriesPageObject = newPage;
					logBookController.currentPageIndex = newNavigationPageInfo.indexInCategory;
					logBookController.desiredPageIndex = newNavigationPageInfo.indexInCategory;
					logBookController.currentCategoryIndex = newCategoryIndex;
					logBookController.availableNavigationPages = newNavigationPages;
					logBookController.currentCategoryLabel.token = categories[newCategoryIndex].nameToken;
					logBookController.categoryHightlightRect.SetParent(logBookController.navigationCategoryButtonAllocator.elements[newCategoryIndex].transform, worldPositionStays: false);
					logBookController.categoryHightlightRect.gameObject.SetActive(value: false);
					logBookController.categoryHightlightRect.gameObject.SetActive(value: true);
					if (logBookController.moveNavigationPageIndicatorContainerToCategoryButton)
					{
						logBookController.navigationPageIndicatorContainer.SetParent(logBookController.navigationCategoryButtonAllocator.elements[newCategoryIndex].transform, worldPositionStays: false);
					}
				}
				base.OnExit();
			}

			private void SetPagePositions(float t)
			{
				UnityEngine.Vector2 vector = new UnityEngine.Vector2(containerSize.x * (0f - moveDirection.x), containerSize.y * moveDirection.y);
				UnityEngine.Vector2 vector2 = vector * t;
				if ((bool)oldPage)
				{
					oldPage.transform.localPosition = vector2;
				}
				if ((bool)newPage)
				{
					newPage.transform.localPosition = vector2 - vector;
					if (frame == 4)
					{
						newPage.GetComponent<GridLayoutGroup>().enabled = false;
					}
				}
			}

			public override void Update()
			{
				base.Update();
				frame++;
				float num = Mathf.Clamp01(unscaledAge / duration);
				SetPagePositions(num);
				if (num == 1f)
				{
					outer.SetNextState(new EntityStates.Idle());
				}
			}
		}

		private class EnterLogViewState : LogBookState
		{
			public Texture iconTexture;

			public RectTransform startRectTransform;

			public RectTransform endRectTransform;

			public Entry entry;

			private GameObject flyingIcon;

			private RectTransform flyingIconTransform;

			private RawImage flyingIconImage;

			private float duration = 0.75f;

			private UnityEngine.Rect startRect;

			private UnityEngine.Rect midRect;

			private UnityEngine.Rect endRect;

			private bool submittedViewEntry;

			public override void OnEnter()
			{
				base.OnEnter();
				flyingIcon = new GameObject("FlyingIcon", typeof(RectTransform), typeof(CanvasRenderer), typeof(RawImage));
				flyingIconTransform = (RectTransform)flyingIcon.transform;
				flyingIconTransform.SetParent(logBookController.transform, worldPositionStays: false);
				flyingIconTransform.localScale = UnityEngine.Vector3.one;
				flyingIconImage = flyingIconTransform.GetComponent<RawImage>();
				flyingIconImage.texture = iconTexture;
				UnityEngine.Vector3[] array = new UnityEngine.Vector3[4];
				startRectTransform.GetWorldCorners(array);
				startRect = GetRectRelativeToParent(array);
				midRect = new UnityEngine.Rect(((RectTransform)logBookController.transform).rect.center, startRect.size);
				endRectTransform.GetWorldCorners(array);
				endRect = GetRectRelativeToParent(array);
				SetIconRect(startRect);
			}

			private void SetIconRect(UnityEngine.Rect rect)
			{
				flyingIconTransform.position = rect.position;
				flyingIconTransform.offsetMin = rect.min;
				flyingIconTransform.offsetMax = rect.max;
			}

			private UnityEngine.Rect GetRectRelativeToParent(UnityEngine.Vector3[] corners)
			{
				for (int i = 0; i < 4; i++)
				{
					corners[i] = logBookController.transform.InverseTransformPoint(corners[i]);
				}
				UnityEngine.Rect result = default(UnityEngine.Rect);
				result.xMin = corners[0].x;
				result.xMax = corners[2].x;
				result.yMin = corners[0].y;
				result.yMax = corners[2].y;
				return result;
			}

			private static UnityEngine.Rect RectFromWorldCorners(UnityEngine.Vector3[] corners)
			{
				UnityEngine.Rect result = default(UnityEngine.Rect);
				result.xMin = corners[0].x;
				result.xMax = corners[2].x;
				result.yMin = corners[0].y;
				result.yMax = corners[2].y;
				return result;
			}

			private static UnityEngine.Rect LerpRect(UnityEngine.Rect a, UnityEngine.Rect b, float t)
			{
				UnityEngine.Rect result = default(UnityEngine.Rect);
				result.min = UnityEngine.Vector2.LerpUnclamped(a.min, b.min, t);
				result.max = UnityEngine.Vector2.LerpUnclamped(a.max, b.max, t);
				return result;
			}

			public override void OnExit()
			{
				EntityState.Destroy(flyingIcon);
				base.OnExit();
			}

			public override void Update()
			{
				base.Update();
				float num = Mathf.Min(unscaledAge / duration, 1f);
				if (num < 0.1f)
				{
					Util.Remap(num, 0f, 0.1f, 0f, 1f);
					SetIconRect(startRect);
				}
				if (num < 0.2f)
				{
					float t = Util.Remap(num, 0.1f, 0.2f, 0f, 1f);
					SetIconRect(LerpRect(startRect, midRect, t));
				}
				else if (num < 0.4f)
				{
					Util.Remap(num, 0.2f, 0.4f, 0f, 1f);
					SetIconRect(midRect);
				}
				else if (num < 0.6f)
				{
					float t2 = Util.Remap(num, 0.4f, 0.6f, 0f, 1f);
					SetIconRect(LerpRect(midRect, endRect, t2));
				}
				else if (num < 1f)
				{
					float num2 = Util.Remap(num, 0.6f, 1f, 0f, 1f);
					flyingIconImage.color = new UnityEngine.Color(1f, 1f, 1f, 1f - num2);
					SetIconRect(endRect);
					if (!submittedViewEntry)
					{
						submittedViewEntry = true;
						logBookController.ViewEntry(entry);
					}
				}
				else
				{
					outer.SetNextState(new EntityStates.Idle());
				}
			}
		}

		[Header("Navigation")]
		public GameObject navigationPanel;

		public RectTransform categoryContainer;

		public GameObject categorySpaceFiller;

		public int categorySpaceFillerCount;

		public UnityEngine.Color spaceFillerColor;

		private UIElementAllocator<MPButton> navigationCategoryButtonAllocator;

		public RectTransform entryPageContainer;

		public GameObject entryPagePrefab;

		public RectTransform navigationPageIndicatorContainer;

		public GameObject navigationPageIndicatorPrefab;

		public bool moveNavigationPageIndicatorContainerToCategoryButton;

		private UIElementAllocator<MPButton> navigationPageIndicatorAllocator;

		public MPButton previousPageButton;

		public MPButton nextPageButton;

		public LanguageTextMeshController currentCategoryLabel;

		private RectTransform categoryHightlightRect;

		[Header("PageViewer")]
		public UnityEvent OnViewEntry;

		public GameObject pageViewerPanel;

		public MPButton pageViewerBackButton;

		[Header("Misc")]
		public GameObject categoryButtonPrefab;

		public GameObject headerHighlightPrefab;

		public LanguageTextMeshController hoverLanguageTextMeshController;

		public string hoverDescriptionFormatString;

		private EntityStateMachine stateMachine;

		private UILayerKey uiLayerKey;

		public static CategoryDef[] categories;

		public static ResourceAvailability availability;

		private static bool IsInitialized;

		public static bool IsStaticDataReady;

		private NavigationPageInfo[] _availableNavigationPages = Array.Empty<NavigationPageInfo>();

		private GameObject currentEntriesPageObject;

		private int currentCategoryIndex;

		private int desiredCategoryIndex;

		private int currentPageIndex;

		private int desiredPageIndex;

		private bool goToEndOfNextCategory;

		private NavigationPageInfo[] allNavigationPages;

		private NavigationPageInfo[][] navigationPagesByCategory;

		private static List<EntitlementDef> lastBuiltEntitlements;

		private NavigationPageInfo[] availableNavigationPages
		{
			get
			{
				return _availableNavigationPages;
			}
			set
			{
				int num = _availableNavigationPages.Length;
				_availableNavigationPages = value;
				if (num != availableNavigationPages.Length)
				{
					navigationPageIndicatorAllocator.AllocateElements(availableNavigationPages.Length);
				}
			}
		}

		public static event Action OnViewablesRegistered;

		private void Awake()
		{
			EntitlementManager.UpdateLocalUsersEntitlements();
			navigationCategoryButtonAllocator = new UIElementAllocator<MPButton>(categoryContainer, categoryButtonPrefab);
			navigationPageIndicatorAllocator = new UIElementAllocator<MPButton>(navigationPageIndicatorContainer, navigationPageIndicatorPrefab);
			navigationPageIndicatorAllocator.onCreateElement = delegate(int index, MPButton button)
			{
				button.onClick.AddListener(delegate
				{
					desiredPageIndex = index;
				});
			};
			previousPageButton.onClick.AddListener(OnLeftButton);
			nextPageButton.onClick.AddListener(OnRightButton);
			pageViewerBackButton.onClick.AddListener(ReturnToNavigation);
			stateMachine = base.gameObject.AddComponent<EntityStateMachine>();
			uiLayerKey = base.gameObject.GetComponent<UILayerKey>();
			stateMachine.initialStateType = default(SerializableEntityStateType);
			stateMachine.AllowStartWithoutNetworker = true;
			stateMachine.ShouldStateTransitionOnUpdate = true;
			categoryHightlightRect = (RectTransform)UnityEngine.Object.Instantiate(headerHighlightPrefab, base.transform.parent).transform;
			categoryHightlightRect.gameObject.SetActive(value: false);
		}

		private void Start()
		{
			GeneratePages(LocalUserManager.GetFirstLocalUser()?.userProfile);
			BuildCategoriesButtons();
			stateMachine.SetNextState(new ChangeCategoryState
			{
				newCategoryIndex = 0
			});
		}

		private void BuildCategoriesButtons()
		{
			navigationCategoryButtonAllocator.AllocateElements(categories.Length);
			ReadOnlyCollection<MPButton> elements = navigationCategoryButtonAllocator.elements;
			for (int i = 0; i < categories.Length; i++)
			{
				int categoryIndex = i;
				MPButton mPButton = elements[i];
				CategoryDef categoryDef = categories[i];
				mPButton.GetComponentInChildren<TextMeshProUGUI>().text = Language.GetString(categoryDef.nameToken);
				mPButton.onClick.RemoveAllListeners();
				mPButton.onClick.AddListener(delegate
				{
					OnCategoryClicked(categoryIndex);
				});
				mPButton.requiredTopLayer = uiLayerKey;
				ViewableTag viewableTag = mPButton.gameObject.GetComponent<ViewableTag>();
				if (!viewableTag)
				{
					viewableTag = mPButton.gameObject.AddComponent<ViewableTag>();
				}
				viewableTag.viewableName = categoryDef.viewableNode.fullName;
			}
			if ((bool)categorySpaceFiller)
			{
				for (int j = 0; j < categorySpaceFillerCount; j++)
				{
					UnityEngine.Object.Instantiate(categorySpaceFiller, categoryContainer).gameObject.SetActive(value: true);
				}
			}
		}

		public static IEnumerator Init()
		{
			if (LocalUserManager.isAnyUserSignedIn)
			{
				BuildStaticData();
			}
			yield return null;
			LocalUserManager.onUserSignIn += OnUserSignIn;
			BaseUserEntitlementTracker<LocalUser>.OnUserEntitlementsUpdated = (Action)Delegate.Combine(BaseUserEntitlementTracker<LocalUser>.OnUserEntitlementsUpdated, new Action(BuildStaticData));
			IsInitialized = true;
		}

		private static void OnUserSignIn(LocalUser obj)
		{
			BuildStaticData();
		}

		private static EntryStatus GetPickupStatus(in Entry entry, UserProfile viewerProfile)
		{
			UnlockableDef unlockableDef = null;
			PickupIndex pickupIndex = (PickupIndex)entry.extraData;
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			ItemIndex itemIndex = pickupDef?.itemIndex ?? ItemIndex.None;
			EquipmentIndex equipmentIndex = pickupDef?.equipmentIndex ?? EquipmentIndex.None;
			if (itemIndex != ItemIndex.None)
			{
				unlockableDef = ItemCatalog.GetItemDef(itemIndex).unlockableDef;
			}
			else
			{
				if (equipmentIndex == EquipmentIndex.None)
				{
					return EntryStatus.Unimplemented;
				}
				unlockableDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex).unlockableDef;
			}
			if (!viewerProfile.HasUnlockable(unlockableDef))
			{
				return EntryStatus.Locked;
			}
			if (!viewerProfile.HasDiscoveredPickup(pickupIndex))
			{
				return EntryStatus.Unencountered;
			}
			return EntryStatus.Available;
		}

		private static TooltipContent GetPickupTooltipContent(in Entry entry, UserProfile userProfile, EntryStatus status)
		{
			UnlockableDef unlockableDef = PickupCatalog.GetPickupDef((PickupIndex)entry.extraData).unlockableDef;
			TooltipContent result = default(TooltipContent);
			if (status >= EntryStatus.Available)
			{
				result.overrideTitleText = entry.GetDisplayName(userProfile);
				result.titleColor = entry.color;
				if (unlockableDef != null)
				{
					result.overrideBodyText = unlockableDef.getUnlockedString();
				}
				result.bodyToken = "";
				result.bodyColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Unlockable);
			}
			else
			{
				result.titleToken = "UNIDENTIFIED";
				result.titleColor = UnityEngine.Color.gray;
				result.bodyToken = "";
				switch (status)
				{
				case EntryStatus.Unimplemented:
					result.titleToken = "TOOLTIP_WIP_CONTENT_NAME";
					result.bodyToken = "TOOLTIP_WIP_CONTENT_DESCRIPTION";
					break;
				case EntryStatus.Unencountered:
					result.overrideBodyText = Language.GetString("LOGBOOK_UNLOCK_ITEM_LOG");
					break;
				case EntryStatus.Locked:
					result.overrideBodyText = unlockableDef.getHowToUnlockString();
					break;
				}
				result.bodyColor = UnityEngine.Color.white;
			}
			return result;
		}

		private static TooltipContent GetMonsterTooltipContent(in Entry entry, UserProfile userProfile, EntryStatus status)
		{
			TooltipContent result = default(TooltipContent);
			result.titleColor = entry.color;
			if (status >= EntryStatus.Available)
			{
				result.overrideTitleText = entry.GetDisplayName(userProfile);
				result.titleColor = entry.color;
				result.bodyToken = "";
			}
			else
			{
				result.titleToken = "UNIDENTIFIED";
				result.titleColor = UnityEngine.Color.gray;
				result.bodyToken = "LOGBOOK_UNLOCK_ITEM_MONSTER";
			}
			return result;
		}

		private static TooltipContent GetStageTooltipContent(in Entry entry, UserProfile userProfile, EntryStatus status)
		{
			TooltipContent result = default(TooltipContent);
			result.titleColor = entry.color;
			if (status >= EntryStatus.Available)
			{
				result.overrideTitleText = entry.GetDisplayName(userProfile);
				result.titleColor = entry.color;
				result.bodyToken = "";
			}
			else
			{
				result.titleToken = "UNIDENTIFIED";
				result.titleColor = UnityEngine.Color.gray;
				result.bodyToken = "LOGBOOK_UNLOCK_ITEM_STAGE";
			}
			return result;
		}

		private static TooltipContent GetSurvivorTooltipContent(in Entry entry, UserProfile userProfile, EntryStatus status)
		{
			TooltipContent result = default(TooltipContent);
			UnlockableDef unlockableDef = SurvivorCatalog.FindSurvivorDefFromBody(((CharacterBody)entry.extraData).gameObject).unlockableDef;
			if (status >= EntryStatus.Available)
			{
				result.overrideTitleText = entry.GetDisplayName(userProfile);
				result.titleColor = entry.color;
				result.bodyToken = "";
			}
			else
			{
				result.titleToken = "UNIDENTIFIED";
				result.bodyToken = "";
				result.titleColor = UnityEngine.Color.gray;
				switch (status)
				{
				case EntryStatus.Unencountered:
					result.overrideBodyText = Language.GetString("LOGBOOK_UNLOCK_ITEM_SURVIVOR");
					break;
				case EntryStatus.Locked:
					result.overrideBodyText = unlockableDef.getHowToUnlockString();
					break;
				}
			}
			return result;
		}

		private static TooltipContent GetAchievementTooltipContent(in Entry entry, UserProfile userProfile, EntryStatus status)
		{
			TooltipContent result = default(TooltipContent);
			UnlockableDef unlockableDef = UnlockableCatalog.GetUnlockableDef(((AchievementDef)entry.extraData).unlockableRewardIdentifier);
			result.titleColor = entry.color;
			result.bodyToken = "";
			if (unlockableDef == null)
			{
				result.overrideTitleText = entry.GetDisplayName(userProfile);
				result.titleColor = UnityEngine.Color.gray;
				result.overrideBodyText = "ACHIEVEMENT HAS NO UNLOCKABLE DEFINED";
				result.bodyColor = UnityEngine.Color.white;
				return result;
			}
			if (status >= EntryStatus.Available)
			{
				result.titleToken = entry.GetDisplayName(userProfile);
				result.titleColor = entry.color;
				result.overrideBodyText = unlockableDef.getUnlockedString();
			}
			else
			{
				result.titleToken = "UNIDENTIFIED";
				result.titleColor = UnityEngine.Color.gray;
				if (status == EntryStatus.Locked)
				{
					result.overrideBodyText = Language.GetString("UNIDENTIFIED_DESCRIPTION");
				}
				else
				{
					result.overrideBodyText = unlockableDef.getHowToUnlockString();
				}
			}
			return result;
		}

		private static TooltipContent GetWIPTooltipContent(in Entry entry, UserProfile userProfile, EntryStatus status)
		{
			TooltipContent result = default(TooltipContent);
			result.titleColor = ColorCatalog.GetColor(ColorCatalog.ColorIndex.WIP);
			result.titleToken = "TOOLTIP_WIP_CONTENT_NAME";
			result.bodyToken = "TOOLTIP_WIP_CONTENT_DESCRIPTION";
			return result;
		}

		private static EntryStatus GetAlwaysAvailable(UserProfile userProfile, Entry entry)
		{
			return EntryStatus.Available;
		}

		private static EntryStatus GetUnimplemented(in Entry entry, UserProfile viewerProfile)
		{
			return EntryStatus.Unimplemented;
		}

		private static EntryStatus GetStageStatus(in Entry entry, UserProfile viewerProfile)
		{
			UnlockableDef unlockableLogFromBaseSceneName = SceneCatalog.GetUnlockableLogFromBaseSceneName((entry.extraData as SceneDef).baseSceneName);
			if (unlockableLogFromBaseSceneName != null && viewerProfile.HasUnlockable(unlockableLogFromBaseSceneName))
			{
				return EntryStatus.Available;
			}
			return EntryStatus.Unencountered;
		}

		private static EntryStatus GetMonsterStatus(in Entry entry, UserProfile viewerProfile)
		{
			CharacterBody characterBody = (CharacterBody)entry.extraData;
			UnlockableDef unlockableDef = characterBody.GetComponent<DeathRewards>()?.logUnlockableDef;
			if (!unlockableDef)
			{
				return EntryStatus.None;
			}
			if (viewerProfile.HasUnlockable(unlockableDef))
			{
				return EntryStatus.Available;
			}
			if (viewerProfile.statSheet.GetStatValueULong(PerBodyStatDef.killsAgainst, characterBody.gameObject.name) != 0)
			{
				return EntryStatus.Unencountered;
			}
			return EntryStatus.Locked;
		}

		private static EntryStatus GetSurvivorStatus(in Entry entry, UserProfile viewerProfile)
		{
			CharacterBody characterBody = (CharacterBody)entry.extraData;
			SurvivorDef survivorDef = SurvivorCatalog.FindSurvivorDefFromBody(characterBody.gameObject);
			if (!viewerProfile.HasUnlockable(survivorDef.unlockableDef))
			{
				return EntryStatus.Locked;
			}
			if (viewerProfile.statSheet.GetStatValueULong(PerBodyStatDef.totalWins, characterBody.gameObject.name) == 0L)
			{
				return EntryStatus.Unencountered;
			}
			return EntryStatus.Available;
		}

		private static EntryStatus GetAchievementStatus(in Entry entry, UserProfile viewerProfile)
		{
			string identifier = ((AchievementDef)entry.extraData).identifier;
			bool flag = viewerProfile.HasAchievement(identifier);
			if (!viewerProfile.CanSeeAchievement(identifier))
			{
				return EntryStatus.Locked;
			}
			if (!flag)
			{
				return EntryStatus.Unencountered;
			}
			return EntryStatus.Available;
		}

		private static void BuildStaticData()
		{
			RoR2Application.instance.StartCoroutine(WaitForBuildingStaticData());
		}

		static LogBookController()
		{
			categories = Array.Empty<CategoryDef>();
			availability = default(ResourceAvailability);
			IsInitialized = false;
			IsStaticDataReady = false;
			lastBuiltEntitlements = null;
		}

		private NavigationPageInfo[] GetCategoryPages(int categoryIndex)
		{
			if (navigationPagesByCategory.GetLength(0) <= categoryIndex)
			{
				return new NavigationPageInfo[0];
			}
			return navigationPagesByCategory[categoryIndex];
		}

		public void OnLeftButton()
		{
			desiredPageIndex--;
		}

		public void OnRightButton()
		{
			desiredPageIndex++;
		}

		private void OnCategoryClicked(int categoryIndex)
		{
			desiredCategoryIndex = categoryIndex;
			goToEndOfNextCategory = false;
		}

		public void OnCategoryLeftButton()
		{
			desiredCategoryIndex--;
			goToEndOfNextCategory = false;
		}

		public void OnCategoryRightButton()
		{
			desiredCategoryIndex++;
			goToEndOfNextCategory = false;
		}

		private void GeneratePages(UserProfile viewerProfile)
		{
			if (!IsInitialized)
			{
				Init();
			}
			navigationPagesByCategory = new NavigationPageInfo[categories.Length][];
			IEnumerable<NavigationPageInfo> enumerable = Array.Empty<NavigationPageInfo>();
			int num = 0;
			for (int i = 0; i < categories.Length; i++)
			{
				CategoryDef categoryDef = categories[i];
				Entry[] array = categoryDef.BuildEntries(viewerProfile);
				bool fullWidth = categoryDef.fullWidth;
				UnityEngine.Vector2 size = entryPageContainer.rect.size;
				if (fullWidth)
				{
					categoryDef.iconSize.x = size.x;
				}
				int num2 = Mathf.FloorToInt(Mathf.Max(size.x / categoryDef.iconSize.x, 1f));
				int num3 = Mathf.FloorToInt(Mathf.Max(size.y / categoryDef.iconSize.y, 1f));
				int num4 = num2 * num3;
				int num5 = Mathf.CeilToInt((float)array.Length / (float)num4);
				if (num5 <= 0)
				{
					num5 = 1;
				}
				NavigationPageInfo[] array2 = new NavigationPageInfo[num5];
				for (int j = 0; j < num5; j++)
				{
					int num6 = j * num4;
					int num7 = array.Length - num6;
					int num8 = num4;
					if (num8 > num7)
					{
						num8 = num7;
					}
					Entry[] array3 = new Entry[num4];
					Array.Copy(array, num6, array3, 0, num8);
					NavigationPageInfo navigationPageInfo = new NavigationPageInfo();
					navigationPageInfo.categoryDef = categoryDef;
					navigationPageInfo.entries = array3;
					navigationPageInfo.index = num++;
					navigationPageInfo.indexInCategory = j;
					array2[j] = navigationPageInfo;
				}
				navigationPagesByCategory[i] = array2;
				enumerable = enumerable.Concat(array2);
			}
			allNavigationPages = enumerable.ToArray();
		}

		private void Update()
		{
			if (desiredPageIndex > availableNavigationPages.Length - 1)
			{
				desiredPageIndex = availableNavigationPages.Length - 1;
				desiredCategoryIndex++;
				goToEndOfNextCategory = false;
			}
			if (desiredPageIndex < 0)
			{
				desiredCategoryIndex--;
				desiredPageIndex = 0;
				goToEndOfNextCategory = true;
			}
			if (desiredCategoryIndex > categories.Length - 1)
			{
				desiredCategoryIndex = 0;
				goToEndOfNextCategory = false;
			}
			if (desiredCategoryIndex < 0)
			{
				desiredCategoryIndex = categories.Length - 1;
				goToEndOfNextCategory = true;
			}
			foreach (MPButton element in navigationPageIndicatorAllocator.elements)
			{
				ColorBlock colors = element.colors;
				colors.colorMultiplier = 1f;
				element.colors = colors;
			}
			if (currentPageIndex < navigationPageIndicatorAllocator.elements.Count)
			{
				MPButton mPButton = navigationPageIndicatorAllocator.elements[currentPageIndex];
				ColorBlock colors2 = mPButton.colors;
				colors2.colorMultiplier = 2f;
				mPButton.colors = colors2;
			}
			if (desiredCategoryIndex != currentCategoryIndex)
			{
				if (stateMachine.state is EntityStates.Idle)
				{
					int num = ((desiredCategoryIndex > currentCategoryIndex) ? 1 : (-1));
					stateMachine.SetNextState(new ChangeCategoryState
					{
						newCategoryIndex = currentCategoryIndex + num,
						goToLastPage = goToEndOfNextCategory
					});
				}
			}
			else if (desiredPageIndex != currentPageIndex && stateMachine.state is EntityStates.Idle)
			{
				int num2 = ((desiredPageIndex > currentPageIndex) ? 1 : (-1));
				stateMachine.SetNextState(new ChangeEntriesPageState
				{
					newNavigationPageInfo = GetCategoryPages(currentCategoryIndex)[currentPageIndex + num2],
					moveDirection = new UnityEngine.Vector2(num2, 0f)
				});
			}
		}

		private UserProfile LookUpUserProfile()
		{
			return LocalUserManager.readOnlyLocalUsersList.FirstOrDefault((LocalUser v) => v != null)?.userProfile;
		}

		private GameObject BuildEntriesPage(NavigationPageInfo navigationPageInfo)
		{
			Entry[] entries = navigationPageInfo.entries;
			CategoryDef categoryDef = navigationPageInfo.categoryDef;
			GameObject gameObject = UnityEngine.Object.Instantiate(entryPagePrefab, entryPageContainer);
			GridLayoutGroup component = gameObject.GetComponent<GridLayoutGroup>();
			component.cellSize = categoryDef.iconSize;
			component.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
			float num = entryPageContainer.rect.width - (float)component.padding.left - (float)component.padding.right;
			component.constraintCount = (int)(num / (component.cellSize.x + component.spacing.x));
			UIElementAllocator<RectTransform> uIElementAllocator = new UIElementAllocator<RectTransform>((RectTransform)gameObject.transform, categoryDef.iconPrefab);
			uIElementAllocator.AllocateElements(entries.Length);
			UserProfile userProfile = LookUpUserProfile();
			ReadOnlyCollection<RectTransform> elements = uIElementAllocator.elements;
			for (int i = 0; i < elements.Count; i++)
			{
				RectTransform rectTransform = elements[i];
				HGButton component2 = rectTransform.GetComponent<HGButton>();
				Entry entry = ((i < entries.Length) ? entries[i] : null);
				EntryStatus entryStatus = entry?.GetStatus(userProfile) ?? EntryStatus.None;
				if (entryStatus != 0)
				{
					TooltipContent tooltipContent = entry.GetTooltipContent(userProfile, entryStatus);
					categoryDef.initializeElementGraphics?.Invoke(rectTransform.gameObject, entry, entryStatus, userProfile);
					if ((bool)component2)
					{
						UnityEngine.UI.Navigation navigation = component2.navigation;
						navigation.mode = UnityEngine.UI.Navigation.Mode.Explicit;
						int index = (i + elements.Count - 1) % elements.Count;
						navigation.selectOnLeft = elements[index].GetComponent<HGButton>();
						int index2 = (i + elements.Count + 1) % elements.Count;
						navigation.selectOnRight = elements[index2].GetComponent<HGButton>();
						if (i - component.constraintCount >= 0)
						{
							navigation.selectOnUp = elements[i - component.constraintCount].GetComponent<HGButton>();
						}
						if (i + component.constraintCount < elements.Count)
						{
							navigation.selectOnDown = elements[i + component.constraintCount].GetComponent<HGButton>();
						}
						component2.navigation = navigation;
						bool flag = entryStatus >= EntryStatus.Available;
						component2.interactable = true;
						component2.disableGamepadClick = component2.disableGamepadClick || !flag;
						component2.disablePointerClick = component2.disablePointerClick || !flag;
						component2.imageOnInteractable = (flag ? component2.imageOnInteractable : null);
						component2.requiredTopLayer = uiLayerKey;
						component2.updateTextOnHover = true;
						component2.hoverLanguageTextMeshController = hoverLanguageTextMeshController;
						string titleText = tooltipContent.GetTitleText();
						string bodyText = tooltipContent.GetBodyText();
						UnityEngine.Color titleColor = tooltipContent.titleColor;
						titleColor.a = 0.2f;
						component2.hoverToken = Language.GetStringFormatted("LOGBOOK_HOVER_DESCRIPTION_FORMAT", titleText, bodyText, ColorUtility.ToHtmlStringRGBA(titleColor));
					}
					if (entry.viewableNode != null)
					{
						ViewableTag viewableTag = rectTransform.gameObject.GetComponent<ViewableTag>();
						if (!viewableTag)
						{
							viewableTag = rectTransform.gameObject.AddComponent<ViewableTag>();
							viewableTag.viewableVisualStyle = ViewableTag.ViewableVisualStyle.Icon;
						}
						viewableTag.viewableName = entry.viewableNode.fullName;
					}
				}
				if (entryStatus >= EntryStatus.Available && (bool)component2)
				{
					component2.onClick.AddListener(delegate
					{
						ViewEntry(entry);
					});
				}
				if (entryStatus == EntryStatus.None)
				{
					if ((bool)component2)
					{
						component2.enabled = false;
						component2.targetGraphic.color = spaceFillerColor;
					}
					else
					{
						rectTransform.GetComponent<UnityEngine.UI.Image>().color = spaceFillerColor;
					}
					for (int num2 = rectTransform.childCount - 1; num2 >= 0; num2--)
					{
						UnityEngine.Object.Destroy(rectTransform.GetChild(num2).gameObject);
					}
				}
				if ((bool)component2 && i == 0)
				{
					component2.defaultFallbackButton = true;
				}
			}
			gameObject.gameObject.SetActive(value: true);
			GridLayoutGroup gridLayoutGroup = gameObject.GetComponent<GridLayoutGroup>();
			Action destroyLayoutGroup = null;
			int frameTimer = 2;
			destroyLayoutGroup = delegate
			{
				int num3 = frameTimer - 1;
				frameTimer = num3;
				if (frameTimer <= 0)
				{
					gridLayoutGroup.enabled = false;
					RoR2Application.onLateUpdate -= destroyLayoutGroup;
				}
			};
			RoR2Application.onLateUpdate += destroyLayoutGroup;
			return gameObject;
		}

		private void ViewEntry(Entry entry)
		{
			OnViewEntry.Invoke();
			LogBookPage component = pageViewerPanel.GetComponent<LogBookPage>();
			component.SetEntry(LookUpUserProfile(), entry);
			component.modelPanel.SetAnglesForCharacterThumbnailForSeconds(0.5f);
			ViewableTrigger.TriggerView(entry.viewableNode?.fullName);
		}

		private void ReturnToNavigation()
		{
			navigationPanel.SetActive(value: true);
			pageViewerPanel.SetActive(value: false);
		}

		private static bool UnlockableExists(UnlockableDef unlockableDef)
		{
			return unlockableDef;
		}

		private static bool IsEntryBodyWithoutLore(in Entry entry)
		{
			CharacterBody obj = (CharacterBody)entry.extraData;
			bool flag = false;
			string text = "";
			string baseNameToken = obj.baseNameToken;
			if (!string.IsNullOrEmpty(baseNameToken))
			{
				text = baseNameToken.Replace("_NAME", "_LORE");
				if (Language.english.TokenIsRegistered(text))
				{
					flag = true;
				}
			}
			return !flag;
		}

		private static bool IsEntryPickupItemWithoutLore(in Entry entry)
		{
			ItemDef itemDef = ItemCatalog.GetItemDef(PickupCatalog.GetPickupDef((PickupIndex)entry.extraData).itemIndex);
			return !Language.english.TokenIsRegistered(itemDef.loreToken);
		}

		private static bool IsEntryPickupEquipmentWithoutLore(in Entry entry)
		{
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(PickupCatalog.GetPickupDef((PickupIndex)entry.extraData).equipmentIndex);
			return !Language.english.TokenIsRegistered(equipmentDef.loreToken);
		}

		private static bool CanSelectItemEntry(ItemDef itemDef, Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			if (itemDef != null)
			{
				ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(itemDef.tier);
				if ((bool)itemTierDef && itemTierDef.isDroppable)
				{
					if (!(itemDef.requiredExpansion == null) && expansionAvailability.ContainsKey(itemDef.requiredExpansion))
					{
						return expansionAvailability[itemDef.requiredExpansion];
					}
					return true;
				}
				return false;
			}
			return false;
		}

		private static bool CanSelectEquipmentEntry(EquipmentDef equipmentDef, Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			if (equipmentDef != null)
			{
				if (equipmentDef.canDrop)
				{
					if (!(equipmentDef.requiredExpansion == null) && expansionAvailability.ContainsKey(equipmentDef.requiredExpansion))
					{
						return expansionAvailability[equipmentDef.requiredExpansion];
					}
					return true;
				}
				return false;
			}
			return false;
		}

		private static Entry[] BuildPickupEntries(Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			new Entry
			{
				nameToken = "TOOLTIP_WIP_CONTENT_NAME",
				color = UnityEngine.Color.white,
				iconTexture = LegacyResourcesAPI.Load<Texture>("Textures/MiscIcons/texWIPIcon"),
				getStatusImplementation = GetUnimplemented,
				getTooltipContentImplementation = GetWIPTooltipContent
			};
			IEnumerable<Entry> first = from pickupDef in PickupCatalog.allPickups
				select ItemCatalog.GetItemDef(pickupDef.itemIndex) into itemDef
				where CanSelectItemEntry(itemDef, expansionAvailability)
				orderby (int)(itemDef.tier + ((itemDef.tier == ItemTier.Lunar) ? 100 : 0))
				select new Entry
				{
					nameToken = itemDef.nameToken,
					color = ColorCatalog.GetColor(itemDef.darkColorIndex),
					iconTexture = itemDef.pickupIconTexture,
					bgTexture = itemDef.bgIconTexture,
					extraData = PickupCatalog.FindPickupIndex(itemDef.itemIndex),
					modelPrefab = itemDef.pickupModelPrefab,
					getStatusImplementation = GetPickupStatus,
					getTooltipContentImplementation = GetPickupTooltipContent,
					pageBuilderMethod = PageBuilder.SimplePickup,
					isWIPImplementation = IsEntryPickupItemWithoutLore
				};
			IEnumerable<Entry> second = from pickupDef in PickupCatalog.allPickups
				select EquipmentCatalog.GetEquipmentDef(pickupDef.equipmentIndex) into equipmentDef
				where CanSelectEquipmentEntry(equipmentDef, expansionAvailability)
				orderby !equipmentDef.isLunar
				select new Entry
				{
					nameToken = equipmentDef.nameToken,
					color = ColorCatalog.GetColor(equipmentDef.colorIndex),
					iconTexture = equipmentDef.pickupIconTexture,
					bgTexture = equipmentDef.bgIconTexture,
					extraData = PickupCatalog.FindPickupIndex(equipmentDef.equipmentIndex),
					modelPrefab = equipmentDef.pickupModelPrefab,
					getStatusImplementation = GetPickupStatus,
					getTooltipContentImplementation = GetPickupTooltipContent,
					pageBuilderMethod = PageBuilder.SimplePickup,
					isWIPImplementation = IsEntryPickupEquipmentWithoutLore
				};
			return first.Concat(second).ToArray();
		}

		private static bool CanSelectMonsterEntry(CharacterBody characterBody, Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			if ((bool)characterBody)
			{
				ExpansionRequirementComponent component = characterBody.GetComponent<ExpansionRequirementComponent>();
				if (!component || !component.requiredExpansion || !expansionAvailability.ContainsKey(component.requiredExpansion) || expansionAvailability[component.requiredExpansion])
				{
					return UnlockableExists(characterBody.GetComponent<DeathRewards>()?.logUnlockableDef);
				}
				return false;
			}
			return false;
		}

		private static Entry[] BuildMonsterEntries(Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			Entry[] array = (from characterBody in BodyCatalog.allBodyPrefabBodyBodyComponents
				where CanSelectMonsterEntry(characterBody, expansionAvailability)
				orderby characterBody.baseMaxHealth
				select new Entry
				{
					nameToken = characterBody.baseNameToken,
					color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.HardDifficulty),
					iconTexture = characterBody.portraitIcon,
					extraData = characterBody,
					modelPrefab = characterBody.GetComponent<ModelLocator>()?.modelTransform?.gameObject,
					getStatusImplementation = GetMonsterStatus,
					getTooltipContentImplementation = GetMonsterTooltipContent,
					pageBuilderMethod = PageBuilder.MonsterBody,
					bgTexture = (characterBody.isChampion ? LegacyResourcesAPI.Load<Texture>("Textures/ItemIcons/BG/texTier3BGIcon") : LegacyResourcesAPI.Load<Texture>("Textures/ItemIcons/BG/texTier1BGIcon")),
					isWIPImplementation = IsEntryBodyWithoutLore
				}).ToArray();
			Dictionary<string, Entry> dictionary = new Dictionary<string, Entry>();
			Entry[] array2 = array;
			foreach (Entry entry in array2)
			{
				if (!dictionary.ContainsKey(entry.nameToken))
				{
					dictionary.Add(entry.nameToken, entry);
				}
			}
			return dictionary.Values.ToArray();
		}

		private static bool CanSelectStageEntry(SceneDef sceneDef, Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			if ((bool)sceneDef)
			{
				ExpansionDef requiredExpansion = sceneDef.requiredExpansion;
				if (!requiredExpansion || !expansionAvailability.ContainsKey(requiredExpansion) || expansionAvailability[requiredExpansion])
				{
					return sceneDef.shouldIncludeInLogbook;
				}
				return false;
			}
			return false;
		}

		private static Entry[] BuildStageEntries(Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			return (from sceneDef in SceneCatalog.allSceneDefs
				where CanSelectStageEntry(sceneDef, expansionAvailability)
				orderby sceneDef.stageOrder
				select new Entry
				{
					nameToken = sceneDef.nameToken,
					iconTexture = sceneDef.previewTexture,
					color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.Tier2ItemDark),
					getStatusImplementation = GetStageStatus,
					modelPrefab = sceneDef.dioramaPrefab,
					getTooltipContentImplementation = GetStageTooltipContent,
					pageBuilderMethod = PageBuilder.Stage,
					extraData = sceneDef,
					isWIPImplementation = delegate(in Entry entry)
					{
						return !Language.english.TokenIsRegistered(((SceneDef)entry.extraData).loreToken);
					}
				}).ToArray();
		}

		private static bool CanSelectSurvivorBodyEntry(CharacterBody body, Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			if ((bool)body)
			{
				ExpansionRequirementComponent component = body.GetComponent<ExpansionRequirementComponent>();
				if ((bool)component && (bool)component.requiredExpansion && expansionAvailability.ContainsKey(component.requiredExpansion))
				{
					return expansionAvailability[component.requiredExpansion];
				}
				return true;
			}
			return false;
		}

		private static Entry[] BuildSurvivorEntries(Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			return (from survivorDef in SurvivorCatalog.orderedSurvivorDefs
				select BodyCatalog.GetBodyPrefabBodyComponent(SurvivorCatalog.GetBodyIndexFromSurvivorIndex(survivorDef.survivorIndex)) into body
				where CanSelectSurvivorBodyEntry(body, expansionAvailability)
				select body into characterBody
				select new Entry
				{
					nameToken = characterBody.baseNameToken,
					color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.NormalDifficulty),
					iconTexture = characterBody.portraitIcon,
					bgTexture = LegacyResourcesAPI.Load<Texture>("Textures/ItemIcons/BG/texSurvivorBGIcon"),
					extraData = characterBody,
					modelPrefab = characterBody.GetComponent<ModelLocator>()?.modelTransform?.gameObject,
					getStatusImplementation = GetSurvivorStatus,
					getTooltipContentImplementation = GetSurvivorTooltipContent,
					pageBuilderMethod = PageBuilder.SurvivorBody,
					isWIPImplementation = IsEntryBodyWithoutLore
				}).ToArray();
		}

		private static bool CanSelectAchievementEntry(AchievementDef achievementDef, Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			if (achievementDef != null)
			{
				ExpansionDef expansionDefForUnlockable = UnlockableCatalog.GetExpansionDefForUnlockable(UnlockableCatalog.GetUnlockableDef(achievementDef.unlockableRewardIdentifier)?.index ?? UnlockableIndex.None);
				if ((bool)expansionDefForUnlockable && expansionAvailability.ContainsKey(expansionDefForUnlockable))
				{
					return expansionAvailability[expansionDefForUnlockable];
				}
				return true;
			}
			return false;
		}

		private static Entry[] BuildAchievementEntries(Dictionary<ExpansionDef, bool> expansionAvailability)
		{
			return (from achievementDef in AchievementManager.allAchievementDefs
				where CanSelectAchievementEntry(achievementDef, expansionAvailability)
				select new Entry
				{
					nameToken = achievementDef.nameToken,
					color = ColorCatalog.GetColor(ColorCatalog.ColorIndex.NormalDifficulty),
					iconTexture = achievementDef.GetAchievedIcon()?.texture,
					extraData = achievementDef,
					modelPrefab = null,
					getStatusImplementation = GetAchievementStatus,
					getTooltipContentImplementation = GetAchievementTooltipContent
				}).ToArray();
		}

		private static Entry[] BuildProfileEntries(UserProfile viewerProfile)
		{
			List<Entry> entries = new List<Entry>();
			if (true)
			{
				foreach (string availableProfileName in PlatformSystems.saveSystem.GetAvailableProfileNames())
				{
					AddProfileStatsEntry(PlatformSystems.saveSystem.GetProfile(availableProfileName));
				}
			}
			else if (viewerProfile != null)
			{
				AddProfileStatsEntry(viewerProfile);
			}
			return entries.ToArray();
			void AddProfileStatsEntry(UserProfile userProfile)
			{
				Entry item = new Entry
				{
					pageBuilderMethod = PageBuilder.StatsPanel,
					getStatusImplementation = delegate
					{
						return EntryStatus.Available;
					},
					extraData = userProfile,
					getDisplayNameImplementation = delegate(in Entry entry, UserProfile _viewerProfile)
					{
						return ((UserProfile)entry.extraData).name;
					},
					iconTexture = userProfile.portraitTexture
				};
				entries.Add(item);
			}
		}

		private static Entry[] BuildMorgueEntries(UserProfile viewerProfile)
		{
			List<Entry> entries = CollectionPool<Entry, List<Entry>>.RentCollection();
			List<RunReport> list = CollectionPool<RunReport, List<RunReport>>.RentCollection();
			MorgueManager.LoadHistoryRunReports(list);
			foreach (RunReport item2 in list)
			{
				AddRunReportEntry(item2);
			}
			CollectionPool<RunReport, List<RunReport>>.ReturnCollection(list);
			Entry[] result = entries.ToArray();
			CollectionPool<Entry, List<Entry>>.ReturnCollection(entries);
			return result;
			void AddRunReportEntry(RunReport runReport)
			{
				GetPrimaryPlayerInfo(runReport, out var _, out var primaryPlayerBody3);
				Entry item = new Entry
				{
					pageBuilderMethod = PageBuilder.RunReportPanel,
					getStatusImplementation = GetEntryStatus,
					extraData = runReport,
					getDisplayNameImplementation = GetDisplayName,
					getTooltipContentImplementation = GetTooltipContent,
					iconTexture = primaryPlayerBody3?.portraitIcon
				};
				entries.Add(item);
			}
			static string GetDisplayName(in Entry entry, UserProfile _viewerProfile)
			{
				return ((RunReport)entry.extraData).snapshotTimeUtc.ToLocalTime().ToString("G", CultureInfo.CurrentCulture);
			}
			static EntryStatus GetEntryStatus(in Entry entry, UserProfile _viewerProfile)
			{
				return EntryStatus.Available;
			}
			void GetPrimaryPlayerInfo(RunReport _runReport, out RunReport.PlayerInfo primaryPlayerInfo, out CharacterBody primaryPlayerBody)
			{
				primaryPlayerInfo = _runReport.FindPlayerInfo(viewerProfile) ?? _runReport.FindFirstPlayerInfo();
				primaryPlayerBody = BodyCatalog.GetBodyPrefabBodyComponent(primaryPlayerInfo?.bodyIndex ?? BodyIndex.None);
			}
			TooltipContent GetTooltipContent(in Entry entry, UserProfile _viewerProfile, EntryStatus entryStatus)
			{
				RunReport runReport2 = (RunReport)entry.extraData;
				GetPrimaryPlayerInfo(runReport2, out var _, out var primaryPlayerBody2);
				TooltipContent result2 = default(TooltipContent);
				result2.overrideTitleText = Language.GetStringFormatted("LOGBOOK_ENTRY_RUNREPORT_TOOLTIP_TITLE_FORMAT", runReport2.snapshotTimeUtc.ToLocalTime().ToString("G", CultureInfo.CurrentCulture));
				result2.overrideBodyText = Language.GetStringFormatted("LOGBOOK_ENTRY_RUNREPORT_TOOLTIP_BODY_FORMAT", Language.GetString(primaryPlayerBody2?.baseNameToken ?? string.Empty), Language.GetString(runReport2.gameMode?.nameToken ?? string.Empty), Language.GetString(runReport2.gameEnding?.endingTextToken ?? string.Empty));
				return result2;
			}
		}

		private static IEnumerator WaitForBuildingStaticData()
		{
			IsStaticDataReady = false;
			Dictionary<ExpansionDef, bool> expansionAvailability = new Dictionary<ExpansionDef, bool>();
			List<EntitlementDef> list = new List<EntitlementDef>();
			foreach (ExpansionDef expansionDef in ExpansionCatalog.expansionDefs)
			{
				expansionAvailability.Add(expansionDef, !expansionDef.requiredEntitlement || EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(expansionDef.requiredEntitlement));
				if (expansionAvailability[expansionDef])
				{
					list.Add(expansionDef.requiredEntitlement);
				}
			}
			if (lastBuiltEntitlements != null && lastBuiltEntitlements.SequenceEqual(list))
			{
				lastBuiltEntitlements = list;
				IsStaticDataReady = true;
				yield break;
			}
			lastBuiltEntitlements = list;
			yield return null;
			Entry[] pickupEntries = BuildPickupEntries(expansionAvailability);
			yield return null;
			Entry[] monsterEntries = BuildMonsterEntries(expansionAvailability);
			yield return null;
			Entry[] stageEntries = BuildStageEntries(expansionAvailability);
			yield return null;
			Entry[] survivorEntries = BuildSurvivorEntries(expansionAvailability);
			yield return null;
			Entry[] achievementEntries = BuildAchievementEntries(expansionAvailability);
			yield return null;
			categories = new CategoryDef[7]
			{
				new CategoryDef
				{
					nameToken = "LOGBOOK_CATEGORY_ITEMANDEQUIPMENT",
					iconPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/ItemEntryIcon"),
					buildEntries = (UserProfile viewerProfile) => pickupEntries,
					navButtons = new CategoryDef.NavButtons
					{
						navigate = "LOGBOOK_ZOOMINOUT"
					}
				},
				new CategoryDef
				{
					nameToken = "LOGBOOK_CATEGORY_MONSTER",
					iconPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/MonsterEntryIcon"),
					buildEntries = (UserProfile viewerProfile) => monsterEntries,
					navButtons = new CategoryDef.NavButtons
					{
						navigate = "LOGBOOK_ZOOMINOUT"
					}
				},
				new CategoryDef
				{
					nameToken = "LOGBOOK_CATEGORY_STAGE",
					iconPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/StageEntryIcon"),
					buildEntries = (UserProfile viewerProfile) => stageEntries
				},
				new CategoryDef
				{
					nameToken = "LOGBOOK_CATEGORY_SURVIVOR",
					iconPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/SurvivorEntryIcon"),
					buildEntries = (UserProfile viewerProfile) => survivorEntries
				},
				new CategoryDef
				{
					nameToken = "LOGBOOK_CATEGORY_ACHIEVEMENTS",
					iconPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/AchievementEntryIcon"),
					buildEntries = (UserProfile viewerProfile) => achievementEntries,
					initializeElementGraphics = CategoryDef.InitializeChallenge
				},
				new CategoryDef
				{
					nameToken = "LOGBOOK_CATEGORY_STATS",
					iconPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/StatsEntryIcon"),
					buildEntries = BuildProfileEntries,
					initializeElementGraphics = CategoryDef.InitializeStats,
					navButtons = new CategoryDef.NavButtons
					{
						scroll = "",
						rotate = "LOGBOOK_PAN"
					}
				},
				new CategoryDef
				{
					nameToken = "LOGBOOK_CATEGORY_MORGUE",
					iconPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/MorgueEntryIcon"),
					buildEntries = BuildMorgueEntries,
					initializeElementGraphics = CategoryDef.InitializeMorgue,
					navButtons = new CategoryDef.NavButtons
					{
						rotate = "",
						navigate = ""
					}
				}
			};
			RegisterViewables(categories);
			availability.MakeAvailable();
			IsStaticDataReady = true;
			EntitlementManager.UpdateLocalUsersEntitlements();
		}

		[ConCommand(commandName = "logbook_list_unfinished_lore", flags = ConVarFlags.None, helpText = "Prints all logbook entries which still have undefined lore.")]
		private static void CCLogbookListUnfinishedLore(ConCommandArgs args)
		{
			List<string> list = new List<string>();
			CategoryDef[] array = categories;
			for (int i = 0; i < array.Length; i++)
			{
				Entry[] array2 = array[i].BuildEntries(args.GetSenderLocalUser()?.userProfile);
				foreach (Entry entry in array2)
				{
					string text = "";
					if (entry.extraData is UnityEngine.Object @object)
					{
						text = @object.name;
					}
					if (entry.isWip)
					{
						list.Add(entry.extraData?.GetType()?.Name + " \"" + text + "\" \"" + Language.GetString(entry.nameToken) + "\"");
					}
				}
			}
			args.Log(string.Join("\n", list));
		}

		private static void RegisterViewables(CategoryDef[] categoriesToGenerateFrom)
		{
			ViewablesCatalog.Node node = new ViewablesCatalog.Node("Logbook", isFolder: true);
			CategoryDef[] array = categories;
			foreach (CategoryDef obj in array)
			{
				ViewablesCatalog.Node parent = (obj.viewableNode = new ViewablesCatalog.Node(obj.nameToken, isFolder: true, node));
				Entry[] array2 = obj.BuildEntries(null);
				foreach (Entry entry in array2)
				{
					string nameToken = entry.nameToken;
					ViewablesCatalog.Node entryNode;
					AchievementDef achievementDef;
					bool hasPrereq;
					if (!entry.isWip && !(nameToken == "TOOLTIP_WIP_CONTENT_NAME") && !string.IsNullOrEmpty(nameToken))
					{
						entryNode = new ViewablesCatalog.Node(nameToken, isFolder: false, parent);
						object extraData = entry.extraData;
						achievementDef = extraData as AchievementDef;
						if (achievementDef != null)
						{
							hasPrereq = !string.IsNullOrEmpty(achievementDef.prerequisiteAchievementIdentifier);
							entryNode.shouldShowUnviewed = Check;
						}
						else
						{
							entryNode.shouldShowUnviewed = Check;
						}
						entry.viewableNode = entryNode;
					}
					bool Check(UserProfile userProfile)
					{
						if (userProfile.HasViewedViewable(entryNode.fullName))
						{
							return false;
						}
						if (userProfile.HasAchievement(achievementDef.identifier))
						{
							return false;
						}
						if (hasPrereq)
						{
							return userProfile.HasAchievement(achievementDef.prerequisiteAchievementIdentifier);
						}
						return true;
					}
					bool Check(UserProfile viewerProfile)
					{
						if (viewerProfile.HasViewedViewable(entryNode.fullName))
						{
							return false;
						}
						return entry.GetStatus(viewerProfile) == EntryStatus.Available;
					}
				}
			}
			ViewablesCatalog.AddNodeToRoot(node);
			LogBookController.OnViewablesRegistered?.Invoke();
		}
	}
	public class LogBookPage : MonoBehaviour
	{
		public RawImage iconImage;

		public ModelPanel modelPanel;

		public TextMeshProUGUI titleText;

		public TextMeshProUGUI categoryText;

		public TextMeshProUGUI pageNumberText;

		public RectTransform contentContainer;

		private PageBuilder pageBuilder;

		[Header("Buttons")]
		public GameObject scroll;

		public LanguageTextMeshController scrollLabel;

		public GameObject back;

		public LanguageTextMeshController backLabel;

		public GameObject navigate;

		public LanguageTextMeshController navigateLabel;

		public GameObject rotate;

		public LanguageTextMeshController rotateLabel;

		public void SetEntry(UserProfile userProfile, Entry entry)
		{
			pageBuilder?.Destroy();
			pageBuilder = new PageBuilder();
			pageBuilder.container = contentContainer;
			pageBuilder.entry = entry;
			pageBuilder.userProfile = userProfile;
			entry.pageBuilderMethod?.Invoke(pageBuilder);
			iconImage.texture = entry.iconTexture;
			titleText.text = entry.GetDisplayName(userProfile);
			categoryText.text = entry.GetCategoryDisplayName(userProfile);
			modelPanel.modelPrefab = entry.modelPrefab;
			modelPanel.transform.parent.parent.gameObject.SetActive(entry.modelPrefab);
			UpdateButtons(entry.category.navButtons);
		}

		private void UpdateButtons(CategoryDef.NavButtons buttons)
		{
			RelabelButton(scroll, scrollLabel, buttons.scroll);
			RelabelButton(back, backLabel, buttons.back);
			RelabelButton(navigate, navigateLabel, buttons.navigate);
			RelabelButton(rotate, rotateLabel, buttons.rotate);
		}

		private void RelabelButton(GameObject button, LanguageTextMeshController label, string text)
		{
			if (text == "")
			{
				button.gameObject.SetActive(value: false);
				return;
			}
			button.gameObject.SetActive(value: true);
			label.token = text;
		}
	}
	public class PageBuilder
	{
		private static readonly StringBuilder sharedStringBuilder = new StringBuilder();

		public UserProfile userProfile;

		public RectTransform container;

		public Entry entry;

		public readonly List<GameObject> managedObjects = new List<GameObject>();

		private StatSheet statSheet => userProfile.statSheet;

		public void Destroy()
		{
			foreach (GameObject managedObject in managedObjects)
			{
				UnityEngine.Object.Destroy(managedObject);
			}
		}

		public void AddSimpleTextPanel(string text)
		{
			AddPrefabInstance(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/SimpleTextPanel")).GetComponent<ChildLocator>().FindChild("MainLabel").GetComponent<TextMeshProUGUI>()
				.text = text;
		}

		public GameObject AddPrefabInstance(GameObject prefab)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(prefab, container);
			managedObjects.Add(gameObject);
			return gameObject;
		}

		public void AddSimpleTextPanel(params string[] textLines)
		{
			AddSimpleTextPanel(string.Join("\n", textLines));
		}

		public void AddSimplePickup(PickupIndex pickupIndex)
		{
			PickupDef pickupDef = PickupCatalog.GetPickupDef(pickupIndex);
			ItemIndex itemIndex = pickupDef?.itemIndex ?? ItemIndex.None;
			EquipmentIndex equipmentIndex = pickupDef?.equipmentIndex ?? EquipmentIndex.None;
			string token = null;
			if (itemIndex != ItemIndex.None)
			{
				ItemDef itemDef = ItemCatalog.GetItemDef(itemIndex);
				AddDescriptionPanel(Language.GetString(itemDef.descriptionToken));
				token = itemDef.loreToken;
				ulong statValueULong = statSheet.GetStatValueULong(PerItemStatDef.totalCollected.FindStatDef(itemIndex));
				ulong statValueULong2 = statSheet.GetStatValueULong(PerItemStatDef.highestCollected.FindStatDef(itemIndex));
				string stringFormatted = Language.GetStringFormatted("GENERIC_PREFIX_FOUND", statValueULong);
				string stringFormatted2 = Language.GetStringFormatted("ITEM_PREFIX_STACKCOUNT", statValueULong2);
				AddSimpleTextPanel(stringFormatted, stringFormatted2);
			}
			else if (equipmentIndex != EquipmentIndex.None)
			{
				EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex);
				AddDescriptionPanel(Language.GetString(equipmentDef.descriptionToken));
				token = equipmentDef.loreToken;
				string stringFormatted3 = Language.GetStringFormatted("EQUIPMENT_PREFIX_COOLDOWN", equipmentDef.cooldown);
				string stringFormatted4 = Language.GetStringFormatted("EQUIPMENT_PREFIX_TOTALTIMEHELD", statSheet.GetStatDisplayValue(PerEquipmentStatDef.totalTimeHeld.FindStatDef(equipmentIndex)));
				string stringFormatted5 = Language.GetStringFormatted("EQUIPMENT_PREFIX_USECOUNT", statSheet.GetStatDisplayValue(PerEquipmentStatDef.totalTimesFired.FindStatDef(equipmentIndex)));
				AddSimpleTextPanel(stringFormatted3);
				AddSimpleTextPanel(stringFormatted4, stringFormatted5);
			}
			AddNotesPanel(Language.IsTokenInvalid(token) ? Language.GetString("EARLY_ACCESS_LORE") : Language.GetString(token));
		}

		public void AddDescriptionPanel(string content)
		{
			AddSimpleTextPanel(Language.GetStringFormatted("DESCRIPTION_PREFIX_FORMAT", content));
		}

		public void AddNotesPanel(string content)
		{
			AddSimpleTextPanel(Language.GetStringFormatted("NOTES_PREFIX_FORMAT", content));
		}

		public void AddBodyStatsPanel(CharacterBody bodyPrefabComponent)
		{
			float baseMaxHealth = bodyPrefabComponent.baseMaxHealth;
			float levelMaxHealth = bodyPrefabComponent.levelMaxHealth;
			float baseDamage = bodyPrefabComponent.baseDamage;
			float levelDamage = bodyPrefabComponent.levelDamage;
			float baseArmor = bodyPrefabComponent.baseArmor;
			float baseRegen = bodyPrefabComponent.baseRegen;
			float levelRegen = bodyPrefabComponent.levelRegen;
			float baseMoveSpeed = bodyPrefabComponent.baseMoveSpeed;
			AddSimpleTextPanel(Language.GetStringFormatted("BODY_HEALTH_FORMAT", Language.GetStringFormatted("BODY_STATS_FORMAT", baseMaxHealth.ToString(), levelMaxHealth.ToString())) + "\n" + Language.GetStringFormatted("BODY_DAMAGE_FORMAT", Language.GetStringFormatted("BODY_STATS_FORMAT", baseDamage.ToString(), levelDamage.ToString())) + "\n" + ((baseRegen >= Mathf.Epsilon) ? (Language.GetStringFormatted("BODY_REGEN_FORMAT", Language.GetStringFormatted("BODY_STATS_FORMAT", baseRegen.ToString(), levelRegen.ToString())) + "\n") : "") + Language.GetStringFormatted("BODY_MOVESPEED_FORMAT", baseMoveSpeed) + "\n" + Language.GetStringFormatted("BODY_ARMOR_FORMAT", baseArmor.ToString()));
		}

		public void AddMonsterPanel(CharacterBody bodyPrefabComponent)
		{
			ulong statValueULong = statSheet.GetStatValueULong(PerBodyStatDef.killsAgainst, bodyPrefabComponent.gameObject.name);
			ulong statValueULong2 = statSheet.GetStatValueULong(PerBodyStatDef.killsAgainstElite, bodyPrefabComponent.gameObject.name);
			ulong statValueULong3 = statSheet.GetStatValueULong(PerBodyStatDef.deathsFrom, bodyPrefabComponent.gameObject.name);
			string stringFormatted = Language.GetStringFormatted("MONSTER_PREFIX_KILLED", statValueULong);
			string stringFormatted2 = Language.GetStringFormatted("MONSTER_PREFIX_ELITESKILLED", statValueULong2);
			string stringFormatted3 = Language.GetStringFormatted("MONSTER_PREFIX_DEATH", statValueULong3);
			AddSimpleTextPanel(stringFormatted, stringFormatted2, stringFormatted3);
		}

		public void AddSurvivorPanel(CharacterBody bodyPrefabComponent)
		{
			string statDisplayValue = statSheet.GetStatDisplayValue(PerBodyStatDef.longestRun.FindStatDef(bodyPrefabComponent.name));
			ulong statValueULong = statSheet.GetStatValueULong(PerBodyStatDef.timesPicked.FindStatDef(bodyPrefabComponent.name));
			ulong statValueULong2 = statSheet.GetStatValueULong(StatDef.totalGamesPlayed);
			double num = 0.0;
			if (statValueULong2 != 0L)
			{
				num = (double)statValueULong / (double)statValueULong2 * 100.0;
			}
			sharedStringBuilder.Clear();
			sharedStringBuilder.AppendLine(Language.GetStringFormatted("SURVIVOR_PREFIX_LONGESTRUN", statDisplayValue));
			sharedStringBuilder.AppendLine(Language.GetStringFormatted("SURVIVOR_PREFIX_TIMESPICKED", statValueULong));
			sharedStringBuilder.AppendLine(Language.GetStringFormatted("SURVIVOR_PREFIX_PICKPERCENTAGE", num));
			AddSimpleTextPanel(sharedStringBuilder.ToString());
		}

		public void AddSimpleBody(CharacterBody bodyPrefabComponent)
		{
			AddBodyStatsPanel(bodyPrefabComponent);
		}

		public void AddBodyLore(CharacterBody characterBody)
		{
			bool flag = false;
			string token = "";
			string baseNameToken = characterBody.baseNameToken;
			if (!string.IsNullOrEmpty(baseNameToken))
			{
				token = baseNameToken.Replace("_NAME", "_LORE");
				if (!Language.IsTokenInvalid(token))
				{
					flag = true;
				}
			}
			if (flag)
			{
				AddNotesPanel(Language.GetString(token));
			}
			else
			{
				AddNotesPanel(Language.GetString("EARLY_ACCESS_LORE"));
			}
		}

		public void AddStagePanel(SceneDef sceneDef)
		{
			string statDisplayValue = userProfile.statSheet.GetStatDisplayValue(PerStageStatDef.totalTimesVisited.FindStatDef(sceneDef.baseSceneName));
			string statDisplayValue2 = userProfile.statSheet.GetStatDisplayValue(PerStageStatDef.totalTimesCleared.FindStatDef(sceneDef.baseSceneName));
			string stringFormatted = Language.GetStringFormatted("STAGE_PREFIX_TOTALTIMESVISITED", statDisplayValue);
			string stringFormatted2 = Language.GetStringFormatted("STAGE_PREFIX_TOTALTIMESCLEARED", statDisplayValue2);
			sharedStringBuilder.Clear();
			sharedStringBuilder.Append(stringFormatted);
			sharedStringBuilder.Append("\n");
			sharedStringBuilder.Append(stringFormatted2);
			AddSimpleTextPanel(sharedStringBuilder.ToString());
		}

		public void AddPieChart(PieChartMeshController.SliceInfo[] sliceInfos)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/PieChartPanel"), container);
			gameObject.GetComponent<PieChartMeshController>().SetSlices(sliceInfos);
			managedObjects.Add(gameObject);
		}

		public static void Stage(PageBuilder builder)
		{
			SceneDef sceneDef = (SceneDef)builder.entry.extraData;
			builder.AddStagePanel(sceneDef);
			builder.AddNotesPanel(Language.IsTokenInvalid(sceneDef.loreToken) ? Language.GetString("EARLY_ACCESS_LORE") : Language.GetString(sceneDef.loreToken));
		}

		public static void SimplePickup(PageBuilder builder)
		{
			builder.AddSimplePickup((PickupIndex)builder.entry.extraData);
		}

		public static void SimpleBody(PageBuilder builder)
		{
			builder.AddSimpleBody((CharacterBody)builder.entry.extraData);
		}

		public static void MonsterBody(PageBuilder builder)
		{
			CharacterBody characterBody = (CharacterBody)builder.entry.extraData;
			builder.AddSimpleBody(characterBody);
			builder.AddMonsterPanel(characterBody);
			builder.AddBodyLore(characterBody);
		}

		public static void SurvivorBody(PageBuilder builder)
		{
			CharacterBody characterBody = (CharacterBody)builder.entry.extraData;
			builder.AddSimpleBody(characterBody);
			builder.AddSurvivorPanel(characterBody);
			builder.AddBodyLore(characterBody);
		}

		public static void StatsPanel(PageBuilder builder)
		{
			UserProfile userProfile = (UserProfile)builder.entry.extraData;
			GameCompletionStatsHelper gameCompletionStatsHelper = new GameCompletionStatsHelper();
			StatSheet statSheet = userProfile.statSheet;
			CalcAllBodyStatTotalDouble(PerBodyStatDef.totalTimeAlive);
			_ = (double)CalcAllBodyStatTotalULong(PerBodyStatDef.timesPicked);
			double value = (double)CalcAllBodyStatTotalULong(PerBodyStatDef.totalWins);
			_ = (double)CalcAllBodyStatTotalULong(PerBodyStatDef.deathsAs);
			ChildLocator component = builder.AddPrefabInstance(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/ProfileStatsPanel")).GetComponent<ChildLocator>();
			RectTransform rectTransform = (RectTransform)component.FindChild("CharacterPieChart");
			RectTransform rectTransform2 = (RectTransform)component.FindChild("CompletionBarPanel");
			RectTransform rectTransform3 = (RectTransform)component.FindChild("CompletionLabel");
			RectTransform rectTransform4 = (RectTransform)component.FindChild("CharacterStatsCarousel");
			RectTransform rectTransform5 = (RectTransform)component.FindChild("TotalsStatsList");
			RectTransform rectTransform6 = (RectTransform)component.FindChild("RecordsStatsList");
			RectTransform rectTransform7 = (RectTransform)component.FindChild("MiscStatsList");
			RectTransform rectTransform8 = (RectTransform)component.FindChild("CompletionStatsList");
			PieChartMeshController characterPieChartMeshController = rectTransform.GetComponent<PieChartMeshController>();
			CarouselNavigationController carousel = rectTransform4.GetComponent<CarouselNavigationController>();
			List<string> statNames = new List<string>();
			List<Action> callbacks = new List<Action>();
			AddPerBodyStat(PerBodyStatDef.totalWins);
			AddPerBodyStat(PerBodyStatDef.timesPicked);
			AddPerBodyStat(PerBodyStatDef.totalTimeAlive);
			AddPerBodyStat(PerBodyStatDef.longestRun);
			AddPerBodyStat(PerBodyStatDef.deathsAs);
			AddPerBodyStat(PerBodyStatDef.damageDealtAs);
			AddPerBodyStat(PerBodyStatDef.damageTakenAs);
			AddPerBodyStat(PerBodyStatDef.damageDealtTo);
			AddPerBodyStat(PerBodyStatDef.damageTakenFrom);
			AddPerBodyStat(PerBodyStatDef.killsAgainst);
			AddPerBodyStat(PerBodyStatDef.killsAgainstElite);
			AddPerBodyStat(PerBodyStatDef.deathsFrom);
			AddPerBodyStat(PerBodyStatDef.minionDamageDealtAs);
			AddPerBodyStat(PerBodyStatDef.minionKillsAs);
			AddPerBodyStat(PerBodyStatDef.killsAs);
			carousel.onPageChangeSubmitted += OnPageChangeSubmitted;
			carousel.SetDisplayData(new CarouselNavigationController.DisplayData(statNames.Count, 0));
			OnPageChangeSubmitted(0);
			GameObject statStripPrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/Logbook/LogbookStatStrip");
			StatDef statDef2 = PerBodyStatDef.longestRun.FindStatDef(statSheet.FindBodyWithHighestStat(PerBodyStatDef.longestRun)) ?? PerBodyStatDef.longestRun.FindStatDef(BodyCatalog.FindBodyIndex("CommandoBody"));
			CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(statSheet.FindBodyWithHighestStat(PerBodyStatDef.deathsFrom));
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(statSheet.FindEquipmentWithHighestStat(PerEquipmentStatDef.totalTimeHeld));
			(string, string, Texture)[] array = new(string, string, Texture)[20];
			(string, string, Texture2D) tuple = StatStripDataFromStatDef(StatDef.totalGamesPlayed);
			array[0] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalTimeAlive);
			array[1] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalDeaths);
			array[2] = (tuple.Item1, tuple.Item2, tuple.Item3);
			array[3] = (Language.GetString("STATNAME_TOTALWINS"), TextSerialization.ToStringNumeric(value), null);
			tuple = StatStripDataFromStatDef(StatDef.totalKills);
			array[4] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalEliteKills);
			array[5] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalDamageDealt);
			array[6] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalStagesCompleted);
			array[7] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalDamageTaken);
			array[8] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalHealthHealed);
			array[9] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.goldCollected);
			array[10] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalDistanceTraveled);
			array[11] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalPurchases);
			array[12] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalBloodPurchases);
			array[13] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalDronesPurchased);
			array[14] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalTurretsPurchased);
			array[15] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalCrocoInfectionsInflicted);
			array[16] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalMinionDamageDealt);
			array[17] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalMinionKills);
			array[18] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.totalDeathsWhileBurning);
			array[19] = (tuple.Item1, tuple.Item2, tuple.Item3);
			SetStats(rectTransform5, array);
			(string, string, Texture)[] obj = new(string, string, Texture)[6]
			{
				(Language.GetString("STATNAME_LONGESTRUN"), statSheet.GetStatDisplayValue(statDef2), null),
				default((string, string, Texture)),
				default((string, string, Texture)),
				default((string, string, Texture)),
				default((string, string, Texture)),
				default((string, string, Texture))
			};
			tuple = StatStripDataFromStatDef(StatDef.highestStagesCompleted);
			obj[1] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.highestLevel);
			obj[2] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.highestDamageDealt);
			obj[3] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.maxGoldCollected);
			obj[4] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromStatDef(StatDef.highestPurchases);
			obj[5] = (tuple.Item1, tuple.Item2, tuple.Item3);
			SetStats(rectTransform6, obj);
			SetStats(rectTransform7, new(string, string, Texture)[2]
			{
				(Language.GetString("STATNAME_NEMESIS"), bodyPrefabBodyComponent ? Language.GetString(bodyPrefabBodyComponent.baseNameToken) : string.Empty, bodyPrefabBodyComponent ? bodyPrefabBodyComponent.portraitIcon : null),
				(Language.GetString("STATNAME_FAVORITEEQUIPMENT"), (equipmentDef != null) ? Language.GetString(equipmentDef.nameToken) : string.Empty, equipmentDef?.pickupIconTexture)
			});
			(string, string, Texture)[] array2 = new(string, string, Texture)[5];
			tuple = StatStripDataFromCompletionFraction("STATNAME_COMPLETION_ACHIEVEMENTS", gameCompletionStatsHelper.GetAchievementCompletion(userProfile));
			array2[0] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromCompletionFraction("STATNAME_COMPLETION_COLLECTIBLES", gameCompletionStatsHelper.GetCollectibleCompletion(userProfile));
			array2[1] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromCompletionFraction("STATNAME_COMPLETION_PICKUPDISCOVERY", gameCompletionStatsHelper.GetPickupEncounterCompletion(userProfile));
			array2[2] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromCompletionFraction("STATNAME_COMPLETION_SURVIVORSPICKED", gameCompletionStatsHelper.GetSurvivorPickCompletion(userProfile));
			array2[3] = (tuple.Item1, tuple.Item2, tuple.Item3);
			tuple = StatStripDataFromCompletionFraction("STATNAME_COMPLETION_SURVIVORSWON", gameCompletionStatsHelper.GetSurvivorWinCompletion(userProfile));
			array2[4] = (tuple.Item1, tuple.Item2, tuple.Item3);
			SetStats(rectTransform8, array2);
			IntFraction value2 = gameCompletionStatsHelper.GetTotalCompletion(userProfile);
			float num = (float)value2;
			UnityEngine.Vector2 anchorMax = rectTransform2.anchorMax;
			anchorMax.x = num;
			rectTransform2.anchorMax = anchorMax;
			rectTransform3.GetComponent<TMP_Text>().SetText($"{num:0%}");
			void AddLine(StatDef statDef, string statNameToken, double? allBodyTotal)
			{
				string @string = Language.GetString("STAT_NAME_VALUE_FORMAT");
				string statDisplayValue = statSheet.GetStatDisplayValue(statDef);
				P_3.bodyTextStringBuilder.AppendFormat(@string, Language.GetString(statNameToken), statDisplayValue);
				if (allBodyTotal.HasValue)
				{
					double statValueAsDouble = statSheet.GetStatValueAsDouble(statDef);
					double num2 = 0.0;
					if (allBodyTotal != 0.0)
					{
						num2 = statValueAsDouble / allBodyTotal.Value;
					}
					P_3.bodyTextStringBuilder.Append(" ").AppendFormat(P_3.rateFormat, num2);
				}
				P_3.bodyTextStringBuilder.AppendLine();
			}
			void AddLineFromPerBodyStat(PerBodyStatDef perBodyStatDef, double? total)
			{
				if (!total.HasValue)
				{
					total = CalcAllBodyStatTotalDouble(perBodyStatDef);
				}
				StatDef statDef3 = perBodyStatDef.FindStatDef(P_2.bodyIndex);
				AddLine(statDef3, perBodyStatDef.nameToken, total);
			}
			void AddPerBodyStat(PerBodyStatDef perBodyStatDef)
			{
				statNames.Add(Language.GetString(perBodyStatDef.nameToken));
				callbacks.Add(Callback);
				void Callback()
				{
					BuildCharacterPieChart(characterPieChartMeshController, (BodyIndex bodyIndex) => GetStatWeight(perBodyStatDef.FindStatDef(bodyIndex)));
				}
			}
			TooltipContent BuildBodyTooltipContent(BodyIndex bodyIndex, UnityEngine.Color bodyColor)
			{
				CharacterBody bodyPrefabBodyComponent2 = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndex);
				StringBuilder bodyTextStringBuilder = HG.StringBuilderPool.RentStringBuilder();
				string rateFormat = Language.GetString("PERCENT_FORMAT_PARENTHESES");
				AddLineFromPerBodyStat(PerBodyStatDef.timesPicked, null);
				AddLineFromPerBodyStat(PerBodyStatDef.totalTimeAlive, null);
				AddLineFromPerBodyStat(PerBodyStatDef.longestRun, null);
				AddLineFromPerBodyStat(PerBodyStatDef.totalWins, null);
				AddLineFromPerBodyStat(PerBodyStatDef.deathsAs, null);
				AddLineFromPerBodyStat(PerBodyStatDef.damageDealtAs, null);
				AddLineFromPerBodyStat(PerBodyStatDef.damageTakenAs, null);
				AddLineFromPerBodyStat(PerBodyStatDef.damageDealtTo, null);
				AddLineFromPerBodyStat(PerBodyStatDef.damageTakenFrom, null);
				AddLineFromPerBodyStat(PerBodyStatDef.killsAgainst, null);
				AddLineFromPerBodyStat(PerBodyStatDef.killsAgainstElite, null);
				AddLineFromPerBodyStat(PerBodyStatDef.deathsFrom, null);
				AddLineFromPerBodyStat(PerBodyStatDef.minionDamageDealtAs, null);
				AddLineFromPerBodyStat(PerBodyStatDef.minionKillsAs, null);
				AddLineFromPerBodyStat(PerBodyStatDef.killsAs, null);
				TooltipContent tooltipContent = default(TooltipContent);
				tooltipContent.titleToken = bodyPrefabBodyComponent2.baseNameToken;
				tooltipContent.titleColor = bodyColor;
				tooltipContent.overrideBodyText = bodyTextStringBuilder.ToString();
				TooltipContent result3 = tooltipContent;
				HG.StringBuilderPool.ReturnStringBuilder(bodyTextStringBuilder);
				return result3;
			}
			void BuildCharacterPieChart(PieChartMeshController pieChartMeshController, Func<BodyIndex, float> bodyWeightGetter)
			{
				List<PieChartMeshController.SliceInfo> list = new List<PieChartMeshController.SliceInfo>();
				for (BodyIndex bodyIndex2 = (BodyIndex)0; (int)bodyIndex2 < BodyCatalog.bodyCount; bodyIndex2++)
				{
					float num4 = bodyWeightGetter(bodyIndex2);
					if (num4 != 0f)
					{
						PieChartMeshController.SliceInfo item4 = default(PieChartMeshController.SliceInfo);
						item4.color = GetBodyColor(bodyIndex2);
						item4.weight = num4;
						item4.tooltipContent = BuildBodyTooltipContent(bodyIndex2, item4.color);
						list.Add(item4);
					}
				}
				pieChartMeshController.SetSlices(list.OrderBy((PieChartMeshController.SliceInfo slice) => 0f - slice.weight).ToArray());
			}
			double CalcAllBodyStatTotalDouble(PerBodyStatDef perBodyStatDef)
			{
				double num5 = 0.0;
				for (BodyIndex bodyIndex4 = (BodyIndex)0; (int)bodyIndex4 < BodyCatalog.bodyCount; bodyIndex4++)
				{
					num5 += statSheet.GetStatValueAsDouble(perBodyStatDef.FindStatDef(bodyIndex4));
				}
				return num5;
			}
			BigInteger CalcAllBodyStatTotalULong(PerBodyStatDef perBodyStatDef)
			{
				BigInteger result4 = 0;
				for (BodyIndex bodyIndex3 = (BodyIndex)0; (int)bodyIndex3 < BodyCatalog.bodyCount; bodyIndex3++)
				{
					result4 += (BigInteger)statSheet.GetStatValueULong(perBodyStatDef.FindStatDef(bodyIndex3));
				}
				return result4;
			}
			static UnityEngine.Color GetBodyColor(BodyIndex bodyIndex)
			{
				CharacterBody bodyPrefabBodyComponent3 = BodyCatalog.GetBodyPrefabBodyComponent(bodyIndex);
				if (bodyPrefabBodyComponent3.bodyColor != UnityEngine.Color.clear)
				{
					return bodyPrefabBodyComponent3.bodyColor;
				}
				string bodyName = BodyCatalog.GetBodyName(bodyIndex);
				ulong num3 = 0uL;
				for (int j = 0; j < bodyName.Length; j++)
				{
					num3 += bodyName[j];
				}
				Xoroshiro128Plus xoroshiro128Plus = new Xoroshiro128Plus(num3);
				return UnityEngine.Color.HSVToRGB(xoroshiro128Plus.nextNormalizedFloat, xoroshiro128Plus.RangeFloat(0.5f, 1f), xoroshiro128Plus.RangeFloat(0.6f, 0.8f));
			}
			float GetStatWeight(StatDef statDef)
			{
				return statDef.dataType switch
				{
					StatDataType.ULong => statSheet.GetStatValueULong(statDef), 
					StatDataType.Double => (float)statSheet.GetStatValueDouble(statDef), 
					_ => throw new ArgumentOutOfRangeException(), 
				};
			}
			void OnPageChangeSubmitted(int newPage)
			{
				callbacks[newPage]();
				carousel.GetComponent<ChildLocator>().FindChild("StatLabel").GetComponent<HGTextMeshProUGUI>()
					.text = statNames[newPage];
			}
			void SetStats(RectTransform container, (string name, string value, Texture texture)[] data)
			{
				UIElementAllocator<ChildLocator> uIElementAllocator = new UIElementAllocator<ChildLocator>(container, statStripPrefab, markElementsUnsavable: true, acquireExistingChildren: true);
				uIElementAllocator.AllocateElements(data.Length);
				ReadOnlyCollection<ChildLocator> elements = uIElementAllocator.elements;
				for (int i = 0; i < data.Length; i++)
				{
					(string name, string value, Texture texture) tuple2 = data[i];
					string item = tuple2.name;
					string item2 = tuple2.value;
					Texture item3 = tuple2.texture;
					ChildLocator childLocator = elements[i];
					childLocator.FindChild("NameLabel").GetComponent<TMP_Text>().SetText(item);
					childLocator.FindChild("ValueLabel").GetComponent<TMP_Text>().SetText("<color=#FFFF7F>" + item2 + "</color>");
					RawImage component2 = childLocator.FindChild("IconRawImage").GetComponent<RawImage>();
					component2.transform.parent.gameObject.SetActive(item3);
					component2.texture = item3;
				}
			}
			static (string name, string value, Texture2D texture) StatStripDataFromCompletionFraction(string displayToken, IntFraction completionFraction)
			{
				(string, string, Texture2D) result = default((string, string, Texture2D));
				result.Item1 = Language.GetString(displayToken);
				result.Item2 = Language.GetStringFormatted("STAT_COMPLETION_VALUE_FORMAT", completionFraction.numerator, completionFraction.denominator, (float)completionFraction);
				result.Item3 = null;
				return result;
			}
			(string name, string value, Texture2D texture) StatStripDataFromStatDef(StatDef statDef)
			{
				(string, string, Texture2D) result2 = default((string, string, Texture2D));
				result2.Item1 = Language.GetString(statDef.displayToken);
				result2.Item2 = statSheet.GetStatDisplayValue(statDef);
				result2.Item3 = null;
				return result2;
			}
		}

		public void AddRunReportPanel(RunReport runReport)
		{
			GameObject gameObject = UnityEngine.Object.Instantiate(LegacyResourcesAPI.Load<GameObject>("Prefabs/UI/GameEndReportPanelScrolling"), container);
			gameObject.GetComponent<GameEndReportPanelController>().SetDisplayData(new GameEndReportPanelController.DisplayData
			{
				runReport = runReport,
				playerIndex = 0
			});
			gameObject.GetComponent<MPEventSystemProvider>().fallBackToMainEventSystem = true;
			managedObjects.Add(gameObject);
		}

		public static void RunReportPanel(PageBuilder builder)
		{
			builder.AddRunReportPanel((RunReport)builder.entry.extraData);
		}
	}
}
namespace RoR2.UI.MainMenu
{
	[RequireComponent(typeof(FirstSelectedObjectProvider))]
	public class LocalMultiplayerMenuController : BaseMainMenuScreen
	{
		public enum Subview
		{
			Main,
			FindGame,
			HostGame
		}

		public enum MPButtons
		{
			HostGame,
			FindGame,
			Quickplay,
			StartPrivateGame,
			Invite,
			FindFriendSession,
			Back,
			EnterGame,
			NONE
		}

		private const float titleTransitionDuration = 0.5f;

		private const float titleTransitionBuffer = 0.1f;

		public UnityEngine.UI.Image fadeImage;

		public LerpUIRect[] uiToLerp;

		private float titleStopwatch;

		private Subview _curSubView;

		[Header("Buttons")]
		public MPButton backButton;

		public CarouselController gameModePicker;

		public MPButton enterGameButton;

		public static LocalMultiplayerMenuController instance { get; private set; }

		private void ToggleMPFeatures(MPFeatures featureFlags)
		{
			Toggle(gameModePicker, val: true);
			Toggle(enterGameButton, val: true);
		}

		private void ToggleMPFeaturesInteractable(MPFeatures featureFlags)
		{
			gameModePicker.ToggleArrowsInteractable(isInteractable: true);
			if (enterGameButton != null)
			{
				enterGameButton.interactable = true;
			}
		}

		private void Toggle(MonoBehaviour component, bool val)
		{
			if ((bool)component)
			{
				component.gameObject.SetActive(val);
			}
			else
			{
				UnityEngine.Debug.LogError("Null ref on Toggle of Button in MultiplayerMenuController on \"" + base.gameObject.name + "\"");
			}
		}

		private void Toggle(GameObject[] goToToggle, bool val)
		{
			int num = goToToggle.Length;
			for (int i = 0; i < num; i++)
			{
				goToToggle[i].gameObject.SetActive(val);
			}
		}

		private void Toggle(MonoBehaviour[] buttons, bool val)
		{
			int num = buttons.Length;
			for (int i = 0; i < num; i++)
			{
				buttons[i].gameObject.SetActive(val);
			}
		}

		public void SetButtonText(MPButton button, string textKey, object[] formatArgs = null)
		{
			if (formatArgs == null)
			{
				formatArgs = Array.Empty<object>();
			}
			TextMeshProUGUI component = button.GetComponent<TextMeshProUGUI>();
			if ((bool)component)
			{
				component.text = Language.GetStringFormatted(textKey, formatArgs);
			}
		}

		public void RefreshFirstObjectSelectedProvider()
		{
			if ((bool)firstSelectedObjectProvider)
			{
				firstSelectedObjectProvider.firstSelectedObject = gameModePicker.gameObject;
				firstSelectedObjectProvider.fallBackFirstSelectedObjects = new GameObject[3] { gameModePicker.gameObject, enterGameButton.gameObject, backButton.gameObject };
			}
		}

		public new void OnEnable()
		{
			RefreshFirstObjectSelectedProvider();
			firstSelectedObjectProvider?.ForceSelectFirstInteractable();
			LerpAllUI(LerpUIRect.LerpState.Entering);
			if (!instance)
			{
				instance = SingletonHelper.Assign(instance, this);
			}
			firstSelectedObjectProvider?.ResetLastSelected();
			firstSelectedObjectProvider?.EnsureSelectedObject();
		}

		public void OnDisable()
		{
			instance = SingletonHelper.Unassign(instance, this);
		}

		public new void Awake()
		{
			base.Awake();
			LerpAllUI(LerpUIRect.LerpState.Entering);
			BuildGameModeChoices();
		}

		public void LerpAllUI(LerpUIRect.LerpState lerpState)
		{
			LerpUIRect[] array = uiToLerp;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].lerpState = lerpState;
			}
		}

		private void BuildGameModeChoices()
		{
			List<CarouselController.Choice> list = new List<CarouselController.Choice>();
			List<string> list2 = gameModePicker.choices.Select((CarouselController.Choice choice) => choice.suboptionDisplayToken).ToList();
			for (GameModeIndex gameModeIndex = (GameModeIndex)0; (int)gameModeIndex < GameModeCatalog.gameModeCount; gameModeIndex++)
			{
				Run gameModePrefabComponent = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex);
				ExpansionRequirementComponent component = gameModePrefabComponent.GetComponent<ExpansionRequirementComponent>();
				if (gameModePrefabComponent != null && gameModePrefabComponent.userPickable && list2.Contains(gameModePrefabComponent.nameToken) && (!component || !component.requiredExpansion || EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(component.requiredExpansion.requiredEntitlement)))
				{
					list.Add(new CarouselController.Choice
					{
						suboptionDisplayToken = gameModePrefabComponent.nameToken,
						convarValue = gameModePrefabComponent.name
					});
				}
			}
			gameModePicker.choices = list.ToArray();
			gameModePicker.gameObject.SetActive(list.Count > 0);
			string @string = Console.instance.FindConVar("gamemode").GetString();
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].convarValue == @string)
				{
					flag = true;
					break;
				}
			}
			if (list.Count == 1 || !flag)
			{
				UnityEngine.Debug.LogFormat("Invalid gamemode {0} detected. Reverting to ClassicRun.", @string);
				gameModePicker.SubmitSetting(list[0].convarValue);
			}
		}

		public void ReturnToMainMenu()
		{
			myMainMenuController.SetDesiredMenuScreen(myMainMenuController.titleMenuScreen);
		}

		public void OnEnterGameButtonPressed()
		{
			titleStopwatch = 0f;
			LerpAllUI(LerpUIRect.LerpState.Leaving);
		}

		public void OnStartGamePressed()
		{
			string @string = Console.instance.FindConVar("gamemode").GetString();
			Console.instance.SubmitCmd(null, $"transition_command \"gamemode {@string}; host 0;\"");
		}

		private new void Update()
		{
			base.Update();
			titleStopwatch += Time.deltaTime;
			if (enterGameButton != null && enterGameButton.isActiveAndEnabled)
			{
				enterGameButton.interactable = true;
			}
			if (SimpleDialogBox.instancesList.Count > 0 && (bool)firstSelectedObjectProvider)
			{
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.instancesList[0];
				if ((bool)simpleDialogBox)
				{
					firstSelectedObjectProvider.firstSelectedObject = simpleDialogBox.GetComponentInChildren<MPButton>().gameObject;
					firstSelectedObjectProvider.ResetLastSelected();
				}
			}
			firstSelectedObjectProvider?.EnsureSelectedObject();
		}

		public override bool IsReadyToLeave()
		{
			return true;
		}

		public void GoBack()
		{
			ReturnToMainMenu();
		}

		public void ResetLastSelected()
		{
			firstSelectedObjectProvider?.ResetLastSelected();
			firstSelectedObjectProvider?.EnsureSelectedObject();
		}

		public void ToggleAllButtonsInteractable(bool interactable)
		{
			for (int i = 0; i < 8; i++)
			{
				SetButtonInteractableStatus((MPButtons)i, interactable);
			}
			firstSelectedObjectProvider.ForceSelectFirstInteractable();
		}

		public void SetButtonInteractableStatus(MPButtons button, bool interactable)
		{
			MPButton mPButton = null;
			switch (button)
			{
			case MPButtons.Back:
				mPButton = backButton;
				break;
			case MPButtons.EnterGame:
				mPButton = enterGameButton;
				break;
			}
			if (mPButton != null)
			{
				mPButton.interactable = interactable;
			}
		}
	}
	[RequireComponent(typeof(RectTransform))]
	public class BaseMainMenuScreen : MonoBehaviour
	{
		public Transform desiredCameraTransform;

		[HideInInspector]
		public bool shouldDisplay;

		protected MainMenuController myMainMenuController;

		protected FirstSelectedObjectProvider firstSelectedObjectProvider;

		public UnityEvent onEnter;

		public UnityEvent onExit;

		public void Awake()
		{
			firstSelectedObjectProvider = GetComponent<FirstSelectedObjectProvider>();
		}

		public void OnEnable()
		{
			MainMenuController.instance?.SetAllowTransition(value: true);
		}

		public virtual bool IsReadyToLeave()
		{
			return true;
		}

		public void Update()
		{
			if (SimpleDialogBox.instancesList.Count == 0)
			{
				firstSelectedObjectProvider?.EnsureSelectedObject();
			}
		}

		public virtual void OnEnter(MainMenuController mainMenuController)
		{
			UnityEngine.Debug.LogFormat("BaseMainMenuScreen: OnEnter()");
			myMainMenuController = mainMenuController;
			if (SimpleDialogBox.instancesList.Count == 0)
			{
				firstSelectedObjectProvider?.EnsureSelectedObject();
			}
			onEnter.Invoke();
		}

		public virtual void OnExit(MainMenuController mainMenuController)
		{
			if (myMainMenuController == mainMenuController)
			{
				myMainMenuController = null;
			}
			onExit.Invoke();
		}
	}
	public sealed class MainMenuController : MonoBehaviour
	{
		[NonSerialized]
		public BaseMainMenuScreen desiredMenuScreen;

		public BaseMainMenuScreen LoadingScreen;

		public BaseMainMenuScreen profileMenuScreen;

		public BaseMainMenuScreen EAwarningProfileMenu;

		public BaseMainMenuScreen multiplayerMenuScreen;

		public BaseMainMenuScreen localMultiplayerMenuScreen;

		public BaseMainMenuScreen titleMenuScreen;

		public BaseMainMenuScreen settingsMenuScreen;

		public BaseMainMenuScreen moreMenuScreen;

		public BaseMainMenuScreen extraGameModeMenuScreen;

		[HideInInspector]
		public BaseMainMenuScreen currentMenuScreen;

		public static MainMenuController instance;

		public HGButton exitButtonTransition;

		public HGButton profileButtonTransition;

		public HGButton onlineMultiplayerButtonTransition;

		public HGButton localMultiplayerButtonTransition;

		public HGButton splitscreenMultiplayerButtonTransition;

		public HGButton logbookButton;

		public HGButton singlePlayerButton;

		public GameObject steamBuildLabel;

		[NonSerialized]
		public bool allowTransition = true;

		public HGButton continueButtonTransition;

		public GameObject EA_Panel;

		public GameObject mainMenuButtonPanel;

		public Transform cameraTransform;

		public float camRotationSmoothDampTime;

		public float camTranslationSmoothDampTime;

		private UnityEngine.Vector3 camSmoothDampPositionVelocity;

		private UnityEngine.Vector3 camSmoothDampRotationVelocity;

		public float camTransitionDuration;

		private float camTransitionTimer;

		private static bool isShownAgeRestriction = false;

		private static bool wasInMultiplayer = false;

		private static EOSLoginManager.EOSLoginState lastEOSLoginState = EOSLoginManager.EOSLoginState.None;

		private static bool eaWarningShown = false;

		private static BoolConVar eaMessageSkipConVar = new BoolConVar("ea_message_skip", ConVarFlags.None, "0", "Whether or not to skip the early access splash screen.");

		private static bool _isInitialized = false;

		public static bool IsOnMultiplayerScreen { get; set; } = false;


		private static bool isInitialized
		{
			get
			{
				return _isInitialized;
			}
			set
			{
				_isInitialized = value;
				if (_isInitialized)
				{
					MainMenuController.OnMainMenuInitialised?.Invoke();
				}
			}
		}

		public static event Action OnMainMenuInitialised;

		public static event Action OnPreMainMenuInitialized;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			NetworkManagerSystem.onStartClientGlobal += delegate
			{
				if (!NetworkServer.active || !NetworkServer.dontListen)
				{
					wasInMultiplayer = true;
				}
			};
		}

		private void Awake()
		{
			RoR2Application.onStart = (Action)Delegate.Combine(RoR2Application.onStart, new Action(StartManaged));
			PauseManager.InitializeLoad();
			RoR2Application.isInLocalMultiPlayer = false;
		}

		private void OnDestroy()
		{
		}

		public void SetButtonsInteractible(bool enabled)
		{
			exitButtonTransition.interactable = enabled;
			profileButtonTransition.interactable = enabled;
			onlineMultiplayerButtonTransition.interactable = enabled;
			localMultiplayerButtonTransition.interactable = enabled;
			splitscreenMultiplayerButtonTransition.interactable = enabled;
			logbookButton.interactable = enabled;
		}

		private void OnNetworkReachabilityChanged(bool networkReachability)
		{
			if (networkReachability)
			{
				SetupMPFeatureButtons();
			}
		}

		private void Start()
		{
			if (instance != null)
			{
				UnityEngine.Object.Destroy(base.gameObject);
				return;
			}
			instance = this;
			SetupMPFeatureButtons();
			exitButtonTransition.transform.SetAsLastSibling();
			StartWaitForLoad();
			if ((bool)LoadingScreen)
			{
				LoadingScreen.gameObject.SetActive(value: true);
			}
			titleMenuScreen.gameObject.SetActive(value: false);
			multiplayerMenuScreen.gameObject.SetActive(value: false);
			localMultiplayerMenuScreen.gameObject.SetActive(value: false);
			settingsMenuScreen.gameObject.SetActive(value: false);
			moreMenuScreen.gameObject.SetActive(value: false);
			extraGameModeMenuScreen.gameObject.SetActive(value: false);
			if (GameIntentReceiver.GameIntentAdapter.hasPendingGameIntent)
			{
				FadeToBlackManager.fadePaused = true;
			}
			desiredMenuScreen = (wasInMultiplayer ? multiplayerMenuScreen : titleMenuScreen);
			_ = wasInMultiplayer;
			wasInMultiplayer = false;
			StartManaged();
		}

		private void DisableButtonsForConsole()
		{
		}

		private void SetupMPFeatureButtons()
		{
			bool flag = PlatformSystems.lobbyManager.GetPlatformMPFeatureFlags().HasFlag(MPFeatures.AdHoc);
			localMultiplayerButtonTransition.gameObject.SetActive(flag);
			LanguageTextMeshController componentInChildren = onlineMultiplayerButtonTransition.GetComponentInChildren<LanguageTextMeshController>();
			if ((bool)componentInChildren)
			{
				componentInChildren.token = (flag ? "TITLE_MULTIPLAYER_ONLINE" : "TITLE_MULTIPLAYER");
			}
			splitscreenMultiplayerButtonTransition.gameObject.SetActive(value: false);
		}

		private void DialogBox(string headerToken, string descriptionToken)
		{
			if (SimpleDialogBox.instancesList.Count == 0)
			{
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
				simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair(headerToken);
				simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair(descriptionToken);
				simpleDialogBox.AddCancelButton(CommonLanguageTokens.ok);
				simpleDialogBox.rootObject.transform.SetParent(RoR2Application.instance.mainCanvas.transform);
			}
		}

		private void StartManaged()
		{
			CheckWarningScreen();
			currentMenuScreen = desiredMenuScreen;
			if (!currentMenuScreen.gameObject.activeInHierarchy)
			{
				currentMenuScreen.gameObject.SetActive(value: true);
			}
			if (currentMenuScreen.desiredCameraTransform != null)
			{
				cameraTransform.rotation = currentMenuScreen.desiredCameraTransform.rotation;
			}
			if ((bool)currentMenuScreen)
			{
				currentMenuScreen.OnEnter(this);
			}
			IsOnMultiplayerScreen = currentMenuScreen == multiplayerMenuScreen;
		}

		private bool CheckWarningScreen()
		{
			return false;
		}

		private static bool IsMainUserSignedIn()
		{
			return LocalUserManager.FindLocalUser(0) != null;
		}

		private bool IsInLobby()
		{
			return PlatformSystems.lobbyManager.isInLobby;
		}

		private void Update()
		{
			if (isInitialized)
			{
				if (currentMenuScreen == multiplayerMenuScreen && PlayerPrefs.GetInt("HasShownFirstTimePopup", 0) == 0)
				{
					PlayerPrefs.SetInt("HasShownFirstTimePopup", 1);
					ShowFirstTimeCrossPlayPopup();
				}
				if (IsInLobby() && currentMenuScreen != multiplayerMenuScreen && currentMenuScreen != localMultiplayerMenuScreen)
				{
					desiredMenuScreen = multiplayerMenuScreen;
				}
				if (!IsMainUserSignedIn() && currentMenuScreen != EAwarningProfileMenu)
				{
					desiredMenuScreen = profileMenuScreen;
				}
				if (!(currentMenuScreen == null))
				{
					UpdateMenuTransition();
				}
			}
		}

		private void UpdateMenuTransition()
		{
			if (desiredMenuScreen != currentMenuScreen)
			{
				if (desiredMenuScreen == multiplayerMenuScreen && PlatformSystems.userManager.CurrentUserHasRestriction(UserManager.PlatformRestriction.Multiplayer))
				{
					PlatformSystems.userManager.DisplayRestrictionMessage();
					desiredMenuScreen = currentMenuScreen;
					return;
				}
				currentMenuScreen.shouldDisplay = false;
				if (currentMenuScreen.IsReadyToLeave())
				{
					MPEventSystemLocator component = GetComponent<MPEventSystemLocator>();
					if ((bool)component)
					{
						component.eventSystem.SetSelectedObject(null);
					}
					if (currentMenuScreen == multiplayerMenuScreen && desiredMenuScreen == titleMenuScreen)
					{
						MultiplayerMenuController.instance?.ResetLobby();
					}
					currentMenuScreen.OnExit(this);
					currentMenuScreen.gameObject.SetActive(value: false);
					currentMenuScreen = desiredMenuScreen;
					camTransitionTimer = camTransitionDuration;
					currentMenuScreen.OnEnter(this);
					IsOnMultiplayerScreen = currentMenuScreen == multiplayerMenuScreen;
				}
			}
			else if (currentMenuScreen.desiredCameraTransform != null)
			{
				camTransitionTimer -= Time.deltaTime;
				cameraTransform.position = UnityEngine.Vector3.SmoothDamp(cameraTransform.position, currentMenuScreen.desiredCameraTransform.position, ref camSmoothDampPositionVelocity, camTranslationSmoothDampTime);
				UnityEngine.Vector3 eulerAngles = cameraTransform.eulerAngles;
				UnityEngine.Vector3 eulerAngles2 = currentMenuScreen.desiredCameraTransform.eulerAngles;
				eulerAngles.x = Mathf.SmoothDampAngle(eulerAngles.x, eulerAngles2.x, ref camSmoothDampRotationVelocity.x, camRotationSmoothDampTime, float.PositiveInfinity, Time.unscaledDeltaTime);
				eulerAngles.y = Mathf.SmoothDampAngle(eulerAngles.y, eulerAngles2.y, ref camSmoothDampRotationVelocity.y, camRotationSmoothDampTime, float.PositiveInfinity, Time.unscaledDeltaTime);
				eulerAngles.z = Mathf.SmoothDampAngle(eulerAngles.z, eulerAngles2.z, ref camSmoothDampRotationVelocity.z, camRotationSmoothDampTime, float.PositiveInfinity, Time.unscaledDeltaTime);
				cameraTransform.eulerAngles = eulerAngles;
				if (camTransitionTimer <= 0f)
				{
					currentMenuScreen.gameObject.SetActive(value: true);
					currentMenuScreen.shouldDisplay = true;
				}
			}
		}

		public void SetAllowTransition(bool value)
		{
			allowTransition = value;
		}

		public void SetDesiredMenuScreen(BaseMainMenuScreen newDesiredMenuScreen)
		{
			if (allowTransition)
			{
				desiredMenuScreen = newDesiredMenuScreen;
			}
		}

		public void ClearEngagementScreen()
		{
			if (!CheckWarningScreen())
			{
				desiredMenuScreen = titleMenuScreen;
			}
		}

		private void UpdateEoSLoginState()
		{
			if (lastEOSLoginState == EOSLoginManager.loginState)
			{
				return;
			}
			switch (EOSLoginManager.loginState)
			{
			case EOSLoginManager.EOSLoginState.AttemptingLink:
				AddAccountLinkPopup();
				break;
			case EOSLoginManager.EOSLoginState.FailedLogin:
				AddAccountLinkPopup();
				break;
			case EOSLoginManager.EOSLoginState.FailedLink:
				AddAccountLinkPopup();
				break;
			case EOSLoginManager.EOSLoginState.Success:
				if (titleMenuScreen.isActiveAndEnabled)
				{
					mainMenuButtonPanel?.SetActive(value: true);
				}
				break;
			}
			lastEOSLoginState = EOSLoginManager.loginState;
		}

		private void AddAccountLinkPopup()
		{
			SimpleDialogBox dialogBox = SimpleDialogBox.Create();
			Action retryLoginFunction = delegate
			{
				if ((bool)dialogBox)
				{
					RetryLogin();
				}
			};
			Action deactiveCrossplayAndRestartFunction = delegate
			{
				if ((bool)dialogBox)
				{
					DeactiveCrossPlayAndRestart();
				}
			};
			dialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "EOS_NOT_LINKED_TITLE",
				formatParams = Array.Empty<object>()
			};
			dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "EOS_NOT_LINKED_MESSAGE",
				formatParams = Array.Empty<object>()
			};
			dialogBox.AddActionButton(delegate
			{
				retryLoginFunction();
			}, "EOS_RETRY_LOGIN", true);
			dialogBox.AddActionButton(delegate
			{
				deactiveCrossplayAndRestartFunction();
			}, "EOS_DEACTIVATE_CROSSPLAY_RESTART", true);
		}

		private void RetryLogin()
		{
			if (EOSLoginManager.loggedInAuthId == null)
			{
				new EOSLoginManager().TryLogin();
			}
			else if (titleMenuScreen.isActiveAndEnabled)
			{
				mainMenuButtonPanel?.SetActive(value: true);
			}
		}

		private void DeactiveCrossPlayAndRestart()
		{
			Console.instance.FindConVar("egsToggle")?.AttemptSetString("0");
			Console.instance.SubmitCmd(null, "quit");
		}

		private void ShowFirstTimeCrossPlayPopup()
		{
			SimpleDialogBox dialogBox = SimpleDialogBox.Create();
			Action activateCrossplayFunction = delegate
			{
				if ((bool)dialogBox)
				{
					ActivateCrossPlay();
				}
			};
			Action deactivateCrossplayFunction = delegate
			{
				if ((bool)dialogBox)
				{
					DeactivateCrossPlay();
				}
			};
			Action ShowCrossplayInfo = delegate
			{
				if ((bool)dialogBox)
				{
					Application.OpenURL("https://support.gearboxsoftware.com/hc/en-us/articles/4440999200269");
				}
			};
			dialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "FIRST_TIME_CROSSPLAY_POPUP_HEADER",
				formatParams = Array.Empty<object>()
			};
			dialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
			{
				token = "FIRST_TIME_CROSSPLAY_POPUP_DESCRIPTION",
				formatParams = Array.Empty<object>()
			};
			dialogBox.AddActionButton(delegate
			{
				activateCrossplayFunction();
			}, "STAT_CONTINUE", true);
			dialogBox.AddActionButton(delegate
			{
				ShowCrossplayInfo();
			}, "FIRST_TIME_CROSSPLAY_POPUP_INFO", false);
			dialogBox.AddActionButton(delegate
			{
				deactivateCrossplayFunction();
			}, "FIRST_TIME_CROSSPLAY_POPUP_DISABLE_CROSSPLAY", true);
			static void ActivateCrossPlay()
			{
				PlayerPrefs.SetInt("ShownFirstTimePopup", 1);
			}
			static void DeactivateCrossPlay()
			{
				PlayerPrefs.SetInt("ShownFirstTimePopup", 1);
				Console.instance.FindConVar("egsToggle")?.AttemptSetString("1");
				Console.instance.SubmitCmd(null, "quit");
			}
		}

		public void StartWaitForLoad()
		{
			if (!IsMainUserSignedIn())
			{
				StartCoroutine(WaitForPlatformLoad());
				return;
			}
			MainMenuController.OnPreMainMenuInitialized?.Invoke();
			isInitialized = true;
		}

		private IEnumerator WaitForPlatformLoad()
		{
			MainMenuController.OnPreMainMenuInitialized?.Invoke();
			SaveSystem platformSaveSystem = PlatformSystems.saveSystem;
			platformSaveSystem.LoadInitialData();
			while (!platformSaveSystem.isInitialLoadFinished)
			{
				yield return null;
			}
			PlatformSystems.userManager.EnableUserControllerHandling();
			if (platformSaveSystem.userProfile != null)
			{
				LocalUserManager.SetLocalUsers(new LocalUserManager.LocalUserInitializationInfo[1]
				{
					new LocalUserManager.LocalUserInitializationInfo
					{
						profile = platformSaveSystem.userProfile
					}
				});
				Console.instance.SubmitCmd(null, "exec config");
				logbookButton.interactable = false;
				while (!LogBookController.IsStaticDataReady)
				{
					yield return null;
				}
				logbookButton.interactable = true;
				isInitialized = true;
			}
			else
			{
				isInitialized = true;
			}
		}

		public void EnableContinueEAWarningButton()
		{
			continueButtonTransition.interactable = true;
		}
	}
	[RequireComponent(typeof(MPEventSystemLocator))]
	public class ProfileMainMenuScreen : BaseMainMenuScreen
	{
		public GameObject createProfilePanel;

		public TMP_InputField createProfileNameInputField;

		public MPButton submitProfileNameButton;

		public GameObject gotoSelectProfilePanelButtonContainer;

		public GameObject selectProfilePanel;

		public MPButton gotoCreateProfilePanelButton;

		public UserProfileListController existingProfileListController;

		private MPEventSystemLocator eventSystemLocator;

		private bool firstTimeConfiguration;

		private const string defaultName = "Nameless Survivor";

		private string GuessDefaultProfileName()
		{
			return PlatformSystems.saveSystem.GetPlatformUsernameOrDefault("Nameless Survivor");
		}

		public UserProfile Editor_TryOpenTestProfile()
		{
			List<string> availableProfileNames = PlatformSystems.saveSystem.GetAvailableProfileNames();
			if (availableProfileNames.Count > 0)
			{
				UnityEngine.Debug.LogWarning("Got existing profile!");
				return PlatformSystems.saveSystem.GetProfile(availableProfileNames[0]);
			}
			return null;
		}

		public void OpenDefaultProfile()
		{
			GuessDefaultProfileName();
			UserProfile mainProfile = null;
			SetMainProfile(mainProfile);
		}

		protected new void Awake()
		{
			eventSystemLocator = GetComponent<MPEventSystemLocator>();
			existingProfileListController.onProfileSelected += SetMainProfile;
			existingProfileListController.onListRebuilt += OnListRebuilt;
		}

		protected new void OnEnable()
		{
			firstTimeConfiguration = true;
			List<string> availableProfileNames = PlatformSystems.saveSystem.GetAvailableProfileNames();
			for (int i = 0; i < availableProfileNames.Count; i++)
			{
				if (IsProfileCustom(PlatformSystems.saveSystem.GetProfile(availableProfileNames[i])))
				{
					firstTimeConfiguration = false;
					break;
				}
			}
			if (firstTimeConfiguration)
			{
				OpenCreateProfileMenu(firstTime: true);
				return;
			}
			createProfilePanel.SetActive(value: false);
			selectProfilePanel.SetActive(value: true);
			OnListRebuilt();
			gotoSelectProfilePanelButtonContainer.SetActive(value: true);
		}

		public void OpenCreateProfileMenu(bool firstTime)
		{
			selectProfilePanel.SetActive(value: false);
			createProfilePanel.SetActive(value: true);
			createProfileNameInputField.text = GuessDefaultProfileName();
			if (firstTime)
			{
				gotoSelectProfilePanelButtonContainer.SetActive(value: false);
			}
		}

		private void OnListRebuilt()
		{
			existingProfileListController.GetReadOnlyElementsList();
		}

		protected void OnDisable()
		{
		}

		private void SetMainProfile(UserProfile profile)
		{
			LocalUserManager.SetLocalUsers(new LocalUserManager.LocalUserInitializationInfo[1]
			{
				new LocalUserManager.LocalUserInitializationInfo
				{
					profile = profile
				}
			});
			if (myMainMenuController != null)
			{
				myMainMenuController.desiredMenuScreen = myMainMenuController.titleMenuScreen;
			}
			else
			{
				UnityEngine.Debug.LogError("myMainMenuController reference null on ProfileMainMenuScreen.cs while trying to run SetMainProfile(UserProfile profile)");
			}
		}

		private static bool IsProfileCustom(UserProfile profile)
		{
			return profile.fileName != "default";
		}

		private static bool IsNewProfileNameAcceptable(string newProfileName)
		{
			if (PlatformSystems.saveSystem.GetProfile(newProfileName) != null)
			{
				return false;
			}
			if (newProfileName == "")
			{
				return false;
			}
			return true;
		}

		public void OnAddProfilePressed()
		{
			if (eventSystemLocator.eventSystem.currentSelectedGameObject == createProfileNameInputField.gameObject && !Input.GetKeyDown(KeyCode.Return) && !Input.GetKeyDown(KeyCode.KeypadEnter))
			{
				return;
			}
			string text = createProfileNameInputField.text;
			if (IsNewProfileNameAcceptable(text))
			{
				createProfileNameInputField.text = "";
				UserProfile userProfile = PlatformSystems.saveSystem.CreateProfile(RoR2Application.cloudStorage, text, 0uL);
				if (userProfile != null)
				{
					SetMainProfile(userProfile);
				}
			}
		}

		protected new void Update()
		{
			if (!eventSystemLocator.eventSystem || eventSystemLocator.eventSystem.player == null || !eventSystemLocator.eventSystem.player.GetButton(31))
			{
				return;
			}
			GameObject currentSelectedGameObject = MPEventSystemManager.combinedEventSystem.currentSelectedGameObject;
			if (!currentSelectedGameObject)
			{
				return;
			}
			UserProfileListElementController component = currentSelectedGameObject.GetComponent<UserProfileListElementController>();
			if ((bool)component)
			{
				if (component.userProfile == null)
				{
					UnityEngine.Debug.LogError("!!!???");
					return;
				}
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.Create();
				string consoleString = "user_profile_delete \"" + component.userProfile.fileName + "\"";
				simpleDialogBox.headerToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "USER_PROFILE_DELETE_HEADER",
					formatParams = null
				};
				simpleDialogBox.descriptionToken = new SimpleDialogBox.TokenParamsPair
				{
					token = "USER_PROFILE_DELETE_DESCRIPTION",
					formatParams = new object[1] { component.userProfile.name }
				};
				simpleDialogBox.AddCommandButton(consoleString, "USER_PROFILE_DELETE_YES");
				simpleDialogBox.AddCancelButton("USER_PROFILE_DELETE_NO");
			}
		}
	}
	public class SignupMainMenuScreen : BaseMainMenuScreen
	{
		private const string environment = "prod";

		private const string title = "Canary";

		private static string viewableName = "Signup";

		[SerializeField]
		private TMP_InputField emailInput;

		[SerializeField]
		private HGButton submitButton;

		[SerializeField]
		private HGButton backButton;

		[SerializeField]
		private HGTextMeshProUGUI successText;

		[SerializeField]
		private HGTextMeshProUGUI failureText;

		[SerializeField]
		private HGTextMeshProUGUI waitingText;

		[SerializeField]
		private HGGamepadInputEvent backGamepadInputEvent;

		private SignupClient signupClient;

		private string email;

		private bool awaitingResponse;

		private HashSet<string> successfulEmailSubmissions;

		[SystemInitializer(new Type[] { })]
		private static void Init()
		{
			ViewablesCatalog.AddNodeToRoot(new ViewablesCatalog.Node(viewableName, isFolder: false)
			{
				shouldShowUnviewed = CheckViewable
			});
		}

		private static bool CheckViewable(UserProfile userProfile)
		{
			return !userProfile.HasViewedViewable("/" + viewableName);
		}

		private new void Awake()
		{
			signupClient = new SignupClient("prod");
			successfulEmailSubmissions = new HashSet<string>();
		}

		private new void OnEnable()
		{
			waitingText?.gameObject?.SetActive(value: false);
			successText?.gameObject?.SetActive(value: false);
			failureText?.gameObject?.SetActive(value: false);
			if ((bool)backGamepadInputEvent)
			{
				backGamepadInputEvent.enabled = true;
			}
		}

		private new void Update()
		{
			base.Update();
			if ((bool)submitButton)
			{
				if ((bool)emailInput && SignupClient.IsEmailValid(emailInput.text) && !awaitingResponse && !successfulEmailSubmissions.Contains(emailInput.text))
				{
					submitButton.interactable = true;
				}
				else
				{
					submitButton.interactable = false;
				}
			}
			if ((bool)backButton)
			{
				backButton.interactable = !awaitingResponse;
			}
			if ((bool)backGamepadInputEvent)
			{
				backGamepadInputEvent.enabled = !awaitingResponse;
			}
		}

		public void TrySubmit()
		{
			if (!awaitingResponse && (bool)emailInput && !successfulEmailSubmissions.Contains(emailInput.text) && SignupClient.IsEmailValid(emailInput.text))
			{
				email = emailInput.text;
				User user = Client.Instance.User;
				user.OnEncryptedAppTicketRequestComplete = (Action<bool, byte[]>)Delegate.Combine(user.OnEncryptedAppTicketRequestComplete, new Action<bool, byte[]>(ProcessAppTicketRefresh));
				Client.Instance.User.RequestEncryptedAppTicketAsync(new byte[0]);
				awaitingResponse = true;
				waitingText?.gameObject?.SetActive(value: true);
				successText?.gameObject?.SetActive(value: false);
				failureText?.gameObject?.SetActive(value: false);
			}
		}

		private void ProcessAppTicketRefresh(bool success, byte[] ticket)
		{
			bool flag = success;
			User user = Client.Instance.User;
			user.OnEncryptedAppTicketRequestComplete = (Action<bool, byte[]>)Delegate.Remove(user.OnEncryptedAppTicketRequestComplete, new Action<bool, byte[]>(ProcessAppTicketRefresh));
			if (success)
			{
				if (SignupClient.IsTicketValid(ticket))
				{
					if (signupClient != null)
					{
						signupClient.SignupCompleted += SignupCompleted;
						signupClient.SignupSteamAsync(email, "Canary", ticket);
					}
				}
				else
				{
					UnityEngine.Debug.LogError("Can't signup with an invalid ticket!");
					flag = false;
				}
			}
			else
			{
				UnityEngine.Debug.LogError("Failure refreshing Encrypted App Ticket from Steam for mailing list!");
				flag = false;
			}
			if (!flag)
			{
				awaitingResponse = false;
				waitingText?.gameObject?.SetActive(value: false);
				successText?.gameObject?.SetActive(value: false);
				failureText?.gameObject?.SetActive(value: true);
			}
		}

		private void SignupCompleted(string email, HttpStatusCode statusCode)
		{
			awaitingResponse = false;
			waitingText?.gameObject?.SetActive(value: false);
			if (statusCode == HttpStatusCode.OK)
			{
				successfulEmailSubmissions.Add(email);
				successText?.gameObject?.SetActive(value: true);
				failureText?.gameObject?.SetActive(value: false);
			}
			else
			{
				successText?.gameObject?.SetActive(value: false);
				failureText?.gameObject?.SetActive(value: true);
			}
		}
	}
	public class SubmenuMainMenuScreen : BaseMainMenuScreen
	{
		[FormerlySerializedAs("settingsPanelPrefab")]
		public GameObject submenuPanelPrefab;

		private GameObject submenuPanelInstance;

		private HGHeaderNavigationController headerNavigationController;

		private new void Awake()
		{
			submenuPanelInstance = UnityEngine.Object.Instantiate(submenuPanelPrefab, base.transform);
			submenuPanelInstance.GetComponent<HGHeaderNavigationController>().isPrimaryPlayer = true;
			headerNavigationController = GetComponentInChildren<HGHeaderNavigationController>();
		}

		public override void OnEnter(MainMenuController mainMenuController)
		{
			submenuPanelInstance.SetActive(value: true);
			headerNavigationController?.ChooseFirstHeader();
			base.OnEnter(mainMenuController);
		}

		public override void OnExit(MainMenuController mainMenuController)
		{
			base.OnExit(mainMenuController);
		}

		public new void Update()
		{
			if (!submenuPanelInstance.activeSelf && (bool)myMainMenuController)
			{
				myMainMenuController.SetDesiredMenuScreen(myMainMenuController.titleMenuScreen);
			}
		}
	}
	[RequireComponent(typeof(FirstSelectedObjectProvider))]
	public class MultiplayerMenuController : BaseMainMenuScreen
	{
		public enum Subview
		{
			Main,
			FindGame,
			HostGame
		}

		public enum MPButtons
		{
			HostGame,
			FindGame,
			Quickplay,
			StartPrivateGame,
			Invite,
			FindFriendSession,
			Back,
			EnterGame,
			NONE
		}

		private const float titleTransitionDuration = 0.5f;

		private const float titleTransitionBuffer = 0.1f;

		public UnityEngine.UI.Image fadeImage;

		public LerpUIRect[] uiToLerp;

		private float titleStopwatch;

		private Subview _curSubView;

		[Header("Subviews")]
		public GameObject MainMultiplayerMenu;

		public GameObject JoinGameMenu;

		public GameObject HostGameMenu;

		[Header("Buttons")]
		public MPButton hostGame;

		public MPButton findGame;

		public MPButton quickplayButton;

		public MPButton startPrivateGameButton;

		public MPButton inviteButton;

		public MPButton findFriendSessionButton;

		public MPButton backButton;

		public CarouselController gameModePicker;

		public MPButton enterGameButton;

		public GameObject[] lobbyActions;

		[Header("Quickplay Logic")]
		public LanguageTextMeshController quickplayLabelController;

		public string quickplayStartToken;

		public string quickplayStopToken;

		public RectTransform quickplaySpinnerRectTransform;

		public TextMeshProUGUI quickplayStateText;

		private string pendingQuickplayText;

		public RectTransform genericSpinnerRectTransform;

		private const float spinnerRotationSpeed = 360f;

		[Header("Sub-Views")]
		public SteamJoinClipboardLobby joinClipboardLobbyButtonController;

		public FriendSessionBrowserController friendSessionBrowserController;

		public LobbyUserList lobbyUserList;

		[Header("Platform Specific Components")]
		public CarouselController lobbyVisibilityController;

		public static float QuickplayWaitTime;

		public bool IsQuickPlaySearching;

		public bool IsQuickPlayButtonLocked;

		private Coroutine checkCanPlayOnlineCoroutine;

		public static MultiplayerMenuController instance { get; private set; }

		public Subview GetCurrentSubview()
		{
			return _curSubView;
		}

		public void SetSubview(Subview targetSubview)
		{
			_curSubView = targetSubview;
			MainMultiplayerMenu.SetActive(targetSubview == Subview.Main);
			JoinGameMenu.SetActive(targetSubview == Subview.FindGame);
			HostGameMenu.SetActive(targetSubview == Subview.HostGame);
			if ((bool)lobbyUserList)
			{
				lobbyUserList.DisplayContent(targetSubview == Subview.HostGame || targetSubview == Subview.Main);
			}
		}

		public void ReturnToMainSubview()
		{
			SetSubview(Subview.Main);
		}

		private void ToggleMPFeatures(MPFeatures featureFlags)
		{
			Toggle(hostGame, featureFlags.HasFlag(MPFeatures.HostGame));
			Toggle(findGame, featureFlags.HasFlag(MPFeatures.FindGame));
			Toggle(quickplayButton, featureFlags.HasFlag(MPFeatures.Quickplay));
			Toggle(gameModePicker, val: true);
			Toggle(startPrivateGameButton, featureFlags.HasFlag(MPFeatures.PrivateGame));
			Toggle(inviteButton, featureFlags.HasFlag(MPFeatures.Invite));
			Toggle(findFriendSessionButton, featureFlags.HasFlag(MPFeatures.FindFriendSession));
			Toggle(enterGameButton, featureFlags.HasFlag(MPFeatures.EnterGameButton));
		}

		private void ToggleMPFeaturesInteractable(MPFeatures featureFlags)
		{
			hostGame.interactable = featureFlags.HasFlag(MPFeatures.HostGame);
			findGame.interactable = featureFlags.HasFlag(MPFeatures.FindGame);
			quickplayButton.interactable = featureFlags.HasFlag(MPFeatures.Quickplay) && ShouldEnableQuickplayButton();
			gameModePicker.ToggleArrowsInteractable(isInteractable: true);
			startPrivateGameButton.interactable = featureFlags.HasFlag(MPFeatures.PrivateGame);
			inviteButton.interactable = featureFlags.HasFlag(MPFeatures.Invite);
			findFriendSessionButton.interactable = featureFlags.HasFlag(MPFeatures.FindFriendSession);
			if (enterGameButton != null)
			{
				enterGameButton.interactable = PlatformSystems.lobbyManager.ShouldEnableEnterGameButton();
			}
		}

		private void SetDefaultFallback()
		{
			if (quickplayButton.isActiveAndEnabled)
			{
				quickplayButton.defaultFallbackButton = true;
			}
		}

		private void ToggleMPLobbyFeaturesInteractable(MPLobbyFeatures lobbyFlags)
		{
			lobbyUserList.createLobbyButton.interactable = lobbyFlags.HasFlag(MPLobbyFeatures.CreateLobby);
			lobbyUserList.leaveLobbyButton.interactable = lobbyFlags.HasFlag(MPLobbyFeatures.LeaveLobby);
			lobbyUserList.copyLobbyButton.interactable = lobbyFlags.HasFlag(MPLobbyFeatures.Clipboard);
			lobbyUserList.joinLobbyButton.interactable = lobbyFlags.HasFlag(MPLobbyFeatures.Clipboard);
			lobbyUserList.lobbyTypeDropdown.interactable = lobbyFlags.HasFlag(MPLobbyFeatures.LobbyDropdownOptions);
		}

		private void Toggle(MonoBehaviour component, bool val)
		{
			if ((bool)component)
			{
				component.gameObject.SetActive(val);
			}
			else
			{
				UnityEngine.Debug.LogError("Null ref on Toggle of Button in MultiplayerMenuController on \"" + base.gameObject.name + "\"");
			}
		}

		private void Toggle(GameObject[] goToToggle, bool val)
		{
			int num = goToToggle.Length;
			for (int i = 0; i < num; i++)
			{
				goToToggle[i].gameObject.SetActive(val);
			}
		}

		private void Toggle(MonoBehaviour[] buttons, bool val)
		{
			int num = buttons.Length;
			for (int i = 0; i < num; i++)
			{
				buttons[i].gameObject.SetActive(val);
			}
		}

		public void SetQuickplayButtonStateText(string textKey, object[] formatArgs = null)
		{
			if (formatArgs == null)
			{
				formatArgs = Array.Empty<object>();
			}
			TextMeshProUGUI textMeshProUGUI = quickplayStateText;
			if ((bool)textMeshProUGUI)
			{
				textMeshProUGUI.text = Language.GetStringFormatted(textKey, formatArgs);
			}
		}

		public void SetButtonText(MPButton button, string textKey, object[] formatArgs = null)
		{
			if (formatArgs == null)
			{
				formatArgs = Array.Empty<object>();
			}
			TextMeshProUGUI component = button.GetComponent<TextMeshProUGUI>();
			if ((bool)component)
			{
				component.text = Language.GetStringFormatted(textKey, formatArgs);
			}
		}

		public void SetNetworkType(bool isInternet)
		{
			PlatformSystems.lobbyManager.SetNetworkType(isInternet);
		}

		public void RefreshFirstObjectSelectedProvider()
		{
			if ((bool)firstSelectedObjectProvider)
			{
				firstSelectedObjectProvider.firstSelectedObject = gameModePicker.gameObject;
				firstSelectedObjectProvider.fallBackFirstSelectedObjects = new GameObject[9] { gameModePicker.gameObject, hostGame.gameObject, findGame.gameObject, quickplayButton.gameObject, enterGameButton.gameObject, startPrivateGameButton.gameObject, inviteButton.gameObject, findFriendSessionButton.gameObject, backButton.gameObject };
			}
		}

		public new void OnEnable()
		{
			ResetText();
			ToggleMPFeatures(PlatformSystems.lobbyManager.GetPlatformMPFeatureFlags());
			SetupLocalAndInternetMPButtons();
			if ((bool)lobbyUserList)
			{
				lobbyUserList.DisplayContent(display: true);
			}
			RefreshFirstObjectSelectedProvider();
			BuildGameModeChoices();
			SetDefaultFallback();
			firstSelectedObjectProvider?.ForceSelectFirstInteractable();
			LerpAllUI(LerpUIRect.LerpState.Entering);
			if (!instance)
			{
				instance = SingletonHelper.Assign(instance, this);
			}
			PlatformSystems.lobbyManager.OnMultiplayerMenuEnabled(OnLobbyLeave);
			checkCanPlayOnlineCoroutine = StartCoroutine(CheckCanPlayOnline());
			firstSelectedObjectProvider?.ResetLastSelected();
			firstSelectedObjectProvider?.EnsureSelectedObject();
		}

		private IEnumerator CheckCanPlayOnline()
		{
			IEnumerator<NetworkManagerSystem.CanPlayOnlineState> canPlayOnlineEnumerator = NetworkManagerSystem.singleton.CanPlayOnline();
			NetworkManagerSystem.CanPlayOnlineState lastResult = NetworkManagerSystem.CanPlayOnlineState.Pending;
			while (canPlayOnlineEnumerator.MoveNext())
			{
				lastResult = canPlayOnlineEnumerator.Current;
				if (lastResult != 0)
				{
					break;
				}
				yield return null;
			}
			if (lastResult != NetworkManagerSystem.CanPlayOnlineState.Yes)
			{
				if (!NetworkManagerSystem.singleton.isNetworkActive)
				{
					PlatformSystems.lobbyManager.LeaveLobby();
				}
				myMainMenuController.SetDesiredMenuScreen(myMainMenuController.titleMenuScreen);
			}
			checkCanPlayOnlineCoroutine = null;
		}

		public void OnDisable()
		{
			if (checkCanPlayOnlineCoroutine != null)
			{
				StopCoroutine(checkCanPlayOnlineCoroutine);
			}
			LobbyManager lobbyManager = PlatformSystems.lobbyManager;
			lobbyManager.onLobbyLeave = (Action<PlatformID>)Delegate.Remove(lobbyManager.onLobbyLeave, new Action<PlatformID>(OnLobbyLeave));
			if (!NetworkManagerSystem.singleton.isNetworkActive)
			{
				PlatformSystems.lobbyManager.LeaveLobby();
			}
			instance = SingletonHelper.Unassign(instance, this);
		}

		private void OnLobbyLeave(PlatformID lobbyId)
		{
			ResetText();
			if (!(PlatformSystems.lobbyManager as SteamworksLobbyManager).isInLobbyDelayed && !PlatformSystems.lobbyManager.awaitingJoin && MainMenuController.instance.desiredMenuScreen == MainMenuController.instance.multiplayerMenuScreen)
			{
				PlatformSystems.lobbyManager.CreateLobby();
			}
		}

		public new void Awake()
		{
			base.Awake();
			LerpAllUI(LerpUIRect.LerpState.Entering);
			hostGame.onClick.AddListener(delegate
			{
				SetSubview(Subview.HostGame);
			});
			findGame.onClick.AddListener(delegate
			{
				SetSubview(Subview.FindGame);
			});
			quickplayButton.onClick.AddListener(delegate
			{
				PlatformSystems.lobbyManager.ToggleQuickplay();
			});
			startPrivateGameButton.onClick.AddListener(delegate
			{
				PlatformSystems.lobbyManager.OnStartPrivateGame();
			});
			findFriendSessionButton.onClick.AddListener(delegate
			{
				PlatformSystems.lobbyManager.OpenFriendSessionBrowser();
			});
		}

		public void ShowFriendSessionBrowser()
		{
			friendSessionBrowserController.gameObject.SetActive(value: true);
		}

		public void LerpAllUI(LerpUIRect.LerpState lerpState)
		{
			LerpUIRect[] array = uiToLerp;
			for (int i = 0; i < array.Length; i++)
			{
				array[i].lerpState = lerpState;
			}
		}

		private void BuildGameModeChoices()
		{
			List<CarouselController.Choice> list = new List<CarouselController.Choice>();
			List<string> list2 = gameModePicker.choices.Select((CarouselController.Choice choice) => choice.suboptionDisplayToken).ToList();
			for (GameModeIndex gameModeIndex = (GameModeIndex)0; (int)gameModeIndex < GameModeCatalog.gameModeCount; gameModeIndex++)
			{
				Run gameModePrefabComponent = GameModeCatalog.GetGameModePrefabComponent(gameModeIndex);
				ExpansionRequirementComponent component = gameModePrefabComponent.GetComponent<ExpansionRequirementComponent>();
				if (gameModePrefabComponent != null && gameModePrefabComponent.userPickable && list2.Contains(gameModePrefabComponent.nameToken) && (!component || !component.requiredExpansion || EntitlementManager.localUserEntitlementTracker.AnyUserHasEntitlement(component.requiredExpansion.requiredEntitlement)))
				{
					list.Add(new CarouselController.Choice
					{
						suboptionDisplayToken = gameModePrefabComponent.nameToken,
						convarValue = gameModePrefabComponent.name
					});
				}
			}
			gameModePicker.choices = list.ToArray();
			gameModePicker.gameObject.SetActive(list.Count > 1);
			string @string = Console.instance.FindConVar("gamemode").GetString();
			bool flag = false;
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].convarValue == @string)
				{
					flag = true;
					break;
				}
			}
			if (list.Count == 1 || !flag)
			{
				UnityEngine.Debug.LogFormat("Invalid gamemode {0} detected. Reverting to ClassicRun.", @string);
				gameModePicker.SubmitSetting(list[0].convarValue);
			}
		}

		public void ResetText()
		{
			if (PlatformSystems.lobbyManager.GetPlatformMPFeatureFlags().HasFlag(MPFeatures.Quickplay))
			{
				SetQuickplayText("", new object[0]);
			}
		}

		private void SetupLocalAndInternetMPButtons()
		{
			LanguageTextMeshController componentInChildren = findFriendSessionButton.GetComponentInChildren<LanguageTextMeshController>();
			LanguageTextMeshController languageTextMeshController = (inviteButton as HGButton)?.hoverLanguageTextMeshController;
			LanguageTextMeshController componentInChildren2 = startPrivateGameButton.GetComponentInChildren<LanguageTextMeshController>();
			if (PlatformSystems.lobbyManager.IsNetworkTypeInternet())
			{
				if ((bool)componentInChildren)
				{
					componentInChildren.token = "FRIEND_GAME_BROWSER";
				}
				if ((bool)languageTextMeshController)
				{
					languageTextMeshController.token = "FRIEND_GAME_BROWSER_DESCRIPTION";
				}
				if ((bool)componentInChildren2)
				{
					componentInChildren2.token = "HOST_PRIVATE_GAME";
				}
				return;
			}
			enterGameButton.interactable = false;
			if ((bool)componentInChildren)
			{
				componentInChildren.token = "BROWSE_LOCAL_GAME";
			}
			if ((bool)languageTextMeshController)
			{
				languageTextMeshController.token = "BROWSE_LOCAL_GAME_DESCRIPTION";
			}
			if ((bool)componentInChildren2)
			{
				componentInChildren2.token = "HOST_LOCAL_GAME";
			}
		}

		public void ReturnToMainMenu()
		{
			ResetLobby();
			myMainMenuController.SetDesiredMenuScreen(myMainMenuController.titleMenuScreen);
		}

		public void ResetLobby()
		{
			PlatformSystems.lobbyManager.LeaveLobby();
			if (enterGameButton != null)
			{
				enterGameButton.interactable = PlatformSystems.lobbyManager.ShouldEnableEnterGameButton();
			}
			lobbyUserList.ClearUserList();
		}

		public void OnEnterGameButtonPressed()
		{
			titleStopwatch = 0f;
			LerpAllUI(LerpUIRect.LerpState.Leaving);
			PlatformSystems.lobbyManager.EnterGameButtonPressed();
		}

		private void UpdateSpinner(RectTransform spinnerRectTransform)
		{
			UnityEngine.Vector3 localEulerAngles = spinnerRectTransform.localEulerAngles;
			localEulerAngles.z += Time.deltaTime * 360f;
			spinnerRectTransform.localEulerAngles = localEulerAngles;
		}

		private new void Update()
		{
			base.Update();
			titleStopwatch += Time.deltaTime;
			PlatformSystems.lobbyManager.CheckBusyTimer();
			if (friendSessionBrowserController.gameObject.activeSelf)
			{
				return;
			}
			if (PlatformSystems.lobbyManager.IsQuickPlaySearching())
			{
				ToggleMPFeaturesInteractable(MPFeatures.Quickplay);
				quickplayLabelController.token = quickplayStopToken;
			}
			if (PlatformSystems.lobbyManager.ShouldShowSpinner())
			{
				quickplaySpinnerRectTransform.gameObject.SetActive(value: true);
				UpdateSpinner(quickplaySpinnerRectTransform);
			}
			else
			{
				ToggleMPFeaturesInteractable(PlatformSystems.lobbyManager.GetPlatformMPFeatureFlags());
				quickplaySpinnerRectTransform.gameObject.SetActive(value: false);
				if (!PlatformSystems.lobbyManager.IsQuickPlaySearching())
				{
					quickplayLabelController.token = quickplayStartToken;
				}
				else
				{
					quickplayLabelController.token = quickplayStopToken;
				}
				if ((bool)quickplayButton)
				{
					quickplayButton.interactable = ShouldEnableQuickplayButton();
				}
				else
				{
					quickplayButton.interactable = ShouldEnableQuickplayButton();
					if (!ShouldEnableQuickplayButton())
					{
						quickplaySpinnerRectTransform.gameObject.SetActive(value: true);
						UpdateSpinner(quickplaySpinnerRectTransform);
					}
				}
				if ((bool)startPrivateGameButton)
				{
					startPrivateGameButton.interactable = ShouldEnableStartPrivateGameButton();
				}
				if ((bool)joinClipboardLobbyButtonController && (bool)joinClipboardLobbyButtonController.mpButton)
				{
					joinClipboardLobbyButtonController.mpButton.interactable = ShouldEnableJoinClipboardLobbyButton();
				}
				if ((bool)inviteButton)
				{
					inviteButton.interactable = PlatformSystems.lobbyManager.ShouldEnableInviteButton();
				}
				if ((bool)findFriendSessionButton)
				{
					findFriendSessionButton.interactable = ShouldEnableFindFriendSessionButton();
				}
				backButton.interactable = ShouldEnableBackButton();
				if (enterGameButton != null && enterGameButton.isActiveAndEnabled)
				{
					enterGameButton.interactable = PlatformSystems.lobbyManager.ShouldEnableEnterGameButton();
				}
			}
			if (PlatformSystems.lobbyManager.ShouldShowGenericSpinner())
			{
				genericSpinnerRectTransform.gameObject.SetActive(value: true);
				UpdateSpinner(genericSpinnerRectTransform);
			}
			else
			{
				genericSpinnerRectTransform.gameObject.SetActive(value: false);
			}
			if (!string.IsNullOrEmpty(pendingQuickplayText))
			{
				SetQuickplayText(pendingQuickplayText);
				pendingQuickplayText = string.Empty;
			}
			if (SimpleDialogBox.instancesList.Count > 0 && (bool)firstSelectedObjectProvider)
			{
				SimpleDialogBox simpleDialogBox = SimpleDialogBox.instancesList[0];
				if ((bool)simpleDialogBox)
				{
					firstSelectedObjectProvider.firstSelectedObject = simpleDialogBox.GetComponentInChildren<MPButton>().gameObject;
					firstSelectedObjectProvider.ResetLastSelected();
				}
			}
			firstSelectedObjectProvider?.EnsureSelectedObject();
		}

		public void InviteButtonPressed()
		{
			if (!PlatformSystems.lobbyManager.isInLobby)
			{
				NetworkManagerSystem.singleton.CreateLocalLobby();
			}
			PlatformSystems.lobbyManager.OpenInviteOverlay();
		}

		private bool ShouldEnableQuickplayButton()
		{
			return PlatformSystems.lobbyManager.ShouldEnableQuickplayButton();
		}

		private bool ShouldEnableStartPrivateGameButton()
		{
			return PlatformSystems.lobbyManager.ShouldEnableStartPrivateGameButton();
		}

		private bool ShouldEnableJoinClipboardLobbyButton()
		{
			if (!PlatformSystems.lobbyManager.newestLobbyData.quickplayQueued)
			{
				return joinClipboardLobbyButtonController.validClipboardLobbyID;
			}
			return false;
		}

		private bool ShouldEnableFindFriendSessionButton()
		{
			return PlatformSystems.lobbyManager.ShouldEnableFindFriendSessionButton();
		}

		public void ToggleQuickplay()
		{
			PlatformSystems.lobbyManager.ToggleQuickplay();
		}

		public override bool IsReadyToLeave()
		{
			return true;
		}

		public bool ShouldEnableBackButton()
		{
			if (!PlatformSystems.lobbyManager.IsBusy)
			{
				return _curSubView == Subview.Main;
			}
			return false;
		}

		public void GoBack()
		{
			if (friendSessionBrowserController.isActiveAndEnabled)
			{
				friendSessionBrowserController.gameObject.SetActive(value: false);
			}
			else if (PlatformSystems.lobbyManager.IsQuickPlaySearching() && NetworkManagerSystem.singleton.IsHost())
			{
				quickplayButton.InvokeClick();
			}
			else if (PlatformSystems.lobbyManager.isInLobby)
			{
				ResetLobby();
				ResetLastSelected();
				ReturnToMainMenu();
			}
			else if (ShouldEnableBackButton())
			{
				ReturnToMainMenu();
			}
		}

		public void ResetLastSelected()
		{
			firstSelectedObjectProvider?.ResetLastSelected();
			firstSelectedObjectProvider?.EnsureSelectedObject();
		}

		public void SetQuickplayTextBelowMinPlayers()
		{
			if (PlatformSystems.lobbyManager.HasMPFeature(MPFeatures.Quickplay))
			{
				object[] formatArgs = new object[2]
				{
					PlatformSystems.lobbyManager.calculatedTotalPlayerCount,
					RoR2Application.maxPlayers
				};
				SetQuickplayText("STEAM_LOBBY_STATUS_QUICKPLAY_WAITING_BELOW_MINIMUM_PLAYERS", formatArgs);
			}
		}

		public void UpdateCutoffTimeText(int numberOfPlayers, float timeRemaining)
		{
			object[] formatArgs = new object[3]
			{
				numberOfPlayers,
				RoR2Application.maxPlayers,
				(int)Math.Max(0.0, timeRemaining)
			};
			SetQuickplayText("STEAM_LOBBY_STATUS_QUICKPLAY_WAITING_ABOVE_MINIMUM_PLAYERS", formatArgs);
		}

		public void SetPendingQuickplayText(string text, object[] formatArgs = null)
		{
			if (formatArgs == null)
			{
				formatArgs = Array.Empty<object>();
			}
			pendingQuickplayText = Language.GetStringFormatted(text, formatArgs);
		}

		public void SetQuickplayText(string text, object[] formatArgs = null)
		{
			if (formatArgs == null)
			{
				formatArgs = Array.Empty<object>();
			}
			quickplayStateText.text = Language.GetStringFormatted(text, formatArgs);
		}

		public void ToggleAllButtonsInteractable(bool interactable)
		{
			for (int i = 0; i < 8; i++)
			{
				SetButtonInteractableStatus((MPButtons)i, interactable);
			}
			firstSelectedObjectProvider.ForceSelectFirstInteractable();
		}

		public void SetButtonInteractableStatus(MPButtons button, bool interactable)
		{
			MPButton mPButton = null;
			switch (button)
			{
			case MPButtons.HostGame:
				mPButton = hostGame;
				break;
			case MPButtons.FindGame:
				mPButton = findGame;
				break;
			case MPButtons.Quickplay:
				mPButton = quickplayButton;
				break;
			case MPButtons.StartPrivateGame:
				mPButton = startPrivateGameButton;
				break;
			case MPButtons.Invite:
				mPButton = inviteButton;
				break;
			case MPButtons.FindFriendSession:
				mPButton = findFriendSessionButton;
				break;
			case MPButtons.Back:
				mPButton = backButton;
				break;
			case MPButtons.EnterGame:
				mPButton = enterGameButton;
				break;
			}
			if (mPButton != null)
			{
				mPButton.interactable = interactable;
			}
		}
	}
	public class PlatformToggle : MonoBehaviour
	{
		public bool Steam;

		public bool XboxOne;

		public bool XboxSeries;

		public bool PS4;

		public bool PS5;

		public bool Switch;

		private void Awake()
		{
			base.gameObject.SetActive(Steam);
		}
	}
	public class TitleMenuController : MonoBehaviour
	{
		public ConsoleFunctions consoleFunctions;

		public MainMenuController mainMenuController;

		public DelayedEvent titleDelayedEvent;

		public CanvasGroup titleButtonPanelCanvas;

		public MultiplayerMenuController multiplayerMenuController;

		public void OnSinglePlayerButtonPressed()
		{
			if (CanTransitionOutOfTitleMenu())
			{
				consoleFunctions.SubmitCmd("transition_command \"gamemode ClassicRun; host 0;\"");
				titleDelayedEvent.CallDelayed(0f);
				titleButtonPanelCanvas.interactable = false;
				mainMenuController.SetAllowTransition(value: false);
			}
		}

		public void OnMultiplayerButtonPressed()
		{
			if (CanTransitionOutOfTitleMenu() && RoR2Application.IsAllUsersEntitlementsUpdated)
			{
				multiplayerMenuController.SetNetworkType(isInternet: true);
				mainMenuController.SetDesiredMenuScreen(mainMenuController.multiplayerMenuScreen);
			}
		}

		public void OnExtraGameModeButtonPressed()
		{
			if (CanTransitionOutOfTitleMenu())
			{
				mainMenuController.SetDesiredMenuScreen(mainMenuController.extraGameModeMenuScreen);
			}
		}

		public void OnLogbookButtonPressed()
		{
			if (CanTransitionOutOfTitleMenu())
			{
				consoleFunctions.SubmitCmd("transition_command \"set_scene logbook\"");
				titleDelayedEvent.CallDelayed(0f);
			}
		}

		private bool CanTransitionOutOfTitleMenu()
		{
			if (RoR2Application.IsMainMenuInitialized && RoR2Application.IsEntitlementsUpdated)
			{
				return !FadeToBlackManager.IsFading();
			}
			return false;
		}
	}
}
namespace Unity
{
	[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
	public class GeneratedNetworkCode
	{
		public static void _ReadStructSyncListPickupIndex_VoidSuppressorBehavior(NetworkReader reader, VoidSuppressorBehavior.SyncListPickupIndex instance)
		{
			ushort num = reader.ReadUInt16();
			instance.Clear();
			for (ushort num2 = 0; num2 < num; num2++)
			{
				instance.AddInternal(instance.DeserializeItem(reader));
			}
		}

		public static void _WriteStructSyncListPickupIndex_VoidSuppressorBehavior(NetworkWriter writer, VoidSuppressorBehavior.SyncListPickupIndex value)
		{
			ushort count = value.Count;
			writer.Write(count);
			for (ushort num = 0; num < count; num++)
			{
				value.SerializeItem(writer, value.GetItem(num));
			}
		}

		public static void _ReadStructSyncListUserVote_None(NetworkReader reader, SyncListUserVote instance)
		{
			ushort num = reader.ReadUInt16();
			instance.Clear();
			for (ushort num2 = 0; num2 < num; num2++)
			{
				instance.AddInternal(instance.DeserializeItem(reader));
			}
		}

		public static void _WriteStructSyncListUserVote_None(NetworkWriter writer, SyncListUserVote value)
		{
			ushort count = value.Count;
			writer.Write(count);
			for (ushort num = 0; num < count; num++)
			{
				value.SerializeItem(writer, value.GetItem(num));
			}
		}

		public static void _WriteArrayString_None(NetworkWriter writer, string[] value)
		{
			if (value == null)
			{
				writer.Write((ushort)0);
				return;
			}
			ushort value2 = (ushort)value.Length;
			writer.Write(value2);
			for (ushort num = 0; num < value.Length; num++)
			{
				writer.Write(value[num]);
			}
		}

		public static string[] _ReadArrayString_None(NetworkReader reader)
		{
			int num = reader.ReadUInt16();
			if (num == 0)
			{
				return new string[0];
			}
			string[] array = new string[num];
			for (int i = 0; i < num; i++)
			{
				ref string reference = ref array[i];
				reference = reader.ReadString();
			}
			return array;
		}

		public static sbyte[] _ReadArraySByte_None(NetworkReader reader)
		{
			int num = reader.ReadUInt16();
			if (num == 0)
			{
				return new sbyte[0];
			}
			sbyte[] array = new sbyte[num];
			for (int i = 0; i < num; i++)
			{
				ref sbyte reference = ref array[i];
				reference = (sbyte)reader.ReadPackedUInt32();
			}
			return array;
		}

		public static void _WriteArraySByte_None(NetworkWriter writer, sbyte[] value)
		{
			if (value == null)
			{
				writer.Write((ushort)0);
				return;
			}
			ushort value2 = (ushort)value.Length;
			writer.Write(value2);
			for (ushort num = 0; num < value.Length; num++)
			{
				writer.WritePackedUInt32((uint)value[num]);
			}
		}

		public static void _WriteNetworkGuid_None(NetworkWriter writer, NetworkGuid value)
		{
			writer.WritePackedUInt64(value._a);
			writer.WritePackedUInt64(value._b);
		}

		public static void _WriteNetworkDateTime_None(NetworkWriter writer, NetworkDateTime value)
		{
			writer.WritePackedUInt64((ulong)value._binaryValue);
		}

		public static void _WriteRunStopwatch_Run(NetworkWriter writer, Run.RunStopwatch value)
		{
			writer.Write(value.offsetFromFixedTime);
			writer.Write(value.isPaused);
		}

		public static NetworkGuid _ReadNetworkGuid_None(NetworkReader reader)
		{
			NetworkGuid result = default(NetworkGuid);
			result._a = reader.ReadPackedUInt64();
			result._b = reader.ReadPackedUInt64();
			return result;
		}

		public static NetworkDateTime _ReadNetworkDateTime_None(NetworkReader reader)
		{
			NetworkDateTime result = default(NetworkDateTime);
			result._binaryValue = (long)reader.ReadPackedUInt64();
			return result;
		}

		public static Run.RunStopwatch _ReadRunStopwatch_Run(NetworkReader reader)
		{
			Run.RunStopwatch result = default(Run.RunStopwatch);
			result.offsetFromFixedTime = reader.ReadSingle();
			result.isPaused = reader.ReadBoolean();
			return result;
		}

		public static CharacterBody.NetworkItemBehaviorData _ReadNetworkItemBehaviorData_CharacterBody(NetworkReader reader)
		{
			CharacterBody.NetworkItemBehaviorData result = default(CharacterBody.NetworkItemBehaviorData);
			result.intItemValue = (int)reader.ReadPackedUInt32();
			result.floatValue = reader.ReadSingle();
			return result;
		}

		public static void _WriteNetworkItemBehaviorData_CharacterBody(NetworkWriter writer, CharacterBody.NetworkItemBehaviorData value)
		{
			writer.WritePackedUInt32((uint)value.intItemValue);
			writer.Write(value.floatValue);
		}

		public static void _WriteNetworkMasterIndex_MasterCatalog(NetworkWriter writer, MasterCatalog.NetworkMasterIndex value)
		{
			writer.WritePackedUInt32(value.i);
		}

		public static MasterCatalog.NetworkMasterIndex _ReadNetworkMasterIndex_MasterCatalog(NetworkReader reader)
		{
			MasterCatalog.NetworkMasterIndex result = default(MasterCatalog.NetworkMasterIndex);
			result.i = reader.ReadPackedUInt32();
			return result;
		}

		public static void _WritePickupIndex_None(NetworkWriter writer, PickupIndex value)
		{
			writer.WritePackedUInt32((uint)value.value);
		}

		public static PickupIndex _ReadPickupIndex_None(NetworkReader reader)
		{
			PickupIndex result = default(PickupIndex);
			result.value = (int)reader.ReadPackedUInt32();
			return result;
		}

		public static PhysForceInfo _ReadPhysForceInfo_None(NetworkReader reader)
		{
			PhysForceInfo result = default(PhysForceInfo);
			result.force = reader.ReadVector3();
			return result;
		}

		public static void _WritePhysForceInfo_None(NetworkWriter writer, PhysForceInfo value)
		{
			writer.Write(value.force);
		}

		public static CharacterMotor.HitGroundInfo _ReadHitGroundInfo_CharacterMotor(NetworkReader reader)
		{
			CharacterMotor.HitGroundInfo result = default(CharacterMotor.HitGroundInfo);
			result.velocity = reader.ReadVector3();
			result.position = reader.ReadVector3();
			result.isValidForEffect = reader.ReadBoolean();
			return result;
		}

		public static void _WriteHitGroundInfo_CharacterMotor(NetworkWriter writer, CharacterMotor.HitGroundInfo value)
		{
			writer.Write(value.velocity);
			writer.Write(value.position);
			writer.Write(value.isValidForEffect);
		}

		public static void _WriteFixedTimeStamp_Run(NetworkWriter writer, Run.FixedTimeStamp value)
		{
			writer.Write(value.t);
		}

		public static Run.FixedTimeStamp _ReadFixedTimeStamp_Run(NetworkReader reader)
		{
			Run.FixedTimeStamp result = default(Run.FixedTimeStamp);
			result.t = reader.ReadSingle();
			return result;
		}

		public static void _WriteHurtBoxReference_None(NetworkWriter writer, HurtBoxReference value)
		{
			writer.Write(value.rootObject);
			writer.WritePackedUInt32(value.hurtBoxIndexPlusOne);
		}

		public static HurtBoxReference _ReadHurtBoxReference_None(NetworkReader reader)
		{
			HurtBoxReference result = default(HurtBoxReference);
			result.rootObject = reader.ReadGameObject();
			result.hurtBoxIndexPlusOne = (byte)reader.ReadPackedUInt32();
			return result;
		}

		public static void _WriteParentIdentifier_NetworkParent(NetworkWriter writer, NetworkParent.ParentIdentifier value)
		{
			writer.WritePackedUInt32(value.indexInParentChildLocatorPlusOne);
			writer.Write(value.parentNetworkInstanceId);
		}

		public static NetworkParent.ParentIdentifier _ReadParentIdentifier_NetworkParent(NetworkReader reader)
		{
			NetworkParent.ParentIdentifier result = default(NetworkParent.ParentIdentifier);
			result.indexInParentChildLocatorPlusOne = (byte)reader.ReadPackedUInt32();
			result.parentNetworkInstanceId = reader.ReadNetworkId();
			return result;
		}

		public static UnlockableIndex[] _ReadArrayUnlockableIndex_None(NetworkReader reader)
		{
			int num = reader.ReadUInt16();
			if (num == 0)
			{
				return new UnlockableIndex[0];
			}
			UnlockableIndex[] array = new UnlockableIndex[num];
			for (int i = 0; i < num; i++)
			{
				ref UnlockableIndex reference = ref array[i];
				reference = (UnlockableIndex)reader.ReadInt32();
			}
			return array;
		}

		public static void _WriteArrayUnlockableIndex_None(NetworkWriter writer, UnlockableIndex[] value)
		{
			if (value == null)
			{
				writer.Write((ushort)0);
				return;
			}
			ushort value2 = (ushort)value.Length;
			writer.Write(value2);
			for (ushort num = 0; num < value.Length; num++)
			{
				writer.Write((int)value[num]);
			}
		}

		public static void _WriteNetworkUserId_None(NetworkWriter writer, NetworkUserId value)
		{
			writer.WritePackedUInt64(value.value);
			writer.Write(value.strValue);
			writer.WritePackedUInt32(value.subId);
		}

		public static NetworkUserId _ReadNetworkUserId_None(NetworkReader reader)
		{
			NetworkUserId result = default(NetworkUserId);
			result.value = reader.ReadPackedUInt64();
			result.strValue = reader.ReadString();
			result.subId = (byte)reader.ReadPackedUInt32();
			return result;
		}

		public static PingerController.PingInfo _ReadPingInfo_PingerController(NetworkReader reader)
		{
			PingerController.PingInfo result = default(PingerController.PingInfo);
			result.active = reader.ReadBoolean();
			result.origin = reader.ReadVector3();
			result.normal = reader.ReadVector3();
			result.targetNetworkIdentity = reader.ReadNetworkIdentity();
			return result;
		}

		public static void _WritePingInfo_PingerController(NetworkWriter writer, PingerController.PingInfo value)
		{
			writer.Write(value.active);
			writer.Write(value.origin);
			writer.Write(value.normal);
			writer.Write(value.targetNetworkIdentity);
		}

		public static WokController.WokIngredientData _ReadWokIngredientData_WokController(NetworkReader reader)
		{
			WokController.WokIngredientData wokIngredientData = new WokController.WokIngredientData();
			wokIngredientData.playerNetId = reader.ReadNetworkId();
			wokIngredientData.unlockedChef = reader.ReadBoolean();
			wokIngredientData.previouslyStoredIngredient1 = reader.ReadBoolean();
			wokIngredientData.previouslyStoredIngredient2 = reader.ReadBoolean();
			wokIngredientData.previouslyStoredIngredient3 = reader.ReadBoolean();
			return wokIngredientData;
		}

		public static void _WriteWokIngredientData_WokController(NetworkWriter writer, WokController.WokIngredientData value)
		{
			writer.Write(value.playerNetId);
			writer.Write(value.unlockedChef);
			writer.Write(value.previouslyStoredIngredient1);
			writer.Write(value.previouslyStoredIngredient2);
			writer.Write(value.previouslyStoredIngredient3);
		}

		public static CubicBezier3 _ReadCubicBezier3_None(NetworkReader reader)
		{
			CubicBezier3 result = default(CubicBezier3);
			result.a = reader.ReadVector3();
			result.b = reader.ReadVector3();
			result.c = reader.ReadVector3();
			result.d = reader.ReadVector3();
			return result;
		}

		public static WormBodyPositions2.KeyFrame _ReadKeyFrame_WormBodyPositions2(NetworkReader reader)
		{
			WormBodyPositions2.KeyFrame result = default(WormBodyPositions2.KeyFrame);
			result.curve = _ReadCubicBezier3_None(reader);
			result.length = reader.ReadSingle();
			result.time = reader.ReadSingle();
			return result;
		}

		public static void _WriteCubicBezier3_None(NetworkWriter writer, CubicBezier3 value)
		{
			writer.Write(value.a);
			writer.Write(value.b);
			writer.Write(value.c);
			writer.Write(value.d);
		}

		public static void _WriteKeyFrame_WormBodyPositions2(NetworkWriter writer, WormBodyPositions2.KeyFrame value)
		{
			_WriteCubicBezier3_None(writer, value.curve);
			writer.Write(value.length);
			writer.Write(value.time);
		}

		public static float[] _ReadArraySingle_None(NetworkReader reader)
		{
			int num = reader.ReadUInt16();
			if (num == 0)
			{
				return new float[0];
			}
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				ref float reference = ref array[i];
				reference = reader.ReadSingle();
			}
			return array;
		}

		public static void _WriteArraySingle_None(NetworkWriter writer, float[] value)
		{
			if (value == null)
			{
				writer.Write((ushort)0);
				return;
			}
			ushort value2 = (ushort)value.Length;
			writer.Write(value2);
			for (ushort num = 0; num < value.Length; num++)
			{
				writer.Write(value[num]);
			}
		}

		public static void _WritePlatformID_None(NetworkWriter writer, RoR2.PlatformID value)
		{
			writer.WritePackedUInt64(value.ID);
			writer.WritePackedUInt64(value.ID2);
			writer.Write(value.stringID);
		}

		public static RoR2.PlatformID _ReadPlatformID_None(NetworkReader reader)
		{
			RoR2.PlatformID result = default(RoR2.PlatformID);
			result.ID = reader.ReadPackedUInt64();
			result.ID2 = reader.ReadPackedUInt64();
			result.stringID = reader.ReadString();
			return result;
		}

		public static void _WriteDamageTypeCombo_None(NetworkWriter writer, DamageTypeCombo value)
		{
			writer.WritePackedUInt64(value.damageTypeCombined);
			writer.Write((int)value.damageType);
			writer.Write((int)value.damageTypeExtended);
		}

		public static DamageTypeCombo _ReadDamageTypeCombo_None(NetworkReader reader)
		{
			DamageTypeCombo result = default(DamageTypeCombo);
			result.damageTypeCombined = reader.ReadPackedUInt64();
			result.damageType = (DamageType)reader.ReadInt32();
			result.damageTypeExtended = (DamageTypeExtended)reader.ReadInt32();
			return result;
		}

		public static ServerAchievementIndex _ReadServerAchievementIndex_None(NetworkReader reader)
		{
			ServerAchievementIndex result = default(ServerAchievementIndex);
			result.intValue = (int)reader.ReadPackedUInt32();
			return result;
		}

		public static void _WriteServerAchievementIndex_None(NetworkWriter writer, ServerAchievementIndex value)
		{
			writer.WritePackedUInt32((uint)value.intValue);
		}
	}
}
